我是否正确,前两个 MOV 指令都只需要 2 个(它们都是将内存移动到寄存器)CPU 周期?我认为对虚拟方法的调用比这慢?在第 178 页的指令延迟表中,它说这个调用的延迟是 2 个 CPU 周期(我认为?)。
不,只有最小延迟的 2 个 CPU 周期。
让我们检查一下 Agner 的表格http://www.agner.org/optimize/instruction_tables.pdf
整数指令。
指令 操作数 uops 融合域 uops 未融合域 (p015 p0 p1 p5 p23 p4) 延迟 倒数吞吐量 注释
Inst Oper fus p23 p4 Latency Rec.
MOV r32/64,m32/64 1 1 2 0.5
要找到时间,什么时候指令会产生结果,你应该使用“延迟”列。并且每个 mov 的延迟为 2 个周期,并且仅列出最小值(检查“列标题说明”中的文本 - “延迟 - 这是指令在依赖链中生成的延迟。数字是最小值。缓存未命中,未对准,...可能会显着增加时钟计数。”)
如果您有很多不同的多态调用,它们所需的内存可能不会被缓存。我们从不同的评论中知道缓存和内存延迟,并且所有这些都是通过长链的依赖MOV
项来衡量的mov eax, [eax]; mov eax, [eax]; mov eax, [eax]; ...
。Ivy 的值是:在 L1 中命中 = 4 个周期,在 L2 中命中 = 11 个周期,在 L3 中命中 = 30-40 个周期,在高速缓存和访问内存中未命中 = 32 个周期 + 60 ns(在 3 GHz 时,每 ns 3 个周期 > 200循环)。甚至没有容易获得 2 个周期延迟的情况(什么比 L1 更接近 ALU?只有 72 条目加载缓冲区用于重新排序加载?),并且第二个周期没有机会有 2 个周期延迟mov
(它的操作数是第一个 mov 的结果,因此在第一个 mov 退休之前没有什么可以乱序执行)。
在从Agner's Links 链接的表格http://instlatx64.atw.hu/中,有报告为 Ivy InstLatX64 for Intel Core i7-3770K, 3700 MHz made with aida_bench64.dll
27 AMD64 :MOV r64, [m64] L: 1.14ns= 4.0c T: 0.14ns= 0.50c
该表显示L
了 L1 缓存中命中的实际延迟 ( ),4 个周期。
64-ia-32-architectures-optimization-manual.pdf第 46 页“2.2.5.1 加载和存储操作概述”部分中的相同数据(L1 为 4c,L2 为 ~12c,L3 为 26-31c) ,表“2- 10 查找顺序和加载延迟"
所以根据 Fog 手册,上面的 ASM 确实需要 6 个 CPU 周期,我没有误解任何东西吗?
在最好的情况下,当第一次加载在关键路径上以乱序 = 2 个周期提前执行时;L1 中的第二次负载命中 = 关键路径上的 4 个周期;2个执行周期call
;BTB(分支目标预测/间接分支目标)成功,当您从单个调用地址总是跳转到同一个目标(或具有周期性模式的少量目标)时更有可能 - 您将有 8 个周期来确认该分支被预测正确,它可能被目标函数的 OoO 执行部分隐藏。
如果 L1/L2 中的任何加载未命中,则应添加相应的缓存延迟。如果 L3 未命中,则添加 200 个循环。
如果 BTB 未命中,您将受到至少 15 个周期的惩罚(查看Agner 的 microarchitecture.pdf,第 27 页“3.7 Intel Sandy Bridge 和 Ivy Brindge 中的分支预测;错误预测惩罚”) - 对于缓存的微指令;更多用于 L1i 中的目标。您可以在相同的 microarchitecture.pdf 第 25 页“3.5 PM 和 Core2 中的分支预测;间接跳转和调用的模式识别”和“BTB 组织......用于间接跳转和间接调用”中阅读有关旧 BTB 的信息。
非常有用的文档来自英特尔:“英特尔® 64 和 IA-32 架构优化参考手册” 64-ia-32-architectures-optimization-manual.pdf。它具有调优建议和有关性能计数器的信息,这将帮助您获得代码的实际延迟和未命中率(请查看 B.6.3.2 部分“虚拟表和间接调用”)。