web-dev-qa-db-fra.com

Comment créer un minuteur haute résolution sous Linux pour mesurer les performances du programme?

J'essaie de comparer les performances du processeur graphique à celles du processeur. Pour le GPU NVIDIA, j’utilise les types cudaEvent_t pour obtenir un timing très précis.

Pour le processeur, j'ai utilisé le code suivant:

// Timers
clock_t start, stop;
float elapsedTime = 0;

// Capture the start time

start = clock();

// Do something here
.......

// Capture the stop time
stop = clock();
// Retrieve time elapsed in milliseconds
elapsedTime = (float)(stop - start) / (float)CLOCKS_PER_SEC * 1000.0f;

Apparemment, ce morceau de code n’est bon que si vous comptez en quelques secondes. En outre, les résultats sont parfois assez étranges.

Est-ce que quelqu'un connaît un moyen de créer un minuteur haute résolution sous Linux?

31
sj755

Vérifiez clock_gettime , qui est une interface POSIX pour les minuteries haute résolution.

Si, après avoir lu la page de manuel, vous vous interrogez sur la différence entre CLOCK_REALTIME et CLOCK_MONOTONIC, voir Différence entre CLOCK_REALTIME et CLOCK_MONOTONIC?

Voir la page suivante pour un exemple complet: http://www.guyrutenberg.com/2007/09/22/profiling-code-using-clock_gettime/

#include <iostream>
#include <time.h>
using namespace std;

timespec diff(timespec start, timespec end);

int main()
{
    timespec time1, time2;
    int temp;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
    for (int i = 0; i< 242000000; i++)
        temp+=temp;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
    cout<<diff(time1,time2).tv_sec<<":"<<diff(time1,time2).tv_nsec<<endl;
    return 0;
}

timespec diff(timespec start, timespec end)
{
    timespec temp;
    if ((end.tv_nsec-start.tv_nsec)<0) {
        temp.tv_sec = end.tv_sec-start.tv_sec-1;
        temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
    } else {
        temp.tv_sec = end.tv_sec-start.tv_sec;
        temp.tv_nsec = end.tv_nsec-start.tv_nsec;
    }
    return temp;
}
41
NPE

Pour résumer les informations présentées jusqu’à présent, ce sont les deux fonctions requises pour des applications types.

#include <time.h>

// call this function to start a nanosecond-resolution timer
struct timespec timer_start(){
    struct timespec start_time;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time);
    return start_time;
}

// call this function to end a timer, returning nanoseconds elapsed as a long
long timer_end(struct timespec start_time){
    struct timespec end_time;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time);
    long diffInNanos = (end_time.tv_sec - start_time.tv_sec) * (long)1e9 + (end_time.tv_nsec - start_time.tv_nsec);
    return diffInNanos;
}

Voici un exemple de leur utilisation pour calculer le temps nécessaire au calcul de la variance d’une liste d’entrées.

struct timespec vartime = timer_start();  // begin a timer called 'vartime'
double variance = var(input, MAXLEN);  // perform the task we want to time
long time_elapsed_nanos = timer_end(vartime);
printf("Variance = %f, Time taken (nanoseconds): %ld\n", variance, time_elapsed_nanos);
18
Alex
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);

il y a aussi CLOCK_REALTIME_HR, mais je ne suis pas sûr que cela fasse une différence.

1
Karoly Horvath

