Контрольный код - деление на количество итераций или нет?

У меня была интересная дискуссия с моим другом о тестировании кода 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 с...

Итак, вот мои вопросы:

  1. мы должны делить (и) на количество итераций, если так, почему?
  2. Как мы можем напечатать 2.34385e-07 с в более удобочитаемой форме? (скажем, это заняло 0.00000003 с)?
  3. Должны ли мы сначала сделать вызов функции один раз, а после этого измерить время процессора для итераций, что-то вроде этого:

    // 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 ответ

  1. если вы разделите время на число итераций, то вы получите независимое от итераций сравнение времени выполнения одной функции: чем больше итераций, тем более точный результат. РЕДАКТИРОВАТЬ: его среднее время выполнения за n итераций.
  2. Вы можете умножить деленное время на 1e6, чтобы получить микросекунды за одну итерационную единицу (я предполагаю, что measureCPU возвращает secods)

    std::cout << 1e6*(e-s)/iterations << " s \n";
    
  3. как говорилось в @ogni42, вы получаете накладные расходы из цикла for в измеренное время, поэтому вы можете попытаться развернуть цикл немного, чтобы уменьшить ошибку измерения, делать 8–16 вызовов на каждую итерацию, попробовать разные счетчики вызовов, чтобы увидеть, как измеренное время изменяется:

    for( j = 0; j < iterations; j++ ) {
        function(args);
        function(args);
        function(args);
        function(args);
        ...
    }
    
  4. То, что вы в основном получаете, это меньшее, лучшее число. Если вы хотели получить более высокий балл, то вы можете измерить различные варианты функций, а затем получить время самого быстрого. Этот мог набрать 10 очков.

    score_for_actual_function = 10.0 * fastest_time / time_of_actual_function
    

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

Другие вопросы по тегам