Während meiner kleinen Untersuchung zu Leistungsproblemen bemerkte ich eine interessante Stapelzuweisungsfunktion, hier ist es eine Vorlage für die Zeitmessung:
%Vor% Jetzt geht es nur noch um foo()
Implementierung, in jeder Implementierung wird insgesamt 500000 ints
zugewiesen:
Wird in one Chunk zugewiesen:
%Vor%Ergebnis: 7,3 Sekunden ;
Wird in zwei Chunks zugewiesen:
%Vor%Ergebnis: 3,5 Sekunden ;
Wird in vier Chunks zugewiesen:
%Vor%Ergebnis: 1,8 Sekunden .
und etc ... Ich teile es in 16 Brocken und erhalte die Ergebniszeit 0,38 Sekunden .
Erklären Sie es mir bitte, warum und wie das passiert?
Ich habe MSVC 2013 (v120), Release Build verwendet.
UPD:
Meine Maschine ist x64-Plattform. Und ich kompilierte es mit Win32-Plattform.
Wenn ich es mit x64-Plattform kompiliere, dann ergibt es in allen Fällen ungefähr 40ms.
Warum Plattformwahl so sehr beeinflussen?
Bei der Disassemblierung von VS2015 Update 3, in der 2 und 4 Array-Versionen von foo
, optimiert der Compiler die nicht verwendeten Arrays, so dass er nur Stack-Platz für 1 Array in jeder Funktion reserviert. Da die späteren Funktionen kleinere Arrays haben, dauert dies weniger Zeit. Die Zuweisung zu x liest den gleichen Speicherort für beide / alle 4 Arrays. (Da die Arrays nicht initialisiert sind, ist das Lesen von ihnen ein nicht definiertes Verhalten.) Ohne den Code zu optimieren, gibt es 2 oder 4 verschiedene Arrays, aus denen gelesen wird.
Die lange Zeit, die für diese Funktionen benötigt wird, ist auf Stack-Tests zurückzuführen, die von __ chkstk als Teil der Stapelüberlauferkennung (erforderlich, wenn der Compiler mehr als eine Seite Speicherplatz für alle lokalen Variablen benötigt).
Sie sollten sich den resultierenden Assembler-Code ansehen, um zu sehen, was Ihr Compiler wirklich mit dem Code macht. Für gcc / clang / icc können Sie Matt Godbolts Compiler Explorer verwenden.
kling optimiert alles wegen UB und das Ergebnis ist ( foo
- erste Version, foo2
- zweite Version:
icc behandelt beide Versionen sehr ähnlich:
%Vor%und gcc erstellt verschiedene Assembler-Codes für verschiedene Versionen. Version 6.1 erzeugt Code, der ein ähnliches Verhalten wie Ihre Experimente zeigt:
%Vor%Der einzige Weg, den Unterschied zu verstehen, besteht darin, sich den Assembler-Code anzusehen, der von Ihrem Compiler erstellt wurde, alles andere ist nur raten.
Tags und Links c c++ stack performance allocation