Einen wunderschönen guten Abend!
Ich bin auf ein unintuitives Problemchen gestoßen..
Ich habe 2 Möglichkeiten für einen cast-ctor:
1
//Fall 1:
2
template<typename U>
3
X( U&& u) : X_b( std::forward<U>(u) ){
4
}
5
6
//Fall 2:
7
template<typename U>
8
X( U&& u){
9
X_b xb( std::forward<U>(u) );
10
(*this) = xb;
11
}
Hat jemand eine Idee, warum das generierte ASM im Fall 2 besser
optimiert ist, als im Fall 1? Der Compiler scheint im ersten Fall extra
eine Ctor-Funktion zu erstellen und zu benutzen. Im zweiten Fall tauch
die jedoch nicht auf.
Woran könnte das liegen??
MfG
Verschwindibus schrieb:> Hat jemand eine Idee, warum das generierte ASM im Fall 2 besser> optimiert ist, als im Fall 1? Der Compiler scheint im ersten Fall extra> eine Ctor-Funktion zu erstellen und zu benutzen.
Bei mir nicht...
Der Compiler erzeugt aus deinem Codeschnipsel zunächst mal gar nichts.
Da kommt es wohl darauf an, was du mit den Templates dann tatsächlich
anstellst.
Daher wäre ein compilierbares Codebeispiel hilfreich, und dazu eine
Aussage, welcher Compiler den Effekt zeigt.
Oliver
Verschwindibus schrieb:> Einen wunderschönen guten Abend!>> Ich bin auf ein unintuitives Problemchen gestoßen..> Ich habe 2 Möglichkeiten für einen cast-ctor:>>
1
> //Fall 1:
2
> template<typename U>
3
> X( U&& u) : X_b( std::forward<U>(u) ){
4
> }
5
>
6
> //Fall 2:
7
> template<typename U>
8
> X( U&& u){
9
> X_b xb( std::forward<U>(u) );
10
> (*this) = xb;
11
> }
12
>
>> Hat jemand eine Idee, warum das generierte ASM im Fall 2 besser> optimiert ist, als im Fall 1? Der Compiler scheint im ersten Fall extra> eine Ctor-Funktion zu erstellen und zu benutzen. Im zweiten Fall tauch> die jedoch nicht auf.>> Woran könnte das liegen??
Fall2 dürfte wohl gar nicht kompilieren, weil X_b wohl der Namen eines
Attributs der umgebenden Klasse sein soll. Dort wird es aber als Typ
verwendet. Dies bedeutet dann auch, dass Du den Fall 2 niemals
instanziiert hast (also Funktionstemplate des ctors), denn sonst wäre
der Fehler wohl aufgefallen.
Also: poste Dein komplettes Beispiel.
Hallo,
Danke für die Antworten trotz der mageren Informationslage..
Ich habe mir das Ganze noch mal genauer angeschaut und festgestellt,
dass es sich im ASM nicht um einen un-ge-inlined-en Ctor handelt,
sondern ein Callback.. Und der Grund dafür schein ein uninitialisiertes
Array gewesen zu sein.
Kann das sein? Kommt das jemandem bekannt vor, oder ergibt das sogar
Sinn?
Verschwindibus schrieb:> Kann das sein? Kommt das jemandem bekannt vor, oder ergibt das sogar> Sinn?
Ohne konkreten Code, nein. Ist ziemlich undurchsichtig so. Was für ein
Callback? C++ erzeugt nicht ungefragt irgendwo Callbacks...
Ps.. Kann eigentlich doch nicht an uninitialisierten Daten gelegen
haben, da mein array zumindest als ": array{}" im ctor aufgetaucht ist
(und somit dessen elemente default-initialisiert werden, wenn ich das
richtig sehe). Und außerdem, weil im Codeschnipsel-Bsp. eben gar kein
member in irgendeinem "ctor()" initialisiert wird.. ( im "ctor(fkt)"
natürlich schon).
Mit Callback meinte ich g().
@Oliver: Ja, natürlich soll es genau das werden...
Oder, ich hatte erwartet, dass der geneigte Leser es ohne groß weitere
Worte versteht:
Man nehme, für ein entsprechendes Bsp des Problems eine Kombination der,
jeweils mit A, B, C, D, oder E gekennzeichneten, Zeilen, entsprechend
der unten stehenden, zugehörigen 'Rezeptur' des jew Beispiels.
Außerdem seien in X_b, wie erwartet, natürlich auch initialisierbare
(POD) Daten vorhanden.
Verschwindibus schrieb:> Man nehme
Was genau verstehst du an "kompilierbarem Beispiel" nicht? Zeig ein
vollständiges Programm, mit allem, was dazugehört. Wie sonst soll man
deine Aussagen zum erzeugten Assemblercode überprüfen können?
Die Frage nach Compiler/Toolchain hast du auch noch nicht beantwortet.
Oliver
>Was genau verstehst du an "kompilierbarem Beispiel" nicht? Zeig ein>vollständiges Programm, mit allem, was dazugehört. Wie sonst soll man>deine Aussagen zum erzeugten Assemblercode überprüfen können?
Wie wärs mit dem erzeugten ASM-Code? Dann musst du dich nicht weiter auf
un-realisierbaren Forderungen versteifen..
Als würde das mal eben so gehen. Wäre das so einfach, würde ich nicht
nach Mutmaßungen Ausschau halten.
Mit anderen Worten, jemand, der mir helfen kann, sollte jetzt schon mehr
parat haben, als dumme Sprüche und Geweine.
Ich arbeite mit GCC, aber in der Hoffnung, dass es nichts
Compiler-abhängiges ist.
Verschwindibus schrieb:> //Fall 2:> template<typename U>> X( U&& u){> X_b xb( std::forward<U>(u) );> (*this) = xb;> }
Der Code lässt mich halt etwas zweifeln, ob du da überhaupt weißt, was
du da tust.
Oliver
>Der Code lässt mich halt etwas zweifeln, ob du da überhaupt weißt, was>du da tust.>>Oliver
Man merkt dir deine Verunsicherung an. Wenn du häufiger
Misstrauensprobleme hast, rate ich dir, einen eigenen Thread
aufzumachen. Auch wenn du in einem Psycho-Forum besser damit aufgehoben
wärst, Oliver.
Andernfalls gäbe es ja noch Inhalte, wie weitere Codeschnipsel und Text,
auf die du dich beziehen könntest... Vorausgesetzt du fühlst dich in
beiden Fällen angesprochen.*
*
>Mit anderen Worten, jemand, der mir helfen kann, sollte jetzt schon mehr>parat haben, als dumme Sprüche und Geweine.
@Kaj:
Die Komplexität. Was nützt ein kompilierbares Beispiel, wenn es das
Problem evtl nicht mehr enthält?
Ein, das Problem enthaltendes, Beispiel, für ein Problem unbekannten
Ursprungs zu fordern ist schon genug Hirnakrobatik für sich genommen..
Verschwindibus schrieb:> @Kaj:> Die Komplexität. Was nützt ein kompilierbares Beispiel, wenn es das> Problem evtl nicht mehr enthält?
Hmpf. Du behauptest, dass irgendein GCC da anderen Code generiert als du
erwartest. Wenn es unmöglich ist, ein compilierbares Beispiel daraus zu
machen, ohne dass der Fehler verschwindet, wie soll sich da jemand den
generierten Code anschauen können? Und wie hast du das dann gemacht?
> Ein, das Problem enthaltendes, Beispiel, für ein Problem unbekannten> Ursprungs zu fordern ist schon genug Hirnakrobatik für sich genommen..
Der erste Schritt, um ein Problem anzugehen, ist immer der Versuch, es
zu reproduzieren. Wenn man das nicht kann, hat man eigentlich keine
Chance, außer es einfach hinzunehmen.
Lieber TO,
der GCC erzeugt in allen Fällen genau den selben Code:
exakt 0 Byte.
Da stehen nämlich nur Templates und diese werden nie konkretisiert.
Die Frage hätte auch ein unbenutztes Macro zeigen können. Solange
Template oder Macro nie benutzt werden, sind sie wie ein Beipackzettel
den keiner liest.
Was soll das sein? Zudem ganz anders als Dein Eingangsproblem.
Wo ist das Basisklassentemplate X<>?
Was soll die Funktion vectLE() sein? Hätte wohl ein ctor werden sollen,
steht dann aber in der falschen Klasse.
Wo ist initWieCtor()?
Nochmal: mache ein MCVE, damit alle hier, die Dir helfen wollen, oder
zumindest das Problem verstehen wollen, auch eine Chance haben.
Verschwindibus schrieb:> Man merkt dir deine Verunsicherung an.
Worüber?
Verschwindibus schrieb:> Ich habe 2 Möglichkeiten für einen cast-ctor:
Deine zwei Möglichkeiten machen das selbe noch das gleiche. Das die
zweite gar nicht kompiliert, wurde die ja schon gesagt. Und selbst wenn
man die korrigiert, spielt da neben den unbekannten
Default-Konstruktoren der Basisklasse auch ein Copy-oder
Move-Konstruktor mit, der ebenfalls unbekannt ist.
Und du fragst jetzt, warum der Compiler da unterschiedlichen Code
generiert? (was er eh nicht tut, weil es so gar nicht kompilierbar ist).
Danach kommt dan plötzlich ein uninitialistertes Array und dubiose
Callbacks ins Spiel.
Da kann man schon mal darüber verunsichert sein, ob das alles das nicht
entweder völlige Ahnungslosigkeit oder reine Trollerei ist.
Oliver
Ich wollte eigentlich nicht noch mehr Verwirrung stiften.. :)
Es geht mir nicht darum, dass meine Syntax auf Fehler überprüft wird
(sonst würde ich standardmäßig in clang, statt gcc programmieren ;) ).
Ich dachte eher an Ratschläge, wie: "Ach, seltsam langes ASM kommt mir
bekannt vor, oder plötzliche Probleme mit Inlining. Versuch mal '-fXYZ',
damit der Compiler 'W' macht."
Ich bin inzwischen selbst auf Flag-Suche gegangen und bei diversen
"-f..inline.." fündig geworden, aber warum, im Detail, das ein oder
andere Flag hilft, ka.
@ Wilhelm M.:
>Was soll das sein? Zudem ganz anders als Dein Eingangsproblem.Verschwindibus schrieb:> Man nehme, für ein entsprechendes Bsp des Problems eine Kombination der,> jeweils mit A, B, C, D, oder E gekennzeichneten, Zeilen, entsprechend> der unten stehenden, zugehörigen 'Rezeptur' des jew Beispiels.> Außerdem seien in X_b, wie erwartet, natürlich auch initialisierbare> (POD) Daten vorhanden.
Nein, mein Eingangsproblem ist unverändert: zu langes ASM.
Nur meine Fehlersuche ist vorangeschritten und der Kreis der
Verdächtigen hat sich geändert.
>Was soll die Funktion vectLE() sein? Hätte wohl ein ctor werden sollen,>steht dann aber in der falschen Klasse.
Stimmt, sorry, bis eben übersehen, sollte natürlich "X(..)" heißen.
>Wo ist initWieCtor()
initWieCtor(...) == X<T>( [&](bool b){ return y.g(b); } == X_b<T>(
[&](bool b){ return y.g(b); } )
Macht was draufsteht und holt sich "y.g(b)" .
Rolf M. schrieb:> Hmpf. Du behauptest, dass irgendein GCC da anderen Code generiert als du> erwartest.
Hmpf. Ja.
>Der erste Schritt, um ein Problem anzugehen, ist immer der Versuch, es>zu reproduzieren. Wenn man das nicht kann, hat man eigentlich keine>Chance, außer es einfach hinzunehmen.
..Sag das all jenen, die nur nach kompilierbaren Beispielen verlangen.
Hast du noch zufällig konkrete Weisheiten über Inlining-Probleme des
gcc??
Gcc schrieb:> Lieber TO,> der GCC erzeugt in allen Fällen genau den selben Code:> exakt 0 Byte.
Lieber Gcc, es wäre schön, wenn das deine Fehlermeldung gewesen wäre.
Stattdessen hast du dich für eine zu künstlerische Interpretation meines
Codes entschieden.
@Oliver: Du solltest Logbuchführer werden. Denn, abgesehen von deinen
konstuierten Porblemchen, hasst du meine Reise relativ gut
zusammengefasst.
>Da kann man schon mal darüber verunsichert sein, ob das alles das nicht>entweder völlige Ahnungslosigkeit oder reine Trollerei ist.
Muss man aber nicht. Kann man aber, wenn man es nötig hat. Da stimme ich
dir zu.
Verschwindibus schrieb:>>Was soll die Funktion vectLE() sein? Hätte wohl ein ctor werden sollen,>>steht dann aber in der falschen Klasse.>> Stimmt, sorry, bis eben übersehen, sollte natürlich "X(..)" heißen.
Das kann doch gar nicht sein, wenn das wirklich Deinem Problem
entspricht.
Wie gesagt: poste einfach ein MCVE, dann sehen wir weiter.
Verschwindibus schrieb:> Ich bin inzwischen selbst auf Flag-Suche gegangen und bei diversen> "-f..inline.." fündig geworden, aber warum, im Detail, das ein oder> andere Flag hilft, ka.
Ach, ist ja toll. Und welche möchtest Du uns nicht erzählen?
Verschwindibus schrieb:> Ich dachte eher an Ratschläge, wie: "Ach, seltsam langes ASM kommt mir> bekannt vor, oder plötzliche Probleme mit Inlining. Versuch mal '-fXYZ',> damit der Compiler 'W' macht."
-fwimiwyg
Wilhelm M. schrieb:> Verschwindibus schrieb:>> Ich bin inzwischen selbst auf Flag-Suche gegangen und bei diversen>> "-f..inline.." fündig geworden, aber warum, im Detail, das ein oder>> andere Flag hilft, ka.>> Ach, ist ja toll. Und welche möchtest Du uns nicht erzählen?
Vor allem, weil die eigentlich alle bei Nutzung von -O2 oder -O3 aktiv
sind.
Oliver
Wilhelm M. schrieb:> Das kann doch gar nicht sein, wenn das wirklich Deinem Problem> entspricht.
So langsam denken wir in die gleiche Richtung..
> Wie gesagt: poste einfach ein MCVE, dann sehen wir weiter.
Wie gesagt, wie soll das unter diesen Umständen einfach gehen..
> Ach, ist ja toll. Und welche möchtest Du uns nicht erzählen?
Der Zyniker in mir würde jetzt sagen: Wozu, du hast doch eh kein MCVE..
Sonst vielleicht einfach normal fragen, wenns dich interessiert!?
Oliver S. schrieb:> Vor allem, weil die eigentlich alle bei Nutzung von -O2 oder -O3 aktiv> sind.>> Oliver
Ich merke schon, da kennst sich jemand aus. Ist ja nicht so, als könnte
genau das das Problem sein.
Kannst dich ja mal fragen, warum es viele Flags mit "no-"-Präfix gibt...
Verschwindibus schrieb:> Wilhelm M. schrieb:>> Das kann doch gar nicht sein, wenn das wirklich Deinem Problem>> entspricht.>> So langsam denken wir in die gleiche Richtung..
Glaube ich nicht!
>> Wie gesagt: poste einfach ein MCVE, dann sehen wir weiter.>> Wie gesagt, wie soll das unter diesen Umständen einfach gehen..
Du hast das ganze doch untersucht, oder? Also, was spricht nun dagegen,
dieses MVCE zu posten. Denn Du musst ja eins haben, sonst könntest Du ja
nicht so sicher sein.
>> Ach, ist ja toll. Und welche möchtest Du uns nicht erzählen?>> Der Zyniker in mir würde jetzt sagen: Wozu, du hast doch eh kein MCVE..> Sonst vielleicht einfach normal fragen, wenns dich interessiert!?
Ich habe jetzt schon so oft nach einem MVCE gefragt, doch Du trollst nur
rum!
Verschwindibus schrieb:>>Der erste Schritt, um ein Problem anzugehen, ist immer der Versuch, es>>zu reproduzieren. Wenn man das nicht kann, hat man eigentlich keine>>Chance, außer es einfach hinzunehmen.>> ..Sag das all jenen, die nur nach kompilierbaren Beispielen verlangen.
Ich sage es dir, weil gerade das der Grund ist, warum sie ein solches
Beispiel verlangen. Wenn keiner dein Problem reproduzieren kann, kann
auch keiner was dazu sagen.
Rolf M. schrieb:> Wenn keiner dein Problem reproduzieren kann, kann> auch keiner was dazu sagen.
Das ist vermutlich wie bei Heisenberg: Entweder man kann das Problem
reproduzieren oder etwas zu dessen Lösung beitragen.
Wilhelm M. schrieb:> Glaube ich nicht!
Schade, ich bin eben ein Optimist. Und du?
> Du hast das ganze doch untersucht, oder? Also, was spricht nun dagegen,> dieses MVCE zu posten. Denn Du musst ja eins haben, sonst könntest Du ja> nicht so sicher sein.> Ich habe jetzt schon so oft nach einem MVCE gefragt, doch Du trollst nur> rum!
Du scheinst anzunehmen, dass ich mir eines Tages gedacht habe: So ich
mach mir jetzt nen MCVE zu einem unvorhergesehenen Problem..
Verschwindibus schrieb:> Mit anderen Worten, jemand, der mir helfen kann, sollte jetzt schon mehr> parat haben, als dumme Sprüche und Geweine.Rolf M. schrieb:> Ich sage es dir, weil gerade das der Grund ist, warum sie ein solches> Beispiel verlangen. Wenn keiner dein Problem reproduzieren kann, kann> auch keiner was dazu sagen.
Dazu du selbst:
Rolf M. schrieb:> Wenn man das nicht kann, hat man eigentlich keine> Chance, außer es einfach hinzunehmen.
Und ich bin durchaus der Meinung, dass man auch dann etwas dazu sagen
kann, wenn man kann.
Um das zu verdeutlichen:
Mal angenommen, es gäbe ein MCVE und das Problem wäre reproduzierbar:
Hätten die Leute mehr parat als dann selbst nur rumzuprobieren, nämlich
Tipps, könnte man sie auch jetzt schon geben.
DerEgon schrieb:> Das ist vermutlich wie bei Heisenberg: Entweder man kann das Problem> reproduzieren oder etwas zu dessen Lösung beitragen.
..wegen seiner Unschärferelation, oder doch seiner ..Katze..??
Gcc schrieb:> Da es hier wohl nur einen gibt, der wirklich was davon versteht, scheint> das Problem gelöst.
Wenigstens das ist eine gelungene Darbietung: Genau was der gcc sagen
würde! :)
Verschwindibus schrieb:> ..wegen seiner Unschärferelation, oder doch seiner ..Katze..??
Heisenbergs Katze oder Schrödingers Unschärferelation, das ist hier die
Frage (einen Totenschädel anblickend).
Verschwindibus schrieb:> Und ich bin durchaus der Meinung, dass man auch dann etwas dazu sagen> kann, wenn man kann.
Also ich hatte schon mit vielen Problemen dieser Art zu tun, aber da
jetzt allgemein ohne konkretes Beispiel was zu sagen ist schwierig. Da
kann man nur so Allgemeinplätze abgeben: Optimierungen einschalten, alle
move/copy Konstruktoren und assignment Operatoren korrekt
implementieren, viel constexpr und inline verwenden, kein volatile o.ä.
verwenden, kein reinterpret_cast oder sonstige Speicher-Schweinereien
verwenden, immer direkte Initialisierung statt nachträglicher Zuweisung,
alles const-Korrekt und Move-Korrekt implementieren, bei Integer-Typen
auf Promotion achten, std::forward verwenden... Es gibt bestimmt noch
mehr, aber ohne das Problem am konkreten Code zu sehen fällt mir gerade
nicht mehr ein.
Solche Probleme habe ich immer gelöst indem ich mir den fraglichen
Assembler-Code angeschaut habe, den Source-Code immer weiter reduziert
und geprüft dass das Problem bestehen bleibt. Irgendwann stößt man auf
die Stelle, die das Problem verursacht.
Ich bin jetzt zwar auch neugierig was genau die Ursache ist aber wenn du
kein vollständiges Beispiel rausrückst, ist es halt so.
Verschwindibus schrieb:> Wilhelm M. schrieb:>> Glaube ich nicht!>> Schade, ich bin eben ein Optimist. Und du?>>> Du hast das ganze doch untersucht, oder? Also, was spricht nun dagegen,>> dieses MVCE zu posten. Denn Du musst ja eins haben, sonst könntest Du ja>> nicht so sicher sein.>> Ich habe jetzt schon so oft nach einem MVCE gefragt, doch Du trollst nur>> rum!>> Du scheinst anzunehmen, dass ich mir eines Tages gedacht habe: So ich> mach mir jetzt nen MCVE zu einem unvorhergesehenen Problem..
Nein.
Fakt ist ein: Du hast ein reales Problem.
Und offensichtlich hast Du es schon so weit herunter gebrochen, dass Du
Dir den Assembler-Code dazu angesehen hast. Du bist also jetzt schon den
halben Weg bis zu einem MVCE gegangen.
Und Du hast versucht, aus diesem tatsächlichen Code ein MVCE zu
extrahieren (was Dir allerdings nicht ganz gelungen ist, denn die
Code-Schnipsel, die Du postest waren bisher fehlerhaft und
unvollständig). Wer weiß, welche anderen Unterschiede noch zu Deinem
wirklichen Code vorhanden sind?
Solange also nichts konkretes kommt von Dir, bist Du wohl auf Dich
allein gestellt.
Verschwindibus schrieb:> Mal angenommen, es gäbe ein MCVE und das Problem wäre reproduzierbar:> Hätten die Leute mehr parat als dann selbst nur rumzuprobieren, nämlich> Tipps, könnte man sie auch jetzt schon geben.
Nein.
Denn wenn dein Code dem des Ausgangsbeitrags ähnelt, dann vergleichst du
Äpfel mit faulen Birnen, und wunderst dich, daß in beiden Fällen kein
Pflaumenmus rauskommt. Sehr vermutlich ist dein Sourcecode fragwürdig,
nicht der Compiler.
Einen Tipp kann man allerdings tatsächlich geben:
Die Frage, warum ein Compiler etwas macht, wie er es macht, ist nie
zielführend.
Oliver
Wilhelm M. schrieb:> Fakt ist ein: Du hast ein reales Problem.
Ach, plötzlich bin ich doch kein Troll.
> Und offensichtlich hast Du es schon so weit herunter gebrochen, dass Du> Dir den Assembler-Code dazu angesehen hast. Du bist also jetzt schon den> halben Weg bis zu einem MVCE gegangen.> Und Du hast versucht, aus diesem tatsächlichen Code ein MVCE zu> extrahieren (was Dir allerdings nicht ganz gelungen ist, denn die> Code-Schnipsel, die Du postest waren bisher fehlerhaft und> unvollständig).MCVE.
Beruht dein programmierstil auch auf solchen "Offensichtlichkeiten"? Du
liegst nämlich falsch. ASM guckt man sich z.B. auch an, wenn man
verschiedene Implementationen miteinander vergleicht. Ebenso falsch sind
deine Beobachtungen: Ich wollte nie ein MCVE extrahieren.
> Wer weiß, welche anderen Unterschiede noch zu Deinem> wirklichen Code vorhanden sind?
Ich.
> Solange also nichts konkretes kommt von Dir, bist Du wohl auf Dich> allein gestellt.
Das zu behaupten, direkt nachdem mir jemand Tipps gegeben hat, zeugt von
einer ganz speziellen Art einer offenen Herangehensweise...
Ganz schöner Umweg um mir mitzuteilen, dass du eigentlich gar keine
Ahnung hast, unter diesen Umständen.
Oliver S. schrieb:> Nein.
Auch an dich: Das zu behaupten, direkt nachdem mir jemand Tipps gegeben
hat, zeugt von einer ganz speziellen Art einer offenen
Herangehensweise...
> Denn wenn dein Code dem des Ausgangsbeitrags ähnelt, dann vergleichst du> Äpfel mit faulen Birnen, und wunderst dich, daß in beiden Fällen kein> Pflaumenmus rauskommt. Sehr vermutlich ist dein Sourcecode fragwürdig,> nicht der Compiler.> Ganz schöner Umweg um mir mitzuteilen, dass du eigentlich gar keine Ahnung> hast, unter diesen Umständen.
..Äpfen, faule Birnen, Pflaumen, ...Klingt für mich nach C++-Alltag..
> Einen Tipp kann man allerdings tatsächlich geben:>> Die Frage, warum ein Compiler etwas macht, wie er es macht, ist nie> zielführend.
Was für ein Nicht-Tipp! Das lässt mich vermuten, dass du dich kein Stück
mit Compilern auskennst. Du hast die Zeit anscheinend nicht genutzt, um
mal herauszufinden, warum es viele Flags mit 'no-' gibt.
Niklas G. schrieb:> Also ich hatte schon mit vielen Problemen dieser Art zu tun, aber da> jetzt allgemein ohne konkretes Beispiel was zu sagen ist schwierig. Da> kann man nur so Allgemeinplätze abgeben:> Optimierungen einschalten
Check: wobei der ASM mit < O3 noch knackiger wird... ._. (als würde er
sich selbst ein Bein stellen. Aber warum. Könnte der Code, meinetwegen,
zu kein sein? )
> alle move/copy Konstruktoren und assignment Operatoren korrekt> implementieren
Check: entweder nie benutzt, implizit, oder manuell erstellt.
> viel constexpr und inline verwenden, kein volatile o.ä. verwenden
Aber sowas von Check.
> kein reinterpret_cast oder sonstige Speicher-Schweinereien verwenden
Ein zivilisiertes Check. (Wobei ich nicht weiß, ob mein Callback-Aufruf
nicht irgendwie dazu zählt...)
> immer direkte Initialisierung statt nachträglicher Zuweisung,
Ca.-Ckeck: Gerade das Gegenteil führt manchmal zum Erfolg.
> alles const-Korrekt und Move-Korrekt implementieren, bei Integer-Typen> auf Promotion achten, std::forward verwenden...
Check: Macht keinen Unterschied, ob alles mit const ref, oder univ. ref.
Und gibt nur einen int-Typ.
> Es gibt bestimmt noch> mehr, aber ohne das Problem am konkreten Code zu sehen fällt mir gerade> nicht mehr ein.>> Solche Probleme habe ich immer gelöst indem ich mir den fraglichen> Assembler-Code angeschaut habe, den Source-Code immer weiter reduziert> und geprüft dass das Problem bestehen bleibt. Irgendwann stößt man auf> die Stelle, die das Problem verursacht.>> Ich bin jetzt zwar auch neugierig was genau die Ursache ist aber wenn du> kein vollständiges Beispiel rausrückst, ist es halt so.
Ich danke dir so oder so, schon mal für deine Hilfe. Das lässt mich
wenigstens hoffen, dass ich nicht der Verrückte bin.. :)
Das Problem ist leider Teil eines Projektes und wurde noch nicht
extrahiert.
Daher kann ich nur weitere Beobachtungen zum drüber Nachdenken teilen:
Mal zurück zu dem obigen Beispiel der Klasse X. Die 'Rezepte' besitzen
noch immer ihre Gültigkeit:
Ich habe es mit "inline __attribute((always_inline))__ X().." probiert:
-> Gar kein Inlining mehr!
Ich habe die Logik (quasi Rezept 'E') in eine Wrapper-Funktion
(ent-)gepackt:
-> Die ANZAHL der Argumente (auch wenn defaulted) macht einen
Unterschied! <--- ???
Habe es mit verzögerter, verzögerter Init ( Cpy cpy; cpy.init(..); *this
= cpy; ) versucht (ähnlich wie in "Fall 2" eingangs):
-> X_b besitze einen Ctor X_b(){ /*leer*/ } ! Dennoch macht es einen
Unterschied, ob ich "Cpy cpy;" , oder "Cpy cpy{};" nehme.
Nun.. Und immer stellt sich mir die Frage: Soll das so sein..? (Btw.
Clang sagt Nein.)
Verschwindibus schrieb:> Check: wobei der ASM mit < O3 noch knackiger wird...
-O2 reicht eigentlich um "Dummheiten" und Umwege loszuwerden.
Verschwindibus schrieb:> Check: entweder nie benutzt, implizit, oder manuell erstellt.
Ich tendiere dazu die alle immer manuell zu erstellen oder mit
"=delete"/"=default" zu definieren, damit ganz sicher ist, dass sie
existieren oder nicht existieren (je nachdem was benötigt).
Verschwindibus schrieb:> (Wobei ich nicht weiß, ob mein Callback-Aufruf> nicht irgendwie dazu zählt...)
Wenn das ein Aufruf über Funktionszeiger oder virtuelle Funktion ist,
kann der Compiler den wahrscheinlich nicht optimieren, es sei denn das
ganze Konstrukt ist "inline".
Verschwindibus schrieb:> Ca.-Ckeck: Gerade das Gegenteil führt manchmal zum Erfolg.
Das entspricht nicht meinen Erfahrungen und deutet IMO auf einen Fehler
im Code hin.
Verschwindibus schrieb:> Check: Macht keinen Unterschied, ob alles mit const ref, oder univ. ref.
Kommt auf den Code an. i.A. sollten die Referenztypen schon überall
korrekt sein.
Verschwindibus schrieb:> Ich habe es mit "inline __attribute((always_inline))__ X().." probiert:
Muss es nicht "__attribute__((always_inline)) inline" sein?
> -> Gar kein Inlining mehr!
Das kann nicht. Der GCC befolgt always_inline immer.
Verschwindibus schrieb:> -> Die ANZAHL der Argumente (auch wenn defaulted) macht einen> Unterschied! <--- ???
Kann schon sein, der Inlining-Algorithmus arbeitet heuristisch (außer
always_inline ist vorhanden).
Verschwindibus schrieb:> Nun.. Und immer stellt sich mir die Frage: Soll das so sein..?
Nein, der GCC kriegt sowas normalerweise gut hin. Verwendest du denn
eine aktuelle Version?
Niklas G. schrieb:> -O2 reicht eigentlich um "Dummheiten" und Umwege loszuwerden.
So wie es sich mir darstellt, tritt das Problem erst ab -O2 auf, und
auch der sonstige Code ist mit -O0 knackiger. Muss ich aber nochmal
durchprobieren..
Aber unter welchen Bedingungen, könnte das überhaupt der Fall sein?
Niklas G. schrieb:> ie alle immer manuell zu erstellen oder mit> "=delete"/"=default" zu definieren, damit ganz sicher ist, dass sie> existieren oder nicht existieren (je nachdem was benötigt).
Alles durchiteriert. Hat keinen Einfluss.
Niklas G. schrieb:> Wenn das ein Aufruf über Funktionszeiger oder virtuelle Funktion ist,> kann der Compiler den wahrscheinlich nicht optimieren, es sei denn das> ganze Konstrukt ist "inline".
Ist zur Compile-Zeit bekannt (Template-Par.).
Niklas G. schrieb:> Das entspricht nicht meinen Erfahrungen und deutet IMO auf einen Fehler> im Code hin.
Ne, meinen auch nicht.
Code, der das Problem auftretem/verschwinden lässt, ist allerdings an
mehreren, (augenscheinlich) von einander unabhängigen, Ecken zu finden.
Niklas G. schrieb:> Kommt auf den Code an. i.A. sollten die Referenztypen schon überall> korrekt sein.
Ich meinte, dass ich es mit 2 Versionen versucht habe. Die "einfache",
bei der man nicht mal eben ein std::forward vergessen kann und die
"moderne".
Niklas G. schrieb:> Muss es nicht "__attribute__((always_inline)) inline" sein?
Ich glaube nicht. So gerade ausprobert: Macht keinen Unterschied.
Und noch ein Spaß für zwischendurch: Wenn ich im Beispiel
"Wrapper-Funktion" sowohl Ctor, als auch die Wrapper-Funktion damit
versehe, wird der Callback jedenfalls gar nicht ge-inlined..
Niklas G. schrieb:> Das kann nicht. Der GCC befolgt always_inline immer.
Finde ich auch! Kann auch nichts weiter dazu sagen.
Wobei, ich könnte mir vorstellen, dass der Compiler sich in dieser
Situation evtl zwischen 2 Inline-Möglichkeiten entscheiden muss, wovon
eine dann zu weiteren Optimierungen führt.
Dass das ASM mit -O0 noch kleiner ist, gefällt mir dabei persönlich
weniger..
Niklas G. schrieb:> Kann schon sein, der Inlining-Algorithmus arbeitet heuristisch (außer> always_inline ist vorhanden).
Ich hätte noch erwähnen sollen, dass die zusätzlichen Argumente nicht
genutzt werden, falls das einen Unterschied macht. Und alles schön
sichtbar sein sollte für den Compiler.
Niklas G. schrieb:> Nein, der GCC kriegt sowas normalerweise gut hin. Verwendest du denn> eine aktuelle Version?
Jup, gerade frisch eine 12.x..
Verschwindibus schrieb:> So wie es sich mir darstellt, tritt das Problem erst ab -O2 auf, und> auch der sonstige Code ist mit -O0 knackiger.
Seltsam. Normalerweise macht der GCC bei -O0 ziemliche Ausschweife, bei
-O2 ist eh kompakt und schnell, bei -O3 wird er gern mal wieder länger
aber dafür noch schneller.
Verschwindibus schrieb:> Wenn ich im Beispiel> "Wrapper-Funktion" sowohl Ctor, als auch die Wrapper-Funktion damit> versehe, wird der Callback jedenfalls gar nicht ge-inlined..
Der Callback selber muss natürlich auch "always_inline" sein, nicht nur
der Aufrufer!
Verschwindibus schrieb:> Niklas G. schrieb:>> Das kann nicht. Der GCC befolgt always_inline immer.>> Finde ich auch! Kann auch nichts weiter dazu sagen.
Außer du nimmst irgendwo einen Zeiger auf die Funktion, oder sie ist
virtuell, dann muss sie natürlich "explizit" existieren.
Verschwindibus schrieb:> Dass das ASM mit -O0 noch kleiner ist, gefällt mir dabei persönlich> weniger..
Gerade bei x86 kann kleiner=langsamer sein.
Was, ziemlich exakt sein sollte, da ich nur eine Berechnung mit Literals
ausführe und ausgebe. Und alles unnötige scheint auch verworfen zu
werden.
ASM mit "-O3":
Mit -O3 wird der Code 'ohne das Problem' zwar länger, aber bleibt
konstant. Damit kann ich leben. Warum das passiert, würde mich trotzdem
interessieren...
Warum plötzlich z.B. __throw_bad_castv und die ganzen jumps..?
Nur 'mit dem Problem' wird, dank evtl. unpassendem Inlining (?), der
Code beliebig lang, je nach Inhalt des Callbacks.
Verschwindibus schrieb:> call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@PLT
vs.
Verschwindibus schrieb:> call> _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_P
KS3_l@PLT
Der Compiler scheint anzunehmen, daß letzteres schneller ist, trotz des
Mehraufwandes drum herum.
Oliver
Also ich habe noch weiter getestet und dabei festgestellt, dass C++20
noch nicht einheitlich behandelt wird von unterschiedlichen Compilern.
Und wenn das schon der Fall ist, ist dieser Heuristik-Schluckauf etwas,
womit man sich abfinden kann..
Danke dennoch.
@Niklas G.: Womit bekommt man denn lesbareren Code raus und was bedeutet
lesbar für dich? Das war jetzt das Zwischenergebnis direkt vom Compiler.
Verschwindibus schrieb:> Das war jetzt das Zwischenergebnis direkt vom Compiler.
Ich bevorzuge es, die finale Anwendung zu disassemblieren, weil die .o
-Dateien ja auch noch einmal verarbeitet werden. Und dann wie gesagt mit
"objdump -d -C application > disassembly.S" o.ä.