Hoeveel GCC-optimalisatieniveaus zijn er?

Hoeveel GCCoptimalisatieniveaus zijn er?

Ik heb gcc -O1, gcc -O2, gcc -O3 en gcc -O4 geprobeerd

Als ik een heel groot aantal gebruik, werkt het niet.

Ik heb het echter geprobeerd

gcc -O100

en het is gecompileerd.

Hoeveel optimalisatieniveaus zijn er?


Antwoord 1, autoriteit 100%

Om pedant te zijn, er zijn 8 verschillende geldige -O-opties die je aan gcc kunt geven, hoewel er enkele zijn die hetzelfde betekenen.

In de originele versie van dit antwoord stond dat er 7 opties waren. GCC heeft sindsdien -Ogtoegevoegd om het totaal op 8 te brengen

Van de man-pagina:

  • -O(Hetzelfde als -O1)
  • -O0(doe geen optimalisatie, de standaardinstelling als er geen optimalisatieniveau is opgegeven)
  • -O1(minimaal optimaliseren)
  • -O2(meer optimaliseren)
  • -O3(nog meer optimaliseren)
  • -Ofast(zeer agressief optimaliseren tot het punt van het breken van de standaardcompliance)
  • -Og(Optimaliseer de foutopsporingservaring. -Og maakt optimalisaties mogelijk die de foutopsporing niet verstoren. Het zou de
    optimalisatieniveau naar keuze voor de standaard cyclus bewerken-compileren-foutopsporing, met een redelijk niveau van optimalisatie
    met behoud van een snelle compilatie en een goede foutopsporingservaring.)
  • -Os(Optimaliseren voor grootte. -Osmaakt alle -O2-optimalisaties mogelijk die normaal gesproken de codegrootte niet vergroten. Het presteert ook verder optimalisaties
    ontworpen om de codegrootte te verkleinen.
    -Osschakelt de volgende optimalisatievlaggen uit: -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)

Er kunnen ook platformspecifieke optimalisaties zijn, zoals @pauldoo opmerkt, OS X heeft -Oz


Antwoord 2, autoriteit 34%

Laten we de broncode van GCC 5.1 interpreteren

We zullen proberen te begrijpen wat er gebeurt op -O100, aangezien het niet duidelijk is op de man-pagina.

We zullen concluderen dat:

  • alles boven -O3tot INT_MAXis hetzelfde als -O3, maar dat kan in de toekomst gemakkelijk veranderen, dus doe het’ vertrouw er niet op.
  • GCC 5.1 voert ongedefinieerd gedrag uit als u gehele getallen invoert die groter zijn dan INT_MAX.
  • het argument kan alleen cijfers bevatten, anders mislukt het gracieus. Dit sluit met name negatieve gehele getallen uit zoals -O-1

Focus op subprogramma’s

Onthoud eerst dat GCC slechts een front-end is voor cpp, as, cc1, collect2. Een snelle ./XXX --helpzegt dat alleen collect2en cc1-Ogebruiken, dus laten we ons concentreren op hen.

En:

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

geeft:

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.

dus -Ois doorgestuurd naar zowel cc1als collect2.

O in common.opt

common.optis een GCC-specifieke CLI-optiebeschrijvingsindeling beschreven in de internals documentatieen vertaald naar C door opth-gen.awken optc-gen.awk.

Het bevat de volgende interessante regels:

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 Oopties specificeren. Merk op hoe -O<n>in een aparte familie zit van de andere Os, Ofasten Og.

Als we bouwen, genereert dit een options.h-bestand dat het volgende bevat:

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

Als een bonus, terwijl we bezig zijn met \bO\nbinnen common.opt, zien we de regels:

-optimize
Common Alias(O)

wat ons leert dat --optimize(dubbel streepje omdat het begint met een streepje -optimizein het bestand .opt) een ongedocumenteerde alias voor -Odie kan worden gebruikt als --optimize=3!

Waar OPT_O wordt gebruikt

Nu grep:

git grep -E '\bOPT_O\b'

wat ons naar twee bestanden verwijst:

Laten we eerst opts.c

opsporen

opts.c:default_options_optimization

Alle gebruik van opts.cvindt plaats binnen: default_options_optimization.

We gaan terug om te zien wie deze functie aanroept, en we zien dat het enige codepad is:

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

en main.cis het toegangspunt van cc1. Goed!

Het eerste deel van deze functie:

  • doet integral_argumentdie atoiaanroept op de string die overeenkomt met OPT_Oom het invoerargument te ontleden
  • slaat de waarde op in opts->x_optimizewaarbij optseen struct gcc_optsis.

struct gcc_opts

Na tevergeefs gepuzzel merken we dat deze structook wordt gegenereerd op options.h:

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

waar x_optimizevan de regels komt:

Variable
int optimize

aanwezig in common.opt, en dat options.c:

struct gcc_options global_options;

dus we veronderstellen dat dit de volledige globale status van de configuratie bevat, en int x_optimizeis de optimalisatiewaarde.

