Ampere Porting Advisor 教程:轻松迁移代码至Ampere处理器

本教程详细介绍了如何使用Ampere Porting Advisor工具分析源代码与Ampere处理器的兼容性,包括容器、Python脚本和二进制三种运行方式,以及如何解读报告并解决C/C++代码迁移中的实际问题。

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。

请注意: 尽管我们尽力查找已知的不兼容性,但我们仍然建议在生产环境之前,在基于 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 特定)。

以下类型的问题会被检测到,但默认不报告:

  • 由编译器特定的预定义宏保护的编译器特定代码。

以下类型的交叉编译特定问题会被检测到,但默认不报告:

  • 依赖于主机而非目标的架构检测。
  • 在构建过程中使用构建产物。

有关如何修改报告问题的更多信息,请使用工具的内置帮助:./porting-advisor-linux-x86_64 --help

如果您遇到任何问题,请参阅项目 GitHub 仓库中的 CONTRIBUTING 文件。

以容器方式运行 Ampere Porting Advisor

使用此选项,您无需担心 Python 或 Java 版本,或工具所需的任何其他依赖。这是入门的最快方式。

前提条件

  • Docker 或 containerd + nerdctl + buildkit

运行容器镜像

构建镜像后,我们可以以容器方式运行该工具。我们使用 -v 将卷从主机挂载到容器。

我们可以直接运行到控制台:

1
docker run --rm -v my/repo/path:/repo porting-advisor /repo

或生成报告:

1
docker run --rm -v my/repo/path:/repo -v my/output:/output porting-advisor /repo --output /output/report.html

Windows 示例:

1
docker run --rm -v /c/Users/myuser/repo:/repo -v /c/Users/myuser/output:/output porting-advisor /repo --output /output/report.html

以 Python 脚本方式运行 Ampere Porting Advisor

前提条件

  • Python 3.10 或更高版本(安装了 PIP3 和 venv 模块)。
  • (可选)如果您想扫描 JAR 文件中的本地方法,需要 Open JDK 17(或更高版本)和 Maven 3.5(或更高版本)。
  • 运行测试用例需要 Unzip 和 jq。

启用 Python 环境

Linux/Mac:

1
2
python3 -m venv .venv
source .venv/bin/activate

Powershell:

1
2
python -m venv .venv
.\.venv\Scripts\Activate.ps1

安装需求

1
pip3 install -r requirements.txt

运行工具(控制台输出)

1
python3 src/porting-advisor.py ~/my/path/to/my/repo

运行工具(HTML 报告)

1
python3 src/porting-advisor.py ~/my/path/to/my/repo --output report.html

以二进制方式运行 Ampere Porting Advisor

生成二进制文件

前提条件

  • Python 3.10 或更高版本(安装了 PIP3 和 venv 模块)。
  • (可选)如果您希望二进制文件能够扫描 JAR 文件中的本地方法,需要 Open JDK 17(或更高版本)和 Maven 3.5(或更高版本)。

build.sh 脚本将生成一个自包含的二进制文件(适用于 Linux/MacOS)。它将输出到名为 dist 的文件夹。

默认情况下,它将生成一个名为 porting-advisor-linux-x86_64 的二进制文件。您可以通过设置环境变量 FILE_NAME 来自定义生成的文件名。

1
./build.sh

对于 Windows,Build.ps1 将生成一个包含 EXE 及其运行所需所有文件的文件夹。

1
.\Build.ps1

运行二进制文件

前提条件

一旦您生成了二进制文件,如果您想扫描 JAR 文件中的本地方法,它只需要 Java 11 运行时(或更高版本)。否则,该文件是自包含的,不需要 Python 即可运行。

默认行为,控制台输出:

1
$ ./porting-advisor-linux-x86_64 ~/my/path/to/my/repo

生成 HTML 报告:

1
$ ./porting-advisor-linux-x86_64 ~/my/path/to/my/repo --output report.html

生成仅包含依赖关系的报告(这会创建一个 Excel 文件,仅包含我们在代码库中找到的依赖关系,不提供建议):

