Std :: system_clock ve std :: steady_clock arasındaki fark?


98

Arasındaki fark nedir std::system_clockve std::steady_clock? (Farklı sonuçları / davranışları gösteren örnek bir vaka harika olurdu).

Amacım, işlevlerin (bir kıyaslama gibi) uygulama süresini kesin olarak ölçmekse std::system_clock, std::steady_clockve arasında en iyi seçim ne olur std::high_resolution_clock?


9
Başlamak için system_clock sabit olmayabilir.
James McNellis

12
@CharlesSalvia Diğer platformlar için konuşamıyorum, ancak system_clockWindows'ta sabit değil. Windows'ta, sistem saati yeterince ayrıcalıklı herhangi bir kullanıcı tarafından herhangi bir keyfi değere değiştirilebilir. Ek olarak, zaman senkronizasyon hizmeti, gerekirse sistem saatini geriye doğru ayarlayabilir. Diğer platformların çoğunun, sistem saatinin ayarlanmasına izin veren benzer özelliklere sahip olmasını bekliyorum.
James McNellis

3
@Charles: Bildiğim çoğu POSIX kutusu benzer şekilde etkileniyor ve kullanıcı saati değiştirirse zamanları da değişecek.
Billy ONeal


1
@CharlesSalvia. Düzinelerce PC veri toplama sisteminden zamanlama çıktısını analiz etme deneyimime göre, bir bilgisayardan gelen zaman sabit değildir. Linux, Windows ve kullanılan belirli sistem çağrıları bilinmemektedir, ancak ortak olan, sonraki zaman değerleri arasında sık görülen negatif zaman farklılıklarıdır. Düz çizgi zaman norm değildir.
Tyson Hilmer

Yanıtlar:


74

N3376'dan:

20.11.7.1 [time.clock.system] / 1:

Sınıfın nesneleri system_clock, sistem genelinde gerçek zamanlı saatin duvar saati zamanını temsil eder.

20.11.7.2 [time.clock.steady] / 1:

Sınıfın nesneleri, fiziksel zaman ilerledikçe steady_clockdeğerleri time_pointhiçbir zaman azalmayan ve ilerleme değerleri time_pointiçin gerçek zamana göre sabit bir hızda olan saatleri temsil eder . Yani saat ayarlanamayabilir.

20.11.7.3 [time.clock.hires] / 1:

Sınıfın nesneleri, high_resolution_clocken kısa tıklama periyoduna sahip saatleri temsil eder. high_resolution_clockeşanlamlıdır olabilir system_clockya da steady_clock.

