&引用;go测试-CPU文件;不生成完整跟踪

&引用;go测试-CPU文件;不生成完整跟踪,go,pprof,Go,Pprof,问题 我有一个围棋包,还有一个测试套件 当我运行此软件包的测试套件时,总运行时间约为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秒:

$ 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
      ...
我看到的问题是:由于某种原因,采样分析器停止采集样本,或者在某个点被阻止/减慢

上下文

go版本为1.14.6,平台为linux/amd64

$ go version
go version go1.14.6 linux/amd64
此包包含与数据库交互的代码,测试在一个实时postgresql服务器上运行

我试过一件事:
t.Skip()
内部调用
runtime.Goexit()
,所以我用一个简单的
返回代替了对
t.Skip
和变体的调用;但这并没有改变结果

问题


为什么不采集更多的样本?我发现一些已知的模式会阻止/减慢采样器,或提前终止采样器?

@Volker在他的评论中引导我找到答案:
-cpuprofile
创建一个配置文件,其中仅对正在使用CPU的goroutine进行采样

在我的用例中:我的go代码花费大量时间等待postgresql server的答案

使用
go-test-trace=trace.out
生成跟踪,然后使用
go-tool-trace-pprof=net-trace.out>network.out
提取网络阻塞配置文件,产生了更多相关信息

作为参考,在使用
go tool trace trace.out
打开完整跟踪的基础上,以下是可以传递给
-pprof=
的值:

发件人:

  • net:网络阻塞配置文件
  • 同步:同步阻止配置文件
  • syscall:syscall阻塞配置文件
  • sched:调度程序延迟配置文件

CpupFile对CPU所做的事情进行采样,它从来都不是“完全捕获”。有效的方法是运行一个基准函数,比如
go test-run X-bench BenchmarkReadDB-cpuprofile cpu.out
,因为基准经常重复,因此对cpu进行采样可以得到所需的信息。所以不,这不是一个已知的问题,这是CPU采样的工作原理。我完全同意yoru的“完全捕获”描述,但是,在实践中,我希望采样覆盖7s运行的很大一部分。在上述情况下,我只获得了约70个样本(我使用
go tool pprof-traces
进行了检查,每个样本的记录时间为10ms,少数样本的记录时间为20ms)。我真正的问题是,如上所述:为什么不收集更多的样本?我发现有一些已知的模式阻止了采样器?更新了我的问题,提到了样本,并重新表述了最后的问题。如果您的代码做的不多,将不会收集太多样本。等待IO的代码没有任何作用。难道我不应该至少让示例说“等待IO”吗?(如上面的
syscall.syscall
$ go version
go version go1.14.6 linux/amd64