Perbedaan antara std :: system_clock dan std :: steady_clock?

97

Apa perbedaan antara std::system_clockdan std::steady_clock? (Contoh kasus yang menggambarkan hasil / perilaku berbeda akan sangat bagus).

Jika tujuan saya adalah mengukur waktu eksekusi fungsi secara tepat (seperti tolok ukur), apa pilihan terbaik antara std::system_clock, std::steady_clockdan std::high_resolution_clock?

Vincent
sumber
9
Pertama-tama, system_clock mungkin tidak stabil.
James McNellis
12
@CharlesSalvia Saya tidak dapat berbicara untuk platform lain, tetapi system_clocktidak stabil di Windows. Di Windows, waktu sistem dapat diubah menjadi nilai arbitrer oleh pengguna yang memiliki hak istimewa yang memadai. Selain itu, layanan sinkronisasi waktu dapat menyesuaikan waktu sistem mundur jika diperlukan. Saya berharap sebagian besar platform lain memiliki fitur serupa yang memungkinkan penyesuaian waktu sistem.
James McNellis
3
@Charles: Kebanyakan kotak POSIX yang saya tahu juga terpengaruh dan waktunya akan berubah jika pengguna mengubah waktu.
Billy ONeal
5
Video jawaban untuk pertanyaan ini: youtube.com/watch?v=P32hvk8b13M&t=48m44s
Howard Hinnant
1
@Tokopedia Menurut pengalaman saya sendiri menganalisis keluaran waktu dari lusinan sistem akuisisi data PC, waktu dari komputer tidak stabil. Linux, Windows, dan panggilan sistem spesifik yang digunakan tidak diketahui, tetapi kesamaannya adalah perbedaan waktu negatif yang sering terjadi antara nilai waktu berikutnya. Waktu garis lurus bukanlah norma.
Tyson Hilmer

Jawaban:

72

Dari N3376:

20.11.7.1 [time.clock.system] / 1:

Objek kelas system_clockmewakili waktu jam dinding dari jam waktu nyata di seluruh sistem.

20.11.7.2 [jam.stabil] / 1:

Objek kelas steady_clockmewakili jam yang nilainya time_pointtidak pernah berkurang seiring waktu fisik berjalan dan nilai time_pointkemajuannya pada kecepatan tetap relatif terhadap waktu nyata. Artinya, jam mungkin tidak bisa disetel.

20.11.7.3 [time.clock.hires] / 1:

Objek kelas high_resolution_clockmewakili jam dengan periode centang terpendek. high_resolution_clockmungkin sinonim untuk system_clockatau steady_clock.

Misalnya, jam lebar sistem mungkin dipengaruhi oleh sesuatu seperti waktu musim panas, di mana waktu aktual yang tercantum di beberapa titik di masa mendatang sebenarnya bisa menjadi waktu di masa lalu. (Misalnya di AS, pada musim gugur waktu bergerak mundur satu jam, sehingga jam yang sama dialami "dua kali") Namun, steady_clocktidak diperbolehkan untuk terpengaruh oleh hal-hal seperti itu.

Cara berpikir lain tentang "mantap" dalam hal ini adalah dalam persyaratan yang ditentukan dalam tabel 20.11.3 [time.clock.req] / 2:

Dalam Tabel 59 C1dan C2menunjukkan jenis jam. t1dan t2merupakan nilai yang dikembalikan oleh C1::now()tempat panggilan balik t1terjadi sebelum panggilan kembali t2dan kedua panggilan ini terjadi sebelumnya C1::time_point::max(). [Catatan: cara C1ini tidak membungkus antara t1dan t2. —Kirim catatan]

Ekspresi: C1::is_steady
Pengembalian: const bool
Semantik Operasional: truejika t1 <= t2selalu benar dan waktu antara detak jam konstan, sebaliknya false.

Hanya itu yang dimiliki standar tentang perbedaan mereka.

Jika Anda ingin melakukan benchmarking, taruhan terbaik Anda mungkin adalah std::high_resolution_clock, karena kemungkinan platform Anda menggunakan timer resolusi tinggi (misalnya QueryPerformanceCounterpada Windows) untuk jam ini. Namun, jika Anda melakukan benchmarking, Anda harus benar-benar mempertimbangkan untuk menggunakan timer khusus platform untuk benchmark Anda, karena platform yang berbeda menangani hal ini secara berbeda. Misalnya, beberapa platform mungkin memberi Anda beberapa cara untuk menentukan jumlah clock sebenarnya dari program yang diperlukan (terlepas dari proses lain yang berjalan pada CPU yang sama). Lebih baik lagi, dapatkan profiler asli dan gunakan itu.

