【问题标题】:Interpreting Intel VTune's Memory Bound Metric解读英特尔 VTune 的内存绑定指标
【发布时间】:2016-12-25 21:27:11
【问题描述】:

在我的工作负载上运行英特尔 VTune 时,我看到以下内容:

 Memory Bound                  50.8%             

我阅读了英特尔文档,上面写着(Intel doc)

Memory Bound 测量一小部分插槽,其中流水线可能由于需求加载或存储指令而停止。这主要是由于不完整的动态内存需求负载与执行饥饿相吻合,此外还有一些不太常见的情况,即存储可能对管道造成背压。

这是否意味着我的应用程序中大约有一半的指令在等待内存时停止,还是比这更微妙?

【问题讨论】:

  • 您能否链接该文档,以便我们了解“插槽”的含义?流水线乱序 CPU 不只是一次运行一条指令,因此您的解释没有意义。如果一条指令必须等待但有独立的工作来保持 CPU 忙碌,这不是吞吐量问题。这更有可能是对没有执行微指令或没有微指令退役的周期的度量。 (它几乎肯定不是前端测量,除非它可以跟踪 ROB 已满的原因或任何其他阻止 uops 发出的原因。)
  • 现在将在最初的帖子中这样做。谢谢。
  • 简而言之:不要考虑哪些指令会受到缓慢的影响;考虑一下您的代码是否让 CPU 为其饥饿的执行单元提供工作,不管它发生的顺序是什么。
  • 是的,我在后端有 4 个管道来执行分配的 uOps。我相信“插槽”是“管道插槽”。但是,我仍然可以将所有管道槽数一起计算,并说所有槽中有 X% 已停止。
  • @PeterCordes 大多数这些数字 IMO 本身毫无意义,因为它们定义不明确。它们仅在比较两个不同的运行时才有用。这包括诸如缓存未命中计数之类的内容,因为在涉及重叠未命中时,“缓存未命中”的定义很差。如果有的话,CPI 和程序集热点是识别“内存绑定”事物的最佳方法。任何具有非常高 CPI 的东西都是可疑的。与周围的指令相比,任何带有大得离谱的条的内存访问也是很好的指标。

标签: performance x86 profiling intel intel-vtune


【解决方案1】:

VTune 使用的流水线槽概念解释例如在这里:https://software.intel.com/en-us/top-down-microarchitecture-analysis-method-win。 简而言之,pipeline slot 代表处理一个 uOp 所需的硬件资源。因此,对于 4 宽 CPU(大多数 Intel 处理器),我们每个周期可以执行 4 个 Ops,并且插槽总数将由 VTune 测量为 4 * CPU_CLK_UNHALTED.THREAD。 Memory Bound 指标建立在 CYCLE_ACTIVITY.STALLS_MEM_ANY 事件上,该事件会导致您因内存而直接停顿。考虑到乱序。基本上只有当 CPU 停止并且同时它有运行中的负载时,计数器才会增加。如果有负载在进行中但 CPU 一直很忙,则不会将其视为内存停顿。 因此,Memory Bound 指标可以非常准确地估计工作负载受内存性能问题的限制。 50% 的值意味着一半的时间浪费在等待内存中的数据上。

【讨论】:

  • 我没有深入阅读那篇文章。但是 CPU 可能会因为内存以外的更多原因而停止。因此,仅仅因为 CPU 在运行中负载时停止并不一定意味着它停止因为内存。我不知道 VTune 在计算该指标时是否考虑到这一点。但如果没有,那就很难说“一半的时间都浪费在等待内存中的数据上了”。
  • “摊位”是否也被定义为 4 个问题槽中的 any 为空?还是当 all 4 个插槽为空时。例如,浮点代码很少会饱和 4 个问题槽,因为 FP 指令具有高延迟并且只有 2 个端口可以执行它们。因此,在获得 2 条指令/周期的 FP 指令链中间的非阻塞缓存未命中绝对不意味着浪费时间等待内存。
  • 也就是说,我确信 VTune 比这更聪明,但我是说有很多极端情况需要考虑,像“50% 的时间被浪费了”这样的绝对数字可以是很难从表面上解释。
【解决方案2】:

slot 是管道的执行端口。一般来说,在 VTune 文档中,停顿可能意味着“未退役”或“未调度执行”。在这种情况下,它是指发送零微指令的周期数。

根据VTune包含的配置文件,Memory Bound计算如下:

Memory_Bound = Memory_Bound_Fraction * BackendBound

Memory_Bound_Fraction 基本上是文档中提到的插槽的一部分。但是,根据优化手册中讨论的自顶向下方法,内存绑定度量是相对于后端绑定度量的。所以这就是为什么要乘以BackendBound

我将重点介绍公式的第一项,Memory_Bound_Fraction。第二项BackendBound的公式其实很复杂。

Memory_Bound_Fraction 计算如下:

Memory_Bound_Fraction = (CYCLE_ACTIVITY.STALLS_MEM_ANY + RESOURCE_STALLS.SB) * NUM_OF_PORTS / Backend_Bound_Cycles * NUM_OF_PORTS

NUM_OF_PORTS是目标CPU微架构的执行端口数。这可以简化为:

Memory_Bound_Fraction = CYCLE_ACTIVITY.STALLS_MEM_ANY + RESOURCE_STALLS.SB / Backend_Bound_Cycles

CYCLE_ACTIVITY.STALLS_MEM_ANYRESOURCE_STALLS.SB 是性能事件。 Backend_Bound_Cycles 计算如下:

Backend_Bound_Cycles = CYCLE_ACTIVITY.STALLS_TOTAL + UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - Few_Uops_Executed_Threshold - Frontend_RS_Empty_Cycles + RESOURCE_STALLS.SB

Few_Uops_Executed_ThresholdUOPS_EXECUTED.CYCLES_GE_2_UOP_EXECUOPS_EXECUTED.CYCLES_GE_3_UOP_EXEC,具体取决于其他一些指标。 Frontend_RS_Empty_CyclesRS_EVENTS.EMPTY_CYCLES 或零,具体取决于某些指标。

我意识到这个答案仍然需要很多额外的解释,BackendBound 需要扩展。但是这个早期的编辑使答案准确。

【讨论】:

    猜你喜欢
    • 2016-06-27
    • 1970-01-01
    • 2015-01-18
    • 2020-10-02
    • 2021-08-25
    • 2020-05-12
    • 1970-01-01
    • 2015-12-08
    • 1970-01-01
    相关资源
    最近更新 更多