写点什么

TaiShan 服务器代码移植经验分享

王博

2019 年 9 月 29 日

TaiShan服务器代码移植经验分享

经历过 2 个项目的业务代码从 X86 服务器迁移到 aarch64 泰山服务器上,以前没有相关经验摸索了好久,踩了很多坑,现在迁移工作也差不多收尾了,Taishan 服务器上跑比 X86 的溜多了。写了一篇代码迁移经验总结,欢迎大家参考。


编程语言简介


按照翻译方式的不同,高级语言通常可以分为两类:一类是编译翻译,一类是解释翻译,分别对应着编译型语言和解释型语言。


1.编译型语言


典型的如 C、C++语言,都属于编译型语言,源代码到执行的过程概括如图 1-1 所示。C/C++编译好的程序是机器指令,由操作系统加载到存储器(一般为内存)后由 CPU 直接执行。



图 编译型语言执行过程


基于编译型语言开发的应用程序,例如 C/C++语言应用程序,其编译后得到可执行程序,可执行程序执行时依赖的指令是 CPU 架构相关的。因此,基于 x86 架构编译的 C/C++语言应用程序,无法直接在 TaiShan 服务器运行,需要进行移植编译,移植编译过程中遇到的问题可以参考第 2、3 章提供的方法解决。


2.解释型语言


典型的如 Java、Python 语言,都属于解释型语言,源代码到执行的过程概括如图 1-2 所示。Java/Python 编译好的程序是平台无关的字节码,由虚拟机解释执行,虚拟机完成平台差异的屏蔽。



图 解释型语言执行过程


基于解释型语言开发的应用程序,是 CPU 架构不相关的,例如 Java、Python,将这类应用程序移植到 TaiShan 服务器,无需修改和重新编译,按照与 x86 一致的方式部署和运行应用程序即可。Java 应用程序 jar 包内,可能包含基于 C/C++语言开发的 so 库文件,这类 so 库需要移植编译,移植编译 so 库遇到的问题可以参考第 2、3 章提供的方法解决,使用编译得到的 so 库重新打包 jar 包。


准备工作


C/C++程序移植需要安装编译器,推荐使用 gcc7.3 及以上版本(最低不低于 4.8.5),下载安装参考链接:


gcc7.3版本下载地址


安装步骤参考


移植相关问题处理-编译脚本移植类问题


1.1 -m64 编译选项


现象描述


告警信息:gcc:error: unrecognized command line option ‘-m64’


可能原因


-m64 是 x86 64 位应用编译选项,m64 选项设置 int 为 32bits 及 long、指针为 64 bits,为 AMD 的 x86 64 架构生成代码。在 ARM64 平台无法支持。


处理步骤


将 ARM64 平台对应的编译选项设置为-mabi=lp64。


1.2 char 数据类型的符号


现象描述


告警信息:warning:comparison is always false due to limitedrange of data type


可能原因


char 变量在不同 CPU 架构下默认符号不一致,在 x86 架构下为 signed char,在 ARM64 平台为 unsigned char,移植时需要指定 char 变量为 signed char。


处理步骤


在编译选项中加入“-fsigned-char”选项,指定 ARM64 平台下的 char 为有符号数。


源码修改类问题


2.1 代码中汇编指令需要重写


现象描述


ARM 的汇编语言与 x86 完全不同,需要重写,涉及使用嵌入汇编的代码,都需要针对 ARM 进行配套修改。


处理步骤


需要重新实现汇编代码段。


示例:


在 x86 架构下:



在 ARM64 平台下,使用 gcc 内置函数实现:



2.2 替换 x86 CRC32 汇编指令


现象描述


编译错误:unknownmnemonic crc32q' --crc32q (x3),x2’或 operand 1 should be an integer register – `crc32b (x1),x0’


或 unrecognizedcommand line option ‘-msse4.2’。


可能原因


x86 使用的是 crc32b 和 crc32q 汇编指令完成 CRC32C 校验值计算功能,而 ARM64 平台使用 crc32cb、crc32ch、crc32cw、crc32cx 4 个汇编指令完成 CRC32C 校验值计算功能。


处理步骤


请使用 crc32cb、crc32ch、crc32cw、crc32cx 取代 x86 的 CRC32 系列汇编指令,替换方法如表所示,并在编译时添加编译参数-mcpu=generic+crc。



示例:


在 x86 下的实现:



在 ARM64 平台下的实现:



2.3 替换 x86 bswap 汇编指令


现象描述


