簡體   English   中英

Linux性能工具顯示奇怪的緩存未命中結果

[英]Linux perf tool showing weird cache miss results

我正在使用linux perf工具來分析CRONO基准測試之一 ,我特別對L1 DCache Misses感興趣,所以我這樣運行程序:

perf record -e L1-dcache-read-misses -o perf/apsp.cycles apps/apsp/apsp 4 16384 16

它運行正常,但會生成以下警告:

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 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
         :

現在,在這些結果中,為什么某些算術指令發生了L1讀錯誤? 另外,第二條語句的指令為什么會導致如此多的高速緩存未命中,即使它們應該由前一個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
    }
}

請注意,我在代碼中添加了(V2)作為注釋。 下面我們回到此代碼。

一階近似

請記住, W_index初始化為W_index[i][j] = i + j (A)

讓我們關注一個內部迭代,首先讓我們假設DEG很大。 此外,我們假設緩存足夠大,可以保存所有數據至少兩次迭代。

D[W_index[v][i]]

查找W_index[v]被加載到寄存器中。 對於W_index[v][i]我們假設一個高速緩存未命中(64字節高速緩存行,每個int 4字節,我們用DIM = 16調用程序)。 D的查找始終始於v ,因此數組的大部分必需部分已經在緩存中。 假設DEG很大,則此查找是免費的。

D[v] + W[v][i]

查找D[v]是免費的,因為它取決於v 第二次查找與上面相同,第二個維度有一個高速緩存未命中。

整個內部陳述沒有影響力。

Q[v]=0;

由於這是v ,因此可以忽略。

總結起來,我們會得到兩個緩存未命中。

二階近似

現在,我們回到DEG很大的假設。 實際上這是錯誤的,因為DEG = 16 因此,我們還需要考慮一些緩存未命中的問題。

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_index[v][0] )。 但是由於上述相同的原因,我們又得到了W[v] 1/8的高速緩存未命中。

Q[v]=0;

這是緩存未命中率的另外1/16。

令人驚訝的是,如果我們現在使用代碼(V2),其中if -clause永遠不會評估為true ,那么每次迭代我都會遇到2.395高速緩存未命中(請注意,您確實需要很好地配置CPU,即沒有超線程,沒有turboboost,性能調速器)。 上面的計算將得出2.375。 所以我們很好。

第三近似

現在有一個不幸的if子句。 此比較多久一次會得出true 我們不能說,一開始它會經常出現,而到最后它永遠不會評估為true

因此,讓我們關注完整循環的真正首次執行。 在這種情況下, D[v]是無窮大, W[v][i]是1到101之間的一個數字。因此,循環在每次迭代中都為true

然后變得很困難-在此迭代中,我們得到2.9個緩存未命中。 它們來自何處-所有數據應該已經在緩存中。

但是 :這是“編譯器之謎”。 您永遠都不知道它們最終會產生什么。 我使用GCC和Clang進行編譯,並得到相同的度量。 我激活-funroll-loops ,突然我得到2.5次緩存未命中。 當然,這在您的系統上可能有所不同。 當我檢查裝配時,我發現它實際上是完全相同的,只是循環已經展開了四次。

那這告訴我們什么呢? 除了檢查之外,您永遠都不知道編譯器會做什么。 即使那樣,您也不能確定。

我猜硬件預取或執行順序可能會在這里產生影響。 但這是一個謎。

關於性能及其問題

我認為您所做的測量存在兩個問題:

  • 他們是相對的,確切的路線不是那么准確。
  • 您是多線程的,這可能很難跟蹤。

我的經驗是,當您想對代碼的特定部分獲得良好的衡量標准時,確實需要手動檢查它。 有時(並非總是如此),它可以解釋得很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM