Whiskey Lake i7-8565U
/Ubuntu 18.04
/HT enabled
考虑以下代码,该代码将寄存器 ymm0
和 ymm1
中的一些垃圾数据写入 16 MiB 静态分配的 WB 内存,循环由 6400 次迭代组成(因此页面错误影响可以忽略不计):
;rdx = 16MiB >> 3
xor rcx, rcx
store_loop:
vmovdqa [rdi + rcx*8], ymm0
vmovdqa [rdi + rcx*8 + 0x20], ymm1
add rcx, 0x08
cmp rdx, rcx
ja store_loop
使用
taskset -c 3 ./bin
我正在通过此示例测量 RFO 请求,结果如下:Performance counter stats for 'taskset -c 3 ./bin':
1 695 029 000 L1-dcache-load-misses # 2325,60% of all L1-dcache hits (24,93%)
72 885 527 L1-dcache-loads (24,99%)
3 411 237 144 L1-dcache-stores (25,05%)
946 374 671 l2_rqsts.all_rfo (25,11%)
451 047 123 l2_rqsts.rfo_hit (25,15%)
495 868 337 l2_rqsts.rfo_miss (25,15%)
2 367 931 179 l2_rqsts.all_pf (25,14%)
568 168 558 l2_rqsts.pf_hit (25,08%)
1 785 300 075 l2_rqsts.pf_miss (25,02%)
1 217 663 928 offcore_requests.demand_rfo (24,96%)
1 963 262 031 offcore_response.demand_rfo.any_response (24,91%)
108 536 dTLB-load-misses # 0,20% of all dTLB cache hits (24,91%)
55 540 014 dTLB-loads (24,91%)
26 310 618 dTLB-store-misses (24,91%)
3 412 849 640 dTLB-stores (24,91%)
27 265 942 916 cycles (24,91%)
6,681218065 seconds time elapsed
6,584426000 seconds user
0,096006000 seconds sys
l2_rqsts.all_rfo
的描述是建议 DCU 可以执行某种 RFO 预取。从
Intel Optimization Manual/2.6.2.4
对 DCU 的描述中不清楚:所以我猜 DCU 遵循“访问类型”:如果它是 RFO,那么 DCU 会执行 RFO 预取。
所有这些 RFO 预取都应该与需求 RFO 一起进入 L2,并且只有其中一些(
l2_rqsts.rfo_miss
)应该进入非核心。 offcore_requests.demand_rfo
只计算需求 rfo,但 l2_rqsts.rfo_miss
计算所有 rfo(需求 + dcu prefectch),这意味着不等式 offcore_requests.demand_rfo < l2_rqsts.rfo_miss
应该成立。问题 1: 为什么
l2_rqsts.rfo_miss
比 offcore_requests.demand_rfo
少很多(甚至 l2_rqsts.all_rfo
比 offcore_requests.demand_rfo
少)我预计需求
offcore_requests.demand_rfo
可以与 offcore_response.demand_rfo.any_response
匹配,因此这些 Core PMU 事件的数量应该大致相等问题 2: 为什么
offcore_response.demand_rfo.any_response
几乎是 offcore_requests.demand_rfo
的 1.5 倍?我猜 L2-streamer 也会做一些 RFO 预取,但无论如何都不应该在
offcore_requests.demand_rfo
中考虑。UPD :
$ sudo rdmsr -p 3 0x1A4
1
L2-Streamer 关闭
Performance counter stats for 'taskset -c 3 ./bin':
1 672 633 985 L1-dcache-load-misses # 2272,75% of all L1-dcache hits (24,96%)
73 595 056 L1-dcache-loads (25,00%)
3 409 928 481 L1-dcache-stores (25,00%)
1 593 190 436 l2_rqsts.all_rfo (25,04%)
16 582 758 l2_rqsts.rfo_hit (25,07%)
1 579 107 608 l2_rqsts.rfo_miss (25,07%)
124 294 129 l2_rqsts.all_pf (25,07%)
22 674 837 l2_rqsts.pf_hit (25,07%)
102 019 160 l2_rqsts.pf_miss (25,07%)
1 661 232 864 offcore_requests.demand_rfo (25,02%)
3 287 688 173 offcore_response.demand_rfo.any_response (24,98%)
139 247 dTLB-load-misses # 0,25% of all dTLB cache hits (24,94%)
56 823 458 dTLB-loads (24,90%)
26 343 286 dTLB-store-misses (24,90%)
3 384 264 241 dTLB-stores (24,94%)
37 782 766 410 cycles (24,94%)
9,320791474 seconds time elapsed
9,213383000 seconds user
0,099928000 seconds sys
可以看出
offcore_requests.demand_rfo
更接近 l2_rqsts.rfo_miss
,但仍然存在一些差异。在 OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD
的英特尔文档中,我发现了以下内容:所以我的猜测是 L2 预取被提升为 Demand 并计入 Demand offcore 请求。但它并没有解释
offcore_response.demand_rfo.any_response
和 offcore_requests.demand_rfo
之间的区别,现在几乎是两倍:offcore_requests.demand_rfo 1 661 232 864
对比
offcore_response.demand_rfo.any_response 3 287 688 173
UPD:
$ sudo rdmsr -p 3 0x1A4
3
所有 L2 预取器关闭
Performance counter stats for 'taskset -c 3 ./bin':
1 686 560 752 L1-dcache-load-misses # 2138,14% of all L1-dcache hits (23,44%)
78 879 830 L1-dcache-loads (23,48%)
3 409 552 015 L1-dcache-stores (23,53%)
1 670 187 931 l2_rqsts.all_rfo (23,56%)
15 674 l2_rqsts.rfo_hit (23,59%)
1 676 538 346 l2_rqsts.rfo_miss (23,58%)
156 206 l2_rqsts.all_pf (23,59%)
14 436 l2_rqsts.pf_hit (23,59%)
173 163 l2_rqsts.pf_miss (23,59%)
1 671 606 174 offcore_requests.demand_rfo (23,59%)
3 301 546 970 offcore_response.demand_rfo.any_response (23,59%)
140 335 dTLB-load-misses # 0,21% of all dTLB cache hits (23,57%)
68 010 546 dTLB-loads (23,53%)
26 329 766 dTLB-store-misses (23,49%)
3 429 416 286 dTLB-stores (23,45%)
39 462 328 435 cycles (23,42%)
9,699770319 seconds time elapsed
9,596304000 seconds user
0,099961000 seconds sys
现在到 l2 的预取请求总数(来自所有预取器)是
156 206 l2_rqsts.all_pf
。UPD:
$ sudo rdmsr -p 3 0x1A4
7
̶A̶l̶l̶ ̶p̶r̶e̶f̶e̶t̶c̶h̶e̶r̶s̶ ̶t̶u̶r̶n̶e̶d̶ ̶o̶f̶f̶.̶ 仅启用IP预取器
Performance counter stats for 'taskset -c 3 ./bin':
1 672 643 256 L1-dcache-load-misses # 1893,36% of all L1-dcache hits (24,92%)
88 342 382 L1-dcache-loads (24,96%)
3 411 575 868 L1-dcache-stores (25,00%)
1 672 628 218 l2_rqsts.all_rfo (25,04%)
10 585 l2_rqsts.rfo_hit (25,04%)
1 684 510 576 l2_rqsts.rfo_miss (25,04%)
10 042 l2_rqsts.all_pf (25,04%)
4 368 l2_rqsts.pf_hit (25,05%)
9 135 l2_rqsts.pf_miss (25,05%)
1 684 136 160 offcore_requests.demand_rfo (25,05%)
3 316 673 543 offcore_response.demand_rfo.any_response (25,05%)
133 322 dTLB-load-misses # 0,21% of all dTLB cache hits (25,03%)
64 283 883 dTLB-loads (24,99%)
26 195 527 dTLB-store-misses (24,95%)
3 392 779 428 dTLB-stores (24,91%)
39 627 346 050 cycles (24,88%)
9,710779347 seconds time elapsed
9,610209000 seconds user
0,099981000 seconds sys
UPD:
$ sudo rdmsr -p 3 0x1A4
f
禁用所有预取器
Performance counter stats for 'taskset -c 3 ./bin':
1 695 710 457 L1-dcache-load-misses # 2052,21% of all L1-dcache hits (23,47%)
82 628 503 L1-dcache-loads (23,47%)
3 429 579 614 L1-dcache-stores (23,47%)
1 682 110 906 l2_rqsts.all_rfo (23,51%)
12 315 l2_rqsts.rfo_hit (23,55%)
1 672 591 830 l2_rqsts.rfo_miss (23,55%)
0 l2_rqsts.all_pf (23,55%)
0 l2_rqsts.pf_hit (23,55%)
12 l2_rqsts.pf_miss (23,55%)
1 662 163 396 offcore_requests.demand_rfo (23,55%)
3 282 743 626 offcore_response.demand_rfo.any_response (23,55%)
126 739 dTLB-load-misses # 0,21% of all dTLB cache hits (23,55%)
59 790 090 dTLB-loads (23,55%)
26 373 257 dTLB-store-misses (23,55%)
3 426 860 516 dTLB-stores (23,55%)
38 282 401 051 cycles (23,51%)
9,377335173 seconds time elapsed
9,281050000 seconds user
0,096010000 seconds sys
即使预取器被禁用,
perf
仍将 12
报告为 pf_miss
(可在不同的运行中以不同的值重现)。这可能是计数错误。此外,1 672 591 830 l2_rqsts.rfo_miss
的值略大于 1 662 163 396 offcore_requests.demand_rfo
,我也倾向于将其解释为计数错误。假设: DCU RFO 预取丢失 L2 和离开核心在
offcore_requests.demand_rfo
中。如果 L2-streamer 关闭,该假设有效:
102 019 160 l2_rqsts.pf_miss + 1 579 107 608 l2_rqsts.rfo_miss = 1 681 126 768
; 1 661 232 864 offcore_requests.demand_rfo
如果所有预取器都关闭,该假设也适用:
1 684 510 576 l2_rqsts.rfo_miss
; 1 684 136 160 offcore_requests
。在所有 PF 关闭的情况下,
L1-dcache-load-misses
大约等于 l2_rqsts.rfo_miss
,而 offcore_requests.demand_rfo
又等于 offcore_response.demand_rfo.any_response
我仍然不知道为什么
offcore_requests.demand_rfo
的值比 ojit_code 大得多 最佳答案
在我看来,循环正在写入 2^18 个缓存行,并且有一个外循环(问题中未显示)执行内循环(所示的那个)6400 次。因此,预期的需求 RFO 总数为 2^18*6400 = 1,677,721,600 条,预期停用的商店指令数为 1677721600*2 = 3,355,443,200。实测L1-dcache-stores
门店数量约为34.10亿,比预期增加了约5500万。这个事件计数应该是准确的,所以我认为问题中没有显示影响事件计数的其他代码。加载事件计数还表明有许多加载来自某处,这对事件 l2_rqsts.all_pf
、 l2_rqsts.pf_hit
、 l2_rqsts.pf_miss
的计数有重大影响。我已经问过我的评论中是否有任何其他重要的代码包含在测量中。
从启用所有预取器的第一个实验的结果来看,l2_rqsts.rfo_hit
+ offcore_requests.demand_rfo
加起来的数量几乎等于需求 RFO 的预期数量。 L2 流传输器实际上可以预取 RFO,如英特尔优化手册中所述,该手册解释了如何存在 l2_rqsts.rfo_hit
。我不知道为什么 l2_rqsts.rfo_miss
不等于 offcore_requests.demand_rfo
。我认为事件 offcore_requests.demand_rfo
是准确的。尝试仅禁用 L1D 预取器并保持启用 L2 预取器,然后查看执行时间是否增加。如果 L1D 预取器实际上发送了大量的 RFO,则 L1D 中应该有足够的写入命中,从而对性能产生影响。
禁用 L2 流光的第二个实验的结果非常接近预期。 l2_rqsts.rfo_hit
非常小并且 l2_rqsts.all_rfo
几乎等于 offcore_requests.demand_rfo
,这等于需求 RFO 的预期数量。这提供了 L1D 预取器不预取 RFO 的实验证据。在这种情况下,l2_rqsts.all_pf
应该为零,因为两个 L2 预取器都被禁用。
在上一个实验中,您只关闭了四个数据缓存预取器中的三个;你错过了 DCU IP 预取器。在这种情况下,2_rqsts.all_rfo
的计数甚至更接近于异常(exception)情况。尝试禁用 DCU IP 预取器并查看 l2_rqsts.rfo_hit
(可能还有 l2_rqsts.all_pf
)是否为零。
您的处理器的规范更新文档中的 Erratum 058 说 offcore_response.demand_rfo.any_response
可能会过度计算,可以使用 offcore_requests.demand_rfo
代替。这解释了为什么 offcore_response.demand_rfo.any_response
大于所有实验中的预期值,并且还表明 offcore_requests.demand_rfo
是可靠的。
关于assembly - 为什么对非核心响应/非核心请求的需求过多?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60390539/