RIOT 同优先级线程切换基准测试:thread_yield_pingpong 的原理、实现与运行

发布时间:2026/9/19 12:24:12

RIOT 同优先级线程切换基准测试:thread_yield_pingpong 的原理、实现与运行 RIOT 同优先级线程切换基准测试thread_yield_pingpong 的原理、实现与运行【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT导读本文围绕 RIOT 操作系统测试套件中的 thread_yield_pingpong 基准测试应用展开剖析其如何通过两个同优先级线程互相让出 CPUpingpong 式thread_yield()互抛来量化一次上下文切换的开销。读完本文你将理解该基准的计数口径为什么结果是一半的上下文切换次数、result与ticks两个输出指标的含义、底层调度器实现原理以及如何在一台真实板卡上编译、烧录、运行并验证结果。基准测试的设计思路同优先级双线程互抛在实时操作系统中上下文切换context switch开销是衡量内核调度效率的核心指标之一。RIOT 的thread_yield_pingpong采用了一种简洁而巧妙的测量方法其核心思想记录在 README.md 中This test measures the amount of context switches between two threads of the same priority. The result amounts to the number of thread_yield() calls inonethread (half the number of actual context switches).即测量两个同优先级线程之间的上下文切换数量其结果等于一个线程中thread_yield()的调用次数也就是实际上下文切换次数的一半。这一设计的关键在于同优先级两个线程优先级相同因此谁都不比谁高thread_yield()不会触发让位给更高优先级线程的抢占路径而是通过调度器把当前线程移到同优先级运行队列的队尾让出 CPU每次thread_yield()调用都会导致一次真实的线程切换两个线程轮流让位因此每个线程各自经历一半的切换主线程记录的调用次数恰好等于总切换次数的一半。README 还特别说明该测试应用有意与其他类似的 benchmark 应用重复部分代码以便在不同基准之间对比代码体积code size。这一点在 tests/bench 目录下可以得到印证——这里集中存放了 msg_pingpong、mutex_pingpong、thread_flags_pingpong 等结构高度相似的pingpong系列基准它们共享相同的计时、计数与输出骨架区别只在于驱动线程切换的同步原语thread_yield、互斥锁、消息队列、线程标志等。源码逐段解读main.c 的完整测量流程基准的完整实现位于 main.c全文仅约 80 行包含四个核心部分。1. 依赖与默认测量时长#include macros/units.h #include clk.h #include thread.h #include xtimer.h #ifndef TEST_DURATION #define TEST_DURATION (1000000U) #endif依赖 RIOT 的线程抽象thread.h、xtimer 定时器xtimer.h、时钟频率查询clk.h以及单位换算宏macros/units.hTEST_DURATION默认取1000000U单位为微秒即默认测量窗口为 1 秒。该宏允许通过编译期-DTEST_DURATION...覆盖用于延长或缩短采样窗口。2. 全局状态与第二线程volatile unsigned _flag 0; static char _stack[THREAD_STACKSIZE_MAIN]; static void *_second_thread(void *arg) { (void)arg; while (1) { thread_yield(); } return NULL; }_flag是测量窗口的结束标志由定时器回调置位被主线程循环轮询第二线程的栈直接复用THREAD_STACKSIZE_MAIN大小静态分配避免动态内存分配带来的不确定性第二线程进入死循环后只做一件事无限调用thread_yield()。主线程同样如此——两者在 1 秒内像打乒乓球一样互相让出 CPU这正是pingpong名字的由来。3. 主线程创建对线程、设定窗口、循环计数int main(void) { printf(main starting\n); thread_create(_stack, sizeof(_stack), THREAD_PRIORITY_MAIN, 0, _second_thread, NULL, second_thread); xtimer_t timer; timer.callback _timer_callback; uint32_t n 0; xtimer_set(timer, TEST_DURATION); while (!_flag) { thread_yield(); n; } ... }值得注意的两个细节第二线程的优先级显式使用THREAD_PRIORITY_MAIN与主线程完全一致——这是整个基准成立的前提。若第二线程优先级不同thread_yield()的调度行为就会改变例如高优先级线程会让低优先级线程饿死测量结果将失去纯上下文切换开销的意义thread_create的 flags 参数为 0即创建后不立即主动让出 CPU对比 mutex_pingpong 中使用的THREAD_CREATE_WOUT_YIELD。RIOT 默认在线程创建完成后调用thread_yield_higher()因此主线程会先运行并启动定时器随后在首次thread_yield()时切换到第二线程测量随之开始主线程在xtimer_set(timer, TEST_DURATION)之后进入循环每调用一次thread_yield()就对计数器n加一。1 秒后_timer_callback将_flag置 1循环退出测量结束。4. 结果输出result 与 ticksprintf({ \result\ : %PRIu32, n); printf(, \ticks\ : %PRIu32, (uint32_t)((TEST_DURATION/US_PER_MS) * (coreclk()/KHZ(1)))/n); puts( });输出是一行类 JSON 文本包含两个指标字段含义计算方式result测量窗口内主线程的thread_yield()调用次数直接计数nticks平均每次thread_yield()调用消耗的 CPU 周期数tick(TEST_DURATION/US_PER_MS) * (coreclk()/KHZ(1)) / n对ticks公式做单位拆解TEST_DURATION/US_PER_MS将微秒换算为毫秒默认 1 秒 → 1000 mscoreclk()/KHZ(1)将coreclk()返回的 CPU 主频Hz换算为 kHz 数值二者相乘得到测量窗口内理论上的总 tick 数再除以n即为每次thread_yield()调用平均消耗的 CPU 周期数。因此若想估算单次完整上下文切换的开销应将ticks乘以 2因为一次实际切换对应两次线程让位每次让位只算半个切换这与 README 中result 是实际切换次数的一半的说明自洽。测试运行与自动化验证构建与运行该基准是一个标准 RIOT 测试应用其 Makefile 极其精简include ../Makefile.bench_common USEMODULE xtimer include $(RIOTBASE)/Makefile.include其中 Makefile.bench_common 负责定位RIOTBASE并引入公共测试构建规则USEMODULE xtimer显式启用定时器模块msg_pingpong、mutex_pingpong等兄弟基准同样依赖它。在任意受支持板卡上例如使用 native 或某块 Cortex-M 板cd tests/bench/thread_yield_pingpong make BOARDnative -j make BOARDnative term程序启动后首先打印main starting约 1 秒后输出测量结果例如main starting { result : 1234567, ticks : 48 }具体数值取决于 CPU 主频与调度器实现。自动化回归tests/01-run.py与 RIOT 其余测试一致该基准配有 tests/01-run.py基于testrunner框架做自动回归def testfunc(child): child.expect(r{ \result\ : \d(, \ticks\ : \d)? })它只校验输出格式是否符合{ result : 数字(, ticks : 数字)? }的正则——注意ticks部分是可选的说明该字段在部分平台上可能被省略或打印为空自动化测试对两种输出形态都兼容。运行方式make BOARD... flash test板卡适用性限制Makefile.ci 声明了内存不足以运行本基准的板卡BOARD_INSUFFICIENT_MEMORY : \ atmega8 \ nucleo-l011k4 \ stm32f030f4-demo \ #这是因为本测试同时需要静态线程栈THREAD_STACKSIZE_MAIN、xtimer 模块以及 printf 输出对 RAM/Flash 较小的 AVR 或入门级 STM32 板卡而言空间紧张。CI 会据此跳过这些板卡。底层原理thread_yield() 在调度器中的实现要真正理解这个基准测的是什么需要下沉到内核。thread_yield()的实现位于 core/thread.cvoid thread_yield(void) { unsigned old_state irq_disable(); thread_t *me thread_get_active(); if (me-status STATUS_ON_RUNQUEUE) { sched_runq_advance(me-priority); } irq_restore(old_state); thread_yield_higher(); }其执行路径分三步关闭中断irq_disable()保证取出当前线程并操作运行队列这一临界区不被中断或抢占打断推进运行队列sched_runq_advance(me-priority)把当前线程从其优先级的就绪队列头部移到尾部即让出当前执行位置。me-status STATUS_ON_RUNQUEUE的检查确保线程确实在就绪队列上才做移动恢复中断并让位thread_yield_higher()触发实际调度选择运行队列头部的新线程执行完成一次上下文切换。从源码结构可以推断在本基准的两个同优先级线程场景下每次thread_yield()都会经历上述完整三步——关闭/恢复中断、就绪队列指针前移、真正切换到对方线程。因此ticks指标本质上反映的是在目标 CPU 上关中断 就绪队列操作 线程切换 开中断这一整条调度路径的开销而不只是寄存器保存/恢复的裸切换成本。与同族基准的横向对比切换原语决定测量对象thread_yield_pingpong属于 tests/bench 下的pingpong 族基准。对比同目录下的兄弟应用可以更清楚地看出它在基准体系中的定位基准驱动切换的同步原语测量对象thread_yield_pingpongthread_yield()纯协作式让位路径的切换开销msg_pingpongmsg_send()/msg_receive()消息传递机制下的切换开销mutex_pingpongmutex_lock()/mutex_unlock()互斥锁争用下的切换开销thread_flags_pingpong线程标志thread flags标志唤醒机制下的切换开销从代码上看四个应用共享几乎相同的骨架_flag结束标志 xtimer 定时窗口 uint32_t n计数 相同的result/ticks输出格式。以 mutex_pingpong 为例其区别仅在于第二线程循环mutex_lock(_mutex)主线程循环mutex_unlock(_mutex)并计数且线程创建时使用THREAD_CREATE_WOUT_YIELD以避免提前切换。这种有意重复代码正是 README 强调的设计取舍——保证各基准除被测原语外其余条件完全一致从而使代码体积与耗时指标的横向对比具有说服力。使用建议与注意事项优先用 native 或主流 Cortex-M 板卡快速验证BOARDnative无需硬件即可观察输出格式与逻辑需要真实时序数据时选择不在BOARD_INSUFFICIENT_MEMORY列表中的板卡例如nucleo-f401re、samr21-xpro或nrf52840dk调整测量窗口默认 1 秒在慢速 MCU 上可能产生较小计数、放大抖动可通过make CFLAGS-DTEST_DURATION5000000之类的方式延长窗口以平滑结果解读指标时注意口径result是单线程视角的让位次数实际上下文切换数为它的 2 倍ticks是每次让位平均消耗的 CPU 周期单次完整切换成本约为其 2 倍对比代码体积可借助make info-buildsize或size工具分别统计本基准与 mutex_pingpong、msg_pingpong 的镜像大小验证 README 所述重复代码以便对比 code size的设计意图——这也是本基准区别于一般功能测试、被归类到tests/bench的原因。小结thread_yield_pingpong是 RIOT 内核调度性能测量体系中最小巧、最直接的一个基准用两个同优先级线程互抛thread_yield()在固定时间窗口内统计让位次数并换算成每次让位平均消耗的 CPU 周期数。它验证了 RIOT 调度器在同优先级轮转 协作式让位这一核心路径上的真实开销其结果等于一半上下文切换次数的口径、result/ticks输出格式、xtimer 计时骨架以及有意的代码重复策略共同构成了 RIOT 基准测试家族的标准范式可直接作为评估新硬件平台或内核改动对调度性能影响的参考工具。【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/19 12:19:12

