Clock sources, Clock events, sched_clock() and delay timers【ChatGPT】

简介: Clock sources, Clock events, sched_clock() and delay timers【ChatGPT】

内核时间管理基础知识

本文将简要解释一些基本的内核时间管理抽象概念。它部分涉及内核树中通常在drivers/clocksource中找到的驱动程序,但代码可能分布在整个内核中。

如果你在内核源代码中使用grep命令,你会发现一些特定于体系结构的时钟源、时钟事件的实现,以及一些类似的体系结构特定的sched_clock()函数覆盖和一些延迟定时器。

为了为你的平台提供时间管理,时钟源提供了基本的时间线,而时钟事件在这个时间线上的某些点上触发中断,提供诸如高分辨率定时器之类的功能。sched_clock()用于调度和时间戳,延迟定时器使用硬件计数器提供准确的延迟源。

时钟源

时钟源的目的是为系统提供一个时间线,告诉你当前时间。例如,在Linux系统上发出date命令最终会读取时钟源来确定确切的时间。

通常,时钟源是一个单调的原子计数器,它提供从0到(2^n)-1的n位计数,并在达到最大值后重新从0开始计数。只要系统运行,它理想情况下永远不会停止计数。在系统暂停期间它可能会停止计数。

时钟源的分辨率应尽可能高,频率应尽可能稳定和正确,与真实世界的挂钟相比。它不应该在时间上不可预测地来回移动,也不应该偶尔丢失几个周期。

它必须免疫硬件中发生的影响,例如在总线上以两个阶段读取计数器寄存器,首先读取最低的16位,然后在第二个总线周期中读取更高的16位,计数器位在两次读取之间可能被更新,导致计数器产生非常奇怪的值。

当时钟源的挂钟精度不令人满意时,有各种技巧和时间管理代码层用于例如将用户可见时间与系统中的RTC时钟或使用NTP的网络时间服务器进行同步,但它们基本上只是更新针对时钟源的偏移量,这为系统提供了基本的时间线。这些措施不会影响时钟源本身,它们只是使系统适应了时钟源的缺陷。

时钟源结构应提供一种将提供的计数器转换为纳秒值的方法,作为无符号长长整型(unsigned 64位)数字。由于这个操作可能经常被调用,严格的数学计算并不理想:相反,使用乘法和移位等算术运算将数字尽可能接近纳秒值,因此在clocksource_cyc2ns()中你会找到:

ns ~= (clocksource * mult) >> shift

你会在时钟源代码中找到一些辅助函数,旨在帮助提供这些multshift值,例如clocksource_khz2mult()clocksource_hz2mult(),它们有助于从固定的移位确定mult因子,以及clocksource_register_hz()clocksource_register_khz(),它们将使用时钟源的频率作为唯一输入来帮助分配shiftmult因子。

对于从单个I/O内存位置访问的真正简单的时钟源,现在甚至有clocksource_mmio_init(),它将获取一个内存位置、位宽、一个参数,告诉寄存器中的计数器是递增还是递减,以及定时器时钟速率,然后产生所有必要的参数。

由于比如一个100 MHz的32位计数器在大约43秒后会重新从0开始计数,处理时钟源的代码将不得不对此进行补偿。这就是为什么时钟源结构还包含一个'mask'成员,告诉源的多少位是有效的。这样,时间管理代码就知道计数器何时会重新开始计数,并且可以在重新开始计数点的两侧插入必要的补偿代码,以使系统时间线保持单调。

时钟事件

时钟事件在概念上与时钟源相反:它们接受所需的时间规范值,并计算要插入硬件定时器寄存器的值。

时钟事件与时钟源是正交的。相同的硬件和寄存器范围可以用于时钟事件,但它本质上是一个不同的东西。驱动时钟事件的硬件必须能够触发中断,以便在系统时间线上触发事件。在SMP系统上,最理想的(也是习惯的)是每个CPU核心都有一个这样的事件驱动定时器,以便每个核心可以独立于任何其他核心触发事件。

你会注意到时钟事件设备代码基于相同的基本思想,使用multshift算术来将计数器转换为纳秒,你会再次找到相同系列的辅助函数,用于分配这些值。然而,时钟事件驱动程序不需要'mask'属性:系统不会尝试计划超出时钟事件时间范围的事件。

sched_clock()

除了时钟源和时钟事件之外,内核中还有一个特殊的弱函数,名为sched_clock()。这个函数应返回自系统启动以来的纳秒数。一个体系结构可能会提供自己的sched_clock()实现,也可能不提供。如果没有提供本地实现,系统节拍计数器将被用作sched_clock()

顾名思义,sched_clock()用于调度系统,例如在CFS调度器中确定某个进程的绝对时间片。它还用于printk时间戳,当你选择在printk中包含时间信息时,例如用于启动图表。

与时钟源相比,sched_clock()必须非常快:它被调用的频率更高,特别是由调度器调用。如果你必须在精度和时钟源之间进行权衡,你可以在sched_clock()中牺牲精度以换取速度。但它需要一些与时钟源相同的基本特征,即它应该是单调的。

