直接用perf采集内核态调用栈并生成火焰图即可清晰识别吃cpu的内核函数,关键在于确保权限和内核调试符号可用;若缺失vmlinux或debuginfo,内核函数将显示为[unknown]或地址,需安装对应debuginfo包,并用sudo perf report验证是否可见do_syscall_64等真实函数名。

直接用 perf 采集内核态调用栈,再生成火焰图,就能清晰看到哪些内核函数在吃 CPU。关键不是“能不能看内核”,而是采样时要让 perf 捕获到内核路径——默认就支持,只需确保权限和符号可用。
确认内核调试信息已安装
没有 vmlinux 或内核 debuginfo,火焰图里内核函数会显示为 [unknown] 或地址,无法识别。需补全:
- Ubuntu/Debian:
sudo apt install linux-image-$(uname -r)-dbgsym
- CentOS/RHEL:
sudo debuginfo-install kernel-$(uname -r)
验证方式:
sudo perf report -F comm,symbol --sort comm,symbol | head -20,若能看到do_syscall_64、cpuidle_enter、__schedule等真实函数名,说明符号已就位。
linux-sysadmin下载Linux系统管理专家,覆盖12大模块:用户权限、SSH、存储、网络、systemd、防火墙、日志监控、备份恢复、TLS证书、Ansible、容器、IaC。提供配置、验证、加固、监控、备份、自动化、故障排查、回滚闭环。关键词:useradd、sudo、sshd_config、chmod、SEL...
采集含内核路径的完整调用栈
对目标进程(如 PID 1234)采样 30 秒,强制包含内核态回溯:
sudo perf record -F 99 -p 1234 -g --call-graph dwarf -- sleep 30
-
-g启用调用图(必须) -
--call-graph dwarf比默认fp(frame pointer)更可靠,尤其在内核栈被优化截断时仍能还原深度 - 不加
--user-only(该选项会过滤掉内核函数)
生成火焰图并聚焦内核部分
按标准三步走后,在 SVG 中快速定位内核热点:
- 打开
flame.svg,用Ctrl+F搜索关键词:do_、sys_、entry_SYSCALL、__schedule、tcp_、ext4_、nvme_等 - 观察顶部宽幅大的“平顶”区域:若最上层是内核函数(如
native_queued_spin_lock_slowpath),说明瓶颈就在锁竞争;若是tcp_transmit_skb,可能网络发包过载 - 注意跨用户/内核边界的调用链:例如
myapp → write → vfs_write → __kernel_write → sock_sendmsg → tcp_sendmsg,整条链横轴越宽,越说明该路径整体耗时高
区分内核态 vs 用户态消耗
火焰图本身不标注“内核态”,但可通过函数命名判断:
- 用户函数通常带可执行文件名前缀(如
nginx:ngx_http_process_request) - 内核函数统一无前缀,常见开头:
do_、sys_、__do_、ext4_、btrfs_、i915_、nvme_、drm_ - 特别关注
swapper(idle 进程)、rcu_sched、ksoftirqd、kthreadd等内核线程的火焰——它们出现在系统级采样中(sudo perf record -C 0 -a -g -- sleep 30),反映全局调度或中断压力
必要时做系统级内核分析
如果问题表现为整体 CPU 飙高但找不到具体进程,直接抓全系统内核行为:
sudo perf record -F 99 -a -g --call-graph dwarf -- sleep 30
之后生成火焰图,重点看:
-
smp_call_function_single/smp_call_function_many:多核广播开销大 -
tick_nohz_idle_enter/cpuidle_enter:空闲态异常频繁进出,可能有定时器风暴 -
handle_irq_event/__handle_domain_irq:硬中断或软中断处理过载(如网卡收包太多)
不需要改代码、不用重启服务,一次采样 + 一张图,内核在哪吃 CPU 就一目了然。










