Ile jest poziomów optymalizacji GCC?

Ile jest poziomów optymalizacji GCC ?

Próbowałem gcc-O1, gcc-O2, gcc-O3 i gcc-O4

Jeśli użyję naprawdę dużej liczby, to nie zadziała.

Jednak próbowałem

gcc -O100

I skompilował się.

Ile jest poziomów optymalizacji?

Author: Peter Mortensen, 2009-11-22

4 answers

Aby być pedantycznym, istnieje 8 różnych opcji valid-O, które możesz dać gcc, chociaż są pewne, które znaczą to samo.

W oryginalnej wersji tej odpowiedzi stwierdzono, że było 7 opcji. GCC dodał -Og, aby doprowadzić całość do 8

Z strony man:

  • -O (to samo co -O1)
  • -O0 (nie Optymalizuj, domyślnie, jeśli nie określono poziomu optymalizacji)
  • -O1 (optimize minimalnie)
  • -O2 (optimize more)
  • -O3 (optimize even more)
  • -Ofast (optymalizacja bardzo agresywnie do punktu złamania zgodności standardowej)
  • -Og (Optimize debugging experience. -Og umożliwia optymalizacje, które nie zakłócają debugowania. Powinno być wybór optymalizacji dla standardowego cyklu edycji-kompilacji-debugowania, oferujący rozsądny poziom optymalizacji przy zachowaniu szybkiej kompilacji i dobrego debugowanie.)
  • -Os (optymalizacja pod kątem rozmiaru. -Os włącza wszystkie optymalizacje -O2, które zazwyczaj nie zwiększają rozmiaru kodu. Wykonuje również dalsze optymalizacje zaprojektowany w celu zmniejszenia rozmiaru kodu. -Os wyłącza następujące flagi optymalizacji: -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)

Mogą być również optymalizacje specyficzne dla platformy, jak zauważa @pauldoo, OS X ma -Oz

 96
Author: Glen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-03 12:00:54

Siedem różnych poziomów:

  • -O0 (domyślnie): brak optymalizacji.

  • -O lub -O1 (to samo): optymalizować, ale nie spędzać zbyt wiele czasu.

  • -O2: Optymalizuj bardziej agresywnie

  • -O3: Optymalizacja najbardziej agresywnie

  • -Ofast: odpowiednik -O3 -ffast-math. -ffast-math uruchamia niestandardowe optymalizacje zmiennoprzecinkowe. Pozwala to kompilatorowi udawać, że liczby zmiennoprzecinkowe są nieskończenie precyzyjne, a algebra na nich spełnia standardowe reguły algebry liczb rzeczywistych. Dodatkowo kompilator każe sprzętowi spłukiwać denormale do zera i traktować denormale jako zero, przynajmniej na niektórych procesorach, w tym x86 i x86-64. Denormale wyzwalają powolną ścieżkę na wielu FPU, więc traktowanie ich jako zera (co nie powoduje powolnej ścieżki) może być dużą wygraną wydajności.

  • -Os: optymalizacja pod kątem rozmiaru kodu. Może to rzeczywiście poprawić prędkość w niektórych przypadki, ze względu na lepsze zachowanie I-cache.

  • -Og: Optymalizuj, ale nie przeszkadzaj w debugowaniu. Pozwala to na bezawaryjną wydajność debugowania kompilacji i ma zastąpić -O0 dla debugowania kompilacji.

Istnieją również inne opcje, które nie są włączone przez żadną z nich i muszą być włączone oddzielnie. Możliwe jest również użycie opcji optymalizacji, ale wyłączenie określonych FLAG włączonych przez tę optymalizację.

Aby uzyskać więcej informacji, zobacz stronę GCC.

 32
Author: Demi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-27 09:24:27

Zinterpretujmy kod źródłowy GCC 5.1, aby zobaczyć, co się stanie na -O100, ponieważ nie jest to jasne na stronie podręcznika.

Wnioskujemy, że:

  • wszystko powyżej -O3 do INT_MAX jest tym samym co -O3, Ale To może się łatwo zmienić w przyszłości, więc nie polegaj na tym.
  • GCC 5.1 uruchamia nieokreślone zachowanie, jeśli wpiszesz liczby całkowite większe niż INT_MAX.
  • argument może mieć tylko cyfry, w przeciwnym razie nie powiedzie się. W szczególności, to wyklucza ujemne liczby całkowite, takie jak -O-1

Skup się na podprogramach

Najpierw pamiętaj, że GCC to tylko front-end dla cpp, as, cc1, collect2. Szybki ./XXX --help mówi, że tylko collect2 i cc1 biorą -O, więc skupmy się na nich.

I:

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

Daje:

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.

Więc -O został przekazany zarówno cc1, jak i collect2.

O wspólne.opt

Pospolite.opt jest GCC format opisu opcji CLI opisany w wewnętrznej dokumentacji i przetłumaczony na język C przez opth-gen. awki optc-gen. awk.

