【发布时间】:2021-04-27 07:09:03
【问题描述】:
我了解加载存储队列的基本工作原理,即
- 当负载计算它们的地址时,它们会检查存储队列中是否存在相同地址的任何先前存储,如果有,则它们会从最近的存储中获取数据,否则会从写入缓冲区或数据缓存中获取。
- 当存储计算它们的地址时,它们会检查加载队列中是否存在任何加载违规
我的疑问是当
-
在第一种情况下,由于存储队列中的一些未解析的存储地址而导致加载访问数据缓存,并且在 L1 数据缓存中访问未命中,并且在可以从缓存中检索数据之前,存储地址已解析。现在,商店确实加载队列检查是否有任何违规行为。依赖负载之前已经访问过数据缓存,但由于长时间的延迟未命中,尚未从缓存中接收到值。存储是发布加载违规还是进行存储到加载转发并从缓存中取消数据?
-
当l1数据缓存中的加载访问未命中时,加载被放置在MSHR中,以免阻塞执行阶段。当未命中解决时,该加载的 MSHR 条目具有有关目标寄存器和物理地址的信息。所以这个值可以在物理寄存器中更新,但是 MSHR 如何与加载队列通信以得知该值可用?这在管道阶段何时发生? 因为我在某处读过 MSHR 存储物理地址和 Load-store 队列存储虚拟地址。那么 MSHR 是如何与 LSQ 通信的呢?
我没有找到任何关于这些疑问的资源。
【问题讨论】:
-
2:例如,英特尔 CPU 重放等待缓存未命中加载的 uops 会导致预期它是 L2 命中,然后是 L3 命中,然后显然会继续重播它们,直到它们最终成功。 (如果这些微指令是该端口最旧的)。 Weird performance effects from nearby dependent stores in a pointer-chasing loop on IvyBridge. Adding an extra load speeds it up?。另请参阅About the RIDL vulnerabilities and the "replaying" of loads 的顶部 - 但请注意需要编辑的警告。
-
@Peter,至少在我对 Skylake 的测试中,它们似乎只是在预期 L1 或 L2 命中而不是 L3 或更高版本时投机调度。这是有道理的,因为 L3 命中不是恒定的延迟。因此,如果有一条指令直接依赖于负载,您通常会收到 3 次未命中 L3 或 DRAM 的总分派。如果有更多的依赖指令,你当然可以得到更多,当你有一个依赖加载链时,它会变得特别有趣。
-
@BeeOnRope:也许我记错了,但我认为我们(你会)在一段时间内看到了许多额外的调度,用于等待来自 RAM 的缓存未命中的 uop。可能那是一个指针追逐测试,所以我们可以一致地同时拥有一个缓存未命中负载,它的地址已经准备好。 IIRC L2-hit pointer-chat 有 1 次额外调度,L3-hit 有更多,而且似乎 L3-miss 有足够的额外时间,可以通过在某个点后每 5 个周期开始调度来解释。或者类似的东西。
-
@BeeOnRope:有没有关于 uop 回放的更新描述的很好的问答?在我们发现从 RS 重放的不是拆分加载或缓存未命中本身,而是依赖于它们的微指令之后,我似乎从未有时间更新我的一些答案,所以指针追逐误导了我们。但我曾希望在 cmets 之外的某个地方有准确的描述。也许在你的维基上?
-
@PeterCordes - 是的,您确实可以看到每次未命中的许多重播(最多约 10 个,IIRC),但这些是在“嵌套”重播的情况下,如指针追逐或在许多 uops 的情况下取决于负载。我不记得您描述的纯负载未命中的任何重复调度。但是,对于其他情况,随着时间的推移会重复分派,也许这就是您所想的:在存储到加载转发的情况下,如果依赖于丢失的负载,您可能会随着时间的推移看到存储的大量重播,什么的。
标签: queue cpu-architecture cpu-cache micro-architecture