1
votes

Mesure du temps d'exécution lors de l'utilisation de threads

Je voudrais mesurer le temps d'exécution de certains codes. Le code commence dans la fonction main () et se termine dans un gestionnaire d'événements.

J'ai un code C ++ 11 qui ressemble à ceci:

#include <iostream>

#include <time.h>

...

volatile clock_t t;

void EventHandler()
{
    // when this function called is the end of the part that I want to measure
    t = clock() - t;
    std::cout << "time in seconds: " << ((float)t)/CLOCKS_PER_SEC;
}

int main()
{
    MyClass* instance = new MyClass(EventHandler); // this function starts a new std::thread
    instance->start(...); // this function only passes some data to the thread working data, later the thread will call EventHandler()
    t = clock();
    return 0;
}

Donc c'est garanti que le EventHandler () ne sera appelé qu'une seule fois, et seulement après un appel instance-> start ().

Cela fonctionne, ce code me donne une sortie, mais c'est un code horrible, il utilise une variable globale et différents threads accèdent à la variable globale. Cependant, je ne peux pas changer l'API utilisée (le constructeur, la façon dont le thread appelle EventHandler).

Je voudrais demander s'il existe une meilleure solution.

Merci.


2 commentaires

FYI: volatile n'est pas atomique <>, si cela fonctionne du tout, c'est essentiellement de la chance.


Il y a un problème de race ici. Si le thread de travail est suffisamment rapide, EventHandler pourrait être appelé avant que t ne soit initialisé pour la première fois ... Vous feriez mieux de ne pas tenter de mesurer le temps entre les threads. C'est juste aléatoire.


3 Réponses :


0
votes

L'appel clock () ne filtrera pas les exécutions de différents processus et threads exécutés par le planificateur en parallèle avec le thread du gestionnaire d'événements du programme. Il existe des alternatives comme times () et getrusage () qui indiquent l'heure du processus au processeur. Bien que cela ne soit pas clairement mentionné sur le comportement des threads pour ces appels, mais s'il s'agit de Linux, les threads sont traités comme des processus mais cela doit être étudié.


0 commentaires

0
votes

clock () est le mauvais outil ici, car il ne compte pas le temps réellement requis par le CPU pour exécuter votre opération, par exemple, si le thread ne fonctionne pas du tout, le temps est toujours compté.

À la place, vous devez utiliser des API spécifiques à la plate-forme, telles que pthread_getcpuclockid pour les systèmes compatibles POSIX (vérifiez si _POSIX_THREAD_CPUTIME est défini), qui compte le temps réel passé par un thread spécifique.

Vous pouvez jeter un œil à une bibliothèque d'analyse comparative que j'ai écrite pour C ++ et qui prend en charge mesure sensible au thread (voir l'implémentation de struct thread_clock ).

Ou, vous pouvez utiliser l'extrait de code de page de manuel :

/* Link with "-lrt" */

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>

#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static void *
thread_start(void *arg)
{
    printf("Subthread starting infinite loop\n");
    for (;;)
        continue;
}

static void
pclock(char *msg, clockid_t cid)
{
    struct timespec ts;
    printf("%s", msg);
    if (clock_gettime(cid, &ts) == -1)
        handle_error("clock_gettime");
    printf("%4ld.%03ld\n", ts.tv_sec, ts.tv_nsec / 1000000);
}

int
main(int argc, char *argv[])
{
    pthread_t thread;
    clockid_t cid;
    int j, s;

    s = pthread_create(&thread, NULL, thread_start, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_create");

    printf("Main thread sleeping\n");
    sleep(1);

    printf("Main thread consuming some CPU time...\n");
    for (j = 0; j < 2000000; j++)
        getppid();

    pclock("Process total CPU time: ", CLOCK_PROCESS_CPUTIME_ID);

    s = pthread_getcpuclockid(pthread_self(), &cid);
    if (s != 0)
        handle_error_en(s, "pthread_getcpuclockid");

    pclock("Main thread CPU time:   ", cid);

    /* The preceding 4 lines of code could have been replaced by:
    pclock("Main thread CPU time:   ", CLOCK_THREAD_CPUTIME_ID); */

    s = pthread_getcpuclockid(thread, &cid);
    if (s != 0)
        handle_error_en(s, "pthread_getcpuclockid");
    pclock("Subthread CPU time: 1    ", cid);

    exit(EXIT_SUCCESS);         /* Terminates both threads */
}


0 commentaires

1
votes

La variable globale est inévitable, tant que MyClass attend une fonction simple et qu'il n'y a aucun moyen de passer un pointeur de contexte avec la fonction ...

Vous pouvez écrire le code légèrement mais de manière plus ordonnée:

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

struct MyClass
{
    typedef void (CallbackFunc)();

    constexpr explicit MyClass(CallbackFunc* handler)
     : m_handler(handler)
    {
    }

    void Start()
    {
        std::thread(&MyClass::ThreadFunc, this).detach();
    }

private:
    void ThreadFunc()
    {
        std::this_thread::sleep_for(std::chrono::seconds(5));
        m_handler();
    }

    CallbackFunc*     m_handler;
};


std::promise<std::chrono::time_point<std::chrono::high_resolution_clock>>   gEndTime;

void EventHandler()
{
    gEndTime.set_value(std::chrono::high_resolution_clock::now());
}


int main()
{
    MyClass         task(EventHandler);

    auto            trigger = gEndTime.get_future();
    auto            startTime = std::chrono::high_resolution_clock::now();
    task.Start();
    trigger.wait();

    std::chrono::duration<double>   diff = trigger.get() - startTime;

    std::cout << "Duration = " << diff.count() << " secs." << std::endl;

    return 0;
}


0 commentaires