Есть ли реальный пример, когда встроенный код вреден для производительности программы на C?

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


person MaiaVictor    schedule 27.06.2014    source источник
comment
Обратите внимание, что inline — это всего лишь предложение; компилятор может игнорировать его.   -  person dan04    schedule 27.06.2014
comment
Если многие единицы компиляции включают один и тот же большой встроенный метод и используют его только один раз, тогда у вас может быть вырожденный пример... Тем не менее, это зависит от того, не выполняется ли генерация кода во время компоновки или подобные вещи.   -  person Deduplicator    schedule 27.06.2014
comment
Как сказал @dan04, компилятору не требуется вас слушать, и в целом это довольно умно.   -  person rjp    schedule 27.06.2014
comment
Многие места, например функция max ('int max (int a, int b)') могут быть просто встроенными (также могут быть определены как макросы на самом деле и будут иметь тот же эффект). Программа не будет «ПЕРЕХОДИТЬ» к этой функции в памяти и не будет загружать стек с переменными. ТОННЫ использований.   -  person Zach P    schedule 27.06.2014
comment
Конечно, встраивание может быть вредным - в противном случае компилятор (или разработчик) просто всегда встраивал бы все, все время. Это увеличивает нагрузку на регистры и размер кода / размер кэша L1i, любой из которых может легко привести к более серьезным проблемам с производительностью, чем накладные расходы на вызов функции. ТАНСТАФЛ.   -  person Jonathan Dursi    schedule 27.06.2014
comment
раздутый сгенерированный код может привести к промаху кэша инструкций.   -  person fukanchik    schedule 22.08.2015


Ответы (2)


Ровно 10 лет и один день назад я сделал этот коммит в OpenBSD:

http://www.openbsd.org/cgi-bin/cvsweb/src/sys/arch/amd64/include/intr.h.diff?r1=1.3;r2=1.4

Сообщение коммита было:

deinline splraise, spllower и setsoftint. Делает ядро ​​меньше и быстрее. Дераадт @ хорошо

Насколько я помню, бинарный файл ядра уменьшился более чем на 100 КБ, и ни один тестовый пример не стал медленнее, а несколько тестов макросов (например, компиляция ядра) были заметно быстрее (на 5-10%, если я правильно помню, но не не цитируйте меня по этому поводу).

Примерно в то же время я отправился на поиски реального измерения встроенных функций в ядре OpenBSD. Я нашел несколько, которые имели минимальный прирост производительности, но большинство из них не оказали измеримого влияния, а некоторые сильно замедляли работу и были убиты. По крайней мере, еще одно отключение оказало огромное влияние, и это были внутренние макросы malloc (где идея заключалась в том, чтобы встроить malloc, если его размер был известен во время компиляции) и распределители буфера пакетов, которые уменьшили ядро ​​​​на 150 КБ и имели значительную производительность. улучшение.

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

person Art    schedule 27.06.2014
comment
Подобные изменения в удалении встроенных строк были сделаны несколько лет назад и в ядре Linux. - person hlovdal; 27.06.2014

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

Отсутствие параметров делает процедуру вызова более легкой, потому что не требуются операции со стеком, занимающие много времени.

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

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

Похоже, это относится к некоторым конкретным функциям, широко используемым в ОС.

person Frankie_C    schedule 21.08.2015