Среднее время работы приложения

Есть собранная программа, написанная на C/C++. Как измерить среднее время её выполнения?

С помощью утилиты time можно 1 раз прогнать приложение. Есть ли подобная утилита, которая сделает это n раз и выведет среднее время работы?


Ответы (3 шт):

Автор решения: Harry

Раз плюнуть написать :)

#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);

    }
}
→ Ссылка
Автор решения: avp

Попробовал быстренько стандартными средствами, без 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"}'
→ Ссылка