Differenza tra std :: system_clock e std :: steady_clock?


97

Qual'è la differenza tra std::system_clocke std::steady_clock? (Un caso esemplificativo che illustri risultati / comportamenti diversi sarebbe fantastico).

Se il mio obiettivo è quello di misurare con precisione il tempo di esecuzione di funzioni (come un punto di riferimento), quale sarebbe la scelta migliore tra i std::system_clock, std::steady_clocke std::high_resolution_clock?


9
Per cominciare, system_clock potrebbe non essere stabile.
James McNellis

12
@CharlesSalvia Non posso parlare per altre piattaforme, ma system_clocknon è stabile su Windows. Su Windows, l'ora di sistema può essere modificata in qualsiasi valore arbitrario da qualsiasi utente sufficientemente privilegiato. Inoltre, il servizio di sincronizzazione dell'ora può regolare l'ora di sistema all'indietro, se necessario. Mi aspetto che la maggior parte delle altre piattaforme abbia caratteristiche simili che consentono la regolazione dell'ora di sistema.
James McNellis

3
@Charles: la maggior parte delle scatole POSIX che conosco sono influenzate in modo simile e cambieranno l'ora se l'utente cambia l'ora.
Billy ONeal

5
Video di risposta a questa domanda: youtube.com/watch?v=P32hvk8b13M&t=48m44s
Howard Hinnant

1
@CharlesSalvia. In base alla mia esperienza nell'analisi dell'output di temporizzazione da dozzine di sistemi di acquisizione dati per PC, il tempo da un computer non è costante. Linux, Windows e le chiamate di sistema specifiche utilizzate sono sconosciute, ma l'elemento comune è rappresentato dalle frequenti differenze temporali negative tra i valori temporali successivi. Il tempo in linea retta non è la norma.
Tyson Hilmer

Risposte:


72

Dalla N3376:

20.11.7.1 [time.clock.system] / 1:

Gli oggetti di classe system_clockrappresentano l'ora dell'orologio da parete dall'orologio in tempo reale a livello di sistema.

20.11.7.2 [time.clock.steady] / 1:

Gli oggetti di classe steady_clockrappresentano orologi per i quali i valori di time_pointnon diminuiscono mai con l'avanzare del tempo fisico e per i quali i valori di time_pointavanzamento ad una velocità costante rispetto al tempo reale. Cioè, l'orologio potrebbe non essere regolato.

20.11.7.3 [time.clock.hires] / 1:

Gli oggetti di classe high_resolution_clockrappresentano gli orologi con il periodo di tick più breve. high_resolution_clockpuò essere sinonimo di system_clocko steady_clock.

