ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

RIOT ztimer 按需时钟基准测试:测量并校准 ztimer_acquire()/ztimer_release() 的开销

2026/9/20 1:46:26 拓冰建站 浏览量
RIOT ztimer 按需时钟基准测试:测量并校准 ztimer_acquire()/ztimer_release() 的开销 物联网嵌入式操作系统实时系统【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址https://gitcode.com/GitHub_Trending/riot/RIOT点击查看免费下载导读本指南围绕 RIOT 操作系统中的ztimer_ondemand_benchmark测试应用tests/sys/ztimer_ondemand_benchmark/README.md讲解如何精确测量按需ondemandztimer 时钟在ztimer_acquire()与ztimer_release()上引入的延迟并通过测试输出的校准值CONFIG_ZTIMER_USEC_ADJUST_CLOCK_START或clock-adjust_clock_start修正时钟唤醒带来的时间偏差。读完本文你将掌握该基准测试的构建与运行方法、独立对比计时器compare timer的选择与配置方式以及如何把测量结果落地为板级/时钟级校准参数从而在低功耗场景下获得更精确的定时精度。为什么需要测量 acquire/release 开销在默认配置下RIOT 的 ztimer 时钟一旦创建定时器就会持续驱动底层外设时钟在空闲时也不会关闭。而ztimer_ondemand系列模块改变了这一行为时钟只在有用户user时运行。当第一个定时器被设置、时钟被唤醒时底层硬件如 periph timer需要被启动当最后一个用户释放时钟时底层硬件被关闭以节省功耗。这个按需启停机制的代价是两处显式开销ztimer_acquire(clock)将时钟的users计数加一若这是第一个用户则调用底层clock-ops-start(clock)启动硬件。ztimer_release(clock)将users计数减一若不再有用户则先clock-ops-cancel(clock)解除武装再调用clock-ops-stop(clock)关闭硬件。其核心实现在 sys/ztimer/core.c。可以看到两个函数都在关中断irq_disable()状态下操作引用计数因此测量结果反映的不仅是外设启停耗时还包含中断屏蔽带来的延迟。更关键的是启动硬件需要时间——ztimer_set()在唤醒时钟时通过adjust_clock_start补偿这一延迟见 sys/ztimer/core.c。ztimer_ondemand_benchmark正是用来量化这些开销、并为adjust_clock_start提供实测依据的。测试原理为什么需要第二个 periph_timer该测试应用测量的是ztimer_acquire()/ztimer_release()引入的延迟。由于它直接操作底层外设来进行计时需要一个独立的、与待测 ztimer 时钟无关的高分辨率计时源来作为秒表。因此 README 明确指出如果你基准测试的是基于ztimer_periph_timer的 ztimer 时钟那么至少需要两个periph_timer实例。在 tests/sys/ztimer_ondemand_benchmark/main.c 中测试通过COMPARE_TIMER_DEV宏选择独立的比较计时器设备默认逻辑是若启用了MODULE_ZTIMER_PERIPH_TIMER则避开CONFIG_ZTIMER_USEC_DEV所占用那个定时器若 ztimer_usec 使用TIMER_DEV(0)则用TIMER_DEV(1)否则回退到TIMER_DEV(0)若未使用 periph timer 后端例如时钟基于 RTT/RTC则直接使用TIMER_DEV(0)。COMPARE_TIMER_FREQ默认取1000000U1 MHz即 1 个 tick 1 微秒。若自动选择失败或你想换用其他外设可以在 Makefile 中通过 CFLAGS 显式指定见下文配置与自定义。基准测试流程五步测量与自校准main()的测量逻辑在 main.c 中。整体流程如下初始化比较计时器timer_init(COMPARE_TIMER_DEV, COMPARE_TIMER_FREQ, NULL, NULL)。测量测量本身的开销bench_overhead()连续读两次timer_read()得到读取计时器的最小固有开销adjust后续所有测量都会用bench_start(adjust)把这部分抵消。依次测量五个指标每个指标都打印- name took N ticksztimer_acquire()on inactive clock —— 从关闭状态唤醒时钟的首次 acquire 耗时ztimer_acquire()on active clock —— 时钟已激活时的 acquire 耗时应远小于前者ztimer_release()with users left —— 仍有其他用户时的 release 耗时ztimer_release()with no users left —— 释放最后一个用户、关闭硬件时的 release 耗时。计算唤醒代价poweron_diff first_acquire - second_acquire即首次唤醒相对后续 acquire 多出的耗时正是时钟从停机到可用的上电延迟。输出校准建议见下节。校准输出把测量结果写回配置测试最后会根据被测时钟类型给出两种形式的校准建议main.c当被测时钟是ZTIMER_USEC且COMPARE_TIMER_FREQ 1000000U时建议在board.h中添加#define CONFIG_ZTIMER_USEC_ADJUST_CLOCK_START poweron_diff该配置项在 sys/ztimer/init.c 中被读取并在初始化时写入ZTIMER_USEC-adjust_clock_start。其他情况例如测的是ZTIMER_MSEC/ZTIMER_SEC或比较计时器频率不是 1 MHz则提示设置clock-adjust_clock_start poweron_diffadjust_clock_start在 sys/ztimer/core.c 中被使用ztimer_set()发现自己是第一个用户、需要唤醒时钟时会从请求的超时值val中扣掉adjust_clock_start从而补偿从调用 set到硬件真正开始计时之间的启动延迟若val小于该值则直接取 0。注意poweron_diff的单位是比较计时器的 tick。只有比较计时器频率为 1 MHz 时 tick 才等同于微秒这与ZTIMER_USEC的刻度一致若使用其他频率需要自行换算成被测时钟的刻度。README 同样提醒该测试应用与底层外设直接交互因此测量期间不应与其他会占用这些定时器的功能并发运行。构建与运行测试应用位于tests/sys/ztimer_ondemand_benchmark/其 MakefileMakefile声明了运行所需的模块与硬件特性USEMODULE ztimer USEMODULE ztimer_ondemand USEMODULE ztimer_ondemand_timer USEMODULE ztimer_ondemand_rtt USEMODULE ztimer_ondemand_rtc FEATURES_REQUIRED periph_timer可见该测试默认启用ztimer_ondemand及其基于 timer、RTT、RTC 的按需后端并要求目标板提供periph_timer特性作为独立比较计时器。ztimer_ondemand与各后端的依赖关系由 sys/ztimer/Makefile.dep 统一解析凡是启用ztimer_ondemand_*的模块都会自动引入ztimer_ondemand。运行方式与普通 RIOT 应用一致以 native 或具体板子为例make -C tests/sys/ztimer_ondemand_benchmark BOARDnative flash term选择被测时钟Makefile 中通过启用/注释USEMODULE选择被测的时钟# Select clock to benchmark: # - ztimer_usec USEMODULE ztimer_usec # - ztimer_msec #USEMODULE ztimer_msec # - ztimer_sec #USEMODULE ztimer_sec默认测试ztimer_usec。main.c中的时钟选择逻辑main.c按ZTIMER_SEC→ZTIMER_MSEC→ZTIMER_USEC的优先级选取CLOCK且仅在选中ZTIMER_USEC时定义CLOCK_IS_ZTIMER_USEC以决定输出校准宏的形式若三者都未启用则直接编译报错No ztimer clock selected!。此外Makefile 还内置了两个可取消注释的自定义项# You may sepcify the compare timer device #CFLAGS -DCOMPARE_TIMER_DEVTIMER_DEV(2) # You may sepcify the compare timer frequency #CFLAGS -DCOMPARE_TIMER_FREQ9750000当 README 提到的自动选择未用计时器失败时例如板子上可用的 timer 数量有限、或 ztimer_usec 占用的设备号与默认选择冲突即可通过这两个宏显式指定比较计时器设备与频率。COMPARE_TIMER_FREQ同时会出现在输出中程序会打印Compare timer frequency: NHz与Compare timer overhead: N ticks方便你确认测量刻度。输出解读示例一次典型运行基于ztimer_usec、1 MHz 比较计时器的输出大致如下Compare timer frequency: 1000000Hz Compare timer overhead: 2 ticks (will be taken into account) --- Benchmarking: - ztimer_acquire() on inactive clock took 18 ticks - ztimer_acquire() on active clock took 4 ticks - ztimer_release() with users left took 3 ticks - ztimer_release() with no users left took 11 ticks --- Add this to you board.h: #define CONFIG_ZTIMER_USEC_ADJUST_CLOCK_START 14解读要点on inactive clock与on active clock的差值就是时钟上电的额外代价也是建议写入的adjust_clock_start值上例为18 - 4 14ticks。release()两次的差值11 - 3 8体现了关闭底层硬件外设的代价如果应用频繁地在有/无定时器用户之间切换这个数字直接反映每轮启停的功耗与延迟开销。若希望把校准值写入配置可将输出的宏定义加入目标板的board.h或参照 sys/ztimer/init.c 的读取逻辑在 Kconfig 中配置CONFIG_ZTIMER_USEC_ADJUST_CLOCK_START。延伸阅读ztimer 按需启停与adjust_clock_start补偿的源码实现在 sys/ztimer/core.c初始化阶段如何应用校准值见 sys/ztimer/init.c基于periph_timer的 ondemand 后端实现见 sys/ztimer/periph_timer.c模块依赖声明见 sys/ztimer/Makefile.dep测试应用完整源码与构建配置见 tests/sys/ztimer_ondemand_benchmark/main.c 与 tests/sys/ztimer_ondemand_benchmark/Makefile。赞分享物联网嵌入式操作系统实时系统【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址https://gitcode.com/GitHub_Trending/riot/RIOT点击查看免费下载相关推荐RIOT OS Mutex Ping-Pong 基准测试用互斥锁握手测量上下文切换开销RIOT OS Mutex Ping Pong 基准测试用互斥锁握手测量上下文切换开销 导读 本文以 RIOT 仓库中 tests/bench/mutex_p物联网嵌入式操作系统实时系统RIOT ztimer 定时器基准测试全解析深入剖析 set / remove / now 操作的耗时与列表实现RIOT ztimer 定时器基准测试全解析深入剖析 set / remove / now 操作的耗时与列表实现 本文以 RIOT 操作系统仓库中的 ztim物联网嵌入式操作系统实时系统Jest 测试文件启动开销基准用 500 个空测试文件量化并对比 Jest 的 per-file 固定开销Jest 测试文件启动开销基准用 500 个空测试文件量化并对比 Jest 的 per file 固定开销 这篇指南基于 Jest 仓库自带的 benchma测试质量保障代码覆盖率开发工具上一篇lit/lit-starter-ts 版本演进全解析从 Lit 2 到 Lit 3 的 TypeScript 模板工程化实践下一篇Hugo Blog Awesome多语言支持构建国际化博客的完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考