Doppelte Kompilierung von C-Code zur Verkürzung der Ausführungszeiten

Doppelte Kompilierung von C-Code zur Verkürzung der Ausführungszeiten


Laut diesem Artikel/Video:



Wenn Sie sich das Video auf dem Link angesehen haben, können Sie sehen, dass diese Methode die Geschwindigkeit einer ausführbaren Datei verdoppelt. Ich bin mir nicht sicher, ob das allgemein gilt.


Meine Frage ist:Warum passiert das?


Bonus:Was passiert, wenn wir ein kompiliertes Programm genau neu kompilieren?


Antworten:


Das ist ein Scherz.


Weder gcc kein anderer Compiler ist in der Lage, Objektcode zu lesen, ihn zu „kompilieren“ und Objektcode zu erzeugen, der schneller ist.


Am nächsten kommt die rückkopplungsgesteuerte Kompilierung, bei der Sie zuerst ein Programm mit Instrumentierung kompilieren (z. B. gcc --fprofile-generate ), führen Sie dieses Programm aus und generieren Sie eine Datendatei über den Lauf (z. B. foo.gcda ) und kompilieren Sie dann das Programm erneut mit demselben Quellcode und der Datendatei als Eingabe für den Compiler (z. B. gcc --fprofile-use ). Dies kann zu ziemlich bescheidenen Beschleunigungen führen, meiner Erfahrung nach typischerweise zwischen 5 % und 10 %.


Angenommen, Sie haben eine lange Kette von 50 if … else if Konstrukte (die nicht als switch umstrukturiert werden können ). Dies tritt beispielsweise häufig in Monte-Carlo-Simulationen auf. Wenn Sie ein einigermaßen erfahrener Programmierer sind, werden Sie diese wahrscheinlich so anordnen, dass der Zweig, der am häufigsten verwendet wird, zuerst erscheint. Die Idee dahinter ist, dass Sie zur Laufzeit keine Zeit damit verschwenden, 30 weniger wahrscheinliche Verzweigungen in Betracht zu ziehen, bevor Sie die wahrscheinlichste in Betracht ziehen. Darüber hinaus werden Sie versuchen, diese Verzweigungen von der wahrscheinlichsten zur unwahrscheinlichsten zu ordnen, sodass im Durchschnitt die geringste Anzahl von Verzweigungstests ausgeführt wird, bevor die richtige gefunden wird.


Beachten Sie, dass der Compiler keine Grundlage hat, diese Zweige zu ordnen, da die Information, dass einer wahrscheinlicher ist als der andere, einfach nicht im Quellcode enthalten ist, also ist das Beste, was getan werden kann, die Zweige in der Quellreihenfolge auszugeben.


Bei der klassischen rückkopplungsgesteuerten Kompilierung erstellen Sie zunächst eine instrumentierte Version der ausführbaren Datei, die (wenn Sie sie ausführen) aufzeichnet, wie oft jeder Zweig in eine Datendatei übernommen (oder nicht) wird. Beim zweiten Kompilieren hat der Compiler empirische Daten aus der Laufzeit (das es normalerweise nicht hat), das verwendet werden kann, um Tests neu zu ordnen und Verzweigungshinweise einzufügen, die den Code schneller laufen lassen ... zumindest bei ähnlichen Arbeitslasten wie das profilierte Testprogramm.


Ich bin mir sicher, dass die moderne Feedback-gesteuerte Kompilierung erheblich ausgeklügelter ist, aber das ist die allgemeine Idee.