Comment calculer le temps d'exécution d'un extrait de Code en C++

je dois calculer le temps d'exécution d'un morceau de code C++ en quelques secondes. Il doit fonctionner sur Windows ou Unix.

j'utilise le code suivant pour faire ceci. (import avant)

clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;

Cependant pour les petites entrées ou les déclarations courtes telles que a = a + 1, j'obtiens le résultat "0 secondes". Je pense que cela doit être quelque chose comme 0.0000001 secondes ou quelque chose comme ça.

je me souviens que System.nanoTime() en Java fonctionne assez bien dans ce cas. Cependant, je ne peux pas obtenir la même fonctionnalité exacte de la fonction clock() de C++.

avez-vous une solution?

109
demandé sur Yu Hao 2009-12-07 19:56:07

16 réponses

vous pouvez utiliser cette fonction que j'ai écrite. Vous appelez GetTimeMs64() , et il renvoie le nombre de millisecondes écoulées depuis l'époque unix en utilisant l'horloge du système - le tout comme time(NULL) , sauf en millisecondes.

il fonctionne à la fois sur windows et linux; il est thread sûr.

notez que la granularité est de 15 ms sous windows; sous linux, elle dépend de l'implémentation, mais elle est généralement de 15 ms également.

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <ctime>
#endif

/* Remove if already defined */
typedef long long int64; typedef unsigned long long uint64;

/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
 * windows and linux. */

