warum allocate_shared und make_shared so langsam

9

Ich habe gerade ein Testprogramm geschrieben, um den schnellsten Weg zu finden, & amp; Geben Sie viele Objekte frei, die von shared_ptr verwaltet wurden.

Ich habe shared_ptr mit new , shared_ptr mit pool , make_shared , allocate_shared versucht. Was mich überrascht, ist allocate_shared ist langsamer als shared_ptr mit pool .

Ich teste den Code in vs2017+win10 mit Release Build. Die Release-Build-Einstellung ist Standard (/ O2). Ich teste es auch in gcc4.8.5+centos6.2 mit g++ -std=c++11 -O3 .

Der Code lautet:

%Vor%

In meinem Computer (vs2017, Windows 10) ist das Ergebnis:

%Vor%

Ich habe es auch in gcc 4.8, centos6.2 getestet, das Ergebnis ist das gleiche, das ist für die Geschwindigkeit, shared_ptr_with_pool > allocate_shared > shared_ptr_with_new > make_shared .

Wie ich weiß, muss shared_ptr :: shared_ptr (T * p) einen kleinen Speicher zuweisen, um den Refcount und den Deleter zu halten, also muss zweimal zugeordnet werden, und der make_shared muss nur einmal zuordnen und allocate_shared muss nicht einmal einmal zugewiesen werden.

Nach meinem Verständnis sollte die Geschwindigkeitsbeziehung allocate_shared > shared_ptr_with_pool > make_shared > shared_ptr_with_new sein, aber nicht shared_ptr_with_pool > allocate_shared > shared_ptr_with_new > make_shared .

Könnte mir jemand den Grund nennen, sehr danke!

Aktualisierung:

Nach einigem Dig von vs2017 + windows10 habe ich std::allocate_shared oder boost::allocate_shared call memset(p, 0, sizeof(Packet)) gefunden, was den While-Vorgang verlangsamt.

Es liegt daran, dass einige Codes in VS2017-Bibliothekskopfzeile so aussehen:

%Vor%

Der Paarkonstruktor ruft memset(addr, 0, sizeof(Pair)) auf.

Ich weiß nicht, warum der Paarkonstruktor memset aufruft, und ich habe einen Testcode geschrieben:

%Vor%

Ich habe den Code mit vs2017 kompiliert und festgestellt, dass das Memset (addr, 0, 1500) aufgerufen wird. Der Asm-Code (Debug-Build, der Release-Build ist gleich) lautet:

%Vor%

Wenn ich einen leeren Konstruktor hinzufüge, sieht es so aus:

%Vor%

Der asm-Code (Debug-Build, der Build ist identisch) lautet:

%Vor%

Die call _memset (0C510BEh) wurde in call A::A (010A1456h) geändert.

So sieht es aus, wenn der Typ A Konstruktor hat, der a_(std::forward<T>(t)...) den Konstruktor aufruft, wenn Typ A keinen Konstruktor hat, der a_(std::forward<T>(t)...) Aufruf memset(addr,0,sizeof(A)) . ( Warum? )

Der Grund für das Aufrufmemset std :: allocate_shared liegt am folgenden Code ( vs2017, xutility, in my computer, at C:\Program Files (x86)\Microsoft Visual Studio17\Community\VC\Tools\MSVC.10.25017\include ):

%Vor%

Der Typ von _Myval2 ist std :: _ Align_type, der definiert ist

%Vor%

Der _Align_type hat keinen Konstruktor, also den _Myval2(_STD forward<_Other2>(_Val2)...) Aufruf memset(addr,0, sizeof(T)) .

Also habe ich die _Align_type-Definition geändert (füge einen Dummy-Konstruktor hinzu) und erneut testen. Ich habe festgestellt, dass std :: allocate_shared memset nicht aufruft und viel schneller als zuvor.

%Vor%

Nachdem ich die Definition von _Align_type geändert habe, ist jetzt die Geschwindigkeit von test_allocate_shared gleich oder etwas schneller als test_shared_ptr_with_pool .

Bis jetzt weiß ich, warum std::allocate_shared so langsam ist, aber ich weiß immer noch nicht warum der Code memset aufruft, wenn Typ T keinen Konstruktor hat, aber nicht memset aufruft, wenn T Konstruktor hat.

%Vor%

Ist es ein C ++ Standard?

Und, da die allocate_shared memset (sizeof (T)) nicht aufrufen sollte, ist es ein Fehler des Compilers?

Aktualisieren :

%Vor%

Ich kompiliere obigen Code von vs2017, x86 Release-Build, und der Asm-Code ist:

%Vor%

Es gibt immer noch ein memset (addr, 0, 1500)!

Aktualisieren : Es scheint, es gibt einen Fehler in Visual Studio 2017 std::allocate_shared . Der Code versucht, perfect-forwarding ein std::_Align_type zu konstruieren, das keinen Konstruktor hat, und so initialisiert value-initialize std::_Align_type , also memset .

    
alpha 13.07.2017, 05:58
quelle

1 Antwort

1

Nach dem Lesen von warum c ++ memset (addr, 0, sizeof (T)) benutzt, um ein Objekt zu konstruieren? Standard-oder Compiler-Bug? und Standard-Initialisierung versus Null Initialisierung , jetzt ich Verstehe, warum es ein memset gibt.

Dies liegt daran, dass das associate_shared-Werkzeug in vs2017 den Typ _Align_type verwendet und dieser Typ keinen Konstruktor hat. Wenn allocate_shared versucht, das _Align_type value-initialize, ruft es memset .

auf

Es scheint ein Fehler in vs2017.

Vor dem Bugfix, denke ich, vielleicht keine gute Idee, um es zu umgehen.

Aktualisierung:

Ich habe einen Fehlerbericht an MS gesendet, und sie haben es getan bestätige es.

Aktualisierung: Dieser Fehler existiert noch in vs2017 Update 3.

    
alpha 14.07.2017 10:35
quelle

Tags und Links