Каковы предостережения от использования встроенной оптимизации в функциях C ++? - PullRequest
2 голосов
/ 22 августа 2010

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

Ответы [ 5 ]

5 голосов
/ 22 августа 2010

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

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

  • Избегайте встроенных функций, пока профилирование не покажет, какие функции могут извлечь выгоду из встроенного.
  • Подумайте об использовании опции компилятора для автоматического встраивания после профилирования как с автоматическим, так и без него.
  • Только встроенные функции, в которых накладные расходы на вызов функции велики относительно кода функции. Другими словами, вставка больших функций или функций, которые вызывают другие (возможно, встроенные) функции, не очень хорошая идея.
3 голосов
/ 22 августа 2010

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

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

2 голосов
/ 22 августа 2010

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

Компилятор высокого уровня часто пытается позаботиться о другой возможности встраивания: когда функция Bвызывается только из функции A и никогда не вызывается из других источников.Это встраивание не выполняется по соображениям производительности (при условии, что A и B не являются небольшими функциями), но полезно для сокращения времени компоновки за счет сокращения общего числа «функций», которые необходимо сгенерировать.

Добавленные примеры

Примером того, как компилятор выполняет массивное встраивание (с огромным ускорением), является компиляция контейнеров STL.Контейнерные классы STL написаны так, чтобы быть очень универсальными, а взамен каждая «функция» выполняет лишь незначительную часть работы.Когда встраивание отключено, например, при компиляции в режиме отладки, скорость контейнеров STL значительно падает.

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

Нижняя строка

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

0 голосов
/ 22 августа 2010

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

0 голосов
/ 22 августа 2010

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

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

Кроме того, размер вашего двоичного файла увеличивается.

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

...