Zawiera następujące interesujące wiersze:

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

Które określają wszystkie opcje {[33] }. Zauważ, że -O<n> jest w oddzielnej rodzinie od innych Os, Ofast i Og.

Kiedy budujemy, generujemy options.h plik zawierający:

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

Jako bonus, podczas gdy my jesteśmy grepping dla \bO\n Wewnątrz common.opt zauważamy linie:

-optimize
Common Alias(O)

Co uczy nas, że --optimize (podwójne myślenie, ponieważ zaczyna się od myślnika -optimize na pliku .opt) jest nieudokumentowanym aliasem dla -O, który może być użyty jako --optimize=3!

Gdzie używa się OPT_O

Teraz grep:

git grep -E '\bOPT_O\b'

Co wskazuje na dwa pliki:

Let ' s first track dół opts.c

Opts.c: default_options_optimization

Wszystkie opts.c zastosowania dzieją się wewnątrz: default_options_optimization.

Grep backtrack, aby zobaczyć, kto wywołuje tę funkcję, i widzimy, że jedyną ścieżką kodu jest:

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

I main.c jest punktem wejścia cc1. Dobrze!

Pierwsza część tej funkcji:

  • does integral_argument which calls atoi na łańcuchu odpowiadającym OPT_O do analizy argumentu wejściowego
  • przechowuje wartość wewnątrz opts->x_optimize gdzie opts jest struct gcc_opts.

Struct gcc_opts

Po wygrawerowaniu na próżno zauważamy, że to struct jest również generowane w options.h:

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

Gdzie x_optimize pochodzi z linii:

Variable
int optimize

Obecny w common.opt, a ten options.c:

struct gcc_options global_options;

Więc domyślamy się, że to jest to, co zawiera całą konfigurację stan globalny, a int x_optimize jest wartością optymalizacji.

255 jest wewnętrznym maksimum

W opts.c:integral_argument, atoi jest stosowany do argumentu wejściowego, więc INT_MAX jest górną granicą. A jeśli umieścisz coś większego, to wygląda na to, że GCC uruchamia C undefined behavior. AUĆ?

integral_argument również cienko zawija atoi i odrzuca argument, jeśli jakikolwiek znak nie jest cyfrą. Więc wartości ujemne zawodzą z wdziękiem.

Powrót do opts.c:default_options_optimization, widzimy linia:

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

, aby poziom optymalizacji został skrócony do 255. Podczas czytania opth-gen.awk natknąłem się na:

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

I na wygenerowanym options.h:

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

Co wyjaśnia, dlaczego okrojenie: opcje muszą być również przekazane do cl_optimization, który używa char, aby zaoszczędzić miejsce. Więc 255 to wewnętrzne maksimum.

Opts.c: maybe_default_options

Wracając do opts.c:default_options_optimization, natykamy się {[79] } co brzmi interesująco. My wpisujemy go, a następnie maybe_default_option gdzie dochodzimy do dużego przełącznika:

switch (default_opt->levels)
  {

  [...]

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

  [...]

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

Nie ma >= 4 kontroli, która wskazuje, że 3 jest największa z możliwych.

Następnie szukamy definicji OPT_LEVELS_3_PLUS w 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! Jest to silny wskaźnik, że istnieją tylko 3 poziomy.

Opts.c: default_options_table

opt_levels jest tak interesujące, że grep OPT_LEVELS_3_PLUS i natknąć się 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 },
    [...]
}

Więc tutaj -On do specyficznego mapowania optymalizacji wymienionego w dokumentach jest zakodowany. Nieźle!

Upewnij się, że nie ma więcej zastosowań dla x_optimize

Głównym zastosowaniem x_optimize było ustawienie innych specyficznych opcji optymalizacji, takich jak -fdefer_pop, zgodnie z dokumentacją na stronie podręcznika. Jest ich więcej?

My grep, i znaleźć kilka więcej. Liczba jest niewielka, a po ręcznej kontroli widzimy, że każde użycie robi co najwyżej x_optimize >= 3, więc nasz wniosek trzyma.

Lto-owijarka.c

Teraz przejdziemy do drugiego wystąpienia OPT_O, które było w lto-wrapper.c.

LTO oznacza optymalizację czasu połączenia, która, jak sama nazwa wskazuje, będzie wymagać opcji -O i będzie połączona z collec2 (która jest w zasadzie linkerem).

W rzeczywistości pierwsza linijka lto-wrapper.c mówi:

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

W tym pliku zdarzenia OPT_O wydają się normalizować tylko wartość O, aby przekazać ją do przodu, więc powinniśmy być dobrze.

 29
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-25 16:40:30

Cztery (0-3): patrz instrukcja GCC 4.4.2 . Wszystko wyższe to tylko-O3, ale w pewnym momencie przekroczysz limit zmiennej wielkości.

 3
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-22 12:17:48