Linux 内核 cpufreq-stats 深入解析:sysfs CPU 频率统计接口完全指南

发布时间:2026/9/15 16:22:54

Linux 内核 cpufreq-stats 深入解析:sysfs CPU 频率统计接口完全指南 Linux 内核 cpufreq-stats 深入解析sysfs CPU 频率统计接口完全指南【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux本文以 Linux 内核 CPUFreq 子系统中的cpufreq-stats驱动为核心系统讲解每个 CPU 的频率驻留时间、切换次数与切换矩阵这三类统计信息的获取方式、数据含义、内核配置方法与源码实现原理。读完本文你将能够在内核已启用CONFIG_CPU_FREQ_STAT的系统上熟练读取/sys/devices/system/cpu/cpuX/cpufreq/stats/下的全部统计接口并结合源码理解统计数据的记录时机与计算细节从而量化评估不同 cpufreq governor 的实际调频行为。1. cpufreq-stats 是什么独立于具体 cpufreq 驱动的通用统计层cpufreq-stats是一个为每个 CPU 提供频率统计信息的驱动其官方文档位于 Documentation/cpu-freq/cpufreq-stats.rst。它把所有统计结果以一批只读read-onlysysfs 接口的形式暴露给用户空间接口配置完成后会出现在每个 CPU 的 cpufreq 目录下的独立子目录中sysfs root/devices/system/cpu/cpuX/cpufreq/stats/该目录下各项统计均为只读文件。这一驱动在设计上不依赖任何特定的 cpufreq_driver因此无论你的 CPU 上运行的是acpi-cpufreq、intel_pstate、amd-pstate还是 ARM 平台的cpufreq-dt等驱动它都能正常工作——从源码结构看cpufreq-stats 只通过 cpufreq 核心提供的通用回调cpufreq_stats_record_transition()、cpufreq_stats_create_table()与核心层交互而非直接操作具体硬件这正是其通用性的来源。2. 统计接口的 sysfs 布局启用CONFIG_CPU_FREQ_STAT后在每个在线 CPU 上都会出现stats子目录。以 cpu0 为例ls -l输出如下与官方文档示例一致mysystem:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l total 0 drwxr-xr-x 2 root root 0 May 14 16:06 . drwxr-xr-x 3 root root 0 May 14 15:58 .. --w------- 1 root root 4096 May 14 16:06 reset -r--r--r-- 1 root root 4096 May 14 16:06 time_in_state -r--r--r-- 1 root root 4096 May 14 16:06 total_trans -r--r--r-- 1 root root 4096 May 14 16:06 trans_table其中reset是只写属性其余三个是只读属性。这一属性集合由源码中的属性组定义在 drivers/cpufreq/cpufreq_stats.c#L173-L183 中default_attrs[]依次挂载了total_trans、time_in_state、reset、trans_table四个属性属性组名称即为stats见同文件 L180-L183 的stats_attr_group因此该目录在 sysfs 中固定命名为stats。所有统计的时间范围是从 stats 驱动加载或统计被 reset 重置之时起到用户读取该统计项之时止。显然在 stats 驱动加载之前发生的频率切换驱动不可能有任何信息。3. 核心统计项详解与示例3.1 reset重置统计计数器reset是一个只写属性用于将统计计数器清零。这在无需重启系统的情况下评估不同 governor 下的系统行为时非常有用——你可以先切换到目标 governor然后重置统计再运行一段负载最后读取的统计即为该 governor 在纯净状态下的完整行为数据。从源码看重置是延迟执行的store_reset()drivers/cpufreq/cpufreq_stats.c#L102-L122只记录当前时钟local_clock()并置位reset_pending真正的清零动作cpufreq_stats_reset_table()drivers/cpufreq/cpufreq_stats.c#L39-L56会在下一次频率转换发生时由cpufreq_stats_record_transition()触发。这种设计是为了避免读写统计与重置操作之间的竞态条件同时重置时会用reset_time补偿自请求重置以来流逝的时间保证重置后time_in_state的起点准确。3.2 time_in_state各频率驻留时间time_in_state给出该 CPU 在它支持的每一个频率上分别停留了多长时间。cat输出为每行一个frequency time对含义是该 CPU 在frequency频率上停留了time个 usertime 单位。输出中每个受支持的频率各占一行。这里的 usertime 单位为10ms即 1/100 秒与/proc中导出的其他时间单位一致。这一点在源码中有直接对应show_time_in_state()drivers/cpufreq/cpufreq_stats.c#L69-L100在内核中以local_clock()纳秒精度累计时长最终通过nsec_to_clock_t()转换为 USER_HZ通常为 100Hz即每 tick 10ms的时钟单位后输出。示例输出mysystem:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat time_in_state 3600000 2089 3400000 136 3200000 34 3000000 67 2800000 172488从上述示例可以直观看出该 CPU 绝大部分时间172488 个 10ms 单位约合 1724.88 秒停留在 2800000 kHz2.8GHz偶尔进入 3.0~3.6GHz 的高频段。3.3 total_trans频率切换总次数total_trans给出该 CPU 上发生的频率切换总次数cat输出为一个单一计数。mysystem:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat total_trans 20该计数在源码中由struct cpufreq_stats的total_trans字段维护每次记录频率转换时自增见 drivers/cpufreq/cpufreq_stats.c#L265-L289。注意只有有效且频率确实发生改变的转换才会被计数源码中old_index -1 || new_index -1 || old_index new_index的情况会被直接忽略同文件 L280-L282即旧频率或新频率不在支持表中、或频率未变化时不计入。3.4 trans_table细粒度的频率切换矩阵trans_table提供关于所有 CPU 频率切换的细粒度信息cat输出是一个二维矩阵条目i,j第 i 行、第 j 列表示从Freq_i切换到Freq_j的次数。Freq_i行与Freq_j列遵循驱动最初提供给 cpufreq 核心的频率表的排序顺序因此该顺序可能是升序、降序也可能无序。输出同时附带每个行列对应的实际频率值便于阅读。示例输出mysystem:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table From : To : 3600000 3400000 3200000 3000000 2800000 3600000: 0 5 0 0 0 3400000: 4 0 2 0 0 3200000: 0 1 0 2 0 3000000: 0 0 1 0 3 2800000: 0 0 0 2 0以上述矩阵为例第 1 行第 2 列的5表示 CPU 从 3600000 kHz 切到 3400000 kHz 共 5 次对角线全为 0因为同一频率之间不存在转换。合计矩阵中所有非零项之和45212123 20恰好等于total_trans的输出值二者可相互印证。重要限制如果转换矩阵比PAGE_SIZE通常为 4KB还大读取该文件将返回-EFBIG错误。对应源码见 drivers/cpufreq/cpufreq_stats.c#L165-L168当输出长度达到PAGE_SIZE - 1时内核会打印一次告警cpufreq transition table exceeds PAGE_SIZE. Disabling并返回-EFBIG。这意味着支持频率档位极多的 CPU如某些服务器处理器有上百个频点可能无法通过该接口导出完整矩阵此时应以time_in_state与total_trans作为替代统计手段。4. 源码视角统计是如何被记录与维护的4.1 核心数据结构struct cpufreq_stats统计驱动的全部状态收敛在一个结构体中drivers/cpufreq/cpufreq_stats.c#L15-L28字段含义total_trans频率切换总次数last_time上一次更新统计的时间戳local_clock()max_state频率表容量含无效条目的最大槽位数state_num实际有效且唯一的频率状态数last_index当前所处频率在freq_table中的下标time_in_state各频率驻留时间累计数组freq_table有效唯一频率列表trans_table二维切换计数矩阵按max_state × max_state展开reset_pending/reset_time延迟重置标志与请求重置时刻该结构体通过policy-stats指针挂接在struct cpufreq_policy上所有 CPU 共享同一 policy 时会共享一份统计。内存分配采用一次kzalloc连续分配time_in_state、freq_table、trans_table三块区域的方式drivers/cpufreq/cpufreq_stats.c#L229-L240减少碎片并简化释放。4.2 统计记录的触发点统计并非由 stats 驱动自身轮询而是由 cpufreq 核心在频率切换的关键路径上主动回调。在 drivers/cpufreq/cpufreq.c 中有两处调用常规切换路径POSTCHANGE 通知后__cpufreq_notify_transition()在处理CPUFREQ_POSTCHANGE时调用cpufreq_stats_record_transition(policy, freqs-new)drivers/cpufreq/cpufreq.c#L333随后更新policy-cur快速切换路径fast_switchcpufreq_driver_fast_switch()在驱动完成快速频率切换、更新policy-cur后同样调用cpufreq_stats_record_transition(policy, freq)drivers/cpufreq/cpufreq.c#L2212。cpufreq_stats_record_transition()drivers/cpufreq/cpufreq_stats.c#L265-L289的执行流程为先处理挂起的重置请求 → 计算新旧频率下标 → 把自上次记录以来经过的时间累加到旧频率的time_in_state→ 更新last_index、递增trans_table[old][new]与total_trans。这也解释了为什么time_in_state的精确度可以达到纳秒级别底层使用local_clock()采样见cpufreq_stats_update()drivers/cpufreq/cpufreq_stats.c#L30-L37。4.3 统计表的创建与销毁创建cpufreq_stats_create_table()drivers/cpufreq/cpufreq_stats.c#L210-L263在 cpufreq 核心为 policy 初始化频率表后调用drivers/cpufreq/cpufreq.c#L1538。它遍历policy-freq_table提取有效且唯一的频点当freq_table_sorted ! CPUFREQ_TABLE_UNSORTED或频点尚未收录时才会加入freq_tabledrivers/cpufreq/cpufreq_stats.c#L244-L248这就是文档所述行列遵循驱动提供的频率表初始顺序的代码体现——无论驱动给出的表是有序还是无序矩阵行列都保持其原始次序。随后创建stats属性组并建立last_index到当前频率的映射销毁cpufreq_stats_free_table()drivers/cpufreq/cpufreq_stats.c#L194-L208在 policy 移除时drivers/cpufreq/cpufreq.c#L1223移除 sysfs 属性组并释放内存。5. 内核配置与编译在内核中配置 cpufreq-stats 的方式如下Config Main Menu Power management options (ACPI, APM) --- CPU Frequency scaling --- [*] CPU Frequency scaling [*] CPU frequency translation statistics两个关键配置项CPU Frequency scalingCONFIG_CPU_FREQcpufreq 子系统的主开关必须启用才能配置 cpufreq-stats。其在 Kconfig 中的定义见 drivers/cpufreq/Kconfig#L4-L18帮助文本明确指出它允许运行时改变 CPU 时钟频率以省电但本身不会自动调频需要配合 governor 或用户态工具CPU frequency translation statisticsCONFIG_CPU_FREQ_STAT提供time_in_state、total_trans、trans_table三项统计其 Kconfig 定义见 drivers/cpufreq/Kconfig#L30-L35。注意 Kconfig 中的正式名称是 CPU frequency transition statisticstransition而非文档菜单里写的 translation。对应构建规则位于 drivers/cpufreq/Makefile#L5-L6# CPUfreq stats obj-$(CONFIG_CPU_FREQ_STAT) cpufreq_stats.o即开启该配置后内核会编译drivers/cpufreq/cpufreq_stats.o并链接进内核该驱动以 built-in 方式编译无独立模块选项。启用后只要 CPU 支持 cpufreq即存在可用的 cpufreq 驱动并成功注册 policy就能在 sysfs 中看到前述统计接口。验证方法# 检查内核配置 zgrep CPU_FREQ_STAT /proc/config.gz 2/dev/null || grep CPU_FREQ_STAT /boot/config-$(uname -r) # 查看各 CPU 的统计目录是否存在 ls /sys/devices/system/cpu/cpu*/cpufreq/stats/6. 典型应用场景与实用技巧评估不同 governor 的行为差异reset接口专为此设计——切换 governor 后执行echo 1 /sys/devices/system/cpu/cpu0/cpufreq/stats/reset清空计数再运行目标负载随后通过time_in_state观察频率驻留分布、通过total_trans观察调频激进程度无需重启即可对比schedutil、ondemand、conservative等 governor 的实际效果定位调频抖动问题trans_table能揭示频繁乒乓切换的频点对矩阵中数值较大的非对角元素配合total_trans的总量即可判断系统是否存在过度调频单位换算time_in_state的第二列是 10ms 单位换算成秒需除以 100例如2800000 172488表示在 2.8GHz 上停留约 1724.88 秒注意读取限制当支持频率档位过多导致矩阵超过PAGE_SIZE时trans_table会返回-EFBIG此时请改用time_in_state与total_trans计数范围所有统计仅覆盖 stats 驱动加载或 reset之后的时间窗口重启或重新加载内核后计数从零开始。参考资料官方文档Documentation/cpu-freq/cpufreq-stats.rst、Documentation/cpu-freq/index.rst核心实现drivers/cpufreq/cpufreq_stats.c调用方drivers/cpufreq/cpufreq.c统计记录回调位于 L333 与 L2212配置定义drivers/cpufreq/Kconfig、构建规则drivers/cpufreq/Makefile【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/15 16:32:56

