今年 4 月,国家发改委进一步明确了新基建的范围,计算作为新型的算力基础设施,在新基建中被提出,随着人工智能的发展,每个服务器的算力变得更强。我们正在从电力时代步入算力时代,算法越来越成为新的生产力。
算力的投入以及算力如何带动社会经济的发展,正在成为各个国家区域抢夺的新战场。根据 IDC 预测,到 2023 年全球计算产业投资空间 1.14 万亿美元,而中国计算产业投资空间 1043 亿美元,接近全球的 10%,是全球计算产业发展的主要推动力和增长引擎。
鲲鹏计算产业“应运而生”,官方给它的定义是,这是一个基于鲲鹏处理器构建的全栈 IT 基础设施、行业应用及服务,包括 PC、服务器、存储、操作系统、虚拟化、数据库、云服务、行业应用以及咨询管理服务等。
在商业策略上,他们将基于华为鲲鹏主板的相应部件,构筑能生产高质量服务器产品的产线、采购、产品的检测这些全球流行的能力。
那么鲲鹏软件迁移大概是什么情况?C、C++代码和 JAVA、Python 代码又是怎么迁移的?这也是本次山东鲲鹏生态技术分享专场上讨论的重点问题。
以下内容经由 InfoQ 编辑整理自济南站 18 城鲲鹏开发者创享日华为鲲鹏智能计算产品线的刘坤)(待确认)、华为鲲鹏计算的软件工程师覃璐瑶的分享。
一、鲲鹏软件迁移概述
由于指令集上的差异,在 x86 平台上编译生成的应用程序,在鲲鹏处理器平台运行时,需要进行重新编译。
1. 鲲鹏软件迁移的五个步骤
迁移准备
主要做一些信息收集,以及编译环境的准备。收集包括操作系统、中间件、业务软件等信息后,还要做编译环境准备。
迁移分析
迁移分析主要指的是,对搜集到的软件栈信息打开进行详细分析,包括使用什么语言,是否有相应的 X86 依赖需要移植。
第一类是业务软件的展开分析,包括开源软件、自研软件和商用软件。
其中,开源软件可通过获取开源代码,进行重新编译,或获取对应的 ARM 包,获取源码重新编译。
自研软件根据语言可分为编译型语言和解释型语言开发的自营软件。
在商用软件领域,我们可以获取支持鲲鹏处理器的一个商用软件版本,当我们没法获取相应的商用软件版本时,可以通过其它软件或者开源软件来进行替换。
第二类是对软件的运行环境进行分析,运行环境可分为 JDK 以及编译器还有操作系统。JDK 替换可以替换成我们支持的华为 JDK,如 openJDK;编译器就是根据我们使用系统自带的一些编译器或者迁移时源码会规定一些 GCC 的版本,这时候我们更推荐的是使用 GCC7.3。操作系统可以通过兼容性助手,查询鲲鹏处理器支持的操作系统版本。
编译迁移
主要分为两类,一类是代码迁移,一类是软件包迁移。
代码迁移可以分为编译型语言和解释型语言,编译型语言修改点主要涉及代码修改、编译脚本修改、内联汇编修改以及不兼容指令,如 SSE Intrinsic 类加速指令。
解释型语言,主要分为直接翻译,如纯解释型语言开发的应用程序,如果软件含依赖库,需要重新编译。
软件包迁移主要是我们对 RPM 进行重构,包括扫描软件包所依赖的依赖项,对这些依赖库获取源码进行重新编译、打包。
性能调优
基于制定的性能指标数据进行针对性调优。完成迁移后,需要进行性能调优,这里总结出性能调优五步法,第一,是建立基准,根据当前硬件配置、组网、测试模型做综合评估,建立合理的调优目标。第二,是压力测试,通过压力测试工具对系统加压,同时监控系统数据,记录数据变化。第三,确定瓶颈,重点观测当前系统的资源,确定系统瓶颈。第四,根据瓶颈点针对性地实施优化措施,同时记录优化措施,记录优化措施,一旦出现负向效果,及时回退。第五,确认效果,重新启动压力测试,准备好相关的工具监视系统,确认优化效果。
测试与认证
通过测试和论证保证迁移完后,性能正常达标,包括压力测试、长稳测试、鲲鹏展翅论证等。
测试的话会经过功能测试、性能测试、长稳测试,这些测试的最终目的都是为了保证规模的商用。这个其实还有一个就是鲲鹏展翅论证。在认证上面,截止 6 月 5 日,累计有 809 家行业伙伴获得鲲鹏展翅论证。
2.典型案例
这里我们拿华为内部项目举例。这个项目涉及的迁移软件代码比较多,代码的规模大概在 450 万行左右,其中 C、C++代码占了一大半,有 272 万行,还有 165 万的 Java 代码,还涉及到 140 多个依赖库。在迁移 C、C++代码和依赖库的过程中,其实我们前面讲到的一些包括汇编指令迁移、选项修改、数据流行修改,其实这些都涉及到了,最后我们还做了代码的归一,构建脚本的归一,目的是兼容鲲鹏处理器平台和其它处理器平台,让代码能在多个平台运行。经过编译和移植后,最后还进行了系列性能调优,最后测试结果是:与 X86 持平。
3.华为鲲鹏开发套件
华为开发了一系列套件,帮助完成分析、迁移、调优过程。在迁移分析阶段,推出分析扫描工具,帮助我们扫描代码依赖的依赖库,做代码初步评估;在性能调优阶段,我们推出性能优化工具,它能做全景资源监控,针对可能出现的热点函数进行监控。
二、C、C++代码的迁移
1.需要移植的原因
架构差异
x86 和鲲鹏是属于不同的架构,鲲鹏它的架构是 aarch64,架构差异导致编译过程中,可能有些编译选项需要基于平台指定,这时候就需要移植。
指令集差异
x86 是复杂指令集,鲲鹏处理器是精简指令集。
向量寄存器差异和向量指令集差异
x86 和鲲鹏处理器使用向量寄存器不同,向量指令集也存在差异。
2.C、C++代码编译构建过程
C、C++代码工程包括文件
我们可以把文件分为两类,第一是编译构建脚本,第二类 C、C++源码。
首先,编译构建脚本中,可能会涉及移植项,主要涉及编译选项之类的移植,比如说这些编译选项通常是指定数据类型,包括我们生成代码的属性,还包括我们的目标、代码架构的相关编译选项。
其次,是 C/C++源码类文件的移植,主要涉及到编译宏移植,编辑自带 builtin 函数移植,内联汇编的移植,也包括 SSE intrinsic 函数移植。
C/C++代码编译构建过程
第一步,需要获取源码,如果是开源的代码,可通过 github 去获取相应的源码;
第二步,准备编译环境,这时我们需要安装对应的 GCC 版本;
第三步,使用源码中的 CMakelists.txt 或 configure 脚本生成 makefile 文件;
第四步,执行 makefile 编译可执行程序;
第五步,替换依赖库,重新译或替换依赖 X86 平台的 so 库;
第六步,将可执行程序安装部署到生产或测试系统。
3. C/C++代码中迁移的典型移植问题
第一类迁移问题:编译脚本、编译选项移植;
一个例子是,定义编译生成程序为 64 位,这时候在 X86 下面编译选项是-M64,在我们鲲鹏处理器平台下,我们需要通过-Mabi,等于 LP64 这个编译选项进行替换。
第二类迁移问题:编译宏移植
什么是编译宏?一段好的代码,比如很多开源工程,一个工程代码会写不同的分支,每个分支对应不同的架构平台,在我们编译器去编译和运行过程中,怎么知道执行哪个分支?这就是编译宏在起作用。它类似于一个标签,告诉你在当前平台下,你需要去执行这个分支下面的一个代码。
编译宏的移植,第一类是 gcc 编译器自定义的宏;第二类是用户自定义的宏。
第三类迁移问题:builtin 函数移植
builtin 函数,是我们编译器自定义的功能函数,这些功能函数通常功能较简单,但内部实践进行了优化,具有较好的性能,大家使用过程中如果有相应的需求可以进行使用。
第四类迁移问题:内联汇编函数移植
内联汇编的迁移主要有两种方法:第一种方法是一个汇编指令方式的替换来进行一个移植。第二种方式就是通过 Buding 函数的方式进行替换。
第五类迁移问题:SSE intrinsic 函数移植
什么是 SIMD?英文全称是 Single Instruction Multi Data,指通过单条指令处理多数据流的并行处理技术,能在批量数据操作时进行向量化运算加速,具有较高的执行效率,在多媒体处理、矩阵运算等场景都有广泛的应用。
关于 SIMD 里的 MMX 和 SSE 指令迁移,鲲鹏处理器采用精简指令集,使用 128 位寄存器实现 SIMD(Single Instruction Multi Data)计算。在实现本例 16 个浮点数的相加时,使用两条 vaddq_f32 指令分别完成,每条指令完成两组共 8 个浮点数计算,最后再从向量寄存器中分别取出 8 个浮点数累加。
SSE intrinsic 函数主要有两个移植方法,第一个方法是:基于 avx2neon.h、SSE2NEON.h 开源文件移植;第二个方法是:手动替换移植。
总结
平时迁移过程中,使用更多的是第一种。它是华为开源的,在 github 有相应的代码,它主要达成了 SSE Intrisic 函数的 Neon 实现,包括 AVX256、512 类的 Intrisic 函数的 Neon 实现。
第二个参与工程是原来已经存在的 SSE to Neon 这个工程比较老了,它主要做的事情是 128 位 SSE Intrisic 函数的替换,以及简单的 load、store、set 等指令的 NEON 实现。实际迁移过程中,可以两个结合起来使用。
迁移工具:Python 代码迁移
定义
Porting Advisor 是一款华为鲲鹏代码迁移工具,针对 C/C++代码进行扫描分析,检查用户 C/C++代码中需移植修 改的 MakeFile 编译文件、X86 汇编及 SSE intrinsic 函数,并指导用户如何移植。
使用步骤
主要分为三步,第一步是环境部署,安装 Porting Advisor 工具,安装后,准备好需要迁移的源码;第二步,通过 Porting Advisor 来进行工程的分析扫描,扫描编译构建脚本、X86 汇编,包括 Intrisic 函数的识别,第三步,生成分析报告,包括关键移植项准确信息、建议移植指导方法以及移植项全面评估等。
四、JAVA、Python 代码迁移
1.Java 代码迁移
Java 运行过程中可能涉及的迁移改动点
Java 源码移植过程是这样的,首先安装 JDK,将 Java 源码通过 Java 编译器编译;其次,对被调用的 SO 库,我们需要替换成 aarch6464 版本;再次,在程序运营时,可能涉及到一些参数的修改。
针对迁移改动点的处理方法
安装合适的 JDK 版本,需要通过源码编译、部署得到。
包含 SO 库调用的 jar 包迁移方法,首先通过 Dependency Advisor 工具分析扫描 jar 包,识别出所依赖的 SO 库,然后下载 SO 库源码,随后安装编译环境比如说 Maven、GCC,然后设置编译选项-fsigned-char,之后可以编译 aarch64 版本的 SO 库,然后替换掉 SO 库,重新打包的 jar 包,这样得到的 jar 包是可以在鲲鹏平台上运行的。
最后一个迁移改动点。需要我们设置 JVM 参数,保证程序稳定快速的运行。
2.Python 代码迁移
Python 代码迁移改动点有哪些?首先是我们的 Python 版本,建议客户将 Python 环境升级到 Python3.X;其次,在含 C 模块或者全 C 模块的迁移上,可以通过 Porting Advisor 工具分析我们的源码,然后识别到依赖的 SO 库以及 C 代码,随后我们下载对应的研源码模块,安装 GCC 编译环境,配置-fsigend-char 编译选项,执行模块中的 setup.py 这个文件自动完成模块编译。编译完成后,自动绘完成 aarch64 版本库的替换,再将编译完成得到的模块安装到 site-package 的目录下,供其他的 Python 源码调用。
五、如何通过 x86 架构的 rpm 包重构得到鲲鹏平台
将 x86 rpm 包重构成鲲鹏 rpm 包,在流程上,分为四个阶段,首先扫描识别对 x86 依赖的文件。第二阶段,是编译阶段。如果是 jar 依赖文件,需要从鲲鹏 Maven 仓上查找,或者鲲鹏上重新编译;如果是 so 或其它二进制依赖文件,需要在鲲鹏上重新编译。第三阶段,是打包,主要步骤是,解压 x86 rpm 并将 x86 依赖文件替换成阶段二鲲鹏 Maven 仓查找到的文件或鲲鹏上重新编译的文件。第四阶段是验证,主要通过扫描来验证,是否还有 x86 依赖文件。
【附】:
与此同时,鲲鹏应用创新大赛也在同步展开,大赛旨在激发行业创新、促进人才培养、加速产业融合,吸引全产业开发者共同打造鲲鹏全栈解决方案,实现技术与商业创新应用。
大赛共设计了 7 类赛题,将开展区域赛和全国总决赛两级赛事,设置 500 万奖金池。报名将在 8 月 7 号截止。
相关链接:
鲲鹏开发者大赛总专题页
https://www.huaweicloud.com/kunpeng/activity/kunpeng_competition20.html
报名链接
https://competition.huaweicloud.com/information/1000041275/introduction
评论