You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

纯用户态进程perf stats中内核内存操作的成因与归因疑问

内核内存操作被归因到用户进程的perf采样问题

测试场景

  • 将线程绑定至CPU 1,从预分配并初始化的2GB内存区域执行随机读取,内存访问循环期间无系统调用。
  • 独立运行perf进程,执行测量指令:mem_inst_retired.all_loads:k,mem_inst_retired.all_stores:k -I 200 -p <pid>

极简测试代码

void access_memory(char *memory) {
    // 绑定线程到CPU 1
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(1, &cpuset);
    pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);

    std::mt19937 gen(std::random_device{}());
    std::uniform_int_distribution<size_t> dist(0, 2GB - 500);
    char buffer[500];

    while (!should_stop) {
        size_t offset = dist(gen);
        memcpy(buffer, memory + offset, 500);
        buffer[0]++; 
    }
}

观测图表

内核加载/存储操作量偏高
图表显示内核加载/存储操作量异常偏高,怀疑与perf采样行为相关。

技术问题

  1. 为何仅执行用户态内存读取的进程会被统计到内核内存操作?是否是PMU(性能监控单元)采样产生的中断导致内核执行的内存操作被归因到该进程?查阅Intel SDM文档未找到明确答案。
  2. perf是如何将内核态操作归因到特定进程的?对于系统调用,内核确实是“代表进程”工作,但调度、内存整理、负载均衡等内核任务属于系统维护操作,并非为进程执行,为何会关联到该进程?其归因边界如何界定?

额外观测

将采样间隔从200ms改为5s后,每间隔测量到的内核操作数从10⁵变为10⁷。

通过taskset -c 1运行测试程序后,执行以下perf命令:

sudo perf record -e mem_inst_retired.all_loads:k -p <PID> -- sleep 20

得到的采样结果如下:

# Total Lost Samples: 0
#
# Samples: 15  of event 'mem_inst_retired.all_loads:k'
# Event count (approx.): 30000045
#
# Overhead  Command    Shared Object      Symbol                            
# ........  .........  .................  ..................................
#
    13.33%  perf-ldst  [kernel.kallsyms]  [k] decay_load
    13.33%  perf-ldst  [kernel.kallsyms]  [k] read_tsc
    13.33%  perf-ldst  [kernel.kallsyms]  [k] update_process_times
    13.33%  perf-ldst  [kernel.kallsyms]  [k] update_vsyscall
     6.67%  perf-ldst  [kernel.kallsyms]  [k] __raw_spin_lock_irqsave
     6.67%  perf-ldst  [kernel.kallsyms]  [k] __update_load_avg_se
     6.67%  perf-ldst  [kernel.kallsyms]  [k] _raw_spin_lock_irqsave
     6.67%  perf-ldst  [kernel.kallsyms]  [k] irq_work_run_list
     6.67%  perf-ldst  [kernel.kallsyms]  [k] timekeeping_adjust.constprop.0
     6.67%  perf-ldst  [kernel.kallsyms]  [k] timekeeping_advance
     6.67%  perf-ldst  [kernel.kallsyms]  [k] xas_move_index

此处的核心疑问是:定时器/调度器中断及管理操作属于系统维护任务,无论哪个进程运行都会执行,并非像系统调用那样“代表进程”执行,为何会被归因到当前运行的用户进程?

问题解答

1. 内核内存操作被统计的原因

使用mem_inst_retired.all_loads:k这类带:k修饰符的事件时,perf会统计所有内核态下执行的内存操作,其归因逻辑基于当前CPU上正在运行的进程:当PMU触发采样中断时,内核会读取CPU的current进程指针(即当前占用CPU的用户进程),并将此次内核中的内存操作关联到该进程。

你的测试线程绑定在CPU1上,几乎独占该CPU,因此CPU1上发生的所有内核中断(包括perf采样自身触发的中断、定时器中断、调度器周期任务)带来的内核内存操作,都会被归因到这个用户进程。此外,perf采样本身会触发内核的中断处理流程,该流程包含大量内存读写操作(如保存/恢复寄存器、更新采样数据结构等),这些操作也会被计入该进程的内核内存操作统计。

2. perf的进程归因规则边界

perf的归因逻辑核心是基于CPU的上下文关联,而非判断任务是否“为进程服务”:

  • 当CPU处于用户态执行时,所有操作直接归因到当前进程。
  • 当CPU进入内核态时,分两种情况:
    1. 主动进入内核态:如系统调用、缺页异常,此时内核明确为当前进程服务,操作会归因到该进程。
    2. 被动进入内核态:如外部中断、定时器中断,此时内核执行系统维护任务,但由于中断发生时CPU正被某个用户进程占用,perf会将这些内核操作关联到这个“被中断”的进程。

这种设计源于硬件层面的限制:中断发生时CPU的上下文属于当前运行的进程,perf无法区分内核操作是“为进程服务”还是“系统自身任务”,只能基于当前的进程上下文进行归因。

你观察到采样间隔从200ms改为5s后内核操作数大幅增加,原因是采样间隔越长,单次采样需要统计的内核操作累积量越大——更长的间隔意味着内核在该CPU上执行的系统维护任务(如定时器触发的负载更新、时间同步等)更多,这些操作都会被关联到你的测试进程。

内容的提问来源于stack exchange,提问作者idle_cycles

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 06:44:54