Sự khác biệt giữa CLOCK_REALTIME và CLOCK_MONOTONIC?


206

Bạn có thể giải thích sự khác biệt giữa CLOCK_REALTIMECLOCK_MONOTONICđồng hồ được trả clock_gettime()về trên Linux không?

Lựa chọn nào tốt hơn nếu tôi cần tính thời gian trôi qua giữa dấu thời gian được tạo bởi nguồn bên ngoài và thời gian hiện tại?

Cuối cùng, nếu tôi có một trình nền NTP định kỳ điều chỉnh thời gian hệ thống, làm thế nào để những điều chỉnh này tương tác với từng CLOCK_REALTIMECLOCK_MONOTONIC?

Câu trả lời:


238

CLOCK_REALTIMEđại diện cho dự đoán tốt nhất của máy về đồng hồ treo tường hiện tại, thời gian trong ngày. Như IgnacioMarkR nói, điều này có nghĩa là CLOCK_REALTIMEcó thể nhảy tiến và lùi khi đồng hồ thời gian trong ngày của hệ thống được thay đổi, bao gồm cả NTP.

CLOCK_MONOTONICđại diện cho thời gian đồng hồ treo tường tuyệt đối trôi qua kể từ một số điểm cố định, tùy ý trong quá khứ. Nó không bị ảnh hưởng bởi những thay đổi trong đồng hồ thời gian trong ngày của hệ thống.

Nếu bạn muốn tính thời gian trôi qua giữa hai sự kiện được quan sát trên một máy mà không cần khởi động lại can thiệp, CLOCK_MONOTONIClà lựa chọn tốt nhất.

Lưu ý rằng trên Linux, CLOCK_MONOTONICkhông đo thời gian tạm dừng, mặc dù theo định nghĩa POSIX thì nên. Bạn có thể sử dụng Linux dành riêng CLOCK_BOOTTIMEcho đồng hồ đơn điệu, luôn chạy trong khi tạm dừng.


11
Lưu ý rằng trên các nhân mới hơn, CLOCK_MONOTONIC_RAW khả dụng thậm chí còn tốt hơn (không cần điều chỉnh NTP).
Joseph Garvin

14
@JosephGarvin với một số giá trị "tốt hơn", có lẽ - CLOCK_MONOTONIC_RAW có thể chạy nhanh hoặc chậm thời gian thực khoảng vài (hoặc vài trăm) phần triệu, và tốc độ của nó có thể thay đổi do điều kiện môi trường như nhiệt độ hoặc điện áp (hoặc thời gian ăn cắp máy ảo). Trên một máy hoạt động tốt, NTP cố gắng hết sức để giảm thiểu tất cả các yếu tố đó và do đó CLOCK_MONOTONIC phản ánh chặt chẽ hơn thời gian trôi qua thực sự .
hobbs

23
Được cấp, thật thú vị khi có CLOCK_MONOTONIC_PARBOILED bị ảnh hưởng bởi các nỗ lực của NTP để sửa lỗi tần số, nhưng không bị ảnh hưởng bởi các nỗ lực của mình để sửa lỗi pha, nhưng điều đó rất phức tạp đối với mức tăng đáng ngờ :)
hobbs

1
Tôi thích điểm mà @hobbs đưa ra. Điều gì xảy ra nếu bạn lo lắng về các chương trình có thể bị ảnh hưởng bởi sự trôi dạt của đồng hồ? Sẽ CLOCK_MONOTONIClà sự lựa chọn tốt nhất trong kịch bản đó? ví dụ: Hệ thống tên lửa yêu nước
sjagr

3
Tôi nghĩ điều quan trọng là phải đề cập rằng CLOCK_REALTIME bị ảnh hưởng bởi những giây nhuận. Điều này có nghĩa là nó sẽ tạo ra dấu thời gian gấp đôi mỗi lần chèn giây. Lần trước điều này xảy ra vào ngày 30 tháng 6 năm 2012 và khá nhiều phần mềm gặp sự cố .
dùng1202136

38

Cuốn sách LINUX System Lập trình 2 của Robert Love , đặc biệt giải quyết câu hỏi của bạn ở đầu Chương 11, trang 363:

Khía cạnh quan trọng của nguồn thời gian đơn điệu KHÔNG phải là giá trị hiện tại, nhưng đảm bảo rằng nguồn thời gian được tăng tuyến tính nghiêm ngặt, và do đó hữu ích cho việc tính toán chênh lệch thời gian giữa hai lần lấy mẫu

Điều đó nói rằng, tôi tin rằng anh ta giả định rằng các quy trình đang chạy trên cùng một phiên bản của một hệ điều hành, vì vậy bạn có thể muốn có một hiệu chuẩn định kỳ đang chạy để có thể ước tính độ trôi.


25

CLOCK_REALTIMEbị ảnh hưởng bởi NTP và có thể di chuyển tiến và lùi. CLOCK_MONOTONIClà không, và tiến lên ở một tích tắc trên mỗi tích tắc.


15
CLOCK_MONOTONIC bị ảnh hưởng bởi việc điều chỉnh thời gian của NTP (xoay vòng thời gian). Nó sẽ không nhảy, tuy nhiên.
derobert

3
Nhưng trên các nhân mới hơn có CLOCK_MONOTONIC_RAW, thực sự không bị ảnh hưởng bởi NTP.
Joseph Garvin

1
"tick" - có ý kiến ​​sơ bộ nào về việc các lệnh lớn / dài / CPU là một đánh dấu trên Linux / amd64 không? Hoặc nơi tôi có thể nhận tài liệu về bất kỳ điều này?
kevinarpe

