Timer ad alta risoluzione multipiattaforma C ++

Sto cercando di implementare un semplice meccanismo del timer in C ++. Il codice dovrebbe funzionare in Windows e Linux. La risoluzione dovrebbe essere il più precisa ansible (precisione almeno millisecondo). Questo sarà usato per tracciare semplicemente il passare del tempo, non per implementare alcun tipo di progettazione guidata dagli eventi. Qual è lo strumento migliore per farlo?

Per C ++ 03 :

Boost.Timer potrebbe funzionare, ma dipende clock funzione C e quindi potrebbe non avere una risoluzione sufficiente per te.

Boost.Date_Time include una class ptime che è stata consigliata su Stack Overflow in precedenza. Vedi i suoi documenti su microsec_clock::local_time e microsec_clock::universal_time , ma nota il suo avvertimento che “i sistemi Win32 spesso non raggiungono la risoluzione di microsecondi tramite questa API”.

STLsoft offre, tra le altre cose, sottili wrapper C ++ multipiattaforma (Windows e Linux / Unix) attorno alle API specifiche del sistema operativo. La sua libreria delle prestazioni ha diverse classi che farebbero ciò di cui hai bisogno. (Per renderlo multipiattaforma, scegli una class come performance_counter che esista in entrambi gli winstl unixstl nomi winstl e unixstl , quindi utilizza lo spazio dei nomi corrispondente alla tua piattaforma.)

Per C ++ 11 e versioni successive :

La libreria std::chrono ha questa funzionalità integrata. Vedi questa risposta di @HowardHinnant per i dettagli.

Risposta aggiornata per una vecchia domanda:

In C ++ 11 è ansible raggiungere in modo portatile il timer con la risoluzione più alta con:

 #include  #include  #include "chrono_io" int main() { typedef std::chrono::high_resolution_clock Clock; auto t1 = Clock::now(); auto t2 = Clock::now(); std::cout < < t2-t1 << '\n'; } 

Esempio di output:

 74 nanoseconds 

"chrono_io" è un'estensione per facilitare i problemi di I / O con questi nuovi tipi ed è liberamente disponibile qui .

C'è anche un'implementazione di disponibile in boost (potrebbe essere ancora su tip-of-trunk, non è sicuro che sia stato rilasciato).

Aggiornare

Questo è in risposta al commento di Ben di seguito che le successive chiamate a std::chrono::high_resolution_clock richiedono diversi millisecondi in VS11. Di seguito è riportata una soluzione alternativa . Tuttavia funziona solo su hardware Intel, è necessario immergersi in un assembly inline (la syntax per farlo varia con il compilatore) e si deve colbind la velocità di clock della macchina all'orologio:

 #include  struct clock { typedef unsigned long long rep; typedef std::ratio<1, 2800000000> period; // My machine is 2.8 GHz typedef std::chrono::duration duration; typedef std::chrono::time_point time_point; static const bool is_steady = true; static time_point now() noexcept { unsigned lo, hi; asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); return time_point(duration(static_cast(hi) < < 32 | lo)); } private: static unsigned get_clock_speed() { int mib[] = {CTL_HW, HW_CPU_FREQ}; const std::size_t namelen = sizeof(mib)/sizeof(mib[0]); unsigned freq; size_t freq_len = sizeof(freq); if (sysctl(mib, namelen, &freq, &freq_len, nullptr, 0) != 0) return 0; return freq; } static bool check_invariants() { static_assert(1 == period::num, "period must be 1/freq"); assert(get_clock_speed() == period::den); static_assert(std::is_same::value, "rep and duration::rep must be the same type"); static_assert(std::is_same::value, "period and duration::period must be the same type"); static_assert(std::is_same::value, "duration and time_point::duration must be the same type"); return true; } static const bool invariants; }; const bool clock::invariants = clock::check_invariants(); 

Quindi non è portatile. Ma se vuoi sperimentare un orologio ad alta risoluzione sul tuo hardware Intel, non è più bello di così. Pur essendo avvisati, le attuali velocità di clock possono cambiare dynamicmente (non sono in realtà una costante in fase di compilazione). E con una macchina multiprocessore è anche ansible ottenere timestamp da processori diversi. Ma ancora, gli esperimenti sul mio hardware funzionano abbastanza bene. Se sei bloccato con risoluzione al millisecondo, questo potrebbe essere una soluzione.

Questo orologio ha una durata in termini di velocità di clock della tua cpu (come lo hai segnalato). Cioè per me questo orologio spunta una volta ogni 1 / 2.800.000.000 di secondo. Se lo desideri, puoi convertirlo in nanosecondi (ad esempio) con:

 using std::chrono::nanoseconds; using std::chrono::duration_cast; auto t0 = clock::now(); auto t1 = clock::now(); nanoseconds ns = duration_cast(t1-t0); 

La conversione troncerà le frazioni di un ciclo della CPU per formare il nanosecondo. Sono possibili altre modalità di arrotondamento, ma questo è un argomento diverso.

Per me questo restituirà una durata pari a 18 ticks di clock, che tronca a 6 nanosecondi.

