Optimisation en MMX/SSE - Besoin d'aide - ASM - Programmation
Marsh Posté le 28-08-2003 à 13:09:23
Au cas où, voici l'une des fonctions qui font goulot d'étranglement :
void ResizePlane::_FilterConvolve(double arg0[], unsigned n0, double arg1[], unsigned n1, double result[])
{
unsigned loop0, loop1;
for(loop0 = 0; loop0 != n0 + n1 - 1; loop0++) {
for(loop1 = 0, result[loop0] = 0; loop1 != n0; loop1++) {
if(loop0 - loop1 < n1) {
result[loop0] += arg0[loop1] * arg1[loop0 - loop1];
}
}
}
}
Marsh Posté le 28-08-2003 à 13:16:23
Je m'en serais bien occupé mais j'ai pas trop le temps en ce moment
Marsh Posté le 28-08-2003 à 13:21:29
ben rien qu'au niveau de l'algo, tu peux le faire facilement sur tes boucles, en calculant plus précisément les bornes, puisque finalement tu executes ta boucle interieur tant que
loop1 != n0 && loop0 - loop1 < n1
tu te calcules le minimum pour pas te taper 2 tests à chaque fois, et voilà, un test en moins
Marsh Posté le 28-08-2003 à 13:40:24
après ben fais un max de pré-calcul, et si ton CPU à des simd, ça peut etre l'occasion de derouler un peu cette boucle (faire 4 passes d'un coup)
Marsh Posté le 28-08-2003 à 13:42:10
Compte tenu que:
- loop0 et loop1 sont unsigned
et que
- loop1 est l'incrément de la boucle intérieure
le bool (loop0 - loop1 < n1) n'est-il pas dangereux??
Edit: ortho!
Marsh Posté le 28-08-2003 à 14:40:45
questions:
ta routine est-elle un traitement d'image ? (à priori oui)
dans ce cas, as-tu besoin d'avoir des flottants de type double ?
c'est quoi l'algorithme initial ?
Marsh Posté le 28-08-2003 à 14:53:39
Finalement, j'ai simplifié un peu :
void ResizePlane::_FilterConvolve(double arg0[], unsigned n0, double arg1[], unsigned n1, double result[])
{
memcpy(result, arg1, n0 + n1 - 1);
}
Edit: Finalement je suis revenu en arrière, car la perte de qualité était importante pour un gain de vitesse minime.
Marsh Posté le 07-09-2003 à 15:13:02
cyberpat92 a écrit : Finalement, j'ai simplifié un peu : |
Marsh Posté le 07-09-2003 à 19:19:02
BJOne a écrit : questions: |
Il s'agit de routines de redimensionnement d'image. Le source complet peut être trouvé sur http://fairuse.free.fr
Le problème c'est d'optimiser les fonctione de Resize.cpp
Marsh Posté le 07-09-2003 à 19:27:28
si tu déroulais un peu toutes ces boucles ça serait mieux (_Resize? et Resize
Marsh Posté le 07-09-2003 à 21:04:02
on a affaire à une fonctione en n^2
j'aimerais bien voir le gain en asm, je doute que ça va faire des miracles
Marsh Posté le 08-09-2003 à 00:05:42
faut que t utilise le DMA, pour transferer la memoire par packet.
Marsh Posté le 08-09-2003 à 00:15:00
cyberpat92 a écrit : Au cas où, voici l'une des fonctions qui font goulot d'étranglement : |
chui un peu perdu dans ton bordel moua....tes indices me laissent reveur
tu gagneras pas grand chose a passer a l'asm.
Marsh Posté le 08-09-2003 à 00:44:20
j'ai toujours pas compris son algo (j'ai pas chercher trop non plus)
je devines que tu as une boucle ligne par ligne, puis pixel par pixel, avec une interpolation linéaire par pixel...
mais le truc est tellement mal tourné, et l'utilité des double me laisse perplexe à la base....
Marsh Posté le 08-09-2003 à 00:47:52
je pense qu'il y a justement énormément à gagner en asm (ou en mmx/sse), c'est le genre de truc ciblé par le simd.
mais vu l'écriture de base, pour qu'il puisse l'optimiser en asm, va y a avoir du boulot (alors que c'est une routine qui semble assez classique)
Marsh Posté le 08-09-2003 à 10:12:31
ben pour mmx & cie ca depend de comment il indice son bordel et je dois dire que son fatras dans la declaration de ses boucles me fait perdre le fil....
Marsh Posté le 08-09-2003 à 10:46:42
ca doit pouvoir se lineariser (quite a calculer des trucs pour rien).
D'ailleurs tu boss sur PC (MMX & cie ) ou sur MAC (AltiVec).
Si c sur Mac je dois pouvoir te pondre une version Altivec rapidement.
Marsh Posté le 08-09-2003 à 11:25:20
n0 est l'indice maxi de arg0[], et n1 celui de arg1[] semblerait-il.
Le type double est obligatoire ? Ca correspond à des niveaux ? Ca irait ss dte plus vite en long si "normalisation" préalable possible.
En ayant une variable locale "Resulta" qui cumule les += puis resul[loop0] = Resulta; en fin de for(loop1..) ça ferait ss dte rien gagner (en QuicBasic ça m'a fait gagner un peu sur un prog, mais compilo pas optimiseur, antiquité !).
EDIT :
si on regarde
for(loop1 = 0; loop1 < n0; loop1++)
{
if(loop0 - loop1 < n1)
{
result[loop0] += arg0[loop1] * arg1[loop0 - loop1];
}
}
le test if(loop0 - loop1 < n1) revient à if (loop0 - n1 < loop1) donc loop1 peut déjà partir de (loop0 - n1 + 1) si non nul ce qui évitera le test à chaque tour (juste un au début pour déterminer les bornes et faisabilité).
EDIT 2 :
Ca ferait qq chose comme
void ResizePlane::_FilterConvolve(double arg0[], unsigned n0, double arg1[], unsigned n1, double result[])
{
unsigned loop0, loop1;
int ind1, ind2;
for (loop0 = 0; loop0 < n0 + n1 - 1; loop0 ++)
{
result[loop0] = 0;
ind1 = loop0 - n1 + 1;
ind2 = n0;
if (ind1 < ind2) // voir si inclusif ou exclusif, pas très réveillé
{
for (loop1 = ind1; loop1 < ind2; loop1 ++)
{
result[loop0] += arg0[loop1] * arg1[loop0 - loop1];
}
}
}
}
EDIT 3 :
Si ind1 ne peut pas être négatif, loop0 - n1 + 1 >=0 donc RAZ des result[i] avec i = 0 à loop0 - n1 puis calcul des suivants avec for (loop0 = n1 - 1; loop0 < n0 + n1 - 1; loop0 ++)
(à voir ds le détail, c'est mon dernier jour de ma semaine de congés ). Si on ne s'intéresse qu'aux points utiles, ça devrait accélérer le traîtement.
void ResizePlane::_FilterConvolve(double arg0[], unsigned n0, double arg1[], unsigned n1, double result[])
{
unsigned loop0, loop1;
if (n1 > 1)
{
for (loop0 = 0; loop0 < n1 - 1; loop0 ++)
{
result[loop0] = 0.0;
}
}
for (loop0 = n1 - 1; loop0 < n0 + n1 - 1; loop0 ++)
{
result[loop0] = 0.0;
for (loop1 = loop0 - n1 + 1; loop1 < n0; loop1 ++)
{
result[loop0] += arg0[loop1] * arg1[loop0 - loop1];
}
}
}
A VERIFIER...
Marsh Posté le 13-09-2003 à 03:52:24
Merci de ces réponses et pistes
...mais après une nuit blanche de plus sur ce p..... de code, j'ai fini par réaliser que la fonction précédemment citée n'est appelée que 4 fois pour un encodage (à l'initialisation en fait)
Par contre, le "vrai" goulot d'étranglement est là, et j'ai bien peur que ce soit cuit, car je ne vois pas comment optimiser une multiplication
Au fait, il s'agit d'un développement pour PC. Est-ce que le MMX pourraît apporter quelque chose ?
void ResizePlane::_ResizeX(const unsigned char *src, unsigned char *dst)
{
const unsigned char *ptr;
int *filter, total;
unsigned loop0, loop1, length;
for(loop0 = 0, filter = _filterX; loop0 != _dstDim.x; loop0++) {
ptr = src + *filter++;
length = *filter++;
//for(loop1 = 0, total = 1 << 15; loop1 != length; loop1++) {
for(loop1 = 0, total = 0x8000; loop1 != length; loop1++) {
total += *ptr++ * *filter++; // <== ça c'est très lent
}
*dst++ = _clip1[total >> 16];
}
}
void ResizePlane::_ResizeY(const unsigned char *src, unsigned srcStep, unsigned char *dst, unsigned dstStep)
{
const unsigned char *ptr;
int *filter, total;
unsigned loop0, loop1, length;
for(loop0 = 0, filter = _filterY; loop0 != _dstDim.y; loop0++, dst += dstStep) {
ptr = src + *filter++ * srcStep;
length = *filter++;
//for(loop1 = 0, total = 1 << 15; loop1 != length; loop1++, ptr += srcStep) {
for(loop1 = 0, total = 0x8000; loop1 != length; loop1++, ptr += srcStep) {
total += *ptr * *filter++; // <== ça c'est très lent
}
*dst = _clip1[total >> 16];
}
}
EDIT : Pour être tout à fait complet, je rajoute la fonction qui appelle les deux précédemment citées :
void ResizePlane::Resize(const unsigned char *src, unsigned char *dst)
{
unsigned loop0;
if(_empty == false) {
if(_xFirst) {
for(loop0 = 0; loop0 != _footprint.dim.y; loop0++) {
_ResizeX(src + (_footprint.pos.y + loop0) * _srcDim.x, _temp + loop0 * _dstDim.x);
}
for(loop0 = 0; loop0 != _dstDim.x; loop0++) {
_ResizeY(_temp + loop0, _dstDim.x, dst + loop0, _dstDim.x);
}
} else {
for(loop0 = 0; loop0 != _footprint.dim.x; loop0++) {
_ResizeY(src + _footprint.pos.x + loop0, _srcDim.x, _temp + loop0, _footprint.dim.x);
}
for(loop0 = 0; loop0 != _dstDim.y; loop0++) {
_ResizeX(_temp + loop0 * _footprint.dim.x, dst + loop0 * _dstDim.x);
}
}
}
}
Marsh Posté le 13-09-2003 à 08:58:13
Taz a raison. Déroule de 4 ou 8, ca devrait te faire gagner qqs facteurs de vitesse (2 a 3 typiquement)
Marsh Posté le 13-09-2003 à 12:13:56
vu. Je connaissais pas le "déroulage" de boucles, mais effectivement ca parait logique.
MErci, je vais essayer ca
Marsh Posté le 13-09-2003 à 17:50:58
Joel F a écrit : ca doit pouvoir se lineariser (quite a calculer des trucs pour rien). |
ça serait pas mal de pouvoir comparer la version asm avec alvitec et une autre avec mmx...
Marsh Posté le 13-09-2003 à 18:10:36
os2 a écrit : |
le mmx et sse c'est de la blague par rapport à altivec
Marsh Posté le 15-09-2003 à 11:01:01
Typiquement AltiVec va 2 à 4 fois plus vite que MMX et 2 foi splus vite que SSE2.
En outre, AltiVec se programme directement en C (pas d'assembleur), n'a pas besoin de "context switching" comme MMX.
Si ca interesse des gens j'ai un papier ou deux de comparaison MMX/AltiVec.
En outre je bosse sur une librairie d'encapsulation d'AltiVec au sein de classe STL like qui devrait pas tarder à etre releaser.
Marsh Posté le 15-09-2003 à 11:32:44
OK, quelques Liens :
Une premiere evaluation :
* http://www.lri.fr/~sebot/publi/tsi.ps
Pour comprendre :
* http://www.mackido.com/Hardware/AltiVecVsMMX.html
* Pour finir, un exemple d'utilisation d'Altivec dans des conditions "exotiques :
http://wwwlasmea.univ-bpclermont.f [...] jfla03.pdf
Je posterais d'autres liens + tard, j'ai pas mes bookmarks de boulot sous la main.
Marsh Posté le 15-09-2003 à 11:42:52
celui ci je laisserais tomber, il est trop vieux sur certains point. Le switch FP-MMX ne coute plus rien (meme si evidemment en utilisant MMX tu trashe ta pile fpu), au moins sur AMD. (j'imagine qu'ils ont mis le paquet la dessus a cause de leur 3dnow) (enfin, ils disent que ca coute plus)
Sur brols un peu recent on peut avoir MMX et calcul flottant en meme tps (3dnow pour l'un, SSE pour l'autre). Par contre je ne qualifierais surement pas ca d'ergonomique...
Marsh Posté le 15-09-2003 à 12:18:32
Je sais bien, des que je retourne au boulot, je posterais les *bons* liens que j'ai utilisé pour ma biblio de DEA.
Marsh Posté le 15-09-2003 à 12:27:06
Joel F a écrit : Je sais bien, des que je retourne au boulot, je posterais les *bons* liens que j'ai utilisé pour ma biblio de DEA. |
je disais ca juste pour avoir le dernier mot hein ?
Marsh Posté le 18-09-2003 à 02:32:13
Bon ben c'est devenu ça :
total += *ptr++ * *filter++;
total += *ptr++ * *filter++;
total += *ptr++ * *filter++;
total += *ptr++ * *filter++;
total += *ptr++ * *filter++;
total += *ptr++ * *filter++;
total += *ptr++ * *filter++;
total += *ptr++ * *filter++;
et effectivement, on gagne quand même un peu. Est-il possible avec MMX de faire plusieurs multiplications durant le même cycle CPU pour gagner du temps de calcul ?
Marsh Posté le 18-09-2003 à 07:58:29
cyberpat92 a écrit : Bon ben c'est devenu ça : |
vi si c aussi lineaire pas de pb
truc genre :
Code :
|
pu sur a 100% des noms des instructions, a verifeir
Marsh Posté le 19-09-2003 à 01:24:28
J'comprends pas, j'ai cherché un peu et en fait il existe un pmull et un pmulh et plein d'autres trucs marrants auxquels j'ai rien compris...
Marsh Posté le 19-09-2003 à 07:35:25
cyberpat92 a écrit : J'comprends pas, j'ai cherché un peu et en fait il existe un pmull et un pmulh et plein d'autres trucs marrants auxquels j'ai rien compris... |
ah ouais c vrai qu'ya deux pmull
ben pmulld alors
(multiplication d'un nombre sur 32bits par un nombre sur 32bits = un nombre sur 64bits. pmull garde les 32bits du bas, tandis que mulh conservera les 32bits du haut)
Marsh Posté le 19-09-2003 à 08:06:47
ca me rapelle que je voulais ecrire un tuto mmx pour le forum fut un tps
Marsh Posté le 19-09-2003 à 09:24:58
Tu sais ou il est ?
ca m'interesse pour faire le portge de ma bibliotheque d'AltiVec vers MMX-SSE 2
Marsh Posté le 28-08-2003 à 12:48:24
Je travaille sur FairUse (logiciel "tout en un" de backup DVD)et j'ai besoin d'optimiser les fonctions de resizing de l'image en les réécrivant en ASM car c'est vraiment très lent en C++ mais je n'ai aucune pratique de ce language.
Est-ce que quelqu'un serait intéressé pour s'occuper de cette partie ?
Précision : c'est un projet open-source sous licence GPL.
Message édité par Cyberpat92 le 26-03-2004 à 13:06:54