Linux perf报告缓存未命中意外指令

时间:2017-05-05 00:02:31

标签: linux performance caching perf

我试图将一些性能工程技术应用于Dijkstra算法的实现。为了找到(天真的和未经优化的)程序的瓶颈,我使用perf命令记录缓存未命中的数量。相关的代码片段如下,它找到距离最小的未访问节点:

for (int i = 0; i < count; i++) {
    if (!visited[i]) {
        if (tmp == -1 || dist[i] < dist[tmp]) {
            tmp = i;
        }
    }
}

对于LLC-load-misses指标,perf report显示了程序集的以下注释:

       │             for (int i = 0; i < count; i++) {                                                                                                                           ▒
  1.19 │ ff:   add    $0x1,%eax                                                                                                                                                  ▒
  0.03 │102:   cmp    0x20(%rsp),%eax                                                                                                                                            ▒
       │     ↓ jge    135                                                                                                                                                        ▒
       │                 if (!visited[i]) {                                                                                                                                      ▒
  0.07 │       movslq %eax,%rdx                                                                                                                                                  ▒
       │       mov    0x18(%rsp),%rdi                                                                                                                                            ◆
  0.70 │       cmpb   $0x0,(%rdi,%rdx,1)                                                                                                                                         ▒
  0.53 │     ↑ jne    ff                                                                                                                                                         ▒
       │                     if (tmp == -1 || dist[i] < dist[tmp]) {                                                                                                             ▒
  0.07 │       cmp    $0xffffffff,%r13d                                                                                                                                          ▒
       │     ↑ je     fc                                                                                                                                                         ▒
  0.96 │       mov    0x40(%rsp),%rcx                                                                                                                                            ▒
  0.08 │       movslq %r13d,%rsi                                                                                                                                                 ▒
       │       movsd  (%rcx,%rsi,8),%xmm0                                                                                                                                        ▒
  0.13 │       ucomis (%rcx,%rdx,8),%xmm0                                                                                                                                        ▒
 57.99 │     ↑ jbe    ff                                                                                                                                                         ▒
       │                         tmp = i;                                                                                                                                        ▒
       │       mov    %eax,%r13d                                                                                                                                                 ▒
       │     ↑ jmp    ff                                                                                                                                                         ▒
       │                     }                                                                                                                                                   ▒
       │                 }                                                                                                                                                       ▒
       │             }   

我的问题如下:为什么jbe指令会产生如此多的缓存未命中?如果我没有弄错的话,该指令根本不必从内存中检索任何内容。我认为它可能与指令缓存未命中有关,但即使使用L1-dcache-load-misses仅测量L1数据缓存未命中,也表明该指令中存在大量缓存未命中。

这让我有点不知所措。谁能解释这个(在我看来)奇怪的结果?提前谢谢。

1 个答案:

答案 0 :(得分:0)

当您读取内存位置时,处理器将尝试预取相邻的内存位置并对其进行缓存。

如果你正在读取一个对象数组,这些对象都在连续的块中分配在内存中,那么效果很好。

但是,例如,如果你有一个存在于堆中的指针数组,那么除非你使用某种专门为此设计的自定义分配器,否则你不太可能在连续的内存部分上进行迭代。

因此,取消引用应被视为某种成本。结构数组可以更有效地指向结构的指针数组。

Herb Sutter(C ++委员会成员)在这次演讲中谈到这一点https://youtu.be/TJHgp1ugKGM?t=21m31s