Ho aggiunto un po 'di "controllo invariante" all'orologio sopra, il più importante dei quali è controllare che il clock::period sia corretto per la macchina. Di nuovo, questo non è un codice portatile, ma se stai usando questo orologio, ti sei già impegnato. La funzione privata get_clock_speed() qui mostrata ottiene la massima frequenza della CPU su OS X e dovrebbe essere lo stesso numero del denominatore costante di clock::period .

Aggiungendo questo si risparmia un po 'di tempo di debugging quando si porta questo codice sul nuovo computer e si dimentica di aggiornare il clock::period alla velocità della nuova macchina. Tutto il controllo viene eseguito sia in fase di compilazione che all'avvio del programma. Quindi non influenzerà le prestazioni di clock::now() in meno.

Le librerie STLSoft di Matthew Wilson offrono diversi tipi di timer, con interfacce congruenti in modo da poter essere plug-and-play. Tra le offerte ci sono i timer a basso costo ma a bassa risoluzione e quelli ad alta risoluzione ma ad alto costo. Ci sono anche quelli per misurare i tempi di pre-thread e per misurare i tempi di processo, così come tutto ciò che misura i tempi trascorsi.

C’è un articolo esaustivo che lo copre nel Dr. Dobb di alcuni anni fa, sebbene riguardi solo quelli di Windows, quelli definiti nel sottoprogetto di WinSTL. STLSoft fornisce anche i timer UNIX nel sottoprogetto UNIXSTL, ed è ansible utilizzare uno “PlatformSTL”, che include UNIX o Windows uno come appropriato, come in:

 #include  #include  int main() { platformstl::performance_counter c; c.start(); for(int i = 0; i < 1000000000; ++i); c.stop(); std::cout << "time (s): " << c.get_seconds() << std::endl; std::cout << "time (ms): " << c.get_milliseconds() << std::endl; std::cout << "time (us): " << c.get_microseconds() << std::endl; } 

HTH

La libreria open source StlSoft fornisce un timer abbastanza buono su entrambe le piattaforms Windows e Linux. Se vuoi implementarlo da solo, dai un’occhiata alle loro fonti.

La libreria ACE ha anche timer portatili ad alta risoluzione.

Doxygen per timer ad alta risoluzione:
http://www.dre.vanderbilt.edu/Doxygen/5.7.2/html/ace/a00244.html

Questa non è la migliore risposta, ma qui ci sono alcune conversazioni su un sito di sviluppo giochi per quanto riguarda i timer ad alta risoluzione:

  1. http://www.gamedev.net/topic/374327-timing-is-everything/
  2. http://www.gamedev.net/topic/471804-high-resolution-timer/
  3. http://www.gamedev.net/topic/40600-high-resolution-timing-in-games/

Consiglio vivamente la libreria boost :: posix_time per questo. Suppongo che i timer in varie risoluzioni fino a microsecondi credo

La prima risposta alle domande della libreria C ++ è generalmente BOOST: http://www.boost.org/doc/libs/1_40_0/libs/timer/timer.htm . Questo fa quello che vuoi? Probabilmente no ma è un inizio.

Il problema è che vuoi le funzioni portatili e timer non sono universali nei sistemi operativi.

Ho visto questo implementato un paio di volte come soluzioni interne a codice chiuso …. che ricorrevano tutte a soluzioni #ifdef attorno ai temporizzatori ad alta risoluzione nativi di Windows da un lato e ai timer del kernel di Linux usando struct timeval (vedi man timeradd ) d’altra parte.

Puoi astrarre questo e alcuni progetti Open Source l’hanno fatto – l’ultimo che ho visto era CoinTimer della class CoinOR ma ce ne sono sicuramente di più.

STLSoft dispone di una libreria delle prestazioni , che include un set di classi timer, alcune che funzionano sia per UNIX che per Windows.

SDL2 ha un eccellente timer ad alta risoluzione multipiattaforma. Se tuttavia è necessaria una precisione inferiore al millisecondo, qui ho scritto una libreria temporizzata cross-platform molto piccola. È compatibile con C ++ 03 e C ++ 11 / versioni successive di C ++.

Non sono sicuro del tuo fabbisogno. Se vuoi calcolare l’intervallo di tempo, consulta la discussione di seguito

Calcolo del tempo trascorso in un programma C in millisecondi

Se si utilizza il framework Qt nel progetto, la soluzione migliore è probabilmente utilizzare QElapsedTimer.

In ritardo per la festa qui, ma sto lavorando in un codice base legacy che non può ancora essere aggiornato a c ++ 11. Nessuno nel nostro team è molto competente in c ++, quindi l’aggiunta di una libreria come STL si sta dimostrando difficile (oltre alle potenziali preoccupazioni che altri hanno sollevato riguardo ai problemi di distribuzione). Avevo davvero bisogno di un timer multipiattaforma estremamente semplice che potesse vivere da solo senza nulla oltre le librerie di sistema standard di bare-bones. Ecco cosa ho trovato:

http://www.songho.ca/misc/timer/timer.html

