Come calcolare il tempo di esecuzione di uno snippet di codice in C ++


121

Devo calcolare il tempo di esecuzione di uno snippet di codice C ++ in pochi secondi. Deve funzionare su macchine Windows o Unix.

Uso il codice seguente per farlo. (importa prima)

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

Tuttavia, per piccoli input o brevi istruzioni come a = a + 1, ottengo il risultato "0 secondi". Penso che debba essere qualcosa come 0,0000001 secondi o qualcosa del genere.

Ricordo che System.nanoTime()in Java funziona abbastanza bene in questo caso. Tuttavia non riesco a ottenere la stessa funzionalità esatta dalla clock()funzione di C ++.

hai una soluzione?


29
Tieni presente che qualsiasi confronto basato sulla differenza di orario potrebbe essere impreciso a causa del fatto che il sistema operativo potrebbe non eseguire il thread dall'inizio alla fine. Potrebbe interromperlo ed eseguire altri thread interlacciati al tuo, il che avrà un impatto significativo sul tempo effettivo impiegato per completare l'operazione. Puoi correre più volte e calcolare la media dei risultati; è possibile ridurre al minimo il numero di altri processi in esecuzione. Ma nessuno di questi eliminerà completamente l'effetto di sospensione del filo.
Mordachai

14
Mordachi, perché dovresti eliminarlo? Vuoi vedere come si comporta la tua funzione in un ambiente del mondo reale, non in un regno magico in cui i thread non vengono mai interrotti. Finché lo esegui più volte e fai una media, sarà molto preciso.
Thomas Bonini

Sì, l'ho eseguito un paio di volte e ho ottenuto i risultati.
AhmetB - Google

14
Andreas, il commento di Mordachai è rilevante se l'OP vorrebbe confrontare le prestazioni del suo codice con un algoritmo diverso. Ad esempio, se esegue diversi test dell'orologio questo pomeriggio e poi testa un algoritmo diverso domani mattina, il suo confronto potrebbe non essere affidabile poiché potrebbe condividere le risorse con molti più processi nel pomeriggio che al mattino. O forse un set di codice farà sì che il sistema operativo gli dia meno tempo di elaborazione. Esistono numerosi motivi per cui questo tipo di misurazione delle prestazioni non è affidabile se si desidera eseguire un confronto basato sul tempo.
weberc2

4
@Mordachai So che sto rispondendo a un vecchio commento, ma per chi si imbatte in questo come ho fatto io - per le prestazioni temporali degli algoritmi vuoi prendere il minimo di poche corse, non la media. Questo è quello che ha avuto il minor numero di interruzioni da parte del sistema operativo e quindi sta cronometrando principalmente il tuo codice.
Baruch

Risposte:


115

Puoi usare questa funzione che ho scritto. Chiami GetTimeMs64()e restituisce il numero di millisecondi trascorsi dall'epoca di Unix utilizzando l'orologio di sistema, esattamente come time(NULL), tranne in millisecondi.

Funziona sia su Windows che su Linux; è thread-safe.

Notare che la granularità è di 15 ms su Windows; su Linux dipende dall'implementazione, ma di solito è anche di 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
}

1
Per riferimento futuro: lo inserisco in un file di intestazione e lo uso. Sono contento di averlo.
Daniel Handojo

1
Credo che il metodo gettimeofdaypossa dare un risultato non intenzionale se l'orologio di sistema viene modificato. Se questo fosse un problema per te, potresti clock_gettimeinvece dare un'occhiata .
Azmisov

Questo metodo per Windows ha dei vantaggi rispetto a GetTickCount?
MicroVirus

Non si compila utilizzandogcc -std=c99
Assimilater

@MicroVirus: sì, GetTickCountè il tempo trascorso da quando il sistema è stato avviato, mentre la mia funzione restituisce il tempo dall'epoca UNIX, il che significa che puoi usarlo per date e ore. Se sei interessato solo al tempo che intercorre tra due eventi il ​​mio è comunque una scelta migliore perché è un int64; GetTickCount è un int32 e overflow ogni 50 giorni, il che significa che puoi ottenere risultati strani se i due eventi che hai registrato si trovano tra l'overflow.
Thomas Bonini

43

Ho un altro esempio funzionante che utilizza microsecondi (UNIX, POSIX, ecc.).

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

Ecco il file in cui lo abbiamo codificato:

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


5
Dovresti aggiungere #include <sys/time.h>all'inizio del tuo esempio.
niekas

40

Ecco una semplice soluzione in C ++ 11 che ti dà una risoluzione soddisfacente.

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

O su * nix, per 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_;
};

Ecco un esempio di utilizzo:

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

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


