Бенчмаркинг с использованием <ctime>и переупорядочение команд - PullRequest
6 голосов
/ 22 ноября 2010

До сих пор я использовал традиционный способ сравнения параллельных методов, который заключается в измерении истекшей продолжительности для ряда прогонов:

template <typename Functor>
double benchmark(Functor const& f, size_t nbRuns)
{
  if (nbRuns == 0) { return 0.0; }

  f(); // Initialize before measuring, I am not interesting in setup cost

  time_t begin = time(0);
  for (size_t i = 0; i != nbRuns; ++i) { f(); }
  time_t end = time(0);

  return difftime(end, begin);
}

, который казался все в порядке и до тех пор, пока я не натолкнулся на этот вопрос: цикл в C ++ 0x .

Что меня удивляет, так это то, что компилятору разрешено выполнять вывод ДО цикла ... и мне вдруг стало интересно:

Что мешает компилятору выполнить time_t end = time(0); перед циклом?

потому что, если бы это произошло, это как-то испортило бы мой маленький тестовый код.

И пока мы находимся на этом, если когда-либо может измениться порядок в этой ситуации:

Как можно предотвратить это?

Я не мог думать о соответствующих тегах, кроме тегов C ++, если кто-то думает, что я пропустил один, не стесняйтесь добавлять его

Ответы [ 2 ]

6 голосов
/ 22 ноября 2010

Это сложный вопрос.

Что мешает компилятору выполнить time_t end = time (0);перед циклом здесь?

Как правило, ничего;на самом деле, даже в C ++ 03.Из-за правила «как будто» компилятор может генерировать любой код, который имеет такое же наблюдаемое поведение.Это означает, что если пропуск f() не изменит какой-либо заданный ввод / вывод или доступ к volatiles, он может вообще не запускаться f().

Что меня удивляет, так это то, что компиляторразрешено выполнять вывод ДО цикла

Это не совсем так - проблема с пустым циклом состоит в том, что C ++ 0x не считает простое нетерминирование наблюдаемым поведением.Дело не в том, что он может переупорядочивать пустой цикл и вывод "Hello", скорее, компилятор может вообще пропустить пустой цикл.

2 голосов
/ 22 ноября 2010

Обычно я помещаю свой таймер в область видимости, используя объект, чтобы он вычислял «конец» в своем деструкторе, когда он выходит из области видимости.

Разрешено ли компилятору выполнять свой деструктор, пока он еще находится в области видимости? Я не знаю.

Конечно, time_t измеряет только секунды, поэтому я обычно измерял бы более мелкое зерно, обычно миллисекунды. Иногда миллисекунды недостаточно детализированы (например, очень маленькие функции, которые вызываются много раз), и в этом случае вы, вероятно, будете использовать микросекунды.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...