Caching 什么是;“页面错误”;在'perf stat'中,是指;“后端循环空闲”吗;?
我编写了一个简单的矩阵乘法程序来演示通过perf进行缓存和性能测量的效果。比较相对效率的两个函数是Caching 什么是;“页面错误”;在'perf stat'中,是指;“后端循环空闲”吗;?,caching,perf,Caching,Perf,我编写了一个简单的矩阵乘法程序来演示通过perf进行缓存和性能测量的效果。比较相对效率的两个函数是sqmat\u mult和sqmat\u mult\u efficient: void sqmat_mult(整数x,常数a[x][x],常数b[x][x],整数m[x][x]) { 对于(int i=0;i
sqmat\u mult
和sqmat\u mult\u efficient
:
void sqmat_mult(整数x,常数a[x][x],常数b[x][x],整数m[x][x])
{
对于(int i=0;i
然而,当我基于这两个函数运行perf stat
时,我对“页面错误”统计信息感到困惑。sqmat\u mult
的输出为:
428374.070363 task-clock (msec) # 1.000 CPUs utilized
128 context-switches # 0.000 K/sec
127 cpu-migrations # 0.000 K/sec
12,334 page-faults # 0.029 K/sec
8,63,12,33,75,858 cycles # 2.015 GHz (83.33%)
2,89,73,31,370 stalled-cycles-frontend # 0.34% frontend cycles idle (83.33%)
7,90,36,10,13,864 stalled-cycles-backend # 91.57% backend cycles idle (33.34%)
2,24,41,64,76,049 instructions # 0.26 insn per cycle
# 3.52 stalled cycles per insn (50.01%)
8,84,30,79,219 branches # 20.643 M/sec (66.67%)
1,04,85,342 branch-misses # 0.12% of all branches (83.34%)
428.396804101 seconds time elapsed
8534.611199 task-clock (msec) # 1.000 CPUs utilized
39876.726670 task-clock (msec) # 1.000 CPUs utilized
11 context-switches # 0.000 K/sec
11 cpu-migrations # 0.000 K/sec
12,334 page-faults # 0.309 K/sec
1,19,87,36,75,397 cycles # 3.006 GHz (83.33%)
49,19,07,231 stalled-cycles-frontend # 0.41% frontend cycles idle (83.33%)
50,40,53,90,525 stalled-cycles-backend # 42.05% backend cycles idle (33.35%)
2,24,10,77,52,356 instructions # 1.87 insn per cycle
# 0.22 stalled cycles per insn (50.01%)
8,75,27,87,494 branches # 219.496 M/sec (66.68%)
50,48,390 branch-misses # 0.06% of all branches (83.33%)
39.879816492 seconds time elapsed
而sqmat\u mult\u efficient
的输出为:
428374.070363 task-clock (msec) # 1.000 CPUs utilized
128 context-switches # 0.000 K/sec
127 cpu-migrations # 0.000 K/sec
12,334 page-faults # 0.029 K/sec
8,63,12,33,75,858 cycles # 2.015 GHz (83.33%)
2,89,73,31,370 stalled-cycles-frontend # 0.34% frontend cycles idle (83.33%)
7,90,36,10,13,864 stalled-cycles-backend # 91.57% backend cycles idle (33.34%)
2,24,41,64,76,049 instructions # 0.26 insn per cycle
# 3.52 stalled cycles per insn (50.01%)
8,84,30,79,219 branches # 20.643 M/sec (66.67%)
1,04,85,342 branch-misses # 0.12% of all branches (83.34%)
428.396804101 seconds time elapsed
8534.611199 task-clock (msec) # 1.000 CPUs utilized
39876.726670 task-clock (msec) # 1.000 CPUs utilized
11 context-switches # 0.000 K/sec
11 cpu-migrations # 0.000 K/sec
12,334 page-faults # 0.309 K/sec
1,19,87,36,75,397 cycles # 3.006 GHz (83.33%)
49,19,07,231 stalled-cycles-frontend # 0.41% frontend cycles idle (83.33%)
50,40,53,90,525 stalled-cycles-backend # 42.05% backend cycles idle (33.35%)
2,24,10,77,52,356 instructions # 1.87 insn per cycle
# 0.22 stalled cycles per insn (50.01%)
8,75,27,87,494 branches # 219.496 M/sec (66.68%)
50,48,390 branch-misses # 0.06% of all branches (83.33%)
39.879816492 seconds time elapsed
使用基于转置的乘法,“后端循环空闲”将如预期的那样大大减少。这是由于获取相干内存的等待时间较短。让我困惑的是,“页面错误”的数量是相同的。起初我认为这可能是一个上下文切换问题,所以我让程序运行时使用调度SCHED_FIFO
和优先级1
。上下文切换的数量从大约800个减少到11个,但“页面错误”仍然与以前完全相同
我使用的矩阵的维数是2048x2048
,因此整个数组将无法容纳在4K页面中。它也不适合我的整个缓存(在我的例子中是4MiB),因为三个矩阵(3*2048*2048*sizeof(int)==48MiB)的大小远远超过了总的可用缓存。假设这里的“页面错误”指的是TLB未命中或缓存未命中,我看不出这两种算法如何具有完全相同的数字。我知道,我看到的许多效率改进来自一级缓存命中的事实,但这并不意味着RAM到缓存的传输没有作用
我还做了另一个实验,看看“页面错误”是否与数组大小成比例关系——正如预期的那样
所以我的问题是——
2我想您可以构建一个体系结构,其中TLB包含未映射的虚拟地址信息,或者内存不包含缓存,但我怀疑这种体系结构是否存在。讨论了页面错误、TLB未命中和缓存未命中的区别。工作集的大小除以页面大小(4k)就相当于案例中的页面错误数。该算法与@Zulan没有任何区别。我不确定你为什么认为该算法的内存访问模式与页面错误无关-我的问题就是这个。好的,我将尝试为你的具体示例澄清。不幸的是,链接问题的答案有问题。为了减少页面错误,请为内核分配足够大的块以使用匿名hugepages。如果默认情况下没有将其设置为对物理内存进行碎片整理以查找连续的2M块,请使用
madvise(MADV_HUGEPAGE)
鼓励它对该区域进行碎片整理。此外,您还可以使用mmap(MAP\u POPULATE)
将内存分配给“prefault”它,这样在触摸它时不会出现任何页面错误,只有TLB未命中@祖兰,你可能想在回答中提到这一点。