Array zurücksetzen (Performance optimiert)



  • Benutz memset, anstelle einer Schleife, dass kann theoretisch effizienter implementiert sein und sollte im schlimmsten Fall nur genauso effizient sein wie die Schleifenlösung.



  • +++



  • Es kann nicht schneller gehen. Oder glaubst du, es gäbe einen CPU Befehl, der ganze Speicherbereiche setzt 😉
    Etwas mann man vielleicht rausholen, wenn die Bytes nicht einzeln sondern wenn Ints benutzt werden. Aber viel mehr ist nciht drin.



  • N-Dream schrieb:

    CLayer[800][600]

    In Deinem Code behandelst Du die Arrays aber so, als ob sie 801x601 Elemente hätten. Mach aus den "<=" jeweils ein "<", dann stimmt es. Sonst könntest Du Dir Probleme einhandeln, weil Du einfach in andere Teile des Speichers reinschreibst.



  • @KennerDerS: Wenn die Arrays größer sind und dein Prozessor HT untersützt kannst du es ja in zwei Threads aufteilen *g* 🙂

    MfG SideWinder



  • Es kann nicht schneller gehen.

    Natürlich kann es. Aber nicht in C.
    Da gibt es doch verschiedensten Verfahren die in den Papers der CPU Hersteller erklärt werden.



  • paper schrieb:

    Natürlich kann es. Aber nicht in C.
    Da gibt es doch verschiedensten Verfahren die in den Papers der CPU Hersteller erklärt werden.

    Ach ja ? eben das bezweifel ich. Oder magst du die Verfahren auch beim Namen nennen ? 😉



  • MMX, SSE2 und Extended 3DNow!

    Die können dann mit mehreren Integern gleichzeitig arbeiten (SSE2 benützt glaube ich 4) und hat damit einen Geschwindigkeitsboost von (spekulativ 🙄) Faktor 4.

    Kannst du aber in C nur über Inline-Assembler erreichen, die meisten Compiler benötigen zusätzlich noch ein Prozessorpack (für den MSVC gratis runterzuladen).

    MfG SideWinder



  • Danke f¨ür eure vielen Antworten.
    Natürlich muss es schneller gehen!

    Könnte man nicht im Memory an den Anfang des Arrays springen und direkt überall in den Speicher Nullen hinein schreiben.
    Das muss doch gehen.

    Es kann doch nicht sein das der Computer jedesmal die Speichadresse ausrechnen muss, an den Richtigen ort springen, eine Null setzen, aus dem Speicher hinaus und das ganze zig tausend mal. Das Ausrechnen, Rein und Raus gehen ist so Zeit aufwendig. Ich will einmal reinspringen ALLES schreiben und dann raus.
    Vielleicht könnte man den Array casten?
    Oder einfach den Array speicher freigeben, und neu allocieren, dann wären alle Elemente ja auch auf NULL?

    Hat jemand eine Idee?

    @Kingruedi: Wie geht das mit Memset, und was macht das genau?
    @TomasRiker: Natürlich sind die array 801x601...

    Danke



  • memset() -> siehe MSDN.

    Der Compiler ist hoffentlich so optimierend und rechnet nicht jedesmal die Adresse aus. Wenn er 0-Optimierer ist dann benütze Zeigerarithmetik. Also Zeiger an den Anfang des Arrays setzen durchlaufen bis 801*601 erreicht ist und die Stelle auf 0 setzen - Pseudocode:

    unsigned long int end = 801*601;
    ptr = array[0][0] // Einmalige Berechnung der Stelle
    for (unsigned long int i = 0; i < end; ++i, ++ptr)
        *ptr = 0;
    

    Aber wie gesagt, das wird dir dein Compiler auch so hinoptimieren und memset() auf jeden Fall.

    MfG SideWinder



  • N-Dream schrieb:

    Oder einfach den Array speicher freigeben, und neu allocieren, dann wären alle Elemente ja auch auf NULL?

    Nö, wären sie nicht.



  • Wenn sie das wären, wäre es noch langsamer. Da sie es nicht sind bringts nichts, und wenn du Pech hast ist es trotzdem langsamer 🤡

    MfG SideWinder



  • Es ist viel schneller mit memset.

    Wenn man einfach durch das Array durchspaziert braucht es etwa 3500 Clockticks.
    Aber wenn man mit memset arbeitet nur gerade 1800!

    Also ist memset doppelt so schnell! Wow! Merci

    memset( CLayer, 0, 1920000 );
            memset( TLayer, 0, 480000 );
    

    Ich nehme 1920000 weil ein Pointer 4 Bytes gross ist (RICHTIG???). 800*600*4
    und 480000 weil ein Boolean im Memory 1 Byte gross ist (RICHTIG???).

    Danke vielmals



  • N-Dream schrieb:

    Es ist viel schneller mit memset.

    Wenn man einfach durch das Array durchspaziert braucht es etwa 3500 Clockticks.
    Aber wenn man mit memset arbeitet nur gerade 1800!

    Also ist memset doppelt so schnell! Wow! Merci

    Hast du das auch im Release-Modus getestet?



  • Da gibts ein Sprachmittel, dass dir diese Fragen erspart -> sizeof(bool) 😉

    MfG SideWinder



  • memset( CLayer, 0, 1920000 );

    nicht vergessen das 0 hier nicht die dezimale 0 ist, eigentlich ist diese 0 bei memset irgendwas (alle bits auf 0) ob das nun irgendeiner Zahlendarstellung entspricht ist dann nicht mehr vom Standard gedeckt.

    bye

    tt



  • N-Dream schrieb:

    Wenn ich jedes mal wieder muss auf jedes Element zugreifen muss dauert das viel zu lange. Ich möchte mit einem Clocktick alle setzen.

    LOL. Dir ist aber schon klar, dass deine Prozessor Pipeline eine begrenzte Datenbreite hat?

    Die schnellste portabelste Lösung ist sicherlich memset, da viele Compiler die Funktion als Intrinsic integriert haben. Richtig gute Compiler können allerdings solch einfache Schleifen genauso effizient wie memset umsetzen. Kannst ja aber auch mal SideWinder's Vorschlag umsetzen, und zB SSE benutzen. Damit kannst du 128 Bit (also 16 Byte) in einem CPU Cycle lesen bzw. schreiben. Durch die Intel Spezifikationen ist das ganze auch relativ portabel, zumindest bei Compilern, die diese Spracherweiterungen unterstützen, wie GCC oder MSC.



  • ...und imho ist SSE auch auf 3DNow-fähigen Compilern ausführbar. Also auch auf AMD-Prozessoren.

    BTW: Mit Debug-& Releasemodus würde ich auch penlihc genau aufpassen. memset() ist in beiden Fallen in reinem hochoptimierendem Assembler geschrieben.

    Im Debug-Modus kann er aber deinen Code gar nicht optimieren.

    MfG SideWinder



  • SideWinder schrieb:

    ...und imho ist SSE auch auf 3DNow-fähigen Compilern ausführbar. Also auch auf AMD-Prozessoren.

    Da musst du aufpassen. SSE ist meines Wissens bei AMD erst ab dem Athlon XP verfügbar. Mein alter Thunderbird 900 MHz (ich glaub es war die B Version) konnte SSE zB nicht, und als museumsreif kann man die CPU noch nicht bezeichnen.



  • Okay dann ein Prüfung für die Library ob Unterstützng da ist, wie in Zerbsts Buch.

    Die Frage nur ob sich der Aufwand für ein 800*600-Feld lonht. Okay letzten Endes lohnt es sich sicherlich, da diese Prüfung nur einmal am Programmstart durchgeführt werden muss. Aber trotzdem. Soviel Arbeit um ein 800*600-Feld auf 0 zu setzen?

    Dann lieber die doppelte for-Schleife und im Release-Modus richtig optimieren lassen über Projekteinstellungen bzw. gleich memset().

    MfG SideWinder


Anmelden zum Antworten