Êtes-vous intéressé par le temps passé au mur (combien de temps s'écoule réellement) ou le nombre de cycles (combien de cycles)? Dans le premier cas, vous devriez utiliser quelque chose comme gettimeofday.

Le minuteur ayant la résolution la plus élevée utilise l'instruction d'assemblage RDTSC x86. Cependant, ceci mesure les temps d'horloge, vous devez donc vous assurer que le mode d'économie d'énergie est désactivé.

La page wiki de TSC donne quelques exemples: http://en.wikipedia.org/wiki/Time_Stamp_Counter

1
Foo Bah

Après avoir lu ce fil, j'ai commencé à tester le code pour clock_gettime par rapport au chrono de c ++ 11 et ils ne semblent pas correspondre.

Il y a un énorme fossé entre eux!

Le std :: chrono :: secondes (1) semble être équivalent à ~ 30 000 du clock_gettime  

#include <ctime>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <thread>
#include <chrono>
#include <iomanip>
#include <vector>

timespec diff(timespec start, timespec end);
timespec get_cpu_now_time();
std::vector<timespec> get_start_end_pairs();
void output_deltas(const std::vector<timespec> &start_end_pairs);

//=============================================================
int main()
{
    std::cout << "Hello waiter" << std::endl; // flush is intentional
    std::vector<timespec> start_end_pairs = get_start_end_pairs();
    output_deltas(start_end_pairs);

    return EXIT_SUCCESS;
}

//=============================================================
std::vector<timespec> get_start_end_pairs()
{
    std::vector<timespec> start_end_pairs;
    for (int i = 0; i < 20; ++i)
    {
        start_end_pairs.Push_back(get_cpu_now_time());
        std::this_thread::sleep_for(std::chrono::seconds(1));
        start_end_pairs.Push_back(get_cpu_now_time());
    }

    return start_end_pairs;
}

//=============================================================
void output_deltas(const std::vector<timespec> &start_end_pairs)
{
    for (auto it_start = start_end_pairs.begin(); it_start != start_end_pairs.end(); it_start += 2)
    {
        auto it_end = it_start + 1;
        auto delta = diff(*it_start, *it_end);

        std::cout
            << "Waited ("
            << delta.tv_sec
            << "\ts\t"
            << std::setw(9)
            << std::setfill('0')
            << delta.tv_nsec
            << "\tns)"
            << std::endl;
    }
}

//=============================================================
timespec diff(timespec start, timespec end)
{
    timespec temp;
        temp.tv_sec = end.tv_sec-start.tv_sec;
        temp.tv_nsec = end.tv_nsec-start.tv_nsec;

        if (temp.tv_nsec < 0) {
        ++temp.tv_sec;
        temp.tv_nsec += 1000000000;
    }
    return temp;
}

//=============================================================
timespec get_cpu_now_time()
{
    timespec now_time;
    memset(&now_time, 0, sizeof(timespec));
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &now_time);

    return now_time;
}

sortie:

Waited (0   s   000064802   ns)
Waited (0   s   000028512   ns)
Waited (0   s   000030664   ns)
Waited (0   s   000041233   ns)
Waited (0   s   000013458   ns)
Waited (0   s   000024068   ns)
Waited (0   s   000027591   ns)
Waited (0   s   000028148   ns)
Waited (0   s   000033783   ns)
Waited (0   s   000022382   ns)
Waited (0   s   000027866   ns)
Waited (0   s   000028085   ns)
Waited (0   s   000028012   ns)
Waited (0   s   000028172   ns)
Waited (0   s   000022121   ns)
Waited (0   s   000052940   ns)
Waited (0   s   000032138   ns)
Waited (0   s   000028082   ns)
Waited (0   s   000034486   ns)
Waited (0   s   000018875   ns)
0
radato

application epoll: https://github.com/ielife/simple-timer-for-c-language

utiliser comme ceci:

timer_server_handle_t *timer_handle = timer_server_init(1024);
if (NULL == timer_handle) {
    fprintf(stderr, "timer_server_init failed\n");
    return -1;
}
ctimer timer1;
    timer1.count_ = 3;
    timer1.timer_internal_ = 0.5;
    timer1.timer_cb_ = timer_cb1;
    int *user_data1 = (int *)malloc(sizeof(int));
    *user_data1 = 100;
    timer1.user_data_ = user_data1;
    timer_server_addtimer(timer_handle, &timer1);

    ctimer timer2;
    timer2.count_ = -1;
    timer2.timer_internal_ = 0.5;
    timer2.timer_cb_ = timer_cb2;
    int *user_data2 = (int *)malloc(sizeof(int));
    *user_data2 = 10;
    timer2.user_data_ = user_data2;
    timer_server_addtimer(timer_handle, &timer2);

    sleep(10);

    timer_server_deltimer(timer_handle, timer1.fd);
    timer_server_deltimer(timer_handle, timer2.fd);
    timer_server_uninit(timer_handle);
0
Kevin Lee