产品战略专家梁宁确认出席AICon北京站,分享AI时代下的商业逻辑与产品需求 了解详情
写点什么

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

王博

  • 2019-09-29
  • 本文字数:3712 字

    阅读完需:约 12 分钟

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-09-29 16:281644

评论

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

如何用建木CI生成Allure报表

Jianmu

CI/CD Allure 国产开源

Java开发之线程、多线程,线程池面试题

@零度

多线程 线程池 JAVA开发

性能监控之 Golang 应用接入 Prometheus 监控

zuozewei

Prometheus 性能测试 性能监控 Go 语言 12月日更

从科技出发,中科柏诚信云链为中小企业融资注入新动能

联营汇聚

Azkaban工作流调度

恒生LIGHT云社区

工作流 工作流调度 任务调度 Azkaban

小红书基于 StarRocks 构建广告数据中心的实践

StarRocks

数据库 数据分析 StarRocks

react源码解析15.scheduler&Lane

buchila11

React

Gartner技术成熟曲线详解

Kafka中文社区

AI新手语音入门:认识词错率WER与字错率CER

华为云开发者联盟

语音识别 词错率 WER 字错率 CER

“数”驰天下,华为云DRS 高效支撑T3出行平稳迁移

华为云开发者联盟

数据库 数据迁移 华为云DRS T3出行

优秀程序员的30种思维--设计思考篇

hackstoic

程序员 架构思维

PassJava 开源(五) :SpringCloud Alibaba 组件简介 #私藏项目实操分享#

悟空聊架构

SpringCloud 28天写作 passjava 悟空聊架构 12月日更

了解 Java 中的锁 Lock

Ayue、

ReentrantReadWriteLock ReentrantLock lock

TCP 两次握手为什么无法阻止历史连接?

华为云开发者联盟

TCP 报文 握手 RST 报文 两次握手

模块七 王者荣耀商城异地多活架构设计

小朱

架构实战营

Flutter 完美的验证码输入框(2 种方法)【Flutter专题25】

坚果

flutter 28天写作 12月日更

Linxu云计算这样学效率更快,Linux基础篇,expect-正则表达式-sed-cut的使用

学神来啦

Linux centos sed linux运维 expect

Log4j2 消停了,Logback 开始塌房了?

程序猿DD

Java 日志 漏洞

给弟弟的信第22封|写技术博客有哪些益处?

大菠萝

28天写作

如何有效使用预训练语言模型

云智慧AIOps社区

算法 智能运维 云智慧 语言模型 南加州大学

打造“智慧之眼”与“创新之轮”,华睿科技助推制造业智能升级

科技新消息

群聊泄密敲响警钟,WorkPlus织密信息安全“防护网”

WorkPlus

Java泛型可行与不可行

编程江湖

服务器数量从21台降至3台,TDengine在跨越速运集团的落地实践

TDengine

数据库 tdengine 时序数据库

DM 分库分表 DDL “乐观协调” 模式介绍丨TiDB 工具分享

PingCAP

定了一份《人民日报》(23/28)

赵新龙

28天写作

管理中的平衡

张老蔫

28天写作

react源码解析16.concurrent模式

buchila11

React

使用 USE 方法分析系统性能瓶颈

耳东@Erdong

监控 28天写作 use 12月日更

Flutter开发:运行项目时提示Error parsing LocalFile:‘/Users/xxx/android/app/src/main/AndroidManifest.xml’…解决方法

三掌柜

28t 28天写作 12月日更

腾讯云商用密码合规解决方案,亮相2021商用密码应用创新高端研讨会

腾讯安全云鼎实验室

商用密码 云上安全 数字生态 安全服务

TaiShan服务器代码移植经验分享_文化 & 方法_InfoQ精选文章