Maximale Effizienz: Schleife oder memset?



  • Hallo,

    ich habe ein zweidimensionales Array vom Datentypen DWORD. Dieses Array muss regelmäßig genullt werden und zwar mit möglichst wenig Einbußen bei der Performance. Im Folgenden sind drei Code-Snippets zu sehen, die das besagte Array initialisieren:

    WORD   i                   = 0;
    WORD   j                   = 0;
    DWORD  ppMtx[MAX_X][MAX_Y] = {0};
    DWORD *p                   = NULL;
    DWORD *pEnd                = NULL;
    
    // === VORSCHLAG 1 ===
    for (i=0; i<MAX_X; ++i)
    {
       for (j=0; j<MAX_Y; ++j)
       {
          ppMtx[i][j] = 0;
       }
    }
    
    // === VORSCHLAG 2 ===
    p    = (DWORD *)ppMtx;
    pEnd = ((DWORD *)ppMtx) + (MAX_X * MAX_Y);
    while (p != pEnd)
    {
       *p = 0;
       ++p;
    }
    
    // === VORSCHLAG 3 ===
    ::memset (ppMtx, 0, sizeof (ppMtx));
    

    Obwohl ich eins der drei Verfahren favorisiere, möchte ich mir eine zweite Meinung einholen:

    Welche Implementierung ist warum effizienter (also "theoretisch" schneller, weil weniger Befehle ausgeführt werden müssen)?



  • Wie sehen die Benchmarkergebnisse aus? Glaube kaum, dass eine Variante besser ist. Allein vom Codeumfang wuerde ich Vorschlag 3 bevorzugen.

    PS: Was hat das mit WinAPI zu tun?



  • Bei vielen C Standardbibliotheken wurde sich schon die Mühe gemacht memset etc. so weit zu optimieren wie möglich. Da wird dann abhängig von der Länge der Daten und ob es unterstützt wird z.B. auch SSE eingesetzt. Damit kann man schon noch etwas Geschwindigkeit gewinnen.

    Bei Vorschlag 1 und 2 kommt es eigentlich nur darauf an was der Compiler daraus macht. Wenn MAX_X und MAX_Y zur Compilezeit bekannt sind, sollte der Compiler bei 1 direkt erkennen was da gewollt ist. Bei 2 sollte das aber eigentlch auch klappen und in so ziemlich dem gleichen Code resultieren. Um das genau zu sagen hilft aber nur Compilieren und den Maschinencode angucken.



  • memset verwenden, und ggf. über ein geeignetes #pragma verbieten dass memset als intrinsic erweitert wird.
    (intrinsic memset ist meist "rep stosb", und das bei grossen blöcken wiederum meist viel langsamer als die "normale" memset funktion)

    bei MSVC geht das z.B. so:

    #pragma function(memset)
    
    void FunktionDieMemsetVerwendet()
    {
        memset(...);
    }
    

Anmelden zum Antworten