【问题标题】:Interpretation of perf stat outputperf stat 输出解读
【发布时间】:2015-05-16 18:35:39
【问题描述】:

我开发了一个代码,该代码将大型二维图像(高达 64MPixels)作为输入,并且:

  • 对每一行应用过滤器
  • 转置图像(使用阻塞来避免大量缓存未命中)
  • 对图像的列(现在的行)应用过滤器
  • 将过滤后的图像转回以进行其他计算

虽然它没有改变什么,但为了我的问题的完整性,过滤是应用离散小波变换,代码是用 C 编写的。

我的最终目标是让它尽可能快地运行。通过使用阻塞矩阵转置、向量化、多线程、编译器友好的代码等,我迄今为止的加速超过了 10 倍。

提出我的问题:我拥有的代码(使用perf stat -e)的最新分析统计数据困扰了我。

        76,321,873 cache-references                                            
     8,647,026,694 cycles                    #    0.000 GHz                    
     7,050,257,995 instructions              #    0.82  insns per cycle        
        49,739,417 cache-misses              #   65.171 % of all cache refs    

       0.910437338 seconds time elapsed

(# of cache-misses)/(# instructions) 很低,约为 0.7%。 Here 有人提到这个数字是检查内存效率的好东西。

另一方面,缓存引用的缓存未命中百分比非常高(65%!),正如我所见,这可能表明缓存效率方面的执行出了问题。

来自perf stat -d的详细统计数据是:

   2711.191150 task-clock                #    2.978 CPUs utilized          
         1,421 context-switches          #    0.524 K/sec                  
            50 cpu-migrations            #    0.018 K/sec                  
       362,533 page-faults               #    0.134 M/sec                  
 8,518,897,738 cycles                    #    3.142 GHz                     [40.13%]
 6,089,067,266 stalled-cycles-frontend   #   71.48% frontend cycles idle    [39.76%]
 4,419,565,197 stalled-cycles-backend    #   51.88% backend  cycles idle    [39.37%]
 7,095,514,317 instructions              #    0.83  insns per cycle        
                                         #    0.86  stalled cycles per insn [49.66%]
   858,812,708 branches                  #  316.766 M/sec                   [49.77%]
     3,282,725 branch-misses             #    0.38% of all branches         [50.19%]
 1,899,797,603 L1-dcache-loads           #  700.724 M/sec                   [50.66%]
   153,927,756 L1-dcache-load-misses     #    8.10% of all L1-dcache hits   [50.94%]
    45,287,408 LLC-loads                 #   16.704 M/sec                   [40.70%]
    26,011,069 LLC-load-misses           #   57.44% of all LL-cache hits    [40.45%]

   0.910380914 seconds time elapsed

这里的前端和后端停滞周期也很高,并且较低级别的缓存似乎遭受了 57.5% 的高未命中率。

哪个指标最适合这种情况?我在想的一个想法是,工作负载可能不再需要在初始图像加载后进一步“接触”LL缓存(加载一次值,然后完成 - 工作负载比 CPU 更受限制) memory-bound 是一种图像过滤算法)。

我运行它的机器是 Xeon E5-2680(20M 智能缓存,其中每个核心 256KB 二级缓存,8 个核心)。

【问题讨论】:

  • koukouviou, perf stat -d 可能不准确,每次运行 4-5 个事件重新运行几次会很有用,perf stat -e L1-dcache-loads,L1-dcache-load-misses,LLC-loads,LLC-loads-misses。如果您的阶段可以分开,您可以测量每个阶段以找出哪个阶段产生未命中。或者您可以运行perf record -e cache-misses 来获取丢失最多的代码的配置文件(正如您链接的"Here" 中所建议的那样)。
  • @osgx 我已经完成了你提到的测试,但这篇文章已经很长了,所以我尽量简短。尽管统计数据发生了一些变化,但在高缓存未命中率方面仍保持统计相似性。我已经运行 perf record/report/annotate 并且未命中主要归因于 kernel-kallsyms,但我不知道该怎么做...
  • koukouviou,您可以使用仅限于用户空间的所有事件重新运行您的统计数据:perf stat -e event1:u,event2:u,... 并与发布的结果进行比较(默认情况下,用户和内核都被测量)。 kernel-kallsyms 表示内核空间中的某些函数发生了此事件...此处列出了一些可能的未知/未解决符号问题:brendangregg.com/blog/2014-06-22/perf-cpu-sample.html。我不能给你关于指标的建议......