Ricevo questo errore con la tua soluzione c ++ 11:/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
user9869932

@julianromera che piattaforma stai usando? hai installato la libreria libstdc ++ e g ++?
gongzhitaao

È una griglia Slurm di Linux Ubuntu 12. L'ho appena risolto. Ho aggiunto -static-libstdc ++ alla fine del linker. Grazie per aver chiesto a @gongzhitaao
user9869932

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

Quando progress_timeresce dall'ambito stamperà il tempo trascorso dalla sua creazione.

AGGIORNAMENTO : ecco una versione che funziona senza Boost (testata su macOS / iOS):

#include <chrono>
#include <string>
#include <iostream>
#include <math.h>
#include <unistd.h>

class NLTimerScoped {
private:
    const std::chrono::steady_clock::time_point start;
    const std::string name;

public:
    NLTimerScoped( const std::string & name ) : name( name ), start( std::chrono::steady_clock::now() ) {
    }


    ~NLTimerScoped() {
        const auto end(std::chrono::steady_clock::now());
        const auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>( end - start ).count();

        std::cout << name << " duration: " << duration_ms << "ms" << std::endl;
    }

};

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

    {
        NLTimerScoped timer( "sin sum" );

        float a = 0.0f;

        for ( int i=0; i < 1000000; i++ ) {
            a += sin( (float) i / 100 );
        }

        std::cout << "sin sum = " << a << std::endl;
    }



    {
        NLTimerScoped timer( "sleep( 4 )" );

        sleep( 4 );
    }



    return 0;
}

2
Funziona, ma nota che progress_timer è deprecato (qualche tempo prima del boost 1.50) - auto_cpu_timer potrebbe essere più appropriato.
davidA

3
@meowsqueak hmm, auto_cpu_timer sembra richiedere il collegamento della libreria di sistema Boost, quindi non è più una soluzione di sola intestazione. Peccato ... rende le altre opzioni più allettanti all'improvviso.
Tomas Andrle

1
sì, questo è un buon punto, se non colleghi già Boost, allora è più un problema di quanto valga la pena. Ma se lo fai già, funziona abbastanza bene.
davidA

@meowsqueak Sì, o per alcuni rapidi test di benchmark, prendi la versione precedente di Boost.
Tomas Andrle

@TomasAndrle Il collegamento non esiste più.
Zheng Qu

5

Windows fornisce la funzione QueryPerformanceCounter () e Unix ha gettimeofday () Entrambe le funzioni possono misurare almeno 1 micro-secondo di differenza.


Ma l'utilizzo di windows.h è limitato. La stessa sorgente compilata deve essere eseguita sia su Windows che su Unix. Come gestire questo problema?
AhmetB - Google

2
Quindi cerca una libreria wrapper stackoverflow.com/questions/1487695/…
Captain Comic

4
la stessa sorgente compilata sembra che tu voglia eseguire lo stesso binario su entrambi i sistemi, il che non sembra essere il caso. se si intende la stessa sorgente poi una #ifdefdeve essere ok (ed è a giudicare dalla risposta che hai accettato), e quindi non vedo il problema: #ifdef WIN32 #include <windows.h> ... #else ... #endif.
solo qualcuno il

3

In alcuni programmi che ho scritto ho usato RDTS per tale scopo. RDTSC non riguarda il tempo ma il numero di cicli dall'avvio del processore. Devi calibrarlo sul tuo sistema per ottenere un risultato in secondi, ma è davvero utile quando vuoi valutare le prestazioni, è ancora meglio usare direttamente il numero di cicli senza provare a riportarli in secondi.

(il collegamento sopra è a una pagina wikipedia francese, ma ha esempi di codice C ++, la versione inglese è qui )


2

Suggerisco di utilizzare le funzioni di libreria standard per ottenere informazioni sull'ora dal sistema.

Se desideri una risoluzione più precisa, esegui più iterazioni di esecuzione. Invece di eseguire il programma una volta e ottenere campioni, eseguirlo 1000 volte o più.


2

È meglio eseguire il ciclo interno più volte con la temporizzazione delle prestazioni solo una volta e la media dividendo le ripetizioni del ciclo interno piuttosto che eseguire l'intera operazione (ciclo + tempistica delle prestazioni) più volte e media. Ciò ridurrà il sovraccarico del codice di temporizzazione delle prestazioni rispetto alla sezione del profilo effettiva.

Avvolgi le chiamate del timer per il sistema appropriato. Per Windows, QueryPerformanceCounter è abbastanza veloce e "sicuro" da usare.

Puoi usare "rdtsc" anche su qualsiasi PC X86 moderno, ma potrebbero esserci problemi su alcune macchine multicore (il core hopping può cambiare il timer) o se hai attivato uno speed-step di qualche tipo.


