2009-11-22 13 views
56

Quanti livelli di ottimizzazione GCC ci sono?Quanti livelli di ottimizzazione GCC ci sono?

ho provato -O1 gcc, gcc -O2, -O3 gcc, e gcc -O4

Se uso davvero un gran numero, non funzionerà.

Tuttavia, ho provato

gcc -O100 

e compilato.

Quanti livelli di ottimizzazione ci sono?

+3

@Jens: TFM è lungo 15.000 righe e non ha molto da dire su '-O' :) – Ryan

+13

@minitech Quale FM stai guardando? Anche con 'man gcc' su Cygwin (12000 righe dispari) puoi cercare' -O' e trovare tutte le risposte che seguono e poi alcune. – Jens

+1

@minmaxavg dopo aver letto la fonte, non sono d'accordo con te: qualsiasi cosa più grande di '3' è la stessa di' 3' (a patto che non abbia un overflow 'int'). Vedi [la mia risposta] (http://stackoverflow.com/a/30308151/895245). –

risposta

82

Per essere pedanti, ci sono 8 diverse opzioni -O valide che puoi dare a gcc, anche se ci sono alcune che significano la stessa cosa.

La versione originale di questa risposta ha dichiarato che c'erano 7 opzioni. GCC dal momento che ha aggiunto -Og per portare il totale a 8

Dal man page:

  • -O (Uguale a -O1)
  • -O0 (fare alcuna ottimizzazione, il default se non è specificato alcun livello di ottimizzazione)
  • -O1 (ottimizzazione minima)
  • -O2 (Ottimizza di più)
  • -O3 (ottimizzare ancora di più)
  • -Ofast (ottimizzare in modo molto aggressivo al punto di rottura rispetto standard)
  • -Og (Ottimizzare il debug esperienza. -Og consente ottimizzazioni che non interferiscono con il debug. Dovrebbe essere il livello ottimizzazione della scelta per il ciclo edit-compile-debug di serie, offrendo un livello ragionevole di ottimizzazione , pur mantenendo la compilazione veloce e una buona esperienza di debug.)
  • -Os (Ottimizza per dimensione. -Os consente a tutti -O2 . ottimizzazioni che non in genere aumentano le dimensioni del codice svolge, inoltre, ulteriori ottimizzazioni progettati per ridurre le dimensioni del codice -Os disabilita i seguenti flag di ottimizzazione:. -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)

ci possono essere anche ottimizzazioni specifiche della piattaforma, come @pauldoo note, OS X ha -Oz

+21

Se stai sviluppando su Mac OS X c'è un'impostazione aggiuntiva "-Oz" che "ottimizza le dimensioni in modo più aggressivo rispetto a" -Os "": http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools /gcc-4.0.1/gcc/Optimize-Options.html – pauldoo

+3

Nota: O3 non è necessariamente migliore di O2 anche se il nome lo suggerisce. Prova entrambi. –

+1

@pauldoo 404 pagina, sostituire con archive.org –

3

Quattro (0-3): vedere GCC 4.4.2 manual. Qualunque cosa più alta è solo -O3, ma ad un certo punto si supererà il limite della dimensione variabile.

+0

