相关文章推荐
卖萌的眼镜  ·  1 ...·  8 月前    · 
卖萌的眼镜  ·  不同CPU性能大PK | plantegg·  8 月前    · 

作者: zhaorenhai

本文简单总结了一下,在aarch64服务器平台进行应用软件开发或者移植工作,编译代码时,编译器应该添加哪些选项。网上类似文章不少,但是由于arm平台涉及了移动开发,嵌入式开发,服务器开发各个领域,编译方式也有交叉编译,本地编译等,而且编译器也有gcc,armcc,armclang,clang等等多种,再加上arm平台历史版本众多,又分了32位,64位,网上这些文档一般都不明确说明文档涉及的开发平台,对应指令集版本,需要的编译器之类的情况,让人看上去比较头疼。

本文涉及的范围:aarch64 Linux 服务器平台应用软件开发,不涉及交叉编译,只讨论本地编译情况, 只讨论可以免费使用的开源gcc编译器(clang也是可以免费可以使用的开源编译器,但是编译参数全面兼容gcc,所以本文只讨论gcc)。 另外本文也只讨论和aarch64平台强相关的参数,通用的编译参数讨论的文章比较多,本文不再赘述。
最主要的参考资料来自于这篇文档: https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html。 本文主要讨论最主要的也是最容易引起混淆的-march,-mtune,-mcpu参数。其余参数一般都是在一些极特殊的场景下才用到,比如需要改变代码模型,需要改变数据模型,需要指定字节序为大端字节序等等,或者开发特殊的软件比如gcc编译器之类的时候才用到,一般服务器应用软件开发很少用到,所以一般保持默认值即可,后续如果有实际遇到的场景,会再补充到本文中。

先看-march参数,原文描述:
-march=name
Specify the name of the target architecture and, optionally, one or more feature modifiers. This option has the form -march=arch{+[no]feature}*.
The table below summarizes the permissible values for arch and the features that they enable by default:

arch value Architecture Includes by default ‘armv8-a’ Armv8-A ‘+fp’, ‘+simd’ ‘armv8.1-a’ Armv8.1-A ‘armv8-a’, ‘+crc’, ‘+lse’, ‘+rdma’ ‘armv8.2-a’ Armv8.2-A ‘armv8.1-a’ ‘armv8.3-a’ Armv8.3-A ‘armv8.2-a’ ‘armv8.4-a’ Armv8.4-A ‘armv8.3-a’, ‘+fp16fml’, ‘+dotprod’ ‘armv8.5-a’ Armv8.5-A ‘armv8.4-a’, ‘+sb’, ‘+ssbs’, ‘+predres’ ‘armv8.6-a’ Armv8.6-A ‘armv8.5-a’, ‘+bf16’, ‘+i8mm’

The value ‘native’ is available on native AArch64 GNU/Linux and causes the compiler to pick the architecture of the host system. This option has no effect if the compiler is unable to recognize the architecture of the host system,
The permissible values for feature are listed in the sub-section on -march and -mcpu Feature Modifiers. Where conflicting feature modifiers are specified, the right-most feature is used.
GCC uses name to determine what kind of instructions it can emit when generating assembly code. If -march is specified without either of -mtune or -mcpu also being specified, the code is tuned to perform well across a range of target processors implementing the target architecture.

这个参数可以指定编译的目标架构,这里的架构指得是ARM CPU的指令集架构,那我们应该指定哪个版本的指令集架构,才能做到最好的兼容性,能兼容市场上所有的ARM CPU,或者既能兼顾兼容性,又能兼顾一部分性能,毕竟新版本的指令集架构能用上更新的具有特定功能的指令集。 这个需要看一下目前市场上所有的ARM服务器CPU的情况,网上目前已有的相关文档要么比较老,信息不全,要么就是出现把移动CPU和服务器CPU都放到一起的情况,比较混乱。所以本文重新搜集了目前所有ARM服务器CPU的信息,如下表(资料来源于互联网):