sched_clock()函数只能在无符号长长整型边界上进行包装,即在64位之后。由于这是一个纳秒值,这意味着它在大约585年后会重新开始计数。(对于大多数实际系统来说,这意味着"永远"。)

如果一个体系结构没有提供自己的此函数的实现,它将回退到使用节拍数,使其最大分辨率为体系结构的节拍频率的1/HZ。这将影响调度的准确性,并可能会在系统基准测试中显示出来。

驱动sched_clock()的时钟在系统暂停/休眠期间可能会停止或重置为零。这对它服务的系统上的调度事件并不重要。但它可能会导致printk()中的有趣时间戳。

sched_clock()函数应该可以在任何上下文中调用,包括中断和NMI安全,并在任何上下文中返回合理的值。

一些体系结构可能具有有限的时间源集,并且缺少一个好的计数器来推导64位纳秒值,因此例如在ARM体系结构上,已经创建了特殊的辅助函数,用于从16位或32位计数器提供sched_clock()纳秒基数。有时也会使用与时钟源相同的计数器来实现此目的。

在SMP系统上,对性能来说,sched_clock()可以在每个CPU上独立调用而不会有任何同步性能损失是至关重要的。一些硬件(例如x86 TSC)会导致sched_clock()函数在系统上的不同CPU之间漂移。内核可以通过启用CONFIG_HAVE_UNSTABLE_SCHED_CLOCK选项来解决这个问题。这是使sched_clock()与普通时钟源不同的另一个方面。

延迟定时器(仅适用于某些体系结构)

在具有可变CPU频率的系统上,各种内核延迟函数有时会表现出奇怪的行为。基本上,这些延迟通常使用硬循环来延迟一定数量的节拍分数,使用在启动时校准的“lpj”(每节拍循环次数)值。

希望在校准此值时你的系统正在以最大频率运行:当频率降低到全频率的一半时,任何延迟()将是原来的两倍长。通常这不会有影响,因为你通常请求的延迟量或更多。但基本上在这些系统上,语义是相当不可预测的。

进入基于定时器的延迟。使用这些,可以使用定时器读取来提供所需的延迟,而不是使用硬编码的循环。

这是通过声明一个struct delay_timer并为这个延迟定时器分配适当的函数指针和速率设置来实现的。

这在一些体系结构上可用,如OpenRISC或ARM。

相关文章
|
网络协议 Unix Linux
有了协程库,开发DPDK应用程序第一次可以这么简单
使用PhotonLibOS协程库,以多执行单元并发的代码模型代替原先的异步回调模型,简化DPDK应用程序的开发。同时使用echo server验证了 用户态TCP/IP协议栈+轮询模式驱动 对比 内核原生协议栈+中断模式驱动 的性能优势
10359 0
有了协程库,开发DPDK应用程序第一次可以这么简单
|
缓存 算法 Linux
深入理解Linux内核调度器:公平性与性能的平衡####
真知灼见 本文将带你深入了解Linux操作系统的核心组件之一——完全公平调度器(CFS),通过剖析其设计原理、工作机制以及在实际系统中的应用效果,揭示它是如何在众多进程间实现资源分配的公平性与高效性的。不同于传统的摘要概述,本文旨在通过直观且富有洞察力的视角,让读者仿佛亲身体验到CFS在复杂系统环境中游刃有余地进行任务调度的过程。 ####
244 6
|
缓存 监控 网络协议
掌控全局:Linux 系统性能调优技巧全面指南
掌控全局:Linux 系统性能调优技巧全面指南
|
网络协议 调度 数据安全/隐私保护
软件体系结构 - 微内核
【4月更文挑战第19天】软件体系结构 - 微内核
367 0
|
存储 运维 API
源码解密协程队列和线程队列的实现原理(一)
源码解密协程队列和线程队列的实现原理(一)
263 1
|
NoSQL
编译和安装 libvirt 8.10.0
编译和安装 libvirt 8.10.0
882 0
|
消息中间件 Oracle 关系型数据库
实时计算 Flink版操作报错合集之一直无法正常运行,并且网络状况良好,是什么原因导致的
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
247 8
|
消息中间件 测试技术 Linux
linux实时操作系统xenomai x86平台基准测试(benchmark)
本文是关于Xenomai实时操作系统的基准测试,旨在评估其在低端x86平台上的性能。测试模仿了VxWorks的方法,关注CPU结构、指令集等因素对系统服务耗时的影响。测试项目包括信号量、互斥量、消息队列、任务切换等,通过比较操作前后的时戳来测量耗时,并排除中断和上下文切换的干扰。测试结果显示了各项操作的最小、平均和最大耗时,为程序优化提供参考。注意,所有数据基于特定硬件环境,测试用例使用Alchemy API编写。
1330 0
linux实时操作系统xenomai x86平台基准测试(benchmark)
|
SQL 消息中间件 Java
Flink部署问题之带上savepoint部署任务报错如何解决
Apache Flink是由Apache软件基金会开发的开源流处理框架,其核心是用Java和Scala编写的分布式流数据流引擎。本合集提供有关Apache Flink相关技术、使用技巧和最佳实践的资源。