movmem



  • Schon klar...wenn man selber proggt wird man wohl kaum so eine Routine basteln 🙂 Die Frage war nur was der assembler draus macht und ich habs ihm gezeigt 😉 Ist eben nur eine auf Intel 32 hochoptimierte Assemblerroutine...man kann das ganze auch in einfachen Schritten machen...

    Im übrigens sollte man Funktionen aus der Runtimelibrary sowieso nie selbst neu erfinden...die in der RTL sind bewährt und jahrelang ausgereift..da lieber auf den eigenen Code achten 😉

    PS: "dem macht es der Compiler u.U. mit drei vier Befehlen inline"...nein, im allgemeinen wird er die runtime-library-Funktionen benutzen...dazu sind sie geschrieben worden



  • Mir geht es darum, dass mein C-Programm auf älteren Rechnern zu langsam ist. Und das liegt daran, daß bei jedem Schleifendurchgang ein 64000 Byte-Speicherblock kopiert wird. Ich mache das mit dem Befehl movmem(ist äquivalent zu memmove). Und ich dachte, man könnte das Kopieren etwas optimieren. Denn die Befehle aus C machen ja noch mehrere Tests, ob sich die Blöcke überschneiden und solche Test brauche ich eigentlich nicht. Hat jemand eine Idee, wie ich diesen Teil meines Programms beschleunigen könnte ?



  • @TriPhoenix: Mit inline meinte ich, dasz der Compiler - zumindest war es mit C fuer WindowsCE so - nicht direkt eine Funktion aufruft sondern den Code analysiert und zum Beispiel lieber vier MOV in Folge schreibt als das ganze mit einem REP MOVSW. Das ist den Architekturen teilweise lieber.
    Wenn du im Quellcode a=b+c schreibst, dann ruft der Compiler fuer die Zuweisung und Addition auch keine Funktion auf, oder? Ach ja, a,b,c Element aus Z.



  • Original erstellt von Steffen Vogel:
    Mir geht es darum, dass mein C-Programm auf älteren Rechnern zu langsam ist. Und das liegt daran, daß bei jedem Schleifendurchgang ein 64000 Byte-Speicherblock kopiert wird. Ich mache das mit dem Befehl movmem(ist äquivalent zu memmove). Und ich dachte, man könnte das Kopieren etwas optimieren. Denn die Befehle aus C machen ja noch mehrere Tests, ob sich die Blöcke überschneiden und solche Test brauche ich eigentlich nicht. Hat jemand eine Idee, wie ich diesen Teil meines Programms beschleunigen könnte ?

    Was sind denn "aeltere Rechner"?
    Die RTLs so wie die oben sind natuerlich auf Pentium und hoeher optimiert...bei niedrigeren Rechnern greift das ganze natuerlich nicht...und wenn du auf alle checks etc. verzichtest sollte ausreichen:

    void mymemmove(void *source, void *destination, int count)
    {
       int i;
       for (i = 0; i < count; i++)
          *(destination + i) = *(source + i);
    }
    

    Achtung, das kuemmert sich nicht die Bohne um ueberlappungen usw 🙂 Kannst ja mal gucken obs was an Speed bringt 🙂
    Wenn das ganze in asm sein soll, waere eine angabe des Zielrechners guenstig..soll ja schnell sein...abe rim Allgemeinen optimiert der C-Compiler die routine wohl auch so 🙂



  • Korrektur...mich hat gerade wer darauf aufmerksam gemacht dass das ganze noch netter geht 🙂

    void mymemmove(char *src, char *dest, int count)
    {
        while (count--)
            *(dest++) = *(src++);
    }
    


  • Original erstellt von <TriPhoenix_ohne_login>:
    **Korrektur...mich hat gerade wer darauf aufmerksam gemacht dass das ganze noch netter geht 🙂
    **

    Derjenige hat Dich verkohlt.
    Der neue Code mit dem while ist genau 0% schneller als der mit dem for. Schließlich kann der optimierende Compiler diese Kleinigkeiten selber.
    Was aber signifikant beschleunigen würde, wäre dafür int* zu nehmen und nur 1/4 der Schleifendurchläufe zu brauchen. Dazu sollte der Speicher natürlich auch fein aligned sein. Dafür soll mal Steffen Vogel selber sorgen.
    Und REPNE MOV ah für sowas doch immer fein aus, oder?



  • Aber mal was andereres. Steffen Vogel meint doch, er will einen Speicherbereich kopieren, also nicht verschieben! Wieso sollte er dann memmove() verwenden? Ist doch eigentlich unsinnig!
    Besonders weil diese 64kByte verdammt nach DoubleBuffering in Modus 0x13 klingen! Und da wird es immer noch schneller sein, wenn er das normale memcopy() verwendet, als wenn er sich jetzt eine neue Routine bastelt! Weil ein Hardware "REP MOVSW" wird immer noch schneller sein als ein wiederholtes "MOV" - sogar wenn vorher irgendwelche Grenzueberschreitungen getestet werden sollten!
    Hier ein Stueck Code, das ab 80286 funktioniert. Es kopiert aus einem Buffer auf den Bildschirm!

    cld
    
       lds SI, Poi
    
       mov AX, $A000
       mov ES, AX
       xor DI, DI
    
       mov CX, 32000
       rep movsw
    


  • Also bisher hab ich den Unterschied zwischen memmove und memcpy hier noch net gesehen 🙂 (In den Runtime-Librarys sind das auch dieselben routinen soweit ichs gefunden habe :))

    Aber ich schätze du hast genau den Verwendungszweck getroffen 😉



  • memcopy: Stures Kopieren ohne Grenzen zu ueberwachen.
    memmove: Kopieren mit Ueberwachung von Grenzen.



  • @RainerSP: Könntest du den Code noch kommentieren ? Ich blick da nämlich nicht ganz durch.



  • @RainerSP: Auch wenn ich nicht alles verstehe, es funktioniert prächtig, und ich kann tatsächlich einen Geschwindigkeitsvorteil erzielen. Ist es möglich, das kopieren über mov abzuwickeln und somit ein paar Clocks zu sparen ?



  • Original erstellt von RainerSp:
    **Aber mal was andereres. Steffen Vogel meint doch, er will einen Speicherbereich kopieren, also nicht verschieben! Wieso sollte er dann memmove() verwenden? Ist doch eigentlich unsinnig!
    Besonders weil diese 64kByte verdammt nach DoubleBuffering in Modus 0x13 klingen! Und da wird es immer noch schneller sein, wenn er das normale memcopy() verwendet, als wenn er sich jetzt eine neue Routine bastelt! Weil ein Hardware "REP MOVSW" wird immer noch schneller sein als ein wiederholtes "MOV" - sogar wenn vorher irgendwelche Grenzueberschreitungen getestet werden sollten!
    Hier ein Stueck Code, das ab 80286 funktioniert. Es kopiert aus einem Buffer auf den Bildschirm!

    cld ; aufsteigende Richtung bei StringBefehlen (REP) erzwingen!
    
       lds SI, Poi  ; ds:[si] beinhaltet den Zeiger auf den Puffer
    
       mov AX, $A000 ; Segment der Graphikkarte
       mov ES, AX    ; nach ES kopieren. Geht nicht direkt!
       xor DI, DI    ; Offset auf Null setzen. Aequiv. zu mov DI, 0
    
       mov CX, 32000 ; 32000 mal
       rep movsw     ; 2 Byte kopieren (w)
       
       mov cx, 16000 ; oder auch 16000 mal 4 Byte kopieren (d)
       rep movsd     ; erst ab 80386
    

    **

    Zum Thema per MOV umsetzen: Willst du wirklich 16000 mal einen MOV Befehl hinschreiben? Wuerde auf jeden Fall nicht so toll sein!

    [ Dieser Beitrag wurde am 04.07.2002 um 22:44 Uhr von RainerSp editiert. ]

    [ Dieser Beitrag wurde am 04.07.2002 um 22:46 Uhr von RainerSp editiert. ]



  • @RainerSP:
    Mit dem mov dachte ich eher, dass man das in einer Schleife abwickelt, oder wäre das am Ende doch langsamer.

    Wie kann man mit möglich wenigen Clocks einen 64k-Bereich gleich 0 setzen ? Ich nehme dafür setmem, aber ich habe über den Debugger herrausgefunden, dass setmem auf memcpy zurückgreift. Wie würdet ihr so einen Bereich löschen.



  • @RainerSP: Das mit dem $A000 funktioniert nur unter Borland C++ 2.0. Unter 3.1 liefert er den Fehler, das er das $A000 nicht versteht. Gibt es da noch einen anderen Weg, die Bildschirmadresse hinzuschreiben ?



  • Ich rate mal mit 😉

    Versuch mal 0xA000



  • Geht auch nicht, hab ich schon probiert.



  • 0xA000



  • Sorry, zu spät. 🙄
    Aber einen hab ich noch: 0A000h 😉



  • Nee, geht auch nicht.



  • speicher bereich auf null setzen wäre sowas in der art:

    mox ax,seg
    mov es,ax
    mov di,pointer
    mov cx,size
    mov al,0
    repnz stosb
    sollte auch flink genug sein

    [ Dieser Beitrag wurde am 08.07.2002 um 17:31 Uhr von Bigor editiert. ]


Anmelden zum Antworten