简化代码迁移:Ampere Porting Advisor助力x86到Arm64的高效移植

本文详细介绍Ampere Porting Advisor工具如何帮助开发者将x86代码迁移到Arm64架构,包括语言支持、依赖检查、架构特定代码检测等功能,并提供容器、Python脚本和二进制三种运行方式的具体操作指南。

简化代码迁移:Ampere Porting Advisor助力x86到Arm64的高效移植

对高效软件移植解决方案的需求正在增长。随着从传统x86向Arm64(尤其是Ampere处理器)的转型势头增强,开发者正在寻找加速现有代码库迁移的方法。通过Github页面提供的Ampere Porting Advisor旨在协助这一过程。

该工具提供了简化的迁移流程,允许开发者节省时间和精力。它自动化了移植代码涉及的许多手动步骤,减少了错误风险,并确保迁移过程中的一致性。通过分析源代码,该顾问提供所需更改的详细见解,突出潜在陷阱,并推荐最佳修改。这种指导使开发者能够更高效地应对架构转换的复杂性,并加速整体迁移过程。

Arm64架构在各种软件包中获得了显著关注,通过利用软件移植顾问,开发者可以进入这个不断扩展的生态系统,并利用基于Arm64平台的优势。该顾问是一个静态命令行工具,分析make环境和源代码中的已知代码模式和依赖库,并生成包含不兼容性和建议的报告。该顾问包括以下功能:

  • 语言支持:Python 3+、Java 8+、Go 1.11+、C、C++、Fortran
  • 架构特定代码检测:缺少对应的AArch64汇编、架构特定指令以及make文件中的架构特定标志
  • 依赖检查:版本控制、JAR扫描和依赖文件
  • 易于运行:通过Python脚本、二进制文件或容器
  • 多种输出格式:终端用于快速检查,HTML用于轻松分发,CSV用于后处理

开始使用Ampere® Porting Advisor

Ampere Porting Advisor是Porting Advisor for Graviton的一个分支,后者是AWS的一个开源项目,而它又是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

构建容器镜像

注意:如果使用containerd,可以将docker替换为nerdctl

1
docker build -t porting-advisor .

注意:在Windows上,您可能需要运行这些命令以避免bash脚本的行尾更改为CRLF:

1
2
git config core.autocrlf false
git reset --hard

运行容器镜像

构建镜像后,我们可以将工具作为容器运行。我们使用-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模块)
  • (可选)Open JDK 17(或以上)和Maven 3.5(或以上),如果您想扫描JAR文件以查找本地方法
  • 运行测试用例需要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模块)
  • (可选)Open JDK 17(或以上)和Maven 3.5(或以上),如果您希望二进制文件能够扫描JAR文件以查找本地方法

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)及其版本。所有这些消息都传达了这些语言的最低版本和推荐版本。其中一些行检测到先决条件版本已被找到,并且纯粹是信息性的。

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

依赖需要更新版本

./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 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/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处理器上构建和运行。

结论

将代码从x86迁移到AArch64架构不必是一个令人畏惧的过程。软件移植顾问通过自动化迁移中涉及的各种任务,显著降低了开发成本。通过最小化手动干预的需要,开发者可以将他们的时间和资源分配到项目的其他关键方面。此外,顾问的全面分析和建议降低了迁移后问题的风险,消除了部署后广泛故障排除的需要。

新的Ampere Porting Advisor的引入在简化x86代码到AArch64架构的迁移方面提供了重大进展。通过简化迁移过程、降低开发成本并实现对更广泛生态系统的访问,该顾问使开发者能够更快速、更有效地拥抱AArch64架构的优势。

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