React+antd实战:环境监测网站实时数据与可视化开发

简介:基于 Reactantd 的环境监测网站课程设计项目,采用 B/S 架构,面向 Web 前端学习者与需要完成课程设计的同学。系统围绕环境数据采集与展示,支持数据上传、查看与分析,并划分数据分析、数据监控、用户工作台、财务管…

2026/9/15 16:32:56

Zvec性能基准工具指南:bench/recall/txt2vecs实战教程

Zvec性能基准工具指南:bench/recall/txt2vecs实战教程 【免费下载链接】zvec A lightweight, lightning-fast, in-process vector database 项目地址: https://gitcode.com/GitHub_Trending/zve/zvec Zvec 是一款轻量级、极速的进程内向量数据库,…

2026/9/15 16:32:56

IntelliJ IDEA 轻量化实战:Java/Spring Boot 开发提效指南

1. “轻量开源版 IDEA”不是新 IDE,而是社区对开发体验的集体反思最近刷到“轻量开源版 IDEA 来了!”这个标题,第一反应是点开——结果发现没有官方公告、没有 GitHub 主页跳转、没有 Release 下载链接。再一搜,满屏都是“Lithe-I…

2026/9/15 16:27:55

STM32H7R CAN FD寄存器级配置与6501kbps采样点校准

简介:本资源是一套专为STM32H7R系列微控制器设计的CAN FD通信驱动工程,面向嵌入式开发工程师、高校电子类专业学生及STM32进阶学习者,解决该新型高性能MCU在高速车载网络通信中的底层驱动适配与快速验证难题。压缩包共268个文件,含…

2026/9/15 4:54:30

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

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

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/15 14:22:53

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

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

2026/9/14 13:53:59

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

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

2026/9/15 11:42:23

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

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

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

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

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