Оптимизация компилятором C ++ переданных аргументов
-
08-07-2019 - |
Вопрос
Я использую модуль регистрации, который может включать / отключать отчеты во время выполнения. Звонки обычно идут примерно так:
WARN(
"Danger Will Robinson! There are "
+ boost::lexical_cast<string>(minutes)
+ " minutes of oxygen left!"
);
Я использую встроенную функцию для WARN, но мне любопытно, сколько оптимизации происходит за кулисами - оценка аргументов во всей программе будет дорогостоящей. Функция WARN
выглядит примерно так:
bool WARNINGS_ENABLED = false;
inline void WARN(const string &message) {
if (!WARNINGS_ENABLED) {
return;
}
// ...
}
Учитывая, что создание строкового аргумента не имеет побочных эффектов, оптимизирует ли его компилятор? Требуется ли определенный уровень оптимизации ( -Ox
в g ++
для некоторого x
)?
Решение
Если вам нужно будет выборочно включать и отключать предупреждения во время выполнения, компилятор не сможет оптимизировать вызов.
Вам нужно переименовать вашу функцию в WARN2
и добавить макрос что-то вроде:
#define WARN(s) do {if (WARNINGS_ENABLED) WARN2(s);} while (false)
Это предотвратит оценку s во время выполнения, если у вас не включены предупреждения.
Do-while - это хитрость, позволяющая использовать его где угодно в коде (голый оператор, оператор в фигурном блоке if, блок в свободном блоке if, фигурный оператор без оператора while и т. д.) . р>
Другие советы
Вы можете проверить, что делает GCC / G ++, используя параметр -S . Это выведет код до его фактической сборки & # 8211; см. gcc (1) .
GCC и G ++ более или менее ведут себя одинаково в этом случае. Поэтому я сначала перевел код на C, чтобы провести дополнительные тесты:
char WARNINGS_ENABLED = 0;
inline void WARN(const char* message) {
if (!WARNINGS_ENABLED) {
return;
}
puts(message);
}
int main() {
WARN("foo");
return 0;
}
запустите gcc -O3 -S file.c и просмотрите выходной файл file.s '
Вы увидите, что GCC ничего не удалил !
Это не то, о чем вы просили, но для того, чтобы дать компилятору возможность оптимизировать этот код, вам нужно сделать WARNINGS_ENABLED постоянным . Альтернатива - сделать его статическим и не изменять значение в этом файле. Но : если сделать его статичным , у него не будет побочного эффекта.
static const char WARNINGS_ENABLED = 0;
inline void WARN(const char* message) {
if (!WARNINGS_ENABLED) {
return;
}
puts(message);
}
int main() {
WARN("foo");
return 0;
}
GCC затем полностью очищает код.
Я полагаю, что у него есть шанс оптимизировать его, только если он может доказать, что побочных эффектов нет (что может быть затруднительно для компилятора при вызове дорогостоящей функции).
Я не эксперт по бусту, но я предполагаю, что есть способ создать лямбду, которая будет оцениваться только для генерации строки, если WARNINGS_ENABLED имеет значение true. Что-то вроде ...
inline void warnFunc(some_boost_lambda &message_generator) {
if (WARNINGS_ENABLED) {
cerr << message_generator() << endl;
}
}
#define WARN(msg) warnFunc(...insert boost magic here to turn msg into a lambda...)
Нет, компилятор не должен не оптимизировать код в любом случае, если глобальный WARNING_ENABLED не объявлен как const.
Кстати, если WARN - встроенная функция, вы все равно заплатите цену за построение сообщения (что очень неэффективно в вашем примере с lexical_cast и operator + для строк), даже если оно отключено.
Вот некоторые эффективные (минимальные (близкие к нулю с ЦП прогнозирования ветвления) издержки при отключении времени выполнения) макросы журналов , которые поддерживают журналирование как функций, так и потоковых стилей.
Разве вы не можете просто определить все это с помощью препроцессора?
void inline void LogWarning(const string &message)
{
//Warning
}
#ifdef WARNINGS_ENABLED
#define WARN(a) LogWarning(a)
#else
#define WARN(a)
#endif
Так работает макрос ASSERT (). Весь код внутри скобок в WARN даже не проходит через препроцессор к компилятору. Это означает, что вы можете делать другие вещи, такие как
#ifdef WARNINGS_ENABLED
// Extra setup for warning
#endif
//....
WARN(uses setup variables)
И это скомпилирует оба пути. Р>
Что касается того, чтобы оптимизатор осознал, что в скобках нет побочных эффектов, вы можете поместить в него несколько довольно сложных выражений (т. е. манипулирование строками высокого уровня), которые трудно доказать в любом случае.