Unterschied zwischen std :: system_clock und std :: stetiger_takt?

97

Was ist der Unterschied zwischen std::system_clockund std::steady_clock? (Ein Beispielfall, der unterschiedliche Ergebnisse / Verhaltensweisen veranschaulicht, wäre großartig).

Wenn mein Ziel genau zu Ausführungszeit von Funktionen (wie ein Benchmark) zu messen, was wäre die beste Wahl zwischen std::system_clock, std::steady_clockund std::high_resolution_clock?

Vincent
quelle
9
Zu Beginn ist die system_clock möglicherweise nicht stabil.
James McNellis
12
@ CharlesSalvia Ich kann nicht für andere Plattformen sprechen, aber das system_clockist unter Windows nicht stabil. Unter Windows kann die Systemzeit von jedem ausreichend privilegierten Benutzer auf einen beliebigen Wert geändert werden. Darüber hinaus kann der Zeitsynchronisationsdienst die Systemzeit bei Bedarf rückwärts anpassen. Ich gehe davon aus, dass die meisten anderen Plattformen ähnliche Funktionen haben, mit denen die Systemzeit angepasst werden kann.
James McNellis
3
@Charles: Die meisten mir bekannten POSIX-Boxen sind ähnlich betroffen und ändern ihre Zeit, wenn der Benutzer die Zeit ändert.
Billy ONeal
5
Video Antwort auf diese Frage: youtube.com/watch?v=P32hvk8b13M&t=48m44s
Howard Hinnant
1
@ Charles Salvia. Nach meiner eigenen Erfahrung bei der Analyse der Timing-Ausgabe von Dutzenden von PC-Datenerfassungssystemen ist die Zeit von einem Computer nicht konstant. Linux, Windows und die spezifischen verwendeten Systemaufrufe sind unbekannt, aber die Gemeinsamkeit sind häufige negative Zeitunterschiede zwischen nachfolgenden Zeitwerten. Gerade Zeit ist nicht die Norm.
Tyson Hilmer

Antworten:

71

Von N3376:

20.11.7.1 [time.clock.system] / 1:

Klassenobjekte system_clockrepräsentieren die Wanduhrzeit von der systemweiten Echtzeituhr.

20.11.7.2 [time.clock.steady] / 1:

Klassenobjekte steady_clockstellen Uhren dar, für die die Werte von time_pointniemals mit fortschreitender physikalischer Zeit abnehmen und für die Werte von time_pointfortschreitender Geschwindigkeit relativ zur Echtzeit. Das heißt, die Uhr kann möglicherweise nicht eingestellt werden.

20.11.7.3 [time.clock.hires] / 1:

Klassenobjekte high_resolution_clockrepräsentieren Uhren mit der kürzesten Tick-Periode. high_resolution_clockkann ein Synonym für system_clockoder sein steady_clock.

Beispielsweise kann die systemweite Uhr von einer Sommerzeit beeinflusst werden. Zu diesem Zeitpunkt kann die zu einem späteren Zeitpunkt angegebene tatsächliche Zeit tatsächlich eine Zeit in der Vergangenheit sein. (ZB in den USA bewegt sich die Herbstzeit um eine Stunde zurück, so dass dieselbe Stunde "zweimal" erlebt wird.) Es steady_clockist jedoch nicht gestattet, von solchen Dingen betroffen zu sein.

Eine andere Art, in diesem Fall über "stetig" nachzudenken, sind die Anforderungen, die in der Tabelle vom 20.11.3 [time.clock.req] / 2 definiert sind:

In Tabelle 59 C1und C2bezeichnen Uhrentypen. t1und t2sind Werte, die zurückgegeben werden, C1::now()wenn die Rückgabe des Anrufs t1vor der Rückgabe des Anrufs erfolgt t2und diese beiden Anrufe zuvor erfolgen C1::time_point::max(). [Hinweis: Dies bedeutet, C1dass nicht zwischen t1und umbrochen wurde t2. - Endnote]

Ausdruck: C1::is_steady
Rückgabe: const bool
Operative Semantik: trueWenn dies t1 <= t2immer der Fall ist und die Zeit zwischen den Ticks der Uhr konstant ist, ist dies ansonsten konstant false.

Das ist alles, was der Standard über ihre Unterschiede hat.

Wenn Sie Benchmarking durchführen möchten, ist dies wahrscheinlich die beste Wahl std::high_resolution_clock, da Ihre Plattform wahrscheinlich einen hochauflösenden Timer (z. B. QueryPerformanceCounterunter Windows) für diese Uhr verwendet. Wenn Sie jedoch ein Benchmarking durchführen, sollten Sie wirklich in Betracht ziehen, plattformspezifische Timer für Ihren Benchmark zu verwenden, da verschiedene Plattformen dies unterschiedlich handhaben. Auf einigen Plattformen können Sie beispielsweise die tatsächliche Anzahl der für das Programm erforderlichen Takt-Ticks ermitteln (unabhängig von anderen Prozessen, die auf derselben CPU ausgeführt werden). Besser noch, besorgen Sie sich einen echten Profiler und nutzen Sie diesen.