Örneğin, sistem geniş saati, gün ışığından yararlanma saati gibi bir şeyden etkilenebilir; bu noktada, gelecekte bir noktada listelenen gerçek zaman aslında geçmişte bir zaman olabilir. (Örneğin ABD'de düşüş zamanı bir saat geriye gider, dolayısıyla aynı saat "iki kez" yaşanır) Ancak steady_clockbu tür şeylerden etkilenmesine izin verilmez.

Bu durumda "sabit" hakkında düşünmenin bir başka yolu, 20.11.3 [time.clock.req] / 2 tablosunda tanımlanan gereksinimlerdedir:

Tablo 59 yılında C1ve C2göstermektedirler saat türleri. t1ve geri dönüşün çağrı geri dönmeden önce olduğu ve bu çağrıların her ikisi de daha önce gerçekleştiği yerde t2döndürülen değerlerdir . [Not: Bu, ve arasında dolaşmadığı anlamına gelir . - notu gönder] C1::now()t1t2C1::time_point::max()C1t1t2

İfade: C1::is_steady
İade: const bool
İşlemsel Semantik: trueeğer t1 <= t2her zaman doğruysa ve saat tıklamaları arasındaki zaman sabittir, aksi halde false.

Standartların farklılıkları bu kadar.

Kıyaslama yapmak istiyorsanız, muhtemelen en iyi seçeneğiniz olacaktır std::high_resolution_clock, çünkü muhtemelen platformunuz QueryPerformanceCounterbu saat için yüksek çözünürlüklü bir zamanlayıcı (örneğin Windows'ta) kullanmaktadır. Bununla birlikte, kıyaslama yapıyorsanız, kıyaslamanız için platforma özel zamanlayıcıları kullanmayı gerçekten düşünmelisiniz, çünkü farklı platformlar bunu farklı şekilde ele alır. Örneğin, bazı platformlar size program için gerekli olan saat tiklerinin gerçek sayısını belirlemenin bazı yollarını verebilir (aynı CPU üzerinde çalışan diğer işlemlerden bağımsız olarak). Daha da iyisi, gerçek bir profil oluşturucuya geçin ve onu kullanın.


1
@Charles: Durumun nerede olduğunu standartta belirtmek ister misiniz? Bunun tam tersini açıkça gösteriyor gibi görünüyor.
Billy ONeal

9
@Charles: Ayrıca, POSIX zamanı "sabit" değildir - kullanıcı bilgisayarındaki zaman ayarını değiştirirse POSIX zamanı da değişecektir. Bir yumurta pişiriyorsanız ve 4 dakika süren bir zamanlayıcıya ihtiyacınız varsa, mevcut saat değişse bile 4 dakika sürmesi gerekir. 5. gün saat 3'te bir toplantı için ayarlanmış bir zamanlayıcınız varsa, yerel saat değişirse değiştirmek için kesinlikle bu zamanlayıcıya ihtiyacınız vardır. Bu nedenle steady_clockve system_clockburası arasındaki fark .
Billy ONeal

1
@ 5gon: Hiçbir şeyin system_clockUTC olmasını gerektirmez .
Billy ONeal

1
@CharlesSalvia Lütfen POSIX saatinin UTC'ye bağlı olduğunu ve UTC'nin artık saniye olduğunu unutmayın (cf. en.wikipedia.org/wiki/Unix_time#Leap_seconds ). Bu, bir makinedeki zaman hiçbir zaman ayarlanmasa bile, C / POSIX zamanının monoton olmayabileceği anlamına gelir.
Michael Schlottke-Lakemper

3
GÜNCELLEME (Visual Studio 2015) steady_clock uygulaması değişti [.....] steady_clock artık QueryPerformanceCounter () 'ı temel alır ve high_resolution_clock artık steady_clock için bir typedef. Msdn.microsoft.com/en-us/library/hh874757.aspx
felix-b'den

47

Billy, tamamen katıldığım ISO C ++ standardına dayalı harika bir cevap verdi. Ancak hikayenin başka bir yanı daha var - gerçek hayat. Görünüşe göre şu anda popüler derleyicilerin uygulanmasında bu saatler arasında gerçekten bir fark yok:

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;

Gcc durumunda, sadece kontrol ederek is_steadyve buna göre davranarak sabit saatle başa çıkıp çıkmadığınızı kontrol edebilirsiniz . Ancak VS2012 burada biraz hile yapıyor gibi görünüyor :-)

Yüksek hassasiyetli saate ihtiyacınız varsa şimdilik C ++ 11 resmi saat arayüzüne uyan kendi saatinizi yazmanızı ve uygulamaların yakalanmasını beklemenizi tavsiye ederim. Doğrudan kodunuzda işletim sistemine özgü API kullanmaktan çok daha iyi bir yaklaşım olacaktır. Windows için bunu şu şekilde yapabilirsiniz:

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

Linux için daha da kolay. Sadece man sayfasını okuyun ve clock_gettimeyukarıdaki kodu değiştirin.


19
VC ++ 2012 uygulaması, MS'nin standart kitaplık bakıcısı tarafından bir hata olarak kabul edildi.
ildjarn

5
İlgilenenler için, bu hataya bir bağlantı
Ben Voigt

1
Boost, QueryPerformanceCounter kullanır, bu nedenle boost :: chrono kullanmak, Visual Studio 14 yayınlanana kadar bu
hatada iyi bir çözümdür

Ve işte GCC 5.3.0'da yönlendirilen POSIX çağrıları: stackoverflow.com/a/36700301/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

19

GCC 5.3.0 uygulaması

C ++ stdlib, GCC kaynağının içindedir:

  • high_resolution_clock takma addır system_clock
  • system_clock mevcut olanlardan ilkine iletir:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock mevcut olanlardan ilkine iletir:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Daha sonra CLOCK_REALTIMEvs CLOCK_MONOTONIC, şu sayfada açıklanır: CLOCK_REALTIME ve CLOCK_MONOTONIC arasındaki fark nedir?


3

Belki de en önemli fark, başlangıç ​​noktasının std::chrono:system_clock1.1.1970, sözde UNIX-dönemi olmasıdır. Öte yandan, std::chrono::steady_clockgenellikle PC'nizin önyükleme süresi için ve aralıkları ölçmek için en uygunudur.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.