一、ksamplingd 线程概述

在内核中新建 ksamplingd 用于采样硬件性能事件的线程:

  • 从 Perf Events 的 ring buffer 里读取样本
  • 处理样本数据
  • 根据自身实际 CPU 时间占用率,动态调整采样频率
    这篇文章的介绍将略过采样和处理样本的部分,因为采样在之前博客里详细分析过。这里主要调整的参数是struct perf_event_attr sample_period

二、线程初始化

1. CPU 线程给定

const struct cpumask *cpumask = cpumask_of_node(0);
if (!cpumask_empty(cpumask))
	do_set_cpus_allowed(access_sampling, cpumask);
  • cpumask_of_node(0) 获取节点 0 所有 CPU 的 mask。
  • 通过 do_set_cpus_allowed() 把采样线程给定运行在某些 CPU 上。看需求,因为在笔者的场景中,只关注 socket0 的冷数据和热数据,而socket0 虽然 NUMA 有两个,实际物理核心只是 NUMA0 的。

2. 时间变量初始化

trace_runtime = total_runtime = exec_runtime = t->se.sum_exec_runtime;
trace_cputime = total_cputime = elapsed_cputime = jiffies;
sleep_timeout = usecs_to_jiffies(2000);
  • t->se.sum_exec_runtime :是内核调度实体 task_structstruct sched_entity 中记录该进程历史上总共运行的 CPU 耗时(单位 ns)。原本用于计算 CFS 调度器中优先级和时间分配。
  • jiffies :内核时钟计数器
  • sleep_timeout :指定最短采样间隔

三、CPU 占用率计算

1. 时间差值

exec_runtime = t->se.sum_exec_runtime - exec_runtime; // ns
elapsed_cputime = jiffies_to_usecs(cur - elapsed_cputime); // us
  • exec_runtime :本次周期内采样线程耗时
  • elapsed_cputime :本次周期内当前增量时间

2. 占用率计算

需要单位符合:把 ns -> us

u64 cur_cputime = div64_u64(exec_runtime / 1000, elapsed_cputime); // permil

最终得到 cputime

  • 单位是 permil (% 的 10倍)
  • 如果 cputime = 300 ,即 CPU 占用 30%

四、动态调整采样频率

1. 调整规则

关键参数:
ksampled_soft_cpu_quota 目标 CPU 占用率上限(permil,千分比)
cputime 实际测得的 CPU 时间占用率
sample_period 当前 LLC 采样周期(控制采样间隔)
sample_inst_period 当前指令采样周期
pcount 宏定义的上限

增加采样周期(降低采样频率):
cputime 超过目标占用率 ksampled_soft_cpu_quota + 5(防止频繁调整),且 sample_period 没有达到上限 pcount,调用 increase_sample_period 使采样周期增加,从而降低采样频率。如果周期有变化,应用新的采样周期。

减少采样周期(提高采样频率):
cputime 低于目标占用率 ksampled_soft_cpu_quota - 5,并且 sample_period 大于 pinstcount,可以调用 decrease_sample_period 减小采样周期,增加采样频率。同样如果采样周期发生变化,需要更新 pebs 采样器的配置。

2. 调整函数实现细节

  • 线性调整:每次增加或减少采样周期,只调整一个单位。确保不会超过预定义的上下限 pcountpinstcount。响应慢但足够稳定。
  • 通过查表(预先定义一个已经排序的数组,数组中每个值表示周期)进行非线性调整,适合对不同采样周期有特殊设计的应用场景。

五、线程休眠机制

schedule_timeout_interruptible(sleep_timeout);
  • 休眠控制线程激活频率
  • 配合采样周期,避免忙等和超时间

文章作者: 易百分
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 易百分 !
  目录