@kevinarpe Không chắc chắn nhưng tôi nghĩ rằng một đánh dấu được định nghĩa là một phần nhỏ thời gian, không phải là một số chu kỳ CPU, thường là 1/100 giây.
Stéphane

@ Stéphane: Tôi chắc chắn phải chặt hơn 10ms. Tôi nghĩ rằng việc System.nanoTime()sử dụng Java CLOCK_MONOTONICvà có thể đo thời lượng từ 1000ns trở xuống. Có thể bạn đang nghĩ về thời gian hệ thống, đôi khi bị giới hạn trong một phần nghìn giây?
kevinarpe

20

Ngoài câu trả lời của Ignacio , CLOCK_REALTIMEcó thể đi lên trong những bước nhảy vọt, và đôi khi ngược lại.CLOCK_MONOTONICkhông; nó chỉ tiếp tục tiến lên (mặc dù nó có thể đặt lại khi khởi động lại).

Một ứng dụng mạnh mẽ cần có khả năng chịu đựng CLOCK_REALTIME nhảy về phía trước thỉnh thoảng (và có lẽ ngược lại rất hơi thỉnh thoảng, mặc dù đó là nhiều hơn một trường hợp cạnh).

Hãy tưởng tượng những gì xảy ra khi bạn treo máy tính xách tay của bạn - CLOCK_REALTIMEnhảy về phía trước sau khi tiếp tục, CLOCK_MONOTONICkhông. Hãy thử nó trên máy ảo.


3
CLOCK_MONOTONIC bắt đầu từ 0 khi chương trình bắt đầu; Nó không phải là để sử dụng liên quá trình.
Benubird

18
@Benubird: Nó không bắt đầu từ 0 khi chương trình bắt đầu. Đó là CLOCK_PROCESS_CPUTIME_ID. Kiểm tra nhanh: $ perl -w -MTime::HiRes=clock_gettime,CLOCK_MONOTONIC -E 'say clock_gettime(CLOCK_MONOTONIC)'-> 706724.117565279. Con số đó phù hợp với thời gian hoạt động của hệ thống trên Linux, nhưng tiêu chuẩn cho biết tùy ý.
derobert

4
Bên cạnh đó, tôi không tin rằng hành vi của Linux khi CLOCK_MONOTONICdừng việc đình chỉ / tiếp tục là tuân thủ POSIX. Nó được cho là thời gian kể từ một điểm cố định trong quá khứ, nhưng việc dừng đồng hồ qua việc đình chỉ / tiếp tục phá vỡ điều đó.
phê

15

Báo giá POSIX 7

POSIX 7 chỉ định cả hai tại http://pub.opengroup.org/onlinepub/9699919799/fifts/clock_getres.html :

CLOCK_REALTIME:

Đồng hồ này đại diện cho đồng hồ đo thời gian thực cho hệ thống. Đối với đồng hồ này, các giá trị được trả về bởi clock_gettime () và được chỉ định bởi clock_settime () đại diện cho lượng thời gian (tính bằng giây và nano giây) kể từ Kỷ nguyên.

CLOCK_MONOTONIC (tính năng tùy chọn):

Đối với đồng hồ này, giá trị được trả về bởi clock_gettime () biểu thị lượng thời gian (tính bằng giây và nano giây) kể từ một điểm không xác định trong quá khứ (ví dụ: thời gian khởi động hệ thống hoặc Epoch). Điểm này không thay đổi sau thời gian khởi động hệ thống. Giá trị của đồng hồ CLOCK_MONOTONIC không thể được đặt qua clock_settime ().

clock_settime() đưa ra một gợi ý quan trọng: hệ thống POSIX có thể tùy ý thay đổi CLOCK_REALITME theo nó, vì vậy đừng dựa vào nó chảy liên tục cũng không chuyển tiếp. NTP có thể được thực hiện bằng cách sử dụng clock_settime()và chỉ có thể ảnh hưởng đếnCLOCK_REALITME .

Việc triển khai nhân Linux dường như lấy thời gian khởi động làm kỷ nguyên cho CLOCK_MONOTONIC: Điểm khởi đầu cho CLOCK_MONOTONIC


0

Xin lỗi, không có danh tiếng để thêm điều này như là một bình luận. Vì vậy, nó đi như một câu trả lời bổ sung.

Tùy thuộc vào tần suất bạn sẽ gọi clock_gettime(), bạn nên nhớ rằng chỉ một số "đồng hồ" được Linux cung cấp trong VDSO (nghĩa là không yêu cầu một tòa nhà với tất cả chi phí của một - điều này chỉ trở nên tồi tệ hơn khi thêm Linux phòng thủ để bảo vệ chống lại các cuộc tấn công giống như Spectre).

Mặc dù clock_gettime(CLOCK_MONOTONIC,...), clock_gettime(CLOCK_REALTIME,...)gettimeofday()luôn luôn cực kỳ nhanh (được tăng tốc bởi VDSO), nhưng điều này không phải đúng với, ví dụ CLOCK_MONOTONIC_RAW hoặc bất kỳ đồng hồ POSIX nào khác.

Điều này có thể thay đổi với phiên bản kernel và kiến ​​trúc.

Mặc dù hầu hết các chương trình không cần chú ý đến điều này, nhưng có thể có sự tăng vọt về độ trễ trong đồng hồ được tăng tốc bởi VDSO: nếu bạn nhấn chúng ngay khi kernel đang cập nhật vùng nhớ chung với bộ đếm đồng hồ, thì phải chờ nhân để hoàn thành.

Đây là "bằng chứng" (GitHub, để tránh bot khỏi kernel.org): https://github.com/torvalds/linux/commit/2aae950b21e4bc789d1fc6668faf67e8748300b7

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.