【问题标题】:What are stalled-cycles-frontend and stalled-cycles-backend in 'perf stat' result?'perf stat' 结果中的停滞周期前端和停滞周期后端是什么?
【发布时间】:2014-04-05 14:17:13
【问题描述】:

有人知道性能统计结果中 stalled-cycles-frontendstalled-cycles-backend 是什么意思吗?我在互联网上搜索但没有找到答案。谢谢

$ sudo perf stat ls                     

Performance counter stats for 'ls':

      0.602144 task-clock                #    0.762 CPUs utilized          
             0 context-switches          #    0.000 K/sec                  
             0 CPU-migrations            #    0.000 K/sec                  
           236 page-faults               #    0.392 M/sec                  
        768956 cycles                    #    1.277 GHz                    
        962999 stalled-cycles-frontend   #  125.23% frontend cycles idle   
        634360 stalled-cycles-backend    #   82.50% backend  cycles idle
        890060 instructions              #    1.16  insns per cycle        
                                         #    1.08  stalled cycles per insn
        179378 branches                  #  297.899 M/sec                  
          9362 branch-misses             #    5.22% of all branches         [48.33%]

   0.000790562 seconds time elapsed

【问题讨论】:

  • 我不确定真正的问题是什么。在问 CPU 的前端和后端是什么?请仔细阅读high level introduction。这能回答你的问题吗?
  • 我搜索并搜索了一个类似的答案...这是我从英特尔找到的最有用的资源:@​​987654322@
  • 不,几乎没有人知道它们的真正含义。但是参考手册(如 Manuel Selva 的回答)和这篇文章(我还不完全理解)是我找到的最接近的:sites.utexas.edu/jdm4372/2014/06/04/…

标签: linux performance optimization computer-architecture cpu-architecture


【解决方案1】:

理论:

让我们从这个开始:现在的 CPU 是超标量的,这意味着它们每个周期 (IPC) 可以执行多条指令。最新的英特尔架构最多可支持 4 个 IPC(4 个 x86 指令解码器)。让我们不要将宏观/微观融合带入讨论以使事情变得更加复杂:)。

通常,由于各种资源争用,工作负载不会达到 IPC=4。这意味着 CPU 正在浪费周期(指令数量由软件给出,CPU 必须在尽可能少的周期内执行它们)。

我们可以将 CPU 花费的总周期分为 3 类:

  1. 指令停用的周期(有用的工作)
  2. 在后端花费的周期(浪费)
  3. 在前端花费的周期(浪费)。

要获得 4 的 IPC,循环退出的数量必须接近循环总数。请记住,在此阶段,所有微操作 (uOps) 从管道中退出并将其结果提交到寄存器/缓存中。在这个阶段,你甚至可以有超过 4 个 uOps 退出,因为这个数字是由执行端口的数量给出的。如果您只有 25% 的周期淘汰 4 uOps,那么您的总体 IPC 将为 1。

在后端停滞的周期是一种浪费,因为 CPU 必须等待资源(通常是内存)或完成长延迟指令(例如,超越 - sqrt、倒数、除法等.).

前端停滞的周期是一种浪费,因为这意味着前端不会为后端提供微操作。这可能意味着您在指令缓存中有未命中,或尚未在微操作缓存中解码的复杂指令。即时编译的代码通常会表达这种行为。

另一个停滞原因是分支预测未命中。这就是所谓的不良投机。在这种情况下,发出了 uOps,但由于 BP 预测错误,它们被丢弃了。

分析器中的实现:

您如何解释 BE 和 FE 停滞周期?

不同的分析器对这些指标有不同的方法。在 vTune 中,类别 1 到 3 加起来可提供 100% 的周期。这很合理,因为要么你的 CPU 停滞(没有 uOps 正在退休)要么它执行有用的工作(uOps)退休。在此处查看更多信息:https://software.intel.com/sites/products/documentation/doclib/stdxe/2013SP1/amplifierxe/snb/index.htm

在 perf 中,这通常不会发生。这是一个问题,因为当您看到 125% 的周期在前端停滞时,您不知道如何真正解释这一点。您可以将 >1 指标与有 4 个解码器的事实联系起来,但如果您继续推理,那么 IPC 将不匹配。

更好的是,你不知道问题有多大。 125% 什么?那么#cycles 是什么意思呢?

我个人对 perf 的 BE 和 FE 停滞周期有点怀疑,希望这会得到解决。

大概我们会从这里调试代码得到最终答案:http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/builtin-stat.c

