Вопрос

Я использую модуль регистрации, который может включать / отключать отчеты во время выполнения. Звонки обычно идут примерно так:

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)

И это скомпилирует оба пути.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top