Sự khác biệt giữa std :: system_clock và std :: stable_clock?


97

Sự khác biệt giữa std::system_clockvà là std::steady_clockgì? (Một trường hợp ví dụ minh họa các kết quả / hành vi khác nhau sẽ rất tuyệt).

Nếu mục tiêu của tôi là để đo lường một cách chính xác thời gian thực hiện các chức năng (như một chuẩn mực), điều gì sẽ là sự lựa chọn tốt nhất giữa std::system_clock, std::steady_clockstd::high_resolution_clock?


9
Để bắt đầu, system_clock có thể không ổn định.
James McNellis

12
@CharlesSalvia Tôi không thể nói cho các nền tảng khác, nhưng system_clocknó không ổn định trên Windows. Trên Windows, thời gian hệ thống có thể được thay đổi thành bất kỳ giá trị tùy ý nào bởi bất kỳ người dùng có đủ đặc quyền. Ngoài ra, dịch vụ đồng bộ hóa thời gian có thể điều chỉnh lùi thời gian hệ thống nếu được yêu cầu. Tôi hy vọng hầu hết các nền tảng khác có các tính năng tương tự cho phép điều chỉnh thời gian hệ thống.
James McNellis

3
@Charles: Hầu hết các hộp POSIX mà tôi biết đều bị ảnh hưởng tương tự và sẽ thay đổi thời gian nếu người dùng thay đổi thời gian.
Billy ONeal

5
Video câu trả lời cho câu hỏi này: youtube.com/watch?v=P32hvk8b13M&t=48m44s
Howard Hinnant

1
@CharlesSalvia. Theo kinh nghiệm của riêng tôi khi phân tích đầu ra thời gian từ hàng chục hệ thống thu thập dữ liệu PC, thời gian từ máy tính không ổn định. Linux, Windows và các lệnh gọi hệ thống cụ thể được sử dụng là không xác định, nhưng điểm chung là sự khác biệt về thời gian âm thường xuyên giữa các giá trị thời gian tiếp theo. Thời gian đường thẳng không phải là tiêu chuẩn.
Tyson Hilmer

Câu trả lời:


71

Từ N3376:

20.11.7.1 [time.clock.system] / 1:

Các đối tượng của lớp system_clockbiểu thị thời gian đồng hồ treo tường từ đồng hồ thời gian thực trên toàn hệ thống.

20.11.7.2 [time.clock.steady] / 1:

Các đối tượng của lớp steady_clockđại diện cho đồng hồ mà giá trị time_pointkhông bao giờ giảm khi thời gian vật lý tăng lên và giá trị nào củatime_point tăng trước với tốc độ ổn định so với thời gian thực. Có nghĩa là, đồng hồ có thể không được điều chỉnh.

20.11.7.3 [time.clock.hires] / 1:

Các đối tượng của lớp high_resolution_clockđại diện cho đồng hồ có chu kỳ tích tắc ngắn nhất. high_resolution_clockcó thể là một từ đồng nghĩa với system_clockhoặc steady_clock.

Ví dụ: đồng hồ toàn hệ thống có thể bị ảnh hưởng bởi một số thứ như thời gian tiết kiệm ánh sáng ban ngày, tại thời điểm này, thời gian thực tế được liệt kê tại một số thời điểm trong tương lai thực sự có thể là một thời điểm trong quá khứ. (Ví dụ: ở Hoa Kỳ, vào mùa thu, thời gian lùi lại một giờ, do đó, cùng một giờ được trải qua "hai lần") Tuy nhiên,steady_clock không được phép bị ảnh hưởng bởi những điều như vậy.

Một cách khác để nghĩ về "ổn định" trong trường hợp này là các yêu cầu được xác định trong bảng 20.11.3 [time.clock.req] / 2:

Trong Bảng 59 C1C2biểu thị các loại đồng hồ. t1t2là các giá trị được trả về bởi C1::now()nơi mà cuộc gọi trả về t1xảy ra trước khi cuộc gọi quay lại t2và cả hai cuộc gọi này đều xảy ra trước đó C1::time_point::max(). [Lưu ý: điều này có nghĩa là C1không quấn quanh giữa t1t2 . —Gửi ghi chú]

Biểu thức: C1::is_steady
Trả về: const bool
Ngữ nghĩa hoạt động: truenếu t1 <= t2luôn đúng và thời gian giữa các lần tích tắc đồng hồ là không đổi, ngược lại false.

Đó là tất cả những gì tiêu chuẩn có về sự khác biệt của chúng.

Nếu bạn muốn thực hiện đo điểm chuẩn, cách tốt nhất của bạn có lẽ sẽ là std::high_resolution_clockvì có khả năng nền tảng của bạn sử dụng bộ đếm thời gian có độ phân giải cao (ví dụ QueryPerformanceCountertrên Windows) cho đồng hồ này. Tuy nhiên, nếu bạn đang đo điểm chuẩn, bạn thực sự nên cân nhắc sử dụng bộ tính giờ dành riêng cho nền tảng cho điểm chuẩn của mình, vì các nền tảng khác nhau xử lý điều này khác nhau. Ví dụ: một số nền tảng có thể cung cấp cho bạn một số phương tiện để xác định số xung nhịp thực tế mà chương trình yêu cầu (độc lập với các quy trình khác chạy trên cùng một CPU). Tốt hơn, hãy chạm tay vào một hồ sơ cá nhân thực sự và sử dụng nó.