编译报错:Error:unknown mnemonic bswap' --bswap x3’。


可能原因


bswap 是 x86 的字节序反序指令,需替换为 ARM64 的 rev 指令。


处理步骤


x86 指令实现的 bswap 如下:



替换为 ARM64 指令后如下:



2.4 替换 x86 rep 汇编指令


现象描述


编译报错:unknownmnemonic reprep


可能原因


rep 为 x86 的重复执行指令,需替换为 ARM64 的 rept 指令。


处理步骤


替换方法如下:


替换前:



替换后:



2.5 快速移植内联 SSE/SSE2 应用


现象描述


部分应用采用了 gcc 封装的用 SSE/SSE2 实现的函数,但是 gcc 目前没有提供对应的 ARM64 平台版本,需要实现对应函数。


处理步骤


目前已有开源代码实现了部分 ARM64 平台的函数,代码下载地址:https://github.com/open-estuary/sse2neon.git


使用方法如下:


步骤 1 将下载项目中的 SSE2NEON.h 文件拷贝到待移植项目中。


步骤 2 在源文件中删除如下代码。



步骤 3 在源代码中包含头文件 SSE2NEON.h


----结束


2.6 弱内存序导致程序执行结果和预期不一致


现象描述


弱内存序导致程序执行结果和预期不一致。


可能原因


ARM64 平台是弱内存序,原理如下:


  1. 同一份数据,在 cache 里面存在多份,需要 CPU 之间进行同步。



  1. 代码编写顺序和执行顺序可能不一样。



CPU 内部是流水线执行,在执行到 x=1 时,如果 x 在内存,那么 CPU 就会等待 x 导入到 cache,在等待的过程中如果 y 已经在 cache 中了,那么 CPU 会执行 y=1,这样就导致后面的语句先执行。


对系统的影响


  • 影响无锁编程的代码。

  • 对于使用信号量机制写的互斥代码,因为信号量函数已经带了内存屏障的指令,所以无影响。


处理步骤


找到使用无锁编程的代码,检查是否用内存屏障指令保证了数据的一致性。


使用内存屏障指令保证对共享数据的访问和预期一致。


示例:



2.7 对结构体中的变量进行原子操作时程序异常 coredump


现象描述


程序调用原子操作函数对结构体中的变量进行原子操作,程序 coredump,堆栈如下:



可能原因


ARM64 平台对变量的原子操作、锁操作等用到了 ldaxr、stlxr 等指令,这些指令要求变量地址必须按变量长度对齐,否则执行指令会触发异常,导致程序 coredump。


一般是因为代码中对结构体进行强制字节对齐,导致变量地址不在对齐位置上,对这些变量进行原子操作、锁操作等会触发问题。


处理步骤


代码中搜索“#pragmapack”关键字(该宏改变了编译器默认的对齐方式),找到使用了字节对齐的结构体,如果结构体中变量会被作为原子操作、自旋锁、互斥锁、信号量、读写锁的输入参数,则需要修改代码保证这些变量按变量长度对齐。


2.8 核数目硬编码


TaiShan 服务器相对于 x86 服务器,CPU 核数会有变化,如果模块代码针对处理器 core 数目硬编码,则会造成无法充分利用系统能力的情况,例如 CPU 核的利用率差异大或者绑核出现跨 numa 的情况。


处理步骤


您可以通过搜索代码中的绑核接口(sched_setaffinity)来排查绑核的实现是否存在 CPU 核数硬编码的情况。


如果存在,则根据 TaiShan 服务器实际核数进行修改,消除硬编码,可通过接口(sysconf(_SC_NPROCESSORS_CONF))来获取实际核数再进行绑核。


2.9 双精度浮点型转整型时数据溢出,与 X86 平台表现不一致


现象描述


C/C++双精度浮点型数转整型数据时,如果超出了整型的取值范围,TaiShan 平台的表现与 x86 平台的表现不同。



可能原因


在两个平台下,是两套 CPU 架构,其中的算数逻辑单元的实现可能会有差异,操作系统、编译器的实现都会有所不同。x86(指令集)中的浮点到整型的转换指令,定义了一个 indefinite integer value——“不确定数值”(64bit:0x8000000000000000),大多数情况下 x86 平台确实都在遵循这个原则,但是在从 double 向无符号整型转换时,又出现了不同的结果。鲲鹏的处理则非常清晰和简单,在上溢出或下溢出时,保留整型能表示的最大值或最小值,开发者并不会面对不确定或无法预期的结果。


