Как компилятор решает, стоит ли делать мои функции встроенными или нет? - PullRequest
7 голосов
/ 06 октября 2011

Мне интересно, знает ли кто-нибудь логику, которую обычно используют компиляторы C ++, чтобы решить, стоит ли встроить функцию при компиляции (при условии, что было запрошено inline).

Является ли этот тип информации общедоступным?

Ответы [ 4 ]

6 голосов
/ 06 октября 2011

Я дал более подробный ответ в этом другом вопросе .

По сути, компиляторы используют эвристику, основанную на анализе затрат, цитируя себя (это означает, что я становлюсь старческим?)

Если вы подумаете о встраивании и его последствиях, вы поймете это:

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

И, конечно, есть также частичное встраивание, в котором встроена только часть функции, обычно это ведущий if охранник, такой как foo(T* t) { if (!t) { return; } <many many things> }.

3 голосов
/ 06 октября 2011

Да, такая информация является общедоступной.Тем более, что существует множество компиляторов с открытым исходным кодом.

Я считаю, что читаемая книга - Книга Дракона .Они проходят через все это, не так?

Но в основном: вызов функции имеет свою стоимость - настройка регистров, прыжки, сбор результатов.Это можно посчитать в циклах.Тело функции также имеет стоимость, измеренную в циклах.Сравните два.Дополнительные баллы за учет локальности кэша.

1 голос
/ 06 октября 2011

Эвристика будет зависеть от параметров, которые вы передаете компилятору, а также будет зависеть от компилятора.Там нет общего ответа.У большинства компиляторов сегодня есть комбинации опций, где они ничего не вставляют.У большинства также есть комбинация опций, где то, что они встраивают, будет зависеть от результатов профилировщика более ранних запусков программы.В противном случае: с точки зрения качества реализации разумно ожидать, что компилятор встроит функции, объявленные inline более агрессивно, чем те, которые не объявлены inline.И обычно только тогда, когда активируется наиболее агрессивная оптимизация, они вставляют функцию, определение которой отсутствует в блоке перевода.Наконец, некоторые функции в функции могут препятствовать встраиванию: некоторые компиляторы могут не включать встроенные рекурсивные функции, например (хотя g ++ делает, по крайней мере, в некоторых случаях).

1 голос
/ 06 октября 2011

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

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

Если это крошечная функция, то вставка может сделать то же самое.

Если функция вызывается в узком цикле много раз, встраивание может улучшить производительность.

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...