Долгое время у нас была система ведения журнала, которая работала примерно так:
#define LOG( LEVEL, FORMAT, ... ) my_log_function( LEVEL, __FUNCTION__, \
__LINE__, FORMAT, __VA_ARGS__ )
my_log_function
проверит уровень ведения журнала, установленного в данный момент, и, если это приемлемо, выполнит некоторую красивую печать (файл / строка, в которой он был записан, время и т. Д.) Из переданной информации.
Теперь проблема в том, что у этого макроопределения есть два существенных недостатка:
1 / При использовании аргументы, передаваемые в этом макросе, оцениваются , что означает большое снижение производительности, когда ваш код переполнен вызовами LOG ().
Смотрите пример здесь:
LOG( INFO, "The parameters: %s %d %d\n", heavyMethod().name(),
heavyMethod2().id(), work_done_in_this_function());
Даже если уровень регистрации «INFO» деактивирован, все параметры будут оцениваться перед входом в функцию.
Если вы зарегистрируете вызовы функций, вы увидите, что это происходит:
- вызов
heavyMethod()
- вызов
name()
- звонок на
heavyMethod2()
- вызов
id()
- вызов
work_done_in_this_function()
- (наконец) звонок на
my_log_function()
Это очень плохо, когда у вас 1000 вызовов LOG ().
Решение простое: возьмите из my_log_function
код, который проверяет уровень, и измените определение LOG () следующим образом:
#define LOG( LVL, FMT, ... ) do{ if( level_enabled(LVL) ) \
{ \
my_log_function( LVL, ...); \
} \
}while(0)
Это гарантирует, что, когда уровень журнала недостаточен, параметры не оцениваются (так как они находятся в блоке скобок).
2 / Как вы видели в моем примере, последняя вызываемая функция выполняет какую-то работу, которая не была бы выполнена, если бы функция LOG () не была вызвана.
Это часто случается в нашем коде (и я знаю, что это отстой, люди уже потеряли из-за этого пальцы).
С улучшением, которое я сделал в пункте 1 /, теперь мы должны проверять каждый вызов LOG (), чтобы увидеть, была ли там какая-то работа, которая больше не выполняется, теперь, когда мы нейтрализовали вызовов.
Здесь вы, ребята, вводите: знаете ли вы простой метод, который бы проверял, действительно ли аргумент функции изменяет что-то?
Проект написан на C ++, и большинство функций, которые "ничего не меняют", помечены как const.
Обратите внимание, что это включает в себя некоторые хитрые вещи, такие как: LOG( INFO, "Number of items: %d\n", _item_number++);
, где _item_number
является членом класса объекта (таким образом, не увеличивается, если уровень INFO не активирован :-().
TL; DR : НИКОГДА, НИКОГДА не выполняйте работу в printf (). ВСЕГДА делайте это заранее:
// BAD
printf("Number: %d\n",++i);
// GOOD
i++;
printf("Number: %d\n", i);