你是一家火爆餐厅的老板,最近出菜越来越慢,客人怨声载道。后厨几十位厨师忙得脚不沾地,可你根本说不清谁在偷懒、哪一步卡了壳。这时你请来一位“效率侦探”——他站在厨房角落,每隔几秒快速扫视全场,手里秒表不停记录:此刻张厨子正在切菜、李厨子正盯着锅发呆、王厨子跑了一趟储藏室拿酱油……一天下来,他把这些“瞬时快照”汇总统计:炒菜环节占 60%、备菜占 25%、“等锅开”空转占 15%——元凶当场现形。这位效率侦探,就是 Linux 内核自带的性能剖析工具 perf。它能深入到 CPU 硬件事件级别,零侵入地观察程序运行,是系统性能调优当之无愧的“瑞士军刀”。从今天起,你也能学会用它,在线上系统卡顿时三分钟锁定元凶。

岗位关联

对 AI 从业者而言,模型训练、推理服务、数据管道的性能瓶颈排查无一不需要系统级剖析能力。掌握 perf,等于给你的职业工具箱配上一把能直插 CPU 内核的“诊断探针”,让性能调优从玄学变成科学。

目录
  1. 可视化演示
  2. perf工具概览
  3. 采样vs计数:两种侦查手法
  4. 常用性能事件:侦探的线索清单
  5. perf top:厨房中央的实时大屏
  6. record与report:深夜回放的工作日志
  7. 火焰图与调用图:把时间堆成金字塔
  8. CPU瓶颈定位:揪出霸占灶台的厨师
  9. 内存瓶颈定位:储藏室与备菜台的管理学
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

动态演示Linux perf性能剖析的核心机制,通过输入/处理/存储/输出四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Linux perf性能剖析:perf perf采样原理与硬件事件模型 perf top实时热点分析 核心机制可视化 Linux perf性能剖析整体架构与关键组件

perf工具概览

老板绕着后厨转了三圈,看着侦探打开工具箱:一把放大镜、一块秒表、一本泛黄的记录本、一部对讲机。装备看着朴素,侦探却一脸自信:“我不用打扰任何一位厨师,只看、只记、只算,就能告诉你灶台背后的秘密。” Linux 的 perf 正是这位效率侦探的完整工具箱。

perf 由两部分组成:内核态的性能剖析子系统 perf_events,以及用户态的一族命令行工具。perf_events 像侦探的“感官”,能读取 CPU 硬件内置的性能计数器(PMC)——这些计数器是芯片在流水线上替你数数的硬件电路,几乎零成本地记录 CPU 周期、指令数、缓存失效等事件;同时它也支持软件事件和内核 tracepoint(内核代码里的探针点)。perf 命令族则是“大脑”,负责把海量事件整理成人能读懂的报告。

为什么说它是“瑞士军刀”?因为它零侵入:不需要改动目标程序,不需要重新编译,几乎所有 Linux 发行版内核都自带。代价是它自己也要吃一点 CPU,这个比例就是剖析开销率。好的剖析工具应该像侦探一样来去无声:

perf 命令族的分工也像侦探团队的岗位:perf top 站岗放哨,perf stat 登记台账,perf record 录下全程,perf report 深夜复盘。老板听得入神:“那快让我们的后厨开开眼吧。”侦探微微一笑,从对讲机里喊出一句话——先记账,再盯梢。

剖析开销率=工具自身CPU开销系统总CPU时间×100%\text{剖析开销率} = \frac{\text{工具自身CPU开销}}{\text{系统总CPU时间}} \times 100\%
  1. 分子——工具自身CPU开销perf 在采样记录、整理数据时消耗的 CPU 时间。采样频率调得越高、记录调用栈越深,这个值就越大——好比侦探在后厨来回走动、不停翻本子,也会占用走廊空间。
    工具自身CPU开销≈采样频率×单次采样成本\text{工具自身CPU开销} \approx \text{采样频率} \times \text{单次采样成本}
  2. 分母——系统总CPU时间被剖析程序的全部 CPU 时间,相当于所有厨师加起来的工时时长。
  3. 比值再乘100%把开销换算成直观百分比。性能调优的经验是压在 5% 以下,超过这个数,侦探的脚步声就会盖过炒菜声,数据失真。