指令集架构 Ampere X-gene-1 8c 2.4GHz 40nm Storm ARMv8.0-A Ampere X-gene-2 8c 2.4GHz 28nm Shadowcat ARMv8.0-A Ampere eMag8180 (X-gene-3) 32c 2.8GHz-3.3GHz 16nm Skylark ARMv8.0-A Ampere Altra 32-80c 1.7-3.3GHz Quicksilver (Neoverse N1) ARMv8.2-A 2020年3月 Ampere Altra Max 128c 7nm Quicksilver (Neoverse N1) ARMv8.2-A 2020年6月 Cavium (被Marvell收购) ThunderX (CN8890) 48c 1.9GHz 28nm ThunderX1 ARMv8.1-A Cavium (被Marvell收购) ThunderX2 (CN99xx系列) 32-54c 1.6-2.5GHz 14nm 16nm Vulcan (从Broadcom收购) ARMv8.1-A 2018年5月 Cavium (被Marvell收购) ThunderX3 96c 3.1GHz 7nm Triton ARMv8.3-A Qualcomm Centriq 2400系列 40-48c 2.2-2.6GHz 10nm Falkor ARMv8.0-A Phytium FT1500 16c 1.6GHz 28nm Earth ARMv8.0-A Phytium FT2000+ 64c 2.3GHz 16nm ARMv8.0-A Phytium S2500 64c 2.0-2.2GHz 16nm ARMv8.0-A HiSilicon Hi1616 32c 2.4GHz 16nm Cortex-A72 ARMv8.0-A HiSilicon Kunpeng 920 (Hi1620) 48c 3.0GHz 7nm Taishan V110 ARMv8.2-A Annapurna Labs (被AWS收购) Gravtion 16c 2.3GHz 16nm Cortex-A72 ARMv8.0-A 2018年11月 Annapurna Labs (被AWS收购) Gravtion2 64c 2.5GHz 7nm Neoverse N1 ARMv8.2-A 2019年12月 Nuvia Phoenix

备注1:此表仅搜集了64位的arm cpu相关信息,32位的arm服务器cpu比较老,实际应用也不多,可以不用再考虑兼容工作。
备注2: 此表仅包含通用arm服务器cpu相关信息,不包含移动平台的cpu以及超算cpu,更不包含嵌入式以及实时计算cpu。

可以看出来市场上还是有不少ARMv8.0-A指令集架构的CPU,所以如果要做到最佳兼容性,-march参数的name的值就要指定为armv8-a。但是也要看到,高通实际上已经退出服务器CPU市场,Cavium,Ampere,Phytium各有一部分市场,但都不大,Nuvia是新晋厂商,还没有产品问世,市场规模最大的应该主要是海思的Kunpeng920和亚马逊的Gravition2,依托于华为云和亚马逊云,应用较广泛。而且从上图中可以看出各厂商最近两年新出的CPU,基本都已经支持了ARMv8.2-A指令集,考虑到近两年ARM服务器应用刚刚开始大规模普及,特别是华为云和亚马逊云上刚刚开始大规模上线ARM的云服务器实例,所以一些新开发的应用软件或者新迁移的应用软件,甚至可以指定为armv8.2-a,这样可以做到兼容性和性能兼顾。
另外-march参数还支持指定一些扩展选项,下面我们来逐个看下这些扩展选项:

从ARMv8.1-a之后就默认包含了此扩展选项,所以当-march参数的name值为armv8-a的时候,才需要添加此选项,如果代码中涉及crc相关功能和指令,建议加上此选项 crypto 加密选项,这个是个额外扩展,没有哪个版本的指令集默认包含此选项,所以如果代码中涉及加密相关功能和指令,都要加上此选项。一般的应用开发涉及这个的比较少,所以这个看实际应用情况来决定要不要加 浮点指令,从ARMv8-a就开始默认支持,可以忽略 高级单指令多数据流指令,从ARMv8-a就开始默认支持,可以忽略 目前已出的cpu支持此功能的较少,当前还不能加 最新的原子指令集需要此选项,从ARMv8.1-a之后就默认包含,当-march参数的name值为armv8-a的时候,而且确定CPU支持此扩展选项的情况下可以添加。 乘积累加指令,在一些特殊场景会用到,使用较少。不过从ARMv8.1-a之后就默认包含。 半精度浮点指令,在一些图形软件中会用到,用途较少,建议视使用情况添加。

还有一些其他的扩展选项,不过都是在更新版本的指令集中才支持,当前已经问世的CPU都不支持,这里就不再讨论。

