ความแตกต่างระหว่าง CLOCK_REALTIME และ CLOCK_MONOTONIC หรือไม่


206

คุณสามารถอธิบายความแตกต่างระหว่างCLOCK_REALTIMEและCLOCK_MONOTONICนาฬิกาที่ส่งคืนโดยclock_gettime()บน Linux ได้หรือไม่

ตัวเลือกใดดีกว่าหากฉันต้องการคำนวณเวลาที่ผ่านไประหว่างการประทับเวลาที่ผลิตโดยแหล่งภายนอกและเวลาปัจจุบัน

ท้ายที่สุดถ้าฉันมี NTP daemon เป็นการปรับเวลาของระบบเป็นระยะ ๆ การปรับเหล่านี้จะทำงานกับแต่ละรายการCLOCK_REALTIMEและCLOCK_MONOTONICอย่างไร

คำตอบ:


238

CLOCK_REALTIMEแสดงถึงการคาดเดาที่ดีที่สุดของเครื่องเกี่ยวกับนาฬิกาแขวนผนังในปัจจุบัน, ช่วงเวลาของวัน ดังที่อิกนาชิโอและMarkRพูดนี่หมายความว่าCLOCK_REALTIMEสามารถกระโดดไปข้างหน้าและข้างหลังเมื่อเวลานาฬิกาของระบบมีการเปลี่ยนแปลงซึ่งรวมถึงโดย NTP

CLOCK_MONOTONICแสดงถึงเวลานาฬิกาแขวนที่ผ่านไปอย่างแน่นอนเนื่องจากบางจุดที่กำหนดไว้โดยพลการในอดีต ไม่ได้รับผลกระทบจากการเปลี่ยนแปลงในนาฬิกาบอกเวลาของระบบ

หากคุณต้องการคำนวณเวลาที่ผ่านไประหว่างสองเหตุการณ์ที่พบในเครื่องเดียวโดยไม่ต้องรีบูตเครื่องCLOCK_MONOTONICเป็นตัวเลือกที่ดีที่สุด

โปรดทราบว่าบน Linux CLOCK_MONOTONICไม่ได้วัดเวลาที่ใช้ในการระงับแม้ว่าตามคำนิยาม POSIX ที่ควรจะเป็น คุณสามารถใช้ลินุกซ์เฉพาะCLOCK_BOOTTIMEสำหรับนาฬิกาแบบโมโนโทนิกที่ทำงานต่อเนื่องในระหว่างการหยุดชั่วคราว


11
โปรดทราบว่าในเมล็ดที่ใหม่กว่า CLOCK_MONOTONIC_RAW จะพร้อมใช้งานซึ่งดียิ่งขึ้น (ไม่มีการปรับ NTP)
โจเซฟการ์วิน

14
@JosephGarvin สำหรับค่าบางส่วนของ "ดีกว่า" บางที - CLOCK_MONOTONIC_RAW อาจทำงานได้เร็วหรือช้าตามเวลาจริงโดยหลายส่วน (หรือหลายร้อย) ต่อล้านและอัตราอาจเปลี่ยนแปลงเนื่องจากสภาพแวดล้อมเช่นอุณหภูมิหรือแรงดันไฟฟ้า (หรือขโมยเวลาใน เครื่องเสมือน) บนเครื่องต้องทำงาน, NTP จะดีที่สุดเพื่อลดปัจจัยทั้งหมดเหล่านั้นและเพื่อ CLOCK_MONOTONIC ใกล้ชิดมากขึ้นสะท้อนให้เห็นถึงความจริงเวลาที่ผ่านไป
ฮอบส์

23
จริงอยู่ที่มันน่าสนใจที่จะมี CLOCK_MONOTONIC_PARBOILED ที่ได้รับผลกระทบจากความพยายามของ NTP ในการแก้ไขข้อผิดพลาดความถี่ แต่ไม่ได้รับผลกระทบจากความพยายามในการแก้ไขข้อผิดพลาดของเฟส แต่นั่นเป็นเรื่องที่ซับซ้อนมากสำหรับผลกำไรที่น่าสงสัย :)
hobbs

1
ฉันชอบจุดที่ @hobbs ปรากฏขึ้น ถ้าคุณกังวลเกี่ยวกับโปรแกรมที่อาจได้รับผลกระทบจากการเลื่อนนาฬิกา จะCLOCK_MONOTONICเป็นตัวเลือกที่ดีที่สุดในสถานการณ์นั้นหรือไม่ เช่นPatriot Missile System
sjagr

