2009-11-22 4 views
56

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

Я попытался Gcc -O1, GCC -O2, GCC -O3 и GCC -O4

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

Однако, я попытался

gcc -O100 

и скомпилированы.

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

+3

@Jens: TFM имеет длину 15 000 строк и не имеет большого значения о '-O' :) – Ryan

+13

@minitech На какой FM вы смотрите? Даже с 'man gcc' на Cygwin (12000 нечетных строк) вы можете искать' -O' и находить все ответы ниже состояния, а затем некоторые. – Jens

+1

@minmaxavg после чтения источника, я не согласен с вами: что-то большее, чем '3', такое же, как' 3' (до тех пор, пока оно не переполняется 'int'). См. [Мой ответ] (http://stackoverflow.com/a/30308151/895245). –

ответ

82

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

В оригинальной версии этого ответа было указано 7 вариантов. НКУ с тех пор добавил -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

+21

Если вы разрабатываете Mac OS X, есть еще одна опция '-Oz', которая« оптимизируется для размера более агрессивно, чем '-O'»: http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools /gcc-4.0.1/gcc/Optimize-Options.html – pauldoo

+3

Примечание: O3 не обязательно лучше, чем O2, даже если это так предположительно. Попробуйте оба. –

+1

@pauldoo 404 страница, заменить на archive.org –

3

4 (0-3): См. GCC 4.4.2 manual. Все, что выше, равно -O3, но в какой-то момент вы превысите ограничение на размер переменной.

+0

Я изучил исходный код [в своем ответе] (http://stackoverflow.com/a/30308151/895245) и согласен с вами. Более педантично, GCC, похоже, полагается на неопределенное поведение 'atoi', за которым следует внутренний предел' 255'. –

+0

Пожалуйста, подумайте об удалении вашего ответа, так как он (по крайней мере в эти дни) неверен. – einpoklum

29

Семь различных уровней:

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

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

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

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

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

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

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

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

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

+0

Действительно, хотя, чтобы быть справедливым по отношению к другим ответам, ни -Ofast, ни -Og не существовало, когда эти ответы были написаны. – janneb

+0

Так почему же '-O100' компилируется? – einpoklum

+2

@einpoklum, потому что GCC обрабатывает все выше -O3 равным -O3. – Demi

25

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

Мы заключаем, что:

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

Фокус на подпрограммах

Во-первых помните, что НКУ просто передний конец для 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.

О в common.opt

common.opt является GCC конкретный вариант CLI описание формата описаны в internals documentation и переведен на С помощью 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 */ 

В качестве бонуса, в то время как мы оглавлению для \bO\n внутри common.opt мы замечаем линии:

-optimize 
Common Alias(O) 

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

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

Теперь мы Grep:

git grep -E '\bOPT_O\b' 

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

Давайте первый трек вниз opts.c

opts.c: default_options_optimization

Все opts.c обыкновений случаются внутри: default_options_optimization.

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

  • 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.

структура gcc_opts

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

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

где x_optimize происходит от линии:

Variable 
int optimize 

prese нт в common.opt, и что options.c:

struct gcc_options global_options; 

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

255 представляет собой внутренний максимальный

в 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 настолько интересно, что мы Grep 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 для конкретного отображения оптимизации упоминается в docs закодирован. Ницца!

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

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

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

LTO-wrapper.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 передать его вперед, поэтому мы должны быть в порядке.

+1

Это должен был быть принятый ответ. –

Смежные вопросы