发布于: Aug 18, 2022
C/C ++ 代码将极大的受益于设置优化代码的编译器标志并启用 ARM 特定的功能。
- GCC/G++ 编译选项
CPU |
GCC |
LLVM |
Graviton |
-march=armv8-a+crc+crypto |
-march=armv8-a+crc+crypto |
Graviton 2 |
-march=armv8.2- a+fp16+rcpc+dotprod+crypto |
-march=armv8.2- a+fp16+rcpc+dotprod+crypto |
-march 编译项告诉编译器应该为系统的处理器架构生成什么代码,即向编译器声明应该为某种 CPU 架构生成代码。不同的 CPU 具有不同的功能,支持不同的指令集,执行代码的方式也不同。march 标志将指示编译器为系统的 CPU 生成特定的代码,包括 CPU 的所有功能、特性、指令集、异常等等。
** 需要注意的一点是,对于 GCC 7.x 和 8.1、8.2 和 8.3 等版本 -march=native 不能正确地检测 Graviton 2 体系架构。务必请使用 -march=armv8.2-a 而不是 -march=native。GCC 9.x 以及 10.x 则可以很好的识别 Graviton 2 的体系结构。目前 Amazon Linux 2 缺省安装的 GCC 版本是 7.3.1,而 Ubuntu 20.04 缺省安装的 GCC 版本为 9.3.0,还可以通过 sudo apt install gcc-10 安装 GCC 10.0.1。
CPU |
GCC < 9 |
GCC >= 9 |
Graviton |
-mtune=cortex-a72 |
-mtune=cortex-a72 |
Graviton 2 |
-mtune=cortex-a72 |
-mtune=neoverse-n1 |
-mtune 此选项指定 GCC 为其调整代码性能对应特定目标 ARM 处理器类型,可以通过使用这个选项来实现更好的性能。此外,此选项可以指定 GCC 为 big.LITTLE 系统调整代码的性能。
所谓的 big.LITTLE ,是 ARM 的异质运算多核心处理器技术。具体做法是将比较耗电、但运算能力强的处理器核心组成的“big 集群”与低耗电、运算能力弱的处理器核心组成的“LITTLE 集群”结合在一起,这些处理器核心共享存储器区段,并能够在不同的 CPU 集群之间在线实时分派、切换负载。
- Large-System Extensions (LSE)
Graviton 2 处理器支持 ARMv8.2 指令集。LSE 则提供低成本的原子操作。原因是是 LSE 提高了 CPU 对 CPU 的通信、锁和互斥的系统吞吐量。当使用 LSE 而不是加载/存储独占时,这种改进可以提升一个数量级。POSIX 线程库需要 LSE 原子指令。LSE 对于锁定和线程同步例程很重要。例如 Amazon Linux 2 与 Ubuntu 20.04 均发布了一个支持 LSE 指令的 libc 库。编译器需要为使用原子操作的应用程序生成 LSE 指令。例如,像 PostgreSQL 这样的数据库代码包含原子结构;带有 std:: 原子语句的 C++11 代码转换为原子操作。GCC 的 -march=armv8.2-a 标志支持所有由 Graviton2 支持的指令,包括了 LSE。如果需要满足对于 LSE 的支持,还需要 libc 的版本要高于 2.3.0。目前 Amazon Linux 2 的 glibc 的版本为 2.26, Ubuntu 20.04 的 libc 的版本为 2.31。
Java 是一种通用编程语言。 编译后的 Java 代码可以在支持 Java 的所有平台上运行,而无需重新编译。 Java 应用程序通常被编译为可在任何 Java 虚拟机上运行的字节码,而与基础计算机体系结构无关。Java 受到了包括 ARM 在内的广泛的支持,并且在 ARM64 上是开箱即用的。 Amazon Corretto 是一种免费的,跨平台的,可立即投入生产的 Open Java Development Kit(OpenJDK)发行版,支持由 Graviton 驱动的实例。
注意:下载时需要选择 aarh64 的安装包。
此外,OpenJDK 也提供了对于 arm64 平台的支持。在 Graviton 处理器上,可以选择安装 openjdk-8、openjdk-11、openjdk-13 以及 openjdk-14 等不同的 JDK 版本。
Java JAR 可以包含特定于体系结构的共享库。一些 Java 库检查是否找到了这些共享库,是否使用 JNI 调用了本机库,而不是依赖于该函数的通用 Java 实现。尽管代码可以工作,但是如果没有 JNI,性能可能会受到影响。
检查 JAR 是否包含此类共享库的一种快速方法是简单地将其解压缩,并检查是否有任何结果文件是共享库,以及是否缺少 aarch64(arm64)共享库:
$ unzip foo.jar $ find . -name "*.so" | xargs file
Python 程序解释执行的特点需要我们使用的 Python 解释器可以很好适配于 Graviton 处理器。对于 Python 解释器优化的关键是确保解释器使用了 PGO 和 LTO 等优化编译的选项。获得 Python 解释器编译选项的方法很简单,
python3 -c “import sysconfig;
print(sysconfig.get_config_var(‘CONFIG_ARGS’))”
Amazon Linux 2 |
Ubuntu 20.03 |
Python 3.7.6 |
Python 3.8.2 |
‘–build=aarch64-koji-linux-gnu’ ‘–host=aarch64-koji-linux-gnu’ ‘–program-prefix=’ ‘–disable-dependency-tracking’ ‘–prefix=/usr’ ‘–exec-prefix=/usr’ ‘–bindir=/usr/bin’ ‘–sbindir=/usr/sbin’ ‘–sysconfdir=/etc’ ‘–datadir=/usr/share’ ‘–includedir=/usr/include’ ‘–libdir=/usr/lib64’ ‘–libexecdir=/usr/libexec’ ‘–localstatedir=/var’ ‘–sharedstatedir=/var/lib’ ‘–mandir=/usr/share/man’ ‘–infodir=/usr/share/info’ ‘–enable-ipv6’ ‘–enable-shared’ ‘–with-computed-gotos=yes’ ‘–with-dbmliborder=gdbm:ndbm:bdb’ ‘–with-system-expat’ ‘–with-system-ffi’ ‘–enable-loadable-sqlite-extensions’ ‘–with-dtrace’ ‘–with-lto’ ‘–with-ssl-default-suites=openssl’ ‘–without-ensurepip’ ‘–enable-optimizations’ ‘build_alias=aarch64-koji-linux-gnu’ ‘host_alias=aarch64-koji-linux-gnu’ ‘CFLAGS=-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong –param=ssp-buffer-size=4 -grecord-gcc-switches -D_GNU_SOURCE -fPIC -fwrapv ‘ ‘LDFLAGS=-Wl,-z,relro -g ‘ ‘CPPFLAGS= ‘ ‘PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig’ |
‘–enable-shared’ ‘–prefix=/usr’ ‘–enable-ipv6’ ‘–enable-loadable-sqlite-extensions’ ‘–with-dbmliborder=bdb:gdbm’ ‘–with-computed-gotos’ ‘–without-ensurepip’ ‘–with-system-expat’ ‘–with-system-libmpdec’ ‘–with-dtrace’ ‘–with-system-ffi’ ‘CC=aarch64-linux-gnu-gcc’ ‘CFLAGS=-g -fstack-protector-strong -Wformat -Werror=format-security ‘ ‘LDFLAGS=-Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 ‘ ‘CPPFLAGS=-Wdate-time -D_FORTIFY_SOURCE=2’ |
可以看得出来,在不同的 Linux 分发版本中,Python 解释器的版本以及优化方法存在一些差异。对比起来 Ubuntu 20.04 的 Python 解释器无论是 Pystone 还是 Pytest-benchmark 都要表现的更好一些。
对于一些场景,Python 应用需要使用 NumPy 以及 SciPy。通常我们通过 pip3 install numpy scipy 安装其二进制版本。一些场景下,使用 BLIS 对 SciPy 和 NumPy 工作负载进行基准测试可以确定额外的性能改进。
注:BLIS 是一个可移植的软件框架,用于实例化高性能 BLAS 高性能稠密线性代数库。
- 在 Ubuntu 上用 BLIS 安装 NumPy 和 SciPy
在 Ubuntu 上安装 python3-numpy 与 python3-scipy 程序包将安装带有 BLAS 和 LAPACK 库的 NumPy 和 SciPy。用 BLIS 和 OpenBLAS 在 Ubuntu 和 Debian 上安装 SciPy 和 NumPy:
sudo apt -y install python3-scipy python3-numpy libopenblas-dev libblis-dev sudo update-alternatives --set libblas.so.3-aarch64-linux-gnu \ /usr/lib/aarch64-linux-gnu/blis-openmp/libblas.so.3
在 blas 与 lapack 之间进行切换
sudo update-alternatives --config libblas.so.3-aarch64-linux-gnusudo update-alternatives -config liblapack.so.3-aarch64-linux-gnu
此外,2019 年 7 月 25 日,PyPy 宣布了对于 Aarch64 架构的支持。在基于 Graviton 处理器的 A1 实例上进行的性能测试。从结果来看,PyPy 对于 Python 程序性能的提升是非常显著的。
在一台基于 Graviton 2 的 m6g.2xlarge 的实例上运行 Pystone,PyPy 的性能是 CPython (Python 3.8.2)的 21 倍!! 性能的提升是非常的惊人了。
Go 是一种静态类型的编译型程序语言。Go 支持开箱即用的 arm64,可以在所有常见的发行版中使用。Go 最新的升级提高了性能,所以请确保使用最新版本的 Go 编译器和工具链。目前 Go 的最新版本是 1.14,而 Amazon Linux 2 与 Ubuntu 20.04 提供的安装包的版本均为 1.13。在 Ubuntu 环境下,安装 Go 最新版本的一个简单的途径还可以考虑通过 snap 进行安装。在 snap 中提供的 Go 的版本为 1.14.6。
Go 的下一个版本 1.16 预计将于 2021 年初发布。预计 Go 编译器将会通过以下列出的几项特性来提高 ARM 架构下程序的性能。
- ARMv8.1-A Atmoics 指令,可显着提高 Graviton 2 上的互斥公平性和速度,以及带有 v8.1 和更新指令集的现代 Arm 内核。
- 复制性能得到改善,尤其是当地址未对齐时。
相关文章