Производительность C ++, оптимизирующий компилятор, пустая функция в .cpp - PullRequest
5 голосов
/ 04 мая 2010

У меня есть очень простой класс, назовите его Basic, который используется почти во всех других файлах в большом проекте. В некоторых случаях требуется вывод результатов отладки, но в режиме выпуска это не должно быть включено и должно быть NOOP.

В настоящее время в заголовке есть определение, которое включает или выключает макрос в зависимости от настройки. Так что это определенно NOOP, когда выключено. Мне интересно, если у меня есть следующий код, если компилятор (MSVS / gcc) может оптимизировать вызов функции, так что это снова NOOP. (При этом переключатель может быть в .cpp, а переключение будет намного быстрее, с точки зрения времени компиляции / компоновки).

--Header--
void printDebug(const Basic* p);

class Basic {
   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
      printDebug(this);
   }
};
--Source--
// PRINT_DEBUG defined somewhere else or here
#if PRINT_DEBUG
void printDebug(const Basic* p) {
   // Lengthy debug print
}
#else
void printDebug(const Basic* p) {}
#endif

Ответы [ 5 ]

2 голосов
/ 04 мая 2010

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

1 голос
/ 04 мая 2010
#if PRINT_DEBUG
#define printDebug _real_print_debug
#else
#define printDebug(...)
#endif

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

1 голос
/ 04 мая 2010

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

#define PRINT_DEBUG    // optional
#ifdef PRINT_DEBUG
#define PRINT_DEBUG_CALL(p) printDebug(p)
#else
#define PRINT_DEBUG_CALL(p)
#endif


void printDebug(const Basic* p);

class Basic {
   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
      PRINT_DEBUG_CALL(this);
   }
};
--Source--
// PRINT_DEBUG defined somewhere else or here
#if PRINT_DEBUG
void printDebug(const Basic* p) {
   // Lengthy debug print
}
#endif
0 голосов
/ 04 мая 2010

В настоящее время большинство оптимизаций выполняется во время компиляции. Некоторые компиляторы как LLVM могут оптимизировать во время соединения. Это действительно интересная идея. Я предлагаю вам взглянуть на.

В ожидании такого рода оптимизации вы можете сделать следующее. Определите макрос, который позволит вам включить следующую инструкцию в зависимости от того, определен ли DEBUG или нет.

#ifdef DEBUG
#define IF_DEBUG (false) {} else
#else
#define IF_DEBUG 
#endif

Вы можете использовать это так

   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
      IF_DEBUG printDebug(this);
   }

, который уже гораздо более читабелен, чем

   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
#if DEBUG
      printDebug(this);
#endif
   }

Обратите внимание, что вы можете использовать его как ключевое слово

IF_DEBUG {
   printDebug(this);
   printDebug(thas);
}
0 голосов
/ 04 мая 2010

эм, почему бы не использовать макрос препроцессора по-другому?

Просто из головы, что-то вроде:

  #define DEBUG_TRACE(p)
  #ifdef PRINT_DEBUG
    printDebug(p);
  #else
    ;
  #endif
...