wake-up-neo.com

Wie viele GCC-Optimierungsstufen gibt es?

Wie viele GCC Optimierungsstufen gibt es?

Ich habe gcc -O1, gcc -O2, gcc -O3 und gcc -O4 ausprobiert

Wenn ich eine sehr große Zahl benutze, funktioniert das nicht.

Ich habe es jedoch versucht

gcc -O100

und es kompiliert.

Wie viele Optimierungsstufen gibt es?

86
neuromancer

Um pedantisch zu sein, gibt es 8 verschiedene gültige -O-Optionen, die Sie gcc geben können, obwohl es einige gibt, die dasselbe bedeuten.

Die ursprüngliche Version dieser Antwort gab an, dass es 7 Optionen gab. GCC hat seitdem -Og Hinzugefügt, um die Summe auf 8 zu bringen

Aus der man page:

  • -O (Gleich wie -O1)
  • -O0 (Keine Optimierung durchführen, der Standardwert, wenn keine Optimierungsstufe angegeben ist)
  • -O1 (Minimal optimieren)
  • -O2 (Mehr optimieren)
  • -O3 (Noch mehr optimieren)
  • -Ofast (Optimierung sehr aggressiv bis zum Verstoß gegen die Standardkonformität)
  • -Og (Debugging-Erfahrung optimieren. -Og aktiviert Optimierungen, die das Debugging nicht beeinträchtigen. Es sollte die Optimierungsstufe der Wahl für den Standardzyklus zum Bearbeiten, Kompilieren und Debuggen sein und ein angemessenes Optimierungsniveau bei gleichzeitiger Beibehaltung der schnellen Kompilierung bieten und eine gute Debug-Erfahrung.)
  • -Os (Für Größe optimieren. -Os Aktiviert alle -O2 - Optimierungen, bei denen die Codegröße normalerweise nicht erhöht wird. Außerdem werden weitere Optimierungen zur Reduzierung der Codegröße durchgeführt. -Os deaktiviert die folgenden Optimierungsflags: -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)

Es kann auch plattformspezifische Optimierungen geben, wie @ pauldoo feststellt, OS X hat -Oz

120
Glen

Lassen Sie uns den Quellcode von GCC 5.1 interpretieren, um zu sehen, was auf -O100 Geschieht, da es auf der Manpage nicht klar ist.

Wir werden folgern, dass:

  • alles über -O3 bis INT_MAX ist dasselbe wie -O3, aber das könnte sich in Zukunft leicht ändern, verlassen Sie sich also nicht darauf.
  • GCC 5.1 führt undefiniertes Verhalten aus, wenn Sie Ganzzahlen eingeben, die größer als INT_MAX Sind.
  • das Argument kann nur Ziffern enthalten, oder es schlägt ordnungsgemäß fehl. Dies schließt insbesondere negative ganze Zahlen wie -O-1 Aus.

Fokus auf Unterprogramme

Denken Sie zunächst daran, dass GCC nur ein Front-End für cpp, as, cc1, collect2 Ist. Ein kurzer ./XXX --help Besagt, dass nur collect2 Und cc1-O Nehmen, also konzentrieren wir uns auf sie.

Und:

gcc -v -O100 main.c |& grep 100

gibt:

COLLECT_GCC_OPTIONS='-O100' '-v' '-mtune=generic' '-march=x86-64'
/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/5.1.0/cc1 [[noise]] hello_world.c -O100 -o /tmp/ccetECB5.

daher wurde -O sowohl an cc1 als auch an collect2 weitergeleitet.

O gemeinsam.opt

common.opt ist ein GCC-spezifisches CLI-Optionsbeschreibungsformat, das in der internen Dokumentation beschrieben und von opth-gen.awk und - in C übersetzt wird. optc-gen.awk .

Es enthält die folgenden interessanten Zeilen:

O
Common JoinedOrMissing Optimization
-O<number>  Set optimization level to <number>

Os
Common Optimization
Optimize for space rather than speed

Ofast
Common Optimization
Optimize for speed disregarding exact standards compliance

Og
Common Optimization
Optimize for debugging experience rather than speed or size

die alle O -Optionen angeben. Beachten Sie, wie sich -O<n> In einer anderen Familie als die anderen Os, Ofast und Og befindet.

Beim Erstellen wird eine options.h - Datei generiert, die Folgendes enthält:

