Я не понимаю количество ошибок кэша между cachegrind и perf инструментом
Я изучаю эффект кэширования с помощью простого микро-теста.
Я думаю, что если N больше, чем размер кеша, то кеш имеет операцию пропуска при каждой первой строке чтения кеша.
На моей машине размер строки кэша =64 байт, так что я думаю, что полностью происходит кеширование.
Тем не менее, перф инструмент показывает другой результат. Всего происходит 34 265 операций с пропуском кеша.
Я сомневаюсь в аппаратной предварительной загрузке, поэтому отключите эту функцию в BIOS. во всяком случае, результат тот же.
Я действительно не знаю, почему промах кеша в инструменте Perf выполняется очень маленькими операциями, чем "cachegrind" Может ли кто-нибудь дать мне разумное объяснение?
1. Вот простая программа микро-тестов.
#include <stdio.h>
#define N 10000000
double A[N];
int main(){
int i;
double temp=0.0;
for (i=0 ; i<N ; i++){
temp = A[i]*A[i];
}
return 0;
}
2. Следующим результатом является вывод cachegrind:
#> sudo perf stat -r 10 -e instructions -e cache-references -e cache-misses -e L1-dcache-loads -e L1-dcache-load-misses -e L1-dcache-stores -e L1-dcache-store-misses -e LLC-loads -e LLC-load-misses -e LLC-prefetches ./test
==27612== Cachegrind, a cache and branch-prediction profiler
==27612== Copyright (C) 2002-2013, and GNU GPL'd, by Nicholas Nethercote et al.
==27612== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==27612== Command: ./test
==27612==
--27612-- warning: L3 cache found, using its data for the LL simulation.
==27612==
==27612== I refs: 110,102,998
==27612== I1 misses: 728
==27612== LLi misses: 720
==27612== I1 miss rate: 0.00%
==27612== LLi miss rate: 0.00%
==27612==
==27612== D refs: 70,038,455 (60,026,965 rd + 10,011,490 wr)
==27612== D1 misses: 1,251,802 ( 1,251,288 rd + 514 wr)
==27612== LLd misses: 1,251,624 ( 1,251,137 rd + 487 wr)
==27612== D1 miss rate: 1.7% ( 2.0% + 0.0% )
==27612== LLd miss rate: 1.7% ( 2.0% + 0.0% )
==27612==
==27612== LL refs: 1,252,530 ( 1,252,016 rd + 514 wr)
==27612== LL misses: 1,252,344 ( 1,251,857 rd + 487 wr)
==27612== LL miss rate: 0.6% ( 0.7% + 0.0% )
Generate a report File
--------------------------------------------------------------------------------
I1 cache: 32768 B, 64 B, 4-way associative
D1 cache: 32768 B, 64 B, 8-way associative
LL cache: 8388608 B, 64 B, 16-way associative
Command: ./test
Data file: cache_block
Events recorded: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Events shown: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Event sort order: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Thresholds: 0.1 100 100 100 100 100 100 100 100
Include dirs:
User annotated: /home/jin/1_dev/99_test/OI/test.s
Auto-annotation: off
--------------------------------------------------------------------------------
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
--------------------------------------------------------------------------------
110,102,998 728 720 60,026,965 1,251,288 1,251,137 10,011,490 514 487 PROGRAM TOTALS
--------------------------------------------------------------------------------
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw file:function
--------------------------------------------------------------------------------
110,000,011 1 1 60,000,003 1,250,000 1,250,000 10,000,003 0 0 /home/jin/1_dev/99_test/OI/test.s:main
--------------------------------------------------------------------------------
-- User-annotated source: /home/jin/1_dev/99_test/OI/test.s
--------------------------------------------------------------------------------
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
-- line 2 ----------------------------------------
. . . . . . . . . .comm A,80000000,32
. . . . . . . . . .comm B,80000000,32
. . . . . . . . . .text
. . . . . . . . . .globl main
. . . . . . . . . .type main, @function
. . . . . . . . . main:
. . . . . . . . . .LFB0:
. . . . . . . . . .cfi_startproc
1 0 0 0 0 0 1 0 0 pushq %rbp
. . . . . . . . . .cfi_def_cfa_offset 16
. . . . . . . . . .cfi_offset 6, -16
1 0 0 0 0 0 0 0 0 movq %rsp, %rbp
. . . . . . . . . .cfi_def_cfa_register 6
1 0 0 0 0 0 0 0 0 movl $0, %eax
1 1 1 0 0 0 1 0 0 movq %rax, -16(%rbp)
1 0 0 0 0 0 1 0 0 movl $0, -4(%rbp)
1 0 0 0 0 0 0 0 0 jmp .L2
. . . . . . . . . .L3:
10,000,000 0 0 10,000,000 0 0 0 0 0 movl -4(%rbp), %eax
10,000,000 0 0 0 0 0 0 0 0 cltq
10,000,000 0 0 10,000,000 1,250,000 1,250,000 0 0 0 movsd A(,%rax,8), %xmm1
10,000,000 0 0 10,000,000 0 0 0 0 0 movl -4(%rbp), %eax
10,000,000 0 0 0 0 0 0 0 0 cltq
10,000,000 0 0 10,000,000 0 0 0 0 0 movsd A(,%rax,8), %xmm0
10,000,000 0 0 0 0 0 0 0 0 mulsd %xmm1, %xmm0
10,000,000 0 0 0 0 0 10,000,000 0 0 movsd %xmm0, -16(%rbp)
10,000,000 0 0 10,000,000 0 0 0 0 0 addl $1, -4(%rbp)
. . . . . . . . . .L2:
10,000,001 0 0 10,000,001 0 0 0 0 0 cmpl $9999999, -4(%rbp)
10,000,001 0 0 0 0 0 0 0 0 jle .L3
1 0 0 0 0 0 0 0 0 movl $0, %eax
1 0 0 1 0 0 0 0 0 popq %rbp
. . . . . . . . . .cfi_def_cfa 7, 8
1 0 0 1 0 0 0 0 0 ret
. . . . . . . . . .cfi_endproc
. . . . . . . . . .LFE0:
. . . . . . . . . .size main, .-main
. . . . . . . . . .ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
. . . . . . . . . .section .note.GNU-stack,"",@progbits
--------------------------------------------------------------------------------
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
--------------------------------------------------------------------------------
100 0 0 100 100 100 100 0 0 percentage of events annotated
3. Следующим результатом является вывод perf:
Статистика счетчика производительности для "./test" (10 прогонов):
113,898,951 instructions # 0.00 insns per cycle ( +- 12.73% ) [17.36%]
53,607 cache-references ( +- 12.92% ) [29.23%]
1,483 cache-misses # 2.767 % of all cache refs ( +- 26.66% ) [39.84%]
48,612,823 L1-dcache-loads ( +- 4.58% ) [50.45%]
34,256 L1-dcache-load-misses # 0.07% of all L1-dcache hits ( +- 18.94% ) [54.38%]
14,992,686 L1-dcache-stores ( +- 4.90% ) [52.58%]
1,980 L1-dcache-store-misses ( +- 6.36% ) [61.83%]
1,154 LLC-loads ( +- 61.14% ) [53.22%]
18 LLC-load-misses # 1.60% of all LL-cache hits ( +- 16.26% ) [10.87%]
0 LLC-prefetches [ 0.00%]
0.037949840 seconds time elapsed ( +- 3.57% )
Подробнее Экспериментальный результат (2014.05.13):
jin@desktop:~/1_dev/99_test/OI$ sudo perf stat -r 10 -e instructions -e r53024e -e r53014e -e L1-dcache-loads -e L1-dcache-load-misses -e r500f0a -e r500109 ./test
Performance counter stats for './test' (10 runs):
116,464,390 instructions # 0.00 insns per cycle ( +- 2.67% ) [67.43%]
5,994 r53024e <-- L1D hardware prefetch misses ( +- 21.74% ) [70.92%]
1,387,214 r53014e <-- L1D hardware prefetch requests ( +- 2.37% ) [75.61%]
61,667,802 L1-dcache-loads ( +- 1.27% ) [78.12%]
26,297 L1-dcache-load-misses # 0.04% of all L1-dcache hits ( +- 48.92% ) [43.24%]
0 r500f0a <-- LLC lines allocated [56.71%]
41,545 r500109 <-- Number of LLC read misses ( +- 6.16% ) [50.08%]
0.037080925 seconds time elapsed
В результате, приведенном выше, число запросов на аппаратную предварительную выборку L1D выглядит как D1 miss(1 250 000) в cachegrind.
В моем заключении, если память обращается к "шаблону потока", то функция L1D prefetch включена. и я не могу проверить, сколько байтов загружается из памяти из-за пропущенной информации LLC.
Мой вывод правильный?
1 ответ
Итог: ваши предположения относительно предварительных выборок верны, но ваш обходной путь не верен.
Во-первых, как отметил Карло, этот цикл обычно оптимизируется любым компилятором. Поскольку как perf, так и cachegrind показывают ~100M инструкций, они удаляются, я думаю, вы не скомпилировали с оптимизацией, что означает, что поведение не очень реалистично - например, ваша переменная цикла может храниться в памяти, а не в регистре, добавляя бессмысленные обращения к памяти и искажение счетчиков кэша.
Теперь разница между вашими прогонами в том, что cachgrind - это всего лишь симулятор кэша, он не имитирует предварительные выборки, поэтому каждый первый доступ к строке пропускается, как и ожидалось. С другой стороны, реальный ЦП действительно имеет предварительные выборки HW, как вы можете видеть, поэтому при первом извлечении каждой строки из памяти она выполняется предварительной выборкой (благодаря простому шаблону потоковой передачи), а не фактической загрузкой по требованию. Вот почему perf пропускает счет этих обращений с обычными счетчиками.
Вы можете видеть, что при включении счетчика предварительной выборки вы видите примерно те же самые предварительные выборки N/8 (плюс некоторые дополнительные из других типов доступа, вероятно).
Отключение предварительной выборки может показаться правильным, однако большинство процессоров не предлагают слишком большого контроля над этим. Вы не указали, какой тип процессора вы используете, но если это был, например, Intel, вы можете увидеть здесь, что только предварительные выборки L2 контролируются BIOS, а ваш вывод показывает предварительные выборки L1 - https://software.intel.com / EN-US / статьи / оптимизация-приложения производительность-на-ИНТЕЛ-coret-микроархитектура-использование-аппаратные Реализуемой-предварительной выборки
Найдите руководства по типу вашего ЦП, чтобы узнать, какие существуют устройства предварительной выборки L1, и понять, как их обойти. Обычно простого шага (больше, чем одна строка кэша) должно быть достаточно, чтобы обмануть их, но если это не сработает, вам нужно будет изменить схему доступа, чтобы она была более случайной. Вы можете рандомизировать некоторую перестановку индексов для этого.