7.2 运行时状态统计与 CPU 负荷画像


7.2 运行时状态统计与 CPU 负荷画像

本节摘要:运行时统计在每次上下文切换处记账,把处理器时间归因到每个任务头上,一张表看清谁在吃 CPU、栈还剩多少、状态是否健康。本节讲清统计的记账原理与精度要求、面板的搭建方法(文本快照与程序化接口两条路)、CPU 负荷的正确读法(空闲占比法及其两个陷阱),最后用一个真实案例演示"从统计表读出病灶"的推理过程。

工程师对系统最常问的三个问题:它现在怎么样?谁最忙?还剩多少余量?没有仪表时,答案靠猜;有了运行时统计,答案是一张表。第 2 章埋的栈水位、第 5 章的堆画像,本章统一组装成面板。

一、统计的原理:在切换点记账

内核做上下文切换时(3.1 节那场栈间接力),顺手做一件会计工作:读一次高精度计数器,减去上次读数,把差值记到"被换出任务"的账上。任务运行时间的归因就这样天然完成——不需要插桩业务代码,开销只是每次切换多读一个计数器。累加的账本存在任务控制块里,查询接口把它格式化成"任务名、状态、优先级、运行占比、栈水位"五行表。

启用要做三件事。第一,打开统计功能开关(它依赖跟踪设施,两个宏一起开)。第二,提供一个高精度计数器:配置里声明"初始化计数器"与"读取计数值"两个映射——典型选型是芯片自带的周期计数调试单元(零成本、主频级精度)或一个专用定时器。第三,计数器频率要有讲究:至少比滴答频率高一个数量级,官方建议高十倍上下——否则短任务的记账全是舍入噪声。若计数器会回绕,读取映射里要做扩展处理。

/* 统计面板:两条输出路径 */ void stats_dump(void) { char buf[512]; vTaskList(buf); /* 路径一:人读的快照表 */ uart_write(buf, strlen(buf)); vTaskGetRunTimeStats(buf); /* 路径二:CPU 归因表 */ uart_write(buf, strlen(buf)); /* 路径三:程序化读取(板端解析或上报云端) */ TaskStatus_t tasks[16]; UBaseType_t n = uxTaskGetSystemState(tasks, 16, NULL); for (UBaseType_t i = 0; i < n; i++) { report_task(&tasks[i]); /* 逐字段上报 结构化消费 */ } }

两条输出路径的分工:文本快照给调试串口直接看,开发期效率最高;程序化接口给量产设备做远程诊断(统计字段上报云端,运维侧画趋势)。重要提醒:拍快照本身要冻结调度器,全系统统计口径才一致——在低优先级诊断任务里调用即可(它跑的时机系统本来就不忙),别在硬实时任务里调。

一张真实的统计表与负荷堆积图

一张真实的统计表与负荷堆积图

二、CPU 负荷的正确读法:空闲占比与两个陷阱

最常用的负荷定义是"一百减空闲占比"——空闲任务占了六成二,系统负荷就是三成八。这个读法简单,但有两个陷阱必须知道。

**陷阱一:空闲时间里有隐形工作。**空闲钩子(喂狗、休眠指令、后台自检)的时间全记在空闲任务账上——你以为的"空闲六成二"里可能藏着自检的一成。修正办法:把重活搬出空闲钩子(6.1 节的定时器或独立低优先级任务),空闲账本回归纯粹。**陷阱二:中断时间不在任何任务账上。**记账发生在切换点,中断里消耗的时间被摊进了"被打断任务的账"或"空闲前的账"——统计表的口径是任务口径,不是全系统口径。要量中断的总开销,用 6.4 节的探针法:一个周期中断做哨兵,量它被推迟的总量,即为系统里"关中断加中断处理"的总和。两个陷阱修正后,"空闲占比"才是可信的余量指标。

负荷画像的健康标准因产品而异,但两条底线通用:稳态余量不低于三成(留足峰值场景的波动空间);分布要能解释——每个大户的占比都要说得出来源(采样率乘单次耗时对得上账),说不清的大户就是下一个排查对象。

三、案例:一张统计表读出的三个病灶

背景。某控制器联调后期做整机评估,统计表如上图(数值微调)。操作与推理。第一步看空闲:六成二,余量健康,系统不会因算力不足出事。第二步看大户:采样任务一成八,与"两毫秒周期乘单次耗时"的推算吻合,正常;网络任务一成四九——按业务节奏推算它该在半成以下,说不清的大户锁定。第三步看栈水位:网络任务只剩二十余字(单位是字),贴着红线——2.4 节的溢出前兆。深挖结果。网络任务里有一段"无等待的循环重试"(收不到完整帧就原地再收,空转烧掉一成);栈水位低是因为它的解析函数里有大局部缓冲(2.4 节同款病因)。修复:重试改为"退出等通知再来"(事件驱动化,4.3 节的手段),大缓冲移出栈。复测:网络任务降到半成,水位回到健康线。解读:这张表一次暴露了三个层面的信息——余量层(空闲够不够)、归因层(大户能不能解释)、资源层(水位有没有红线)。读表的三问固定化,就是团队的日常体检流程。变式:守护任务占比异常偏高时,病灶方向完全不同——按 6.1 节的回调纪律查(某回调干了重活);统计任务自己的占比高企则是另一个方向(拍快照太频繁或表太大)。

⚠️ 统计功能的两个配置坑:计数器频率不足(任务占比全是噪声,短任务齐刷刷显示零);忘记开跟踪设施宏(统计功能静默失效或编译报缺失字段)。前者最阴险——数字看起来"合理",其实毫无意义。启用后先用一个已知负载(如每秒翻转一千次引脚的任务)验证计数准确性,再信数字。

四、从面板到趋势:量产设备的观测

开发期的面板靠调试串口,量产设备的观测要走另一条路:程序化接口加定期上报。设计要点三个:节流——诊断字段按小时级上报,异常时刻(分配失败、水位触线)即时上报,别让观测本身成为负荷;结构化——上报的是字段不是文本,云端可画趋势(水位随版本变化、负荷随温度变化);带版本——每条记录带固件版本号,跨版本的对比是发现"优化回归"的唯一手段。观测体系至此完成从"调试器里看一眼"到"数据资产"的升级,第 8 章的性能优化将直接消费这些趋势数据。

本节要点回顾

  • 记账发生在切换点:高精度计数器读差值归因到被换出任务,业务代码零插桩;
  • 计数器频率至少十倍于滴答,且启用后要用已知负载验证,否则数字是无意义的噪声;
  • 读表三问:空闲够吗、大户能解释吗、水位有红的吗——三问即日常体检流程;
  • 空闲占比的两个陷阱:钩子里的隐形工作、中断时间不在任务口径——修正后再谈余量;
  • 快照要冻结调度且在低优先级任务里拍,量产观测走程序化接口加节流上报加版本标识;
  • 统计是汇总口径,要看每次切换的细节得用下一节的追踪录制。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U