Linux2.26计时架构

在上一篇文章中,介绍了计算机系统的时间设备。这些设备在Linux整个计时架构中处于最底层。 在硬件设备中获取时间相关的数据后,Linux系统需要做以下几个工作:

  • 更新自系统启动以来的时间戳
  • 更新当前时间日期
  • 计算每个CPU上进程执行的时间
  • 更新资源使用率统计
  • 更新定时器系统调用

这些操作每一个tick都会完成一次。 那么什么是tick呢? tick是Linux计时架构中一个重要的概念,中文称之为时钟滴答。 在IRQ0上连续两次定时器中断的时间间隔称为tick,时长保存在tick_nsec变量中。 tick_nsec通常情况下会初始化为999,848纳秒,接近1毫秒,因为时间中断的频率一般设置为1000Hz(PIT的时间中断频率)。

Kernel将时间抽象成几个重要的数据结构:

  • The timer object

    这个结构用来抽象不同时间源的数据。 其中两个重要变量mark_offsetget_offset

    • mark_offset记录上一次tick的时间,定时器中断的时候更新。
    • get_offset返回自上一次tick后经过的时间,单位是微秒。

    Linux使用这两个变量做插值,提供比tick更高精度的时间记录。 另外cur_timer变量保存精度最高的时间源(timer_hpet > timer_pmtmr > timer_tsc > timer_pit > timer_none

  • The jiffies variable

    jiffies变量保存系统开启到现在的tick数。 在x86体系下,jiffies是一个32位的变量,只能记录约50天。当要溢出的时候,Linux会使用其他变量去转换,做到持续记录tick。 在系统启动的时候,jiffies初始化为0xfffb6c20,五分钟后即溢出。 这样做的目的是可以及时发现不对溢出做的处理的kernel,不会影响稳定的版本。 jiffies不声明为64位的原因是在32位系统不能高效读写64位的变量。

  • The xtime variable

    xtime保存的是上墙时间。 其中有两个字段tv_sectv_nsec

    • tv_sec保存从(UTC)1970-1-1号到当前时间的秒数。
    • tv_nsec保存上一秒到现在经历的纳秒数。

    xtime每个tick更新一次,一秒钟大约更新1000次。

为了完成时间相关的工作,Linux计时架构有两个主要操作,计时器的初始化和定时器的中断处理。

  • 计时器初始化

    在kernel初始化期间会调用time_init()函数。time_init()完成以下操作:

    1. 初始化xtime变量。从RTC读取至1970-1-1至今的秒数。
    2. 初始化wall_to_monotonic变量。这个变量和xtime类似。
    3. 如果系统支持HPET,则调用hpet_enable()函数启动HPET,否则使用PIT
    4. 调用select_timer()选择最好的时钟源。
    5. 开启IRQ0中断,系统定时器可以接收来自PIT或者HPET的中断。

    至此计时器初始化完成。之后每次tick都会调用timer_interrupt()函数。

  • 定时器中断处理(timer_interrupt)

    1. 开启xtime自旋锁
    2. 根据cur_timer的值,处理mark_offset
      • timer_hpet: HPET是中断源,如果丢失中断,mark_offset则更新jiffies
      • timer_pmtmr: PIT是中断源,APIC是时间源。如果丢失中断,mark_offset则更新jiffies
      • timer_tsc: PIT是中断源,TSC是时间源。如果丢失中断,mark_offset根据需要更新jiffies
      • timer_pit: PIT是中断源,而且没有其他时间源,mark_offset不更新
    3. 调用do_timer_interrupt()函数
      • 增加jiffies
      • 调用update_times()函数更新系统时间日期和计算系统复杂
      • 调用update_process_times()函数执行特定CPU相关的操作,比如切换进程等
      • 调用profile_tick()函数
    4. 释放xtime自旋锁

需要注意的是,多核的定时器架构和单核的定时器架构有不同的处理流程。 在单处理器系统,所有的时间活动都由全局定时器触发。 在多处理器系统,所有一般的活动由全局定时器触发,特定CPU的活动由CPU Local Timer触发。 但是这两种情况的界定比较模糊,而且一些多核系统的CPU并没有CPU Local Timer。

Tags: 定时器 服务端技术