Проверка оптимизации компилятора в gcc / g ++ путем анализа списков сборок - PullRequest
9 голосов
/ 07 января 2010

Я только что задал вопрос, связанный с тем, как компилятор оптимизирует определенный код C ++ , и я искал в SO любые вопросы о том, как проверить, что компилятор выполнил определенные оптимизации. Я пытался посмотреть на лист сборки, сгенерированный с помощью g ++ (g++ -c -g -O2 -Wa,-ahl=file.s file.c), чтобы увидеть, что происходит под капотом, но вывод слишком загадочный для меня. Какие методы используют люди для решения этой проблемы, и есть ли хорошие рекомендации о том, как интерпретировать списки сборок оптимизированного кода или статьи, относящиеся к цепочке инструментов GCC, в которых говорится об этой проблеме?

Ответы [ 8 ]

19 голосов
/ 07 января 2010

Оптимизация GCC передает работу над промежуточным представлением вашего кода в формате GIMPLE .

Используя семейство опций -fdump-* , вы можете попросить GCC вывести промежуточные состояния дерева.

Например, введите это gcc -c -fdump-tree-all -O3

unsigned fib(unsigned n) {
    if (n < 2) return n;
    return fib(n - 2) + fib(n - 1);
}

и наблюдайте, как он постепенно превращается из простого экспоненциального алгоритма в сложный полиномиальный алгоритм. (Действительно!)

4 голосов
/ 18 января 2010

Полезным методом является запуск кода под хорошим профилировщиком выборки, например, Увеличьте масштаб под Linux или Instruments (с инструментом Time Profiler) под Mac OS X. Эти профилировщики не только показывают вам горячие точки в вашем коде, но и отображают исходный код в разобранный объектный код. Выделение строки источника показывает (не обязательно смежные) строки сгенерированного кода, которые отображаются на строку источника (и наоборот). Хорошие бонусы - ссылки на коды операций онлайн и советы по оптимизации.

3 голосов
/ 07 января 2010

Не gcc, но при отладке в Visual Studio у вас есть возможность перемежать сборку и исходный код, что дает хорошее представление о том, что было сгенерировано для какого оператора. Но иногда это не совсем правильно выровнено.

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

2 голосов
/ 07 января 2010

Добавление опции -L (например, gcc -L -ahl) может обеспечить несколько более понятные списки.

Эквивалентный параметр MSVC - /FAcs (и он немного лучше, поскольку включает в себя источник, машинный язык и двоичный файл и содержит некоторые полезные комментарии).


Около трети моей работы состоит в том, чтобы делать то, что вы делаете: жонглировать кодом на C, а затем смотреть на вывод сборки, чтобы убедиться, что он оптимизирован правильно (что предпочтительнее, чем просто писать встроенную сборку везде). ).

Блоги и статьи по разработке игр могут быть хорошим ресурсом для этой темы, поскольку игры являются приложениями реального времени в постоянной памяти - У меня есть некоторые заметки , так же как и Майк Актон и другие. Обычно мне нравится держать ссылку на набор инструкций Intel в окне при просмотре списков.

Самое полезное - сначала получить хорошее представление о программировании на ассемблере - не потому, что вы хотите писать код на ассемблере, а потому, что это делает чтение дизассемблирования намного проще. Мне было трудно найти хороший современный учебник.

1 голос
/ 05 января 2016

Для вывода примененных оптимизаций вы можете использовать:

-fopt-инфо-оптимизированная

Чтобы увидеть те, которые не были применены

-fopt-инфо пропущенным

Остерегайтесь того, что выходные данные отправляются в стандартный поток ошибок, поэтому для его просмотра вам действительно нужно перенаправить это : (подсказка 2> & 1)

Вот хороший пример:

g++ -O3 -std=c++11 -march=native -mtune=native 
        -fopt-info-optimized h2d.cpp -o h2d 2>&1

h2d.cpp:225:3: note: loop vectorized
h2d.cpp:213:3: note: loop vectorized
h2d.cpp:198:3: note: loop vectorized
h2d.cpp:186:3: note: loop vectorized

Вы можете проверить чередующийся вывод, применив -g с objdump -dS|c++filt, но это не даст вам такой возможности. Наслаждайтесь!

1 голос
/ 09 июня 2010

Zoom from RotateRight (http://rotateright.com) упоминается в другом ответе, но более подробно об этом: он показывает отображение исходного кода на сборку в том, что они называют «браузером кода». Это невероятно удобно, даже если вы не являетесь экспертом asm, потому что они также интегрировали документацию по сборке в приложение. А список сборок снабжен комментариями и временем для нескольких типов процессоров.

Вы можете просто открыть свой объект или исполняемый файл с помощью Zoom и взглянуть на то, что компилятор сделал с вашим кодом.

0 голосов
/ 07 января 2010

Вместо того, чтобы пытаться прочитать дамп ассемблера, запустите вашу программу внутри отладчика. Вы можете приостанавливать выполнение, выполнять пошаговые инструкции, устанавливать точки останова в коде, который вы хотите проверить, и т. Д. Многие отладчики могут отображать ваш исходный код C вместе с сгенерированной сборкой, чтобы вам было легче видеть, что компилятор сделал для оптимизации вашего кода.

Кроме того, если вы пытаетесь протестировать конкретную оптимизацию компилятора, вы можете создать короткую фиктивную функцию, которая содержит тип кода, который соответствует интересующей вас оптимизации (и не более того, чем проще, тем проще сборка это читать). Скомпилируйте программу один раз с включенной оптимизацией и один раз с выключенной; Сравнение сгенерированного кода сборки для фиктивной функции между сборками должно показать вам, что сделали оптимизаторы компилятора.

0 голосов
/ 07 января 2010

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

Что касается общего вопроса, я читаю (и пишу) ассемблер уже более (глотком) 30 лет, и все, что я могу сказать, это то, что для этого требуется практика, особенно для чтения вывода компилятора. 1003 *

...