go tool的代码追踪

go tool trace 实用程序是一个工具,用来查看由以下三种方式中任何一种产生的追踪文件:

  • 使用 runtime/trace
  • 使用 net/http/pprof
  • 执行 go test --trace 命令

这节将只使用第一种技术。如下命令的输出将极大帮助您理解 Go execution tracer 在做什么:

11.6 go tool的代码追踪 - 图1

第2章(深入剖析Go的内部原理),我们讨论了 Go 的垃圾回收,并介绍了一个 Go 实用程序 gColl.go,它能让我们看到 Go 垃圾回收的一些变量。在这节,我将使用 go tool trace 实用程序来获得关于 goColl.go 操作的更多信息。

首先,让我们来查看一下 gColl.go 程序的修改版,它告诉 Go 去收集性能数据。它被另存为 goGC.go,将分三部分来介绍。

goGC.go 的第一部分如下:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "runtime"
  6. "runtime/trace"
  7. "time"
  8. )
  9. func printStats(mem runtime.MemStats) {
  10. runtime.ReadMemStats(&mem)
  11. fmt.Println("mem.Alloc:", mem.Alloc)
  12. fmt.Println("mem.TotalAlloc:", mem.TotalAlloc)
  13. fmt.Println("mem.HeapAlloc:", mem.HeapAlloc)
  14. fmt.Println("-----")
  15. }

如您所知,您首先需要引入 runtime/trace 标准包以便为 go tool trace 实用程序收集数据。

goGC.go 的第二段代码如下:

  1. func main() {
  2. f, err := os.Create("/tmp/traceFile.out")
  3. if err != nil {
  4. panic(err)
  5. }
  6. defer f.Close()
  7. err = trace.Start(f)
  8. if err != nil {
  9. fmt.Println(err)
  10. return
  11. }
  12. defer trace.Stop()

这部分是所有为 go tool trace 实用程序获取数据的地方,并且它与实际程序的功能无关。首先,你将创建一个新文件来保存为 go tool trace 工具追踪的数据。然后,您使用 trace.Start() 启动追踪处理。当您完成追踪,可以调用 trace.Stop() 函数。defer 调用这个函数的意思是您想要在程序结束时终止追踪。

使用 go tool trace 实用程序是一个包含俩个需要额外 Go 代码阶段的过程。首先您收集数据,然后您显示并处理数据。

余下代码如下:

  1. var mem runtime.MemStats
  2. printStats(mem)
  3. for i := 0; i < 3; i++ {
  4. s := make([]byte, 50000000)
  5. if s == nil {
  6. fmt.Println("Operation failed!")
  7. }
  8. }
  9. printStats(mem)
  10. for i := 0; i < 5; i++ {
  11. s := make([]byte, 100000000)
  12. if s == nil {
  13. fmt.Println("Operation failed!")
  14. }
  15. time.Sleep(time.Millisecond)
  16. }
  17. printStats(mem)
  18. }

执行 goGC.go 产生如下输出以及带有跟踪信息的名为 /tmp/traceFile.out 的新文件:

  1. $ go run goGC.go
  2. mem.Alloc: 107264
  3. mem.TotalAlloc: 107264
  4. mem.HeapAlloc: 107264
  5. mem.NumGC: 0
  6. -----
  7. mem.Alloc: 50117672
  8. mem.TotalAlloc: 150129416
  9. mem.HeapAlloc: 50117672
  10. mem.NumGC: 3
  11. -----
  12. mem.Alloc: 117320
  13. mem.TotalAlloc: 650174208
  14. mem.HeapAlloc: 117320
  15. mem.NumGC: 8
  16. -----
  17. $ cd /tmp
  18. $ ls -l traceFile.out
  19. -rw-r--r-- 1 mtsouk wheel 8275 Mar 7 08:37 traceFile.out
  20. $ file /tmp/traceFile.out
  21. /tmp/traceFile.out: data

当您执行如下命令时,go tool trace 实用程序自动开启一个web 节目:

  1. $ go tool trace /tmp/traceFile.out
  2. 2018/03/07 08:34:36 Parsing trace...
  3. 2018/03/07 08:34:36 Serializing trace...
  4. 2018/03/07 08:34:36 Splitting trace...
  5. 2018/03/07 08:34:36 Opening browser. Trace viewer is listening on http://127.0.0.1:61428

下面的截屏显示了当查看 tmp/traceFiel.out 追踪文件时,go tool trace 实用程序的初始 web 界面:

go trace tool 的初始 web 界面

现在您应该选择 View trace 链接。它将带您到下个界面,显示 go tool trace 实用程序的另一个 web 界面,使用来自 /tmp/traceFile.out 的数据:

使用 go tool trace 查看 Go 垃圾收集的操作

从上图,您能看到 Go GC 运行在自己的 goroutine,但它没有一直运行。另外,您可以看到程序使用了一定数量的 goroutines。关于Go GC,您可以通过选择交互界面的某些部分来了解更多信息。由于我们对 GC 的操作感兴趣,一段有用的显示信息是 Go GC 运行的频率和持续时间。

注意尽管 go tool trace 是一个非常方便强大的工具,但它不能解决任何性能问题。有时 go tool pprof 更合适,特别当您想要查找您的程序在哪个独立的功能上花费了大部分时间。