采样vs计数:两种侦查手法

侦探干活的第一晚,先立两条规矩。第一条是“台账法”:派个助手守在灶台边,每炒一锅记一笔,一天下来告诉你“今天总共炒了 320 锅、用了 200 斤油”。第二条是“快照法”:他自己每隔几十秒扫一眼后厨,在记录本上飞快写下此刻每个厨师在干什么,一天下来统计这些快照,得出“张厨子有 60% 的时间在炒菜、15% 的时间在等锅开”。

在 perf 里,记账本式的做法叫计数模式,对应 perf stat 命令。它直接读取硬件计数器,得到的是确定精确的累加总量:某段时间里执行了多少条指令、发生了多少次缓存失效。优点是开销极小、结果精确;缺点是没有“分布”——知道张厨子炒了 320 锅,却不知道哪道菜最费时。

快照法则对应采样模式,也就是 perf record + perf report 的组合。perf 每隔固定时间(比如 1 毫秒)触发一次中断,记录 CPU 此刻正在执行的函数和调用栈。一次次快照累积起来,就形成了对程序时间分布的统计推断。如果总共采样 N 个点,其中 n_i 个落在函数 i 上,那么函数 i 的耗时占比约等于 n_i / N:

回到后厨,台账法适合用量说话的场合——“今晚出菜两百道”;快照法适合查分布——“原来红烧肉这道菜占了大厨师一半工时”。高手过招,两种手法常常配合出牌。

T^i=niN×Ttotal\hat{T}_i = \frac{n_i}{N} \times T_{\text{total}}
  1. n_i——落在函数 i 的样本数采样点中恰好在执行函数 i 的次数。函数执行得越久、被采样到的概率就越大。
  2. N——总样本数整个采样过程的全部样本点数量。样本越多,推断越接近真实比例。
  3. T_total——总耗时被剖析程序的完整时间窗,乘以占比就得到该函数的估算耗时。
  4. \hat{T}_i——估算值帽子符号表示“估计值”,因为采样本质是概率推断,不是精确测量。

常用性能事件:侦探的线索清单

侦探的办案夹里贴着一张“异常行为清单”:厨师频繁掀锅盖说明锅不热,频繁跑储藏室说明备菜台太小,上菜顺序总变说明分工混乱。对 perf 来说,这套清单就是它能监听的事件列表,每一条都对应 CPU 或内核里的一个可观测信号。

最常用的四类事件。CPU 周期(cpu-cycles):灶台的火苗跳动次数,对应 CPU 实际消耗的时间;指令数(instructions):厨师一共颠了多少次勺,对应程序执行的指令总量。两者一除,就得到 IPC(每周期指令数)——好比“一次颠勺能炒熟几片菜”,反映 CPU 流水线利用得是否充分:

另外两类线索是缓存事件和调度事件。缓存失效(cache-misses):厨师去备菜台却没找到食材,必须跑储藏室;上下文切换(context-switches):厨师刚切到一半被叫去帮忙做别的菜,过一会儿又回来——切换本身不产出任何菜,还把手艺打断了。perf 把 branches(分支预测)、page-faults(缺页)等几十种事件也一并收纳,具体用哪一种,取决于你想查哪条线索。侦探合上记录本说:线索再多,也要靠工具去实时观察,这就该 perf top 上场了。

IPC=NinsNcyc\text{IPC} = \frac{N_{\text{ins}}}{N_{\text{cyc}}}
  1. N_ins——指令数程序实际执行完成的指令条数,厨师有效颠勺的次数。
  2. N_cyc——CPU周期数CPU 时钟跳动的总次数,相当于灶台火苗跳动的总次数。
  3. 两者相除每个周期能执行几条指令。IPC 越高说明流水线越健康,越低说明中间藏着等待、停顿或无效空转。

perf top:厨房中央的实时大屏

侦探在后厨挂了一面大屏,上面实时滚动着所有厨师的“灶台占用排行”:排名第一的厨师名字后面跟着一个跳动的百分比,每秒钟刷新一次。老板一眼就能看出,那个叫“张厨子”的人一直霸着灶台 40% 的时间——不用等下班,当场就能找他谈话。perf top 就是这面大屏。

perf top 的工作方式是对全系统(或指定进程)做持续采样,把当前开销最大的函数实时排序展示。它的输出第一列是 Overhead(开销占比),后面跟着进程名、共享对象、符号名。常用的姿势有几种:perf top -p 1234 只看指定进程;-K 只看内核态、-U 只看用户态;--sort comm,dso 可以按进程或模块聚合,快速判断是业务代码还是第三方库在烧 CPU。

这面大屏的每一个百分比背后,都是采样统计在支撑:当前窗口内,落在该函数上的样本数占总样本数的比例:

侦探提醒老板:大屏适合“抓现行”,但张厨子的 40% 到底是自己切菜慢,还是他不停被叫去拿酱油导致的?要查清来龙去脉,光看大屏不够,得把整个过程录下来复盘——这就是 perf record 和 perf report 的活。

self%=NselfNtotal×100%\text{self\%} = \frac{N_{\text{self}}}{N_{\text{total}}} \times 100\%
  1. N_self——该函数自身的采样数采样点中直接落在这个函数里的次数,不包含它调用子函数的时长(自耗时)。
  2. N_total——总采样数当前界面刷新窗口内的全部样本。
  3. 乘以100%换算成 Overhead 百分比。大屏默认按这个值降序排列。

record与report:深夜回放的工作日志

白天大屏上看到张厨子占用率异常,侦探不急着下结论。他从兜里掏出一台行车记录仪,挂在后厨门口,录了半小时的完整视频。晚上打烊后,他回办公室一格一格回放:张厨子 40% 的时间里,有 25% 是在“把菜从 A 桌端到 B 桌”的路上——问题根本不在切菜。perf record 就是这台行车记录仪,perf report 是播放器。

实际动手时,一行命令就能录制:

-F 99 表示每秒采样 99 次(这个数字是经验值,下文细说);-g 记录调用栈;-p 指定进程;sleep 30 控制录制时长。录制结束后,当前目录会生成 perf.data 文件,然后 perf report 打开它,进入交互界面:按 + 键展开调用链,按回车进入 perf annotate 对热点指令逐行标注。你采集的总样本数由采样频率和时长共同决定:

侦探还补充了一招:perf script 可以把 perf.data 导出成纯文本调用栈,方便脚本二次处理——这正是生成火焰图的前置步骤。他拍拍老板的肩膀:“日志已经拿到,明天我给你们画一张一眼就懂的金字塔。”

Nsample=fs×TrunN_{\text{sample}} = f_s \times T_{\text{run}}
  1. f_s——采样频率每秒触发的采样次数。-F 99 中的 99 就是频率,一般取 50~200 之间。
  2. T_run——录制时长-- sleep 30 让录制持续 30 秒。
  3. N_sample——样本总量频率乘以时长,得到本次录制的总样本数。样本越多,统计推断越稳。
bash1 行
perf record -F 99 -g -p 1234 -- sleep 30

火焰图与调用图:把时间堆成金字塔

侦探把后厨的录像逐帧拆开,按“做菜工序”层层堆叠,画出一座金字塔:底层是“出菜主流程”,往上一层是“备菜阶段”,再往上是“切菜”“焯水”“装盘”,每一层的宽度代表这个环节占用了多少时间。老板看了一眼就惊呼——原来金字塔里最宽的那一层,不是炒菜,而是“反复打开冰箱确认食材还有没有”。这座金字塔就是火焰图。

火焰图由 Brendan Gregg 发明,是性能剖析可视化的标配。生成流程不复杂:先用 perf record -g 拿到带调用栈的采样数据,再用 perf script 导出文本,接着用 FlameGraph 工具集里的 stackcollapse-perf.pl 压平调用栈,最后 flamegraph.pl 渲染出 SVG。火焰图横轴是时间占比(注意不是时间线),纵轴是调用栈层次,每个矩形的宽度正比于该函数在总耗时中的占比。第 k 层某个函数的矩形宽度就是所有包含它的调用栈样本时间之和:

调用图(call graph)则是另一视角:它用树形结构展示“谁调用了谁、各自累加花了多少时间”,在 perf report 里按 g 键就能切换。看火焰图有个口诀:宽的是胖子、尖的是深井——矩形特别宽说明这个函数自身消耗巨大,特别尖说明调用栈很深。侦探在金字塔上圈出最宽的那一块,转身对老板说:CPU 和内存的元凶,就藏在形状里。

