专栏名称: 狗厂
目录
相关文章推荐
半导体行业联盟  ·  阿里 “All in AI” :野心下一个抖音! ·  4 天前  
半导体行业联盟  ·  上海,又一芯片重大并购! ·  4 天前  
51好读  ›  专栏  ›  狗厂

Go语言汇编优化-蒙卓

狗厂  · 掘金  ·  · 2018-06-12 06:08

正文

目录

  • 基础知识

  • 汇编语法

  • Demo

  • 基本程序

  • debug

讲汇编优化,不得不说一句高德纳的名言——过早的优化就是万恶之源。如果你们没有被逼到绝路,或者要榨干CPU的性能,千万不要尝试以下演讲的内容。



我给 Go 的 1.11 提交了这几个项目,第一个是 Hashmap 优化,就是你们常用的 map 操作里面最费时的哈希值计算优化。VDSO,虚拟动态对接的 syscall,主要是优化系统时间调用。Md5、Chacha20就不说了。还有一个 Duffcopy,这是给编译器展开优化用的,它在 arm64平台优化得不是很好,所以我也做了优化。除了 Chacha20还没有完成外,其他的都已经在 Go master 上可以用到了。可能有些人会觉得为什么都是 arm64 平台的优化?其实就是 Go 官方团队维护了 X86-64,已经优化得很好,我就不要搀和了,就挑了一个比较新的平台,arm64。



国内 arm 公司的大牛肖玮带领他的团队也在做 Go 相关的优化,比如 sha256,提升的效率有 16倍。国外的也有,Cloudflare,做CDN的公司,他们有一个密码学大牛弗拉德做了一些优化,也在 Go 的1.11里面合进去了,优化的效率是多少呢?



这是他们的CTO转发的推,CTO问他上周优化了一些什么东西呢?他说他优化了一些Go的库,RSA 性能有20倍,AES-GCM有15倍,P256有18倍。看了这些大牛优化以后有这么好的性能提升,是不是很心动啊?这次演讲就是教大家入门汇编优化,怎么做十几倍的加速。

1. 基础知识

所以怎么跑得那么快?就要知道干什么。 总结下来有三点,减少读写,并行操作,硬件加速。

1.1 减少读写



上图是谷歌的 Jeff Dean 分享的《程序员应该知道的延迟》,这个延迟是什么延迟呢?比如数据从CPU L1里面挖出来的速度,在2012年的时候是0.5ns,CPU L2里面是7ns;储存,也就是我们常说的内存里面拉出来是100ns。大家有没有发现每多一层就是10倍的性能下降,所以你要尽量少用内存的操作,多用寄存器。还有,CPU访问内存的时候有一个小窍门,把这个对齐再访问,CPU会执行得更快一些。这些都是基本知识,大家可以百度、Google 一下,不展开。

1.2 并行操作

业内叫做并行操作SIMD,就是单一指令多个数据进行操作。比如一般的加法操作,一次性只能加一个数,但是你要是用上一些向量指令集,就可以一次性操作8个、16个、32个,意味着相同的时间内能操作数据就更多,也就更快,这是很自然的事情。

1.3 硬件加速

算法再好,最多10倍,然而硬件指令是16倍朝上,比如肖伟和弗拉德他们做的优化基本上是借助硬件指令,非常简单粗暴。像马云说的,武功再高,也怕菜刀。

1.4 程序内存分布

  • 构造与其他程序一致

  • TEXT=可执行代码

  • DATA=堆+全局变量

  • frame=函数参数+临时数据

  • stack=Go调度器/信号处理



Go 的内存分布要大致了解,因为汇编是直接对内存进行的操作,所以你需要对内存的位置,哪个位置存什么东西有所了解。其实 Go 怎么使用内存和其他程序是差不多的。最下面的TEXT是存放可知性代码,DATA 是堆和全局变量。唯一不一样的地方是 Go 没有完全使用系统栈,而是拆成 frame 栈帧,栈帧保证程序存的参数和临时数据。那原来系统的栈拿去干嘛了?Go 的调度器和信号处理都是在系统栈上,不在栈帧上。

2. 汇编语法

汇编语法特点

  • 准抽象汇编语言

  • AT&T风格(左到右)

  • 指令 参数×N 目标(N=0...3)

虽然看起来汇编语法是好复杂,其实是非常简单粗暴的,没有 C++、Java 等一堆术语。对内存直接操作,就是这么简单。实际上Go的汇编语法和Plan9这个操作系统渊源很深,Plan9 操作系统大家可能没有听说过,其实和Go是同一波人做的。

Go 的汇编语法其实很简单,它是准抽象的汇编语言,为什么叫准抽象?Go 本来的汇编语言是希望大一统,有什么X86-64,Arm64,大家只要写一种汇编语言就可以。实现起来后发现大部分做不到,最后只能保留差异,统一了风格,再输出机器码,所以叫准抽象的汇编语言。再有就是它的AT&T的风格,从左到右的写法,就是指令级在最左边,中间设几个参数,然后放目标寄存器或者目标,其他的嘛,各个平台就完全不一样了。

2.1 汇编语法例子

  这个函数很复杂,c=a+b,然后返回。第一步怎么做呢?我把这个函数名搬下来,这个英文SB实际上是告诉汇编器是说这个东西是static base,基于静态地址寻址。 刚才讲的TEXT区,这是告诉汇编器说你从这里开始找,不要从别的地方找,汇编器说,行,我直接把地址编进去,就这么简单。  还记得例子里刚才我们看到三个参数,abc,都是 int64,一个 int64多少字节?8个字节哈,所以这个栈帧长24个字节。注意这里有对齐的问题,其他平台不一定是24,不过为了简单理解,我把24放到这里来。

2.2 例子代码讲解

第一步是move指令

就是把一个数据从一个地方挪到另外一个地方,简单就是把ab两个数据放寄存器R1、R2里面,这里面多一个东西,FP,就是 Frame Pointer,刚才讲到栈帧保存参数和临时存储的数据的地方。 这就是就是FP开始寻址,FP指栈帧的最低位。你把a拿出来,从0开始寻,挪到R1里面,把B拿出来,是不是8个字节,然后就把它存到R2里面。

第三步,R3=a+b。

最后把R3里面的数据放回C的参数返回,Return。

 大家到现在就已经学会汇编语言了。







请到「今天看啥」查看全文