Wie viele GCC-Optimierungsstufen gibt es?

Lesezeit: 10 Minuten

Benutzeravatar des Neuromancers
Neuromant

Wie viele GCC Optimierungsstufen gibt es?

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

Wenn ich eine wirklich große Zahl verwende, wird es nicht funktionieren.

Allerdings habe ich es versucht

gcc -O100

und es kompiliert.

Wie viele Optimierungsstufen gibt es?

  • @minitech Welchen FM schaust du dir an? Sogar mit man gcc auf Cygwin (12000 ungerade Zeilen) können Sie suchen -O und finden Sie alles, was die Antworten unten angeben, und noch einige mehr.

    – Jens

    25. Juli 2012 um 13:32 Uhr

  • @minmaxavg Nachdem ich die Quelle gelesen habe, stimme ich Ihnen nicht zu: alles größer als 3 ist das gleiche wie 3 (Solange nicht int Überlauf). Siehe meine Antwort.

    – Ciro Santilli OurBigBook.com

    18. Mai 2015 um 16:17 Uhr

  • Tatsächlich hat GCC viele andere Flags zur Feinabstimmung von Optimierungen. -fomit-stack-pointer ändert den generierten Code.

    – Basile Starynkevitch

    25. Juni 2015 um 16:27 Uhr


Glens Benutzer-Avatar
Tal

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

Die Originalversion dieser Antwort gab an, dass es 7 Optionen gab. GCC wurde inzwischen hinzugefügt -Og um die Summe auf 8 zu bringen.

Von dem Manpage:

  • -O (Gleich wie -O1)
  • -O0 (keine Optimierung durchführen, die Standardeinstellung, wenn keine Optimierungsstufe angegeben ist)
  • -O1 (minimal optimieren)
  • -O2 (mehr optimieren)
  • -O3 (noch mehr optimieren)
  • -Ofast (Optimieren Sie sehr aggressiv bis zu dem Punkt, an dem die Standardkonformität gebrochen wird)
  • -Og (Optimieren Sie das Debugging-Erlebnis. -Og ermöglicht Optimierungen, die das Debugging nicht beeinträchtigen. Es sollte die Optimierungsstufe der Wahl für den standardmäßigen Bearbeitungs-Kompilierungs-Debug-Zyklus sein und ein angemessenes Optimierungsniveau bieten, während eine schnelle Kompilierung und ein gutes Debugging-Erlebnis beibehalten werden. )
  • -Os (Auf Größe optimieren. -Os ermöglicht alles -O2 Optimierungen, die die Codegröße normalerweise nicht erhöhen. Es führt auch weitere Optimierungen durch, um die Codegröße zu reduzieren.
    -Os deaktiviert die folgenden Optimierungs-Flags: -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 anmerkt, OS X hat -Oz.

  • Wenn Sie unter Mac OS X entwickeln, gibt es eine zusätzliche -Oz Einstellung, die “größer optimieren aggressiver als -Os“: developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/…

    – Pauldoo

    5. Mai 2010 um 10:54 Uhr

  • Hinweis: O3 ist nicht unbedingt besser als O2, auch wenn der Name dies vermuten lässt. Probieren Sie beides aus.

    – Johann D

    19. September 2013 um 14:04 Uhr


  • @pauldoo 404-Seite, durch archive.org ersetzen

    – noɥʇʎʀʎzɐɹƆ

    6. Juli 2016 um 16:58 Uhr

  • @pauldoo funktionierender Link gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Optimize-Options.html

    – Max MacLeod

    9. Juli 2021 um 12:53 Uhr

  • Das Aufrufen von “Os” für die Größe optimieren ist meiner Meinung nach irreführend, da es immer noch hauptsächlich auf Geschwindigkeit optimiert, aber bestimmte Optimierungen nur überspringt oder ändert, die andernfalls zu einer Erhöhung der Codegröße führen könnten. Sie haben dies in Ihrem Text gut genug erklärt und nur auf einen Ärger hingewiesen, den ich im Allgemeinen habe, indem Sie sagen, dass dies “auf Größe optimieren” bedeutet, was impliziert, dass dies das Gegenteil von Optimierung auf Geschwindigkeit ist. “O0” sollte niemals verwendet werden, da es lächerlichen Code generiert, wie etwas von einem Compiler aus den 1970er Jahren, und so ziemlich jeder verbleibende Grund, es zu verwenden, ist jetzt, da “Og” existiert, weg

    – Thomas Rutter

    11. August 2021 um 7:08 Uhr


Ciro Santilli Benutzeravatar von OurBigBook.com
Ciro Santilli OurBigBook.com

Lassen Sie uns den Quellcode von GCC 5.1 interpretieren

Wir werden versuchen zu verstehen, was passiert -O100da es auf der Manpage nicht klar ist.

Wir kommen zu dem Schluss, dass:

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

Konzentrieren Sie sich auf Unterprogramme

Denken Sie zunächst daran, dass GCC nur ein Frontend für ist cpp, as, cc1, collect2. Eine schnelle ./XXX --help sagt das nur collect2 und cc1 nehmen -Okonzentrieren wir uns also 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.

Also -O wurde an beide weitergeleitet cc1 und collect2.

O gemeinsam.opt

common.opt ist ein GCC-spezifisches CLI-Optionsbeschreibungsformat, das in beschrieben wird Interne Dokumentation und nach C übersetzt von opth-gen.awk und 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 angeben O Optionen. Beachten Sie, wie -O<n> ist in einer anderen Familie als die andere Os, Ofast und Og.

Wenn wir bauen, erzeugt dies a options.h Datei, die enthält:

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

Als Bonus, während wir danach greifen \bO\n Innerhalb common.opt wir bemerken die Zeilen:

-optimize
Common Alias(O)

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

Wo OPT_O verwendet wird

Jetzt grep wir:

git grep -E '\bOPT_O\b'

was uns auf zwei Dateien verweist:

Lassen Sie uns zuerst aufspüren opts.c

opts.c:default_options_optimization

Alle opts.c Verwendungen finden im Inneren statt: default_options_optimization.

Wir grep backtrack, 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:

  • tut integral_argument was ruft atoi auf der entsprechenden Zeichenfolge OPT_O um das Eingabeargument zu analysieren
  • speichert den Wert im Inneren opts->x_optimize wo opts ist ein struct gcc_opts.

struct gcc_opts

Nachdem wir vergeblich herumgetastet haben, bemerken wir das struct wird auch bei generiert options.h:

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

wo x_optimize kommt aus den Zeilen:

Variable
int optimize

anwesend in common.optund das options.c:

struct gcc_options global_options;

Wir vermuten also, dass dies den gesamten globalen Status der Konfiguration enthält, und int x_optimize ist der Optimierungswert.

255 ist ein internes Maximum

in opts.c:integral_argument, atoi wird auf das Eingabeargument angewendet, also INT_MAX ist eine Obergrenze. Und wenn Sie etwas Größeres angeben, scheint es, dass GCC C undefiniertes Verhalten ausführt. Autsch?

integral_argument auch dünn wickeln atoi und weist das Argument zurück, wenn irgendein Zeichen keine Ziffer ist. Negative Werte scheitern also elegant.

Zurück zu opts.c:default_options_optimizationsehen wir die Zeile:

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

damit die Optimierungsebene abgeschnitten wird 255. Während des Lesens opth-gen.awk Ich war 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;

was die Kürzung erklärt: die Optionen müssen auch weitergeleitet werden cl_optimizationdie a verwendet char um Platz zu sparen. 255 ist also eigentlich ein internes Maximum.

opts.c:maybe_default_options

Zurück zu opts.c:default_options_optimizationstoßen wir auf maybe_default_options was interessant klingt. Wir betreten es, 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 Kontrollen, was darauf hindeutet 3 ist das größtmögliche.

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 Ebenen gibt.

opts.c:default_options_table

opt_levels ist so interessant, dass wir grep OPT_LEVELS_3_PLUSund komm vorbei opts.c:default_options_table:

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 },
    [...]
}

