amd-pipeline



  • hallo,

    ich hab mal einbichen in den datenblättern meines prozessors geschmökert und gelesen, dass der amd-model8-prozessor 3 integer-pipelines, 3 adressberechnungs-pilelines und 3 floatingpoint-pipelines hat. also insgesammt 9.
    so .. jetzt zum kern meiner frage 🙂

    movq mm0, [%eax]
    pfmul mm0, [%ebx]
    movq [%eax], mm0
    

    das kurze codestück da oben wird "einemilliardemal" asgeführt (auf einem specherbereich dessen offset in ebx/eax liegt und nach jeder ausführung entsprechend erhöht wird).
    lohnt es sich das codestück etwas "auszurollen", um eine optimalere pipelineausnutzung zu erreichen?
    da die von amd darauf wertlegen dass es sich um 3x3 pipelines handelt, würde ich dann quasi erst 3 movq befehle anstossen, dann 3 floatingpoint operationen und dann wieder 3 movq...
    dummerweise habe ich (so schön sich das auch anhört) ein schlechtes gefühl bei der sache.. alsob das nicht stimmen würde was ich mir da zusammengelegt habe 🙂
    wenn sich jemand in der materie auskennt würde ich mich über eine antwort freuen.

    gruss

    eviluser



  • Kennst du den AMD CodeAnalyst? Damit kannst du solchen Code simulieren und die Perfomance (Pipelineauslastung u.a.) analysieren.

    CodeAnalyst gibt es kostenlos auf der AMD-Seite.


  • Mod

    Im zweifelsfall hilft nur ausprobieren.
    der hauptgrund, in diesem falle die schleife etwas auszurollen, würde darin liegen, die befehlsanzahl pro zyklus zu senken. mal ausgehend von der grundform:

    mov     eax, ...
           mov     ebx, ...
           add     eax, 1000
           add     ebx, 1000
           mov     edx, 1000000000 / 1000
    _loop2:mov     ecx, -1000    ; sicher ist der speicherblock nicht 4GB groß
    _loop: movq    mm0, [ eax + ecx * 8 ]
           inc     ecx
           pfmul   mm0, [ ebx + ecx * 8 ]
           movq    [ eax + ecx ], mm0
           jnz     _loop
           dec     edx
           jnz     _loop2
    

    hast du hier 5 befehle im inneren zyklus
    wenn wir das jetzt einmal ausrollen:

    _loop2:mov     ecx, -1000
    _loop: movq    mm0, [ eax + ecx * 8 ]
           add     ecx, 2
           pfmul   mm0, [ ebx + ecx * 8 ]
           movq    mm1, [ eax + ecx * 8 + 8 ]
           pfmul   mm1, [ ebx + ecx * 8 + 8 ]
           movq    [ eax + ecx * 8 ], mm0
           movq    [ eax + ecx * 8 + 8 ], mm1
           jnz     _loop
           dec     edx
           jnz     _loop2
    

    sind es offenbar nur noch 4 pro zyklus, da einmal inc und jmp eingespart wurden,
    ein weiteres denkbares problem ist im nicht ausgerollten fall, dass der storebefehl movq [ .. ], mm0 evtl. das laden im nächsten zyklus verzögert, wenn beide befehle auf dieselbe cacheline wirken. ausserdem kann dieser storebefehl ja ohnehin nicht gleich ausgeführt werden, da erst auf das ergebnis von pfmul gewartet werden muss
    man könnte noch versuchen, das ganze noch einmal um den faktor 2 auszurollen, mehr lohnt dann wahrscheinlich nicht mehr


  • Mod

    im allg. sollte man versuchen, pipelines jeden typs beschäftigt zu halten (insbes. mit fpu), als die existenz mehrerer gleichartiger pipes auszunutzen: also z.b. mov,add,mul abwechseln - wenn du mov und mul und add jeweils für sich gruppierst, sind die anderen pipes ja nicht beschäftigt. alle 9 gleichzeitig auszunutzen wird dir sowieso nicht gelingen, im zweifelsfall wartest du nur auf den speicher 🙂


Anmelden zum Antworten