OPT_O = 139,                               /* -O */
OPT_Ofast = 140,                           /* -Ofast */
OPT_Og = 141,                              /* -Og */
OPT_Os = 142,                              /* -Os */

Als Bonus bemerken wir, während wir in \bO\n Nach common.opt Suchen, die Zeilen:

-optimize
Common Alias(O)

was uns lehrt, dass --optimize (doppelter Gedankenstrich, weil er mit einem Gedankenstrich -optimize in der .opt - Datei beginnt) ein undokumentierter Alias ​​für -O ist, der verwendet werden kann als --optimize=3!

Wo OPT_O verwendet wird

Jetzt grüßen wir:

git grep -E '\bOPT_O\b'

was uns auf zwei Dateien verweist:

Finden wir zuerst opts.c

opts.c: default_options_optimization

Alle opts.c - Verwendungen finden innerhalb von default_options_optimization Statt.

Wir gehen zurück, um zu sehen, wer diese Funktion aufruft, und wir sehen, dass der einzige Codepfad ist:

  • main.c:main
  • toplev.c:toplev::main
  • opts-global.c:decode_opts
  • opts.c:default_options_optimization

und main.c ist der Einstiegspunkt von cc1. Gut!

Der erste Teil dieser Funktion:

  • bewirkt, dass integral_argumentatoi für die Zeichenfolge aufruft, die OPT_O entspricht, um das Eingabeargument zu analysieren
  • speichert den Wert in opts->x_optimize, wobei opts ein struct gcc_opts ist.

struct gcc_opts

Nachdem wir vergeblich gegriffen haben, stellen wir fest, dass dieses struct auch bei options.h Generiert wird:

struct gcc_options {
    int x_optimize;
    [...]
}

woher kommt x_optimize aus den Zeilen:

Variable
int optimize

vorhanden in common.opt und dass options.c:

struct gcc_options global_options;

wir vermuten also, dass dies der gesamte globale Konfigurationsstatus ist und int x_optimize der Optimierungswert ist.

255 ist ein internes Maximum

in opts.c:integral_argument wird atoi auf das Eingabeargument angewendet, sodass INT_MAX eine obere Grenze ist. Und wenn Sie etwas größer setzen, scheint es, dass GCC C undefiniertes Verhalten ausführt. Autsch?

integral_argument Schließt auch atoi dünn ein und weist das Argument zurück, wenn ein Zeichen keine Ziffer ist. Negative Werte scheitern also anmutig.

Zurück zu opts.c:default_options_optimization Sehen wir die Zeile:

if ((unsigned int) opts->x_optimize > 255)
  opts->x_optimize = 255;

so dass die Optimierungsstufe auf 255 gekürzt wird. Beim Lesen von opth-gen.awk War ich auf Folgendes gestoßen:

# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.

und auf dem generierten options.h:

