Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Linux性能工具显示奇怪的缓存未命中结果_C++_Caching_Linux Kernel_Profiling_Perf - Fatal编程技术网

C++ Linux性能工具显示奇怪的缓存未命中结果

C++ Linux性能工具显示奇怪的缓存未命中结果,c++,caching,linux-kernel,profiling,perf,C++,Caching,Linux Kernel,Profiling,Perf,我正在使用linux perf工具进行评测,我对L1 DCache未命中特别感兴趣,因此我运行的程序如下: perf record -e L1-dcache-read-misses -o perf/apsp.cycles apps/apsp/apsp 4 16384 16 perf annotate --stdio -i perf/apsp.cycles --dsos=apsp 它运行正常,但会生成以下警告: WARNING: Kernel address maps (/proc/{kall

我正在使用linux perf工具进行评测,我对L1 DCache未命中特别感兴趣,因此我运行的程序如下:

perf record -e L1-dcache-read-misses -o perf/apsp.cycles apps/apsp/apsp 4 16384 16
perf annotate --stdio -i perf/apsp.cycles --dsos=apsp
它运行正常,但会生成以下警告:

WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,
check /proc/sys/kernel/kptr_restrict.

Samples in kernel functions may not be resolved if a suitable vmlinux
file is not found in the buildid cache or in the vmlinux path.

Samples in kernel modules won't be resolved at all.

If some relocation was applied (e.g. kexec) symbols may be misresolved
even with a suitable vmlinux or kallsyms file.

Cannot read kernel map
Couldn't record kernel reference relocation symbol
Symbol resolution may be skewed if relocation was used (e.g. kexec).
Check /proc/kallsyms permission or run as root.

Threads Returned!
Threads Joined!
Time: 2.932636 seconds
[ perf record: Woken up 5 times to write data ]
[ perf record: Captured and wrote 1.709 MB perf/apsp.cycles (44765 samples) ]
然后,我对输出文件进行如下注释:

perf record -e L1-dcache-read-misses -o perf/apsp.cycles apps/apsp/apsp 4 16384 16
perf annotate --stdio -i perf/apsp.cycles --dsos=apsp
但在其中一个代码部分中,我看到了一些奇怪的结果:

Percent |      Source code & Disassembly of apsp for L1-dcache-read-misses
---------------------------------------------------------------------------
         :               {
         :                  if((D[W_index[v][i]] > (D[v] + W[v][i])))
   19.36 :        401140:       movslq (%r10,%rcx,4),%rsi
   14.50 :        401144:       lea    (%rax,%rsi,4),%rdi
    1.22 :        401148:       mov    (%r9,%rcx,4),%esi
    5.82 :        40114c:       add    (%rax,%r8,4),%esi
   20.02 :        401150:       cmp    %esi,(%rdi)
    0.00 :        401152:       jle    401156 <do_work(void*)+0x226>
         :                     D[W_index[v][i]] = D[v] + W[v][i];
    9.72 :        401154:       mov    %esi,(%rdi)
   19.93 :        401156:       add    $0x1,%rcx
         :
Percent |源代码和针对L1 dcache读取未命中的apsp反汇编
---------------------------------------------------------------------------
:               {
:if((D[W_index[v][i]]>(D[v]+W[v][i]))
19.36:401140:movslq(%r10,%rcx,4),%rsi
14.50:401144:lea(%rax,%rsi,4),%rdi
1.22:401148:mov(%r9,%rcx,4),%esi
5.82:40114c:add(%rax,%r8,4),%esi
20.02:401150:cmp%esi,(%rdi)
0.00:401152:jle 401156
:D[W_index[v][i]=D[v]+W[v][i];
9.72:401154:mov%esi,(%rdi)
19.93:401156:添加$0x1,%rcx
:
现在在这些结果中,为什么一些算术指令有一级读取未命中?还有,为什么第二条语句的指令会导致如此多的缓存未命中,即使它们本应该由前一条if语句带入缓存? 我在这里做错了什么吗?我在另一台具有root访问权限的机器上尝试了同样的方法,它给了我类似的结果,因此我认为我上面提到的警告不会导致这种情况。但到底是怎么回事?

因此我们有以下代码:

for(v=0;v<N;v++)
{
    for(int i = 0; i < DEG; i++)
    {
        if((/* (V2) 1000000000 * */ D[W_index[v][i]] > (D[v] + W[v][i])))
            D[W_index[v][i]] = D[v] + W[v][i];

        Q[v]=0; //Current vertex checked
    }
}
查找
W_索引[v]
加载到寄存器中。对于
W_索引[v][i]
我们假设一个缓存未命中(64字节缓存线,每int 4字节,我们调用DIM=16的程序)。在
D
中的查找始终从
v
开始,因此阵列的大部分所需部分已在缓存中。假设
DEG
很大,此查找是免费的

D[v] + W[v][i]
查找
D[v]
是免费的,因为它取决于
v
。第二次查找与上面相同,第二个维度有一次缓存未命中

整个内心的陈述没有影响

Q[v]=0;
由于这是
v
,因此可以忽略

总结起来,我们得到两个缓存未命中

第二近似值

现在,我们回到“代码> DEG/CODE >很大的假设。实际上,这是错误的,因为<代码> DEG=16 < /COD>。因此我们还需要考虑缓存缺失的分数。

D[W_index[v][i]]
查找
W_index[v]
的代价是缓存未命中的1/8(它的大小为8字节,缓存线为64字节,因此我们每次迭代都会得到一个缓存未命中)

D[W_index[v][i]
也是如此,除了
D
保存整数。平均而言,除了一个整数外,所有整数都在缓存中,因此这会导致缓存未命中的1/16

D[v] + W[v][i]
D[v]
已经在缓存中(这是
W\u index[v][0]
)。但是我们得到了
W[v]
的另一个1/8的缓存未命中,原因与上面相同

Q[v]=0;
这是另一个1/16的缓存未命中

D[v] + W[v][i]
令人惊讶的是,如果我们现在使用
if
-子句从未计算为
true
的代码(V2),那么每次迭代都会有2.395次缓存未命中(请注意,您确实需要很好地配置CPU,也就是说,如果可能的话,没有超线程、没有turboboost、性能调节器).上面的计算结果会是2.375.所以我们很好

第三近似值

现在出现了一个不幸的
if
子句。这个比较的结果是
true
的频率有多高。我们不能说,一开始它会非常频繁,最后它的结果永远不会是
true

让我们关注完整循环的第一次执行。在本例中,
D[v]
是无穷大,
W[v][i]
是一个介于1和101之间的数字。因此循环在每次迭代中计算为
true

然后它变得很难-我们在这个迭代中得到2.9个缓存未命中。它们来自哪里-所有数据都应该已经在缓存中了

但是:这就是“编译器之谜”。你永远不知道它们最终会产生什么。我使用GCC和Clang编译,得到了相同的度量值。我激活了
-funroll循环
,突然我得到了2.5次缓存未命中。当然,这在你的系统上可能会有所不同。当我检查程序集时,我发现它实际上是完全相同的,只是循环已经展开了四次

那么这告诉我们什么呢?你永远不知道你的编译器在做什么,除非你检查它。即使这样,你也不能确定

我猜硬件预取或执行顺序可能会对这里产生影响。但这是个谜

关于性能和您的问题

我认为你的测量有两个问题:

  • 它们是相对的,精确的线不是那么准确
  • 您是多线程的,这可能更难跟踪

我的经验是,当您想要为代码的特定部分获得良好的度量值时,您确实需要手动检查。有时——并非总是如此——它可以很好地解释问题。

您能提供绝对值吗?我认为这会有很大帮助。我预计每次迭代都会有略多于一次的缓存未命中(D[W_index…].Perf可能会显示一点模糊的结果,但这种相对计时在这种情况下没有帮助。@在国外,我不知道如何从Perf中获取绝对数。我在谷歌上搜索了一点,似乎找不到任何绝对数。如果我使用Perf list,所有列出的事件都会输出我问题中所示的百分比。请在此处检查代码:您可能是also要检查
man perf\u open\u event
。要从perf中获取绝对数(函数中有多少个样本),我们可以使用
-n
选项,但它仅为
perf report
命令实现,这类似于一个bug。使用重新运行
perf record