计算机时钟
既然本书中的大多数的例子都需要测量一个时间间隔,我们需要更仔细地介绍一下当前U n i x系统所采用的记录时间的方法。下面的描述适用于本书中例子所使用的系统,也适用于大多数的U n i x系统。[ L e ffler et al. 1989]的3 . 4节和3 . 5节给出了另外的细节。
硬件按照一定的频率产生一个时钟中断。对于 Sun SPA R C和Intel 80386,时钟中断每10 ms产生一次。应该注意到大多数的计算机使用一种无补偿的晶体振荡器来生成这些时钟中断。正如RFC1305 [Mills 1992] 的表7指出的,你不要想知道这种振荡器一天的偏差有多少。这就意味着几乎没有计算机能维持精确的时间(即,中断并不是精确地每 10 ms发生一次)。一个0 . 0 1%的误差就会产生一个每天 8 . 6 4秒的差错。为了得到更好的时间测量需要: (1)一个更好的振荡器; (2)一个外部的更精确的时间资源(如,全球定位卫星提供的时间资源);或者 ( 3)通过因特网访问一个具有更精确时钟的系统。后者通过 R F C 1 3 0 5定义的网络时间协议实现,对该协议的描述超出了本书的范围。
U n i x系统中引起时间差错的另一个公共的原因是 10 ms的中断只是引起内核给一个记录时间的变量增 1。如果内核丢失了一个中断(也就是说两个连续中断之间间隔 10 ms 对于内核来说太快了),时钟将失去 10 ms 。丢失这种类型的中断经常引起 U n i x系统丢失时间。
尽管时间中断近似于每10 ms到达一次,更新的系统,如 S PA R C,提供了一个更高精度的定时器来测量时间差异。通过 N I T驱动程序,t c p d u m p(在附录A中描述)已经访问了这个更高精度的定时器。在 S PA R C上,这个定时器提供了 微 秒 级 的 精 度 。 用 户 进 程 也 可 以 通 过g e t t i m e o f d a y( 2 )函数来访问这个更高精度的定时器。
作者做了下面的试验。我们运行了一个程序,这个程序在一个循环里调用了10 000次g e t t i m e o f d a y函数,并将每次的返回值保存在一个数组中。在循环结束后,打印了9 9 9 9个时间差。对于一个S PARC ELC,时间差的分布如图B - 1所示。
在一个空闲的系统中,运行这个程序所花的时钟时间为 0 . 3 8秒。根据这一点,我们可以说进程调用g e t t i m e o f d a y所花的时间大约 3 7微秒。既然E L C的速度是2 1 M I P S(M I P S表示每秒1 0 0万指令),3 7微秒相应于大约8 0 0个指令。这些指令对于内核处理一个用户进程的调用、执行系统调用、复制 8个字节的结果及返回给用户进程看起来是合理的( M I P S速度是不可靠的,很难测量当前系统的指令时间。我们试图做的只是得到一个粗略的估计来评价一下上面的值是否有意义)。
从这个简单的试验,我们可以说 g e t t i m e o f d a y返回的值确实包含了微秒级的精度。
如果我们在S V R 4 / 3 8 6上进行类似的测试,结果是不同的。这是因为很多 386 Unix 系统,如S V R 4,只计数 10 ms的时钟中断,而没有提供更高的精度。图 B - 2是运行在 25 MHz 80386 上的S V R 4中9 9 9 9个时间差的分布。
这些值是无意义的,因为时间差一般小于 1 0 m s,都被认为是0了。在这些系统中,我们所能做的就是在一个空闲的系统上测量时钟时间,除以循环的次数。这个结果提供了一个上界,因为它包含了调用 p r i n t f函数9 9 9 9次的时间和将结果写入一个文件的时间(在 S PA R C的情况,图B - 1,时间差没有包括p r i n t f的时间,因为所有10 000个值都是首先获得的,然后才打印结果)。在S V R 4的时钟时间为3 . 1 5秒,每个系统调用消耗了3 1 5微秒。这个大约比S PA R C慢8 . 5倍的系统调用时间看来是正确的。
BSD/386 1.0版提供了类似于S PA R C的微秒级的精度。它读8 2 5 3时钟寄存器,计算从上次时钟中断以来的微秒次数。调用 g e t t i m e o f d a y的进程和内核模块,如BSD 分组过滤器,可以使用这个精度。
和t c p d u m p联系起来,这些数字意味着我们可以相信在 S PA R C和B S D / 3 8 6系统上打印的毫秒和亚毫秒( s u b m i l l i s e c o n d )的值。而在S V R 4 / 3 8 6上,t c p d u m p打印的值总是10 ms的倍数。对于其他打印往返时间的程序,如 p i n g(第7章)和t r a c e r o u t e(第8章),在S PA R C和B S D / 3 8 6系统上,我们可以相信它们输出的毫秒值,但在 S V R 4 / 3 8 6上,打印的值总是 1 0的倍数。为了在 L A N上测量某个 p i n g的时间,在第 7章中我们显示的时间是 3 ms,所以需要在S PA R C和B S D / 3 8 6系统上运行p i n g程序。
本书中的一些例子是运行在BSD/386 0.9.4版上,它类似于S V R 4,只提供了10 ms的时钟精度。在我们显示这个系统的t c p d u m p输出时,只显示到小数点后面两位,因为这就是所提供的精度。