ℹ️ 本文基于 Go 1.13。
pprof是用于分析性能数据(例如CPU或内存分配)的工具。 对应用程序进行性能分析需要在运行时收集数据,以便稍后聚合它们并生成图形。 现在,让我们深入研究此数据收集的工作流程,并了解如何对其进行调整。
工作流
pprof以固定的时间间隔收集分析数据,该间隔由每秒的收集次数定义。 默认参数是100,这意味着pprof每秒将收集一百次数据,即每10毫秒一次。
可以通过调用StartCPUProfile来启动pprof:
func main() { f, _ := os.Create(`cpu.prof`) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() ... }
此过程将在正在运行的线程上自动设置一个定时器(下图中的M表示),该定时器允许Go定期收集分析数据。 这是第一个图:
有关P,M,G表示形式的更多信息,建议您阅读之前的文章 “Go: Goroutine, 系统线程和CPU管理”
pprof仅分析当前正在运行的线程。 当Go调度器调度goroutine在某线程上运行时,将实时跟踪该线程。 这是更新的图:
关于Go调度器的更多信息,我建议您阅读之前的文章“Go: g0, 特殊的goroutine”
然后,分析数据将按每个定义的时间间隔定期转储到缓冲区:
数据实际上是由gsignal转储的,gsignal是一个处理传入信号的goroutine。实际上,定时器在每个时间间隔发出信号。
关于信号和gsignal的更多信息,我建议您阅读之前的文章“Go:gsignal,信号大师”
基于信号
在每个线程上创建的定时器是由setitimer方法和时间间隔定时器ITIMER_PROF管理的。时间计数仅在进程运行时才会减少,这样就能确保分析数据的准确。
一旦达到时间间隔,定时器就会发出一个SIGPROF信号,该信号将被Go截获,并将分析数据转储到缓冲区。可以通过从运行时包中调用函数SetCPUProfileRate来配置分析频率。必须在启动分析器之前执行以下操作:
func main() { f, err := os.Create(`cpu.prof`) if err != nil { log.Fatal(err) } runtime.SetCPUProfileRate(10) pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() ... }
配置分析频率只能定义一次,pprof在启动分析器时定义它。在启动分析器之前调用该方法将导致pprof忽略默认值。但是,在大多数情况下,默认值应该足够了。这个选择在软件包中有很好的解释:
100赫兹是一个合理的选择:可以产生足够多有用的数据,足够少影响系统稳定。
数据收集
定时器现在都设置好了。一旦缓冲,pprof需要一种方法来收集所有数据来创建报告。这个过程由一个单独的goroutine完成,该goroutine每隔100毫秒收集并格式化数据。
生成完成后,即分析停止后,专用goroutine会将报告转储到文件中,使其可用并完成可视化。
编译自:https://medium.com/a-journey-with-go/go-samples-collection-with-pprof-2a63c3e8a142