x86/Linux多线程:perf报告子项百分比总和与父项不匹配咨询
问题:perf report 中符号百分比求和与父项不匹配的原因
示例代码
#define _GNU_SOURCE #include <stdatomic.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/mman.h> #include <sched.h> #include <syscall.h> #include <linux/futex.h> volatile atomic_int variable; int futex_word; int foo(void *v) { while (1) { int expected = atomic_load(&variable); atomic_compare_exchange_strong(&variable, &expected, expected + 1); syscall(SYS_futex, &futex_word, FUTEX_WAKE, 1); } } int main(void) { void *stack = (char *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0) + 4096; clone(foo, stack, CLONE_CHILD_SETTID, NULL); sleep(1000); }
运行命令
编译代码生成可执行文件main后,执行采样命令:
sudo perf record --call-graph dwarf,16384 -F 9123 ./main
随后生成性能报告:
sudo perf report
异常现象
得到的报告显示:展开符号foo后包含两个子条目,分别是95.53% foo和0.93% __GI___clone;子项百分比求和为96.46%,但父项foo显示的总占比是96.52%,二者存在微小偏差。
原因分析
这种偏差是正常现象,主要来自两个方面:
采样的统计误差
perf采用基于事件的采样机制(此处为9123Hz频率的CPU周期采样),每次采样仅记录当前瞬间的调用栈,属于概率性统计而非精确计数。采样过程中必然存在微小的统计波动,导致最终百分比数值出现偏差。四舍五入的累计影响
报告中显示的百分比均为四舍五入保留两位小数的结果:
- 子项的百分比是各自独立四舍五入后的数值
- 父项的百分比是基于该符号的总采样数直接计算后四舍五入的数值
两者计算逻辑不同,子项求和后自然会与父项数值存在微小差异。比如实际子项占比可能是95.526%和0.927%,四舍五入后变成95.53%和0.93%,求和为96.46%;而父项实际总占比是96.518%,四舍五入后显示为96.52%,二者偏差由此产生。
另外,__GI___clone出现在foo的子项中,是因为新线程通过clone创建后,内核会跳转到指定的foo函数入口,采样可能刚好捕获到clone系统调用返回后、线程完全进入foo前的瞬间,属于调用栈回溯的边界正常情况,占比极低无需在意。
内容的提问来源于stack exchange,提问作者Some Name
相关产品推荐
相关产品推荐

