brew install graphviz
go tool pprof -inuse_space http://1x.1xx.1x3.xx:4803/debug/pprof/heap
go tool pprof -http=127.0.0.1:12345 -inuse_space http://1x.1xx.1x3.xx:4803/debug/pprof/heap
go tool pprof -inuse_objects http://1x.1xx.1xx.x0:487/sxx/debug/pprof/heap
go tool pprof -http=127.0.0.1:12345 -inuse_objects http://1x.1xx.1xx.x0:487/sxx/debug/pprof/heap
% tree
.
├── data
│ └── d.go
├── go.mod
└── main.go
1 directory, 3 files
Main.go
package main
import (
"log"
"net/http"
_ "net/http/pprof"
"pproftest/data"
"time"
)
func main() {
go func() {
for {
time.Sleep(1*time.Second)
log.Println(data.Add("https://github.com/EDDYCJY"))
}
}()
http.ListenAndServe("0.0.0.0:6060", nil)
}
d.go
package data
var datas []string
func Add(str string) string {
data := []byte(str)
sData := string(data)
datas = append(datas, sData)
return sData
}
启动程序
go run main.go
实际应用
package main
import (
"fmt"
"net/http"
_ "net/http/pprof" // 第一步~
)
// 一段有问题的代码
func do() {
var c chan int
for {
select {
case v := <-c:
fmt.Printf("我是有问题的那一行,因为收不到值:%v", v)
default:
}
}
}
func main() {
// 执行一段有问题的代码
for i := 0; i < 4; i++ {
go do()
}
http.ListenAndServe("0.0.0.0:6061", nil)
}
http://127.0.0.1:6060/debug/pprof/
描述
类型 | 描述 |
---|---|
allocs | 内存分配情况的采样信息 |
blocks | 阻塞操作情况的采样信息 |
cmdline | 显示程序启动命令参数及其参数 |
goroutine | 显示当前所有协程的堆栈信息 |
heap | 堆上的内存分配情况的采样信息 |
mutex | 锁竞争情况的采样信息 |
profile | cpu占用情况的采样信息,点击会下载文件 |
threadcreate | 系统线程创建情况的采样信息 |
trace | 程序运行跟踪信息 |
CPU的指标,通常这个和锁有关系
一般情况是GC的时候进行的STW的开启锁定锁导致
gopark函数在协程的实现上扮演着非常重要的角色,用于协程的切换,协程切换的原因一般有以下几种情况:
func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason waitReason, traceEv byte, traceskip int) {
if reason != waitReasonSleep {
checkTimeouts() // timeouts may expire while two goroutines keep the scheduler busy
}
mp := acquirem()
gp := mp.curg
status := readgstatus(gp)
if status != _Grunning && status != _Gscanrunning {
throw("gopark: bad g status")
}
mp.waitlock = lock
mp.waitunlockf = *(*unsafe.Pointer)(unsafe.Pointer(&unlockf))
gp.waitreason = reason
mp.waittraceev = traceEv
mp.waittraceskip = traceskip
releasem(mp)
// can't do anything that might move the G between Ms here.
mcall(park_m)
}
源码里面最重要的一行就是调用 mcall(park_m)
函数,park_m是一个函数指针。mcall在golang需要进行协程切换时被调用,做的主要工作是:
func goready(gp *g, traceskip int) {
// 切换到g0的栈
systemstack(func() {
ready(gp, traceskip, true)
})
}
goready函数相比gopark函数来说简单一些,主要功能就是唤醒某一个goroutine,该协程转换到runnable的状态,并将其放入P的local queue,等待调度。
same as runtime·notetsleep, but called on user g (not g0)
// calls only nosplit functions between entersyscallblock/exitsyscall
检测栈增长及监控G的执行时间是否超过10ms,如果超过将当前G和M绑定,解绑P
cpu(CPU Profiling): $HOST/debug/pprof/profile,默认进行 30s 的 CPU Profiling,得到一个分析用的 profile 文件
另外启动中端,等待30s
go tool pprof http://localhost:6060/debug/pprof/profile\?seconds\=60
类型 | 描述 | 举例 |
---|---|---|
flat | 该函数占用CPU的耗时 | selectnbrecv占用CPU的耗时是12.29s |
flat% | 该函数占用CPU的耗时的百分比 | selectnbrecv耗时:12.29s,cpu总耗时:29.14,12.29/29.14=42.18 |
sum% | top命令中排在它上面的函数以及本函数flat%之和 | chanrecv:42.18%+30.47% = 72.65% |
cum | 当前函数加上该函数调用之前的累计CPU耗时 | chanrecv:8.88+0.54=9.42 |
cum% | 当前函数加上该函数调用之前的累计CPU耗时的百分比 | 9.42/29.14=32.33% |
最后一列 | 当前函数名称 | - |
默认情况下取样时只取当前内存使用情况,可以加可选命令alloc_objects,将从程序开始时的内存取样
go tool pprof -alloc_objects -http=127.0.0.1:12345 http://xxx:9999/debug/pprof/heap
终端模式下输入
list 加函数名
go tool pprof -http=127.0.0.1:1234 http://localhost:6061/debug/pprof/profile\?seconds\=10
线越粗越有问题,耗时越高
终端模式下
web png 或者pdf
查看do函数
list main.do
发现有问题的行数在文中具体的位置,原来是卡住了,加上default休眠n秒即可解决。
block(Block Profiling):$HOST/debug/pprof/block,查看导致阻塞同步的堆栈跟踪
go tool pprof http://localhost:6061/debug/pprof/block\?seconds\=10
和上边CPu的一样list
Web 也是一样
goroutine:$HOST/debug/pprof/goroutine,查看当前所有运行的 goroutines 堆栈跟踪
go tool pprof http://localhost:6061/debug/pprof/goroutine\?seconds\=10
go tool pprof -http=127.0.0.1:1345 http://localhost:6061/debug/pprof/goroutine
heap(Memory Profiling): $HOST/debug/pprof/heap,查看活动对象的内存分配情况
go tool pprof http://localhost:6061/debug/pprof/heap
go tool pprof -http=127.0.0.1:1345 http://localhost:6061/debug/pprof/heap
mutex(Mutex Profiling):$HOST/debug/pprof/mutex,查看导致互斥锁的竞争持有者的堆栈跟踪
go tool pprof http://localhost:6061/debug/pprof/mutex
同上
go tool pprof -http=127.0.0.1:1345 http://localhost:6061/debug/pprof/mutex
threadcreate:$HOST/debug/pprof/threadcreate,查看创建新OS线程的堆栈跟踪
go tool pprof http://localhost:6061/debug/pprof/threadcreate
list runtime.main
go tool pprof -http=127.0.0.1:1345 http://localhost:6061/debug/pprof/threadcreate
每一块代表一个函数,越大代表占用 CPU 的时间更长
另一种可视化数据的方法是火焰图,需手动安装原生 PProf 工具:
(1) 安装 PProf
$ go get -u github.com/google/pprof
(2) 启动 PProf 可视化界面:
$ pprof -http=:8080 cpu.prof
代码
package main
import (
"fmt"
"log"
"os"
"runtime/pprof"
"time"
)
func do() {
var c chan int
for {
select {
case v := <-c:
fmt.Println("有问题", v)
default:
fmt.Println("default")
}
}
}
func main() {
var (
file *os.File
err error
)
if file, err = os.Create("./cpu.prof"); nil != err {
log.Fatal(err)
}
//1、获取CPU信息
if err = pprof.StartCPUProfile(file); err != nil {
log.Fatal(err)
}
defer pprof.StopCPUProfile()
for i := 0; i < 4; i++ {
go do()
}
time.Sleep(10 * time.Second)
}
生成
go tool pprof
go tool pprof cpu.prof
package main
import (
"fmt"
"net/http"
_ "net/http/pprof" // 第一步~
)
// 一段有问题的代码
func do() {
var c chan int
for {
select {
case v := <-c:
fmt.Printf("我是有问题的那一行,因为收不到值:%v", v)
default:
}
}
}
func main() {
// 执行一段有问题的代码
for i := 0; i < 4; i++ {
go do()
}
http.ListenAndServe("0.0.0.0:6061", nil)
}
获取CPU信息和Heap信息
package main
import (
"fmt"
"log"
"os"
"runtime/pprof"
"time"
)
func do() {
var c chan int
for {
select {
case v := <-c:
fmt.Println("有问题", v)
default:
fmt.Println("default")
}
}
}
func main() {
var (
file, file1 *os.File
err error
)
if file, err = os.Create("./cpu.prof"); nil != err {
log.Fatal(err)
}
if file1, err = os.Create("./heap.prof"); nil != err {
log.Fatal(err)
}
//1、获取CPU信息
if err = pprof.StartCPUProfile(file); err != nil {
log.Fatal(err)
}
defer pprof.StopCPUProfile()
//2、获取heap信息
if err = pprof.WriteHeapProfile(file1); nil != err {
log.Fatal(err)
}
for i := 0; i < 4; i++ {
go do()
}
time.Sleep(10 * time.Second)
}
https://segmentfault.com/a/1190000016412013
https://segmentfault.com/a/1190000016354758