1
@Charles: Cẩn thận chỉ ra trong tiêu chuẩn đó là trường hợp nào? Nó dường như chỉ rõ điều ngược lại.
Billy ONeal

9
@Charles: Ngoài ra, thời gian POSIX không "ổn định" - nếu người dùng thay đổi cài đặt thời gian trên máy tính của họ, thời gian POSIX sẽ thay đổi. Nếu bạn đang nấu trứng và cần hẹn giờ kéo dài 4 phút, thì bạn cần hẹn giờ kéo dài 4 phút ngay cả khi thời gian hiện tại được thay đổi. Nếu bạn đã đặt bộ hẹn giờ cho cuộc họp vào ngày 5 lúc 3 giờ, thì bạn hoàn toàn cần bộ hẹn giờ đó thay đổi nếu giờ địa phương thay đổi. Do đó sự khác biệt giữa steady_clocksystem_clockđây.
Billy ONeal

1
@ 5gon: Không có gì yêu cầu phải system_clocklà UTC.
Billy ONeal

1
@CharlesSalvia Cũng xin lưu ý rằng vì thời gian POSIX gắn liền với UTC và UTC có giây nhuận (xem en.wikipedia.org/wiki/Unix_time#Leap_seconds ). Điều đó có nghĩa là ngay cả khi thời gian trên máy không bao giờ được điều chỉnh, thời gian C / POSIX có thể không đơn điệu.
Michael Schlottke-Lakemper

3
CẬP NHẬT (Visual Studio 2015) Việc triển khai stable_clock đã thay đổi [.....] stable_clock hiện dựa trên QueryPerformanceCounter () và high_resolution_clock hiện là một định dạng cho stable_clock. Trích dẫn từ msdn.microsoft.com/en-us/library/hh874757.aspx
felix-b

47

Billy đã đưa ra một câu trả lời tuyệt vời dựa trên tiêu chuẩn ISO C ++ mà tôi hoàn toàn đồng ý. Tuy nhiên có một mặt khác của câu chuyện - cuộc sống thực. Có vẻ như ngay bây giờ thực sự không có sự khác biệt giữa các đồng hồ đó trong việc triển khai các trình biên dịch phổ biến:

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;

Trong trường hợp gcc, bạn có thể kiểm tra xem bạn có xử lý đồng hồ ổn định hay không bằng cách kiểm tra is_steady và xử lý phù hợp. Tuy nhiên VS2012 có vẻ gian lận một chút ở đây :-)

Nếu bạn cần đồng hồ chính xác cao, tôi khuyên bạn nên viết đồng hồ của riêng bạn phù hợp với giao diện đồng hồ chính thức của C ++ 11 và đợi các triển khai bắt kịp. Nó sẽ là cách tiếp cận tốt hơn nhiều so với việc sử dụng API cụ thể của hệ điều hành trực tiếp trong mã của bạn. Đối với Windows, bạn có thể làm như vậy:

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

Đối với Linux, nó thậm chí còn dễ dàng hơn. Chỉ cần đọc trang người đàn ông của clock_gettimevà sửa đổi mã ở trên.


19
Việc triển khai VC ++ 2012 đã được người bảo trì thư viện tiêu chuẩn của MS thừa nhận là một lỗi.
ildjarn

5
Đối với những người quan tâm, đây là một liên kết đến lỗi
Ben Voigt

1
Boost sử dụng QueryPerformanceCounter, vì vậy việc sử dụng tăng :: chrono là một tốt workaround lỗi này cho đến Visual Studio 14 được phát hành
Mohamed El-Nakib

Và đây là các cuộc gọi POSIX mà những người đó chuyển tiếp đến trên GCC 5.3.0: stackoverflow.com/a/36700301/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

19

Triển khai GCC 5.3.0

C ++ stdlib bên trong nguồn GCC:

  • high_resolution_clock là một bí danh cho system_clock
  • system_clock chuyển tiếp đến phần đầu tiên trong số các phần sau có sẵn:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock chuyển tiếp đến phần đầu tiên trong số các phần sau có sẵn:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Sau đó, CLOCK_REALTIMEso với CLOCK_MONOTONICđược giải thích tại: Sự khác biệt giữa CLOCK_REALTIME và CLOCK_MONOTONIC?


2

Có thể, sự khác biệt đáng kể nhất là thực tế điểm khởi đầu std::chrono:system_clocklà 1.1.1970, được gọi là UNIX-epoch. Mặt khác, std::chrono::steady_clockthường là thời gian khởi động của PC và nó phù hợp nhất để đo khoảng thời gian.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.