1
$ ./porting-advisor-linux-x86_64 ~/my/path/to/my/repo --output dependencies.xlsx --output-format dependencies

理解 Ampere Porting Advisor 报告

以下是一个使用示例项目生成的输出报告示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
./dist/porting-advisor-linux-x86_64 ./sample-projects/ 
| Elapsed Time: 0:00:03 
 
Porting Advisor for Ampere Processor v1.0.0 
Report date: 2023-05-10 11:31:52 
 
13 files scanned. 
detected go code. min version 1.16 is required. version 1.18 or above is recommended. we detected that you have version 1.19. see https://github.com/AmpereComputing/ampere-porting-advisor/blob/main/doc/golang.md for more details. 
detected python code. if you need pip, version 19.3 or above is recommended. we detected that you have version 22.3.1 
detected python code. min version 3.7.5 is required. we detected that you have version 3.10.9. see https://github.com/AmpereComputing/ampere-porting-advisor/blob/main/doc/python.md for more details. 
./sample-projects/java-samples/pom.xml: dependency library: leveldbjni-all is not supported on Ampere processor. 
./sample-projects/java-samples/pom.xml: using dependency library snappy-java version 1.1.3. upgrade to at least version 1.1.4 
./sample-projects/java-samples/pom.xml: using dependency library zstd-jni version 1.1.0. upgrade to at least version 1.2.0 
./sample-projects/python-samples/incompatible/requirements.txt:3: using dependency library OpenBLAS version 0.3.16. upgrade to at least version 0.3.17 
detected go code. min version 1.16 is required. version 1.18 or above is recommended. we detected that you have version 1.19. see https://github.com/AmpereComputing/ampere-porting-advisor/blob/main/doc/golang.md for more details. 
./sample-projects/java-samples/pom.xml: using dependency library hadoop-lzo. this library requires a manual build  more info at: https://github.com/AmpereComputing/ampere-porting-advisor/blob/main/doc/java.md#building-jar-libraries-manually 
./sample-projects/python-samples/incompatible/requirements.txt:5: dependency library NumPy is present. min version 1.19.0 is required. 
detected java code. min version 8 is required. version 17 or above is recommended. see https://github.com/AmpereComputing/ampere-porting-advisor/blob/main/doc/java.md for more details. 
 
Use --output FILENAME.html to generate an HTML report.

在报告中,我们看到检测到了几种语言运行时(Python、pip、golang、Java)及其版本。所有这些消息都传达了这些语言的最低版本和推荐版本。其中一些行检测到已找到先决条件版本,并且纯粹是信息性的。

我们还看到来自 Java 项目的项目对象模型(POM)中检测到的依赖项的一些消息。这些是将在 Maven 构建过程中下载和使用的依赖项,我们看到三种类型的可操作消息:

依赖项需要更新版本

1
./sample-projects/java-samples/pom.xml: using dependency library snappy-java version 1.1.3. upgrade to at least version 1.1.4

此类消息表明我们应该使用依赖项的更新版本,这需要在继续之前重新构建和验证项目。

依赖项需要手动构建

1
./sample-projects/java-samples/pom.xml: using dependency library hadoop-lzo. this library requires a manual build more info at: https://github.com/AmpereComputing/ampere-porting-advisor/blob/main/doc/java.md#building-jar-libraries-manually

在这种情况下,依赖项确实支持该架构,但由于某种原因(可能是为了测试可用的硬件功能并为目标平台构建项目的优化版本),必须手动重新构建项目,而不是依赖预先存在的二进制工件。

依赖项在此架构上不可用

1
./sample-projects/java-samples/pom.xml: dependency library: leveldbjni-all is not supported on Ampere processor.

在这种情况下,项目被指定为依赖项,但在 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 处理器上构建和运行。

Dave Neary 领导 Ampere Computing 的开发者关系团队,帮助提高 Ampere Arm64 处理器在云计算中的认知度和采用率。他之前曾在 Red Hat 开源项目办公室工作十年,从事开源基础设施项目和开发者工具的工作。他还是一位长期的自由软件和开源倡导者,并多年来为多个开源项目做出贡献。他与家人住在波士顿地区。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计