【讨论】:

  • VTune 中使用哪些事件作为 FE 和 BE? Manuel 在 Sandy Bridge 上发布了 perf 的活动。有时解码器无法解码 4 条指令(realworldtech.com/sandy-bridge/4 - 有 3 个简单的解码器无法解码复杂的命令)。
  • 确实还有一个复杂的解码器,但它也可以解码简单的指令。我用 vTune 计数器的链接更新了我的帖子。它使用与 perf 相同的计数器,但我认为 vTune 的组合方式不同。
  • Vtune 使用 software.intel.com/en-us/articles/… "IDQ_UOPS_NOT_DELIVERED.CORE / SLOTS" 作为“前端绑定”和“1 - (前端绑定 + 停用 + 错误推测)”作为“后端绑定”,其中“停用 = UOPS_RETIRED.RETIRE_SLOTS / SLOTS”、“Bad Speculation=(UOPS_ISSUED.ANY – UOPS_RETIRED.RETIRE_SLOTS + 4*INT_MISC.RECOVERY_CYCLES) / SLOTS”和“SLOTS=4* CPU_CLK_UNHALTED.THREAD”,其中 4 等于“机器流水线宽度”。
  • 对于 Sandy Bridge,英特尔的优化手册 intel.com/content/dam/www/public/us/en/documents/manuals/… 在“B.3.2 分层自顶向下性能表征方法”中给出了相同的内容“%FE_Bound = 100 * (IDQ_UOPS_NOT_DELIVERED.CORE / N) ; %Bad_Speculation = 100 * ( (UOPS_ISSUED.ANY – UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES ) / N) ; %Retiring = 100 * ( UOPS_RETIRED.RETIRE_SLOTS/ N) ; %BE_Bound = 100 * (1 – (FE_Bound + Retiring + Bad_Speculation ) ) ; N = 4*CPU_CLK_UNHALTED.THREAD"
  • @osgx 谢谢。现在我们知道这些指标在 vTune 中的含义是什么,它们加起来是 100%。下一个问题是为什么 perf 计算它们的方式不同?是bug还是背后有什么意义?
【解决方案2】:

要将 perf 导出的通用事件转换为您可以运行的 CPU 文档原始事件:

more /sys/bus/event_source/devices/cpu/events/stalled-cycles-frontend 

它会显示类似的东西

event=0x0e,umask=0x01,inv,cmask=0x01

根据Intel documentation SDM volume 3B(我有核心i5-2520):

UOPS_ISSUED.ANY:

  • 在每个周期增加 RAT 向 RS 发出的 Uops 的数量。
  • 设置 Cmask = 1、Inv = 1、Any=1 以计算此内核的停滞周期。

对于在我的系统上转换为 event=0xb1,umask=0x01 的停滞周期后端事件,相同的文档说:

UOPS_DISPATCHED.THREAD:

  • 计算每个周期每个线程要调度的微指令总数
  • 设置 Cmask = 1,INV =1 以计算停顿周期。

通常,停滞周期是指处理器正在等待某些事情(例如,在执行加载操作后要供给内存)并且没有任何其他事情要做的周期。此外,CPU 的前端部分是负责获取和解码指令(将它们转换为 UOP)的硬件,而后端则负责有效地执行 UOP。

【讨论】:

  • 感谢您的回复。那么停滞和闲置有什么区别?
  • 停滞和空闲是一样的。 CPU 处于空闲状态,因为它因指令流水线没有移动而停止。
  • @Milind,不应该有区别吗,stalled应该是“我们不前进,因为下一阶段不允许它”,idle应该是“没有什么要处理的“?
【解决方案3】:

当流水线在此期间没有前进时,CPU 周期被“停止”。

处理器管道由许多阶段组成:前端是一组这些阶段,负责获取和解码阶段,而后端执行指令。前端和后端之间有一个缓冲区,所以当前者停止时,后者仍然可以做一些工作。

取自http://paolobernardi.wordpress.com/2012/08/07/playing-around-with-perf/

【讨论】:

  • 我们如何才能拥有比循环更多的停顿?
【解决方案4】:

根据这些事件的作者,它们定义松散,并由可用的 CPU 性能计数器近似。据我所知,perf 不支持基于多个硬件事件计算某些合成事件的公式,因此它不能使用英特尔优化手册(在 VTune 中实现)http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf 中的前端/后端停顿绑定方法@“ B.3.2 分层自上而下的性能表征方法"

%FE_Bound = 100 * (IDQ_UOPS_NOT_DELIVERED.CORE / N ); 
%Bad_Speculation = 100 * ( (UOPS_ISSUED.ANY – UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES ) / N) ; 
%Retiring = 100 * ( UOPS_RETIRED.RETIRE_SLOTS/ N) ; 
%BE_Bound = 100 * (1 – (FE_Bound + Retiring + Bad_Speculation) ) ; 
N = 4*CPU_CLK_UNHALTED.THREAD" (for SandyBridge)

正确的公式可以与一些外部脚本一起使用,就像在 Andi Kleen 的 pmu-tools (toplev.py) 中所做的那样:https://github.com/andikleen/pmu-tools(来源)、http://halobates.de/blog/p/262(描述):