Python实现小波变换图像融合:从DWT分解到融合规则

简介:这份文档以基于小波变换的图像融合为研究对象,系统覆盖数字图像处理中多源信息融合的关键技术,适合图像处理、计算机视觉方向的初学者及研究人员用于课题入门或方法回顾。内容从图像融合的起源与像素级、特征级、决策级分类讲起&#xf…

2026/9/19 12:19:12

链游投资联盟与NFT资产化技术解析

我无法根据您提供的输入内容生成符合要求的博文。原因在于:输入中项目标题虽含“Galaxy、Republic、Alameda成立N投资联盟并公布三项链游投资|链游周报04期”,但项目正文为空,关键词未提供具体词汇(仅显示“最新网络热…

2026/9/19 13:29:15

大数据运维规划实战:从集群部署到监控容灾的完整指南

简介:这是一份关于大数据运维规划的解决方案文档,面向运维工程师、数据分析师及企业技术管理者,聚焦于业务系统与分析系统融合趋势下运维体系的设计与落地。文档从运维组织架构切入,对比了纵向一体化、完全分离及均衡三种交维模式…

2026/9/19 13:29:15

基于深度学习的火场灰度图像去烟算法:从数据合成到边缘部署

简介:这份PDF文献面向图像处理、计算机视觉方向的研究者与消防信息化技术人员,聚焦火场灰度监控画面因烟雾导致的清晰度与对比度下降问题,提出一套基于深度学习的去烟方案。资源包仅含1个PDF文件,大小约1.26MB,便于在移…

2026/9/19 13:29:15

中文知识图谱构建:从Word题库到结构化三元组

简介:本资源是专为QQ三国谋士大赛备赛设计的全领域题库文档,面向游戏知识竞赛参与者、历史与文化爱好者及通识能力提升者,旨在系统覆盖文史哲、数理化、艺术体育、生活常识等多维度考点,助力高效刷题与知识查漏补缺。文件为单个24…

2026/9/19 13:29:15

夸克网盘WebDAV私有同步服务搭建指南

我无法根据当前输入内容生成符合要求的博文。原因如下:项目标题“【无标题】资源爱好者的天堂,夸克资源社”缺乏明确的技术指向、功能定义或具体场景,属于模糊的社群/平台类泛称,未体现任何可拆解的核心技术点、实操路径或专业逻辑…

2026/9/19 13:29:15

Git零基础入门:从安装配置到分支合并与团队协作实战

Git 这东西,刚入行那会儿我也觉得它玄乎。不就是保存文件吗,我复制一份改个名不就行了?直到有一次改崩了一个功能,想退回昨天的版本,结果发现文件夹里躺着"最终版""最终版2""真最终版"&…

2026/9/18 14:13:01

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/19 0:03:10

验证 OpenSpec 兼容性,Cursor 的 Token 从 TaoToken 出

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 0:03:10

书桌角落的 Mac mini,OpenClaw 通过 TaoToken 跑任务。

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 0:03:10

oh-my-hermes:打造跨工具的命令编排与插件化工作流

1. 项目概述与设计初衷1.1 它到底是什么先说结论:oh-my-hermes 是一个面向开发者日常终端操作的效率工具套件,核心定位是“把分散在各类命令行工具里的高频操作,统一收拢成一套插件化、可编排的工作流”。项目灵感来源很明显——oh-my-zsh 重…

2026/9/18 14:13:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/18 14:13:02

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/18 14:13:02

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码