web-dev-qa-db-fra.com

Différence entre std :: system_clock et std :: steady_clock?

Quelle est la différence entre std::system_clock Et std::steady_clock? (Un exemple de cas illustrant différents résultats/comportements serait formidable).

Si mon objectif est de mesurer avec précision le temps d'exécution des fonctions (comme un point de repère), quel serait le meilleur choix entre std::system_clock, std::steady_clock Et std::high_resolution_clock?

83
Vincent

À partir de N3376:

20.11.7.1 [time.clock.system]/1:

Les objets de classe system_clock Représentent l'heure de l'horloge murale à partir de l'horloge en temps réel du système.

20.11.7.2 [time.clock.steady]/1:

Les objets de classe steady_clock Représentent des horloges pour lesquelles les valeurs de time_point Ne diminuent jamais à mesure que le temps physique avance et pour lesquelles les valeurs de time_point Avancent à un taux constant par rapport au temps réel. C'est-à-dire que l'horloge ne peut pas être ajustée.

20.11.7.3 [time.clock.hires]/1:

Les objets de classe high_resolution_clock Représentent des horloges avec la période de tick la plus courte. high_resolution_clock Peut être un synonyme de system_clock Ou steady_clock.

Par exemple, l'horloge à l'échelle du système peut être affectée par quelque chose comme l'heure d'été, l'heure à laquelle l'heure réelle indiquée à un moment donné dans le futur peut en réalité être une heure passée. (Aux États-Unis, par exemple, à l’automne, le temps recule d’une heure et la même heure est vécue "deux fois"). Cependant, steady_clock N’est pas autorisé à être affecté par de telles choses.

Une autre façon de penser à "stable" dans ce cas est dans les exigences définies dans le tableau de 20.11.3 [time.clock.req]/2:

Dans le tableau 59, C1 Et C2 Désignent des types d'horloge. t1 Et t2 Sont des valeurs renvoyées par C1::now() où l'appel renvoyant t1 A lieu avant l'appel renvoyant t2 Et ces deux appels. se produire avant C1::time_point::max(). [Remarque: cela signifie que C1 Ne s'est pas écoulé entre t1 Et t2. —Fin note]

Expression: C1::is_steady
Retourne: const bool
Sémantique opérationnelle: true si t1 <= t2 Est toujours vrai et le temps entre les impulsions d'horloge est constant, sinon false.

C'est tout ce que la norme a sur leurs différences.

Si vous souhaitez effectuer une analyse comparative, votre meilleur choix sera probablement std::high_resolution_clock, Car il est probable que votre plate-forme utilise un minuteur haute résolution (par exemple, QueryPerformanceCounter sur Windows) pour cette horloge. Toutefois, si vous effectuez des analyses comparatives, vous devriez vraiment envisager d’utiliser des minuteries spécifiques à votre plate-forme, car différentes plates-formes gèrent cela différemment. Par exemple, certaines plates-formes peuvent vous donner un moyen de déterminer le nombre réel de ticks d'horloge requis par le programme (indépendamment des autres processus s'exécutant sur le même processeur). Mieux encore, mettez la main sur un véritable profileur et utilisez-le.

66
Billy ONeal

Billy a fourni une excellente réponse basée sur la norme ISO C++ avec laquelle je suis entièrement d'accord. Cependant, il y a un autre aspect de l'histoire: la vie réelle. Il semble qu’à l’heure actuelle il n’existe vraiment aucune différence entre ces horloges lors de l’implémentation de compilateurs populaires:

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;

Dans le cas de gcc, vous pouvez vérifier si vous utilisez une horloge fixe simplement en vérifiant is_steady et se comporter en conséquence. Cependant VS2012 semble tricher un peu ici :-)

Si vous avez besoin d'une horloge de haute précision, je vous recommande d'écrire votre propre horloge conforme à l'interface d'horloge officielle C++ 11 et d'attendre que les implémentations se mettent à jour. Ce sera une bien meilleure approche que d’utiliser l’API spécifique au système d’exploitation directement dans votre code. Pour Windows, vous pouvez le faire comme ça:

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

Pour Linux, c'est encore plus facile. Il suffit de lire la page de manuel de clock_gettime et modifiez le code ci-dessus.

45
Mateusz Pusz

Implémentation de GCC 5.3.0

C++ stdlib est dans la source GCC:

  • high_resolution_clock est un alias pour system_clock
  • system_clock transmet au premier des éléments suivants qui sont disponibles:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock transmet au premier des éléments suivants qui sont disponibles:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Alors CLOCK_REALTIME Vs CLOCK_MONOTONIC Est expliqué à: Différence entre CLOCK_REALTIME et CLOCK_MONOTONIC?