Intel & AMD 指令集之间的差异 您所在的位置:网站首页 inter和AMD怎么看型号 Intel & AMD 指令集之间的差异

Intel & AMD 指令集之间的差异

2024-06-19 23:32| 来源: 网络整理| 查看: 265

促进我写这篇文章的起因是,线上机器会使用基于 SPDK 的云盘存储方案,需要编译一个 RPM 包。这个包在 Intel 机器是运行正常的,在 AMD 的机器上无法运行报不支持 AVX512 指令。

这个问题很常见,是指令集不兼容造成的。AMD 虽然是 x86 厂商,即使是同一代其生产的 CPU 也不是和 Intel 的 CPU 是指令集完全兼容的。两家厂商的 CPU 会有一些对方不支持的指令集。

出现问题的原因也很简单,这个 RPM 包是在一台编译机器上编译的,这台编译机器是 Intel 机器,正好支持部分 AVX512 指令集。但线上的 AMD 机器是不支持 AVX512 指令集的。解决这个问题很简单,只要使用 I 家 和 A 家 这两款 CPU 共同支持的指令集即可。实际上,是不需要我们手动对比指令集的差异,寻找交集。因为 CPU 指令集之间的差异会对软件的移植性造成重大影响,所以业界早早就有了对应的指令集基线(baseline)。

指令集的演进

gcc 编译器执行 gcc -Q --help=target,输出会包含如下部分,

Known valid arguments for -march= option: i386 i486 i586 pentium lakemont pentium-mmx [...]

其中 march option 下面罗列的就是 gcc 的支持的各种指令集,重点关注其中 x86-64/x86-64-v2/x86-64-v3/x86-64-v4 这几个,这几个是 x86 平台最常用的指令集了。绝大多数软件都会使用这几个指令集进行编译,保证不同 CPU 之间的指令集兼容。指令集从 x86-64 到 x86-64-v4 ,每一个版本都往 baseline 中加入了新的指令集,性能会更好,但移植会变差,一些比较老的 CPU 可能跑不了使用 x86-64-v4 指令集编译的软件了。

x86-64-v2 brings support (among other things) for vector instructions up to Streaming SIMD Extensions 4.2 (SSE4.2)  and Supplemental Streaming SIMD Extensions 3 (SSSE3), the POPCNT instruction (useful for data analysis and bit-fiddling in some data structures), and CMPXCHG16B (a two-word compare-and-swap instruction useful for concurrent algorithms). x86-64-v3 adds vector instructions up to AVX2, MOVBE (for big-endian data access), and additional bit-manipulation instructions. x86-64-v4 includes vector instructions from some of the AVX-512 variants. 对比 Intel 与 AMD 指令集差异

查看两款 CPU 支持的指令集之间的差异

gcc -Q -march=native --help=target | grep enabled

当 march 为 native 可以获得当前 CPU 支持的所有指令集。

表格中是 AMD EPYC 和 Intel Ice Lake CPU 的其中一款 CPU 指令集差异图, 两家的 CPU 每一代都会有各种各样的型号,这里是其中两款的对比,从图中看到,这个两款 CPU 都是比较新的,均支持 AVX512 系列指令集。两款 CPU 支持的指令集大部分都是重合的,一小部分是自家 CPU 独有的。如果我们使用 -march=native 在其中一款 CPU 上编译软件,计划运行在这两款 CPU 上,那么编译器使用到了任何一家的独有的指令集,软件在这两款 CPU 上就存在移植性问题了。

AMD EPYC Bergamo 仅 AMD 支持 仅 Intel 支持 Intel Ice Lake -m128bit-long-double -m128bit-long-double -m64 -m64 -m80387 -m80387 -mabm -mabm -madx -madx -maes -maes -malign-stringops -malign-stringops -mavx -mavx -mavx2 -mavx2 -mavx512bf16 AMD ONLY -mavx512bitalg -mavx512bitalg -mavx512bw -mavx512bw -mavx512cd -mavx512cd -mavx512dq -mavx512dq -mavx512f -mavx512f -mavx512ifma -mavx512ifma -mavx512vbmi -mavx512vbmi -mavx512vbmi2 -mavx512vbmi2 -mavx512vl -mavx512vl -mavx512vnni -mavx512vnni -mavx512vpopcntdq -mavx512vpopcntdq -mbmi -mbmi -mbmi2 -mbmi2 -mclflushopt -mclflushopt -mclwb -mclwb -mcrc32 -mclzero AMD ONLY -mcx16 -mcrc32 -mf16c -mcx16 -mfancy-math-387 -mf16c -mfma -mfancy-math-387 -mfp-ret-in-387 -mfma -mfsgsbase -mfp-ret-in-387 -mfxsr -mfsgsbase Intel ONLY -mgfni -mfxsr -mglibc -mglibc -mhard-float -mhard-float Intel ONLY -mhle -mieee-fp -mieee-fp -mlong-double-80 -mlong-double-80 -mlzcnt -mlzcnt -mmmx -mmmx -mmovbe -mmovbe -mmwait -mmwait -mpclmul -mpclmul -mpopcnt -mpopcnt -mprfchw -mprfchw -mpush-args -mpush-args -mrdpid AMD ONLY -mrdrnd -mrdrnd -mrdseed -mrdseed -mred-zone -mred-zone Intel ONLY -mrtm -msahf -msahf -msha -msha -msse -msse -msse2 -msse2 -msse3 -msse3 -msse4 -msse4 -msse4.1 -msse4.1 -msse4.2 -msse4.2 -msse4a AMD ONLY -mssse3 -mssse3 -mstv -mstv -mtls-direct-seg-refs -mtls-direct-seg-refs -mvaes -mvaes -mvpclmulqdq -mvpclmulqdq -mvzeroupper -mvzeroupper -mwbnoinvd -mwbnoinvd -mxsave -mxsave -mxsavec -mxsavec -mxsaveopt -mxsaveopt 指令集的基线 baseline

