当前位置: 首页 > news >正文

【计算机基础】-26-RT-Thread-实际系统中,计算CPU使用率的原理与算法,代码示例

在 RT-Thread 实际系统中,CPU 使用率的计算默认不启用,需通过配置开启。其核心原理是:基于 idle 线程的运行时间占比反推 CPU 负载,但不是简单地在 idle 函数首尾记录 tick(这种 naive 方法会因抢占导致错误),而是采用“线程运行时间统计”机制,在线程切换时精确累加每个线程的实际运行时间。


一、启用条件(rtconfig.h

#define RT_USING_CPU_USAGE // 启用 CPU 使用率功能 #define RT_USING_THREAD_RUNTIME_STATISTICS // 启用线程运行时间统计(关键!)

⚠️ 注意:仅定义RT_USING_CPU_USAGE不够,必须配合RT_USING_THREAD_RUNTIME_STATISTICS才能获得准确结果。


二、核心原理

✅ 正确公式:

CPU 使用率 = (1 - idle_thread 运行时间 / 采样周期总时间) × 100%

  • idle_thread 运行时间:由调度器在线程切换时精确累加(单位:cycles 或 ticks);
  • 采样周期:通常为 1 秒;
  • 时间源:Cortex-M 使用DWT Cycle Counter(高精度),其他平台可用 SysTick。

三、关键数据结构(RT-Thread 源码)

每个线程控制块(TCB)增加运行时间字段:

// rtdef.h struct rt_thread { ... #ifdef RT_USING_THREAD_RUNTIME_STATISTICS rt_uint64_t runtime; // 累计运行时间(cycles) #endif };

四、实际代码实现(以 Cortex-M 为例)

1.初始化 DWT Cycle Counter(board.c

// 在 rt_hw_board_init() 中 void rt_hw_board_init(void) { /* 使能 DWT Cycle Counter */ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // ... 其他初始化 }

2.线程切换时累加运行时间(cpuport.c

RT-Thread 在PendSV 异常处理上下文切换汇编中调用以下函数:

// libcpu/arm/cortex-m/cpuport.c #include <rthw.h> #ifdef RT_USING_THREAD_RUNTIME_STATISTICS static rt_uint32_t last_cyc = 0; void rt_update_runtime(rt_ubase_t *sp) { rt_uint32_t cyc_now = DWT_CYCCNT; rt_thread_t thread = rt_current_thread; if (last_cyc == 0) { last_cyc = cyc_now; return; } if (thread) { /* 累加当前线程运行时间 */ thread->runtime += (cyc_now - last_cyc); } last_cyc = cyc_now; } #endif

🔔 注:实际调用位置在context_gcc.S的 PendSV_Handler 中:

#ifdef RT_USING_THREAD_RUNTIME_STATISTICS bl rt_update_runtime #endif

3.CPU 使用率计算(cpuusage.c

// src/cpuusage.c #include <rtthread.h> static rt_uint64_t last_total_time = 0; static rt_uint64_t last_idle_time = 0; static rt_uint8_t cpu_usage = 0; rt_uint8_t rt_cpu_get_usage(void) { return cpu_usage; } void rt_cpu_usage_calc(void) { rt_thread_t idle_thread; rt_uint64_t total_time, idle_time; rt_uint64_t delta_total, delta_idle; /* 获取 idle 线程(单核系统默认名为 "tidle0")*/ idle_thread = rt_thread_find("tidle0"); if (!idle_thread) return; /* 总时间 = DWT_CYCCNT(或所有线程 runtime 之和)*/ total_time = DWT_CYCCNT; idle_time = idle_thread->runtime; /* 计算差值 */ delta_total = total_time - last_total_time; delta_idle = idle_time - last_idle_time; if (delta_total > 0) { /* CPU 使用率 = (1 - idle/total) * 100 */ cpu_usage = (rt_uint8_t)(100 - (delta_idle * 100 / delta_total)); } last_total_time = total_time; last_idle_time = idle_time; }

4.定期触发计算(通过 idle hook)

// 应用代码 static rt_tick_t last_calc_tick = 0; void cpu_usage_hook(void) { /* 每秒计算一次 */ if (rt_tick_get() - last_calc_tick >= RT_TICK_PER_SECOND) { rt_cpu_usage_calc(); last_calc_tick = rt_tick_get(); } } int cpu_usage_init(void) { rt_thread_idle_sethook(cpu_usage_hook); return 0; } INIT_APP_EXPORT(cpu_usage_init);

五、用户使用示例

1.FinSH 命令

msh /> cpu_usage CPU usage: 12%

2.应用代码获取

#include <rtthread.h> void cpu_monitor_thread(void *param) { while (1) { rt_kprintf("CPU Usage: %d%%\n", rt_cpu_get_usage()); rt_thread_mdelay(1000); } } /* 创建监控线程 */ rt_thread_t tid = rt_thread_create("cpu_mon", cpu_monitor_thread, RT_NULL, 512, 10, 10); rt_thread_startup(tid);

六、为什么不会受抢占影响?

关键设计

  • 运行时间在线程切换时刻(PendSV)累加;
  • 每次只累加上一个线程从上次切换到本次切换的真实运行时间
  • idle 线程的runtime仅包含它真正占用 CPU 的时间
  • 中断或其他线程的运行时间会计入它们自己的runtime不会污染 idle 统计

📌 示例:

  • idle 运行 100 cycles → 被 UART 中断打断;
  • ISR 运行 50 cycles → 切换到线程 A 运行 200 cycles;
  • 最终:
    • idle.runtime += 100
    • threadA.runtime += 200
    • ISR 时间通常计入被中断的线程(或单独统计)
      idle 时间统计完全准确

七、注意事项

项目说明
硬件依赖DWT 仅支持 Cortex-M3/M4/M7/M33,Cortex-M0 需改用 SysTick(精度较低)
多核系统需分别统计每个核的 idle 线程(如 "tidle0", "tidle1")
idle 线程名单核默认为"tidle0",可通过list_thread查看
开销极小(每次切换仅 1 次减法 + 1 次加法)

✅ 总结

RT-Thread 实际系统中 CPU 使用率计算:

  1. 原理CPU Usage = 1 - (idle_thread 运行时间 / 总时间)
  2. 机制:在线程切换时,用DWT Cycle Counter精确累加每个线程的运行时间;
  3. 抗干扰:完全不受中断、抢占影响;
  4. 启用:需定义RT_USING_CPU_USAGE+RT_USING_THREAD_RUNTIME_STATISTICS
  5. 输出:通过rt_cpu_get_usage()或 FinSH 命令获取。

🔑核心思想
“通过调度器打时间戳,精确记录每个线程的真实运行时间,从而可靠计算 CPU 负载。”

http://www.jsqmd.com/news/374463/

相关文章:

  • 2026智能咖啡机哪家好?怎么选?质量优服务佳的智能咖啡机厂家 - 品牌2025
  • 2026年,银川学校装修找哪家?优先选津都华丽 本地20年工装经验 - 宁夏壹山网络
  • 告别低效繁琐!当红之选的降AIGC工具 —— 千笔·降AI率助手
  • 单北斗GNSS在变形监测中的应用与优势分析
  • 2026年2月抗皱紧致护肤品品牌推荐,配方、专利、肤感三维数据透视 - 品牌鉴赏师
  • 2026高奢酒店智能咖啡机推荐 高端商务接待高品质咖啡需求 - 品牌2025
  • 2026必备!AI论文工具 千笔 VS speedai,自考写作新选择!
  • 题4
  • 2026年咖啡连锁商用咖啡机推荐 全自动高效稳定机型合集 - 品牌2025
  • 深度相机原理(TOF、双目、结构光)
  • 交稿前一晚!研究生必备的降AI率神器 —— 千笔·专业降AI率智能体
  • 2026更新版!AI论文写作软件 千笔AI VS PaperRed,研究生写论文神器!
  • 真心不骗你!专科生专用降AI率工具,千笔 VS 知文AI
  • Jenkins 启动的命令
  • 10个新颖的springboot毕业设计题目(非烂大街版)
  • 探讨日本经营管理签证申请公司,广州上海哪家口碑好 - 工业设备
  • 永辉超市卡回收成功后,资金多久到账? - 京顺回收
  • 软考高项计算:她终于搞懂了当年中项计算题错在哪
  • 如何快速回收分期乐礼品卡?推荐高效平台,让闲置卡变现轻松! - 团团收购物卡回收
  • 2026年北京可靠的CE认证公司排名,郜盟认证助力企业轻松拿证 - 工业推荐榜
  • 济宁GEO优化服务公司选型攻略破解本地流量即时性困局 - 博客万
  • 2026年碳化铪供应商排名揭晓,这些品牌值得关注 - mypinpai
  • 2026必备!降AI率平台 千笔·专业降AIGC智能体 VS 文途AI,本科生专属首选
  • 2026年专利申请机构性价比排行,名扬高玥满足企业多维度专利需求 - 工业设备
  • 2026山西学区房现房推荐,让孩子赢在起跑线上,新房/婚房/学区房/70年大产权住宅/南都新城,学区房机构怎么选择 - 品牌推荐师
  • Java小白面试:探索Spring Boot与微服务场景的技术实践
  • 2026京津冀复古婚礼策划推荐,AND婚礼定制专属浪漫体验多少钱 - 工业品网
  • 用数据说话 8个AI论文写作软件测评:本科生毕业论文+科研写作必备工具推荐
  • 2026年京津唐可靠的婚礼策划服务商家前十名单出炉 - 工业品牌热点
  • 上海选购施工图深化设计企业要注意什么,哪家比较靠谱 - 工业品网