标签: performance caching optimization computer-architecture perf


【解决方案1】:

您要确保的第一件事是没有其他计算密集型进程在您的计算机上运行。那是一个服务器 CPU,所以我认为这可能是个问题。

如果您在程序中使用多线程,并且在线程之间分配相同数量的工作,您可能会对仅在一个 CPU 上收集指标感兴趣。

我建议在优化阶段禁用超线程,因为它会在解释分析指标时导致混淆。 (例如,增加后端花费的#cycles)。此外,如果您将工作分配给 3 个线程,则很有可能 2 个线程将共享一个内核的资源,而第 3 个线程将拥有整个内核 - 而且速度会更快。

Perf 从来都不善于解释指标。从数量级来看,缓存引用是命中 LLC 的 L2 未命中。如果 LLC 引用/#Instructions 的数量较低,则与 LLC 引用相比,较高的 LLC 未命中数并不总是坏事。在您的情况下,您有 0.018,这意味着您的大部分数据都是从 L2 使用的。高 LLC 未命中率意味着您仍然需要从 RAM 中获取数据并将其写回。

关于#Cycles BE 和 FE bound,我有点担心这些值,因为它们的总和不是 100% 和循环总数。您有 8G,但在 FE 中保持 6G 周期,在 BE 中保持 4G 周期。这似乎不太正确。

如果 FE 周期很高,则意味着指令缓存中存在未命中或分支推测错误。如果 BE 周期很高,则意味着您在等待数据。

无论如何,关于你的问题。评估代码性能最相关的指标是指令/周期 (IPC)。您的 CPU 最多可以执行 4 条指令/周期。你只执行 0.8。这意味着资源未被充分利用,除非您有许多向量指令。在 IPC 之后,您需要检查分支未命中和 L1 未命中(数据和代码),因为它们会产生最多的惩罚。

最后一个建议:您可能有兴趣尝试英特尔的 vTune 放大器。它可以更好地解释指标,并指出代码中的最终问题。

【讨论】:

  • VAndrei、BE 和 FE 停顿永远不会与 100% 周期的指令相加,因为大多数 Intel CPU 都是超级流水线的。许多指令可能正在流水线中运行,有些会产生停顿;但有些会被处决。 71% 的 FE 停顿很高(你有很多代码很难解码?),51% 的 BE 停顿也很高 - 所以有几个问题......免费缓解 Vtune。
  • @osgx。我不太确定。 FE 绑定意味着预留单元没有收到指令,因此没有执行端口有工作要做。这是由于代码缓存未命中、复杂指令和错误推测造成的。如果 BE 很高,则意味着指令使执行端口保持忙碌,但它们正在等待资源(数据或空闲寄存器)或者它们具有很高的延迟(例如超越)。应该有另一个指标:#cycles 退休。如果您查看 vTune,您会看到 FE+BE+Retiring 始终添加到 100%。
  • vTune 可能对 FE/BE 使用不同的计数器。 Perf 使用(根据 Manuel Selva 的回答 stackoverflow.com/a/22166684sources for SandyBridgeUOPS_ISSUED.ANY,umask=0x01,inv,cmask=0x01 用于 FE 档位,UOPS_DISPATCHED.THREAD,umask=0x01,inv,cmask=0x01 用于 BE。
  • VAndrei,感谢您提供的所有见解。在我对这段代码的优化“旅程”期间,我使用了 VTune 和 perf。至于坏的分支预测,这个数字非常低(至少可以接受的低)。代码使用 pgo-gen/pgo-use 编译,分支预测略有改进。 CPU 是一种服务器模型,但我是唯一一个可以访问服务器的人,除了在其上运行的最低限度的进程之外没有其他任何东西。
  • IPC 很低,但正如你提到的,我确实有大量矢量指令(图像像素的过滤是在 CPU 的 SIMD 管道上完成的——这是加快速度的设计决定)。我正在使用 CilkPlus 进行多线程处理(对线程数没有限制),因此最多可以有 16 个线程。 @osgx 感谢toplev.py 工具,我不知道,我会试一试
猜你喜欢
  • 1970-01-01
  • 2021-08-03
  • 2013-11-14
  • 2014-05-26
  • 2019-05-30
  • 2021-10-09
  • 2013-11-14
  • 1970-01-01
  • 2016-07-18
相关资源
最近更新 更多