Подтвердить что ты не робот

Эвристика С++ для оценки функций, придающих преимущества

В С++ то, что является хорошей эвристикой для оценки преимуществ времени вычислений в зависимости от функции, особенно когда функция вызывается очень часто и учитывает >= 10% времени выполнения программы (например, функция оценки грубой силы или стохастической оптимизации). Несмотря на то, что inlining может быть в конечном счете вне моего контроля, мне все еще интересно.

4b9b3361

Ответ 1

Нет общего ответа. Это зависит от оборудования, количества и тип его аргументов и то, что делается в функции. И как часто он называется, и где. Например, на Sparc аргументы (и возвращаемое значение) передаются в регистры, и каждая функция получает 16 новых регистры: если функция достаточно сложная, эти новые регистры могут избегайте пролития, которое могло бы произойти, если бы функция была встроена, и не-встроенная версия может закончиться быстрее, чем встроенная. На Intel, который плохо регистрируется, и передает аргументы в регистры, только напротив, может быть правдой, для той же функции в той же программе. Больше как правило, встраивание может увеличить размер программы, уменьшая местность. Или для очень простых функций, это может уменьшить размер программы; но это снова зависит от архитектуры. Единственный возможный способ узнать - попробовать оба, измеряя время. И даже тогда вы будете знать только об этом конкретной программы, на этом конкретном оборудовании.

Ответ 2

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

Ответ 3

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

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

* EDIT после комментария, что рекурсия не предназначена, а скорее итерация *

Если компилятор имеет доступ к определению функции, в большинстве случаев он примет правильное решение. Если у него нет доступа к определению, просто переместите код так, чтобы он его видел. Возможно, сделать функцию a static функцией, чтобы предоставить дополнительную подсказку о том, что она больше не будет использоваться нигде или даже будет отмечена как inline (зная, что это не приведет к принудительной вставке), но не используйте специальные атрибуты, которые будут force, поскольку компилятор, вероятно, делает это лучше, чем любая простая эвристика, которую можно создать без просмотра кода.

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

Наш опыт, 20+ лет написания вычислительно интенсивного С++, заключается в том, что вложение не является серебряной пулей. Вам действительно нужно профилировать свой код, чтобы увидеть, увеличит ли производительность. Для нас, кроме низкоуровневых 2D и 3D точечных и векторных манипуляций, это пустая трата времени. Вы намного лучше разрабатываете лучший алгоритм, чем пытаетесь микрокартировать тактовые сигналы.