Billy ONeal
sumber
1
@ Charles: Peduli untuk menunjukkan dalam standar di mana kasusnya? Tampaknya dengan jelas menunjukkan sebaliknya.
Billy ONeal
9
@Charles: Selain itu, waktu POSIX tidak "stabil" - jika pengguna mengubah pengaturan waktu di komputer mereka, waktu POSIX akan berubah. Jika Anda memasak telur, dan membutuhkan pengatur waktu yang bertahan selama 4 menit, maka Anda memerlukannya untuk bertahan selama 4 menit meskipun waktu saat ini diubah. Jika Anda memiliki timer yang disetel untuk rapat pada tanggal 5 pukul 3, maka Anda benar-benar membutuhkan timer tersebut untuk diubah jika waktu setempat berubah. Karenanya perbedaan antara steady_clockdan di system_clocksini.
Billy ONeal
1
@ 5gon: Tidak ada yang mensyaratkan system_clockUTC.
Billy ONeal
1
@CharlesSalvia Harap perhatikan juga bahwa karena waktu POSIX terkait dengan UTC, dan UTC memiliki detik kabisat (lih. En.wikipedia.org/wiki/Unix_time#Leap_seconds ). Itu berarti bahwa meskipun waktu pada mesin tidak pernah disesuaikan, waktu C / POSIX mungkin tidak monotonik.
Michael Schlottke-Lakemper
3
UPDATE (Visual Studio 2015) Implementasi steady_clock telah berubah [.....] steady_clock sekarang didasarkan pada QueryPerformanceCounter () dan high_resolution_clock sekarang menjadi typedef untuk steady_clock. Dikutip dari msdn.microsoft.com/en-us/library/hh874757.aspx
felix-b
47

Billy memberikan jawaban yang bagus berdasarkan standar ISO C ++ yang saya setujui sepenuhnya. Namun ada sisi lain dari cerita ini - kehidupan nyata. Tampaknya saat ini tidak ada perbedaan antara jam-jam tersebut dalam implementasi kompiler populer:

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;

Dalam kasus gcc, Anda dapat memeriksa apakah Anda menggunakan jam yang stabil hanya dengan memeriksa is_steadydan berperilaku sesuai. Namun VS2012 tampaknya sedikit curang di sini :-)

Jika Anda memerlukan jam presisi tinggi, saya sarankan untuk saat ini menulis jam Anda sendiri yang sesuai dengan antarmuka jam resmi C ++ 11 dan menunggu implementasi menyusul. Ini akan menjadi pendekatan yang jauh lebih baik daripada menggunakan API khusus OS secara langsung di kode Anda. Untuk Windows Anda dapat melakukannya seperti itu:

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

Untuk Linux bahkan lebih mudah. Cukup baca halaman manual clock_gettimedan ubah kode di atas.

Mateusz Pusz
sumber
19
Implementasi VC ++ 2012 telah diakui sebagai bug oleh pengelola perpustakaan standar MS.
ildjarn
5
Bagi mereka yang tertarik, ini adalah tautan ke bug itu
Ben Voigt
1
Boost menggunakan QueryPerformanceCounter, jadi menggunakan boost :: chrono adalah solusi yang baik untuk bug ini sampai Visual Studio 14 dirilis
Mohamed El-Nakib
Dan berikut adalah panggilan POSIX yang diteruskan ke GCC 5.3.0: stackoverflow.com/a/36700301/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
19

Penerapan GCC 5.3.0

C ++ stdlib ada di dalam sumber GCC:

  • high_resolution_clock adalah alias untuk system_clock
  • system_clock meneruskan ke yang pertama dari yang berikut ini yang tersedia:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock meneruskan ke yang pertama dari yang berikut ini yang tersedia:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Lalu CLOCK_REALTIMEvs CLOCK_MONOTONICdijelaskan di: Perbedaan antara CLOCK_REALTIME dan CLOCK_MONOTONIC?

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

Mungkin, perbedaan yang paling signifikan adalah fakta bahwa titik awalnya std::chrono:system_clockadalah 1.1.1970, yang disebut UNIX-epoch. Di sisi lain, std::chrono::steady_clockbiasanya untuk waktu boot PC Anda dan paling cocok untuk mengukur interval.

Silviu
sumber