我已经开发了一个代码,可以获取大的二维图像(最大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%的未命中率。

哪种指标最适合这种情况?我当时想到的一个想法是,可能的情况是,在初始映像加载后(再加载一次值之后,工作负载不再需要进一步“触及” LL缓存)-工作负载比CPU负担更多内存绑定是一种图像过滤算法)。

我在其上运行的计算机是Xeon E5-2680(20M的Smart高速缓存,其中每个内核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放大器感兴趣。它为度量提供了更好的解释,并指出了代码中的最终问题。

07-26 00:41