Контрольный код - деление на количество итераций или нет?
У меня была интересная дискуссия с моим другом о тестировании кода C/C++ (или кода в целом). Мы написали простую функцию, которая использует getrusage
измерить время процессора для данного куска кода. (Он измеряет, сколько времени процессора потребовалось для запуска определенной функции). Позволь мне привести пример:
const int iterations = 409600;
double s = measureCPU();
for( j = 0; j < iterations; j++ )
function(args);
double e = measureCPU();
std::cout << (e-s)/iterations << " s \n";
Мы спорили, должны ли мы делить (и) на количество итераций или нет? Я имею в виду, что когда мы не делим его, результат находится в приемлемой форме (например, 3,0 с), но когда мы делим его, это дает нам результаты, такие как 2,34385e-07 с...
Итак, вот мои вопросы:
- мы должны делить (и) на количество итераций, если так, почему?
- Как мы можем напечатать 2.34385e-07 с в более удобочитаемой форме? (скажем, это заняло 0.00000003 с)?
Должны ли мы сначала сделать вызов функции один раз, а после этого измерить время процессора для итераций, что-то вроде этого:
// first function call, doesnt bother with it at all function(args); // real benchmarking const int iterations = 409600; double s = measureCPU(); for( j = 0; j < iterations; j++ ) function(args); double e = measureCPU(); std::cout << (e-s)/iterations << " s \n";
1 ответ
- если вы разделите время на число итераций, то вы получите независимое от итераций сравнение времени выполнения одной функции: чем больше итераций, тем более точный результат. РЕДАКТИРОВАТЬ: его среднее время выполнения за n итераций.
Вы можете умножить деленное время на 1e6, чтобы получить микросекунды за одну итерационную единицу (я предполагаю, что measureCPU возвращает secods)
std::cout << 1e6*(e-s)/iterations << " s \n";
как говорилось в @ogni42, вы получаете накладные расходы из цикла for в измеренное время, поэтому вы можете попытаться развернуть цикл немного, чтобы уменьшить ошибку измерения, делать 8–16 вызовов на каждую итерацию, попробовать разные счетчики вызовов, чтобы увидеть, как измеренное время изменяется:
for( j = 0; j < iterations; j++ ) { function(args); function(args); function(args); function(args); ... }
То, что вы в основном получаете, это меньшее, лучшее число. Если вы хотели получить более высокий балл, то вы можете измерить различные варианты функций, а затем получить время самого быстрого. Этот мог набрать 10 очков.
score_for_actual_function = 10.0 * fastest_time / time_of_actual_function
Эта оценка не зависит от времени, поэтому вы можете просто сравнить различные варианты функций, и функция может набрать менее одного балла... и остерегаться деления на ноль:)