据 IDC 预测,到 2023 年全球计算产业生态体系将发展为近两万亿美元的市场,中国则将超过 1.1 万亿人民币,数字经济产值将占到全球 GDP 的 62%。全球进入数字经济时代,数字化浪潮已经是全球大势所趋。
在宏观政策和科技进步的双重驱动下,数字经济迅猛发展,当前已经发展到以人工智能、云计算、大数据为核心支撑力的时代,计算产业的窗口大开,多样的场景和爆发式增长的数据也激发了大量的计算需求。
在这样的背景下,计算产业的发展势在必行。秉持着“硬件开放、软件开源、使能伙伴”的初心,华为鲲鹏以技术创新为动力、以技术布道为使命,致力于推动计算产业的发展。在 18 城鲲鹏创新中心开发者创享日——鲲鹏开发者嘉年华西安站,来自华为鲲鹏的技术专家为大家分享了如何从 x86 迁移到 ARM,并结合迁移案例让大家更好地理解。
为什么要做软件迁移
一般来说,计算框架是从下到上,从硬件到软件,传递的是软件的信息模拟和处理。最底层的基础物理原材料、晶体管、寄存器、微架构等都属于硬件层面。而软件层面则特指由高级语言、汇编语言开发的应用程序。要执行软件层的应用程序,就需要将高级的编程语言编译成机器语言,这个过程是通过一个个指令完成的。
不同的处理器架构指令集不一样,指令的长度也不一样,比如 x86 上 mov 指令一般是 16-24 位,在鲲鹏上则都是 32 位。
因为以上这些差异,在 x86 上编译出来的程序无法直接在鲲鹏上运行,所以才有了从 x86 到鲲鹏的迁移必要。
从 x86 到鲲鹏,5 个步骤完成软件迁移
从 x86 到鲲鹏整个软件迁移过程主要分为以下 5 个步骤:
迁移准备
收集硬软件信息。包括芯片类型、存储等硬件设备信息和中间件,开源软件,商业软件,包括自己的自研软件等软件信息。
准备迁移环境。做环境申请,可以在华为的 Openlab 网上申请,做一些软件的初步认证。
迁移分析
这一步要做的是分析前一步收集到的信息,判断是否真正需要迁移,评估迁移的工作量。针对主要的业务软件:
开源软件总的策略就是把原网的代码下载下来,做编译。
自研软件:有的 C/C++/Go 类编译语言需要做重新编译,Java/Python 等解释型语言需替换 ARM 版本 JDK 或 PVM 虚拟机。
商用软件:可以通过联系厂商获取它对应 ARM 架构下的软件版本,如果没有的话就需要寻找有类似功能的软件做替换。
编译迁移
代码迁移:对于编译型语言,一些宏定义如果代码是 x86 上面运行的就不做修改。解释型语言在鲲鹏服务器上安装 JDK 就可以,但是要注意 Java 依赖库可能需要把 C 库做迁移。
软件包迁移:首先需要扫描该软件包是否存在依赖库或者依赖的可执行程序,这些库和可执行程序如果是用 C 语言写的是需要重新编译的,编译之后重新把软件包打包即可。
性能调优
性能调优主要分为建立基准 、压力测试 、确定瓶颈、 实施优化、 确认效果五个步骤。首先需要确认调优的目标是什么、业务指标是什么,有了目标以后,后边所有动作围绕这个目标而来:测试,找瓶颈等。这是一个循环的过程,一步步优化和确认效果,如果有负面效果就回退。
测试与认证
和日常软件开发一样,需要对其进行功能、性能、长稳等层层测试,以确保能达到商用标准。此外也可以拿软件和系统到鲲鹏上做鲲鹏展翅认证,可以扩展应用的软件使用空间并能够加入鲲鹏生态。
接下来我们将聚焦到具体如何做迁移。
C/C++ 代码迁移
因为 x86 和鲲鹏处理器在架构、指令集、向量寄存器方面的差异,C、C++、GO 这些典型的编译型语言从 x86 平台移植到鲲鹏平台时一般都需要重新编译才能运行。
在 C/C++ 编译构建过程中,代码工程主要包括编译构建脚本、C/C++ 源码这两类文件,会对这两类文件包括脚本选项、宏、builtin 函数等方面的修改。
C/C++代码编译构建过程主要分为以下几步:
获取源码,可以通过 GitHub 等开源社区来获取;
选择所需的编译环境,就是安装编译器 gcc 等;
根据源码的编译脚本生成 Makefile 文件;
再用 Makefile 编译生成可持续文件;
如果这部分代码之中有依赖 x86 平台的 SO 库,那么这部分的依赖库需要重新编译替换;
在编译完成之后进行安装部署,之后进入到实际的系统之中进行测试。
C/C++ 代码迁移典型移植类问题
编译脚本和编译选项移植:比如说 64 位编译在 x86 上是 -m64,对应到鲲鹏上是用 -mabi=lp64 的编译选项,此类编译选项需要在脚本中修改;此外, x86 平台上默认的 char 类型是一种有符号的类型,对应到鲲鹏上则是无符号类型,在移植过程中需要显示定义并将 char 类型定义为有符号。
编译宏的移植:编译器自己内部带的宏 x86 上可以直接定义,可以把宏的名称改成-aarch64。对于平台属性意义编译宏的移植,x86 系列 -amd64 下面 SIMD 指定的宏要换成对应的。
builtin 函数移植:Builtin 函数是编译器自带的函数,需要移植的普通 builtin 函数实际并不多,大部分需移植的 builtin 函数集中在 SSE intrinsic 函数内。
内联汇编函数移植:移植时有两种方式,第一种是汇编方式指令替换,x86 上对应的是 bswap 指令,鲲鹏对应的是 rev 指令。第二种是 builtin 函数方式替换,以 x86 的指令 popcnt 为例,比如 popcount 是对二进制数里面的 1 进行计数,对应到鲲鹏平台上所替换的是 popcountll。
SSE intrinsic 函数移植:Intel 的 SIMD 扩展指令统称 SSE,主要分为三类,MMX 是 64 位寄存器,SSE 到 SSE4 是 28 位的,三是 AVX256 和 AVX512。鲲鹏基于 SIMD 的技术发展比较成熟,现在有些基于开源量的 NEON 库主要是在图象处理和视频处理层面。x86 和鲲鹏对这些指令的含义和运算方式有区别。SSE intrinsic 函数移植的主要方法主要有两种:1. 基于 avx2neon.h、SSE2NEON.h 开源文件移植,大家可以在鲲鹏的开源工程网站上去下载,已经有改好的相关文件。2. 手动替换移植,移植的时候看 x86 原来的指令什么意思,放到 NEON 里面怎么改。
Java/Python 代码迁移
虽然 Java/Python 等解释型语言的代码迁移相对来说比 C/C++ 简单一些,迁移过程中也有一些问题需要注意。
首先是 Java 的迁移。Java 的 JDK 里面包含很多东西,最主要的就是 JRE 和 JVM。如果转换在鲲鹏下面,首先需要安装 JDK,JDK 的功能基本上没有变化,但是 JDK 必须要装支持 aarch 64 版的。在这个过程中,如果 jar 包调用了 SO 库,x86 的 SO 库也需要迁移,重新编译成 aarch64 版的。
再来看看 Python。Python 的迁移和 Java 有很多类似的地方,也是从环境到源码最后到执行程序。在这个过程中要改动的点主要有两个:
版本改动:需要对定制版本编译,还需要进行 Python 2.X 到 Python3.X 的切换
对有依赖的 SO 库,需要重新编译为 aarch64 版本的 SO 库并替换。
Maven 迁移
Java 开发代码一般有三个开发工具,LVY,Maven 和 Gradle,能把依赖路径和方法配置的非常好。Maven 是 Apache 下的一个纯 Java 开发的开源项目,基于项目对象模型(POM) 可以对 Java 项目进行项目构建和依赖管理。
Maven 仓库分为本地仓库、远程仓库和中央仓库。Maven 仓库软件构建流程就是将 x86 依赖文件替换为鲲鹏依赖文件,再重新构建,直到不包含 x86 依赖。Maven 仓的部分 jar 包依赖 x86 SO,无法在鲲鹏上直接使用,需要在鲲鹏上直接编译。部分 Jar 包已经编译好放在鲲鹏 Maven 仓内,可以直接从鲲鹏远程 Maven 仓库下载 ARM 依赖文件,无需重新编译。
软件包迁移
常见的 Linux 发行版主要有 类 RedHat 和 类 Debian 两个系列。类 RedHat 系统软件包的格式是 rpm,提供 rpm 命令来安装、卸载和升级 rpm 软件包。
常见开发语言编译成的应用程序一般包含二进制文件、库文件(jar)、配置文件、帮助文件等。rpm 可以将应用程序打包,所以 rpm 包通常包含应用程序包含的这些文件。rpm 包中与处理器架构相关的有二进制文件和库文件,所以将 x86 的 rpm 包重构到 ARM 的 rpm 包,需将 rpm 中包含有 x86 的 SO、二进制文件替换成 ARM 架构的 SO 和二进制文件。这个重构过程主要有以下步骤:
扫描:用 Dependency Advisor 工具扫描 x86 rpm,识别 x86 依赖文件。
编译:如果识别到该 rpm 包里的 jar 依赖文件没有在鲲鹏 Maven 仓库中找到,必须要重新编译,SO 或其他二进制文件也需要重新编译。
打包:首先生成一个 spec 文件,然后解压 x86 rpm 包,将编译好的组件替换掉 x86 rpm 包中的对应文件,最后重新打包。
验证:重新扫描 rpm 包,确认是否还有 x86 依赖文件,如果扫描结果没有,则进行安装验证。
应用迁移案例分享
Maven 构建迁移案例:NiFi
NiFi 是基于 Java 开发的开源大数据工作流平台,将各个数据处理环节模块化,简化大数据开发。这个案例中在执行 Maven 数据终出现了左侧的报错,找不到 64 的 jar 包。
面对这种问题,我们首先会排查网络的原因,这是因为在执行 Maven 的过程中会解析配置文件分析里面的依赖,根据这个标签判断是否加载。如果里面有这个 jar 包的话就可以直接使用,如果在本地没有 jar 包就要去下载。如果下载不下来,获取不到这个 jar 包就会终止,报一个找不到 jar 包的错误。
这个案例里网络是正常的。往后分析,想要查找一下这个 jar 包是否存在,就可以通过配置来去查找 jar 包路径,可以通过这些标签找到一些地址,然后找到路径。classifire 是一个 64 的版本,我们发现只有 x86 的 jar 包,所以才会报这个错误。
面对这种情况我们首先想到获取源码,编译这个 jar 包。可以看到 SCOPE 下面是 TEST,它是用来测试用的,所以影响范围还是可控的,我们就把它屏蔽掉,后续采用手动测试的方式来去测试它的影响功能,这样就可以完成迁移了。
总结一下,Maven 的迁移思路是:
如果在 Maven 打包,编译打包失败的情况下,通常首先会检查下载的 jar 包是不是失败了。这里首先也是要看一下网络的问题,是不是能正常访问,如果可以正常访问,我们就检查一下 POM 的配置,根据配置去仓库里面查找是否能找到这个 jar 包。同时也要检查 POM 的其他配置是否正确。
如果前面没有问题,我们要看一下是不是 jar 包调用有错误。可以通过鲲鹏开发套件进行扫描,检查一下 jar 包是不是调用了 x86 架构的 SO 文件,如果有的话就要获取到源码重新去编译,直到没有 x86 架构的 SO 库。重新编译之后手动做一些替换,再重新的进行打包编译,就可以完成 Maven 的迁移。
Python 迁移案例
Pandas 迁移
Pandas 是 Python 的数据分析包,基于 NUMPY 的工具,用于解决数据分析任务。
上图这个报错是找不到模块。遇到这种报错,首先检查是不是有安装 NUMPY,发现安装了 1.11.3 这个版本的 NUMPY,然后找有没有 BUILD-UTIS 模块。实际上在这个里面定义了最低版本是 1.13.3,和实际安装的不一致。升级 NUMPY 之后这个问题就得到了解决。
OpenCV-Python 迁移
基于 Python 预编译的 OpenCV 包主要用于图象处理和计算机视觉。在这个迁移过程中遇到了一个 CLONE 的报错,发现没有外网的环境导致 CLONE 失败。可以选择手动下载子模块到指定文件夹中,我们把 GIT CLONE 模块屏蔽掉,是会判断是否有 GIT 文件。如果有的话,就通过 GIT CLOEN 拉取子模块。我们的方法是注释掉这个逻辑,手动写入 OpenCV 版本信息。修改完之后重新安装,就可以解决这个问题。
总结 Python 迁移的一般的思路:
首先也是通过官方的手册,然后结合 setup.py 分析依赖信息。
关注依赖的仓库。检查网络是否联通,如果联通一种是可以通过 PIP 进行安装,另一种如果网络有问题,我们可以通过源码编译安装,或者编译一些可以访问的源。
注意 SO 的加载,关注无法解析。如果是 x86 的,还是要进行替换,通过源码编译安装,或者下载一些已经提供的编译好的包进行替换,最终重新编译。
写在最后
随着新基建浪潮的来袭,ARM 平台展现出了自身强大的潜力,从 x86 到 ARM 的转换也将成为国内 IT 基础设施架构的趋势。鲲鹏基于处理器,构建了从底层服务器到存储到上层应用软件的全栈 IT 领域。结合更多元的算力,鲲鹏将打造算力产业的坚实底座。
为激发行业创新,促进人才培养,全国各地的鲲鹏生态创新中心正在联合举办鲲鹏应用创新大赛,目前共有北京、重庆、福建、广州、广西、河南、湖南、江苏、陕西、深圳、四川、天津和浙江 13 个区域赛区。大赛的陕西赛区主要面向企业参赛者,参赛作品须有 demo 演示,并且要在作品提交截止时间之前完成鲲鹏认证流程的发起和完成兼容性测试并在线输出测试报告,并把测试报告(或兼容性认证证书)与参赛作品一起提交。
陕西赛区奖项激励总额 42 万,奖项设置包括 “政府”、 “大数据”、“ARM 原生应用”和“开放命题” 4 个赛题,奖项设置一致:
一等奖:4 个团队(每赛题 1 个团队),每团队奖励:50000 元现金。
二等奖:4 个团队(每赛题 1 个团队),每团队奖励:30000 元现金。
三等奖:4 个团队(每赛题 1 个团队),每团队奖励:20000 元现金。
此外,“金融”赛题只设置一等奖(1 个团队),团队奖励:20000 元。
点击链接获取鲲鹏应用创新大赛 2020 陕西赛区的更多详情及报名信息
评论