解释perf属性输出

kou*_*iou 5 optimization performance caching computer-architecture perf

我开发了一个代码,可以输入一个大的2-D图像(最高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
Run Code Online (Sandbox Code Playgroud)

(缓存未命中数)/(#指令)低约0.7%.这里提到这个数字是检查内存效率的好事.

另一方面,高速缓存未命中高速缓存引用的百分比非常高(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
Run Code Online (Sandbox Code Playgroud)

这里前端和后端停滞的周期也很高,较低级别的缓存似乎遭受57.5%的高失误率.

哪种指标最适合此方案?我想到的一个想法是,在初始图像加载之后,工作负载不再需要进一步"触摸"LL缓存(加载值一次,之后就完成了 - 工作负载比CPU更多 - 内存绑定是一种图像过滤算法).

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

VAn*_*rei 6

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

如果您在程序中使用多线程,并且在线程之间分配等量的工作,您可能有兴趣仅收集一个 CPU 上的指标

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

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

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

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

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

最后的建议:您可能有兴趣尝试英特尔的 vTune Amplifier。它对指标提供了更好的解释,并指出代码中的最终问题。