阿小信大人的头像
Life is short (You need Python) Bruce Eckel

我和Dave有个约会2019-04-29 18:54

start

今天上午参加了Go语言项目开发成员Dave Cheney的分享。

分享的主题是”High Performance Go: Two tools, three types of profiling in 45 minutes”

分享的内容来自 https://dave.cheney.net/high-performance-go-workshop/gopherchina-2019.html 非常有干货的分享!

两个工具分别是pprof和trace,三种类型的分析例子cpu性能分析,内存性能分析,trace性能分析

Dave首先感谢了Tencent Tarscloud,估计是Tars项目的同事邀请他来的。

第一个例子cpu性能分析

通过一个统计文件内容中单词的个数的go程序和linux自带的wc的性能对比来展示go的性能分析工具pprof的用法。

原始程序代码如下:

编译运行后统计《Moby Dick》白鲸记这篇小说的单词个数。(moby dick直译是大雕???《白鲸记》为赫尔曼·梅尔维尔发表于1851年的小说,被认为是美国最伟大的长篇小说之一。是一部以海上捕鲸业为题材的小说,一位名叫亚哈的“裴廓德号”捕鲸船船长带领全体船员,追捕一条叫做“莫比·迪克”的大白鲸的历险过程。https://www.gutenberg.org/files/2701/2701-h/2701-h.htm)该程序大约2秒统计完成,而wc只要0.012秒,性能差距太大,经过分析优化后,性能接近wc,不如wc我猜测应该是wc的统计逻辑相对简单导致的,他们的统计结果其实并不一样。

于是在代码中开始CPU性能分析,添加profile代码:

go默认的pprof有两个包:net/http/pprofruntime/pprof,前者是通过后者实现的。这里的pkg/profile是第三方包,也是通过runtime/pprof实现的,更加好用。

使用go run运行后会生成cpu.pprof文件(go build不行),接下来就可以通过执行命令 go tool pprof /path/to/cpu.pprof来展示分析结果,执行top命令:

可以通过在上面的命令中添加-http=:PORT参数来启动http服务,就会自动打开浏览器在里面展示dot图,里面可以交互可视化的查看top,火焰图,调用图,源码信息,很强大,需要先安装Graphviz,注意添加bin目录到Path中才行。

我这里测试是windows本地创建了一个有320万个英文字符文件,字符数量太少效果不太明显,调用图如下(和*nix上的输出有所不同):

上面的graph可以看到cpu 90+%是在做syscall.Syscall,因为readbyte直接对文件对象进行读取操作,每次读一个单词,于是这个程序有多少个单词就会调用多少次syscall,系统调用通常都是比较昂贵的操作,大量的syscall就占用了cpu,导致程序性能下降。

优化:因为readbyte接收的是io.Reader的interface,所以可以把文件对象f通过bufio缓存起来就不用每次去读取文件导致syscall了。bufio实现了io.Reader和io.Writer。

性能分析数据

本地测试文件优化以前有大量syscall大概要62秒,优化后没有产生syscall,只需要860毫秒左右,主要耗时在readbyte里创建buf对象。

总结:通过pprof工具可以分析出cpu瓶颈所在。频繁的文件操作会是syscall大量占用cpu,可以使用bufio避免syscall大幅优化性能。

接下来就是第二个例子内存性能分析

profile.Start默认分析cpu,其他指标需要显示指定参数,内存分析rate设置为1表示搜集所有的内存分配信息

可以看到程序内存主要分配在readbyte这里,这里windows上的测试结果和dave分享的结果不太一样。

最后是trace一个生成图片的程序mandelbrot

项目地址: https://github.com/campoy/mandelbro

运行这个程序会生成一张图片,大约花了1.6秒。如何评估它的性能好坏?是否可能让它更快?

首先还是通过pprof分析cpu性能

可以看到cpu消耗在seqFillg中调用fillPixel函数上

在代码中加入trace分析

编译成可执行文件,然后执行,会生成trace.out文件,现在可以使用trace工具分析该文件 go tool trace trace.out 会自动打开浏览器,页面上有查看trace,gorutine分析,网络阻塞分析,同步阻塞分析,系统调用阻塞分析,调度耗时分析等

页面显示只利用了一个cpu

使用gorutine来利用多个cpu

oneToOne方法

每一次的fillpixel都开一个gorutine,运行时间并没有缩短,在trace页面放大看,虽然使用了多个cpu,到cpu并不是连续的,全部是断开的,因为fillpixel做的事太少,花费了大量的时间在gorutine的调度上。

onePerRow方法

将一行像素的填充作为一个gorutine,运行耗时大幅减少,再看trace页面,cpu也利用的不错,gorutine数量也不多。

最后还有一个nworker方法

执行耗时会最慢,因为它使用的是无缓冲channel,每一次都得等。修改为有缓冲的channel就会大幅提升性能。

trace信息也可以通过http接口获取 curl -o trace.out http://127.0.0.1:8080/debug/pprof/trace?seconds=5

end

接下来是QA环节,同学们纷纷用流利的英语和Dave交流 :)

最后是Tars团队和Dave一起坐上讲台不知道要干嘛,我就先溜了。

如果您觉得从我的分享中得到了帮助,并且希望我的博客持续发展下去,请点击支付宝捐赠,谢谢!

若非特别声明,文章均为阿小信的个人笔记,转载请注明出处。文章如有侵权内容,请联系我,我会及时删除。

#Golang#  
分享到:
阅读[419] 评论[0]

下一篇:已经是最后一篇

你可能也感兴趣的文章推荐

本文最近访客

发表评论