Ho esplorato il codice sorgente [nella mia risposta] (http://stackoverflow.com/a/30308151/895245) e sono d'accordo con te. Più pedante, GCC sembra fare affidamento su un comportamento indefinito 'atoi', seguito da un limite interno' 255 '. –

+0

Si prega di considerare di rimuovere la risposta, poiché è (almeno in questi giorni) errata. – einpoklum

29

sette livelli distinti:

  • -O0 (default): Nessuna ottimizzazione.

  • -O o -O1 (stessa cosa): Ottimizza, ma non passare troppo tempo.

  • -O2: ottimizzare in modo più aggressivo

  • -O3: Ottimizzare più aggressivamente

  • -Ofast: Equivalente a -O3 -ffast-math. -ffast-math attiva le ottimizzazioni in virgola mobile non conformi agli standard. Questo consente al compilatore di fingere che i numeri in virgola mobile sono infinitamente precisi, e che l'algebra sopra segue le regole standard di vera algebra numero. Si dice anche al compilatore di raccontare l'hardware per irrigare denormals a zero e trattare denormals come pari a zero, almeno su alcuni processori, tra cui x86 e x86-64. Denormals innescare un percorso lento su molti FPU, e così li trattano come zero (che non innescare il percorso lento) può essere una grande vittoria prestazioni.

  • -Os: Ottimizza per le dimensioni del codice. In alcuni casi questo può effettivamente migliorare la velocità, a causa del miglior comportamento della cache I.

  • -Og: Ottimizza, ma non interferisce con il debug. In questo modo le prestazioni non imbarazzante per build di debug ed è destinato a sostituire -O0 per build di debug.

Ci sono anche altre opzioni che non sono abilitate da nessuno di questi e devono essere abilitate separatamente. È anche possibile utilizzare un'opzione di ottimizzazione, ma disabilitare i flag specifici abilitati da questa ottimizzazione.

Per ulteriori informazioni, consultare il sito GCC.

+0

Infatti, anche se per essere giusti per le altre risposte, né -Ottimo né -Og esistevano quando quelle risposte sono state scritte – janneb

+0

Allora, perché '-O100' compila allora? – einpoklum

+2

@einpoklum perché GCC considera tutto sopra -O3 uguale a -O3. – Demi

25

Let's interpretare il codice sorgente di GCC 5.1 per vedere cosa succede su -O100 poiché non è chiaro sulla pagina man.

Dobbiamo concludere che:

  • qualsiasi cosa sopra -O3 fino al INT_MAX è lo stesso di -O3, ma che potrebbe facilmente cambiare in futuro, in modo da non fare affidamento su di esso.
  • GCC 5.1 esegue un comportamento non definito se si immettono numeri interi maggiori di INT_MAX.
  • l'argomento può contenere solo cifre o non funziona correttamente. In particolare, questo esclude interi negativi come -O-1

Focus on sottoprogrammi

Prima ricordare che GCC è solo un front-end per cpp, as, cc1, collect2. Un rapido ./XXX --help dice che solo collect2 e cc1 prendono -O, quindi concentriamoci su di essi.

E:

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

dà:

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. 

così -O è stata trasmessa sia cc1 e collect2.

O in common.opt

common.opt è un'opzione specifica CLI descrizione formato GCC descritto nella internals documentation e tradotto a C opth-gen.awk e optc-gen.awk.

Esso contiene le seguenti righe interessanti:

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 

che specificano tutte le opzioni O. Si noti come -O<n> si trovi in ​​una famiglia separata dall'altra Os, Ofast e Og.

Quando costruiamo, questo genera un file options.h che contiene:

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

Come bonus, mentre stiamo grep per \bO\n all'interno common.opt notiamo le linee:

-optimize 
Common Alias(O) 

che ci insegna che --optimize (doppio trattino perché inizia con un trattino -optimize sul file .opt) è un alias non documentato per -O che può essere utilizzato come --optimize=3!

Dove OPT_O viene utilizzato

Ora ci Grep:

git grep -E '\bOPT_O\b' 

che ci indica due file:

prima traccia

Let giù opts.c

opts.c: default_options_optimization

Tutti opts.c usi avvengono all'interno: default_options_optimization.

Abbiamo grep passo indietro per vedere chi chiama questa funzione, e vediamo che l'unico percorso di codice è:

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

e main.c è il punto di ingresso di cc1. Buona!

La prima parte di questa funzione:

  • fa integral_argument che invita atoi sulla stringa corrispondente al OPT_O per analizzare l'argomento di input
  • memorizza il valore all'interno opts->x_optimize dove opts è un struct gcc_opts.

struct gcc_opts

Dopo grep invano, notiamo che questo struct viene generata anche in options.h:

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

dove x_optimize viene dalle linee:

Variable 
int optimize 

prese nt in common.opt, e che options.c:

struct gcc_options global_options; 

così abbiamo indovinare che questo è ciò che contiene tutto lo stato globale di configurazione, e int x_optimize è il valore di ottimizzazione.

255 è un interno massimo

in opts.c:integral_argument, atoi viene applicata l'argomento di input, in modo INT_MAX è un limite superiore. E se metti qualcosa di più grande, sembra che GCC esegua un comportamento non definito. Ahia?

integral_argument avvolge anche atoi e rifiuta l'argomento se qualsiasi carattere non è una cifra. Quindi i valori negativi falliscono con grazia.

Torna opts.c:default_options_optimization, vediamo la linea:

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

in modo che il livello di ottimizzazione è troncato a 255.Durante la lettura opth-gen.awk mi ero imbattuto in:

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

e sulla generato options.h:

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

il che spiega il motivo per cui il troncamento: le opzioni devono essere inoltrate al cl_optimization, che utilizza un char per risparmiare spazio . Quindi 255 è effettivamente un massimo interno.

opts.c: maybe_default_options

Torna opts.c:default_options_optimization, ci imbattiamo in maybe_default_options che sembra interessante. Entriamo, e poi maybe_default_option dove si arriva ad un grande interruttore:

switch (default_opt->levels) 
    { 

    [...] 

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

    [...] 

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

non ci sono >= 4 controlli, che indica che 3 è il più grande possibile.

Poi cerchiamo la definizione di 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! Questo è un forte indicatore che ci sono solo 3 livelli.

opts.c: default_options_table

opt_levels è così interessante, che noi Grep OPT_LEVELS_3_PLUS, e si imbatte 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 }, 
    [...] 
} 

quindi questo è dove il -On alla mappatura ottimizzazione specifico menzionato nella i documenti sono codificati. Bello!

assicuro che non ci sono più usi per x_optimize

L'utilizzo principale del x_optimize era per impostare altre opzioni di ottimizzazione specifici come -fdefer_pop come documentato nella pagina man. Ce ne sono altri?

grep, e trovarne alcuni altri. Il numero è piccolo, e dopo l'ispezione manuale vediamo che ogni utilizzo fa al massimo uno x_optimize >= 3, quindi la nostra conclusione vale.

lto-wrapper.c

Adesso andiamo per la seconda occorrenza di OPT_O, che era in lto-wrapper.c.

LTO significa Link Time Optimization, che come suggerisce il nome avrà bisogno di un'opzione -O e sarà collegato a collec2 (che è fondamentalmente un linker).

In effetti, la prima linea di lto-wrapper.c dice:

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

In questo file, i OPT_O occorrenze sembra normalizzarsi solo il valore del O a passare in avanti, in modo che dovrebbe andare bene.

+1

Questa dovrebbe essere la risposta accettata. –

Problemi correlati