Среднее время работы приложения
Есть собранная программа, написанная на C/C++. Как измерить среднее время её выполнения?
С помощью утилиты time можно 1 раз прогнать приложение. Есть ли подобная утилита, которая сделает это n раз и выведет среднее время работы?
Ответы (3 шт):
~$ perf stat -r 100 ./program
https://github.com/Hellseher/cix/blob/master/spices/cix-perf.org
Раз плюнуть написать :)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <process.h>
#include <chrono>
class muTimer
{
using Clock = std::chrono::high_resolution_clock;
bool active = false;
Clock::duration duration_;
Clock::time_point start_ = Clock::now(), stop_ = Clock::now();
muTimer(const muTimer&) = delete;
muTimer& operator=(const muTimer&) = delete;
public:
using ns = std::chrono::nanoseconds;
using mks = std::chrono::microseconds;
using ms = std::chrono::milliseconds;
muTimer() { reset(); start(); }
~muTimer() = default;
muTimer& reset()
{
duration_ = std::chrono::nanoseconds(0);
active = false;
return *this;
}
muTimer& start()
{
if (!active)
{
start_ = Clock::now();
active = true;
}
return *this;
}
muTimer& stop()
{
if (active)
{
stop_ = Clock::now();
duration_ += stop_ - start_;
active = false;
}
return *this;
}
template<typename T = mks>
unsigned long long duration()
{
return static_cast<unsigned long long>
(std::chrono::duration_cast<T>(stop_-start_).count());
}
};
void help()
{
puts("timeit [-n rep_count] cmd args...");
exit(1);
}
int main(int argc, const char * argv[])
{
int repeats = 1;
int start = 1;
if (argc < 2) help();
if (_stricmp(argv[1],"-n") == 0)
{
if (argc < 3) help();
repeats = atoi(argv[2]);
start += 2;
}
long long total = 0;
double total2 = 0;
for(int i = 0; i < repeats; ++i)
{
muTimer mu;
int ret = _spawnvp(_P_WAIT,argv[start],argv+start);
mu.stop();
if (ret == -1)
{
printf("Error spawing process: ");
switch(errno)
{
case E2BIG : puts("too long list of arguments"); break;
case EINVAL: puts("invalid mode"); break;
case ENOENT: puts("executable file not found"); break;
case ENOMEM: puts("insufficient memory"); break;
default: printf("errno = %d\n",errno); break;
}
return 1;
}
total += mu.duration();
total2 += double(mu.duration())*mu.duration();
printf("Spawning successful; return state = %d\n",ret);
}
printf("\nTotal time = %6lld %03lld mks\n"
"Average time = %6lld %03lld mks\n",total/1000, total%1000,
(total + repeats/2)/repeats/1000, (total + repeats/2)/repeats%1000);
if (repeats > 1)
{
double x = total, x2 = total2;
int N = repeats;
x2 = sqrt((N*x2-x*x)/N/(N-1));
x = x/N;
printf(" = %.2lf +- %.2lf\n",x,x2);
}
}
Попробовал быстренько стандартными средствами, без perf
avp@avp-desktop:~/avp/hashcode$ perf
Command 'perf' not found, but can be installed with:
sudo apt install linux-tools-common
avp@avp-desktop:~/avp/hashcode$
(не везде же у нас могут быть права админа...),
используя для измерения time.
time выводит свои данные в stderr, поэтому получилось что-то в таком духе:
avp@avp-desktop:~/avp/hashcode$ (i=0; while [ $i -lt 10 ]; do time gcc t.c >/dev/null; i=$((i+1)); done) 2>&1 | grep real | tr "m.s" " " | awk '{ s += ($2 * 60 * 1000 + $3 * 1000 + $4); nli++ } END {print "avg real " s/nli/1000 " sec"}'
avg real 0.0441 sec
avp@avp-desktop:~/avp/hashcode$
Хочу обратить внимание на то, что stdout тестируемой программы перенаправляется в /dev/null, а весь блок шелловских инструкций заключается в ( ... ), образующих отдельный процесс. Это нужно для перенаправления stderr от последовательности команд time в конвейер.
Для этого перенаправления мы пишем конструкцию
(...) 2>&1 | ....
и в этот конвейер не должен попадать stdout от тестируемой программы (в данном примере gcc).
Само вычисление средноего арифметического (в секундах) осуществляется
awk '{ s += ($2 * 60 * 1000 + $3 * 1000 + $4); nli++ } END {print "avg real " s/nli/1000 " sec"}'