it-swarm.com.de

Berechnen der Ausführungszeit eines Code-Snippets in C++

Ich muss die Ausführungszeit eines C++ - Code-Snippets in Sekunden berechnen. Es muss entweder auf Windows- oder Unix-Computern funktionieren.

Ich verwende dazu den folgenden Code. (Import vor)

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

Bei kleinen Eingaben oder kurzen Anweisungen wie a = a + 1 bekomme ich jedoch "0 Sekunden". Ich denke, es muss ungefähr 0,0000001 Sekunden oder so ähnlich sein.

Ich erinnere mich, dass System.nanoTime() in Java in diesem Fall ziemlich gut funktioniert. Ich kann jedoch nicht dieselbe exakte Funktionalität von clock() von C++ erhalten.

Hast du eine Lösung?

113
AhmetB - Google

Sie können diese Funktion verwenden, die ich geschrieben habe. Sie rufen GetTimeMs64() auf und geben die Anzahl der seit der Unix-Epoche verstrichenen Millisekunden mithilfe der Systemuhr zurück - genau wie time(NULL), außer in Millisekunden.

Es funktioniert sowohl unter Windows als auch unter Linux. es ist fadensicher.

Beachten Sie, dass die Granularität unter Windows 15 ms beträgt. Unter Linux ist es von der Implementierung abhängig, aber normalerweise auch 15 ms.

#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
}
112
Andreas Bonini

Ich habe ein anderes Arbeitsbeispiel, das Mikrosekunden verwendet (UNIX, POSIX usw.).

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

Hier ist die Datei, in der wir das codiert haben:

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

42
arhuaco

Hier ist eine einfache Lösung in C++ 11, die eine zufriedenstellende Auflösung bietet.

#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_;
};

Oder an * nix für 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_;
};

Hier ist die Beispielnutzung:

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;
}

Von https://Gist.github.com/gongzhitaao/7062087

32
gongzhitaao
#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;
}

Wenn progress_timer den Gültigkeitsbereich verlässt, druckt er die seit seiner Erstellung verstrichene Zeit aus.

UPDATE: Ich habe einen einfachen Standalone-Ersatz (OSX/iOS, aber einfach zu portieren) gemacht: https://github.com/catnapgames/TestTimerScoped

18
Tomas Andrle

Windows bietet die Funktion QueryPerformanceCounter () und Unix verfügt über die Funktion "gettimeofday ()". Beide Funktionen können mindestens 1 Mikrosekunde Differenz messen. 

5
Captain Comic

In einigen Programmen, die ich geschrieben habe, habe ich RDTS für diesen Zweck verwendet. Bei RDTSC geht es nicht um die Zeit, sondern um die Anzahl der Zyklen ab dem Start des Prozessors. Sie müssen es auf Ihrem System kalibrieren, um ein Ergebnis in Sekundenschnelle zu erhalten, aber es ist sehr praktisch, wenn Sie die Leistung bewerten möchten. Noch besser ist es, die Anzahl der Zyklen direkt zu verwenden, ohne zu versuchen, sie auf Sekunden zurückzusetzen.

(Link oben bezieht sich auf eine französische Wikipedia-Seite, jedoch mit C++ - Codebeispielen. Die englische Version ist hier ).

3
kriss

(Windows-spezifische Lösung) Die aktuelle (etwa 2017) Möglichkeit, genaue Timings unter Windows zu erhalten, ist die Verwendung von "QueryPerformanceCounter". Dieser Ansatz hat den Vorteil, dass er sehr genaue Ergebnisse liefert und wird von den MS empfohlen. Ploppen Sie einfach den Code-Blob in eine neue Konsolen-App, um ein funktionierendes Beispiel zu erhalten. Hier gibt es eine lange Diskussion: Zeitstempel mit hoher Auflösung erwerben

#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
pmw1234

Ich empfehle die Verwendung der Standard-Bibliotheksfunktionen, um Zeitinformationen vom System zu erhalten.

Wenn Sie eine genauere Auflösung wünschen, führen Sie mehr Ausführungsiterationen durch. Anstatt das Programm einmal auszuführen und Samples abzurufen, führen Sie es mindestens 1000 Mal aus.

2
Thomas Matthews

