高分辨率定时器和动态时钟设计笔记 【ChatGPT】

发布时间 2023-12-11 22:02:20作者: 摩斯电码

高分辨率定时器和动态时钟设计笔记

更多信息可以在OLS 2006年的演讲论文"hrtimers and beyond"中找到。该论文是OLS 2006年会议第1卷的一部分,可以在OLS网站上找到:https://www.kernel.org/doc/ols/2006/ols2006v1-pages-333-346.pdf

此次演讲的幻灯片可从以下链接获取:http://www.cs.columbia.edu/~nahum/w6998/papers/ols2006-hrtimers-slides.pdf

幻灯片包含五个图表(第2页、第15页、第18页、第20页、第22页),展示了Linux子系统中与时间相关的变化。图表#1(第2页)显示了在hrtimers和其他构建模块合并到主线内核之前Linux时间系统的设计。

注意:论文和幻灯片中提到了"clock event source",而我们目前已经切换到了"clock event devices"的名称。

设计包括以下基本构建模块:

  • 高分辨率定时器基础设施
  • 时间和时钟源管理
  • 时钟事件管理
  • 高分辨率定时器功能
  • 动态时钟

高分辨率定时器基础设施

高分辨率定时器基础设施已合并到2.6.16内核中。基础实现的详细信息在"hrtimers - subsystem for high-resolution kernel timers"中有所涵盖。另请参阅图表#2(OLS幻灯片第15页)。

与定时器轮相比,主要区别在于:

  • 时间有序地加入到红黑树中
  • 独立于时钟滴答(处理基于纳秒)

时间和时钟源管理

John Stultz的通用时间管理框架(GTOD)将大部分代码从特定于体系结构的区域移出,放入了一个通用的管理框架中,如图表#3(OLS幻灯片第18页)所示。体系结构特定部分被减少到时钟源的低级硬件细节,这些细节在框架中注册并根据质量进行选择。低级代码提供硬件设置和读取例程,并初始化数据结构,这些数据结构被通用时间保持代码用于将时钟滴答转换为基于纳秒的时间值。所有其他与时间相关的功能都移入了通用代码。GTOD基础补丁已合并到2.6.18内核中。

有关通用时间管理框架的更多信息,请参阅OLS 2005年会议第1卷:

论文"We Are Not Getting Any Younger: A New Approach to Time and Timers"由J. Stultz、D.V. Hart和N. Aravamudan撰写。

图表#3(OLS幻灯片第18页)说明了这一转变。

时钟事件管理

虽然时钟源提供对单调递增时间值的读取访问,但时钟事件设备用于调度下一个事件中断。当前定义的下一个事件是周期性的,其周期在编译时定义。对各种事件驱动功能的事件设备的设置和选择是硬编码到体系结构相关代码中的。这导致了所有体系结构中的重复代码,并且使得难以更改系统配置以使用除了已经内置到体系结构中的事件中断设备之外的其他设备。当前设计的另一个影响是,为了提供新功能(如高分辨率定时器或动态时钟),需要触及所有体系结构特定的实现。

时钟事件子系统试图通过提供一种通用解决方案来管理时钟事件设备及其在各种时钟事件驱动内核功能中的使用,来解决这个问题。时钟事件子系统的目标是将与时钟事件相关的体系结构相关代码最小化到纯硬件相关处理,并允许轻松添加和利用新的时钟事件设备。它还最小化了跨体系结构的重复代码,因为它提供了通用功能,直到中断服务处理程序,这几乎是固有地依赖于硬件。

时钟事件设备可以由体系结构相关的引导代码或模块插入时注册。每个时钟事件设备都填充了一个具有特定于时钟的属性参数和回调函数的数据结构。时钟事件管理通过使用指定的属性参数,决定时钟事件设备将用于支持的系统功能集。这包括区分每CPU和全局系统级事件设备。

系统级全局事件设备用于Linux的周期性滴答。每CPU事件设备用于提供本地CPU功能,如进程账户、分析和高分辨率定时器。

管理层为时钟事件设备分配以下一个或多个功能:

  • 系统全局周期性滴答(jiffies更新)
  • CPU本地update_process_times
  • CPU本地分析
  • CPU本地下一个事件中断(非周期模式)

时钟事件设备完全委托了这些定时器中断相关功能的选择给管理层。时钟管理层在设备描述结构中存储一个函数指针,该指针必须从硬件级处理程序中调用。这样可以从体系结构特定的定时器中断处理程序中删除大量重复的代码,并将时钟事件设备的控制和定时器中断相关功能的分配交给核心代码。

时钟事件层的API相当小。除了时钟事件设备注册接口外,它还提供了用于调度下一个事件中断、时钟事件设备通知服务和挂起和恢复支持的函数。

该框架增加了约700行代码,导致内核二进制大小增加了2KB。对i386的转换删除了约100行代码。二进制大小的减少在400字节的范围内。我们相信,灵活性的增加和跨体系结构的重复代码的避免,可以证明轻微的二进制大小增加是合理的。