3
ฉันคิดว่ามันสำคัญเช่นกันที่ต้องพูดถึงว่า CLOCK_REALTIME ได้รับผลกระทบจากวินาทีกระโดด ซึ่งหมายความว่ามันจะสร้างการประทับเวลาสองครั้งทุกครั้งที่แทรกวินาทีกระโดด ครั้งสุดท้ายที่เกิดขึ้นใน 30 มิถุนายน 2012 และค่อนข้างมากซอฟต์แวร์วิ่งเข้าสู่ปัญหา
user1202136

38

หนังสือ Robert Love's LINUX System Programming รุ่นที่ 2โดยเฉพาะคำถามของคุณที่จุดเริ่มต้นของบทที่ 11, pg 363:

ลักษณะที่สำคัญของแหล่งเวลาแบบโมโนโทนิกไม่ใช่ค่าปัจจุบัน แต่การรับประกันว่าแหล่งเวลานั้นเพิ่มขึ้นแบบเส้นตรงอย่างเคร่งครัดจึงมีประโยชน์สำหรับการคำนวณความแตกต่างของเวลาระหว่างสองตัวอย่าง

ที่กล่าวว่าฉันเชื่อว่าเขากำลังสมมติว่ากระบวนการกำลังทำงานอยู่บนอินสแตนซ์เดียวกันของระบบปฏิบัติการดังนั้นคุณอาจต้องการให้มีการสอบเทียบเป็นระยะเพื่อให้สามารถประมาณค่าดริฟท์ได้


25

CLOCK_REALTIMEได้รับผลกระทบจาก NTP และสามารถเลื่อนไปข้างหน้าและข้างหลังได้ CLOCK_MONOTONICไม่ใช่และเลื่อนไปหนึ่งขีดต่อหนึ่งขีด


15
CLOCK_MONOTONIC ได้รับผลกระทบจากการปรับเปลี่ยนเวลาของ NTP (การเลื่อนเวลา) อย่างไรก็ตามมันจะไม่กระโดด
Derobert

3
แต่สำหรับเมล็ดที่ใหม่กว่านั้นคือ CLOCK_MONOTONIC_RAW ซึ่งไม่ได้รับผลกระทบจาก NTP จริงๆ
โจเซฟการ์วิน

1
"ติ๊ก" - มีความคิดคร่าวๆว่าคำสั่งขนาดใหญ่ / ยาว / CPU มีขีดใน Linux / amd64 อย่างไร หรือฉันจะหาเอกสารได้จากที่ใด
kevinarpe

@kevinarpe ไม่แน่ใจ แต่ฉันคิดว่าเห็บถูกกำหนดเป็นเสี้ยวเวลาไม่ใช่จำนวนรอบของ CPU ซึ่งมักจะเป็น 1/100 วินาที
Stéphane

@ Stéphane: แน่นอนฉันต้องเข้มงวดกว่า 10ms ฉันคิดว่าการSystem.nanoTime()ใช้งานของ Java CLOCK_MONOTONICและสามารถวัดระยะเวลา 1,000ns หรือน้อยกว่า บางทีคุณอาจคิดถึงเวลาของระบบซึ่งบางครั้ง จำกัด ไว้ที่มิลลิวินาที?
kevinarpe

20

นอกจากคำตอบของอิกนาชิโอแล้วCLOCK_REALTIMEก็สามารถก้าวขึ้นไปข้างหน้าได้ในบางครั้ง CLOCK_MONOTONICไม่; มันจะดำเนินต่อไป (แม้ว่ามันอาจจะรีเซ็ตเมื่อรีบูต)

แอปที่แข็งแกร่งต้องสามารถทนต่อการCLOCK_REALTIMEกระโจนไปข้างหน้าเป็นครั้งคราว (และอาจย้อนกลับไปเล็กน้อยมากบางครั้งถึงแม้ว่าจะเป็นกรณีขอบมากขึ้น)

ลองจินตนาการถึงสิ่งที่เกิดขึ้นเมื่อคุณระงับแล็ปท็อปของคุณ - CLOCK_REALTIMEกระโดดไปข้างหน้าต่อไปสมัครงาน, CLOCK_MONOTONICไม่ได้ ลองใช้กับ VM


3
CLOCK_MONOTONIC เริ่มที่ 0 เมื่อโปรแกรมเริ่มทำงาน มันไม่ได้มีไว้สำหรับการใช้งานระหว่างกระบวนการ
Benubird

18
@Benubird: มันไม่ได้เริ่มต้นที่ 0 เมื่อโปรแกรมเริ่มต้น CLOCK_PROCESS_CPUTIME_IDที่ ทดสอบอย่างรวดเร็ว: $ perl -w -MTime::HiRes=clock_gettime,CLOCK_MONOTONIC -E 'say clock_gettime(CLOCK_MONOTONIC)'-> 706724.117565279 หมายเลขนั้นตรงกับช่วงเวลาที่ระบบทำงานบน Linux แต่มาตรฐานระบุว่าเป็นไปโดยพลการ
Derobert