% toplev.py -d -l2 numademo  100M stream
...
perf stat --log-fd 4 -x, -e
{r3079,r19c,r10401c3,r100030d,rc5,r10e,cycles,r400019c,r2c2,instructions}
{r15e,r60006a3,r30001b1,r40004a3,r8a2,r10001b1,cycles}
numademo 100M stream
...
BE      Backend Bound:                      72.03%
    This category reflects slots where no uops are being delivered due to a lack
    of required resources for accepting more uops in the    Backend of the pipeline.
 .....
FE      Frontend Bound:                     54.07%
This category reflects slots where the Frontend of the processor undersupplies
its Backend.

Commit 引入了stalled-cycles-frontend 和stalled-cycles-backend 事件,而不是原来的通用stalled-cycles

http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/commit/?id=8f62242246351b5a4bc0c1f00c0c7003edea128a

author  Ingo Molnar <mingo@el...>   2011-04-29 11:19:47 (GMT)
committer   Ingo Molnar <mingo@el...>   2011-04-29 12:23:58 (GMT)
commit  8f62242246351b5a4bc0c1f00c0c7003edea128a (patch)
tree    9021c99956e0f9dc64655aaa4309c0f0fdb055c9
parent  ede70290046043b2638204cab55e26ea1d0c6cd9 (diff)

perf 事件:添加通用前端和后端停滞周期事件定义 添加两个通用硬件事件:前端和后端停滞周期。

这些事件测量 CPU 正在执行代码但它的 能力没有得到充分利用。了解这种情况并 分析它们是代码优化工作流的一个重要子任务。

这两个事件都限制了性能:大多数前端失速往往是由 通过分支错误预测或指令获取缓存未命中,后端 停顿可能是由于各种资源短缺或效率低下造成的 指令调度。

前端停滞是更重要的:代码无法快速运行 如果指令流没有跟上。

过度使用的后端会导致前端停止,从而 也必须密切关注。

确切的组成是非常程序逻辑和指令混合 依赖。

我们松散地使用术语“stall”、“front-end”和“back-end”,并且 尝试使用来自特定 CPU 的最佳可用事件 近似这些概念。

抄送:Peter Zijlstra 抄送:阿纳尔多·卡瓦略·德·梅洛 抄送:弗雷德里克·韦斯贝克 链接:http://lkml.kernel.org/n/tip-7y40wib8n000io7hjpn1dsrm@git.kernel.org 签字人:Ingo Molnar

    /* Install the stalled-cycles event: UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */
-       intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES] = 0x1803fb1;
+       intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1;

-   PERF_COUNT_HW_STALLED_CYCLES        = 7,
+   PERF_COUNT_HW_STALLED_CYCLES_FRONTEND   = 7,
+   PERF_COUNT_HW_STALLED_CYCLES_BACKEND    = 8,

【讨论】:

  • 那么到底是perf出错了?因为 FE + BE + ?不要添加到已知的理论值,很难评估代码的问题有多大。当您看到 75% 的 FE 停滞时,需要将其与某些东西进行比较。说 100% 中的 75% 代码在 FE 或 BE 中停滞不前,这具有完全不同的含义和价值。据我所知,即使 toplev.py 也有同样的问题。如果这不是问题,我们如何解释这些指标?是什么使指标高或低?
  • VAndrei,你有关于 SandyBridge(+-1 代)的简短且可重复的示例吗?对于 FE > 100% 的 perf stat 和 toplev.py?我刚从简短的简单循环开始,并且有 3G 周期用于 3G 指令(1G 是具有 0.00% 未命中率的分支),具有 2G FE 停顿(perf stat)和 1G BE 停顿(IPC=1.00)。我认为问题在于正确定义复杂 OOO 核心的“停顿”,另一个是正确解释 toplev.py 结果。
  • 我在这里发布的代码:stackoverflow.com/questions/28961405/… 应该是前端绑定的。其中有很多分支未命中,因此会产生 FE 停顿。关于 BE bound,您需要一个等待 RAM 数据的工作负载。在缓冲区中分配 1/2 的物理内存大小并使用 LCG(就像在我的代码中一样)在缓冲区中的随机位置执行读取/修改/写入操作。除了 RMW 事务之外,这还会生成少量指令,并且内核将在 BE 中停止等待 RAM 数据。
  • 生成 FE 绑定的工作负载是一个相当大的挑战。请尝试分支微基准是否有效,但如果没有,您需要更复杂的东西。 FE 停顿将由大量指令高速缓存未命中产生。为了做到这一点,你需要一个大的代码,通过它有很远的跳转,以导致多个 I$ 未命中。在这一点上,我不知道如何在微基准测试中制作 FE 绑定的工作负载。
  • 我想你会对这个链接感兴趣:stackoverflow.com/questions/1756825/… 你可以使用一些讨论过的技术来刷新 I$,从而产生 FE 停顿。
猜你喜欢
  • 1970-01-01
  • 2018-10-23
  • 2020-02-26
  • 2016-07-18
  • 2013-11-14
  • 1970-01-01
  • 2018-07-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多