also hier ist die -On zu einer bestimmten Optimierungszuordnung, die in den Dokumenten erwähnt wird, codiert ist. Nett!

Stellen Sie sicher, dass x_optimize nicht mehr verwendet werden kann

Die Hauptverwendung von x_optimize war, andere spezifische Optimierungsoptionen wie einzustellen -fdefer_pop wie auf der Manpage dokumentiert. Gibt es noch mehr?

Wir grep, und finde noch ein paar mehr. Die Anzahl ist gering, und bei manueller Überprüfung sehen wir, dass jede Verwendung höchstens a bewirkt x_optimize >= 3also gilt unsere Schlussfolgerung.

lto-wrapper.c

Jetzt gehen wir zum zweiten Vorkommen von OPT_Owas drin war lto-wrapper.c.

LTO bedeutet Link Time Optimization, die, wie der Name schon sagt, eine benötigen wird -O Option und wird verlinkt collec2 (was im Grunde ein Linker ist).

Tatsächlich ist die erste Zeile von lto-wrapper.c sagt:

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

In dieser Datei ist die OPT_O Vorkommnisse scheinen nur den Wert zu normalisieren O um es weiterzugeben, also sollte es uns gut gehen.

  • Sehr ausführliche Antwort, beeindruckt! GCC unter der Haube.

    – pmor

    22. Dezember 2020 um 22:48 Uhr


Benutzeravatar von Demi
Demi

Sieben verschiedene Ebenen:

  • -O0 (Standard): Keine Optimierung.

  • -O oder -O1 (das Gleiche): Optimieren, aber nicht zu viel Zeit aufwenden.

  • -O2: Aggressiver optimieren

  • -O3: Am aggressivsten optimieren

  • -Ofast: Gleichwertig -O3 -ffast-math. -ffast-math löst nicht standardkonforme Gleitkommaoptimierungen aus. Dadurch kann der Compiler vorgeben, dass Gleitkommazahlen unendlich genau sind und dass die Algebra auf ihnen den Standardregeln der Algebra mit reellen Zahlen folgt. Es weist den Compiler auch an, die Hardware anzuweisen, Denormals auf Null zu spülen und Denormals als Null zu behandeln, zumindest auf einigen Prozessoren, einschließlich x86 und x86-64. Denormals 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 aufgrund des besseren I-Cache-Verhaltens tatsächlich die Geschwindigkeit verbessern.

  • -Og: Optimieren, aber nicht in das Debugging eingreifen. Dies ermöglicht eine nicht peinliche Leistung für Debug-Builds und soll ersetzen -O0 für Debug-Builds.

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.

  • Um den anderen Antworten gerecht zu werden, existierten weder -Ofast noch -Og, als diese Antworten geschrieben wurden.

    – janeb

    17. Juni 2013 um 19:15 Uhr

  • Warum also -O100 dann kompilieren?

    – einpoklum

    27. Februar 2016 um 9:24 Uhr

  • @einpoklum, weil GCC alles über -O3 als gleich -O3 behandelt.

    – Demi

    27. Februar 2016 um 19:25 Uhr

  • Leider erhalten Sie im Debugger mit -Og immer noch eine Menge . Stepping springt immer noch zufällig herum. Es ist IMHO nutzlos.

    – doug65536

    23. Oktober 2017 um 5:00 Uhr

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

1423220cookie-checkWie viele GCC-Optimierungsstufen gibt es?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy