gpt4 book ai didi

gcc - mtune 实际上是如何工作的?

转载 作者:行者123 更新时间:2023-12-01 18:35:28 26 4
gpt4 key购买 nike

有一个相关问题:GCC: how is march different from mtune?

但是,现有的答案并没有比 GCC 手册本身更进一步。最多,我们得到:

If you use -mtune, then the compiler will generate code that works on any of them, but will favour instruction sequences that run fastest on the specific CPU you indicated.

The -mtune=Y option tunes the generated code to run faster on Y than on other CPUs it might run on.

但是,GCC 在构建时到底如何支持一种特定的架构,同时仍然能够在其他(通常较旧的)架构上运行构建,尽管速度较慢?

我只知道一件事(但我不是计算机科学家)能够做到这一点,那就是 CPU 调度程序。然而,(对我来说)似乎 mtune 并没有在幕后生成调度程序,而是可能有其他一些机制在起作用。

我有这样的感觉有两个原因:

  1. 搜索“gcc mtune cpudispatcher”没有找到任何相关内容;和
  2. 如果它基于调度程序,我认为它可能会更智能(即使通过 mtune 之外的某些选项)并测试 cpuid 以在运行时检测支持的指令,而不是依赖于构建时提供的命名架构。

那么它到底是如何工作的呢?

最佳答案

-mtune 不会创建调度程序,它也不需要调度程序:我们已经告诉编译器我们的目标架构是什么。

来自GCC docs :

-mtune=cpu-type

        Tune to cpu-type everything applicable about the generated code, except for the ABI and the
        set of available instructions.

这意味着 GCC 不会使用仅在 cpu 类型 1 上可用的指令,但它将生成在 cpu 类型 上最佳运行的代码嗯>。

要理解最后这句话对于理解架构和微架构之间的区别是必要的。
该架构意味着 ISA(指令集架构),并且不受 -mtune 的影响。
微架构是架构在硬件中的实现方式。对于相同的指令集(读:体系结构),代码序列可能在一个 CPU(读微体系结构)上以最佳方式运行,但由于实现的内部细节而不能在另一个 CPU 上运行。这可以达到仅在一个微架构上优化代码序列的程度。

在生成机器代码时,GCC 通常在选择如何排序指令以及使用哪种变体方面具有一定的自由度。
它将使用启发式方法生成在最常见的 CPU 上快速运行的指令序列,有时它会牺牲 CPU x 的 100% 最优解决方案(如果这会惩罚 CPU y) em>、zw

当我们使用 -mtune=x 时,我们正在针对 CPU x 微调 GCC 的输出,从而生成 100% 最佳的代码(从 GCC 角度来看)在该 CPU 上。

作为一个具体示例,请考虑 how this code is compiled :

float bar(float a[4], float b[4])
{
for (int i = 0; i < 4; i++)
{
a[i] += b[i];
}

float r=0;

for (int i = 0; i < 4; i++)
{
r += a[i];
}

return r;
}

当针对 Skylake 或 Core2 时,a[i] += b[i]; 的矢量化(如果矢量不重叠)会有所不同:

Skylake

    movups  xmm0, XMMWORD PTR [rsi]
movups xmm2, XMMWORD PTR [rdi]
addps xmm0, xmm2
movups XMMWORD PTR [rdi], xmm0
movss xmm0, DWORD PTR [rdi]

核心2

    pxor    xmm0, xmm0
pxor xmm1, xmm1
movlps xmm0, QWORD PTR [rdi]
movlps xmm1, QWORD PTR [rsi]
movhps xmm1, QWORD PTR [rsi+8]
movhps xmm0, QWORD PTR [rdi+8]
addps xmm0, xmm1
movlps QWORD PTR [rdi], xmm0
movhps QWORD PTR [rdi+8], xmm0
movss xmm0, DWORD PTR [rdi]

主要区别在于 xmm 寄存器的加载方式,在 Core2 上,它使用 movlpsmovhps 加载两次,而不是使用单个movups
两种加载方法在 Core2 微架构上效果更好,如果您查看 Agner Fog 的指令表,您会发现 movups 被解码为 4 uops,并且有 2 个周期的延迟,而每个 movXps 为 1 uop 和 1 个延迟周期。
这可能是由于当时 128 位访问被分成了两个 64 位访问。
在 Skylake 上,情况恰恰相反:movups 的性能优于两个 movXps

所以我们必须选择一个。
一般来说,GCC 选择第一个变体,因为 Core2 是一个旧的微架构,但我们可以使用 -mtune 覆盖它。

<小时/>

1指令集通过其他开关选择。

关于gcc - mtune 实际上是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44490331/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com