Linux如何管理和度量时间

 

Timing Measurement

Linux 内核的Timer必须要完成两种定时测量(timing measurement)

  • 保存当前的日期时间
  • 维护定时器(Timer)

     保存当前时间提供给相关系统调用time(), ftime(),gettimeofday(),以便他们将日期时间返回给用户程序;维护定时器提醒内核某一段时间已经过去。要实现以上定时测量就离不开相关硬件的支持,下面看下X86体系下相关时钟和定时电路有哪些。

 

时钟和定时电路

     下面仅列出X86体系结构下常见的时间相关硬件定时器、时钟。

实时时钟, 依靠电池供电,集成在CMOS芯片上(结合NVRAM和RTC),可以得到日期和时间

 80×86处理器通过CLK引线,接收外部时钟信号,从Pentium开始 80×86处理器提供了一个TSC寄存器, 收到时钟信号后加一。可以通过rtdsc指令获取该值。因此TSC可以做为时钟设备。

又被称作8253/8254芯片, 这种设备不是通过振铃而是通过发出一种特殊中断,时钟中断通知内核一个时间间隔又过去了。时钟频率大约1.193182 MHz

由于是CPU内部的振荡器所有避免了资源抢占,APIC timer分为三种模式: Periodic Mode(周期模式),One-Shot Mode(一次性模式),TSC-Deadline Mode(Deadline模式) 

是Intel和Microsoft设计的硬件,用于替换PIT,RTC, 提供更高的频率, 包含一个64位的主计数器和3到32个32位或64位的比较器。工作模式分为: eriodic Mode(周期模式),One-Shot Mode(一次性模式)

         在所有基于 ACPI 的主板, 频率为 3.579545 MHz

         关于 Timer Interrupt Sources 的比较

https://wiki.osdev.org/Timer_Interrupt_Sources

       从上面表格也可以看到 这些硬件设备提供的功能非常简单:中断、计数,要基于这些硬件进行时间管理,还需要Linux Kernel做很多工作。 

 

Linux 内核中的时间概念

            内核依据硬件提供的时钟,以特定的频率称作 tick rate, 触发时钟中断,通过中断处理程序对其进行处理。

  • 内核通过tick rate可以知道两次时钟中断的时间, 等于1/(tick rate)秒。
  • 通过已知的时钟中断来跟踪实际时间(Wall time)和系统运行时间。
  • 内核依据实际时间(Wall time)给用户空间提供一组相关系统调用。
  • 系统运行时间-自系统启动后的时间,对于内核空间和用户空间都非常有用。

 

利用时钟中断进行的工作

  • 更新系统时间
  • 更新实际时间
  • SMP系统中均衡调度程序中各处理器上运行队列
  • 运行已超时的动态计数器
  •  更新资源消耗和处理时间的统计值。

The Tick Rate :HZ

        HZ是通过静态预处理定义的,在系统启动时按照HZ值对硬件进行设置。根据体系结构不通HZ值也不同。时钟中断周期为 1/HZ。

        X86下默认HZ 100, 一个时钟中断周期为10ms,下面X86 CentOS 环境的设置。

[root@centosgpt asm-generic]# pwd
/usr/include/asm-generic
[root@centosgpt asm-generic]# cat param.h
#ifndef __ASM_GENERIC_PARAM_H
#define __ASM_GENERIC_PARAM_H

#ifndef HZ
#define HZ 100
#endif
  • 高HZ的优点
    • 内核计数器以更精细的分辨率( finer resolution)和更高的准确度(increased accuracy)运行。
    • 测量(measurement)以更精细的分辨率记录
    • 进程抢占更准确地发生
  • 高HZ的缺点
    • 更大的开销
    • 处理器花费更多时间在时间中断上
    • 更频繁执行中断打乱了处理器高速缓存,并增加耗电
  • tickless

 编译内核是可以通过CONFIG_HZ选项设置,系统可以根据需要动态调整时钟中断,在不需要终端的空档期, 不触发时钟中断,从而减少消耗。配置tickless

 

jiffies

          全局变量jiffies用来记录系统启动以来产生的节拍的总数, 启动时,初始化为0, 每次时钟中断处理程序会递增。

           jiffies与HZ, 一秒钟内时钟中断次数等于HZ,jiffies一秒中增加的值就是HZ,系统运行时间以秒为单位等于jiffies/HZ; 以秒为单位的时间转化为jiffies(seconds * HZ),

  • The jiffies 变量总是一个 unsigned long类型,  32-bit 体系结构 32位,  64-bit 体系结构是64位
  • 在100HZ情况下, 497天会溢出,1000HZ情况下49.7天会溢出,如果是64位的jiffies,由于数值非常大, 1000HZ情况下,大约 ‭213503982334.6天会溢出‬。
  • jiffies溢出后的回绕。
  • 变量 extern u64 jiffies_64 ,jiffies读取jiffies_64低32位,通过get_jiffies_64()获得全部的64-bits值。

          2038年问题 与jiffies回绕(wrap round)相关的问题,time_t被定义为32位的相关系统,在其上运行的应用如果使用POSIX时间的程序都将涉及2038年问题, 也就是到了2038年1月19日, time_t数字将无法工作。

     

定时器

  • 定时器使用:设置一个超时时间, 指定超时发生后函数, 然后激活定时器就可以了。
  •  定时器的竞争条件:定时器执行的与当前代码异步,所以可能存在潜在的竞争条件。
  • 实现定时器:内核在时钟中断发生后执行定时器 , 定时器做为软中断在下半部上下文执行。

 

 延迟

  •   忙等待:需要一致循环,替代方案是使用cond_reched()
  •   短延时:内核提供的三个延迟函数ji,他们没有使用jiffies
    • void udelay(unsigned long usecs)
    • void ndelay(unsigned long nsecs)
    • void mdelay(unsigned long msecs)
  • schedule_timeout() 让需要延时的任务睡眠到指定延时时间耗尽然后重新运行。

       

           依赖于硬件提供的时钟中断和计数, 通过jiffies记录时钟tick, 完成对时间度量, 通过时间度量也完成了时间记录,定时器使用和延时的设置。

 

参考

            Linux 核心設計: Timer 及其管理機制

            Linux 时间系统分析

           What is the difference between CMOS and RTC?

           2038年问题

           64-bit computing – Wikipedia

 

 

Be First to Comment

发表回复