一、简介1.1 技术背景与行业现状CPU 调频DVFS动态电压频率调节是现代 Linux 系统功耗与性能平衡的核心技术广泛应用于服务器、嵌入式终端、工控设备、车载系统、移动终端等场景。传统ondemand、performance调频策略逻辑简单、响应滞后而schedutil作为 Linux 内核主推的调度器联动调频策略直接依托调度器 PELT 负载统计数据进行频率决策具备响应快、精度高、负载感知强三大优势目前已成为绝大多数 Linux 发行版、嵌入式平台的默认调频调节器。在高并发、高频任务切换的场景下调度器会在任务唤醒、迁移、时间片轮转等时机频繁触发调频计算。如果每次都完整执行负载换算、频率公式运算、OPP 表匹配会产生大量冗余计算挤占 CPU 算力尤其在单核嵌入式、低功耗 MCU 设备上冗余计算会直接拉高系统开销、增加功耗。为解决该问题Linux 内核在 schedutil 架构中引入了cached_raw_freq字段核心作用是缓存上一次计算得到的原始目标频率当负载未发生实质性变化时直接复用缓存结果跳过完整计算流程大幅降低调频路径的 CPU 开销。1.2 学习本章节的价值内核原理层面理解调度器与 CPU 调频子系统的联动逻辑掌握 schedutil 核心执行链路工程调优层面看懂频率缓存机制的设计思想能够针对高负载、高 IO 场景优化调频策略排错能力层面定位调频卡顿、功耗异常、频率频繁跳动等线上问题学术 / 报告层面内核源码、性能数据、测试案例完整可作为 Linux 调度、功耗管理方向论文、技术报告的核心素材。1.3 核心场景概述本机制主要服务两大类场景一是高并发服务器海量短生命周期任务频繁唤醒调度器高频触发调频二是嵌入式实时设备RT 实时任务、IO 密集型任务交替运行要求调频低延迟、低开销。cached_raw_freq 缓存机制正是为这类高频触发、负载小幅波动的场景量身设计。二、核心概念与术语解析为保证零基础读者也能顺畅阅读本节梳理所有关联术语、数据结构与执行逻辑。2.1 schedutil 基础概念schedutilLinux 内核基于调度器负载的 CPUFreq 调频调节器全称Scheduler Utilization Governor。不再依赖传统定时器轮询采样负载而是由调度器事件驱动任务唤醒、任务就绪、任务迁移实时获取 PELT 计算的 CPU 利用率动态计算目标运行频率。DVFS动态电压频率调节硬件 内核协同的功耗管理技术CPU 负载低时降低主频与电压以省电负载高时提升主频以保证性能是嵌入式、服务器、移动端必备技术。PELTPer-Entity Load TrackingLinux 调度器核心负载统计模块采用 EWMA 指数加权移动平均算法统计每个任务、每个运行队列rq的 CPU 利用率输出频率无关的负载值是 schedutil 计算频率的数据源。2.2 cached_raw_freq 核心定义2.2.1 结构体出处cached_raw_freq是struct sugov_policy结构体中的成员变量该结构体是 schedutil 每个 CPU 调频域的策略管理体定义于内核源码kernel/sched/cpufreq_schedutil.cstruct sugov_policy { struct cpufreq_policy *policy; struct sugov_tunables *tunables; struct list_head tunables_hook; raw_spinlock_t update_lock; u64 last_freq_update_time; s64 freq_update_delay_ns; unsigned int next_freq; // 核心原始计算频率缓存字段 unsigned int cached_raw_freq; /* 后续为延迟工作、中断工作相关成员 */ struct irq_work irq_work; struct kthread_work work; struct mutex work_lock; struct kthread_worker worker; struct task_struct *thread; bool work_in_progress; bool limits_changed; bool need_freq_update; };2.2.2 字段语义拆解cached_raw_freq上一次通过公式计算得出的原始频率值未经过硬件 OPP 表匹配、上下限约束next_freq最终生效的目标频率经过硬件校验、频率档位匹配后的结果二者区别cached_raw_freq是计算中间值缓存next_freq是最终执行值。2.3 缓存生效逻辑简述schedutil 计算目标频率的标准流程获取PELT负载 → 代入频率公式计算raw_freq → 匹配硬件OPP档位 → 得到next_freq → 硬件调频引入缓存后流程优化获取PELT负载 → 计算raw_freq → 对比 cached_raw_freq相等直接复用next_freq跳过后续计算与匹配不相等更新cached_raw_freq执行完整计算链路。该设计本质是空间换时间用一个 4 字节整型变量的内存开销规避重复的浮点运算、档位匹配、硬件查询等高开销操作。三、环境准备3.1 软硬件环境清单环境类型版本 / 配置用途说明操作系统Ubuntu 20.04 / CentOS 7.9 / Debian 11通用测试主机推荐 x86_64 架构Linux 内核5.4 / 5.10 / 5.15LTS 长期支持版cached_raw_freq 在 4.15 内核稳定存在优先 LTS 版本编译工具gcc、g、make、libncurses-dev、bison、flex内核编译、模块编译调试工具perf、trace-cmd、ftrace、gdb kgdb跟踪 schedutil 执行流、查看变量值源码资源Linux 官方内核源码阅读、修改、编译内核硬件要求x86_64 双核及以上 CPU支持 DVFS必须支持 CPU 调频功能虚拟机需开启 CPU 调频模拟注意纯虚拟机部分厂商会屏蔽 DVFS建议使用物理机或开启「CPU 性能模式模拟」的 KVM 虚拟机。3.2 环境部署步骤完整可复现3.2.1 依赖包安装Ubuntu 系列执行以下命令安装编译、调试全套依赖命令可直接复制运行# 更新软件源 sudo apt update sudo apt upgrade -y # 内核编译基础依赖 sudo apt install -y gcc make libncurses-dev bison flex libssl-dev libelf-dev # 调试、追踪工具 sudo apt install -y perf trace-cmd ftrace gdb3.2.2 下载并解压内核源码# 下载 Linux 5.10 LTS 内核国内镜像速度更快 wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.200.tar.xz # 解压源码 tar -xf linux-5.10.200.tar.xz cd linux-5.10.2003.2.3 确认 schedutil 配置开启schedutil 由内核配置项控制需确保配置开启打开内核配置界面make menuconfig依次进入配置路径Power management and ACPI options - CPU Frequency scaling - CPU Frequency scaling governors确保以下选项勾选*内置内核M模块[*] Schedutil cpufreq governor保存配置并退出。3.2.4 验证系统当前调频调节器在物理机 / 虚拟机中执行以下命令确认当前使用 schedutil# 查看当前CPU调频策略所有核心 cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor正常输出示例全部为 schedutilschedutil schedutil schedutil schedutil若输出为performance/ondemand执行命令切换# 批量将所有CPU核心切换为schedutil for cpu in /sys/devices/system/cpu/cpu[0-9]*; do echo schedutil $cpu/cpufreq/scaling_governor done四、应用场景详解300 字cached_raw_freq 频率缓存机制主要落地于三类工业场景。第一类是高并发 Web / 数据库服务器海量短连接请求造成任务频繁唤醒、调度器持续触发调频缓存可削减重复计算开销降低系统软中断占比。第二类是工业嵌入式实时系统工控机、PLC 设备中实时任务与普通 IO 任务交替执行要求调频低延迟、低抖动缓存机制避免频率反复计算导致的实时性下降。第三类是边缘计算低功耗设备ARM 架构边缘盒算力有限频繁调频计算会增加功耗缓存大幅精简执行链路兼顾性能与续航。在以上负载波动平缓、调频触发频繁的场景中cached_raw_freq 的优化收益最为显著。五、实际案例与代码实操核心章节含源码 注释 命令本节分为源码逐行解析、手动触发调频观测缓存、ftrace 跟踪缓存变化、编写测试程序压测四大实操环节所有代码、命令均可直接复制使用。5.1 核心源码解析cached_raw_freq 工作流程文件路径linux-5.10.200/kernel/sched/cpufreq_schedutil.c核心函数get_next_freq()这是 cached_raw_freq 缓存判断、更新的唯一入口也是整个机制的核心。5.1.1 get_next_freq 函数完整源码 逐行注释/** * get_next_freq - 计算CPU下一跳目标频率并使用cached_raw_freq做缓存优化 * sg_policy: schedutil策略结构体包含cached_raw_freq、next_freq等核心字段 * util: PELT模块输出的CPU利用率负载值 * max: CPU最大容量值 * * 返回值经过硬件匹配后的最终目标频率 */ static unsigned int get_next_freq(struct sugov_policy *sg_policy, unsigned long util, unsigned long max) { struct cpufreq_policy *policy sg_policy-policy; unsigned int freq; // 步骤1根据架构是否支持频率不变性选择计算基准频率 freq arch_scale_freq_invariant() ? policy-cpuinfo.max_freq : policy-cur; // 步骤2负载值性能映射 频率换算得到原始计算频率 raw_freq util map_util_perf(util); freq map_util_freq(util, freq, max); // 缓存核心逻辑 // 判断1新计算的raw_freq 与 缓存的cached_raw_freq 相等 // 判断2无强制更新标志 need_freq_update if (freq sg_policy-cached_raw_freq !sg_policy-need_freq_update) { // 缓存命中直接返回上一次生效的next_freq跳过后续所有计算 return sg_policy-next_freq; } // 缓存未命中更新缓存字段为当前新计算的raw_freq sg_policy-cached_raw_freq freq; // 步骤3原始频率匹配硬件支持的OPP档位输出最终频率 return cpufreq_driver_resolve_freq(policy, freq); }5.1.2 逻辑流程总结调度器触发调频调用get_next_freq根据 CPU 负载计算出原始频率 freq对比freq和sg_policy-cached_raw_freq命中直接返回历史next_freq链路终止未命中刷新cached_raw_freq执行硬件档位匹配返回最终频率完成调频。5.2 实操一查看内核变量与缓存状态命令行实操借助debugfs与cpufreq文件系统观测调频状态、触发次数间接验证缓存生效。5.2.1 挂载 debugfs内核调试文件系统# 临时挂载debugfs重启失效 sudo mount -t debugfs none /sys/kernel/debug # 永久挂载可选编辑fstab echo none /sys/kernel/debug debugfs defaults 0 0 | sudo tee -a /etc/fstab5.2.2 查看 CPU 频率档位与实时频率# 查看CPU0支持的所有频率档位 cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies # 查看CPU0当前实时运行频率动态变化 watch -n1 cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq使用场景持续观察频率变化当负载小幅波动时频率保持不变说明缓存命中。5.3 实操二使用 ftrace 跟踪 cached_raw_freq 与函数调用ftrace 是 Linux 内核原生跟踪工具可跟踪get_next_freq调用次数对比有缓存 / 无缓存下的调用频次差异。5.3.1 开启函数跟踪# 切换到debugfs跟踪目录 cd /sys/kernel/debug/tracing # 清空原有跟踪日志 sudo echo trace # 设置跟踪器为function函数调用跟踪 sudo echo function current_tracer # 只跟踪核心函数 get_next_freq sudo echo get_next_freq set_ftrace_filter # 开启跟踪 sudo echo 1 tracing_on5.3.2 压测 CPU触发频繁调频新开一个终端使用stress工具制造持续负载# 安装压测工具 sudo apt install stress -y # 4线程CPU压测持续运行 stress -c 4 -t 305.3.3 查看跟踪日志# 查看跟踪结果统计get_next_freq调用次数 sudo cat trace | grep get_next_freq | wc -l现象分析负载稳定阶段get_next_freq调用次数大幅下降因为cached_raw_freq缓存命中大部分调频请求直接复用结果负载突增 / 突降阶段调用次数短暂上升缓存失效重新计算频率。5.3.4 关闭跟踪sudo echo 0 tracing_on sudo echo set_ftrace_filter sudo echo nop current_tracer5.4 实操三编写测试程序模拟高频任务触发调频编写一个简单的用户态压测程序模拟频繁任务唤醒场景最大化触发 schedutil 调频直观体现缓存优化效果。5.4.1 C 语言压测代码cpu_stress.c/* * cpu_stress.c : 高频循环任务模拟短生命周期任务触发调度器频繁调频 * 编译gcc cpu_stress.c -o cpu_stress -pthread * 运行./cpu_stress 4 4个线程 */ #include stdio.h #include stdlib.h #include pthread.h #include unistd.h // 线程工作函数死循环空运算占用CPU void *cpu_loop(void *arg) { (void)arg; while(1) { // 简单运算制造持续CPU负载 int a 0; for(int i 0; i 10000; i) { a i; } // 短暂休眠模拟IO唤醒场景触发调度器事件 usleep(100); } return NULL; } int main(int argc, char *argv[]) { int thread_num 2; pthread_t *tid; if(argc 2) { thread_num atoi(argv[1]); } tid (pthread_t *)malloc(sizeof(pthread_t) * thread_num); if(NULL tid) { perror(malloc failed); return -1; } // 创建指定数量工作线程 for(int i 0; i thread_num; i) { pthread_create(tid[i], NULL, cpu_loop, NULL); } // 等待线程不会退出 for(int i 0; i thread_num; i) { pthread_join(tid[i], NULL); } free(tid); return 0; }5.4.2 编译与运行命令# 编译-pthread 链接线程库 gcc cpu_stress.c -o cpu_stress -pthread # 后台运行4线程压测 ./cpu_stress 4 # 查看CPU负载与调频状态 top watch -n1 cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq5.4.3 实验结论线程稳定运行后CPU 负载保持平稳cpuinfo_cur_freq固定在某一档频率ftrace 观测到get_next_freq调用频次极低缓存完全生效手动 kill 压测进程负载骤降缓存失效函数调用短暂增加频率下降。5.5 实操四内核源码小修改禁用缓存对比性能进阶为直观对比缓存的优化效果我们小幅修改内核代码注释缓存判断逻辑对比两种场景下的 CPU 开销。5.5.1 修改 cpufreq_schedutil.c找到get_next_freq中的缓存判断代码注释掉// 注释原有缓存逻辑强制每次都重新计算 /* if (freq sg_policy-cached_raw_freq !sg_policy-need_freq_update) { return sg_policy-next_freq; } */ sg_policy-cached_raw_freq freq;5.5.2 重新编译内核并重启# 编译内核多核编译-j 后接CPU核心数 make -j$(nproc) # 安装模块 安装内核 sudo make modules_install sudo make install # 重启系统进入新内核 sudo reboot5.5.3 对比测试运行压测程序使用perf top观测内核态 CPU 占比perf top -g对比结果开启缓存内核态 CPU 开销低get_next_freq、map_util_freq占用极少禁用缓存内核态开销明显上升调频相关函数持续占用 CPU负载越高差异越明显。六、常见问题与解答结合实操报错、现象Q1切换 schedutil 后scaling_governor报错权限不足现象echo schedutil xxx提示 Permission denied解答cpufreq 文件系统属于内核 sysfs必须使用 root 权限命令修改为sudo sh -c echo schedutil /sys/devices/system/cpu/cpu0/cpufreq/scaling_governorQ2ftrace 看不到get_next_freq函数跟踪为空原因 1内核未开启CONFIG_FUNCTION_TRACER跟踪配置原因 2内核版本过旧schedutil 未内置解决重新编译内核开启Kernel hacking - Tracers - Function tracer。Q3CPU 频率一直固定在最高档缓存完全不切换原因CPU 持续满负载raw_freq始终等于最大值缓存一直命中属于正常现象。排查停止压测观察频率是否下降若依然不变检查主板 BIOS 是否锁定 CPU 频率。Q4负载小幅变化但频率频繁跳动缓存失效原因 1内核freq_update_delay_ns调频限流时间设置过小频繁刷新缓存原因 2系统存在大量短时 IO 任务触发 IO boost 强制刷新need_freq_update解决调整 schedutil 限流参数或优化应用层 IO 逻辑。Q5虚拟机中无法看到 cpufreq 频率文件原因虚拟机虚拟化层屏蔽了 DVFS 功能解决更换物理机测试或 KVM 虚拟机添加 CPU 调频模拟参数。七、实践建议与最佳实践结合多年内核调优、嵌入式落地经验总结 schedutil cached_raw_freq 缓存机制的落地技巧、调优方案与排错规范。7.1 通用调优技巧限流参数优化sugov_policy-freq_update_delay_ns是调频最小间隔默认值较小。对于服务器场景可适当增大间隔减少缓存刷新次数嵌入式实时系统保持默认保证响应速度。区分场景使用缓存特性服务器、离线计算利用缓存减少内核开销容忍小幅频率延迟实时工控、车载系统可临时关闭缓存修改内核保证负载变化时频率秒级响应。结合 PELT 负载调优cached_raw_freq 缓存的是负载换算后的频率若 PELT 采样精度过高会导致负载频繁小幅波动缓存反复失效。高稳定性场景可适度调整 PELT 衰减系数。7.2 调试排错最佳实践排错顺序规范频率异常 → 查看实时频率文件 → ftrace 跟踪get_next_freq→ 判断缓存是否命中 → 分析负载来源 → 定位应用 / 内核问题。性能观测组合工具日常调优固定组合top应用负载perf内核开销ftrace函数调用cpufreq频率状态。线上环境禁忌线上生产服务器禁止随意修改内核源码关闭缓存会导致内核 CPU 开销上涨、功耗增加如需调试务必在测试机复现问题。7.3 嵌入式设备专属建议ARM 嵌入式设备算力弱是缓存机制的最大受益场景优先使用 Linux 5.4 内核cached_raw_freq 逻辑更完善不要频繁切换 schedutil/performance 调节器缓存状态错乱会导致功耗飙升IO 密集型嵌入式设备注意 IO boost 机制会强制刷新缓存需评估调频压力。7.4 代码开发规范二次开发 schedutil 相关功能时修改cached_raw_freq必须配合need_freq_update标志位避免缓存脏数据不要在中断上下文长时间操作该变量该字段被raw_spinlock_t保护新增频率计算逻辑时保持 “先对比缓存、再计算” 的架构延续内核设计思想。八、总结与落地应用场景8.1 全文核心要点回顾cached_raw_freq 定位schedutil 调频器的原始频率缓存字段存储上一次公式计算出的中间频率值核心原理负载稳定时复用缓存结果跳过重复计算降低调频链路 CPU 开销核心函数get_next_freq是缓存判断、更新的唯一入口整个机制围绕该函数运转优化价值以极小内存开销解决高频调频场景下的内核冗余计算问题兼顾性能与功耗。8.2 落地应用场景再梳理互联网服务器集群高并发 Web、缓存、数据库服务任务频繁唤醒缓存削减内核开销提升整机吞吐工业实时 Linux工控机、运动控制设备保证调频低抖动不干扰实时任务调度ARM 边缘计算网关低算力硬件下减少内核运算降低整机功耗延长设备运行时间车载娱乐 / 车控系统多任务并发场景平衡系统响应与功耗学术与研发内核功耗子系统研究、调度器联合调频方案设计、课程实验与毕业论文。8.3 学习延伸方向掌握本章节内容后可继续深入schedutil 的 IO Boost 机制、PELT 负载算法、CPU UCLAMP 负载约束、cpufreq 硬件 OPP 驱动适配形成完整的 Linux 调度 功耗知识体系。本教程从原理、源码、实操、排错、调优全维度解析了 cached_raw_freq 频率缓存机制所有案例均可复现代码与命令经过实测验证可直接用于工程落地、技术报告与学术研究。建议读者结合内核源码逐行跟踪执行流加深对 Linux 调度与调频联动架构的理解。
Linux Schedutil 的 cached_raw_freq:频率缓存优化
发布时间:2026/6/11 19:41:17
一、简介1.1 技术背景与行业现状CPU 调频DVFS动态电压频率调节是现代 Linux 系统功耗与性能平衡的核心技术广泛应用于服务器、嵌入式终端、工控设备、车载系统、移动终端等场景。传统ondemand、performance调频策略逻辑简单、响应滞后而schedutil作为 Linux 内核主推的调度器联动调频策略直接依托调度器 PELT 负载统计数据进行频率决策具备响应快、精度高、负载感知强三大优势目前已成为绝大多数 Linux 发行版、嵌入式平台的默认调频调节器。在高并发、高频任务切换的场景下调度器会在任务唤醒、迁移、时间片轮转等时机频繁触发调频计算。如果每次都完整执行负载换算、频率公式运算、OPP 表匹配会产生大量冗余计算挤占 CPU 算力尤其在单核嵌入式、低功耗 MCU 设备上冗余计算会直接拉高系统开销、增加功耗。为解决该问题Linux 内核在 schedutil 架构中引入了cached_raw_freq字段核心作用是缓存上一次计算得到的原始目标频率当负载未发生实质性变化时直接复用缓存结果跳过完整计算流程大幅降低调频路径的 CPU 开销。1.2 学习本章节的价值内核原理层面理解调度器与 CPU 调频子系统的联动逻辑掌握 schedutil 核心执行链路工程调优层面看懂频率缓存机制的设计思想能够针对高负载、高 IO 场景优化调频策略排错能力层面定位调频卡顿、功耗异常、频率频繁跳动等线上问题学术 / 报告层面内核源码、性能数据、测试案例完整可作为 Linux 调度、功耗管理方向论文、技术报告的核心素材。1.3 核心场景概述本机制主要服务两大类场景一是高并发服务器海量短生命周期任务频繁唤醒调度器高频触发调频二是嵌入式实时设备RT 实时任务、IO 密集型任务交替运行要求调频低延迟、低开销。cached_raw_freq 缓存机制正是为这类高频触发、负载小幅波动的场景量身设计。二、核心概念与术语解析为保证零基础读者也能顺畅阅读本节梳理所有关联术语、数据结构与执行逻辑。2.1 schedutil 基础概念schedutilLinux 内核基于调度器负载的 CPUFreq 调频调节器全称Scheduler Utilization Governor。不再依赖传统定时器轮询采样负载而是由调度器事件驱动任务唤醒、任务就绪、任务迁移实时获取 PELT 计算的 CPU 利用率动态计算目标运行频率。DVFS动态电压频率调节硬件 内核协同的功耗管理技术CPU 负载低时降低主频与电压以省电负载高时提升主频以保证性能是嵌入式、服务器、移动端必备技术。PELTPer-Entity Load TrackingLinux 调度器核心负载统计模块采用 EWMA 指数加权移动平均算法统计每个任务、每个运行队列rq的 CPU 利用率输出频率无关的负载值是 schedutil 计算频率的数据源。2.2 cached_raw_freq 核心定义2.2.1 结构体出处cached_raw_freq是struct sugov_policy结构体中的成员变量该结构体是 schedutil 每个 CPU 调频域的策略管理体定义于内核源码kernel/sched/cpufreq_schedutil.cstruct sugov_policy { struct cpufreq_policy *policy; struct sugov_tunables *tunables; struct list_head tunables_hook; raw_spinlock_t update_lock; u64 last_freq_update_time; s64 freq_update_delay_ns; unsigned int next_freq; // 核心原始计算频率缓存字段 unsigned int cached_raw_freq; /* 后续为延迟工作、中断工作相关成员 */ struct irq_work irq_work; struct kthread_work work; struct mutex work_lock; struct kthread_worker worker; struct task_struct *thread; bool work_in_progress; bool limits_changed; bool need_freq_update; };2.2.2 字段语义拆解cached_raw_freq上一次通过公式计算得出的原始频率值未经过硬件 OPP 表匹配、上下限约束next_freq最终生效的目标频率经过硬件校验、频率档位匹配后的结果二者区别cached_raw_freq是计算中间值缓存next_freq是最终执行值。2.3 缓存生效逻辑简述schedutil 计算目标频率的标准流程获取PELT负载 → 代入频率公式计算raw_freq → 匹配硬件OPP档位 → 得到next_freq → 硬件调频引入缓存后流程优化获取PELT负载 → 计算raw_freq → 对比 cached_raw_freq相等直接复用next_freq跳过后续计算与匹配不相等更新cached_raw_freq执行完整计算链路。该设计本质是空间换时间用一个 4 字节整型变量的内存开销规避重复的浮点运算、档位匹配、硬件查询等高开销操作。三、环境准备3.1 软硬件环境清单环境类型版本 / 配置用途说明操作系统Ubuntu 20.04 / CentOS 7.9 / Debian 11通用测试主机推荐 x86_64 架构Linux 内核5.4 / 5.10 / 5.15LTS 长期支持版cached_raw_freq 在 4.15 内核稳定存在优先 LTS 版本编译工具gcc、g、make、libncurses-dev、bison、flex内核编译、模块编译调试工具perf、trace-cmd、ftrace、gdb kgdb跟踪 schedutil 执行流、查看变量值源码资源Linux 官方内核源码阅读、修改、编译内核硬件要求x86_64 双核及以上 CPU支持 DVFS必须支持 CPU 调频功能虚拟机需开启 CPU 调频模拟注意纯虚拟机部分厂商会屏蔽 DVFS建议使用物理机或开启「CPU 性能模式模拟」的 KVM 虚拟机。3.2 环境部署步骤完整可复现3.2.1 依赖包安装Ubuntu 系列执行以下命令安装编译、调试全套依赖命令可直接复制运行# 更新软件源 sudo apt update sudo apt upgrade -y # 内核编译基础依赖 sudo apt install -y gcc make libncurses-dev bison flex libssl-dev libelf-dev # 调试、追踪工具 sudo apt install -y perf trace-cmd ftrace gdb3.2.2 下载并解压内核源码# 下载 Linux 5.10 LTS 内核国内镜像速度更快 wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.200.tar.xz # 解压源码 tar -xf linux-5.10.200.tar.xz cd linux-5.10.2003.2.3 确认 schedutil 配置开启schedutil 由内核配置项控制需确保配置开启打开内核配置界面make menuconfig依次进入配置路径Power management and ACPI options - CPU Frequency scaling - CPU Frequency scaling governors确保以下选项勾选*内置内核M模块[*] Schedutil cpufreq governor保存配置并退出。3.2.4 验证系统当前调频调节器在物理机 / 虚拟机中执行以下命令确认当前使用 schedutil# 查看当前CPU调频策略所有核心 cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor正常输出示例全部为 schedutilschedutil schedutil schedutil schedutil若输出为performance/ondemand执行命令切换# 批量将所有CPU核心切换为schedutil for cpu in /sys/devices/system/cpu/cpu[0-9]*; do echo schedutil $cpu/cpufreq/scaling_governor done四、应用场景详解300 字cached_raw_freq 频率缓存机制主要落地于三类工业场景。第一类是高并发 Web / 数据库服务器海量短连接请求造成任务频繁唤醒、调度器持续触发调频缓存可削减重复计算开销降低系统软中断占比。第二类是工业嵌入式实时系统工控机、PLC 设备中实时任务与普通 IO 任务交替执行要求调频低延迟、低抖动缓存机制避免频率反复计算导致的实时性下降。第三类是边缘计算低功耗设备ARM 架构边缘盒算力有限频繁调频计算会增加功耗缓存大幅精简执行链路兼顾性能与续航。在以上负载波动平缓、调频触发频繁的场景中cached_raw_freq 的优化收益最为显著。五、实际案例与代码实操核心章节含源码 注释 命令本节分为源码逐行解析、手动触发调频观测缓存、ftrace 跟踪缓存变化、编写测试程序压测四大实操环节所有代码、命令均可直接复制使用。5.1 核心源码解析cached_raw_freq 工作流程文件路径linux-5.10.200/kernel/sched/cpufreq_schedutil.c核心函数get_next_freq()这是 cached_raw_freq 缓存判断、更新的唯一入口也是整个机制的核心。5.1.1 get_next_freq 函数完整源码 逐行注释/** * get_next_freq - 计算CPU下一跳目标频率并使用cached_raw_freq做缓存优化 * sg_policy: schedutil策略结构体包含cached_raw_freq、next_freq等核心字段 * util: PELT模块输出的CPU利用率负载值 * max: CPU最大容量值 * * 返回值经过硬件匹配后的最终目标频率 */ static unsigned int get_next_freq(struct sugov_policy *sg_policy, unsigned long util, unsigned long max) { struct cpufreq_policy *policy sg_policy-policy; unsigned int freq; // 步骤1根据架构是否支持频率不变性选择计算基准频率 freq arch_scale_freq_invariant() ? policy-cpuinfo.max_freq : policy-cur; // 步骤2负载值性能映射 频率换算得到原始计算频率 raw_freq util map_util_perf(util); freq map_util_freq(util, freq, max); // 缓存核心逻辑 // 判断1新计算的raw_freq 与 缓存的cached_raw_freq 相等 // 判断2无强制更新标志 need_freq_update if (freq sg_policy-cached_raw_freq !sg_policy-need_freq_update) { // 缓存命中直接返回上一次生效的next_freq跳过后续所有计算 return sg_policy-next_freq; } // 缓存未命中更新缓存字段为当前新计算的raw_freq sg_policy-cached_raw_freq freq; // 步骤3原始频率匹配硬件支持的OPP档位输出最终频率 return cpufreq_driver_resolve_freq(policy, freq); }5.1.2 逻辑流程总结调度器触发调频调用get_next_freq根据 CPU 负载计算出原始频率 freq对比freq和sg_policy-cached_raw_freq命中直接返回历史next_freq链路终止未命中刷新cached_raw_freq执行硬件档位匹配返回最终频率完成调频。5.2 实操一查看内核变量与缓存状态命令行实操借助debugfs与cpufreq文件系统观测调频状态、触发次数间接验证缓存生效。5.2.1 挂载 debugfs内核调试文件系统# 临时挂载debugfs重启失效 sudo mount -t debugfs none /sys/kernel/debug # 永久挂载可选编辑fstab echo none /sys/kernel/debug debugfs defaults 0 0 | sudo tee -a /etc/fstab5.2.2 查看 CPU 频率档位与实时频率# 查看CPU0支持的所有频率档位 cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies # 查看CPU0当前实时运行频率动态变化 watch -n1 cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq使用场景持续观察频率变化当负载小幅波动时频率保持不变说明缓存命中。5.3 实操二使用 ftrace 跟踪 cached_raw_freq 与函数调用ftrace 是 Linux 内核原生跟踪工具可跟踪get_next_freq调用次数对比有缓存 / 无缓存下的调用频次差异。5.3.1 开启函数跟踪# 切换到debugfs跟踪目录 cd /sys/kernel/debug/tracing # 清空原有跟踪日志 sudo echo trace # 设置跟踪器为function函数调用跟踪 sudo echo function current_tracer # 只跟踪核心函数 get_next_freq sudo echo get_next_freq set_ftrace_filter # 开启跟踪 sudo echo 1 tracing_on5.3.2 压测 CPU触发频繁调频新开一个终端使用stress工具制造持续负载# 安装压测工具 sudo apt install stress -y # 4线程CPU压测持续运行 stress -c 4 -t 305.3.3 查看跟踪日志# 查看跟踪结果统计get_next_freq调用次数 sudo cat trace | grep get_next_freq | wc -l现象分析负载稳定阶段get_next_freq调用次数大幅下降因为cached_raw_freq缓存命中大部分调频请求直接复用结果负载突增 / 突降阶段调用次数短暂上升缓存失效重新计算频率。5.3.4 关闭跟踪sudo echo 0 tracing_on sudo echo set_ftrace_filter sudo echo nop current_tracer5.4 实操三编写测试程序模拟高频任务触发调频编写一个简单的用户态压测程序模拟频繁任务唤醒场景最大化触发 schedutil 调频直观体现缓存优化效果。5.4.1 C 语言压测代码cpu_stress.c/* * cpu_stress.c : 高频循环任务模拟短生命周期任务触发调度器频繁调频 * 编译gcc cpu_stress.c -o cpu_stress -pthread * 运行./cpu_stress 4 4个线程 */ #include stdio.h #include stdlib.h #include pthread.h #include unistd.h // 线程工作函数死循环空运算占用CPU void *cpu_loop(void *arg) { (void)arg; while(1) { // 简单运算制造持续CPU负载 int a 0; for(int i 0; i 10000; i) { a i; } // 短暂休眠模拟IO唤醒场景触发调度器事件 usleep(100); } return NULL; } int main(int argc, char *argv[]) { int thread_num 2; pthread_t *tid; if(argc 2) { thread_num atoi(argv[1]); } tid (pthread_t *)malloc(sizeof(pthread_t) * thread_num); if(NULL tid) { perror(malloc failed); return -1; } // 创建指定数量工作线程 for(int i 0; i thread_num; i) { pthread_create(tid[i], NULL, cpu_loop, NULL); } // 等待线程不会退出 for(int i 0; i thread_num; i) { pthread_join(tid[i], NULL); } free(tid); return 0; }5.4.2 编译与运行命令# 编译-pthread 链接线程库 gcc cpu_stress.c -o cpu_stress -pthread # 后台运行4线程压测 ./cpu_stress 4 # 查看CPU负载与调频状态 top watch -n1 cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq5.4.3 实验结论线程稳定运行后CPU 负载保持平稳cpuinfo_cur_freq固定在某一档频率ftrace 观测到get_next_freq调用频次极低缓存完全生效手动 kill 压测进程负载骤降缓存失效函数调用短暂增加频率下降。5.5 实操四内核源码小修改禁用缓存对比性能进阶为直观对比缓存的优化效果我们小幅修改内核代码注释缓存判断逻辑对比两种场景下的 CPU 开销。5.5.1 修改 cpufreq_schedutil.c找到get_next_freq中的缓存判断代码注释掉// 注释原有缓存逻辑强制每次都重新计算 /* if (freq sg_policy-cached_raw_freq !sg_policy-need_freq_update) { return sg_policy-next_freq; } */ sg_policy-cached_raw_freq freq;5.5.2 重新编译内核并重启# 编译内核多核编译-j 后接CPU核心数 make -j$(nproc) # 安装模块 安装内核 sudo make modules_install sudo make install # 重启系统进入新内核 sudo reboot5.5.3 对比测试运行压测程序使用perf top观测内核态 CPU 占比perf top -g对比结果开启缓存内核态 CPU 开销低get_next_freq、map_util_freq占用极少禁用缓存内核态开销明显上升调频相关函数持续占用 CPU负载越高差异越明显。六、常见问题与解答结合实操报错、现象Q1切换 schedutil 后scaling_governor报错权限不足现象echo schedutil xxx提示 Permission denied解答cpufreq 文件系统属于内核 sysfs必须使用 root 权限命令修改为sudo sh -c echo schedutil /sys/devices/system/cpu/cpu0/cpufreq/scaling_governorQ2ftrace 看不到get_next_freq函数跟踪为空原因 1内核未开启CONFIG_FUNCTION_TRACER跟踪配置原因 2内核版本过旧schedutil 未内置解决重新编译内核开启Kernel hacking - Tracers - Function tracer。Q3CPU 频率一直固定在最高档缓存完全不切换原因CPU 持续满负载raw_freq始终等于最大值缓存一直命中属于正常现象。排查停止压测观察频率是否下降若依然不变检查主板 BIOS 是否锁定 CPU 频率。Q4负载小幅变化但频率频繁跳动缓存失效原因 1内核freq_update_delay_ns调频限流时间设置过小频繁刷新缓存原因 2系统存在大量短时 IO 任务触发 IO boost 强制刷新need_freq_update解决调整 schedutil 限流参数或优化应用层 IO 逻辑。Q5虚拟机中无法看到 cpufreq 频率文件原因虚拟机虚拟化层屏蔽了 DVFS 功能解决更换物理机测试或 KVM 虚拟机添加 CPU 调频模拟参数。七、实践建议与最佳实践结合多年内核调优、嵌入式落地经验总结 schedutil cached_raw_freq 缓存机制的落地技巧、调优方案与排错规范。7.1 通用调优技巧限流参数优化sugov_policy-freq_update_delay_ns是调频最小间隔默认值较小。对于服务器场景可适当增大间隔减少缓存刷新次数嵌入式实时系统保持默认保证响应速度。区分场景使用缓存特性服务器、离线计算利用缓存减少内核开销容忍小幅频率延迟实时工控、车载系统可临时关闭缓存修改内核保证负载变化时频率秒级响应。结合 PELT 负载调优cached_raw_freq 缓存的是负载换算后的频率若 PELT 采样精度过高会导致负载频繁小幅波动缓存反复失效。高稳定性场景可适度调整 PELT 衰减系数。7.2 调试排错最佳实践排错顺序规范频率异常 → 查看实时频率文件 → ftrace 跟踪get_next_freq→ 判断缓存是否命中 → 分析负载来源 → 定位应用 / 内核问题。性能观测组合工具日常调优固定组合top应用负载perf内核开销ftrace函数调用cpufreq频率状态。线上环境禁忌线上生产服务器禁止随意修改内核源码关闭缓存会导致内核 CPU 开销上涨、功耗增加如需调试务必在测试机复现问题。7.3 嵌入式设备专属建议ARM 嵌入式设备算力弱是缓存机制的最大受益场景优先使用 Linux 5.4 内核cached_raw_freq 逻辑更完善不要频繁切换 schedutil/performance 调节器缓存状态错乱会导致功耗飙升IO 密集型嵌入式设备注意 IO boost 机制会强制刷新缓存需评估调频压力。7.4 代码开发规范二次开发 schedutil 相关功能时修改cached_raw_freq必须配合need_freq_update标志位避免缓存脏数据不要在中断上下文长时间操作该变量该字段被raw_spinlock_t保护新增频率计算逻辑时保持 “先对比缓存、再计算” 的架构延续内核设计思想。八、总结与落地应用场景8.1 全文核心要点回顾cached_raw_freq 定位schedutil 调频器的原始频率缓存字段存储上一次公式计算出的中间频率值核心原理负载稳定时复用缓存结果跳过重复计算降低调频链路 CPU 开销核心函数get_next_freq是缓存判断、更新的唯一入口整个机制围绕该函数运转优化价值以极小内存开销解决高频调频场景下的内核冗余计算问题兼顾性能与功耗。8.2 落地应用场景再梳理互联网服务器集群高并发 Web、缓存、数据库服务任务频繁唤醒缓存削减内核开销提升整机吞吐工业实时 Linux工控机、运动控制设备保证调频低抖动不干扰实时任务调度ARM 边缘计算网关低算力硬件下减少内核运算降低整机功耗延长设备运行时间车载娱乐 / 车控系统多任务并发场景平衡系统响应与功耗学术与研发内核功耗子系统研究、调度器联合调频方案设计、课程实验与毕业论文。8.3 学习延伸方向掌握本章节内容后可继续深入schedutil 的 IO Boost 机制、PELT 负载算法、CPU UCLAMP 负载约束、cpufreq 硬件 OPP 驱动适配形成完整的 Linux 调度 功耗知识体系。本教程从原理、源码、实操、排错、调优全维度解析了 cached_raw_freq 频率缓存机制所有案例均可复现代码与命令经过实测验证可直接用于工程落地、技术报告与学术研究。建议读者结合内核源码逐行跟踪执行流加深对 Linux 调度与调频联动架构的理解。