Ich möchte einen einfachen Timer-Mechanismus in C ++ implementieren. Der Code sollte unter Windows und Linux funktionieren. Die Auflösung sollte so genau wie möglich sein (mindestens Millisekundengenauigkeit). Dies wird verwendet, um einfach den Zeitablauf zu verfolgen und keine Art von ereignisgesteuertem Design zu implementieren. Was ist das beste Werkzeug, um dies zu erreichen?
c++
cross-platform
timer
Amischer Programmierer
quelle
quelle
Antworten:
Für C ++ 03 :
Boost.Timer funktioniert möglicherweise, hängt jedoch von der C-Funktion ab
clock
und hat möglicherweise nicht genügend Auflösung für Sie.Boost.Date_Time enthält eine
ptime
Klasse , die zuvor für Stack Overflow empfohlen wurde. Lesen Sie die Dokumentation zumicrosec_clock::local_time
undmicrosec_clock::universal_time
, beachten Sie jedoch die Einschränkung, dass "Win32-Systeme über diese API häufig keine Mikrosekundenauflösung erreichen".STLsoft bietet unter anderem dünne plattformübergreifende (Windows und Linux / Unix) C ++ - Wrapper für betriebssystemspezifische APIs. Die Leistungsbibliothek verfügt über mehrere Klassen, die genau das tun, was Sie benötigen. (Um es plattformübergreifend zu machen, wählen Sie eine solche Klasse aus
performance_counter
, die sowohl imwinstl
als auch imunixstl
Namespace vorhanden ist, und verwenden Sie dann den Namespace, der Ihrer Plattform entspricht.)Für C ++ 11 und höher :
In der
std::chrono
Bibliothek ist diese Funktionalität integriert. Weitere Informationen finden Sie in dieser Antwort von @HowardHinnant.quelle
<chrono>
und<thread>
? Wenn möglich, wie?Aktualisierte Antwort auf eine alte Frage:
In C ++ 11 können Sie portabel zum Timer mit der höchsten Auflösung gelangen mit:
#include <iostream> #include <chrono> #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'; }
Beispielausgabe:
74 nanoseconds
„chrono_io“ ist eine Erweiterung E / A - Probleme mit diesen neuen Typen zu erleichtern und ist frei verfügbar hier .
Es gibt auch eine Implementierung von
<chrono>
Boost (möglicherweise immer noch an der Spitze des Trunks, nicht sicher, ob es veröffentlicht wurde).Aktualisieren
Dies ist eine Reaktion auf Bens Kommentar unten, dass nachfolgende Aufrufe
std::chrono::high_resolution_clock
in VS11 mehrere Millisekunden dauern sollen. Unten finden Sie eine<chrono>
kompatible Problemumgehung. Es funktioniert jedoch nur auf Intel-Hardware. Sie müssen in die Inline-Assembly eintauchen (die Syntax variiert je nach Compiler) und die Taktrate der Maschine fest mit der Uhr verbinden:#include <chrono> struct clock { typedef unsigned long long rep; typedef std::ratio<1, 2800000000> period; // My machine is 2.8 GHz typedef std::chrono::duration<rep, period> duration; typedef std::chrono::time_point<clock> 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<rep>(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<rep, duration::rep>::value, "rep and duration::rep must be the same type"); static_assert(std::is_same<period, duration::period>::value, "period and duration::period must be the same type"); static_assert(std::is_same<duration, time_point::duration>::value, "duration and time_point::duration must be the same type"); return true; } static const bool invariants; }; const bool clock::invariants = clock::check_invariants();
Es ist also nicht tragbar. Wenn Sie jedoch mit einer hochauflösenden Uhr auf Ihrer eigenen Intel-Hardware experimentieren möchten, wird sie nicht feiner. Seien Sie gewarnt, die heutigen Taktraten können sich dynamisch ändern (sie sind nicht wirklich eine Konstante für die Kompilierungszeit). Und mit einer Multiprozessor-Maschine können Sie sogar Zeitstempel von verschiedenen Prozessoren erhalten. Trotzdem funktionieren Experimente mit meiner Hardware ziemlich gut. Wenn Sie mit der Millisekundenauflösung nicht weiterkommen, kann dies eine Problemumgehung sein.
Diese Uhr hat eine Dauer in Bezug auf die Taktrate Ihrer CPU (wie Sie es gemeldet haben). Dh für mich tickt diese Uhr einmal alle 1 / 2.800.000.000 Sekunden. Wenn Sie möchten, können Sie dies (zum Beispiel) in Nanosekunden umwandeln mit:
using std::chrono::nanoseconds; using std::chrono::duration_cast; auto t0 = clock::now(); auto t1 = clock::now(); nanoseconds ns = duration_cast<nanoseconds>(t1-t0);
Die Umwandlung schneidet Bruchteile eines CPU-Zyklus ab, um die Nanosekunde zu bilden. Andere Rundungsmodi sind möglich, aber das ist ein anderes Thema.
Für mich ergibt dies eine Dauer von nur 18 Takt-Ticks, die auf 6 Nanosekunden verkürzt wird.
Ich habe der obigen Uhr eine "invariante Überprüfung" hinzugefügt, von der die wichtigste die Überprüfung ist, ob die
clock::period
für die Maschine korrekt ist. Auch dies ist kein portabler Code, aber wenn Sie diese Uhr verwenden, haben Sie sich bereits dazu verpflichtet. Dieget_clock_speed()
hier gezeigte private Funktion erhält unter OS X die maximale CPU-Frequenz, und diese sollte dieselbe Zahl sein wie der konstante Nenner vonclock::period
.Wenn Sie dies hinzufügen, sparen Sie ein wenig Zeit beim Debuggen, wenn Sie diesen Code auf Ihren neuen Computer portieren und vergessen, den Code
clock::period
auf die Geschwindigkeit Ihres neuen Computers zu aktualisieren . Die gesamte Überprüfung erfolgt entweder zur Kompilierungszeit oder zum Start des Programms. Es hat also keinen Einfluss auf die Leistung vonclock::now()
.quelle
high_resolution_clock
beträgt das kürzeste Intervall ungleich Null leider mehrere Millisekunden.Die STLSoft-Bibliotheken von Matthew Wilson bieten verschiedene Timertypen mit kongruenten Schnittstellen, sodass Sie Plug-and-Play- fähig sind . Zu den Angeboten gehören Timer, die kostengünstig, aber niedrig aufgelöst sind, und Timer, die hochauflösend, aber kostenintensiv sind. Es gibt auch solche zum Messen der Vorfadenzeiten und zum Messen der Prozesszeiten sowie alle, die die verstrichenen Zeiten messen.
Es gibt einen ausführlichen Artikel in Dr. Dobbs von vor einigen Jahren, der jedoch nur die Windows- Artikel behandelt, die im WinSTL-Teilprojekt definiert sind. STLSoft bietet auch UNIX-Timer im UNIXSTL-Unterprojekt, und Sie können den "PlatformSTL" verwenden, der den UNIX- oder Windows-Timer enthält, wie in:
#include <platformstl/performance/performance_counter.hpp> #include <iostream> 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
quelle
Die StlSoft Open Source-Bibliothek bietet sowohl auf Windows- als auch auf Linux-Plattformen einen recht guten Timer . Wenn Sie möchten, dass es selbst implementiert wird, schauen Sie sich einfach die Quellen an.
quelle
Die ACE-Bibliothek verfügt auch über tragbare hochauflösende Timer.
Sauerstoff für hochauflösende Timer:
http://www.dre.vanderbilt.edu/Doxygen/5.7.2/html/ace/a00244.html
quelle
Ich habe gesehen, dass dies einige Male als Closed-Source-Inhouse-Lösungen implementiert wurde. Alle haben auf
#ifdef
Lösungen für native Windows-Hi-Res-Timer einerseits und Linux-Kernel-Timerstruct timeval
(sieheman timeradd
) andererseits zurückgegriffen.Sie können dies abstrahieren, und einige Open Source-Projekte haben es geschafft - das letzte, das ich mir angesehen habe, war die CoinOR-Klasse CoinTimer, aber es gibt sicherlich noch mehr davon.
quelle
Ich empfehle dazu die Bibliothek boost :: posix_time. Es unterstützt Timer in verschiedenen Auflösungen bis zu Mikrosekunden, glaube ich
quelle
SDL2 verfügt über einen hervorragenden plattformübergreifenden hochauflösenden Timer. Wenn Sie jedoch Sub-Millisekunden - Genauigkeit benötigen, schrieb ich eine sehr kleine Cross-Plattform - Timer Bibliothek hier . Es ist sowohl mit C ++ 03 als auch mit C ++ 11 / höheren Versionen von C ++ kompatibel.
quelle
Die erste Antwort auf Fragen zur C ++ - Bibliothek lautet im Allgemeinen BOOST: http://www.boost.org/doc/libs/1_40_0/libs/timer/timer.htm . Macht das was du willst? Wahrscheinlich nicht, aber es ist ein Anfang.
Das Problem ist, dass Sie tragbare Geräte möchten und Timer-Funktionen in Betriebssystemen nicht universell sind.
quelle
STLSoft verfügt über eine Leistungsbibliothek , die eine Reihe von Zeitgeberklassen enthält, von denen einige sowohl für UNIX als auch für Windows funktionieren.
quelle
Ich bin mir über Ihre Anforderung nicht sicher. Wenn Sie das Zeitintervall berechnen möchten, lesen Sie bitte den Thread unten
Berechnung der verstrichenen Zeit in einem C-Programm in Millisekunden
quelle
Wenn Sie das Qt-Framework im Projekt verwenden, ist die beste Lösung wahrscheinlich die Verwendung von QElapsedTimer.
quelle
Spät zur Party hier, aber ich arbeite in einer alten Codebasis, die noch nicht auf C ++ 11 aktualisiert werden kann. Niemand in unserem Team ist sehr erfahren in C ++, daher erweist sich das Hinzufügen einer Bibliothek wie STL als schwierig (zusätzlich zu den potenziellen Bedenken, die andere in Bezug auf Bereitstellungsprobleme geäußert haben). Ich brauchte wirklich einen extrem einfachen plattformübergreifenden Timer, der ohne die Standard-Systembibliotheken von Bare-Bones auskommen kann. Folgendes habe ich gefunden:
http://www.songho.ca/misc/timer/timer.html
Reposting der gesamten Quelle hier, damit sie nicht verloren geht, wenn die Site jemals stirbt:
////////////////////////////////////////////////////////////////////////////// // 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 ([email protected]) - 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 <stdlib.h> /////////////////////////////////////////////////////////////////////////////// // 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(); }
und die Header-Datei:
////////////////////////////////////////////////////////////////////////////// // 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 ([email protected]) - 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 <windows.h> #else // Unix based system specific #include <sys/time.h> #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
quelle
Ich fand das vielversprechend und äußerst unkompliziert, nicht sicher, ob es irgendwelche Nachteile gibt:
https://gist.github.com/ForeverZer0/0a4f80fc02b96e19380ebb7a3debbee5
/* ----------------------------------------------------------------------- */ /* Easy embeddable cross-platform high resolution timer function. For each platform we select the high resolution timer. You can call the 'ns()' function in your file after embedding this. */ #include <stdint.h> #if defined(__linux) # define HAVE_POSIX_TIMER # include <time.h> # ifdef CLOCK_MONOTONIC # define CLOCKID CLOCK_MONOTONIC # else # define CLOCKID CLOCK_REALTIME # endif #elif defined(__APPLE__) # define HAVE_MACH_TIMER # include <mach/mach_time.h> #elif defined(_WIN32) # define WIN32_LEAN_AND_MEAN # include <windows.h> #endif static uint64_t ns() { static uint64_t is_init = 0; #if defined(__APPLE__) static mach_timebase_info_data_t info; if (0 == is_init) { mach_timebase_info(&info); is_init = 1; } uint64_t now; now = mach_absolute_time(); now *= info.numer; now /= info.denom; return now; #elif defined(__linux) static struct timespec linux_rate; if (0 == is_init) { clock_getres(CLOCKID, &linux_rate); is_init = 1; } uint64_t now; struct timespec spec; clock_gettime(CLOCKID, &spec); now = spec.tv_sec * 1.0e9 + spec.tv_nsec; return now; #elif defined(_WIN32) static LARGE_INTEGER win_frequency; if (0 == is_init) { QueryPerformanceFrequency(&win_frequency); is_init = 1; } LARGE_INTEGER now; QueryPerformanceCounter(&now); return (uint64_t) ((1e9 * now.QuadPart) / win_frequency.QuadPart); #endif } /* ----------------------------------------------------------------------- */-------------------------------- */
quelle