2

(soluzione specifica per Windows) Il modo corrente (circa 2017) per ottenere tempi precisi sotto Windows è utilizzare "QueryPerformanceCounter". Questo approccio ha il vantaggio di fornire risultati molto accurati ed è raccomandato dalla SM. Basta inserire il BLOB di codice in una nuova app console per ottenere un esempio funzionante. C'è una lunga discussione qui: Acquisizione di timestamp ad alta risoluzione

#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

Una soluzione completa e infallibile alla pianificazione dei thread, che dovrebbe produrre esattamente gli stessi tempi per ogni test, consiste nel compilare il programma in modo che sia indipendente dal sistema operativo e avviare il computer in modo da eseguire il programma in un ambiente privo di sistema operativo. Tuttavia, questo è in gran parte impraticabile e sarebbe difficile nella migliore delle ipotesi.

Un buon sostituto per liberarsi del sistema operativo è semplicemente impostare l'affinità del thread corrente su 1 core e la priorità sulla massima. Questa alternativa dovrebbe fornire risultati sufficientemente coerenti.

Inoltre dovresti disattivare le ottimizzazioni che interferirebbero con il debug, che per g ++ o gcc significa aggiungere -Ogalla riga di comando , per evitare che il codice in fase di test venga ottimizzato. Il -O0flag non dovrebbe essere usato perché introduce un overhead extra non necessario che verrebbe incluso nei risultati di temporizzazione, distorcendo così la velocità temporizzata del codice.

Al contrario, sia assumendo che si utilizzi -Ofast(o, come minimo, -O3) sulla build di produzione finale sia ignorando il problema dell'eliminazione "morta" del codice, vengono -Ogeseguite pochissime ottimizzazioni rispetto a -Ofast; quindi -Ogpuò travisare la velocità reale del codice nel prodotto finale.

Inoltre, tutti i test di velocità (in una certa misura) falsano: nel prodotto di produzione finale compilato -Ofast, ogni frammento / sezione / funzione di codice non è isolato; piuttosto, ogni frammento di codice scorre continuamente nel successivo, consentendo così al compilatore di unire, unire e ottimizzare insieme pezzi di codice da ogni parte.

Allo stesso tempo, se stai valutando uno snippet di codice che fa un uso pesante di realloc() intensivo, lo snippet di codice potrebbe essere eseguito più lentamente in un prodotto di produzione con una frammentazione della memoria sufficientemente elevata. Quindi, l'espressione "l'intero è più della somma delle sue parti" si applica a questa situazione perché il codice nella build di produzione finale potrebbe essere notevolmente più veloce o più lento del singolo frammento che stai testando.

Una soluzione parziale che può ridurre l'incongruenza è quella di utilizzare -Ofastper il test di velocità CON l'aggiunta di asm volatile("" :: "r"(var))alle variabili coinvolte nel test per evitare l'eliminazione di codice morto / loop.

Ecco un esempio di come confrontare le funzioni della radice quadrata su un computer Windows.

// set USE_ASM_TO_PREVENT_ELIMINATION  to 0 to prevent `asm volatile("" :: "r"(var))`
// set USE_ASM_TO_PREVENT_ELIMINATION  to 1 to enforce `asm volatile("" :: "r"(var))`
#define USE_ASM_TO_PREVENT_ELIMINATION 1

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

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-- ) {
        auto result = (*function_to_do)( i << 7 );
        #if USE_ASM_TO_PREVENT_ELIMINATION == 1
            asm volatile("" :: "r"(
                // There is no data type in C++ that is smaller than a char, so it will
                //  not throw a segmentation fault error to reinterpret any arbitrary
                //  data type as a char. Although, the compiler might not like it.
                result
            ));
        #endif
    }
    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;
}

Inoltre, credito a Mike Jarvis per il suo Timer.

Si noti (questo è molto importante) che se si eseguono frammenti di codice più grandi, è necessario ridurre il numero di iterazioni per evitare che il computer si blocchi.


2
Buona risposta tranne che per disabilitare l'ottimizzazione. Il -O0codice di benchmarking è una grande perdita di tempo perché l'overhead -O0 invece di un normale -O2o -O3 -march=nativevaria notevolmente a seconda del codice e del carico di lavoro. es. tmp vars con nome aggiuntivo costa tempo a -O0. Ci sono altri modi per evitare che le cose vengano ottimizzate, come nascondere le cose dall'ottimizzatore con volatilefunzioni non inline o istruzioni asm inline vuote. -O0non è nemmeno quasi utilizzabile perché il codice ha colli di bottiglia diversi-O0 , non uguali ma peggiori.
Peter Cordes

