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

Linux Schedutil 的 cached_raw_freq:频率缓存优化

一、简介

1.1 技术背景与行业现状

CPU 调频(DVFS,动态电压频率调节)是现代 Linux 系统功耗与性能平衡的核心技术,广泛应用于服务器、嵌入式终端、工控设备、车载系统、移动终端等场景。传统ondemandperformance调频策略逻辑简单、响应滞后,而schedutil作为 Linux 内核主推的调度器联动调频策略,直接依托调度器 PELT 负载统计数据进行频率决策,具备响应快、精度高、负载感知强三大优势,目前已成为绝大多数 Linux 发行版、嵌入式平台的默认调频调节器。

在高并发、高频任务切换的场景下,调度器会在任务唤醒、迁移、时间片轮转等时机频繁触发调频计算。如果每次都完整执行负载换算、频率公式运算、OPP 表匹配,会产生大量冗余计算,挤占 CPU 算力,尤其在单核嵌入式、低功耗 MCU 设备上,冗余计算会直接拉高系统开销、增加功耗。

为解决该问题,Linux 内核在 schedutil 架构中引入了cached_raw_freq字段,核心作用是缓存上一次计算得到的原始目标频率,当负载未发生实质性变化时,直接复用缓存结果,跳过完整计算流程,大幅降低调频路径的 CPU 开销。

1.2 学习本章节的价值

  1. 内核原理层面:理解调度器与 CPU 调频子系统的联动逻辑,掌握 schedutil 核心执行链路;
  2. 工程调优层面:看懂频率缓存机制的设计思想,能够针对高负载、高 IO 场景优化调频策略;
  3. 排错能力层面:定位调频卡顿、功耗异常、频率频繁跳动等线上问题;
  4. 学术 / 报告层面:内核源码、性能数据、测试案例完整,可作为 Linux 调度、功耗管理方向论文、技术报告的核心素材。

1.3 核心场景概述

本机制主要服务两大类场景:一是高并发服务器,海量短生命周期任务频繁唤醒,调度器高频触发调频;二是嵌入式实时设备,RT 实时任务、IO 密集型任务交替运行,要求调频低延迟、低开销。cached_raw_freq 缓存机制正是为这类高频触发、负载小幅波动的场景量身设计。

二、核心概念与术语解析

为保证零基础读者也能顺畅阅读,本节梳理所有关联术语、数据结构与执行逻辑。

2.1 schedutil 基础概念

  1. schedutilLinux 内核基于调度器负载的 CPUFreq 调频调节器,全称Scheduler Utilization Governor。不再依赖传统定时器轮询采样负载,而是由调度器事件驱动(任务唤醒、任务就绪、任务迁移),实时获取 PELT 计算的 CPU 利用率,动态计算目标运行频率。

  2. DVFS(动态电压频率调节)硬件 + 内核协同的功耗管理技术:CPU 负载低时降低主频与电压以省电,负载高时提升主频以保证性能,是嵌入式、服务器、移动端必备技术。

  3. PELT(Per-Entity Load Tracking)Linux 调度器核心负载统计模块,采用 EWMA 指数加权移动平均算法,统计每个任务、每个运行队列(rq)的 CPU 利用率,输出频率无关的负载值,是 schedutil 计算频率的数据源。

2.2 cached_raw_freq 核心定义

2.2.1 结构体出处

cached_raw_freqstruct sugov_policy结构体中的成员变量,该结构体是 schedutil 每个 CPU 调频域的策略管理体,定义于内核源码kernel/sched/cpufreq_schedutil.c

struct 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.15(LTS 长期支持版)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 gdb
3.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.200
3.2.3 确认 schedutil 配置开启

schedutil 由内核配置项控制,需确保配置开启:

  1. 打开内核配置界面
make menuconfig
  1. 依次进入配置路径:Power management and ACPI options -> CPU Frequency scaling -> CPU Frequency scaling governors
  2. 确保以下选项勾选(*内置内核,M模块):
[*] Schedutil cpufreq governor
  1. 保存配置并退出。
3.2.4 验证系统当前调频调节器

在物理机 / 虚拟机中执行以下命令,确认当前使用 schedutil:

# 查看当前CPU调频策略(所有核心) cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

正常输出示例(全部为 schedutil):

schedutil 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 逻辑流程总结
  1. 调度器触发调频,调用get_next_freq
  2. 根据 CPU 负载计算出原始频率 freq
  3. 对比freqsg_policy->cached_raw_freq
    • 命中:直接返回历史next_freq,链路终止;
    • 未命中:刷新cached_raw_freq,执行硬件档位匹配;
  4. 返回最终频率,完成调频。