Ripubblicando l’intera fonte qui solo perché non si perda se il sito dovesse mai morire:

  ////////////////////////////////////////////////////////////////////////////// // Timer.cpp // ========= // High Resolution Timer. // This timer is able to measure the elapsed time with 1 micro-second accuracy // in both Windows, Linux and Unix system // // AUTHOR: Song Ho Ahn (song.ahn@gmail.com) - http://www.songho.ca/misc/timer/timer.html // CREATED: 2003-01-13 // UPDATED: 2017-03-30 // // Copyright (c) 2003 Song Ho Ahn ////////////////////////////////////////////////////////////////////////////// #include "Timer.h" #include  /////////////////////////////////////////////////////////////////////////////// // constructor /////////////////////////////////////////////////////////////////////////////// Timer::Timer() { #if defined(WIN32) || defined(_WIN32) QueryPerformanceFrequency(&frequency); startCount.QuadPart = 0; endCount.QuadPart = 0; #else startCount.tv_sec = startCount.tv_usec = 0; endCount.tv_sec = endCount.tv_usec = 0; #endif stopped = 0; startTimeInMicroSec = 0; endTimeInMicroSec = 0; } /////////////////////////////////////////////////////////////////////////////// // distructor /////////////////////////////////////////////////////////////////////////////// Timer::~Timer() { } /////////////////////////////////////////////////////////////////////////////// // start timer. // startCount will be set at this point. /////////////////////////////////////////////////////////////////////////////// void Timer::start() { stopped = 0; // reset stop flag #if defined(WIN32) || defined(_WIN32) QueryPerformanceCounter(&startCount); #else gettimeofday(&startCount, NULL); #endif } /////////////////////////////////////////////////////////////////////////////// // stop the timer. // endCount will be set at this point. /////////////////////////////////////////////////////////////////////////////// void Timer::stop() { stopped = 1; // set timer stopped flag #if defined(WIN32) || defined(_WIN32) QueryPerformanceCounter(&endCount); #else gettimeofday(&endCount, NULL); #endif } /////////////////////////////////////////////////////////////////////////////// // compute elapsed time in micro-second resolution. // other getElapsedTime will call this first, then convert to correspond resolution. /////////////////////////////////////////////////////////////////////////////// double Timer::getElapsedTimeInMicroSec() { #if defined(WIN32) || defined(_WIN32) if(!stopped) QueryPerformanceCounter(&endCount); startTimeInMicroSec = startCount.QuadPart * (1000000.0 / frequency.QuadPart); endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart); #else if(!stopped) gettimeofday(&endCount, NULL); startTimeInMicroSec = (startCount.tv_sec * 1000000.0) + startCount.tv_usec; endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec; #endif return endTimeInMicroSec - startTimeInMicroSec; } /////////////////////////////////////////////////////////////////////////////// // divide elapsedTimeInMicroSec by 1000 /////////////////////////////////////////////////////////////////////////////// double Timer::getElapsedTimeInMilliSec() { return this->getElapsedTimeInMicroSec() * 0.001; } /////////////////////////////////////////////////////////////////////////////// // divide elapsedTimeInMicroSec by 1000000 /////////////////////////////////////////////////////////////////////////////// double Timer::getElapsedTimeInSec() { return this->getElapsedTimeInMicroSec() * 0.000001; } /////////////////////////////////////////////////////////////////////////////// // same as getElapsedTimeInSec() /////////////////////////////////////////////////////////////////////////////// double Timer::getElapsedTime() { return this->getElapsedTimeInSec(); } 

e il file di intestazione:

 ////////////////////////////////////////////////////////////////////////////// // Timer.h // ======= // High Resolution Timer. // This timer is able to measure the elapsed time with 1 micro-second accuracy // in both Windows, Linux and Unix system // // AUTHOR: Song Ho Ahn (song.ahn@gmail.com) - http://www.songho.ca/misc/timer/timer.html // CREATED: 2003-01-13 // UPDATED: 2017-03-30 // // Copyright (c) 2003 Song Ho Ahn ////////////////////////////////////////////////////////////////////////////// #ifndef TIMER_H_DEF #define TIMER_H_DEF #if defined(WIN32) || defined(_WIN32) // Windows system specific #include  #else // Unix based system specific #include  #endif class Timer { public: Timer(); // default constructor ~Timer(); // default destructor void start(); // start timer void stop(); // stop the timer double getElapsedTime(); // get elapsed time in second double getElapsedTimeInSec(); // get elapsed time in second (same as getElapsedTime) double getElapsedTimeInMilliSec(); // get elapsed time in milli-second double getElapsedTimeInMicroSec(); // get elapsed time in micro-second protected: private: double startTimeInMicroSec; // starting time in micro-second double endTimeInMicroSec; // ending time in micro-second int stopped; // stop flag #if defined(WIN32) || defined(_WIN32) LARGE_INTEGER frequency; // ticks per second LARGE_INTEGER startCount; // LARGE_INTEGER endCount; // #else timeval startCount; // timeval endCount; // #endif }; #endif // TIMER_H_DEF