Wie überzeuge ich GCC, eine Schleife aufzulösen, in der die Anzahl der Iterationen bekannt ist, aber groß?
Ich kompiliere mit -O3
.
Der fragliche echte Code ist natürlich komplexer, aber hier ist ein heruntergekommenes Beispiel, das dasselbe Verhalten hat:
%Vor% ... Wenn CONSTANT_COUNT
als 8 (oder weniger) definiert ist, dann wird GCC die Schleife ausrollen, die Konstanten propagieren und die gesamte Funktion auf ein einfaches return <value>;
reduzieren. Wenn andererseits CONSTANT_COUNT
9 (oder größer) ist, wird die Schleife nicht abgerollt, und GCC erzeugt eine Binärdatei, die Schleifen ausführt, die Konstanten liest und sie zur Laufzeit hinzufügt - obwohl theoretisch die Funktion könnte noch optimiert werden, um nur eine Konstante zurückzugeben. (Ja, ich habe mir die Dekompilierung der Binärdatei angesehen.)
Wenn ich manuell die Schleife abrollte, wie folgt:
%Vor%Oder das:
%Vor%... dann ist die Funktion bis zur Rückgabe einer Konstante optimiert. Daher scheint GCC in der Lage zu sein, die konstante Ausbreitung für größere Schleifen zu handhaben, sobald sie einmal ausgerollt sind; Das Auflegen scheint GCC nur dazu zu bringen, in Betracht zu ziehen, die längere Schleife überhaupt abzurollen.
Allerdings sind weder Hand-entrolling noch BOOST_PP_REPEAT
praktikable Optionen, da es einige -Fällen gibt, in denen CONSTANT_COUNT
ein Laufzeitausdruck und gleich ist Code muss für diese Fälle immer noch ordnungsgemäß funktionieren. (In diesen Fällen ist die Leistung nicht so kritisch.)
Ich arbeite in C (nicht in C ++), also sind weder Template-Metaprogrammierung noch constexpr
für mich verfügbar.
Ich habe -funroll-loops
, -funroll-all-loops
, -fpeel-loops
versucht und große Werte für max-unrolled-insns
, max-average-unrolled-insns
, max-unroll-times
, max-peeled-insns
, max-peel-times
, max-completely-peeled-insns
und% festgelegt. co_de%, von denen keine zu unterscheiden scheint.
Ich verwende GCC 4.8.2, unter Linux, x86_64.
Irgendwelche Ideen? Gibt es eine Flagge oder einen Parameter, der mir fehlt ...?
Ich bin mir nicht sicher, ob diese Problemumgehung auf Ihr tatsächliches Problem anwendbar ist, aber ich habe festgestellt, dass GCC 4.9.0 20140604 (Vorabversion) auf einem x86_64 mit Parabola GNU / Linux die folgende Schleife bis einschließlich CONSTANT_COUNT == 33
/ p>
%Vor%
Ich habe nur das -O3
-Flag übergeben. Der Assemblierungscode für get_sum
ist wirklich nur
Ich habe es nicht versucht, aber vielleicht kann das Muster noch weiter ausgedehnt werden.
Es scheint mir merkwürdig, dass das funktioniert - zumindest für meine menschlichen Augen - sieht der Code jetzt viel komplexer aus. Leider ist es eine eher aufdringliche Art, das Abrollen zu erzwingen. Ein Compiler-Flag wäre viel schöner gewesen.
GCC hat eine große Menge an obskuren Parametern und Programmargumenten bezüglich Schleifen-Abrollung (und Optimierungen) ). Du könntest mit -funroll-loops
, -funroll-all-loops
, --param
name = wert spielen (zB mit name ist max-unroll-times
....) usw.
Die Reihenfolge der Argumente für gcc
ist sehr wichtig. Wahrscheinlich möchtest du zuerst -O3
und danach die seltsamen Optionen setzen.
Die Erhöhung des Abrollens verbessert jedoch nicht immer die Leistung.
Zu guter Letzt könnten Sie Ihr eigenes GCC-Plugin programmieren, das die Abwicklungskriterien ändern würde.
Clever mit __builtin_prefetch
könnte die Leistung verbessern, siehe diese Antwort (aber verwenden Sie sie sorglos wird die Leistung beeinträchtigen
Sie müssen einen Benchmark erstellen. Mein Gefühl ist, dass vorzeitige Mikro-Optimierung ein großer Verlust Ihrer Zeit ist.
Tags und Links c gcc loop-unrolling