1
Uffa, non -Ogè ancora molto realistico, dipende dal codice. Almeno -O2, preferibilmente -O3è più realistico. Usa asm volatile("" ::: "+r"(var))o qualcosa per fare in modo che il compilatore materializzi un valore in un registro e neutralizzi la propagazione costante attraverso di esso.
Peter Cordes

@PeterCordes Grazie ancora per i tuoi approfondimenti. Ho aggiornato il contenuto con -O3e lo snippet di codice con asm volatile("" ::: "+r"(var)).
Jack Giffin

1
asm volatile("" ::: "+r"( i ));sembra inutile. Nel codice ottimizzato, non c'è motivo per forzare il compilatore a materializzarsi icosì come i<<7all'interno del ciclo. Stai impedendo di ottimizzare a tmp -= 128invece di cambiare ogni volta. Usare il risultato di una chiamata di funzione è buono, però, se non è void. Mi piace int result = (*function_to_do)( i << 7 );. Potresti usare una asmdichiarazione su quel risultato.
Peter Cordes

@PeterCordes Grazie mille ancora per i tuoi suggerimenti. Il mio post ora contiene le correzioni per il valore di ritorno da in function_to_domodo che function_to_dopossa essere inline senza essere eliminato. Per favore fatemi sapere se avete ulteriori suggerimenti.
Jack Giffin

1

Per i casi in cui si desidera cronometrare lo stesso tratto di codice ogni volta che viene eseguito (ad esempio per il profiling del codice che si ritiene possa essere un collo di bottiglia), ecco un wrapper (una leggera modifica) alla funzione di Andreas Bonini che trovo 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;
};

1

solo una semplice classe che confronta il blocco di codice:

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

0

boost :: timer probabilmente ti darà tutta la precisione di cui avrai bisogno. Non è neanche lontanamente abbastanza preciso da dirti quanto tempo a = a+1;ci vorrà, ma quale motivo avresti per cronometrare qualcosa che richiede un paio di nanosecondi?


Si basa sulla clock()funzione dell'intestazione standard C ++.
Petter

0

Ho creato un lambda che ti chiama chiamata di funzione N volte e ti restituisce la media.

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

Puoi trovare l'intestazione c ++ 11 qui .


0

Ho creato una semplice utility per misurare le prestazioni dei blocchi di codice, utilizzando high_resolution_clock della libreria chrono: https://github.com/nfergu/codetimer .

Le temporizzazioni possono essere registrate su chiavi diverse e può essere visualizzata una vista aggregata delle temporizzazioni per ciascuna chiave.

L'utilizzo è il seguente:

#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

Potresti anche guardare [cxx-rtimers][1]su GitHub, che fornisce alcune routine di sola intestazione per raccogliere statistiche sul tempo di esecuzione di qualsiasi blocco di codice in cui puoi creare una variabile locale. Questi timer hanno versioni che usano std :: chrono su C ++ 11, o timer dalla libreria Boost o funzioni timer POSIX standard. Questi timer riporteranno la durata media, massima e minima trascorsa all'interno di una funzione, nonché il numero di volte in cui viene chiamata. Possono essere usati semplicemente come segue:

#include <rtimers/cxx11.hpp>

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

0

È così che lo faccio, non molto codice, facile da capire, adatto alle mie esigenze:

void bench(std::function<void()> fnBench, std::string name, size_t iterations)
{
    if (iterations == 0)
        return;
    if (fnBench == nullptr)
        return;
    std::chrono::high_resolution_clock::time_point start, end;
    if (iterations == 1)
    {
        start = std::chrono::high_resolution_clock::now();
        fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    else
    {
        start = std::chrono::high_resolution_clock::now();
        for (size_t i = 0; i < iterations; ++i)
            fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    printf
    (
        "bench(*, \"%s\", %u) = %4.6lfs\r\n",
        name.c_str(),
        iterations,
        std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count()
    );
}

Uso:

bench
(
    []() -> void // function
    {
        // Put your code here
    },
    "the name of this", // name
    1000000 // iterations
);

0
#include <omp.h>

double start = omp_get_wtime();

// code 

double finish = omp_get_wtime();

double total_time = finish - start;

2
Sebbene questo codice possa risolvere la domanda, inclusa una spiegazione di come e perché questo risolve il problema aiuterebbe davvero a migliorare la qualità del tuo post e probabilmente si tradurrebbe in più voti positivi. Ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo alla persona che chiede ora. Si prega di modificare la risposta per aggiungere spiegazioni e dare un'indicazione di ciò si applicano le limitazioni e le assunzioni.
Dharman
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.