Profiling ngcore in go
因为新版本的ngcore已经把mining模块删除了,因此在空闲状态从理论上看应该是非常低调的一个p2p“哑巴”。但是实际在PC这个3600x相对高级u的环境下都能占据>10%的cpu且高耗电。因此这里就开始对程序尝试调优。
暂时就只关注cpu利用率的问题(高耗电在客户端上太致命了
首先通过注释掉import _ "net/http/pprof"
确认了高电量不是由于引入profile导致的。
然后根据profile给出的结果对几个loop都加了runtime.Goshced,并没有太大起色。
profile结果全是runtime.xxx这种内部的方法。
go的profile
首先肯定是需要熟练一下go自带的pprof工具。
为了方便profiling,ngcore会在一个随机可用端口上建立一个http server来为pprof提供当前运行数据。
一般可以使用go tool pprof http://localhost:[port]
来开启命令行模式,如果带-http=:[another_port]
参数就可以在another_port上建一个网页来展示diagrams
下面说一下在命令行模式下的一些命令
topNN
NN可以换成任何数字,比如top10就profile(CPU)前十的func。
go的blog上示例明显老旧了,这里我拿go1.16下的结果讲解一下
1 | (pprof) top10 |
- flat:样本中running时间(不包含waiting for a called function to return,默认按此排序)
- flat%:占总样本时间百分比
- sum:即从上往下sum(flat%)
- cum:func出现(包括running或waiting for a called function to return)的样本时间(用-cum就用它排序)
- cum%:占总百分比
web
web
命令就是在网页显示stack trace。命令行打开的web不如直接host在http。
通过trace就可以看到是主要哪里call了这个在前面疯狂running的func。
list
list Func
会给你打印Func这个func的源码,并且在每行的左边显示对应的flat和cum
优化
从上面的可以看出来其实是eventLoop里的select导致了selectgo的大量调用。
在这个函数里我用了两个case的for-select结构,两个case都是从channel里接受内容。
尝试了下把for-select-<- ch
分解成了两个for-<- ch
(不影响业务),cpu占用瞬间变成1-2%(而且是平板上)可以说是相当显著。
有关这个for-select性能的讨论
Ref
https://github.com/dgryski/go-perfbook/blob/master/performance.md