wk=∑i∈Sktiw_k = \sum_{i \in S_k} t_i
  1. w_k——第 k 层矩形的宽度火焰图中一个函数块的总宽度,代表它占用的总时间比例。
  2. i ∈ S_k——包含该函数的所有调用栈样本凡是调用链途经这个函数的采样点都算进来,无论它是被谁调用的。
  3. t_i——单个样本代表的时间片每个样本对应一小段时间,累加起来就是该函数的真实耗时。

CPU瓶颈定位:揪出霸占灶台的厨师

老板盯着金字塔最宽的那层,发现上面写着“张厨子 + 频繁取酱油”。他问侦探:灶台明明每个都在冒火,为什么出菜还是慢?侦探把录像摊开,指着几个画面说:瓶颈分三种——张厨子自己炒得慢(用户态热点)、张厨子老被喊去帮忙(内核态调度与系统调用)、或者张厨子霸着灶台不走导致别人干等(锁竞争)。CPU 瓶颈的定位,就是先分清这三种。

用户态热点看 perf top 或 perf report 的 self 列,一眼找到自耗时最高的业务函数;如果 Top 榜被 sys_ 开头或 kworker 占据,说明问题在内核态。系统调用频繁的表现是 perf stat 中 context-switches 和 syscalls 数量极高——程序像一只在灶台和储藏室之间反复横跳的兔子。多核负载不均可以用 perf report --sort cpu 看样本是否集中在个别核心上。衡量瓶颈严重程度,就看热点函数占用的时间比例:

定位之后要对症下药:用户态热点就优化算法或加缓存;系统调用频繁就减少小 IO、改用批处理;锁竞争则考虑无锁数据结构或降低锁粒度。老板恍然大悟:“原来不是厨师偷懒,是派工方式出了问题。” 侦探点头,又指向另一叠数据——别忘了,还有一批厨师是“跑储藏室跑断腿”,那是内存的账。

Uhot=ThotTtotal×100%U_{\text{hot}} = \frac{T_{\text{hot}}}{T_{\text{total}}} \times 100\%
  1. T_hot——热点函数累计耗时从采样报告里统计出的“霸灶台”总时间。
  2. T_total——总采样时间全部样本覆盖的总时长。
  3. 两者比值乘100%得到热点占用率。超过 50% 基本可以认定是该函数的锅;结合调用链看是它自己在忙,还是被高频调用拖累。

内存瓶颈定位:储藏室与备菜台的管理学

后厨还有一条隐形瓶颈:储藏室(主存)和备菜台(CPU 缓存)之间那几十米的走廊。厨师每次去储藏室拿一趟食材,来回要半分钟;如果备菜台准备得充分,根本不用跑。性能优化里最经典的画面,就是程序的数据在内存和缓存之间搬运——搬运成本往往比加工成本还高。

perf stat 里和内存相关的核心指标有两个:cache-references(访问缓存的次数)和 cache-misses(缓存没命中的次数)。缓存命中率就是备菜台直接找到食材的概率:

内存瓶颈的另一面是页错误(page-faults):程序首次访问某块内存或频繁申请释放内存时,内核要忙着分配页表,就像储藏室管理员每次都要重新翻找钥匙。perf record -e page-faults 能精确采样到是哪一行代码在频繁分配内存。更细的活儿可以上 perf mem record,它能记录内存访问的延迟分布,定位是“读慢”还是“写慢”,是访问栈还是访问堆。内存带宽告急时,perf stat -e mem-loads,mem-stores 能看到读写指令的总吞吐——相当于观察储藏室走廊每分钟有多少趟搬运。

修复手段通常是三板斧:改善数据局部性让命中率回升、用对象池减少重复分配、用大页(HugePages)降低页表压力。侦探合上记录本,总结道:CPU 瓶颈是“谁在忙”,内存瓶颈是“谁在等”。 两条线都查清了,性能元凶就没有藏身之处。

命中率=NhitNhit+Nmiss×100%\text{命中率} = \frac{N_{\text{hit}}}{N_{\text{hit}} + N_{\text{miss}}} \times 100\%
  1. N_hit——缓存命中次数厨师在备菜台直接找到食材的次数。
  2. N_miss——缓存失效次数备菜台没有,必须跑储藏室的次数。
  3. 分母是两者之和总共的缓存访问次数。命中率低于 90% 就要警惕数据局部性问题。

