3dnow tests (tutorial scherfgen)
-
Ich glaube, es gibt keinen Compiler, der 3dnow-Code erzeugt. Aber mit SSE könnte man den Vergleich mit dem Intel-Compiler mal wagen. Dein Code schaut nicht unbedingt schlecht aus, aber der Compiler wird's vermutlich doch noch etwas schneller hinkriegen.
-
Ringding schrieb:
Ich glaube, es gibt keinen Compiler, der 3dnow-Code erzeugt.
gcc
-
ein paar kleinigkeiten müssten es noch etwas beschleunigen: (auf jeden fall solltest du einfach mal nen benchmark laufen lassen, um zu sehen, welche änderungen tatsächlich etwas bringen)
ich würde die pfacc befehle unmittelbar hinter die entsprechenden pfmul befehle bringen, ansonsten ist der adder eine weile lang nicht beschäftigt während er später überstunden schieben muss
"pfacc %%mm2, %%mm0\n\t" kann ja auch nicht unmittelbar nach "pfacc %%mm3, %%mm2\n\t" ohne zwangspause ausgeführt werden. (der compiler macht sowas ganz auomatisch, weil ja bei a*b+c*d+e*f... die token bereits ganz natürlich abwechselnd vorkommen: mul, mul, add, mul, add...)
sub durch zwei dec befehle zu ersetzen ist nicht notwendigerweise günstig, da das zweite vom ersten dec abhängig ist, wenn du stattdessen sub benutzt könntest du auch das carry flag abfragen (das ja von dec nicht gesetzt wird) und so den unbedingten sprung vermeiden (der bedingte sprung wird ja fast nie - bis auf den letzten durchlauf) ausgeführt, und er nimmt ja auch code weg):
"sub 2,%%edx\n\t" "jnc loop\n\t"
jetzt könntest du nat. auch gleich um 16 erniedrigen, das macht bei sub ja keinen unterschied.
noch günstiger - wobei in diesem fall wahrscheinlich ohne auswirkungen auf die laufzeit - ist es, den vektor von vorne nach hinten und nicht umgekehrt zu durchlaufen:"mov %4, %%edx\n\t" //vectorcount "shl 4, %%edx\n\t" // vectocount*16 "mov %0, %%eax\n\t" "mov %1, %%ebx\n\t" "mov %2, %%ecx\n\t" "add %%edx, %%ebx\n\t" "add %%edx, %%ecx\n\t" "neg %%edx"
jetzt kannst du ganz normal über ebx+edx bzw ecx+edx addressieren, statt sub muss dann nat. add am ende der schleifen stehen, und es wird auf 0 und nicht carry geprüft.
-
mein vorschlag wäre das hier:
inline void multwithvector(const float* input, const float* output, const int vectorcount) { asm ( "mov %3, %%edx\n\t" //vectorcount "shl 4, %%edx\n\t" //vectocount*16 "mov %0, %%eax\n\t" "mov %1, %%ebx\n\t" "mov %2, %%ecx\n\t" "add %%edx, %%ebx\n\t" "add %%edx, %%ecx\n\t" "neg %%edx" "femms\n\t" "loop:\n\t" "movq (%%ebx,%%edx), %%mm0\n\t" //für alle nicht at&t assembler: "movq 8(%%ebx,%%edx), %%mm1\n\t" //(%%ebx,%%edx,8) == (%ebx+%edx*8) "add 16, %%edx\n\t" //flags frühzeitig setzen, um sprungvorhersage zu optimieren "movq %%mm0, %%mm2\n\t" "pfmul (%%eax), %%mm0\n\t" "movq %%mm1, %%mm3\n\t" "pfmul 8(%%eax), %%mm1\n\t" "pfacc %%mm1, %%mm0\n\t" "movq %%mm2, %%mm4\n\t" "pfmul 16(%%eax), %%mm2\n\t" "pfacc %%mm2, %%mm0\n\t" "movq %%mm3, %%mm5\n\t" "pfmul 24(%%eax), %%mm3\n\t" "pfacc %%mm3, %%mm0\n\t" "movq %%mm4, %%mm6\n\t" "pfmul 32(%%eax), %%mm4\n\t" "movq %%mm5, %%mm7\n\t" "pfmul 40(%%eax), %%mm5\n\t" "pfacc %%mm5, %%mm4\n\t" "pfmul 48(%%eax), %%mm6\n\t" "pfacc %%mm6, %%mm4\n\t" "pfmul 56(%%eax), %%mm7\n\t" "pfacc %%mm7, %%mm4\n\t" "movq %%mm0, -16(%%ecx,%%edx)\n\t" //edx wurde schon erhöht "movq %%mm4, -8(%%ecx,%%edx)\n\t" "jnz loop\n\t" "femms\n\t" ://kein output //Ah=matrix .. ich berechne A*x nicht x*A wie im tutorial :"a" (Ah), "b" (input), "c" (output), "d" (vectorcount) ); }
-
huuuuuuuuuuu schrieb:
Ringding schrieb:
Ich glaube, es gibt keinen Compiler, der 3dnow-Code erzeugt.
gcc
Hmm, stimmt. Der kann aber nicht vektorisieren, das ist bei solchen Sachen auch oft nützlich/notwendig.
-
schön
funktioniert aber leider nicht.. gibt nen seg. fault. ich versuche gerade herauszufinden woran das liegt.. aber das selbe problem hatte ich auch mal (mein erster war auch ein logischer "von vorne nach hinten durchlaufen" ansatz) und konnte es nicht lösen.
gruss
eviluser
-
die pfacc befehle sind nat. falsch gewesen:
"movq (%%ebx,%%edx), %%mm0\n\t" "movq 8(%%ebx,%%edx), %%mm1\n\t" "add 16, %%edx\n\t" "movq %%mm0, %%mm2\n\t" "pfmul (%%eax), %%mm0\n\t" "movq %%mm1, %%mm3\n\t" "pfmul 8(%%eax), %%mm1\n\t" "pfacc %%mm1, %%mm0\n\t" "movq %%mm2, %%mm4\n\t" "pfmul 16(%%eax), %%mm2\n\t" "movq %%mm3, %%mm5\n\t" "pfmul 24(%%eax), %%mm3\n\t" "pfacc %%mm3, %%mm2\n\t" "movq %%mm4, %%mm6\n\t" "pfmul 32(%%eax), %%mm4\n\t" "pfacc %%mm2, %%mm0\n\t" "movq %%mm5, %%mm7\n\t" "pfmul 40(%%eax), %%mm5\n\t" "pfacc %%mm5, %%mm4\n\t" "pfmul 48(%%eax), %%mm6\n\t" "pfmul 56(%%eax), %%mm7\n\t" "pfacc %%mm7, %%mm6\n\t" "pfacc %%mm6, %%mm4\n\t" "movq %%mm0, -16(%%ecx,%%edx)\n\t" "movq %%mm4, -8(%%ecx,%%edx)\n\t"
warum hier ein segfault auftritt ist mir allerdings nicht klar
-
okok.. ich bestehe ja darauf at&t assembler zu verwenden.. da bin ich selbst daran schuld..
die lösung ist.. ich kann nicht einfach so ne zahl in nen operator schreiben.. ich muss sie kennzeichnen.. add $16, %%edxdann klappts.. bis auf den letzten schleifendurchlauf..
den kopiere ich einfach runter..
so.. perfekt
-
ich weiss nicht inwiefern das representativ ist.. deshalb nenne ich das ding einfach mal pseudobench..
ich brauche für 10000000 vektoren angeblich 1.1 sekunden prozessorzeit.
mit der anderen (umgekehrten version) genau das selbe.. ich suche jetzt erstmal nach diesem amd-tool.. vieleicht bekomme ich da brauchbarere werte raus
gruss
eviluser
-
ich probiere gerade einbischen mit der ausrichtung von adressen herum und wenn ich mir den code ansehe den du mir vorher gepostet hattest..
int *p,*p_aligned; p = malloc( 1000 * sizeof( int ) - 1 + ALIGNMENT ); p_aligned = (int*)( ( (unsigned)p - 1 + ALIGNMENT ) & -ALIGNMENT ); // irgendwas mit p_aligned tun free( p );
muss ich feststellen dass das ein trick ist den ich nciht verstehe
du erzeugst 2 pointer vom typ int. einem davon reservierst du speicher .. so etwa 4015 gross. und dann machst du etwas krasses mit p_aligned .. vergleichst es bitweise mit -Alignment ?? im endeffekt haben dan beide (p&p_aligned) die selbe adresse.. und die endet mit 0.. und irgendwie beschleicht mich das gefühl dass das kein zufall war..gruss
eviluser