Wenn Sie so Optimierungen vornehmen, tun Sie es falsch. Es tut mir leid, ich verwende normalerweise keine negativen Begriffe, wenn ich etwas erkläre, aber du bist auf einem falschen Weg.
Was Sie tun, heißt vorzeitige Optimierung und Mikro-Optimierung. Sie versuchen, etwas zu optimieren, von dem Sie nicht wissen, dass es optimiert werden muss. Erstens, und das ist ein Deal Breaker: Verwenden Sie Compiler-Optimierungen. Und dann würden Sie normalerweise profilieren und versuchen, die Krisenherde zu optimieren.
Mal sehen, wie relevant die Optimierung Sie versuchen zu tun ist:
ich zunächst mit -O3
(gcc 6.1) kompilieren: Lassen Sie uns die Ausgabe (auch auf der Godbolt compiler explorer) sehen:
mul_inverse3(double):
mulsd .LC0(%rip), %xmm0
cvttsd2si %xmm0, %eax
ret
div3(double):
divsd .LC1(%rip), %xmm0
cvttsd2si %xmm0, %eax
ret
wo .LCO
und .LC1
sind die Konstanten: der nächste double
-1/3.0 und 3.0
:
.LC0:
.long 1431655765
.long 1070945621
.LC1:
.long 0
.long 1074266112
Ok, so sehen Sie bereits, wie viel der Compiler für sich selbst tun kann. Dies ist, was Sie gesehen haben sollten, nicht die lauten -O0
Ausgabe.
Welcher ist schneller? Als Faustregel gilt: Multiplikation ist schneller als Division auf allen CPUs. Das Verhältnis hängt von der spezifischen Mikroarchitektur ab. Für x86 siehe Agner Fog's instruction tables and microarch pdf und andere Perf-Links im x86-Tag-Wiki. Zum Beispiel, ~ 3x die Latenz und ~ 1/12 der Durchsatz bei Intel Sandybridge. Und trotzdem ist div vielleicht nicht einmal der Flaschenhals, also kann div vs mul die Gesamtleistung nicht beeinflussen. Cache-Misses, andere Pipelines oder andere Dinge wie IO könnten den Unterschied komplett verbergen.
Aber sie sind immer noch anders. Können wir den gleichen Code vom Compiler erhalten? Ja! Fügen Sie -ffast-math
hinzu. Mit dieser Option kann der Compiler Floating-Operationen neu anordnen/ändern, auch wenn sich das Ergebnis etwas ändert (was Sie von Hand versuchen möchten). Seien Sie jedoch vorsichtig, da dies für das gesamte Programm gilt.
mul_inverse3(double):
mulsd .LC0(%rip), %xmm0
cvttsd2si %xmm0, %eax
ret
div3(double):
mulsd .LC0(%rip), %xmm0
cvttsd2si %xmm0, %eax
ret
Können wir mehr tun? Ja: Fügen Sie -march=native
hinzu und suchen Sie in der Compiler-Dokumentation nach weiteren Optionen.
Das war also die erste Lektion: Lassen Sie den Compiler tun, es ist Optimierungen zuerst!
Hier kommt die zweite:
Sie verbringen 1 Woche versucht, eine zufällige Operationen zu optimieren. Du machst es endlich! Nach einer Woche harter Arbeit und schlaflosen Nächten machen Sie diese Operation 10-mal schneller (wow! Herzlichen Glückwunsch!). Dann starten Sie Ihr Programm und sehen, dass das Programm nur 1% schneller ist. Der Horror! Wie kann das möglich sein? Nun, wenn Ihr Programm nur 1% seiner Zeit damit verbringt, diese Operation auszuführen, dann ... Sie bekommen den Punkt. Oder es können andere Mechanismen darunter wie OS-Optimierungen, CPU-Pipeline usw. vorhanden sein, die eine Operation 100 Mal wiederholen, um viel weniger als 100 Mal mehr zu verbrauchen. Was Sie tun müssen, ist Profil zuerst! Finden Sie die heißen Schleifen und optimieren Sie diese! Optimiere die Schleife/Funktion, die das Programm 60% seiner Zeit verbringt.
Noch wichtiger ist, suchen Sie nach High-Level-Optimierungen, damit Ihr Code weniger Arbeit leisten kann, anstatt nur die gleiche Arbeit schneller zu erledigen.
Ich würde sagen, dass der erste ASM-Code länger ist als der zweite, so dass es etwas länger dauern kann. – ForceBru
Versuchen Sie Folgendes: https: //en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax –
Sie müssen wirklich Zeit sie zu finden, und natürlich, dass das Ergebnis gilt nur für diese Maschine an der Adresse, wo Sie die Tests gefunden. Sie sollten auch versuchen, zu optimieren, wenn Sie kompilieren. Es kann einen Teil dieses Codes und einige der Zugriffe auf beide Tests reduzieren. –