Ad esempio, l'orologio del sistema potrebbe essere influenzato da qualcosa come l'ora legale, a quel punto l'ora effettiva elencata in un momento futuro può effettivamente essere un'ora nel passato. (Ad esempio, negli Stati Uniti, in autunno il tempo torna indietro di un'ora, quindi la stessa ora viene vissuta "due volte") Tuttavia, steady_clocknon è consentito essere influenzato da tali cose.

Un altro modo di pensare a "steady" in questo caso è nei requisiti definiti nella tabella del 20.11.3 [time.clock.req] / 2:

Nella Tabella 59 C1e C2denotano i tipi di orologio. t1e t2sono valori restituiti da C1::now()dove la chiamata di ritorno t1avviene prima della chiamata di ritorno t2ed entrambe queste chiamate si verificano prima C1::time_point::max(). [Nota: questo significa che C1non è stato eseguito il wrapping tra t1e t2. —End nota]

Espressione: C1::is_steady
Restituisce: const bool
Semantica operazionale: truese t1 <= t2è sempre vero e il tempo tra i tick dell'orologio è costante, altrimenti false.

Questo è tutto ciò che lo standard ha sulle loro differenze.

Se vuoi fare benchmarking, la soluzione migliore sarà probabilmente std::high_resolution_clock, perché è probabile che la tua piattaforma utilizzi un timer ad alta risoluzione (ad esempio QueryPerformanceCountersu Windows) per questo orologio. Tuttavia, se stai effettuando il benchmarking, dovresti davvero prendere in considerazione l'utilizzo di timer specifici della piattaforma per il tuo benchmark, perché piattaforme diverse gestiscono questo in modo diverso. Ad esempio, alcune piattaforme potrebbero fornire alcuni mezzi per determinare il numero effettivo di tick di clock richiesti dal programma (indipendentemente da altri processi in esecuzione sulla stessa CPU). Meglio ancora, metti le mani su un vero profiler e usalo.


1
@Charles: vuoi far notare nello standard dov'è il caso? Sembra indicare chiaramente il contrario.
Billy ONeal

9
@Charles: Inoltre, il tempo POSIX non è "stabile" - se l'utente modifica l'impostazione dell'ora sul proprio computer, l'ora POSIX cambierà. Se stai cucinando un uovo e hai bisogno di un timer che duri 4 minuti, allora devi farlo durare 4 minuti anche se l'ora corrente è cambiata. Se hai un timer impostato per una riunione il 5 alle 3, allora devi assolutamente cambiarlo se cambia l'ora locale. Da qui la differenza tra steady_clocke system_clockqui.
Billy ONeal

1
@ 5gon: Niente richiede che system_clocksia UTC.
Billy ONeal

1
@CharlesSalvia Nota anche che poiché l'ora POSIX è legata all'UTC e l'UTC ha secondi intercalari (cfr. En.wikipedia.org/wiki/Unix_time#Leap_seconds ). Ciò significa che anche se l'ora su una macchina non viene mai regolata, l'ora C / POSIX potrebbe non essere monotona.
Michael Schlottke-Lakemper,

3
UPDATE (Visual Studio 2015) L'implementazione di steady_clock è cambiata [.....] steady_clock è ora basato su QueryPerformanceCounter () e high_resolution_clock è ora un typedef per steady_clock. Citato da msdn.microsoft.com/en-us/library/hh874757.aspx
felix-b

47

Billy ha fornito un'ottima risposta basata sullo standard ISO C ++ con cui sono pienamente d'accordo. Tuttavia, c'è un altro aspetto della storia: la vita reale. Sembra che in questo momento non ci sia davvero alcuna differenza tra questi clock nell'implementazione di compilatori popolari:

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;

In caso di gcc puoi controllare se hai a che fare con un orologio stabile semplicemente controllando is_steady e comportandoti di conseguenza. Tuttavia VS2012 sembra barare un po 'qui :-)

Se hai bisogno di un orologio ad alta precisione, ti consiglio per ora di scrivere il tuo orologio che sia conforme all'interfaccia ufficiale dell'orologio C ++ 11 e attendere che le implementazioni raggiungano. Sarà un approccio molto migliore rispetto all'utilizzo dell'API specifica del sistema operativo direttamente nel codice. Per Windows puoi farlo in questo modo:

// 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()));
  }
};

Per Linux è ancora più semplice. Basta leggere la pagina man di clock_gettimee modificare il codice sopra.


19
L'implementazione di VC ++ 2012 è stata riconosciuta come un bug dal manutentore della libreria standard di MS.
ildjarn

5
Per chi fosse interessato, questo è un collegamento a quel bug
Ben Voigt

1
Boost utilizza QueryPerformanceCounter, quindi l'utilizzo di boost :: chrono è una buona soluzione a questo bug fino al rilascio di Visual Studio 14
Mohamed El-Nakib

E qui sono POSIX chiama quelli in avanti per il GCC 5.3.0: stackoverflow.com/a/36700301/895245
Ciro Santilli郝海东冠状病六四事件法轮功

19

Implementazione di GCC 5.3.0

Lo stdlib di C ++ è all'interno del sorgente GCC:

  • high_resolution_clock è un alias per system_clock
  • system_clock inoltra al primo dei seguenti disponibili:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock inoltra al primo dei seguenti disponibili:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Quindi CLOCK_REALTIMEvs CLOCK_MONOTONICè spiegato in: Differenza tra CLOCK_REALTIME e CLOCK_MONOTONIC?


2

Forse, la differenza più significativa è il fatto che il punto di partenza di std::chrono:system_clockè l'1.1.1970, la cosiddetta epoca UNIX. D'altro canto, std::chrono::steady_clocktipicamente il tempo di avvio del tuo PC ed è più adatto per misurare gli intervalli.

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.