perf lock record 报“not supported”是因为默认 perf 未编译锁统计支持,需手动编译 tools/perf 并链接内核 lockstat 模块;抓真实锁竞争需确保内核 CONFIG_LOCK_STAT=y、perf 含 lock events、使用 -a 或 -p 采样、程序运行足够久;report 中 contended 高 + wait_total 高 + wait_max 显著才表强竞争;须结合 sched:sched_stat_blocked 交叉验证是否真阻塞,且依赖 -g 符号和调用栈定位具体 std::mutex 实例。

perf lock record 为什么经常报错“not supported”
因为默认编译的 perf 不带锁统计支持,即使内核启用了 CONFIG_LOCK_STAT=y,用户态 perf 二进制也得自己编译并链接内核源码中的 lockstat 模块。
常见错误现象:perf lock record --help 不显示子命令,或运行时提示 lock events not supported。
- 确认内核配置:
zcat /proc/config.gz | grep CONFIG_LOCK_STAT(若没压缩则查/boot/config-$(uname -r)),必须为y - 确认 perf 是否启用 lock:运行
perf list | grep lock,应看到类似lock:lock_acquire的 tracepoint - 若无 lock 相关事件,需进入内核源码目录(如
/lib/modules/$(uname -r)/build),执行make -C tools/perf重新编译perf - 替换系统
perf:通常新二进制在tools/perf/perf,建议用绝对路径调用,避免和系统自带版本混淆
perf lock record 怎么抓到真实锁竞争数据
直接跑 perf lock record ./my_cpp_program 很可能什么也抓不到——锁事件是 tracepoint,只在 kernel space 触发,而 C++ 程序的锁操作(如 pthread_mutex_lock)最终会落到 futex 或 spinlock 系统调用上,但不是所有锁路径都走 tracepoint。
关键点在于:只有内核态锁原语(如 mutex_lock, rwsem, spin_lock)且被 CONFIG_LOCK_STAT 覆盖的才会上报;用户态 pthread 实现是否触发这些 tracepoint,取决于 glibc 版本和锁类型。
立即学习“C++免费学习笔记(深入)”;
- 优先测自旋锁和内核模块锁:它们更可能触发
lock:lock_acquire等事件 - 对 pthread_mutex,确保使用的是
PTHREAD_MUTEX_DEFAULT或PTHREAD_MUTEX_ERRORCHECK,而非PTHREAD_MUTEX_ADAPTIVE_NP(后者可能绕过 kernel lockstat) - 加
-a选项捕获全系统锁事件,避免只录主线程;若目标明确,可用-p $(pidof my_program) - 不要依赖单次短运行:锁争用是概率事件,建议让程序稳定运行 >10 秒,并重复多次验证
perf lock report 输出里哪些字段真正反映竞争强度
perf lock report 默认输出表格含 acquire、contended、wait_total、wait_max 等列,但容易误读。
真正说明「热点锁」的是:contended 高 + wait_total 高 + wait_max 显著大于平均值。单看 acquire 次数没意义——一个锁被无竞争地获取百万次,不构成瓶颈。
-
contended是发生等待的次数,不是「尝试获取失败」次数,而是「至少等待了一次」的 acquire 计数 -
wait_total单位是纳秒,但实际精度受 tracepoint 开销影响,仅作相对比较;若某锁wait_total占比 >30%,基本可定位为瓶颈 -
name列常显示[unknown]:这是符号未解析导致,需确保编译时加-g,且perf运行时能访问到你的可执行文件(别 strip,别移动) - 注意锁名重复:比如多个
std::mutex实例可能都显示为mutex,需结合调用栈(加-g启用 call-graph)或源码位置判断具体是哪个实例
对比 sched:sched_stat_blocked 才能看出锁是否真卡住线程
perf lock 只告诉你「锁被争用」,但无法区分是短暂等待还是长时间阻塞。很多情况下,高 contended 对应的是微秒级等待,而真正的吞吐下降来自毫秒级阻塞——这得靠调度事件来交叉验证。
运行:perf record -e sched:sched_stat_blocked,sched:sched_switch -g -p $(pidof my_program),再用 perf report --sort comm,dso,symbol 查看 blocked 时间分布。
- 若某个函数在
perf lock report中 contended 高,又在sched_stat_blocked报告中对应大量 blocked 时间,则基本锁定为真实瓶颈 - 若 lock 报告有争用,但 sched 报告里 blocked 时间极低,大概率是锁粒度细、竞争激烈但延迟可控,优化收益有限
- C++ 中
std::shared_mutex的 reader-writer 场景,常出现 lock 报告里rwsemcontended 高,但 sched blocked 低——说明 reader 多、writer 少,属正常模式
perf lock 的数字和代码里那个 std::mutex mtx; 实例准确对应上;没有调试符号、没有调用栈、没有 sched 事件交叉验证,很容易对着一个泛化的 [unknown] 锁名空转。


















