Ich habe eine Frage zur C-Compiler-Optimierung und wann / wie Schleifen in Inline-Funktionen abgerollt werden.
Ich entwickle einen numerischen Code, der so etwas wie das folgende Beispiel macht. Im Grunde würde my_for()
eine Art Schablone berechnen und op()
aufrufen, um etwas mit den Daten in my_type *arg
für jedes i
zu tun. Hier fügt my_func()
die my_for()
ein, erstellt das Argument und sendet den Funktionszeiger an my_op()
... Wer ist der Job, den i
th double für jedes der ( arg->n
) Doppel-Arrays% co_de zu ändern %.
Das funktioniert gut. Die Funktionen sind inlining wie sie sollten und der Code ist (fast) so effizient wie alles inline in einer einzigen Funktion geschrieben und entrollt die arg->dest[j]
Schleife, ohne irgendeine Art von j
.
Hier ist die Verwirrung: Wenn ich my_type Arg
anstatt int const n = 2;
in int const n = arg->n;
einstelle, wird der Code so schnell wie die ausgerollte Einzelfunktionsversion. Die Frage ist also: Warum? Wenn alles in my_op()
eingezeichnet ist, warum sieht der Compiler dann nicht, dass ich my_func()
wirklich definiere? Außerdem gibt es keine Verbesserung, wenn ich die Grenze für Arg.n = 2
loop j
explizit festlege, was nach dem Inlining genauso aussehen sollte wie das schnellere arg->n
. Ich habe auch versucht, int const n = 2;
überall zu verwenden, um diese Konstante wirklich dem Compiler zu signalisieren, aber ich will die Schleife einfach nicht abwickeln.
In meinem Zahlencode entspricht dies einem Leistungseinbruch von etwa 15%. Wenn es darauf ankommt, werden my_type const
und diese n=4
-Schleifen in einigen bedingten Zweigen in j
angezeigt.
Ich kompiliere mit ICC 12.1.5 20120612. Ich probierte op()
. Hier sind meine Compiler-Optionen (habe ich irgendwelche guten vermisst?):
#pragma unroll
Danke!
Nun, offensichtlich ist der Compiler nicht 'schlau' genug, um die Konstante n
zu propagieren und die for
Schleife zu entrollen. Tatsächlich spielt es auf Nummer sicher, da arg->n
zwischen Instanziierung und Verwendung wechseln kann.
Um eine konsistente Leistung über Compiler-Generationen hinweg zu erreichen und das Maximum aus Ihrem Code herauszuquetschen, führen Sie das Abwickeln manuell aus.
Was Menschen in solchen Situationen (Leistung ist König) tun, ist auf Makros angewiesen.
Makros werden in Debug-Builds "inline" (nützlich) und können mithilfe von Makroparametern (zu einem bestimmten Zeitpunkt) templatiert werden. Makroparameter, die Kompilierzeitkonstanten sind, bleiben garantiert auf diese Weise erhalten.
Es ist schneller, weil Ihr Programm der Variablen keinen Speicher zuweist.
Wenn Sie unbekannte Werte nicht bearbeiten müssen, werden sie so behandelt, als wären sie #define constant 2
mit der Typprüfung. Sie werden nur während der Kompilierung hinzugefügt.
Könnten Sie bitte eines der beiden Tags wählen (ich meine C oder C ++), es ist verwirrend, weil die Sprachen const
Werte anders behandeln - C behandelt sie wie normale Variablen, deren Wert einfach nicht geändert werden kann C ++ sie haben oder haben keinen Speicher zugewiesen abhängig vom Kontext (wenn Sie ihre Adresse benötigen oder wenn Sie sie berechnen müssen, wenn das Programm ausgeführt wird, dann wird Speicher zugeordnet).
Quelle: "Denken in C ++". Kein genaues Zitat.
Tags und Links optimization c inline icc