对体系结构的转换没有功能影响,但允许利用高分辨率和动态滴答功能,而无需更改时钟事件设备和定时器中断代码。转换后,启用高分辨率定时器和动态滴答只需将kernel/time/Kconfig文件添加到特定体系结构的Kconfig中,并将动态滴答特定调用添加到空闲例程中(总共添加了3行到空闲函数和Kconfig文件)。

图表#4(OLS幻灯片第20页)说明了这一转变。

高分辨率定时器功能

在系统启动期间,不可能使用高分辨率定时器功能,而使其可能会很困难,也没有实际用途。在高分辨率功能生效之前,必须初始化时钟事件设备框架、时钟源框架(GTOD)和hrtimers本身,并注册适当的时钟源和时钟事件设备。直到hrtimers初始化之前,系统都是在通常的低分辨率周期模式下运行。时钟源和时钟事件设备层提供通知功能,通知hrtimers有新硬件的可用性。hrtimers在切换到高分辨率模式之前验证已注册的时钟源和时钟事件设备的可用性。这也确保了配置为高分辨率定时器的内核可以在缺乏必要的硬件支持的系统上运行。

高分辨率定时器代码不支持仅具有全局时钟事件设备的SMP机器。支持这样的硬件将涉及在发生中断时进行IPI调用。开销将远大于收益。这就是为什么我们目前在i386 SMP系统上停用高分辨率和动态滴答,这些系统在C3电源状态下停用本地APIC。虽然有一个解决方法的想法,但这个问题尚未解决。

定时器的时间有序插入提供了所有的基础设施,以决定在添加定时器时是否需要重新编程事件设备。这个决定是基于每个定时器基础,并在支持函数中跨每CPU定时器基础上同步。该设计允许系统利用单独的每CPU时钟事件设备来支持每CPU定时器基础,但目前每CPU只利用一个可重新编程的时钟事件设备。

当定时器中断发生时,下一个事件中断处理程序从时钟事件分发代码中调用,并将过期的定时器从红黑树移动到一个单独的双向链表,并调用软中断处理程序。hrtimer结构中的附加模式字段允许系统直接从下一个事件中断处理程序执行回调函数。这仅限于可以在硬中断上下文中安全执行的代码。例如,这适用于nanosleep使用的唤醒函数的常见情况。在中断上下文中执行处理程序的优点是避免了最多两次上下文切换 - 从中断上下文到软中断和被过期定时器唤醒的任务。

一旦系统切换到高分辨率模式,周期性滴答将被关闭。这将禁用每系统全局周期性时钟事件设备,例如i386 SMP系统上的PIT。

周期性滴答功能由每CPU的hrtimer提供。回调函数在下一个事件中断上下文中执行,并更新jiffies并调用update_process_times和profiling。基于hrtimer的周期性滴答的实现被设计为可以扩展为动态滴答功能。这允许在UP系统上使用单个时钟事件设备来调度高分辨率定时器和周期性事件(jiffies滴答、分析、进程账户)。这已被证明在i386上的PIT和PPC上的Incrementer上可以工作。

用于运行hrtimer队列和执行回调的软中断已从与滴答绑定的定时器软中断中分禅出来,以允许准确传递由itimer和POSIX间隔定时器使用的高分辨率定时器信号。这个软中断的执行仍然可能被其他软中断延迟,但这种分离显著改善了整体延迟。

图表#5(OLS幻灯片第22页)说明了这一转变。

动态滴答

动态滴答是基于hrtimer的周期性滴答替代(sched_tick)的逻辑结果。sched_tick hrtimer的功能通过三个函数进行了扩展:

  • hrtimer_stop_sched_tick
  • hrtimer_restart_sched_tick
  • hrtimer_update_jiffies

当CPU进入空闲状态时,会调用hrtimer_stop_sched_tick()。该代码评估下一个计划的定时器事件(来自hrtimers和定时器轮),如果下一个事件的时间比下一个滴答远,则将sched_tick重新编程到这个未来事件,以允许更长的空闲睡眠而不会被周期性滴答无意义地打断。当在空闲期间发生中断时,不会导致重新调度,但是需要调用该函数,因为中断处理程序可能已经启动了一个新的定时器,其到期时间早于在上一次调用hrtimer_stop_sched_tick中确定为最近事件的时间。

当CPU在调用schedule()之前离开空闲状态时,会调用hrtimer_restart_sched_tick()。hrtimer_restart_sched_tick()恢复周期性滴答,保持活动状态,直到下一次调用hrtimer_stop_sched_tick()。

当在空闲期间发生中断时,从irq_enter()调用hrtimer_update_jiffies(),以确保jiffies是最新的,并且中断处理程序不必处理可能过时的jiffy值。

动态滴答功能提供了通过/proc/stat向用户空间导出的统计值,并可以用于增强的电源管理控制。

该实现为进一步发展留下了空间,例如完全无滴答系统,其中时间片由调度程序控制,可变频率分析,以及将来完全删除jiffies。

除了当前对i386支持的初始提交外,该补丁集已扩展到x86_64和ARM。对MIPS和PowerPC也已经有了初始(正在进行中的工作)支持。

Thomas, Ingo