1 Go trace 介绍

go trace 在 go 1.5 版本加入,会在运行中收集以下事件的所有数据

  • 创建,启动和终止 goroutine

  • 阻塞/非阻塞 goroutines(syscalls, channels, locks)

  • 网络 io

  • Syscalls

  • gc

收集后不会做任何类型的聚合和抽样。

pprof 用来分析 CPU 和内存分别用在了哪里,trace 用来确定什么阻止了 goroutine 运行,goroutine 在 OS 线程上如何被调度。

1.1 收集 trace 的方式

有三种收集trace的方法:

**使用 runtime/trace包 **

这个需要调用trace.Starttrace.Stop

f, _ := os.Create("./trace.out")
_ = trace.Start(f)
defer trace.Stop()

**使用 ****-trace=****测试标志 **

用来收集关于被测试代码的trace时比较有用。

**使用 debug/pprof/trace handler **

这是用来收集运行中的web应用的trace的最好的方法。

curl localhost:8080/debug/pprof/trace?seconds=10 > trace.out // zsh 可能报错

2 实践

首先从一个简单的程序开始。

package main

import (
    "log"
    "os"
    "runtime/trace"
)

func main() {
    f, _ := os.Create("./trace.out")
    _ = trace.Start(f)
    defer trace.Stop()

    const n = 3

    leftmost := make(chan int)
    right := leftmost
    left := leftmost

    for i := 0; i < n; i++ {
        right = make(chan int)
        go pass(left, right)
        left = right
    }

    go sendFirst(right)
    log.Println(<-leftmost)
}

func pass(left, right chan int) {
    v := 1 + <-right
    left <- v
}

func sendFirst(ch chan int) { ch <- 0 }

这份代码通过 channel 创建了一个 goroutine 链。

我们指定了会在当前目录生成 trace 文件。运行代码,然后使用 go tool trace trace.out

它会启动一个 web 服务,127.0.0.1 加上一个随机端口。页面如下

3 View trace

交互式,可视化的显示了这个程序执行的时间轴。这个视图显示了在每个虚拟处理器上运行着什么,以及什么是被阻塞等待运行的。注意这个视图只能在 Chrome 上显示。

3.1 Timeline

Timeline 显示执行的时间,根据跟踪定位的不同,时间单位可能会发生变化。可以用键盘的 WASD 键来导航时间轴。

3.2 STATS

Heap,Goroutine,Threads这里有几行数据,鼠标定位到某一行在数据,在下方就会显示对应的信息

  • Goroutine 行显示有多少 Goroutine 在运行。有多少是可运行(等待被调度)的。大量可运行的 goroutine 说明可能存在调度竞争。

  • Heap 行显示的是执行期间的内存分配,这对于发现内存泄露非常有用。也能检查垃圾回收在每次运行时能够释放多少内存。

  • OS Threads 显示有多少 OS 线程正在被使用,有多少个被 syscall 阻塞。

3.3 Procs

Virtual Processors每个虚拟处理器显示一行。数量即 GOMAXPROCS 环境环境变量控制的。

3.4 Goroutine 和 events

显示在每个虚拟处理器上有什么 goroutine 在运行。连接 goroutine 的连线代表事件,

选择右上角 “View Options -> Flow events” 可以看到 goroutine 之间的连线,这些连线代表事件。

选择一个 goroutine,可以看到这些信息

  • Title 它的名称

  • Start 开始时间

  • Wall Duration 持续时间

  • Start Stack Trace 开始时的栈 trace

  • End Stack Trace 结束时的栈 trace

  • Events 该 goroutine 产生的事件

4 Goroutine analysis

显示了在整个执行过程中,每种类型的 goroutine 是如何创建的。在选择一种类型后就可以看到关于这种类型的 goroutine 信息。比如,视图中 mutex 中获取锁,从网络读取等等。

5 Network/Sync/Syscall blocking profile

这些图显示了 goroutine 在这些资源上所花费的时间。它们非常接近 pprof 上的内存/cpu 分析。是分析锁竞争的最佳选择。

6 Scheduler latency profiler

为调度器级别的信息提供计时功能,显示调度在哪里最耗费时间。

参考

Go调优神器trace介绍

https://mp.weixin.qq.com/s/I9xSMxy32cALSNQAN8wlnQ

Go 性能调优之 —— 跟踪

https://segmentfault.com/a/1190000016354853

https://studygolang.com/articles/9693