"go test -cpuprofile" 不生成完整跟踪
"go test -cpuprofile" does not generate a full trace
问题
我有一个带有测试套件的 go 包。
当我运行这个包的测试套件时,总运行时间是~7秒:
$ go test ./mydbpackage/ -count 1
ok mymodule/mydbpackage 7.253s
但是,当我添加 -cpuprofile=cpu.out
选项时,采样并没有覆盖整个 运行 :
$ go test ./mydbpackage/ -count 1 -cpuprofile=cpu.out
ok mymodule/mydbpackage 7.029s
$ go tool pprof -text -cum cpu.out
File: mydbpackage.test
Type: cpu
Time: Aug 6, 2020 at 9:42am (CEST)
Duration: 5.22s, Total samples = 780ms (14.95%) # <--- depending on the runs, I get 400ms to 1s
Showing nodes accounting for 780ms, 100% of 780ms total
flat flat% sum% cum cum%
0 0% 0% 440ms 56.41% testing.tRunner
10ms 1.28% 1.28% 220ms 28.21% database/sql.withLock
10ms 1.28% 2.56% 180ms 23.08% runtime.findrunnable
0 0% 2.56% 180ms 23.08% runtime.mcall
...
查看收集的样本:
# sample from another run :
$ go tool pprof -traces cpu.out | grep "ms " # get the first line of each sample
10ms runtime.nanotime
10ms fmt.(*readRune).ReadRune
30ms syscall.Syscall
10ms runtime.scanobject
10ms runtime.gentraceback
...
# 98 samples collected, for a total sum of 1.12s
我看到的问题是:出于某种原因,采样分析器停止收集样本,或者 blocked/slowed 在某个时候停止。
上下文
go版本为1.14.6,平台为linux/amd64
$ go version
go version go1.14.6 linux/amd64
此包包含与数据库交互的代码,测试是针对实时 postgresql 服务器 运行。
我试过一件事:t.Skip()
内部调用 runtime.Goexit()
,所以我用简单的 return
替换了对 t.Skip
和变体的调用;但这并没有改变结果。
问题
为什么不收集更多样本?我有一些已知的模式 blocks/slows 停止采样器,或者提前终止采样器?
@Volker 在他的评论中引导我找到答案:
-cpuprofile
创建一个配置文件,其中仅对积极使用 CPU 的 goroutine 进行采样。
在我的用例中:我的 go 代码花费了大量时间等待 postgresql 服务器的响应。
使用 go test -trace=trace.out
生成跟踪,然后使用 go tool trace -pprof=net trace.out > network.out
提取网络阻塞配置文件产生了更多相关信息。
作为参考,除了使用 go tool trace trace.out
打开完整跟踪之外,这里是您可以传递给 -pprof=
的值:
from go tool trace
docs :
- net: network blocking profile
- sync: synchronization blocking profile
- syscall: syscall blocking profile
- sched: scheduler latency profile
问题
我有一个带有测试套件的 go 包。
当我运行这个包的测试套件时,总运行时间是~7秒:
$ go test ./mydbpackage/ -count 1
ok mymodule/mydbpackage 7.253s
但是,当我添加 -cpuprofile=cpu.out
选项时,采样并没有覆盖整个 运行 :
$ go test ./mydbpackage/ -count 1 -cpuprofile=cpu.out
ok mymodule/mydbpackage 7.029s
$ go tool pprof -text -cum cpu.out
File: mydbpackage.test
Type: cpu
Time: Aug 6, 2020 at 9:42am (CEST)
Duration: 5.22s, Total samples = 780ms (14.95%) # <--- depending on the runs, I get 400ms to 1s
Showing nodes accounting for 780ms, 100% of 780ms total
flat flat% sum% cum cum%
0 0% 0% 440ms 56.41% testing.tRunner
10ms 1.28% 1.28% 220ms 28.21% database/sql.withLock
10ms 1.28% 2.56% 180ms 23.08% runtime.findrunnable
0 0% 2.56% 180ms 23.08% runtime.mcall
...
查看收集的样本:
# sample from another run :
$ go tool pprof -traces cpu.out | grep "ms " # get the first line of each sample
10ms runtime.nanotime
10ms fmt.(*readRune).ReadRune
30ms syscall.Syscall
10ms runtime.scanobject
10ms runtime.gentraceback
...
# 98 samples collected, for a total sum of 1.12s
我看到的问题是:出于某种原因,采样分析器停止收集样本,或者 blocked/slowed 在某个时候停止。
上下文
go版本为1.14.6,平台为linux/amd64
$ go version
go version go1.14.6 linux/amd64
此包包含与数据库交互的代码,测试是针对实时 postgresql 服务器 运行。
我试过一件事:t.Skip()
内部调用 runtime.Goexit()
,所以我用简单的 return
替换了对 t.Skip
和变体的调用;但这并没有改变结果。
问题
为什么不收集更多样本?我有一些已知的模式 blocks/slows 停止采样器,或者提前终止采样器?
@Volker 在他的评论中引导我找到答案:
-cpuprofile
创建一个配置文件,其中仅对积极使用 CPU 的 goroutine 进行采样。
在我的用例中:我的 go 代码花费了大量时间等待 postgresql 服务器的响应。
使用 go test -trace=trace.out
生成跟踪,然后使用 go tool trace -pprof=net trace.out > network.out
提取网络阻塞配置文件产生了更多相关信息。
作为参考,除了使用 go tool trace trace.out
打开完整跟踪之外,这里是您可以传递给 -pprof=
的值:
from
go tool trace
docs :
- net: network blocking profile
- sync: synchronization blocking profile
- syscall: syscall blocking profile
- sched: scheduler latency profile