AI 应用场景

大模型推理服务CPU飙高排查

阶段:模型服务部署与性能调优

解决的问题:推理服务上线后 CPU 居高不下、P99 延迟恶化,传统做法是盲猜“是不是 GPU 没吃满”或“是不是并发设太高”。用 perf 可以精准回答:CPU 到底烧在 tokenizer、注意力计算还是 Python 推理框架的调度开销上。

具体案例:某团队部署 LLM 服务时发现单机 CPU 打满但吞吐不升。perf top -p <pid> 看到 tokenize 占 38%,perf record -g 后发现是未启用缓存导致每次请求重复分词;修复后 CPU 下降一半,吞吐翻倍。

GPU训练数据管道瓶颈定位

阶段:数据加载与预处理管线

解决的问题:数据加载器(DataLoader)占用大量 CPU,导致 GPU 饿肚子等待。perf 能定位是图像解码、数据增强还是磁盘读取在烧 CPU,从而决定用内存缓存还是换压缩格式。

具体案例:训练 ResNet 时 GPU 利用率只有 40%,perf record -F 99 -g -p <进程> 后火焰图显示 libjpeg 解码占 55% 耗时,换用 TFRecord 预解码后 GPU 利用率升至 90%。

微服务性能回归门禁

阶段:CI/CD 质量保障

解决的问题:代码合并后性能悄悄退化,等到上线才发现。把 perf stat 固化在 CI 里,对关键微基准采集 IPC、缓存命中率、上下文切换次数,超过阈值即拦截合并。

具体案例:某公司每次 PR 触发 perf stat -e cycles,instructions,cache-misses,context-switches 跑一组微基准,IPC 下降超 10% 自动告警,成功拦截过三次由无锁队列误用引入的性能回退。

Python 演示

python42 行
import random # 模拟系统中几个热点函数, 每个有自己的真实耗时占比(权重)hotspots = {    "do_parse": 45,      # 解析请求占45%    "memcpy_data": 25,   # 拷贝数据占25%    "lock_wait": 18,     # 锁等待占18%    "do_sleep": 7,       # 睡眠占7%    "other": 5           # 其他占5%}  def simulate_sampling(total_samples=10000):    """模拟perf采样: 按权重随机抽取样本, 统计占比"""    counts = {name: 0 for name in hotspots}     for _ in range(total_samples):        name = random.choices(            list(hotspots.keys()),            weights=list(hotspots.values()),            k=1        )[0]        counts[name] += 1     print("=== 采样统计结果 ===")    print(f"{'函数':<12} {'采样数':>6} {'估算占比':>8}  柱状图")    total = total_samples    ranked = sorted(counts.items(), key=lambda kv: kv[1], reverse=True)    for name, cnt in ranked:        ratio = cnt / total * 100        bar = "#" * int(ratio / 2)        print(f"{name:<12} {cnt:>6} {ratio:>7.2f}%  {bar}")     print("\n=== 估算值与真实权重对比 ===")    for name, real in hotspots.items():        est = counts[name] / total * 100        diff = abs(est - real)        print(f"{name:<12} 真实{real:>5.1f}% 估算{est:>6.2f}% 偏差{diff:>5.2f}%")  if __name__ == "__main__":    simulate_sampling(10000)
目的:用随机采样模拟 perf 的工作机制,直观展示“采样次数足够多时,估算占比会收敛到真实占比”,帮助理解性能剖析的统计学本质。
  1. counts = {name: 0 for name in hotspots}初始化采样计数器,相当于 perf 内部为每个函数维护一个样本计数。
  2. random.choices(..., weights=..., k=1)按权重做一次随机采样,模拟 perf 每帧“咔嚓”一下随机命中正在执行的热点函数。
  3. ranked = sorted(counts.items(), key=lambda kv: kv[1], reverse=True)按采样次数降序排列,复现 perf top 的实时热点排行榜逻辑。
  4. ratio = cnt / total * 100计算估算占比,对应正文中的采样统计推断公式 n_i / N。
  5. bar = "#" * int(ratio / 2)用字符串绘制柱状图,呼应火焰图“宽度越宽越耗时”的可视化思想。

