Bee*_*ope 5 x86 intel cpu-architecture micro-architecture
在现代 Intel 1 x86 上,是否在调度2 时、或完成3时或介于4之间的某个时间点从 RS(保留站)释放负载 uops ?
1我也对 AMD Zen 和续集很感兴趣,所以也可以随意包括在内,但为了使问题易于管理,我将其限制为英特尔。此外,AMD 似乎与英特尔的加载管道略有不同,这可能会使在 AMD 上进行调查成为一项单独的任务。
2这里的调度是指让 RS 执行。
3在这里完成意味着当加载数据返回并准备好满足相关的 uops 时。
4甚至在这两个事件定义的时间范围之外的某个地方,这似乎不太可能,但可能。
以下实验表明在加载完成之前的某个时间点取消分配 uops。虽然这不是您问题的完整答案,但它可能会提供一些有趣的见解。
在 Skylake 上,有一个 33 入口的负载预留站(参见/sf/answers/4100312891/)。Coffee Lake i7-8700K 也应该是这种情况,用于以下实验。
我们假设R14包含一个有效的内存地址。
clflush [R14]
clflush [R14+512]
mfence
# start measuring cycles
mov RAX, [R14]
mov RAX, [R14]
...
mov RAX, [R14]
mov RBX, [R14+512]
# stop measuring cycles
Run Code Online (Sandbox Code Playgroud)
mov RAX, [R14]展开 35 次。在这个系统上从内存加载至少需要大约 280 个周期。如果加载 uops 一直停留在 33 个入口的保留站直到完成,最后一个加载只能在 280 多个周期后开始,并且还需要大约 280 个周期。然而,该实验的总测量时间仅为约 340 个循环。这表明负载 uops 在完成之前的某个时间离开 RS。
相比之下,以下实验显示了大多数 uop 被迫留在预留中直到第一次加载完成的情况:
mov RAX, R14
mov [RAX], RAX
clflush [R14]
clflush [R14+512]
mfence
# start measuring cycles
mov RAX, [RAX]
mov RAX, [RAX]
...
mov RAX, [RAX]
mov RBX, [R14+512]
# stop measuring cycles
Run Code Online (Sandbox Code Playgroud)
前 35 个负载现在相互依赖。该实验的测量时间约为 600 个循环。
实验是在除一个内核之外的所有内核都禁用的情况下进行的,并将 CPU 调控器设置为性能 ( cpupower frequency-set --governor performance)。
以下是我使用的nanoBench命令:
./nanoBench.sh -unroll 1 -basic -asm_init "clflush [R14]; clflush [R14+512]; mfence" -asm "mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RAX, [R14]; mov RBX, [R14+512]"
./nanoBench.sh -unroll 1 -basic -asm_init "mov RAX, R14; mov [RAX], RAX; clflush [R14]; clflush [R14+512]; mfence" -asm "mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RAX, [RAX]; mov RBX, [R14+512]"
刚刚遇到这个问题。这是我对答案的尝试。
简短回答:我对某些部分仍然有点不确定,但根据使用各种性能计数器和性能监控中断的一些测量结果,“看起来”负载 uop 在被分派到负载端口的同一周期内从 RS 中删除或者至少在不久之后。
详细信息:不久前我尝试编写一个内核模块来模仿这里的想法。链接的博客文章很好地描述了这个想法,所以我不会在这里详细解释。主要思想是在经过一定数量的周期后触发性能监控中断,冻结所有计数器值(当前跟踪),存储它们并重置/重复。对 1, 2, ... n 个周期执行此操作可以让我们了解在周期粒度上微架构发生的情况。图片的准确程度是另一回事...我用于测量的内核模块的源代码可以在这里找到。
长答案:我在 i7-1065G7 (Ice Lake) 上使用上面提到的内核模块分析了以下代码,并跟踪了 11 个不同的性能计数器。在mov描述指令之前,clflush存储在的地址上调用r8. 这样做是为了让加载需要足够长的时间,以便轻松判断 uop 是否在执行之前、之后或期间从 RS 中删除(否则加载将在大约 4 个周期内完成)。我总共测量了多达 600 个周期,其中大多数与这个问题相关的事件发生在 65 个周期内。为了解决噪音,我对每个周期进行了 1024 次试验,并存储了出现次数最多的计数器值。幸运的是,对于下表中的每个周期和每个计数器,我最多只看到一次试验的值偏差,其余 1023 次试验给出相同的计数器值。
563: 0f 30 wrmsr
565: 4d 8b 00 mov (%r8),%r8
568: 0f ae f0 mfence
56b: 0f ae e8 lfence
Run Code Online (Sandbox Code Playgroud)
下面列出了跟踪的计数器。描述来自英特尔 SDM。
INST_RETIRED_ANY_P: To track when wrmsr retired
RS_EVENTS_EMPTY_CYCLES: Count of cycles RS is empty
UOPS_DISPATCHED_PORT_PORT_0: # uops dispatched to port 0
UOPS_DISPATCHED_PORT_PORT_1: # uops dispatched to port 1
UOPS_DISPATCHED_PORT_2_3: # uops dispatched to port 2,3 (load addr ports)
UOPS_DISPATCHED_PORT_4_9: # uops dispatched to port 4,9 (store data ports)
UOPS_DISPATCHED_PORT_PORT_5: # uops dispatched to port 5
UOPS_DISPATCHED_PORT_PORT_6: # uops dispatched to port 6
UOPS_DISPATCHED_PORT_7_8: # uops dispatched to port 7,8 (store addr ports)
UOPS_EXECUTED_THREAD: # uops executed
UOPS_ISSUED_ANY: # uops sent to RS from RAT
Run Code Online (Sandbox Code Playgroud)
下表列出了每个周期的每个计数器值。因此,根据下表,在第 47 个周期将一个 uop 发送到 RS,并在第 51-54 个周期占用 RS。这大概是负载 uop。在周期 54RS_EVENTS_EMPTY_CYCLES和UOPS_DISPATCHED_PORT_2_3增量这意味着(至少我是如何解释它的)负载 uop 已被分派并从 RS 中释放出来。
我不确定的是,在周期 52 时,还会向 RS 发出三个 uops。他们似乎到达并占据了第 55-58 周期的 RS。但是只有两个 uops 被分派到执行端口并且 RS 被清空。无论到第 59 个周期,RS 都是空的(计数在每个周期增加)。负载完成并在mov大约 500 个周期后退出。
+-------+--------------+-----------------+--------+--------+----------+----------+--------+--------+----------+---------------+-------------------+------------------------+
| Cycle | Inst Retired | Cycles RS Empty | Port 0 | Port 1 | Port 2,3 | Port 4,9 | Port 5 | Port 6 | Port 7,8 | uops executed | uops issued to RS | Comments |
+-------+--------------+-----------------+--------+--------+----------+----------+--------+--------+----------+---------------+-------------------+------------------------+
| 1 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | |
| 2 | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | |
| 3 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | |
| 4 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 2 | 2 uops issued |
| 5 | 0 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 2 | |
| 6 | 0 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 2 | |
| 7 | 0 | 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 2 | |
| 8 | 0 | 10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 2 | |
| 9 | 0 | 11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 2 | |
| 10 | 0 | 12 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 2 | |
| 11 | 0 | 12 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 2 | |
| 12 | 0 | 12 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 2 | |
| 13 | 0 | 12 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 2 | |
| 14 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 3 | 2 | |
| 15 | 0 | 14 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 3 | 2 | 2 uops dispatched |
| 16 | 0 | 15 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 4 | 2 | |
| 17 | 0 | 16 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 2 | 2 uops executedd |
| 18 | 0 | 17 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 2 | |
| 19 | 0 | 18 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 2 | |
| 20 | 0 | 19 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 2 | |
| 21 | 0 | 20 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 2 | |
| 22 | 0 | 21 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 2 | |
| 23 | 0 | 22 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 5 | |
| 24 | 0 | 23 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 6 | 4 uops issued |
| 25 | 0 | 24 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 6 | |
| 26 | 0 | 25 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 6 | |
| 27 | 0 | 25 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 6 | |
| 28 | 0 | 25 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 6 | |
| 29 | 0 | 25 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 5 | 6 | |
| 30 | 0 | 25 | 0 | 1 | 0 | 0 | 0 | 2 | 0 | 5 | 6 | |
| 31 | 0 | 26 | 0 | 1 | 0 | 0 | 0 | 3 | 0 | 5 | 6 | |
| 32 | 0 | 27 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 6 | 6 | |
| 33 | 0 | 28 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 7 | 6 | |
| 34 | 0 | 29 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | 3 uops executed |
| 35 | 0 | 30 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 36 | 1 | 31 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | wrmsr retired |
| 37 | 1 | 32 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 38 | 1 | 33 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 39 | 1 | 34 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 40 | 1 | 35 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 41 | 1 | 36 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 42 | 1 | 37 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 43 | 1 | 38 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 44 | 1 | 39 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 45 | 1 | 40 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 46 | 1 | 41 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 47 | 1 | 42 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 6 | |
| 48 | 1 | 43 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 7 | 1 uop issued |
| 49 | 1 | 44 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 7 | |
| 50 | 1 | 45 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 7 | |
| 51 | 1 | 46 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 7 | |
| 52 | 1 | 46 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 10 | 3 uops issued |
| 53 | 1 | 46 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 10 | |
| 54 | 1 | 46 | 0 | 1 | 0 | 0 | 0 | 4 | 0 | 8 | 10 | port 2,3 load addr |
| 55 | 1 | 47 | 0 | 1 | 1 | 0 | 0 | 4 | 0 | 8 | 10 | |
| 56 | 1 | 47 | 0 | 1 | 1 | 0 | 0 | 4 | 0 | 8 | 10 | executing load |
| 57 | 1 | 47 | 0 | 1 | 1 | 0 | 0 | 4 | 0 | 9 | 10 | |
| 58 | 1 | 47 | 0 | 1 | 1 | 0 | 0 | 4 | 0 | 9 | 10 | port 4,9 store data |
| 59 | 1 | 48 | 0 | 1 | 1 | 1 | 0 | 4 | 1 | 9 | 10 | port 7,8 store address |
| 60 | 1 | 49 | 0 | 1 | 1 | 1 | 0 | 4 | 1 | 9 | 10 | |
| 61 | 1 | 50 | 0 | 1 | 1 | 1 | 0 | 4 | 1 | 11 | 10 | 2 uops executed |
| 62 | 1 | 51 | 0 | 1 | 1 | 1 | 0 | 4 | 1 | 11 | 10 | |
| 63 | 1 | 52 | 0 | 1 | 1 | 1 | 0 | 4 | 1 | 11 | 10 | |
| 64 | 1 | 53 | 0 | 1 | 1 | 1 | 0 | 4 | 1 | 11 | 10 | |
| 65 | 1 | 54 | 0 | 1 | 1 | 1 | 0 | 4 | 1 | 11 | 10 | |
+-------+--------------+-----------------+--------+--------+----------+----------+--------+--------+----------+---------------+-------------------+------------------------+
Run Code Online (Sandbox Code Playgroud)
因此,根据该表,负载 uop 似乎是在调度到负载端口的同时或几个周期后从 RS 中删除的。我对图表中的值进行了一些完整性检查,在大多数情况下,所有计数器值都有意义。我还没有弄清楚的两件事是,4 个 uops 将被发送到 RS(周期 24),但只有 3 个被执行(周期 35)。同样在第 52 次循环发出 3 次 uops,但只执行了 2 次(第 61 次循环)
谢谢
| 归档时间: |
|
| 查看次数: |
289 次 |
| 最近记录: |