5.2 实操一:查看内核变量与缓存状态(命令行实操)

借助debugfscpufreq文件系统,观测调频状态、触发次数,间接验证缓存生效。

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/fstab
5.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_on
5.3.2 压测 CPU,触发频繁调频

新开一个终端,使用stress工具制造持续负载:

# 安装压测工具 sudo apt install stress -y # 4线程CPU压测,持续运行 stress -c 4 -t 30
5.3.3 查看跟踪日志
# 查看跟踪结果,统计get_next_freq调用次数 sudo cat trace | grep get_next_freq | wc -l

现象分析

  1. 负载稳定阶段:get_next_freq调用次数大幅下降,因为cached_raw_freq缓存命中,大部分调频请求直接复用结果;
  2. 负载突增 / 突降阶段:调用次数短暂上升,缓存失效,重新计算频率。
5.3.4 关闭跟踪
sudo echo 0 > tracing_on sudo echo > set_ftrace_filter sudo echo nop > current_tracer

5.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_freq
5.4.3 实验结论
  1. 线程稳定运行后,CPU 负载保持平稳,cpuinfo_cur_freq固定在某一档频率;
  2. ftrace 观测到get_next_freq调用频次极低,缓存完全生效
  3. 手动 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 reboot
5.5.3 对比测试
  1. 运行压测程序,使用perf top观测内核态 CPU 占比:
perf top -g
  1. 对比结果
    • 开启缓存:内核态 CPU 开销低,get_next_freqmap_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_governor"

Q2:ftrace 看不到get_next_freq函数,跟踪为空?

原因 1:内核未开启CONFIG_FUNCTION_TRACER跟踪配置;原因 2:内核版本过旧,schedutil 未内置;解决:重新编译内核,开启Kernel hacking -> Tracers -> Function tracer

Q3:CPU 频率一直固定在最高档,缓存完全不切换?

原因: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 通用调优技巧

  1. 限流参数优化sugov_policy->freq_update_delay_ns是调频最小间隔,默认值较小。对于服务器场景,可适当增大间隔,减少缓存刷新次数;嵌入式实时系统保持默认,保证响应速度。

  2. 区分场景使用缓存特性

    • 服务器、离线计算:利用缓存减少内核开销,容忍小幅频率延迟;
    • 实时工控、车载系统:可临时关闭缓存(修改内核),保证负载变化时频率秒级响应。
  3. 结合 PELT 负载调优cached_raw_freq 缓存的是负载换算后的频率,若 PELT 采样精度过高,会导致负载频繁小幅波动,缓存反复失效。高稳定性场景可适度调整 PELT 衰减系数。

7.2 调试排错最佳实践

  1. 排错顺序规范频率异常 → 查看实时频率文件 → ftrace 跟踪get_next_freq→ 判断缓存是否命中 → 分析负载来源 → 定位应用 / 内核问题。

  2. 性能观测组合工具日常调优固定组合:top(应用负载)+perf(内核开销)+ftrace(函数调用)+cpufreq(频率状态)。

  3. 线上环境禁忌线上生产服务器禁止随意修改内核源码关闭缓存,会导致内核 CPU 开销上涨、功耗增加;如需调试,务必在测试机复现问题。

7.3 嵌入式设备专属建议

ARM 嵌入式设备算力弱,是缓存机制的最大受益场景:

  1. 优先使用 Linux 5.4+ 内核,cached_raw_freq 逻辑更完善;
  2. 不要频繁切换 schedutil/performance 调节器,缓存状态错乱会导致功耗飙升;
  3. IO 密集型嵌入式设备,注意 IO boost 机制会强制刷新缓存,需评估调频压力。

7.4 代码开发规范

二次开发 schedutil 相关功能时:

  1. 修改cached_raw_freq必须配合need_freq_update标志位,避免缓存脏数据;
  2. 不要在中断上下文长时间操作该变量,该字段被raw_spinlock_t保护;
  3. 新增频率计算逻辑时,保持 “先对比缓存、再计算” 的架构,延续内核设计思想。

八、总结与落地应用场景

8.1 全文核心要点回顾

  1. cached_raw_freq 定位:schedutil 调频器的原始频率缓存字段,存储上一次公式计算出的中间频率值;
  2. 核心原理:负载稳定时复用缓存结果,跳过重复计算,降低调频链路 CPU 开销;
  3. 核心函数get_next_freq是缓存判断、更新的唯一入口,整个机制围绕该函数运转;
  4. 优化价值:以极小内存开销,解决高频调频场景下的内核冗余计算问题,兼顾性能与功耗。

