考虑以下循环:
.loop:
add rsi, STRIDE
mov eax, dword [rsi]
dec ebp
jg .loop
其中STRIDE
是一些非负整数,而rsi
包含一个指向bss
节中定义的缓冲区的指针。此循环是代码中的唯一循环。也就是说,它不会在循环之前被初始化或触动。在Linux上,缓冲区的所有4K虚拟页面将按需映射到同一物理页面。
我已经为所有可能的跨度(0-8192)运行了此代码。每访问的一页,次要和主要页面错误的度量数量分别分别为1和0。我还测量了该范围内所有跨度的Haswell下列所有性能事件。
DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK :在所有TLB级别中均未命中 导致任意页面大小的页面浏览。
DTLB_LOAD_MISSES.WALK_COMPLETED_4K :由于需求而完成的页面浏览 导致4K分页浏览在任何TLB级别下的加载未命中。
DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M :由于以下原因完成了页面浏览: 在任何TLB级别中,导致2M / 4M页面漫游的需求负载未命中。
DTLB_LOAD_MISSES.WALK_COMPLETED_1G :所有TLB级别的加载未命中原因 完成的页面浏览。 (1G)。
DTLB_LOAD_MISSES.WALK_COMPLETED :已完成的页面可在任何 由于未满足需求负载而导致页面大小
对于所有大步幅,大页面的两个计数器都为零。如下图所示,其他三个计数器很有趣。
在大多数情况下,MISS_CAUSES_A_WALK
事件每访问一页都会发生5次,WALK_COMPLETED_4K
和WALK_COMPLETED
事件每访问一页都会发生4次。这意味着所有完成的页面遍历都是针对4K页面。但是,没有完成第五步。为什么每页有那么多的页面浏览?是什么导致这些页面漫游?也许当页面遍历触发页面错误时,在处理完该错误之后,还会有另一个页面遍历,因此这可以算作两次已完成的页面遍历。但是,为什么会有4个完整的页面漫游和一个显然被取消的漫游?请注意,Haswell上只有一个页面漫游器(而Skylake上只有两个)。
我意识到有一个TLB预取器似乎只能预取此thread中讨论的下一页。同样根据该线程,预取程序遍历似乎没有被计为MISS_CAUSES_A_WALK
或WALK_COMPLETED_4K
事件。
如上图所示,还有一种特殊的小步幅模式。另外,在步幅220附近有一个非常奇怪的图案(尖峰)。我能够多次重现这些图案。下图放大了该奇怪的图案,因此您可以清楚地看到它。这些模式的原因是什么?
我还尝试了以下配置:
mlockall
。我得出以下结论:
DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK
事件,但不会发生DTLB_LOAD_MISSES.WALK_COMPLETED_4K
。当由于软件预取而导致页面漫游导致页面错误时,将发生DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK
事件和DTLB_LOAD_MISSES.WALK_COMPLETED_4K
事件。当然,在预取的情况下,不会触发页面错误。mlockall
似乎对事件计数没有任何重大影响。DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK
似乎总是比DTLB_LOAD_MISSES.WALK_COMPLETED_4K
大。PAGE_WALKER_LOADS.*
事件计数的总和始终大于页面浏览的数量。我不清楚它们之间的关系。DTLB_LOAD_MISSES.WALK_DURATION
。但是似乎任何页面走动都至少需要14个周期。除此之外,我没有看到关于PAGE_WALKER_LOADS.*
的模式。 @BeeOnRope建议将LFENCE
放入循环中,并将其展开零次或多次,以更好地了解投机,无序执行对事件计数的影响。下图显示了结果。当循环展开0-63次(单次迭代中有1-64个添加/加载指令对)时,每一行代表一个特定的加载步幅。 y轴每页标准化。访问的页面数与次要的页面错误数相同。
我还进行了没有LFENCE
但展开度不同的实验。我没有为这些图表制作图表,但下面将讨论主要区别。
我们可以得出以下结论:
MISS_CAUSES_A_WALK
和WALK_COMPLETED_4K
在不同的展开度上会显示出较大的变化。大步幅具有平滑的曲线,其中MISS_CAUSES_A_WALK
收敛到3或5,WALK_COMPLETED_4K
收敛到3或4。LFENCE
似乎仅在展开度精确为零(即,每次迭代有一个负载)时有所不同。如果没有LFENCE
,则结果(如上所述)为每页5 MISS_CAUSES_A_WALK
和4 WALK_COMPLETED_4K
个事件。使用LFENCE
,它们每页都变为3。对于较大的展开度,事件计数平均逐渐增加。当展开度至少为1时(即,每次迭代至少有两个负载),LFENCE
基本上没有区别。这意味着,在没有LFENCE
的情况下,上面的两个新图图是相同的,除了每次迭代有一个负载时。顺便说一下,只有在展开度为零且没有LFENCE
时,才会出现怪异的尖峰。LFENCE
可以实质上获得相同的效果。展开后,无需使用LFENCE
。在任何情况下,使用LFENCE
的执行时间都会更长。因此,使用它减少页面浏览量会大大降低性能,而不是提高性能。