一、前语
时钟或许挂钟(clock)是一种计时东西,每个人都至少有一块,或许在你的手机里,也或许佩带在你的手腕上。假如Linux也是一个普通人的话,那么她的手腕上应该有十几块手表,包含:CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_PROCESS_CPUTIME_ID、CLOCK_THREAD_CPUTIME_ID、CLOCK_MONOTONIC_RAW、CLOCK_REALTIME_COARSE、CLOCK_MONOTONIC_COARSE、CLOCK_BOOTTIME、CLOCK_REALTIME_ALARM、CLOCK_BOOTTIME_ALARM、CLOCK_TAI。本文首要便是介绍Linux内核中的五花八门的“挂钟”。
二、了解Linux中各种clock分类的根底
已然本文讲Linux中的计时东西,那么咱们首要面临的便是“什么是时刻?”,这个问题实在是太难答复了,因而咱们这儿就不正面答复了,咱们只是从几个旁边面来窥视时刻的特性,而时刻的实质就留给物理学家和哲学家考虑吧。
1、怎么衡量时刻
时刻往往是和改变相关,因而人们往往喜爱运用有固定周期改变规则的运动行为来界说时刻,所以人们把地球围自转一周的时刻分红24份,每一份界说为一个小时,而一个小时被均匀分红3600份,每一份便是1秒。可是,地球的运动周期不是那么安稳,怎么办?多丈量几个,均匀一下嘛。
尽管经过天体的运动界说了秒这样的根本的时刻衡量单位,可是,要想准确的表明时刻,咱们依靠一种有安稳的周期改变的现象。上一节咱们说过了:地球环绕太阳工作不是一个安稳的周期现象,因而每次观察到的周期不是固定的(当然都大约是24小时的姿态),用它来界说秒多少显得不是那么精准。科学家们发现铯133原子在能量跃迁时分辐射的电磁波的振动频率十分的安稳(不要问我这是什么原理,我也不知道),因而被用来界说时刻的根本单位:秒(或许称之为原子秒)。
2、Epoch
界说了时刻单位,等于时刻轴上有了刻度,尽管这条代表时刻的直线咱们不知道从何开端,终究去向何方,咱们终归是能够把一个时刻点映射到这条直线上了。乃至假如界说了原点,那么咱们能够用一个数字(到原点的间隔)来表明时刻。
假如说界说时刻的衡量单位是技术活,那么界说时刻轴的原点则完全是一个习气问题。拿出你的手表,上面能够读出2017年5月10,23时17分28秒07毫秒……作为一个地球人,你挑选了耶稣诞辰日做原点,讲真,这弱爆了。作为linuxer,你应该具有这样的一块手表,从这个手表上只能看到一个从当时时刻点到linux epoch的秒数和毫秒数。Linux epoch界说为1970-01-01 00:00:00 +0000 (UTC),后边的这个UTC十分十分重要,咱们后边会描绘。
除了wall time,linux体系中也需求了解体系自发动以来过去了多少的时刻,这时分,咱们能够把挂钟的epoch调整成体系的发动时刻点,这时分获取体系发动时刻就很简略了,直接看这块挂钟的读数即可。
3、时刻调整
记住小的时分,每隔一段时刻,老爸的手表总会慢上一分钟左右的时刻,也是他总是在7点钟,新闻联播之前等候那校时的最终一响。一听到“方才最终一响是北京时刻7点整”中那最终“滴”的一声,老爸也把自己的手表调整成为7点整。关于linux体系,这个操作相似clock_set接口函数。
相似老爸机械表的时刻调整,linux的时刻也需求调整,机械表的发条和齿轮结构没有那么精准,核算机的晶振亦然。前面讲了,UTC的计时是依据原子钟的,可是来到Linux内核这个场景,咱们莫非要为咱们的核算机装置一个原子钟来计时吗?当然能够,假如你满意有钱的话。咱们一般人的核算机仍是依据体系中的本地振动器来计时的,尽管精度不抱负,可是短时刻内你也不会有太多的感觉。当然,人们往往是神往更准确的计时(有些场合也需求),因而就有了时刻同步的概念(例如NTP(Network Time Protocol))。
所谓时刻同步其实便是用一个精准的时刻来调整本地的时刻,详细的调整方法有两种,一种便是直接设定当时时刻值,别的一种是采用了润物细无声的方式,对本地振动器的输出进行纠正。第一种方法会导致时刻轴上的时刻会向前或许向后的跳动,无法确保时刻的接连性和单调性。第二种方法是对时刻轴缓慢的调整(而不是直接设定),然后确保了接连性和单调性。
4、闰秒(leap second)
经过原子秒延展出来的时刻轴便是TAI(International Atomic Time)clock。这块“表”不论日出、日落,机械的依照ce原子界说的那个秒在推进时刻。冷冰冰的TAI clock尽管精准,可是对人类而言是不友好的,究竟人仍是日子在这颗蓝色星球上。而那些依据地球自转,公转周期的时刻(例如GMT)尽管契合人类习气,可是又不行准确。在这样的布景下,UTC(Coordinated Universal Time)被提出来了,它是TAI clock的基因(运用原子秒),可是又会恰当的调整(leap second),满意人类出产和日子的需求。
OK,至此,咱们了解了TAI和UTC两块表的状况,这两块表的发条是相同的,依照相同的时刻滴答(tick,精准的依据原子频率界说的那个秒)来推进挂钟的秒针的滚动,仅有不同的是,UTC clock有一个调节器,在恰当的时刻,能够把秒针向前或许向后调整一秒。
TAI clock和UTC clock在1972年进行了对准(相差10秒),尔后就各自独立运行了。在大部分的时刻里,UTC clock跟从TAI clock,除了在恰当的时刻点,realtime clock会进行leap second的补偿。从1972年到2017年,现已有了27次leap second,因而TAI clock的读数现已比realtime clock(UTC时刻)快了37秒。换句话说,TAI和UTC两块表其实能够笼统成一个时刻轴,只不过它们之间有一个固定的偏移。在1972年,它们之间的offset是10秒,经过多年的工作,到了2017年,offset累计到37秒,让我静静等候下一个leap second到了的时刻吧。
5、计时规模
有一类特别的clock称作秒表,发动后开端计时,中心能够暂停,能够康复。咱们能够经过这样的秒表来记载一个人睡觉的时刻,当进入睡觉状况的时分,按下start按键开端计时,一旦醒来则按下stop,暂停计时。linux中也有这样的计时东西,用来核算一个进程或许线程的履行时刻。
6、时刻精度
时刻是接连的吗?你眼中的国际是接连的吗?看到窗外清风吹拂的树叶的时分,你感觉每一个树叶的形状都被你捕捉到了。可是,未必,你看急速行进的轿车的轮胎的时分,感觉车轮是倒转的。为什么?其实这只是是由于咱们的眼睛大约是每秒15~20帧的速度在采样这个国际,你看到的国际是离散的。算了,扯远了,咱们权且以为时刻的接连的,可是Linux中的时刻记载却不是接连的,咱们能够用下面的图片表明:
体系在每个tick到来的时分都会更新体系时刻(到linux epoch的秒以及纳秒值记载),当然,也有其他场景进行体系时刻的更新,这儿就不赘述了。因而,关于linux的时刻而言,它是一些离散值,是一些时刻采样点的值罢了。当用户恳求时刻服务的时分,例如获取当时时刻(上图中的红线),那么最近的那个Tick对应的时刻采样点值再加上一个当时时刻点到上一个tick的delta值就精准的定位了当时时刻。不过,有些场合下,时刻精度没有那么重要,直接获取上一个tick的时刻值也根本是OK的,不需求校准那个delta也能满意需求。并且粗粒度的clock会带来performance的优势。
7、睡觉的时分时刻会中止运作吗?
在实践国际提出这个问题会稍显可笑,鲁迅同学有一句名言:时刻永是消逝,街市仍旧和平。可是关于Linux体系中的clock,这个就有实践的含义了。比如说clock的一个重要的派生功用是创立timer(也便是说timer总是依据一个特定的clock运作)。在一个5秒的timer超期之前,体系先进入了suspend或许关机状况,这时分,5秒时刻抵达的时分,一般的timer都不会触发,由于底层的clock或许是依据一个free running counter的,在suspend或许关机状况的时分,这个HW counter都不再运作了,你怎么期盼它能唤醒体系,来履行timer expired handler?可是用户仍是有这方面的实践需求的,最简略的便是关机闹铃。怎么办?这就需求一个特别的clock,能够在suspend或许关机的时分,依然能够运作,推进timer到期触发。
三、Linux下的各种clock总结
在linux体系中界说了如下的clock id:
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 1
#define CLOCK_PROCESS_CPUTIME_ID 2
#define CLOCK_THREAD_CPUTIME_ID 3
#define CLOCK_MONOTONIC_RAW 4
#define CLOCK_REALTIME_COARSE 5
#define CLOCK_MONOTONIC_COARSE 6
#define CLOCK_BOOTTIME 7
#define CLOCK_REALTIME_ALARM 8
#define CLOCK_BOOTTIME_ALARM 9
#define CLOCK_SGI_CYCLE 10 /* Hardware specific */
#define CLOCK_TAI 11
CLOCK_PROCESS_CPUTIME_ID和CLOCK_THREAD_CPUTIME_ID这两个clock是专门用来核算进程或许线程的履行时刻的(用于功能分析),一旦进程(线程)被切换出去,那么该进程(线程)的clock就会停下来。因而,这两种的clock都是per-process或许per-thread的,而其他的clock都是体系等级的。
依据上面一章的各种分类要素,咱们能够将其他clock总结收拾如下:
leap second?clock set?clock tunning?original pointresolutionactive in suspend?realtimeyesyesyesLinux epochnsnomonotonicyesnoyesLinux epochnsnomonotonic rawyesnonoLinux epochnsnorealtime coarseyesyesyesLinux epochticknomonotonic coarseyesnoyesLinux epochticknoboot timeyesnoyesmachine startnsnorealtime alarmyesyesyesLinux epochnsyesboottime alarmyesnoyesmachine startnsyestainononoLinux epochnsno