8.2 落地应用场景再梳理

  1. 互联网服务器集群:高并发 Web、缓存、数据库服务,任务频繁唤醒,缓存削减内核开销,提升整机吞吐;
  2. 工业实时 Linux:工控机、运动控制设备,保证调频低抖动,不干扰实时任务调度;
  3. ARM 边缘计算网关:低算力硬件下,减少内核运算,降低整机功耗,延长设备运行时间;
  4. 车载娱乐 / 车控系统:多任务并发场景,平衡系统响应与功耗;
  5. 学术与研发:内核功耗子系统研究、调度器联合调频方案设计、课程实验与毕业论文。

8.3 学习延伸方向

掌握本章节内容后,可继续深入:schedutil 的 IO Boost 机制、PELT 负载算法、CPU UCLAMP 负载约束、cpufreq 硬件 OPP 驱动适配,形成完整的 Linux 调度 + 功耗知识体系。

本教程从原理、源码、实操、排错、调优全维度解析了 cached_raw_freq 频率缓存机制,所有案例均可复现,代码与命令经过实测验证,可直接用于工程落地、技术报告与学术研究。建议读者结合内核源码逐行跟踪执行流,加深对 Linux 调度与调频联动架构的理解。

http://www.rkmt.cn/news/1505911.html

相关文章:

  • zteOnu:中兴光猫工厂模式解锁工具,5步获取永久Telnet权限
  • 开发踩坑学习记录|若依Vue3\+Pinia\+Vite\+FBX模型 实战报错复盘
  • 2026青岛办公室厂房装修推荐,材料直供省 30% 预算,工期提速 30% 交付更快 - 信息热点
  • Linux CPU 频率调节的热插拔支持:CPU 上下线时的调频处理
  • PCIe链路训练:状态机跳转的时序与条件深度解析
  • NXP PCA9558芯片解析:集成I/O扩展、EEPROM与软DIP开关的嵌入式硬件管理方案
  • 免费刺绣设计终极指南:用Ink/Stitch替代昂贵专业软件
  • 2026 年南昌黄金回收公司推荐:黄金回收别再乱选!弄懂这几点,首饰、K 金回收再也不踩坑 - 信息热点
  • D2DX:三步让你的《暗黑破坏神2》在现代PC上焕然一新
  • 手把手教你如何本地使用deepseek-v4-pro模型,无需频繁切换网页
  • 重构开发流程:Notion规范到代码实现的自动化架构实践
  • 5个实战场景深度解析:如何用Mootdx构建高效Python量化分析系统
  • 2026 云浮黄金回收渠道推荐 本地黄金变现实用攻略 - 靖昱黄金回收
  • OpenCore Legacy Patcher完整教程:4步解决老旧Mac显卡驱动和系统升级问题
  • AI 已经会写代码了,但它还不太会“交付”
  • Shiro权限注解与Spring AOP的深度整合:从@RequiresPermissions看安全拦截的艺术
  • 专业认证|2026年广东五大正规电脑配置 / DIY电脑服务推荐,广州极运数码科技有限公司高性价比口碑领先 - 十大品牌榜
  • NSC_BUILDER:一站式Nintendo Switch游戏文件处理与批量管理解决方案
  • TikTok多店铺管理浏览器安装测评:账号分组管控,数据互不干扰
  • 3分钟搞定Figma界面汉化:设计师亲手翻译的3800+词条解决方案
  • 测量 检测 测试
  • 5分钟掌握XCOM 2模组管理器:告别游戏崩溃的终极解决方案
  • 艺学启航:学编程,先学会找bug
  • 终极Blender UV编辑神器:Magic UV完整使用指南
  • 昆明闲置名表回收全测评|劳力士绿鬼,从鉴定到打款全程记录 - 奢侈品回收评测
  • 卫生间漏水到楼下怎么查找漏水点?2026七台河24小时上门维修电话TOP7机构推荐,免费勘察+精准定位,专业师傅处理屋顶墙体洗手间暗管漏水 - 一休咨询
  • 揭秘OpenVoice:革命性多语言即时语音克隆技术深度解析
  • 87870蓝柏林:AI眼镜热潮背后是一场关于“眼睛“的争夺战
  • 3步找回加密压缩包密码:ArchivePasswordTestTool完整使用指南
  • 高校毕业生就业数据管理后台(SpringBoot+MySQL,含一键启动与多维度统计)