kernel侧CPU是怎样判断共享的?
Linux CPUFreq 子系统的核心架构设计
788 if (policy_is_shared(policy))
789 uu = sugov_update_shared;
790 else if (policy->fast_switch_enabled && cpufreq_driver_has_adjust_perf())
791 uu = sugov_update_single_perf;
792 else
793 uu = sugov_update_single_freq;
policy_is_shared()
函数实现
static inline bool policy_is_shared(struct cpufreq_policy *policy)
{
return cpumask_weight(policy->cpus) > 1;
}
关键点解释:
| 一个 |
| 计算位图中置位的 CPU 数量(即参与该策略的 CPU 个数) |
| 只要有两个或以上 CPU 共享同一个策略,就认为是 shared |
✅结论:只要一个
cpufreq_policy
管理多个 CPU,就被视为 "shared"。
二、为什么需要 shared 概念?
根本原因:硬件频率域限制
现代 SoC 中,多个 CPU 核心可能共享同一个时钟源(clock domain),这意味着它们必须运行在同一频率。
示例场景:
x86 单核 | 1 CPU per policy | ❌ 不共享 |
ARM big.LITTLE | 4x Cortex-A7 (LITTLE) | ✅ 共享 |
多核服务器 | 所有核心独立调频 | ❌ 不共享 |
三、具体硬件平台案例分析
1. Intel HWP (Hardware P-States)
# 查看策略分布
cat /sys/devices/system/cpu/cpufreq/policy*/scaling_governor# 输出示例:
# policy0: performance (CPU0)
# policy1: powersave (CPU4)
- 每个物理核心有自己的策略 → 不 shared
cpumask_weight(policy->cpus) == 1
2. ARM big.LITTLE 架构
# Exynos 或 Kirin 平台常见配置
ls /sys/devices/system/cpu/cpufreq/
# policy0/ policy4/# policy0 控制 CPU0-3 (LITTLE cluster)
cat /sys/devices/system/cpu/cpufreq/policy0/cpus
# 输出: 0 1 2 3# policy4 控制 CPU4-7 (big cluster)
cat /sys/devices/system/cpu/cpufreq/policy4/cpus
# 输出: 4 5 6 7
- 每个 cluster 一个策略,管理多个 CPU
cpumask_weight(policy->cpus) == 4
→ shared
四、shared 策略的实际影响
当 policy_is_shared()
返回 true
时,governor 必须采取不同的行为:
1. 频率决策逻辑变化
if (policy_is_shared(policy))uu = sugov_update_shared; // 使用共享更新函数
elseuu = sugov_update_single_xxx;
sugov_update_shared
的特殊处理:
static void sugov_update_shared(struct update_util_data *hook, u64 time, unsigned int flags)
{struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util);struct sugov_policy *sg_policy = sg_cpu->sg_policy;unsigned long util = 0, max = 0;unsigned int next_f;int cpu;// 遍历所有共享 CPU,取最大利用率for_each_cpu(cpu, policy->cpus) {struct sugov_cpu *tmp_sg_cpu = &per_cpu(sugov_cpu, cpu);unsigned long tmp_util = tmp_sg_cpu->util;if (tmp_util > util) {util = tmp_util;max = tmp_sg_cpu->max;}}next_f = map_util_freq(util, policy->cpuinfo.max_freq, max);cpufreq_driver_update_util(sg_policy, next_f);
}
🔑 关键点:不是平均值,而是取最大值,确保最忙的 CPU 得到足够频率。
2. 锁竞争与同步开销
// 在 sugov_update_shared 中需要加锁
mutex_lock(&sg_policy->update_lock);// 计算频率...
next_freq = compute_freq();mutex_unlock(&sg_policy->update_lock);
- 防止多个 CPU 同时触发频率更新
- 增加了上下文切换延迟
3. 性能 vs 能效权衡
频率切换次数 | 少(统一变更) | 多(各自调整) |
能效 | 较低(整体降频慢) | 较高(精细控制) |
响应速度 | 慢(受最忙 CPU 影响) | 快(按需调整) |
硬件复杂度 | 低 | 高 |
五、调试技巧:查看当前 policy 结构
1. 查看每个 policy 管理的 CPU
for f in /sys/devices/system/cpu/cpufreq/policy*/cpus; do
echo "$f: $(cat $f)"
done
输出示例:
/sys/devices/system/cpu/cpufreq/policy0/cpus: 0 1 2 3
/sys/devices/system/cpu/cpufreq/policy4/cpus: 4 5 6 7
2. 计算 weight 验证 shared
# 对 policy0
echo $(cat /sys/devices/system/cpu/cpufreq/policy0/cpus | wc -w)
# 输出: 4 → >1 → shared!
3. 使用 ftrace 观察策略选择
echo 'sugov_start' > /sys/kernel/debug/tracing/set_ftrace_filter
echo function > /sys/kernel/debug/tracing/current_tracer
cat /sys/kernel/debug/tracing/trace_pipe | grep policy