perf record(或其他性能分析工具)是如何选择将哪些指令计算为耗时的? perf record (或其他性能分析工具) 如何选择要计算时间成本的指令?

5

最近,我发现实际上perf(或pprof)可以在反编译视图中显示在没有实际花费这段时间的行附近的指令时序。实际花费这段时间的真正指令是它之前的指令。我知道这是由于CPU中指令流水线而发生的模糊解释。但是,我想找出以下内容:

  1. 是否有更详细的解释?
  2. 是否在perf或pprof文档中有记录?我没有找到任何参考资料。
  3. 是否有一种方法可以获取正确放置的时序?

2
我认为问题并不是直接来自性能,而是来自CPU。更根本地说,这与我们如何测量时间有关。事实上,现代CPU可以以乱序和并行的方式执行指令。如果像div这样的指令非常缓慢,但可以完全与其他指令重叠,我们应该怎么办?我们应该报告div是缓慢的还是免费的?如果一条指令因为只能在关键路径上的另一条指令之后执行而被严重延迟,我们该怎么办?如果这个指令包括一个延迟的内存访问,又该怎么办? - Jérôme Richard
1
通常情况下,CPU“归咎于”等待慢速产生结果的指令,而非产生该结果的指令,特别是缓存未命中加载。例如,在英特尔x86 CPU上可以看到这种情况,请参见Why is this jump instruction so expensive when performing pointer chasing?,这似乎还取决于在引发中断时允许ROB中的最后一个指令退休的影响。我不知道其他CPU设计是否会有任何重大差异,例如ARM或AMD,并且您没有打标签 [tag:intel-pmu] 或甚至没有提及x86。 - Peter Cordes
1个回答

5
简而言之,perf 通过使用CPU硬件性能计数器来记录事件,当计数器归零或达到阈值时,可以将其置于记录模式。这可能会引发中断或在内存缓冲区中写入事件(使用PEBS精确事件)。事件将包括CPU选择与事件关联的代码地址(即引发中断的点),即使对于像 cycles 这样的事件,也不像 instructions 一样固有地具有特定的指令相关联。当计数器溢出时,乱序执行后端可以有几百个指令正在运行,但必须为任何给定的样本选择一个指令。通常情况下,CPU“责怪”等待慢速产生结果的指令,而不是生成它的指令,尤其是缓存未命中加载操作。在某些情况下,比实际花费时间的指令要晚被责怪,可能有不同的原因,特别是对于异步发生的不核心事件。(例如uncore events)

3
Travis Downs对哪条指令将被选中进行了深入调查,详情可参见此处链接:https://travisdowns.github.io/blog/2019/08/20/interrupts.html - Noah
有没有关于在事件阈值后设置中断的文档链接? - Noah
@Noah:你说的“设置中断”是什么意思?是指如何编写一个内核,其中包含一个在PMU事件触发时被调用的中断处理程序,或者收集一个PEBS缓冲区满的事件吗?有一些轻量级的替代PAPI的选项,它们有自己的代码来实现这一点,作为内核模块。比如libpfm。 - Peter Cordes
是的,我猜这个逻辑在内核中的位置。但我还没有找到它。 - Noah
@Noah:如果你只是想重现Travis的结果(记录哪个指令被中断)以进行PMU触发的中断,perf record -e cycles或者ref_cycles基本上可以做到这一点,并且你可以使用perf选项手动配置阈值;你不需要安装自己的中断处理程序。但是出于好奇,抱歉我不知道具体在哪里查找。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接