常见误区

误区perf report 给出的百分比是精确的,函数显示 40% 耗时它就真的花了 40% 时间,不用怀疑。

正解采样是统计推断,不是全量测量。就像侦探只扫了几百眼厨房就推断各环节占比,样本量不够时误差会很大。-F 99 录 30 秒约有 3000 个样本,对热点函数足够可靠;但如果某个函数只执行了 10 毫秒,很可能一个样本都落不上去,直接“隐形”。结论:样本量越大越可信,小占比数字要谨慎解读。

为何常见:perf 界面直接显示百分比,看起来像精确统计,初学者很容易忽略它背后的抽样本质。

误区perf 必须用 sudo 跑,普通用户一敲 perf top 就报权限错误,所以非 root 没法做性能剖析。

正解Linux 内核提供了 perf_event_paranoid 参数控制访问级别。<=3 时用户可以采样自己的进程用户态事件;<=2 时只能访问用户态;<=1 才放开内核态事件访问。很多发行版默认值允许普通用户剖析自己的进程,只是系统范围采样和内核态事件需要 root。建议:先跑 cat /proc/sys/kernel/perf_event_paranoid 看看自己机器的门槛。

为何常见:网上教程为了省事统一写 sudo,加上共享机器上确实常常需要 root 权限采内核事件,让大家误以为这是硬性要求。

误区为了测得准,把 `-F` 设成 99999,反正 computer 快,多采点没坏处。

正解采样频率越高,perf 自身产生的剖析开销越大(见第一节的开销率公式),高到一定程度工具本身就变成了干扰源,测出来的性能反而是“被 perf 拖慢后的性能”。还有一个隐蔽坑:100Hz 恰好可能和系统的调度周期或定时器产生共振,导致采样点集中在特定状态。Brendan Gregg 推荐的 99Hz 就是为了避开共振的取舍。

为何常见:“多多益善”的直觉迁移到了采样频率上,忽略了剖析工具自身也有开销。

误区跑完 `perf record` 就自动生成火焰图了,或者以为 perf report 里那张图就是火焰图。

正解perf 本身只产生 perf.data 和文本格式的调用栈,火焰图需要两件套:Brendan Gregg 的 FlameGraph 脚本仓库 + 管道处理。完整链路是 perf record -g → perf script > out.perf → stackcollapse-perf.pl out.perf | flamegraph.pl > flame.svg。这个管道里每一步都有独立的生态工具。

为何常见:火焰图太出名,教程又往往把 perf 和火焰图放在一起讲,让人误以为它们是一体的。

误区perf top 里排第一的函数就是罪魁祸首,把它优化掉性能就好了。

正解热点排名(self%)只代表“这个函数自身占了很多 CPU”,但它为什么占了这么多,可能是它被上层高频调用、也可能它在等锁等 IO。比如一个看似很忙的 hash_lookup,真相是上层循环里多了一层无意义重复调用——改 hash_lookup 本身没用,砍掉那层循环才有用。所以必须结合调用链(callchain)顺藤摸瓜,看热点的上游是谁、下游在等什么。

为何常见:perf top 默认界面按 self 排序,第一眼看到的就是占比最高的函数,大脑会自动把它判为“元凶”。

面试题

Q1. perf 工具的核心作用是什么?

单选题 · easy

  • A.监控服务器网络流量分布
  • B.剖析CPU与硬件事件性能← 正确答案
  • C.管理Linux内核模块加载
  • D.搭建Web应用服务器集群

答案:B。perf 是 Linux 内核自带的性能剖析工具,核心价值是剖析 CPU 与硬件级性能事件,如周期、缓存失效、上下文切换等。就像效率侦探记录后厨每个动作;网络流量、模块管理、Web 服务都不是它的职责。

Q2. 下列哪个命令用于实时刷新热点函数排行?

单选题 · easy

  • A.perf record命令
  • B.perf report命令
  • C.perf top命令← 正确答案
  • D.perf stat命令

答案:C。perf top 相当于后厨实时大屏,持续采样并把当前开销最大的函数动态排序刷新;perf record 是录制、perf report 是回放、perf stat 是统计总量,都不是实时热点排行。

