Ampere Porting Advisor 教程
工具概述
Ampere Porting Advisor 是 AWS Graviton Porting Advisor 的一个分支,而后者又是 Arm 高性能计算组 Porting Advisor 的分支。该工具最初是一个 Python 模块,用于分析 C 和 Fortran 代码的已知不兼容性。
Ampere Porting Advisor 是一个命令行工具,用于分析源代码中的已知代码模式和依赖库,生成与 Ampere 处理器不兼容性的报告。该工具提供语言运行时和依赖库在 Ampere 处理器上运行所需的最低版本和推荐版本建议。
重要提示:该工具可在非 Arm64 机器(如 Intel 和 AMD)上运行,不需要 Ampere 处理器。它仅处理源代码,不处理二进制文件,不会进行任何代码修改,不提供 API 级别建议,也不会将数据发送回 Ampere。
支持的语言和依赖
该工具扫描源代码树中的所有文件,支持以下语言/依赖:
Python 3+
- Python 版本
- PIP 版本
- requirements.txt 文件中的依赖版本
Java 8+
- Java 版本
- pom.xml 文件中的依赖版本
- JAR 扫描本地方法调用(需要安装 JAVA)
Go 1.11+
- Go 版本
- go.mod 文件中的依赖版本
C、C++、Fortran
- 无对应 aarch64 内联汇编的内联汇编
- 无对应 aarch64 汇编源文件的汇编源文件
- autoconf config.guess 脚本中缺少 aarch64 架构检测
- 链接到 aarch64 架构不可用的库
- 使用架构特定的内部函数
- 在 aarch64 上编译时触发的预处理器错误
- 使用旧的 Visual C++ 运行时(Windows 特定)
作为容器运行
使用此选项无需担心 Python 或 Java 版本问题,这是最快的入门方式。
先决条件
- Docker 或 containerd + nerdctl + buildkit
运行容器镜像
构建镜像后,我们可以将工具作为容器运行。使用 -v
将卷从主机挂载到容器。
直接输出到控制台:
|
|
生成报告:
|
|
Windows 示例:
|
|
作为 Python 脚本运行
先决条件
- Python 3.10 或更高版本(安装 PIP3 和 venv 模块)
- (可选)如果要扫描 JAR 文件的本地方法,需要 Open JDK 17(或更高版本)和 Maven 3.5(或更高版本)
- 运行测试用例需要 Unzip 和 jq
启用 Python 环境
Linux/Mac:
|
|
Powershell:
|
|
安装依赖
|
|
运行工具(控制台输出)
|
|
运行工具(HTML 报告)
|
|
作为二进制文件运行
生成二进制文件
先决条件
- Python 3.10 或更高版本(安装 PIP3 和 venv 模块)
- (可选)如果希望二进制文件能够扫描 JAR 文件的本地方法,需要 Open JDK 17(或更高版本)和 Maven 3.5(或更高版本)
build.sh 脚本将生成自包含的二进制文件(适用于 Linux/MacOS),输出到名为 dist 的文件夹。
默认生成名为 porting-advisor-linux-x86_64 的二进制文件,可以通过设置环境变量 FILE_NAME 来自定义生成的文件名。
|
|
对于 Windows,Build.ps1 将生成一个包含 EXE 和运行所需所有文件的文件夹。
|
|
运行二进制文件
先决条件 生成二进制文件后,如果希望扫描 JAR 文件的本地方法,仅需要 Java 11 运行时(或更高版本)。否则,文件是自包含的,不需要 Python 即可运行。
默认行为,控制台输出:
|
|
生成 HTML 报告:
|
|
生成仅包含依赖关系的报告(创建一个 Excel 文件,仅包含在代码库中找到的依赖关系,不提供建议):
|
|
理解 Ampere Porting Advisor 报告
以下是使用示例项目生成的输出报告示例:
|
|
在报告中,我们看到检测到的几种语言运行时(Python、pip、golang、Java)及其版本。所有这些信息都传达了这些语言的最低版本和推荐版本。其中一些行检测到先决条件版本已找到,仅为信息性提示。
我们还看到来自项目对象模型(POM)或 Java 项目中检测到的依赖项的消息。这些是作为 Maven 构建过程的一部分将被下载和使用的依赖项,我们看到三种类型的可操作消息:
依赖需要更新版本
|
|
此类消息表明我们应该使用更新版本的依赖项,这需要在继续之前重新构建和验证项目。
依赖需要手动构建
|
|
在这种情况下,依赖项确实支持该架构,但由于某种原因(可能是为了测试可用的硬件功能并为目标平台构建优化版本的项目),必须手动重新构建项目,而不是依赖预先存在的二进制工件。
依赖在此架构上不可用
|
|
在这种情况下,项目被指定为依赖项,但在 Ampere 平台上不可用。工程师可能需要检查使依赖项代码在目标平台上正确编译所涉及的内容。这个过程可能很简单,但也可能需要相当多的时间和精力。或者,您可以调整项目以使用支持 Ampere 架构的替代包提供类似功能,并相应地修改项目代码以使用此替代方案。
C/C++ 迁移示例
MEGAHIT 是一个 NGS 汇编工具,可作为 x86_64 的二进制文件使用。客户希望在 Arm64 上运行 MEGAHIT 作为架构转换的一部分。但在第一个文件上编译在 Arm64 上失败:
开发人员想知道需要更改什么才能使 MEGAHIT 在 Arm64 上正确编译。
在这种情况下,Ampere Porting Advisor (APA) 可以发挥关键作用。使用 APA 扫描 MEGAHIT 项目的源代码库后,我们得到了在 Arm64 上重新构建 MEGAHIT 之前需要检查的问题列表:
让我们调查列表中的每个错误类型,并在必要时为 Arm64 进行更正。
架构特定的构建选项
一旦 APA 检测到在 Arm64 上无效的构建选项,就会触发这些错误。
原始的 CMakeList.txt 默认使用 x86_64 编译标志而不检查 CPU 架构。要解决此问题,我们可以测试 CMAKE_SYSTEM_PROCESSOR 条件,以确保 APA 报告的标志仅应用于 x86_64 架构。
架构特定指令
一旦 APA 检测到代码中使用了非 Arm64 C 风格函数,就会触发架构特定指令错误。内部函数由编译器直接编译为平台特定的汇编代码,通常每个平台都有自己的一组内部函数和针对该平台优化的汇编代码指令。
在这种情况下,我们可以使用预处理器条件,仅在 #if defined(x86_64)
为真时编译 HasPopcnt() 和 HasBmi2() 函数的 _pdep_u32/64
和 __cpuid/ex
指令。对于 vec_vsx_ld
,它已经包装在预处理器条件中,并且仅在 Power PC 架构上编译,因此我们可以保持原样。
架构特定内联汇编
一旦 APA 检测到代码中使用了汇编代码,就会触发架构特定指令错误。我们需要检查汇编代码片段是否适用于 Arm64。
MEGAHIT 项目仅在 x86_64 架构上编译时在 phmap_bits.h 中使用 bswap 汇编代码。在其他架构上编译时,它会编译来自 glibc 的回退实现。因此 phmap_bits.h 中不需要更改。
在 cpu_dispatch.h 中,两个内联函数 HasPopcnt() 和 HasBmi2() 无条件地包含 x86_64 汇编指令 cpuid 来测试 x86_64 上的 CPU 功能。我们可以添加预编译器条件标志 #if defined(x86_64)
以确保此代码不会在 Arm64 上调用,并且我们将始终返回 false。
架构特定 SIMD 内部函数
一旦 APA 检测到代码中使用了 x86_64 SIMD 指令(如 AVX256 或 AVX512),就会触发架构特定指令错误。这些 SIMD 指令由预编译器条件标志包装,通常不会在 Arm64 上引起任何功能问题。
如果没有针对 Arm64 的算法的 SIMD 实现,与 x86_64 相比可能会存在性能差距。在这种情况下,xxh3.h 中有一个针对 Arm64 的 NEON SIMD 实现,该实现将由编译器根据 CPU 架构进行选择。不需要采取进一步的操作。
AArch64 上的预处理器错误
APA 将触发预处理器错误,以指示 Arm64 架构可能未包含在预编译阶段。在这种情况下,我们可以看到预编译条件仅适用于 x86_64,与 Arm64 架构无关。
重新构建和测试
完成所有这些调整后,我们可以重新构建项目:
项目编译成功。然后我们检查是否通过了项目的测试套件:
在我们手动检查并修复了 APA 报告的所有潜在陷阱后,MEGAHIT 现在能够在 Ampere 处理器上构建和运行。