Billy ONeal
quelle
1
@ Charles: Möchtest du im Standard darauf hinweisen, wo das der Fall ist? Es scheint klar das Gegenteil anzuzeigen.
Billy ONeal
9
@ Charles: Außerdem ist die POSIX-Zeit nicht "konstant" - wenn der Benutzer die Zeiteinstellung auf seinem Computer ändert, ändert sich die POSIX-Zeit. Wenn Sie ein Ei kochen und einen Timer benötigen, der 4 Minuten dauert, müssen Sie 4 Minuten dauern, auch wenn die aktuelle Zeit geändert wird. Wenn Sie einen Timer für ein Meeting am 5. um 3 Uhr eingestellt haben, müssen Sie diesen Timer unbedingt ändern, wenn sich die Ortszeit ändert. Daher der Unterschied zwischen steady_clockund system_clockhier.
Billy ONeal
1
@ 5gon: Nichts erfordert system_clockUTC.
Billy ONeal
1
@CharlesSalvia Bitte beachten Sie auch, dass die POSIX-Zeit an UTC gebunden ist und UTC Schaltsekunden hat (vgl. En.wikipedia.org/wiki/Unix_time#Leap_seconds ). Dies bedeutet, dass die C / POSIX-Zeit möglicherweise nicht monoton ist, selbst wenn die Zeit auf einer Maschine niemals angepasst wird.
Michael Schlottke-Lakemper
3
UPDATE (Visual Studio 2015) Die Implementierung von stetige Uhr hat sich geändert [.....] stetige Uhr basiert jetzt auf QueryPerformanceCounter () und high_resolution_clock ist jetzt ein typedef für stetige Uhr. Zitiert von msdn.microsoft.com/en-us/library/hh874757.aspx
felix-b
47

Billy gab eine großartige Antwort basierend auf dem ISO C ++ - Standard, dem ich voll und ganz zustimme. Es gibt jedoch eine andere Seite der Geschichte - das wirkliche Leben. Es scheint, dass es im Moment wirklich keinen Unterschied zwischen diesen Uhren bei der Implementierung populärer Compiler gibt:

gcc 4.8:

#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
   ...
#else
  typedef system_clock steady_clock;
#endif
  typedef system_clock high_resolution_clock;

Visual Studio 2012:

class steady_clock : public system_clock
{   // wraps monotonic clock
public:
  static const bool is_monotonic = true;    // retained
  static const bool is_steady = true;
};

typedef system_clock high_resolution_clock;

Im Falle von gcc können Sie überprüfen, ob Sie mit einer stabilen Uhr umgehen, indem Sie einfach prüfen is_steadyund sich entsprechend verhalten. Allerdings scheint VS2012 hier ein bisschen zu schummeln :-)

Wenn Sie eine hochpräzise Uhr benötigen, empfehle ich Ihnen, zunächst eine eigene Uhr zu schreiben, die der offiziellen C ++ 11-Uhrschnittstelle entspricht, und zu warten, bis die Implementierungen aufholen. Dies ist ein viel besserer Ansatz als die Verwendung einer betriebssystemspezifischen API direkt in Ihrem Code. Für Windows können Sie dies folgendermaßen tun:

// Self-made Windows QueryPerformanceCounter based C++11 API compatible clock
struct qpc_clock {
  typedef std::chrono::nanoseconds                       duration;      // nanoseconds resolution
  typedef duration::rep                                  rep;
  typedef duration::period                               period;
  typedef std::chrono::time_point<qpc_clock, duration>   time_point;
  static bool is_steady;                                                // = true
  static time_point now()
  {
    if(!is_inited) {
      init();
      is_inited = true;
    }
    LARGE_INTEGER counter;
    QueryPerformanceCounter(&counter);
    return time_point(duration(static_cast<rep>((double)counter.QuadPart / frequency.QuadPart *
                                                period::den / period::num)));
  }

private:
  static bool is_inited;                                                // = false
  static LARGE_INTEGER frequency;
  static void init()
  {
    if(QueryPerformanceFrequency(&frequency) == 0)
      throw std::logic_error("QueryPerformanceCounter not supported: " + std::to_string(GetLastError()));
  }
};

Für Linux ist es noch einfacher. Lesen Sie einfach die Manpage von clock_gettimeund ändern Sie den obigen Code.

Mateusz Pusz
quelle
19
Die VC ++ 2012-Implementierung wurde vom Standard-Bibliotheksbetreuer von MS als Fehler eingestuft.
ildjarn
5
Für Interessierte ist dies ein Link zu diesem Fehler
Ben Voigt
1
Boost verwendet QueryPerformanceCounter, daher ist die Verwendung von boost :: chrono eine gute Lösung für diesen Fehler, bis Visual Studio 14 veröffentlicht wird
Mohamed El-Nakib
Und hier sind die POSIX-Aufrufe, die auf GCC 5.3.0 weitergeleitet werden: stackoverflow.com/a/36700301/895245
Ciro Santilli 23 冠状 病 六四 事件 23
19

Implementierung von GCC 5.3.0

C ++ stdlib befindet sich in der GCC-Quelle:

  • high_resolution_clock ist ein Alias ​​für system_clock
  • system_clock leitet an die erste der folgenden Optionen weiter, die verfügbar sind:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock leitet an die erste der folgenden Optionen weiter, die verfügbar sind:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Dann wird CLOCK_REALTIMEvs CLOCK_MONOTONICerklärt unter: Unterschied zwischen CLOCK_REALTIME und CLOCK_MONOTONIC?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
2

Der vielleicht bedeutendste Unterschied ist die Tatsache, dass der Ausgangspunkt std::chrono:system_clockder 1.1.1970, der sogenannten UNIX-Epoche, ist. Auf der anderen Seite ist dies std::chrono::steady_clocknormalerweise die Startzeit Ihres PCs und eignet sich am besten zum Messen von Intervallen.

Silviu
quelle