Q3. perf record 与 perf report 配合的工作原理是什么?

单选题 · mid

  • A.全量记录所有函数指令
  • B.按频率采样做统计推断← 正确答案
  • C.修改内核代码动态插桩
  • D.模拟执行目标程序流程

答案:B。record 按固定频率(如 99Hz)打断 CPU,记录当前执行的函数和调用栈,这本质是采样;report 基于样本做统计推断,估算各函数耗时占比。它不打断全部指令、不改内核、不模拟执行,所以选 B。

Q4. IPC(每周期指令数)偏高通常说明什么?

单选题 · mid

  • A.缓存未命中率非常严重
  • B.CPU流水线利用较充分← 正确答案
  • C.系统内存容量严重不足
  • D.磁盘每秒读写次数过多

答案:B。IPC = 指令数 / CPU周期数,衡量每个时钟周期完成多少条指令。IPC 高说明 CPU 流水线被塞得满、等待少,类似颠勺一次就炒熟好几片菜,是健康信号。缓存失效严重会让 IPC 偏低而非偏高。

Q5. 下列哪些属于 perf 的常用性能事件?

多选题 · mid

  • A.cpu-cycles周期计数事件← 正确答案
  • B.cache-misses缓存失效事件← 正确答案
  • C.context-switches切换事件← 正确答案
  • D.tcp-retrans丢包统计事件

答案:ABC。cpu-cycles、cache-misses、context-switches 都是 perf 内置的核心事件,分别对应灶台火苗、备菜台失手、厨师频繁换岗。tcp-retrans 属于网络子系统统计,不在 perf 主流事件清单中。

Q6. perf report 默认读取的数据文件是哪个?

单选题 · easy

  • A.report.txt文本文件
  • B.perf.data数据文件← 正确答案
  • C.perf.rpt报告文件
  • D.output.log日志文件

答案:B。perf record 录制结束后会在当前目录生成 perf.data,perf report 默认读取这个文件进行回放分析,相当于行车记录仪的内存卡。report.txt、perf.rpt、output.log 都不是 perf 的默认产物。

Q7. 火焰图中矩形宽度代表什么?

单选题 · mid

  • A.函数代码行数的多少
  • B.函数在总耗时中的占比← 正确答案
  • C.函数被调用的次数多少
  • D.函数自身内存占用大小

答案:B。火焰图横轴是时间占比(所有矩形加总为 100%),矩形越宽代表该函数在总耗时中占比越高。它不反映代码行数、调用次数或内存占用。宽度与调用次数有关联但不等价,因为单次耗时才是核心。

Q8. 定位缓存未命中热点可以怎么做?

多选题 · hard

  • A.perf stat统计缓存失效次数← 正确答案
  • B.perf record跟踪该具体事件← 正确答案
  • C.查看调用链定位代码位置← 正确答案
  • D.通过BIOS直接禁用硬件缓存

答案:ABC。先用 perf stat 看 cache-misses 总数确认问题存在,再用 perf record -e cache-misses --call-graph 采样该事件,结合调用链定位到具体代码。BIOS 禁用缓存是危险操作且无法定位热点,显然不可取。

Q9. 上下文切换频繁通常暗示什么问题?

单选题 · mid

  • A.CPU主频设置得过高了
  • B.锁竞争或线程数量过多← 正确答案
  • C.磁盘可用空间即将耗尽
  • D.网络带宽被占满导致拥塞

答案:B。上下文切换频繁说明线程反复被切换调度,常见诱因是锁竞争导致阻塞、线程数远超核心数、或频繁的 IO 等待。就好比厨师做每道菜都要被人叫走换岗,做菜效率自然低;它与 CPU 主频、磁盘、网络无关。

Q10. 关于 perf 采样模式的说法,哪些是正确的?

多选题 · hard

  • A.采样本质是统计推断方法← 正确答案
  • B.采样频率越高工具开销越大← 正确答案
  • C.采样数据无法还原性能真相
  • D.默认的99Hz是常用经验值← 正确答案

答案:ABD。采样是统计推断,样本足够时能逼近真相,样本不足时会漏掉短耗函数,所以 C 的说法太绝对。采样频率越高开销越大,99Hz 是 Brendan Gregg 提出的经典经验值,能避开系统调度共振。故选 A、B、D。