struct GTY(()) cl_optimization
{
  unsigned char x_optimize;

das erklärt, warum die Kürzung: Die Optionen müssen auch an cl_optimization weitergeleitet werden, das ein char verwendet, um Platz zu sparen. 255 ist also tatsächlich ein internes Maximum.

opts.c: maybe_default_options

Zurück zu opts.c:default_options_optimization Stoßen wir auf maybe_default_options, Was interessant klingt. Wir geben es ein und dann maybe_default_option, Wo wir einen großen Schalter erreichen:

switch (default_opt->levels)
  {

  [...]

  case OPT_LEVELS_1_PLUS:
    enabled = (level >= 1);
    break;

  [...]

  case OPT_LEVELS_3_PLUS:
    enabled = (level >= 3);
    break;

Es gibt keine >= 4 - Prüfungen, was darauf hinweist, dass 3 Die größtmögliche ist.

Dann suchen wir nach der Definition von OPT_LEVELS_3_PLUS In common-target.h:

enum opt_levels
{
  OPT_LEVELS_NONE, /* No levels (mark end of array).  */
  OPT_LEVELS_ALL, /* All levels (used by targets to disable options
                     enabled in target-independent code).  */
  OPT_LEVELS_0_ONLY, /* -O0 only.  */
  OPT_LEVELS_1_PLUS, /* -O1 and above, including -Os and -Og.  */
  OPT_LEVELS_1_PLUS_SPEED_ONLY, /* -O1 and above, but not -Os or -Og.  */
  OPT_LEVELS_1_PLUS_NOT_DEBUG, /* -O1 and above, but not -Og.  */
  OPT_LEVELS_2_PLUS, /* -O2 and above, including -Os.  */
  OPT_LEVELS_2_PLUS_SPEED_ONLY, /* -O2 and above, but not -Os or -Og.  */
  OPT_LEVELS_3_PLUS, /* -O3 and above.  */
  OPT_LEVELS_3_PLUS_AND_SIZE, /* -O3 and above and -Os.  */
  OPT_LEVELS_SIZE, /* -Os only.  */
  OPT_LEVELS_FAST /* -Ofast only.  */
};

Ha! Dies ist ein starker Indikator dafür, dass es nur 3 Stufen gibt.

opts.c: default_options_table

opt_levels Ist so interessant, dass wir nach OPT_LEVELS_3_PLUS Greifen und auf opts.c:default_options_table Stoßen:

static const struct default_options default_options_table[] = {
    /* -O1 optimizations.  */
    { OPT_LEVELS_1_PLUS, OPT_fdefer_pop, NULL, 1 },
    [...]

    /* -O3 optimizations.  */
    { OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },
    [...]
}

hier wird also das in den Dokumenten erwähnte -On für die spezifische Optimierungszuordnung codiert. Nett!

Sicherstellen, dass x_optimize nicht mehr verwendet wird

Die Hauptverwendung von x_optimize Bestand darin, andere spezifische Optimierungsoptionen wie -fdefer_pop Festzulegen, wie auf der Manpage dokumentiert. Gibt es noch mehr

Wir grep und finden ein paar mehr. Die Anzahl ist gering, und bei manueller Überprüfung stellen wir fest, dass jede Verwendung höchstens einen x_optimize >= 3 Ergibt, so dass unsere Schlussfolgerung zutrifft.

lto-wrapper.c

Nun gehen wir zum zweiten Vorkommen von OPT_O Über, das in lto-wrapper.c Enthalten war.

LTO steht für Link Time Optimization (Linkzeitoptimierung), für die, wie der Name schon sagt, eine -O - Option erforderlich ist und die mit collec2 (Im Grunde ein Linker) verknüpft wird.

In der Tat steht in der ersten Zeile von lto-wrapper.c:

/* Wrapper to call lto.  Used by collect2 and the linker plugin.

In dieser Datei scheint das Auftreten von OPT_O Nur den Wert von O zu normalisieren, um ihn weiterzuleiten.

Sieben verschiedene Ebenen:

  • -O0 (Standard): Keine Optimierung.

  • -O Oder -O1 (Dasselbe): Optimieren, aber nicht zu viel Zeit aufwenden.

  • -O2: Optimieren Sie aggressiver

  • -O3: Am aggressivsten optimieren

  • -Ofast: Entspricht -O3 -ffast-math. -ffast-math Löst nicht standardkonforme Gleitkomma-Optimierungen aus. Auf diese Weise kann der Compiler vorgeben, dass Gleitkommazahlen unendlich genau sind und dass die Algebra auf ihnen den Standardregeln der reellen Zahlenalgebra folgt. Außerdem wird der Compiler angewiesen, die Hardware anzuweisen, die Denormale auf Null zu setzen und die Denormale zumindest auf einigen Prozessoren, einschließlich x86 und x86-64, als Null zu behandeln. Denormale lösen bei vielen FPUs einen langsamen Pfad aus, und daher kann es ein großer Leistungsgewinn sein, sie als Null zu behandeln (was den langsamen Pfad nicht auslöst).

  • -Os: Für Codegröße optimieren. Dies kann in einigen Fällen die Geschwindigkeit verbessern, da sich der I-Cache besser verhält.

  • -Og: Optimieren, aber das Debuggen nicht stören. Dies ermöglicht eine nicht peinliche Leistung für Debugbuilds und soll -O0 Für Debugbuilds ersetzen.

Es gibt auch andere Optionen, die von keiner dieser Optionen aktiviert werden und separat aktiviert werden müssen. Es ist auch möglich, eine Optimierungsoption zu verwenden, aber bestimmte Flags zu deaktivieren, die durch diese Optimierung aktiviert werden.

Weitere Informationen finden Sie auf der GCC-Website.

38
Demi

Four (0-3): Siehe GCC 4.4.2 manual . Alles, was höher ist, ist nur -O3, aber irgendwann werden Sie die variable Größenbeschränkung überschreiten.

3
Tom