在最近的高端Intel CPU上重新排序x64(x86-64)指令可以获得多少性能提升。在非常时间紧迫的情况下值得打扰吗?
我还想知道通过更改寄存器使用/使用额外的寄存器(如果空闲)来获得收益的可能性,以便在某些奇怪的情况下允许更长距离的代码移动?
答案 0 :(得分:7)
指令调度在短距离内通常不是很重要,因为无序执行通常有效。对于像某些ARM内核这样的有序CPU而言,这一点非常重要,因为调度会在使用结果的指令之前加载很多。
它可以帮助一些甚至在高端x86上,这取决于什么样的瓶颈限制了你的执行吞吐量。有关ROB大小与物理寄存器数量有关的一些有趣内容,请参阅http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/,这是无序执行的限制因素。 Software-pipelining可以帮助解决乱序执行难以隐藏的长依赖链。
尽早在关键路径依赖关系链上提供指令可能有所帮助,因为OOO调度通常会尝试执行最早的就绪优先。 (见How are x86 uops scheduled, exactly?)。
现代CPU是复杂的野兽,有时重新排序的东西会在你不希望它重要的时候发挥作用。有时候无法准确猜出它为何会产生影响。不同的排序会影响解码器甚至uop缓存中的前端带宽,因为有许多规则关于uop缓存(在Intel CPU上)如何将解码的uop包装成最多6个uop线。例如,Branch alignment for loops involving micro-coded instructions on Intel SnB-family CPUs
有时解释非常模糊不清。例如,在英特尔的优化手册Example 3-25. Re-ordering Sequence to Improve Effectiveness of Zero-Latency MOV Instructions中,他们讨论了立即覆盖零延迟-movzx结果以更快地释放内部资源。 (我尝试了Haswell和Skylake的例子,并发现mov-elimination确实在更多的时候工作,但实际上它在整个周期中实际上稍微慢了一些,而不是更快。这个例子是为了显示IvyBridge的好处,可能是其3个ALU端口的瓶颈,但HSW / SKL只是dep链中资源冲突的瓶颈,并且似乎不需要ALU端口来处理更多的movzx指令。)
这也可能适用于eliminated mov
instructions,而不仅仅是movzx
,但可能不适用。{/ p>
如果英特尔的手册没有将它作为一个例子,如果我能在真正的优化情况下(对于IvyBridge)遇到问题,我会想出这个IDK。发布与执行的uops(融合域与未融合域)的性能计数器显示消除了多少个移动uop,但如果没有优化手册说明原因,几乎不可能找出它发生的原因。重新排序附近的独立指令只是为了尝试,可以作为调整的最后一步,但在那时它是巫毒/黑魔法/猜测。
正如玛格丽特指出的那样,除了简单的调度之外,还有理由对指令进行重新排序。请参阅Agner Fog's optimization and microarchitecture guides以及x86代码Wiki中的其他资源以了解详情。
例如,由于宏观融合,将cmp/jcc
和test/jcc
分组在一起总是一个好主意。当您使用-march=haswell
或其他内容进行编译时,您的编译器将为您执行此操作,因为这将启用-mtune=haswell
。
如果它允许您避免某些mov
指令或溢出/重新加载,它还可以打开其他优化机会,但这不仅仅是调度指令。