Сколько существует уровней оптимизации GCC?


сколько GCC уровни оптимизации существуют?

я попробовал на GCC -О1, ССЗ -О2, НКУ -О3, и gcc -О4

Если я использую действительно большое число, это не будет работать.

однако, я пробовал

gcc -O100

и он компилируется.

сколько существует уровней оптимизации?

4 64

4 ответа:

чтобы быть педантичным, есть 8 различных допустимых вариантов-O, которые вы можете дать gcc, хотя есть некоторые, которые означают одно и то же.

в оригинальной версии этого ответа говорилось, что было 7 вариантов. GCC с тех пор добавил -Og чтобы довести общее число до 8

С man page:

  • -O (то же, что и -O1)
  • -O0 (не оптимизируйте, по умолчанию, если нет уровня оптимизации указано)
  • -O1 (минимально оптимизировать)
  • -O2 (больше оптимального)
  • -O3 (оптимизировать еще больше)
  • -Ofast (оптимизация очень агрессивно до точки нарушения стандартного соответствия)
  • -Og (оптимизировать процесс отладки. - Og включает оптимизации, которые не мешают отладке. Это должно быть уровень оптимизации выбора для стандартного цикла редактирования-компиляции-отладки, предлагая разумный уровень оптимизации при сохранении быстрой компиляции и хорошего опыта отладки.)
  • -Os (оптимизации по размеру. -Os позволяет всем -O2 оптимизации, которые обычно не увеличивают размер кода. Он также выполняет дальнейшие оптимизации предназначен для уменьшения размера кода. -Os отключает следующие флаги оптимизации: -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)

также могут быть оптимизации для конкретной платформы, как отмечает @pauldoo, OS X имеет -Oz

семь отдельных уровней:

  • -O0 (по умолчанию): нет оптимизация.

  • -O или -O1 (то же самое): оптимизируйте, но не тратьте слишком много времени.

  • -O2: оптимизация более агрессивно

  • -O3: оптимизация наиболее агрессивно

  • -Ofast: эквивалентно -O3 -ffast-math. -ffast-math триггеры не соответствуют стандартам с плавающей точкой процессы оптимизации. Это позволяет компилятору делать вид, что числа с плавающей запятой бесконечно точны, и что алгебра на них следует стандартным правилам алгебры действительных чисел. Это также говорит компилятору сказать оборудование для промывки denormals к нулю и лечить denormals как ноль, по крайней мере на некоторых процессоров, включая x86 и x86-64. Денормалы запускают медленный путь на многих FPU, и поэтому их обработка как ноль (который не запускает медленный путь) может быть большой выигрыш в производительности.

  • -Os: оптимизация для размера кода. Это может фактически улучшить скорость в некоторых случаях, из-за лучшего поведения I-кэша.

  • -Og: оптимизируйте, но не мешайте отладке. Это позволяет не стеснять производительность для отладочных сборок и предназначено для замены -O0 для отладки строит.

есть также другие параметры, которые не включены ни одним из них, и должны быть включены отдельно. Оно также можно использовать опцию оптимизации, но отключить определенные флаги, включенные этой оптимизацией.

дополнительную информацию см. На веб-сайте GCC.

давайте интерпретируйте исходный код GCC 5.1 чтобы увидеть, что происходит на -O100 так как это не ясно на странице man.

мы сделаем вывод, что:

  • все, что выше -O3 до INT_MAX это то же самое, что -O3, но это может легко измениться в будущем, так что не полагаться на него.
  • GCC 5.1 выполняет неопределенное поведение, если вы вводите целые числа больше, чем INT_MAX.
  • аргумент может быть только есть цифры, или это не корректно. В частности, это исключает отрицательные целые числа, такие как -O-1

сосредоточьтесь на подпрограммах

сначала помните, что GCC-это просто интерфейс для cpp,as,cc1,collect2. Быстро ./XXX --help говорит, что только collect2 и cc1 взять -O, так что давайте сосредоточимся на них.

и:

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

выдает:

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.

так -O был направлены как cc1 и collect2.

O в общем.опт

общие.опт - это формат описания конкретного параметра CLI GCC, описанный в внутренняя документация и переводится на C с помощью opth-gen. awk и optc-gen. awk.