uint64 GetTimeMs64()
{
#ifdef _WIN32
 /* Windows */
 FILETIME ft;
 LARGE_INTEGER li;

 /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
  * to a LARGE_INTEGER structure. */
 GetSystemTimeAsFileTime(&ft);
 li.LowPart = ft.dwLowDateTime;
 li.HighPart = ft.dwHighDateTime;

 uint64 ret = li.QuadPart;
 ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
 ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */

 return ret;
#else
 /* Linux */
 struct timeval tv;

 gettimeofday(&tv, NULL);

 uint64 ret = tv.tv_usec;
 /* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
 ret /= 1000;

 /* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
 ret += (tv.tv_sec * 1000);

 return ret;
#endif
}
110
répondu Andreas Bonini 2015-04-10 19:55:24

j'ai un autre exemple de travail qui utilise des microsecondes (UNIX, POSIX, etc.).

    #include <sys/time.h>
    typedef unsigned long long timestamp_t;

    static timestamp_t
    get_timestamp ()
    {
      struct timeval now;
      gettimeofday (&now, NULL);
      return  now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
    }

    ...
    timestamp_t t0 = get_timestamp();
    // Process
    timestamp_t t1 = get_timestamp();

    double secs = (t1 - t0) / 1000000.0L;

voici le fichier où nous l'avons codé:

https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c

42
répondu arhuaco 2016-05-08 00:12:08

Voici une solution simple en C++11 qui vous donne une résolution satisfaisante.

#include <iostream>
#include <chrono>

class Timer
{
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const { 
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }

private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

Ou sur *nix, c++03

#include <iostream>
#include <ctime>

class Timer
{
public:
    Timer() { clock_gettime(CLOCK_REALTIME, &beg_); }

    double elapsed() {
        clock_gettime(CLOCK_REALTIME, &end_);
        return end_.tv_sec - beg_.tv_sec +
            (end_.tv_nsec - beg_.tv_nsec) / 1000000000.;
    }

    void reset() { clock_gettime(CLOCK_REALTIME, &beg_); }

private:
    timespec beg_, end_;
};

Voici l'exemple d'usage:

int main()
{
    Timer tmr;
    double t = tmr.elapsed();
    std::cout << t << std::endl;

    tmr.reset();
    t = tmr.elapsed();
    std::cout << t << std::endl;

    return 0;
}

de https://gist.github.com/gongzhitaao/7062087

30
répondu gongzhitaao 2018-03-21 15:35:06
#include <boost/progress.hpp>

using namespace boost;

int main (int argc, const char * argv[])
{
  progress_timer timer;

  // do stuff, preferably in a 100x loop to make it take longer.

  return 0;
}

quand progress_timer sort de la portée il imprimera le temps écoulé depuis sa création.

UPDATE : j'ai fait un simple remplacement autonome (OSX / iOS mais facile à port): https://github.com/catnapgames/TestTimerScoped

18
répondu Tomas Andrle 2014-08-03 13:08:21

Windows fournit la fonction QueryPerformanceCounter (), et Unix A gettimeofday () les deux fonctions peuvent mesurer au moins 1 micro-différence de seconde.

5
répondu Captain Comic 2009-12-07 17:00:09

dans certains programmes que j'ai écrit, j'ai utilisé RDTS à cette fin. RDTSC n'est pas une question de temps mais de nombre de cycles depuis le début du processeur. Vous devez le calibrer sur votre système pour obtenir un résultat en seconde, mais il est vraiment pratique lorsque vous voulez évaluer la performance, il est encore mieux d'utiliser le nombre de cycles directement sans essayer de les changer en secondes.

(lien ci-dessus vers une page Wikipédia en français, mais il y a des exemples de code C++), la version anglaise est ici )

3
répondu kriss 2015-03-23 19:35:06

je suggère d'utiliser les fonctions de bibliothèque standard pour obtenir des informations sur l'heure à partir du système.

Si vous voulez une résolution plus fine, effectuez plus d'itérations d'exécution. Au lieu d'exécuter le programme une fois et d'obtenir des échantillons, l'exécuter 1000 fois ou plus.

2
répondu Thomas Matthews 2009-12-07 18:32:57

il est préférable d'exécuter la boucle intérieure plusieurs fois avec le temps de performance seulement une fois et Moyenne en divisant les répétitions de boucle intérieure que d'exécuter l'ensemble de la chose (boucle + temps de performance) plusieurs fois et moyenne. Cela réduira les frais généraux du code de synchronisation de performance par rapport à votre section profilée réelle.

enveloppez votre minuteur demande le système approprié. Pour Windows, QueryPerformanceCounter est assez rapide et" sûr " à utiliser.

vous pouvez utiliser" rdtsc " sur n'importe quel PC x86 moderne aussi bien, mais il peut y avoir des problèmes sur certaines machines multicore (core hopping peut changer de minuterie) ou si vous avez vitesse-pas d'une certaine sorte allumée.

2
répondu Adisak 2009-12-08 20:10:22

si vous voulez obtenir de bons résultats exacts, alors comme indiqué ci-dessus, votre temps d'exécution dépend de la planification du thread. Une solution complète et infaillible à cela, qui devrait produire exactement les mêmes temps par chaque test, est de compiler votre programme pour être indépendant du système D'exploitation et démarrer votre ordinateur de manière à exécuter le programme dans un environnement sans système d'exploitation. Cependant, un bon substitut à cela est juste de mettre l'affinité du fil courant à 1 core et la priorité à la plus haute. Le résultat de le faire c'est des résultats très cohérents. Une autre chose est que vous devez désactiver les optimisations, ce qui pour G++ ou gcc signifie ajouter-O0 à la ligne de commande, pour empêcher que votre code soit testé pour être optimisé. Voici un exemple de la façon dont je suis le bench-marking racine carrée fonctions sur un ordinateur Windows.

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <chrono>
#include <cmath>
#include <windows.h>
#include <intrin.h>
#pragma intrinsic(__rdtsc)

class Timer {
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const { 
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }
private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

unsigned int guess_sqrt32(register unsigned int n) {
    register unsigned int g = 0x8000;
    if(g*g > n) {
        g ^= 0x8000;
    }
    g |= 0x4000;
    if(g*g > n) {
        g ^= 0x4000;
    }
    g |= 0x2000;
    if(g*g > n) {
        g ^= 0x2000;
    }
    g |= 0x1000;
    if(g*g > n) {
        g ^= 0x1000;
    }
    g |= 0x0800;
    if(g*g > n) {
        g ^= 0x0800;
    }
    g |= 0x0400;
    if(g*g > n) {
        g ^= 0x0400;
    }
    g |= 0x0200;
    if(g*g > n) {
        g ^= 0x0200;
    }
    g |= 0x0100;
    if(g*g > n) {
        g ^= 0x0100;
    }
    g |= 0x0080;
    if(g*g > n) {
        g ^= 0x0080;
    }
    g |= 0x0040;
    if(g*g > n) {
        g ^= 0x0040;
    }
    g |= 0x0020;
    if(g*g > n) {
        g ^= 0x0020;
    }
    g |= 0x0010;
    if(g*g > n) {
        g ^= 0x0010;
    }
    g |= 0x0008;
    if(g*g > n) {
        g ^= 0x0008;
    }
    g |= 0x0004;
    if(g*g > n) {
        g ^= 0x0004;
    }
    g |= 0x0002;
    if(g*g > n) {
        g ^= 0x0002;
    }
    g |= 0x0001;
    if(g*g > n) {
        g ^= 0x0001;
    }
    return g;
}

unsigned int empty_function( unsigned int _input ) {
    return _input;
}

unsigned long long empty_ticks=0;
double empty_seconds=0;
Timer my_time;

template<unsigned int benchmark_repetitions>
void benchmark( char* function_name, auto (*function_to_do)( auto ) ) {
    register unsigned int i=benchmark_repetitions;
    register unsigned long long start=0;
    my_time.reset();
    start=__rdtsc();
    while ( i-- ) {
        (*function_to_do)( i << 7 );
    }
    if ( function_name == nullptr ) {
        empty_ticks = (__rdtsc()-start);
        empty_seconds = my_time.elapsed();
        std::cout<< "Empty:\n" << empty_ticks
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << empty_seconds
                << " seconds\n\n";
    } else {
        std::cout<< function_name<<":\n" << (__rdtsc()-start-empty_ticks)
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << (my_time.elapsed()-empty_seconds)
                << " seconds\n\n";
    }
}


int main( void ) {
    void* Cur_Thread=   GetCurrentThread();
    void* Cur_Process=  GetCurrentProcess();
    unsigned long long  Current_Affinity;
    unsigned long long  System_Affinity;
    unsigned long long furthest_affinity;
    unsigned long long nearest_affinity;

    if( ! SetThreadPriority(Cur_Thread,THREAD_PRIORITY_TIME_CRITICAL) ) {
        SetThreadPriority( Cur_Thread, THREAD_PRIORITY_HIGHEST );
    }
    if( ! SetPriorityClass(Cur_Process,REALTIME_PRIORITY_CLASS) ) {
        SetPriorityClass( Cur_Process, HIGH_PRIORITY_CLASS );
    }
    GetProcessAffinityMask( Cur_Process, &Current_Affinity, &System_Affinity );
    furthest_affinity = 0x8000000000000000ULL>>__builtin_clzll(Current_Affinity);
    nearest_affinity  = 0x0000000000000001ULL<<__builtin_ctzll(Current_Affinity);
    SetProcessAffinityMask( Cur_Process, furthest_affinity );
    SetThreadAffinityMask( Cur_Thread, furthest_affinity );

    const int repetitions=524288;

    benchmark<repetitions>( nullptr, empty_function );
    benchmark<repetitions>( "Standard Square Root", standard_sqrt );
    benchmark<repetitions>( "Original Guess Square Root", original_guess_sqrt32 );
    benchmark<repetitions>( "New Guess Square Root", new_guess_sqrt32 );


    SetThreadPriority( Cur_Thread, THREAD_PRIORITY_IDLE );
    SetPriorityClass( Cur_Process, IDLE_PRIORITY_CLASS );
    SetProcessAffinityMask( Cur_Process, nearest_affinity );
    SetThreadAffinityMask( Cur_Thread, nearest_affinity );
    for (;;) { getchar(); }

    return 0;
}

aussi, crédit à Mike Jarvis pour son minuteur.

et, s'il vous plaît noter (c'est très important) que si vous allez courir plus d'extraits de code, alors vous devez VRAIMENT baisser le nombre d'itérations pour empêcher votre ordinateur de geler.

2
répondu Jack Giffin 2016-10-13 22:11:06

(windows solution spécifique) La façon actuelle (vers 2017) d'obtenir des minuteries précises sous windows est d'utiliser "QueryPerformanceCounter". Cette approche a l'avantage de donner des résultats très précis et est recommandé par MS.Just plop le code blob dans une nouvelle application de console pour obtenir un échantillon de travail. Il y a une longue discussion ici: acquérir des horodateurs haute résolution

#include <iostream>
#include <tchar.h>
#include <windows.h>

int main()
{
constexpr int MAX_ITER{ 10000 };
constexpr __int64 us_per_hour{ 3600000000ull }; // 3.6e+09
constexpr __int64 us_per_min{ 60000000ull };
constexpr __int64 us_per_sec{ 1000000ull };
constexpr __int64 us_per_ms{ 1000ull };

// easy to work with
__int64 startTick, endTick, ticksPerSecond, totalTicks = 0ull;

QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond);

for (int iter = 0; iter < MAX_ITER; ++iter) {// start looping
    QueryPerformanceCounter((LARGE_INTEGER *)&startTick); // Get start tick
    // code to be timed
    std::cout << "cur_tick = " << iter << "\n";
    QueryPerformanceCounter((LARGE_INTEGER *)&endTick); // Get end tick
    totalTicks += endTick - startTick; // accumulate time taken
}

// convert to elapsed microseconds
__int64 totalMicroSeconds =  (totalTicks * 1000000ull)/ ticksPerSecond;

__int64 hours = totalMicroSeconds / us_per_hour;
totalMicroSeconds %= us_per_hour;
__int64 minutes = totalMicroSeconds / us_per_min;
totalMicroSeconds %= us_per_min;
__int64 seconds = totalMicroSeconds / us_per_sec;
totalMicroSeconds %= us_per_sec;
__int64 milliseconds = totalMicroSeconds / us_per_ms;
totalMicroSeconds %= us_per_ms;


std::cout << "Total time: " << hours << "h ";
std::cout << minutes << "m " << seconds << "s " << milliseconds << "ms ";
std::cout << totalMicroSeconds << "us\n";

return 0;
}
2
répondu pmw1234 2017-12-07 16:28:51

juste une simple classe qui référence la codeblock :

using namespace std::chrono;

class benchmark {
  public:
  time_point<high_resolution_clock>  t0, t1;
  unsigned int *d;
  benchmark(unsigned int *res) : d(res) { 
                 t0 = high_resolution_clock::now();
  }
  ~benchmark() { t1 = high_resolution_clock::now();
                  milliseconds dur = duration_cast<milliseconds>(t1 - t0);
                  *d = dur.count();
  }
};
// simple usage 
// unsigned int t;
// { // put the code in a block
//  benchmark bench(&t);
//  // ...
//  // code to benchmark
// }
// HERE the t contains time in milliseconds

// one way to use it can be :
#define BENCH(TITLE,CODEBLOCK) \
  unsigned int __time__##__LINE__ = 0;  \
  { benchmark bench(&__time__##__LINE__); \
      CODEBLOCK \
  } \
  printf("%s took %d ms\n",(TITLE),__time__##__LINE__);


int main(void) {
  BENCH("TITLE",{
    for(int n = 0; n < testcount; n++ )
      int a = n % 3;
  });
  return 0;
}
1
répondu nullqube 2018-04-05 06:26:12

boost::timer vous donnera probablement autant de précision que vous aurez besoin. C'est loin d'être assez précis pour vous dire combien de temps prendra a = a+1; , mais quelle raison auriez-vous de chronométrer quelque chose qui prend quelques nanosecondes?

0
répondu Brendan Long 2010-02-26 00:51:31

j'ai créé un lambda qui vous appelle fonction appel N fois et vous renvoie la moyenne.

double c = BENCHMARK_CNT(25, fillVectorDeque(variable));

vous pouvez trouver l'en-tête c++11 ici .

0
répondu burner 2014-06-16 08:41:56

pour les cas où vous voulez chronométrer la même longueur de code chaque fois qu'il est exécuté (par exemple pour le code de profilage que vous pensez pourrait être un goulot d'étranglement), voici un enveloppement autour (une légère modification à la fonction de Andreas Bonini que je trouve utile:

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#endif

/*
 *  A simple timer class to see how long a piece of code takes. 
 *  Usage:
 *
 *  {
 *      static Timer timer("name");
 *
 *      ...
 *
 *      timer.start()
 *      [ The code you want timed ]
 *      timer.stop()
 *
 *      ...
 *  }
 *
 *  At the end of execution, you will get output:
 *
 *  Time for name: XXX seconds
 */
class Timer
{
public:
    Timer(std::string name, bool start_running=false) : 
        _name(name), _accum(0), _running(false)
    {
        if (start_running) start();
    }

    ~Timer() { stop(); report(); }

    void start() {
        if (!_running) {
            _start_time = GetTimeMicroseconds();
            _running = true;
        }
    }
    void stop() {
        if (_running) {
            unsigned long long stop_time = GetTimeMicroseconds();
            _accum += stop_time - _start_time;
            _running = false;
        }
    }
    void report() { 
        std::cout<<"Time for "<<_name<<": " << _accum / 1.e6 << " seconds\n"; 
    }
private:
    // cf. http://stackoverflow.com/questions/1861294/how-to-calculate-execution-time-of-a-code-snippet-in-c
    unsigned long long GetTimeMicroseconds()
    {
#ifdef _WIN32
        /* Windows */
        FILETIME ft;
        LARGE_INTEGER li;

        /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
         *   * to a LARGE_INTEGER structure. */
        GetSystemTimeAsFileTime(&ft);
        li.LowPart = ft.dwLowDateTime;
        li.HighPart = ft.dwHighDateTime;

        unsigned long long ret = li.QuadPart;
        ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
        ret /= 10; /* From 100 nano seconds (10^-7) to 1 microsecond (10^-6) intervals */
#else
        /* Linux */
        struct timeval tv;

        gettimeofday(&tv, NULL);

        unsigned long long ret = tv.tv_usec;
        /* Adds the seconds (10^0) after converting them to microseconds (10^-6) */
        ret += (tv.tv_sec * 1000000);
#endif
        return ret;
    }
    std::string _name;
    long long _accum;
    unsigned long long _start_time;
    bool _running;
};
0
répondu Mike Jarvis 2015-11-25 22:29:20

j'ai créé un utilitaire simple pour mesurer la performance de blocs de code, en utilisant le high_resolution_clock de la bibliothèque chrono: https://github.com/nfergu/codetimer .

Les minuteries

peuvent être enregistrées par rapport à différentes clés, et une vue agrégée des minuteries pour chaque clé peut être affichée.

Utilisation est la suivante:

#include <chrono>
#include <iostream>
#include "codetimer.h"

int main () {
    auto start = std::chrono::high_resolution_clock::now();
    // some code here
    CodeTimer::record("mykey", start);
    CodeTimer::printStats();
    return 0;
}
0
répondu Neil 2016-04-20 10:49:03

vous pouvez également regarder le [cxx-rtimers][1] sur GitHub, qui fournissent quelques routines d'en-tête seulement pour recueillir des statistiques sur le temps d'exécution de n'importe quel bloc de code où vous pouvez créer une variable locale. Ces minuteries ont des versions qui utilisent std:: chrono sur C++11, ou des minuteries de la bibliothèque Boost, ou des fonctions de minuterie POSIX standard. Ces minuteries indiqueront la durée moyenne, maximale et minimale d'une fonction, ainsi que le nombre de fois qu'elle est appelée. Ils peuvent être utilisés aussi simplement que

#include <rtimers/cxx11.hpp>

void expensiveFunction() {
    static rtimers::cxx11::DefaultTimer timer("expensive");
    auto scopedStartStop = timer.scopedStart();
    // Do something costly...
}
0
répondu rwp 2018-01-27 07:40:39