Wenn Sie gute exakte Ergebnisse erzielen möchten, hängt Ihre Ausführungszeit wie oben angegeben von der Thread-Planung ab. Eine vollkommen sichere Lösung, die genau die gleichen Zeiten für jeden Test ergeben sollte, besteht darin, Ihr Programm so zu kompilieren, dass es unabhängig vom Betriebssystem ist, und den Computer hochzufahren, um das Programm in einer betriebssystemfreien Umgebung auszuführen. Ein guter Ersatz dafür ist jedoch, die Affinität des aktuellen Threads auf 1 Kern und die Priorität auf den höchsten Wert festzulegen. Das Ergebnis sind sehr konsistente Ergebnisse. Eine weitere Sache ist, dass Sie Optimierungen deaktivieren sollten. Dies bedeutet für g ++ oder gcc, dass der Befehlszeile -O0 hinzugefügt wird, um zu verhindern, dass der getestete Code optimiert wird. Hier ist ein Beispiel, wie ich Quadratwurzel-Funktionen auf einem Windows-Computer als Benchmarking benutze.

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

Dank auch an Mike Jarvis für seinen Timer.

Beachten Sie (dies ist sehr wichtig), dass Sie, wenn Sie größere Code-Snippets ausführen, die Anzahl der Iterationen wirklich reduzieren müssen, damit Ihr Computer nicht einfriert.

2
Jack Giffin

Es ist besser, die innere Schleife mehrmals mit dem Performance-Timing nur einmal auszuführen und den Mittelwert durch Teilen der Wiederholungen der inneren Schleife zu bestimmen, als das Ganze (Loop + Performance-Timing) mehrmals und durchschnittlich auszuführen. Dadurch wird der Aufwand für den Performance-Timing-Code gegenüber dem tatsächlichen Profilabschnitt reduziert.

Wickeln Sie Ihre Timer-Anrufe für das entsprechende System ein. Für Windows ist QueryPerformanceCounter ziemlich schnell und "sicher" zu verwenden.

Sie können "rdtsc" auch auf jedem modernen X86-PC verwenden. Bei einigen Multicore-Computern kann es jedoch zu Problemen kommen (Core-Hopping kann den Timer ändern) oder wenn Sie die Geschwindigkeitsstufe aktiviert haben.

2
Adisak

nur eine einfache Klasse, die den Codeblock als Benchmark verwendet:

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
nullqube

Ich habe ein Lambda erstellt, das den Funktionsaufruf N-mal aufruft und Ihnen den Durchschnitt zurückgibt.

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

Sie finden den C++ 11-Header hier .

0
burner

In Fällen, in denen Sie den gleichen Code-Code bei jeder Ausführung zeitgesteuert ausführen möchten (z. B. für die Profilerstellung von Code, von dem Sie annehmen, dass er einen Engpass darstellt), finden Sie hier einen Wrapper um (eine geringfügige Änderung an) der Funktion von Andreas Bonini, die ich nützlich finde:

#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
Mike Jarvis

Ich habe ein einfaches Dienstprogramm zum Messen der Leistung von Codeblöcken erstellt, indem die Chrono-Bibliothek high_resolution_clock verwendet wird: https://github.com/nfergu/codetimer .

Timings können gegen verschiedene Schlüssel aufgezeichnet werden, und eine aggregierte Ansicht der Timings für jeden Schlüssel kann angezeigt werden.

Die Verwendung ist wie folgt:

#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
Neil

Sie können sich auch [cxx-rtimers][1] auf GitHub ansehen, die einige Header-Routinen zum Erfassen von Statistiken zur Laufzeit eines beliebigen Codeblocks enthält, in dem Sie eine lokale Variable erstellen können. Diese Timer verfügen über Versionen, die std :: chrono unter C++ 11 oder Timer aus der Boost-Bibliothek oder Standard-POSIX-Timerfunktionen verwenden. Diese Timer geben die durchschnittliche, maximale und minimale Dauer einer Funktion sowie die Anzahl der Aufrufe an. Sie können wie folgt verwendet werden:

#include <rtimers/cxx11.hpp>

void expensiveFunction() {
    static rtimers::cxx11::DefaultTimer timer("expensive");
    auto scopedStartStop = timer.scopedStart();
    // Do something costly...
}
0
rwp

boost :: timer gibt Ihnen wahrscheinlich so viel Genauigkeit, wie Sie benötigen. Es ist bei weitem nicht genau genug, um Ihnen zu sagen, wie lange a = a+1; dauern wird, aber aus welchem ​​Grund müssten Sie sich etwas Zeit nehmen, für das ein paar Nanosekunden benötigt werden?

0
Brendan Long