4
ในฐานะที่เป็นกันฉันไม่เชื่อว่าพฤติกรรมลินุกซ์ที่CLOCK_MONOTONICหยุดมากกว่าหยุดชั่วคราว / ประวัติย่อเป็น POSIX- สอดคล้อง มันควรจะเป็นเวลาตั้งแต่จุดคงที่ในอดีต แต่การหยุดนาฬิกาเพื่อหยุดชั่วคราว / กลับมาพักอีกครั้ง
caf

15

คำพูด POSIX 7

POSIX 7 ระบุทั้งที่http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html :

CLOCK_REALTIME:

นาฬิกานี้แสดงเวลาจริงของนาฬิกาสำหรับระบบ สำหรับนาฬิกานี้ค่าที่ส่งคืนโดย clock_gettime () และระบุโดย clock_settime () แทนจำนวนเวลา (เป็นวินาทีและนาโนวินาที) ตั้งแต่ Epoch

CLOCK_MONOTONIC (คุณสมบัติเสริม):

สำหรับนาฬิกานี้ค่าที่ส่งคืนโดย clock_gettime () หมายถึงจำนวนเวลา (เป็นวินาทีและนาโนวินาที) ตั้งแต่จุดที่ไม่ระบุในอดีต (ตัวอย่างเช่นเวลาเริ่มต้นระบบหรือ Epoch) จุดนี้ไม่เปลี่ยนแปลงหลังจากเวลาเริ่มต้นระบบ ค่าของนาฬิกา CLOCK_MONOTONIC ไม่สามารถตั้งค่าผ่าน clock_settime ()

clock_settime()ให้คำแนะนำที่สำคัญ: ระบบ POSIX สามารถเปลี่ยนแปลงได้โดยพลการCLOCK_REALITMEดังนั้นไม่ต้องพึ่งพาการไหลไม่ต่อเนื่องหรือส่งต่อ NTP อาจจะดำเนินการโดยใช้และอาจส่งผลกระทบเท่านั้นclock_settime()CLOCK_REALITME

การใช้เคอร์เนลของ Linux ดูเหมือนว่าจะใช้เวลาบูตเป็นจุดเริ่มต้นของCLOCK_MONOTONIC : จุดเริ่มต้นสำหรับ CLOCK_MONOTONIC


0

ขออภัยไม่มีชื่อเสียงในการเพิ่มความคิดเห็น ดังนั้นมันจึงเป็นคำตอบที่สมบูรณ์

ขึ้นอยู่กับว่าคุณมักจะเรียกclock_gettime()คุณควรเก็บไว้ในใจว่ามีเพียงบางส่วนของ "นาฬิกา" ที่ให้บริการโดยลินุกซ์ใน VDSO (คือไม่จำเป็นต้อง syscall ที่มีค่าใช้จ่ายทั้งหมดของหนึ่ง - ซึ่งมีเพียงเลวร้ายยิ่งเมื่อลินุกซ์เพิ่ม การป้องกันเพื่อป้องกันการโจมตีเหมือนปีศาจ)

ในขณะที่clock_gettime(CLOCK_MONOTONIC,...), clock_gettime(CLOCK_REALTIME,...)และgettimeofday()มักจะไปได้อย่างรวดเร็ว (เร่งโดย VDSO) นี้เป็นไม่จริงสำหรับเช่น CLOCK_MONOTONIC_RAW หรือใด ๆ ของนาฬิกา POSIX อื่น ๆ

สิ่งนี้สามารถเปลี่ยนแปลงได้ด้วยเวอร์ชันเคอร์เนลและสถาปัตยกรรม

แม้ว่าโปรแกรมส่วนใหญ่ไม่จำเป็นต้องให้ความสนใจกับสิ่งนี้ แต่อาจมีหนามแหลมในเวลาที่นาฬิกาเร่งโดย VDSO: หากคุณกดได้ถูกต้องเมื่อเคอร์เนลกำลังปรับปรุงพื้นที่หน่วยความจำที่ใช้ร่วมกันด้วยตัวนับสัญญาณนาฬิกาก็ต้องรอ เคอร์เนลให้เสร็จ

นี่คือ "หลักฐาน" (GitHub เพื่อป้องกันบอทจาก kernel.org): https://github.com/torvalds/linux/commit/2aae950b21e4bc789d1fc6668faf67e8748300b7

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.