处理步骤


参考如下数据转换的表格,调整代码中的实现:


double 数据向 long 转换:



double 数据向 unsigned long 转换:



double 数据向 int 转换:



double 数据向 unsigned int 转换:



编译优化项


4.1 gcc 编译器优化浮点运算精度


现象描述


编译优化选项设置-O2 级别及以上时,相同的浮点数乘加运算在 x86 平台和 ARM64 平台的运算结果,在小数点后 16 位存在差异。


可能原因


ARM64 平台编译优化选项设置为-O2 级别及以上,进行浮点数的乘加运算(a+=b*c),运算结果的精度只能精确到小数点后 16 位。在配置-O2 选项时,gcc 使用融合指令 fmadd 完成乘加运算,而不是 fadd 和 fmul。


fmadd 将浮点数的乘法和加法看成不可分的一个操作,不对中间结果进行舍入,从而导致计算结果有所差别。


对系统的影响


编译优化选项设置-O2 级别及以上时,浮点乘加运算的性能有提升,但是运算的精度受到影响。


处理步骤


添加编译选项-ffp-contract=off 可以关闭该优化。


4.2 增加编译选项匹配 Kunpeng 处理器架构,提升性能


在编译时增加编译选项指定处理器架构为 armv8,使编译器按照 Kunpeng 处理器的架构和微架构生成可执行程序,提升性能。


处理步骤


编译选项中添加-march=armv8-a。


4.3 增加编译选项匹配 Kunpeng 处理器流水线,提升性能


如果使用了 gcc 9.1 以上的版本,在编译时增加编译选项指定使用 tsv110 流水线,使编译器按照 Kunpeng 处理器的流水线编排指令执行顺序,充分利用流水线的指令集并行,提升性能。


处理步骤


编译选项中添加 -mtune=tsv110。


本文转载自公众号华为开发者社区(ID:Huawei_Developer)。


原文链接:


https://mp.weixin.qq.com/s/_-6H99jfp8D-MIm3GIcpWQ


2019 年 9 月 29 日 16:28768

评论

发布
暂无评论
发现更多内容

架构师训练营第四周 架构分析

suke

极客大学架构师训练营

假想 一个进销存软件是如何发展的

不在调上

架构师训练营第 04 周—— 练习

李伟

极客大学架构师训练营

互联系统架构演化史之感

旭东(Frank)

架构 感悟 极客大学架构师训练营

互联网系统架构设计概览

dony.zhang

第四周作业

赵龙

通用编程风格

顿晓

Java 学习 编程风格

架构师训练营第4周学习总结

不谈

架构师训练营——第四周总结

jiangnanage

week04 总结

Geek_2e7dd7

大型互联网应用系统常用技术(持续更新)

2流程序员

程序员如何提升自己横向能力?

Boss.Guo

团队建设 能力提升 人才培养 个人总结

架构师训练营第4周作业

不谈

极客大学架构师训练营

架构师训练营作业 (第四周)

王海

极客大学架构师训练营

极客时间第 0 期架构师训练营第四周总结

2流程序员

架构师训练营第四周作业

张锐

「架构师训练营」第 4 周作业

旭东(Frank)

大型互联网应用系统的技术方案和手段

周冬辉

区块链技术打通信用壁垒赋能租赁业务

CECBC区块链专委会

去中心 区块链技术 防篡改 去信任

西博泰科携手中国电信共同抢占NB-IoT新赛道

Geek_116789

第四周总结

赵龙

写给大忙人看的操作系统(内附思维导图)

cxuan

后端 操作系统

「架构师训练营」第 4 周作业 - 一个典型的大型互联网应用系统使用了哪些技术方案和手段,主要解决什么问题

guoguo 👻

极客大学架构师训练营

架构师训练营-第四章-学习总结

而立

极客大学架构师训练营

第四周总结

不在调上

week04

Geek_2e7dd7

来了!Spring Boot从入门到入土的私藏教程,不收藏你就亏了

互联网架构师小马

spring 面试 Java 面试 springboot SpringBoot 2

浅谈比特币匿名的意义

CECBC区块链专委会

架构师训练营第4周——学习总结

极客大学架构师训练营 互联网架构模式 互联网架构的演进

愿景集团与聚盛国际达成战略合作共建外汇市场新篇章

Geek_116789

链技术如何提升金融行业安全与互信

CECBC区块链专委会

百度 区块链技术 超级链 探索与实践

TaiShan服务器代码移植经验分享-InfoQ