255 is een intern maximum

in opts.c:integral_argumentwordt atoitoegepast op het invoerargument, dus INT_MAXis een bovengrens. En als je iets groters plaatst, lijkt het erop dat GCC C ongedefinieerd gedrag uitvoert. Au?

integral_argumentwikkelt atoiook dun in en verwerpt het argument als een teken geen cijfer is. Negatieve waarden mislukken dus gracieus.

Terug naar opts.c:default_options_optimization, zien we de regel:

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

zodat het optimalisatieniveau wordt afgekapt tot 255. Tijdens het lezen van opth-gen.awkkwam ik het volgende tegen:

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

en op de gegenereerde options.h:

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

wat verklaart waarom de truncatie: de opties moeten ook worden doorgestuurd naar cl_optimization, die een chargebruikt om ruimte te besparen. Dus 255 is eigenlijk een intern maximum.

opts.c:maybe_default_options

Terug naar opts.c:default_options_optimization, komen we maybe_default_optionstegen, wat interessant klinkt. We voeren het in, en dan maybe_default_optionwaar we een grote switch bereiken:

switch (default_opt->levels)
  {
  [...]
  case OPT_LEVELS_1_PLUS:
    enabled = (level >= 1);
    break;
  [...]
  case OPT_LEVELS_3_PLUS:
    enabled = (level >= 3);
    break;

Er zijn geen >= 4controles, wat aangeeft dat 3de grootst mogelijke is.

Vervolgens zoeken we naar de definitie van OPT_LEVELS_3_PLUSin 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! Dit is een sterke indicator dat er maar 3 niveaus zijn.

opts.c:default_options_table

opt_levelsis zo interessant, dat we OPT_LEVELS_3_PLUSgrijpen en opts.c:default_options_table:

tegenkomen

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

dus dit is waar de -Onnaar specifieke optimalisatietoewijzing die in de documenten wordt genoemd, is gecodeerd. Leuk!

Zorg ervoor dat x_optimize niet meer gebruikt kan worden

Het belangrijkste gebruik van x_optimizewas om andere specifieke optimalisatie-opties in te stellen, zoals -fdefer_popzoals beschreven op de man-pagina. Zijn er nog meer?

Wij grep, en vinden er nog een paar. Het aantal is klein en bij handmatige inspectie zien we dat elk gebruik maximaal een x_optimize >= 3oplevert, dus onze conclusie geldt.

lto-wrapper.c

Nu gaan we voor de tweede keer dat OPT_Ovoorkomt, namelijk in lto-wrapper.c.

LTO betekent Link Time Optimization, wat, zoals de naam al doet vermoeden, een -O-optie nodig heeft, en zal worden gekoppeld aan collec2(wat in feite een linker is) .

In feite zegt de eerste regel van lto-wrapper.c:

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

In dit bestand lijken de OPT_O-exemplaren alleen de waarde van Ote normaliseren om het door te geven, dus we zouden in orde moeten zijn.


Antwoord 3, autoriteit 24%

Zeven verschillende niveaus:

  • -O0(standaard): Geen optimalisatie.

  • -Oof -O1(hetzelfde): Optimaliseer, maar besteed niet te veel tijd.

  • -O2: agressiever optimaliseren

  • -O3: Optimaliseer het meest agressief

  • -Ofast: gelijk aan -O3 -ffast-math. -ffast-mathactiveert niet-conforme drijvende-komma-optimalisaties. Hierdoor kan de compiler doen alsof getallen met drijvende komma oneindig nauwkeurig zijn en dat de algebra daarop de standaardregels van de algebra met reële getallen volgt. Het vertelt de compiler ook om de hardware te vertellen om denormalen naar nul te spoelen en denormals als nul te behandelen, althans op sommige processors, waaronder x86 en x86-64. Denormalen veroorzaken een langzaam pad op veel FPU’s, en dus kan het een grote prestatiewinst zijn om ze als nul te behandelen (wat niet het langzame pad activeert).

  • -Os: optimaliseren voor codegrootte. Dit kan in sommige gevallen zelfs de snelheid verbeteren, vanwege een beter I-cache-gedrag.

  • -Og: Optimaliseer, maar verstoor het debuggen niet. Dit zorgt voor niet-gênante prestaties voor debug-builds en is bedoeld om -O0te vervangen voor debug-builds.

Er zijn ook andere opties die door geen van deze zijn ingeschakeld en die afzonderlijk moeten worden ingeschakeld. Het is ook mogelijk om een optimalisatieoptie te gebruiken, maar schakel specifieke vlaggen uit die door deze optimalisatie zijn ingeschakeld.

Zie de GCC-website voor meer informatie.


Antwoord 4, autoriteit 2%

Vier (0-3): zie de GCC 4.4.2 handleiding. Alles wat hoger is, is gewoon -O3, maar op een gegeven moment overschrijdt u de limiet van de variabele grootte.

Other episodes