不同 CPU 指令集之间的差异,会导致软件的移植性产生重大影响。通常的情况下,我们希望我在 x86 平台编译的软件,能在任意 x86 机器(无论 Intel 还是 AMD)上运行,而不是在每一 款 CPU 上都要重新编译。这种问题就是指令集的移植性问题。

目前已经有解决方案了,那就是 gcc 的 -march 选项,通过在编译的时候指定 -march 实现一次编译,任意运行。gcc 编译的 -march 选项会限定是编译过程可以使用的指令集,目前这个阶段 x86-64-v2 架构是当前推荐的 -march 选项,在性能和移植性之间取得了比较好的平衡。

感兴趣的小伙伴可以在不同 CPU 平台上查询 x86-64-v2 指令集是否存在差异,结论肯定是不存在差异,因为这是一个 baseline,已经被标准化了。

gcc -Q -march=x86-64-v2 --help=target | grep enabled

那这些指令集的 baseline 是怎么标准化的?有些同学可能会对标准的由来感兴趣,通俗来说,是 CPU/OS/Compiler (具有影响力的头部)厂商大家一起坐下来开个会,在会上确定下一代指令集标准,也就是 baseline,确定后,软件厂商按照这个指令集标准编译软件,CPU 厂商按照这个标准设计 CPU。共同保证软件的移植性。其他非头部厂商也会跟进这个标准。

https://developers.redhat.com/blog/2021/01/05/building-red-hat-enterprise-linux-9-for-the-x86-64-v2-microarchitecture-level#

其他语言 go/java/python 编译

前面的介绍,主要是 C 语言,那其他语言比如(go/java/python/rust)编译的/运行的软件是否需要考虑指令集兼容?理论上,所有的语言,无论是编译型还是解释性语言都会面临兼容性的问题。毕竟写的软件总要在 CPU 上跑的。。。 前面介绍 C 语言,主要是因为 C 和硬件打交道的多,对性能和可移植性都有较高的要求,其他语言更多的集中在应用层。

python 是解释性语言,用户侧不存在指令集兼容问题。指令集差异在 cpython 那块。我们就认为不存在吧 go 是编译型语言。用户侧存在指令集兼容问题。但是因为 go 的默认配置使用的是最原始版本的 x86-64 指令集(go env 中 GOAMD64 环境变量代表是指令集版本),所以兼容性很好。。。。我们就认为不存在吧 java 是运行在 JVM 上的,指令集差异在 JVM 那层被屏蔽了,和 python 情况一样。我们也认为不存在 rust 是编译型语言,存在指令集兼容问题,情况类似 go,取决于默认配置。 编译优化与可移植性的矛盾

这里有一个规律,当我们使用 native 指令集(编译器使用机器上所有可用的指令集来优化) 编译的软件性能是最好的,同时可移植性也是最差的。

还有一个规律,所有语言都存在指令集的兼容性问题,但是实际使用中,我们并不需要考虑,这是因为语言的设计者已经将指令集兼容通过各种方式屏蔽掉了,比如 go 是使用最原始的 x86-64 指令集来屏蔽,java 通过 JVM 来屏蔽等等。

实际上往往只有像 C 语言会考虑指令集的兼容性,因为为了性能,编译器应该使用所有支持的指令集进行编译期优化,但是为了可移植性,又不能使用独有指令集。这本身就是一个矛盾。举个例子,像 DPDK/SPDK 这种专门为了性能而生的软件框架,他们在编译的时候,默认采用 native 进行编译,实际上为了可移植性,我么在编译时会使用 x86-64-v2/corei7 这些指令集,牺牲一些性能,提高可移植性。

在现实场景中,如果 CPU 型号是可控的,那么在编译时候,可以激进一些。如果 CPU 型号不可控的,那么还是保守一些。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有