再来看-mtune参数,原文描述:
-mtune=name
Specify the name of the target processor for which GCC should tune the performance of the code. Permissible values for this option are: ‘generic’, ‘cortex-a35’, ‘cortex-a53’, ‘cortex-a55’, ‘cortex-a57’, ‘cortex-a72’, ‘cortex-a73’, ‘cortex-a75’, ‘cortex-a76’, ‘cortex-a76ae’, ‘cortex-a77’, ‘cortex-a65’, ‘cortex-a65ae’, ‘cortex-a34’, ‘ares’, ‘exynos-m1’, ‘emag’, ‘falkor’, ‘neoverse-e1’,‘neoverse-n1’,‘qdf24xx’, ‘saphira’, ‘phecda’, ‘xgene1’, ‘vulcan’, ‘octeontx’, ‘octeontx81’, ‘octeontx83’, ‘octeontx2’, ‘octeontx2t98’, ‘octeontx2t96’ ‘octeontx2t93’, ‘octeontx2f95’, ‘octeontx2f95n’, ‘octeontx2f95mm’, ‘a64fx’, ‘thunderx’, ‘thunderxt88’, ‘thunderxt88p1’, ‘thunderxt81’, ‘tsv110’, ‘thunderxt83’, ‘thunderx2t99’, ‘thunderx3t110’, ‘zeus’, ‘cortex-a57.cortex-a53’, ‘cortex-a72.cortex-a53’, ‘cortex-a73.cortex-a35’, ‘cortex-a73.cortex-a53’, ‘cortex-a75.cortex-a55’, ‘cortex-a76.cortex-a55’ ‘native’.
The values ‘cortex-a57.cortex-a53’, ‘cortex-a72.cortex-a53’, ‘cortex-a73.cortex-a35’, ‘cortex-a73.cortex-a53’, ‘cortex-a75.cortex-a55’, ‘cortex-a76.cortex-a55’ specify that GCC should tune for a big.LITTLE system.
Additionally on native AArch64 GNU/Linux systems the value ‘native’ tunes performance to the host system. This option has no effect if the compiler is unable to recognize the processor of the host system.
Where none of -mtune=, -mcpu= or -march= are specified, the code is tuned to perform well across a range of target processors.
This option cannot be suffixed by feature modifiers.
这个参数比较简单,实际上就是指定目标CPU微架构,让gcc编译的时候,根据目标cpu的微架构进行特定的优化,比如指定为tsv110时,gcc就会根据鲲鹏920的微架构,进行一些指令的流水线重排,会提高一些性能。但是指定这个,同时也就意味着牺牲了兼容性,编译后的软件只能在目标CPU平台上运行。

最后看一下-mcpu参数,原文描述:
-mcpu=name
Specify the name of the target processor, optionally suffixed by one or more feature modifiers. This option has the form -mcpu=cpu{+[no]feature}*, where the permissible values for cpu are the same as those available for -mtune. The permissible values for feature are documented in the sub-section on -march and -mcpu Feature Modifiers. Where conflicting feature modifiers are specified, the right-most feature is used.
GCC uses name to determine what kind of instructions it can emit when generating assembly code (as if by -march) and to determine the target processor for which to tune for performance (as if by -mtune). Where this option is used in conjunction with -march or -mtune, those options take precedence over the appropriate part of this option.
可以看出来,这个参数实际上就是前面两个参数的综合,而且指定两个参数的优先级会高于这个参数。据说后续这个参数会被干掉。建议可以忽略此参数,只用前面两个参数即可。

总结:在aarch64服务器平台,进行应用软件开发,编译时,除了通用的编译选项之外,一般只需要添加-march=armv8-a即可,考虑到crc扩展选项应用比较多,可以加上crc扩展选项,比如-march=armv8-a+crc,这样可以做到最好的兼容性。 如果确定平台支持最新的原子指令,可以再加上+lse,其余的扩展选项建议根据实际应用情况添加。 如果既想兼顾兼容性和性能,建议直接指定-march=armv8.2-a,这样不仅包含了crc和lse扩展选项,而且最两年新出的CPU都可以做到兼容。 如果想做到最佳性能,还可以添加-mtune参数,但是这个要确保编译出来的软件只在目标平台运行。
另外,由于编译器的习惯, ARM平台上char的默认类型为unsigned char,这与x86正好相反(x86的char默认是有符号的),在x86上运行稳定的代码,移植过来将遇到char类型的变化,会带来不少问题。由于x86上的char类型与我们的编程习惯更一致,所以我们一般将ARM平台上的程序的char类型指定为signed char。所以还需要添加编译选项-fsigned-char。

最后,上述编译选项和扩展是在不同的gcc版本里逐步得到支持的,所以添加这些选项还要注意gcc的版本,对于-march的 name和扩展选项的支持情况,可以参考ARM官方的这个文档: https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/architecture-support 对于-mtune选项的支持建议参考不同版本的gcc文档,主要看AArch64-Options这个章节就行。

参考资料:
https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/architecture-support
https://clang.llvm.org/docs/ClangCommandLineReference.html
http://www.semiinsights.com/s/electronic_components/23/39697.shtml
http://news.eeworld.com.cn/qrs/2019/ic-news011452649.html
http://news.eeworld.com.cn/xfdz/ic497298.html
https://www.cirmall.com/articles/31558
https://koolshare.cn/thread-147215-1-3.html
http://www.360doc.com/content/20/0101/18/99071_883541215.shtml
https://en.wikichip.org/wiki/
https://blog.csdn.net/u014470361/article/details/85988772
https://www.cnblogs.com/panda-w/p/11003389.html
https://developer.arm.com/ip-products/processors/cortex-a/cortex-a78
https://en.wikipedia.org/wiki/Comparison_of_ARMv8-A_cores
https://aijishu.com/a/1060000000133361
http://phytium.com.cn/article/5
https://www.sohu.com/a/361552782_163726?scm=1002.44003c.fe021c.PC_ARTICLE_REC
https://www.infoq.cn/article/34moxVRHI8qprbh9I1mp

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now