содержит следующие интересные строки:

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

которые указывают все O параметры. Отмечать как -O<n> находится в отдельной семье от других Os,Ofast и Og.

когда мы строим, это создает options.h файл, который содержит:

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

в качестве бонуса, в то время как мы находимся на применение grep к \bO\n внутри common.opt мы видим строки:

-optimize
Common Alias(O)

, который учит нас, что --optimize (двойной тире, потому что он начинается с тире -optimize на .opt file) - это недокументированный псевдоним для -O, который может быть использован в качестве --optimize=3!

где используется OPT_O

теперь мы рассмотрим более подробно:

git grep -E '\bOPT_O\b'

, который указывает нам на два файла:

давайте сначала отследим opts.c

opts.c: default_options_optimization

все opts.c обычаи происходят внутри: default_options_optimization.

мы grep backtrack, чтобы увидеть, кто вызывает эту функцию, и мы видим, что единственный путь кода:

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

и main.c является точкой входа cc1. Хорошо!

первая часть этой функции:

  • тут integral_argument которых звонки atoi в строке, соответствующей OPT_O для разбора входного аргумента
  • сохраняет значение внутри opts->x_optimize здесь opts это struct gcc_opts.

struct gcc_opts

после применение grep к зря, мы замечаем, что этот struct также генерируется в options.h:

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

здесь x_optimize исходит из строк:

Variable
int optimize

в настоящее время common.opt и options.c:

struct gcc_options global_options;

Итак, мы предполагаем, что это что содержит всю конфигурацию глобального состояния, и int x_optimize значение оптимизации.

255-это внутренний максимум

in opts.c:integral_argument,atoi применяется к входному аргументу, поэтому INT_MAX - это верхняя граница. И если вы положите что-нибудь большее, кажется, что GCC запускает c неопределенным поведением. Ай?

integral_argument также тонко обертывания atoi и отвергает аргумент, если какой-либо символ не является цифрой. Поэтому отрицательные значения не изящно.

на opts.c:default_options_optimization мы видим строку:

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

так что уровень оптимизации усекается до 255. Во время чтения opth-gen.awk я сталкивался:

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

и на созданном options.h:

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

что объясняет, почему усечение: параметры также должны быть перенаправлены в cl_optimization, который использует char для экономии места. Так что 255-это внутренний максимум на самом деле.

opts.c: maybe_default_options

на opts.c:default_options_optimization, мы встречаем maybe_default_options звучит интересно. Мы входим в него, а потом maybe_default_option где мы достигаем большой переключатель:

switch (default_opt->levels)
  {

  [...]

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

  [...]

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

нет >= 4 проверяет, что указывает на то, что 3 является максимально возможным.

тогда мы ищем определение OPT_LEVELS_3_PLUS на 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.  */
};

ха! Это сильный показатель что есть только 3 уровня.

opts.c: default_options_table

opt_levels так интересно, что мы грэп OPT_LEVELS_3_PLUS, и 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 },
    [...]
}

вот здесь -On к конкретному отображению оптимизации, упомянутому в документах, кодируется. Мило!

убедитесь, что больше нет использования для x_optimize

основное использование x_optimize должен был установить другие конкретные параметры оптимизации, такие как -fdefer_pop как указано на справочной странице. Есть еще что-нибудь?

мы grep, и найти еще несколько. Их количество невелико, и при ручном осмотре мы видим, что каждое использование не только в x_optimize >= 3, так что наш вывод имеет.

lto-обертка.c

теперь мы идем на второе появление OPT_O, который находился в lto-wrapper.c.

LTO значит оптимизирование времени соединения, которое как имя предполагает, что понадобится -O вариант, и будет связан с collec2 (который в основном является компоновщиком).

в самом деле, первая строка lto-wrapper.c говорит:

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

в этом файле OPT_O вхождения, кажется, только нормализуют значение O пропустить его вперед, так что мы должны быть в порядке.

четыре (0-3): см. GCC 4.4.2 руководство. Все, что выше-это просто-O3, но в какой-то момент Вы будете переполнять предел размера переменной.