考虑以下循环:
loop:
movl $0x1,(%rax)
add $0x40,%rax
cmp %rdx,%rax
jne loop
Run Code Online (Sandbox Code Playgroud)
whererax被初始化为大于 L3 缓存大小的缓冲区的地址。每次迭代都会对下一个缓存行执行存储操作。我希望从 L1D 发送到 L2 的 RFO 请求数量或多或少等于访问的缓存线数量。问题是,即使程序在用户模式下运行,这似乎也只是当我计算内核模式事件时的情况,除非我在下面讨论的一种情况。缓冲区的分配方式似乎无关紧要(.bss、.data 或来自堆)。
我的实验结果如下表所示。所有实验都是在禁用超线程和启用所有硬件预取器的处理器上进行的。
我测试了以下三种情况:
NoInit. 在这种情况下只有一个循环。LoadInit. 在这种情况下有两个循环。StoreInit. 在这种情况下有两个循环。下表显示了英特尔 CFL 处理器上的结果。这些实验是在 Linux 内核版本 4.4.0 上进行的。
下表显示了英特尔 HSW 处理器上的结果。请注意,HSW 未记录事件L2_RQSTS.PF_HIT、L2_RQSTS.PF_MISS和OFFCORE_REQUESTS.ALL_REQUESTS。这些实验是在 Linux 内核版本 4.15 上进行的。
每个表的第一列包含性能监控事件的名称,其计数显示在其他列中。在列标签中,字母U和 分别K代表用户模式和内核模式事件。对于有两个循环的情况,数字1和2分别用于指代初始化循环和主循环。例如,LoadInit-1K代表LoadInit案例初始化循环的内核模式计数。
表中显示的值按高速缓存行的数量标准化。它们也按以下颜色编码。绿色越深,该值相对于同一表中的所有其他单元格就越大。但是,CFL 表的最后三行和 HSW 表的最后两行未进行颜色编码,因为这些行中的某些值太大。这些行被涂成深灰色,以表明它们不像其他行那样进行颜色编码。
我期望用户模式L2_RQSTS.ALL_RFO事件的数量等于访问的缓存行的数量(即标准化值为 1)。该事件在手册中描述如下:
计算对 L2 缓存的 …
我得到了错误的结果,因为我在测量时没有包括这里讨论的预取触发事件。话虽如此,AFAIKrep movsb与临时存储相比,我只看到 RFO 请求减少,memcpy因为在加载时预取更好,而没有对存储进行预取。不是因为 RFO 请求针对完整缓存行存储进行了优化。这种有意义的,因为我们没有看到RFO请求优化掉了vmovdqa一个zmm寄存器,我们预计如果真的在那里为整个缓存线存储情况。话虽如此,存储上缺乏预取和非临时写入的缺乏使得很难看出如何rep movsb具有合理的性能。
编辑:RFO 可能来自rep movsb不同的请求vmovdqa,因为rep movsb它可能不请求数据,只需在独占状态下取行即可。对于有收银机的商店,情况也可能如此zmm。但是,我没有看到任何性能指标来测试这一点。有谁知道吗?
rep movsb的memcpy作为相比,memcpy与实现的vmovdqa?rep movsb的memcpy作为相比,memcpy与实现vmovdqa两个单独的问题,因为我相信我应该看到 RFO 请求减少了rep movsb,但如果不是这种情况,我是否也应该看到增加?
CPU - Icelake: Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz
我试图在使用不同的方法时测试 RFO 请求的数量,memcpy包括:
vmovdqa