perf stat 输出的解释

Interpretation of perf stat output

我开发了一种代码,可以将大型二维图像(高达 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

(缓存未命中数)/(指令数)很低,约为 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% 的高未命中率。

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

我运行安装此机器的机器是 Xeon E5-2680(20M 智能缓存,其中每个内核 256KB L2 缓存,8 个内核)。

您要确保的第一件事是您的机器上运行没有其他计算密集型进程。那是一台服务器 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 放大器。它对指标进行了更好的解释,并指出了代码中可能出现的问题。