-march和-mtune有什么不同?

104

我试图查阅GCC手册,但仍然不太明白。

-march-mtune有什么区别?

在什么情况下只使用-march,而在什么情况下需要同时使用两者?是否有可能只使用-mtune

2个回答

121
如果您使用-march,那么GCC将生成适用于指定CPU的指令,但通常不适用于体系结构系列中较早的CPU。
如果您只是使用-mtune,那么编译器将生成适用于其中任何一个的代码,但会优先考虑在您指定的特定CPU上运行最快的指令序列。例如,为该CPU适当设置循环展开启发式。 -march=foo意味着-mtune=foo,除非您还指定了不同的-mtune。这是使用-march比仅启用-mavx等选项更好的原因之一,而不采取调整措施。
注意:对于GCC没有明确识别的CPU而言,-march=native仍将启用GCC可以检测到的新指令集,但会保留-mtune=generic。如果您希望它生成良好的代码,请使用足够新的GCC来了解您的CPU。

11
不回答是否同时使用两者是否有意义,或者当设置相同值时mtune是否是多余的。 - Pavel Šimerda
18
直观地说,答案已经隐含在这两个特性的定义中。此外,文档明确说明“march”意味着“mtune”。因此,对你的异议的回答分别是“不”和“是”。 - underscore_d
谢谢您如此优雅地解释!您让它变得易于理解。 - Rahim Khoja
7
如果你只在自己的处理器上运行,使用-march选项;如果你希望代码在其他处理器上也能稳定运行,使用-mtune选项。 - j riv
6
用户还应该明白,旧版本的编译器(在某些CPU出现之前发布)可能会导致不同的最优 mtunemarch 组合。这篇博客文章通过其他内容阐明了这一点:https://lemire.me/blog/2018/07/25/it-is-more-complicated-than-i-thought-mtune-march-in-gcc/ - qneill

57
这是我搜到的内容: -march=X选项接受一个CPU名称X,允许GCC生成使用X所有特性的代码。GCC手册详细解释了哪些CPU名称意味着哪些CPU系列和特性。
因为通常会添加特性但不会删除,使用-march=X构建的二进制文件将在CPU X上运行,并有很大的机会在比X更新的CPU上运行,但几乎肯定不会在任何旧于X的CPU上运行。某些指令集(如3DNow!)可能特定于特定的CPU供应商,使用这些指令集可能会得到不能运行在竞争对手的CPU上的二进制文件,无论是更新的还是其他的。 -mtune=Y选项调整生成的代码,使其在可能运行的其他CPU上比在Y上更快。 -march=X意味着-mtune=X-mtune=Y不会覆盖-march=X,因此,例如,-march=core2-mtune=i686可能没有意义——由于-march=core2,您的代码将无法在任何旧于core2的CPU上运行,因此为什么要优化比core2还老的东西呢?-march=core2 -mtune=haswell更有意义:不要使用超出core2提供范围(这仍然比-march=i686提供的要多得多!)的特性,但确实针对更新的haswell CPU进行代码优化,而不是针对core2

还有一个选项是-mtune=genericgeneric让GCC生成在当前CPU上运行最佳的代码(generic的含义随着GCC版本的变化而改变)。在Gentoo论坛上有传言说-march=X -mtune=generic生成的代码比-march=X -mtune=X(或仅-march=X,因为-mtune=X被隐含)生成的代码在X上运行得更快。不知道这是否正确。

一般来说,除非您确切地知道您需要什么,否则最好的做法似乎是指定-march=<您要运行的最旧CPU>-mtune=generic-mtune=generic在这里用于对抗隐含的-mtune=<您要运行的最旧CPU>,因为您可能不想针对最旧的CPU进行优化)。或者如果您只打算在构建时运行在同一台机器上,可以使用-march=native


4
但如果您使用-march=native,您可能想要指定-mtune=X,因为默认值仍然是-mtune=generic,如此处所述:https://lemire.me/blog/2018/07/25/it-is-more-complicated-than-i-thought-mtune-march-in-gcc/。 - Roland Weber
@RolandWeber:只有在使用GCC版本过旧而不了解您的CPU时才会发生这种情况。如果您使用了了解您的CPU的GCC,则“-march=native”可以很好地暗示“tune=native”。该文章只呈现了糟糕的情况。新的GCC版本通常会生成更好的代码,特别是在使用AVX2和AVX-512等新指令时。而且,拥有为您的CPU设计的调整设置(如循环展开启发式)绝对是一个优点。因此,如果您足够关心性能以使用这些选项,请使用新的GCC,至少要使用了解您的CPU的版本,最好是当前稳定版本。 - Peter Cordes
GCC 不能为同一微架构系列的新成员提供比 tune=generic 更好的支持,尤其是像 Kaby Lake 这样在微架构上与 Skylake 完全相同的处理器。但我认为它仍然有不同的系列/步进,因此只知道 Skylake 及更早版本的 GCC 可能无法识别并进行优化。 - Peter Cordes
如果您将“-march=native”用于来自同一供应商的所有在您之后发布的CPU,那么这不应该是可以的吗? - ZeroPhase
@ZeroPhase:通常情况下,CPU供应商通常会使其CPU向后兼容以前的型号,不删除之前支持的指令。虽然并非总是如此:AMD仅在Bulldozer系列中支持了XOP SIMD扩展,而Zen则没有支持。Intel支持Ice Lake / Tiger Lake芯片中的AVX-512,但在Alder Lake中又将其删除。更早之前,AMD支持3dNow(64位MMX寄存器中的FP SIMD),但一旦SSE变得普及(新的128位寄存器),就将其删除了。这还仅仅是在x86中,在那里向后兼容驱动商业成功(在CPUID特征检测之前)。 - Peter Cordes
@ZeroPhase:此外,-march=native也包含了-mtune=native。通常情况下,厂商会让新的CPU能够高效地运行为早期一代所调整的机器码,至少不会有明显的减速。有时候可能会发现性能有所提升,例如在不同的展开次数之间选择最佳的方案,或者使用不同的指令等。Pentium 4曾试图避免这种情况,希望每个人都会重新编译以避免如inc这样在P4上不够优化的指令,但结果并不是很好(主要原因还有其他),后来的CPU大多数情况下都没有这种缺陷。Silvermont仍然有些…… - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接