Go语言常用性能分析入门

Go语言常用性能分析入门

pprof包来做代码的性能监控,pprof 是一种用于分析数据可视化和分析的工具。

Package pprof writes runtime profiling data in the format expected by the pprof visualization tool.

主要有2个package

net/http/pprof采集工具型应用运行数据进行分析

runtime/pprof 采集服务型应用运行时数据进行分析

在使用pprof之前先安装一些工具

Graphviz

Graphviz 是一款由 AT&T Research 和 Lucent Bell 实验室开源的可视化图形工具,可以很方便的用来绘制结构化的图形网络,支持多种格式输出。

官网:https://graphviz.org

安装

mac

brew install graphviz

liunx

yum install graphviz

windows

可以直接去官方下载安装包,window需要添加系统变量、

验证

dot -version

go-torch

go-torch是uber开源的分析工具

官网 https://github.com/uber-archive/go-torch

安装FlameGraph脚本

git clone https://github.com/brendangregg/FlameGraph.git
cp FlameGraph/flamegraph.pl /usr/local/bin

安装go-torch

go get -v github.com/uber/go-torch

pprof 使用

本次使用在liunx环境上。

首先我们这边写一份代码

main.go

package main

import (
    "log"
    "os"
    "runtime/pprof"
    "strconv"
)

type User struct {
    Name string
    Age  int
}

func main() {
    //创建输出文件句柄
    f, err := os.Create("cpu.prof")
    if err != nil {
        log.Fatal("could not create CPU profile: ", err)
    }

    // 获取系统信息
    // 监控cpu
    if err := pprof.StartCPUProfile(f); err != nil {
        log.Fatal("could not start CPU profile: ", err)
    }
    defer pprof.StopCPUProfile()

    users := GetUsers()
    UpdateUsers(users)

    // 监控堆内存
    f1, err := os.Create("mem.prof")
    if err != nil {
        log.Fatal("could not create memory profile: ", err)
    }
    // runtime.GC()                                       // GC,获取最新的数据信息
    if err := pprof.WriteHeapProfile(f1); err != nil { // 写入内存信息
        log.Fatal("could not write memory profile: ", err)
    }
    f1.Close()

    // 监控goroutine
    f2, err := os.Create("goroutine.prof")
    if err != nil {
        log.Fatal("could not create groutine profile: ", err)
    }
    if gProf := pprof.Lookup("goroutine"); gProf == nil {
        log.Fatal("could not write groutine profile: ")
    } else {
        gProf.WriteTo(f2, 0)
    }
    f2.Close()

}

func GetUsers() []*User {
    users := []*User{}
    for i := 0; i < 1000000; i++ {
        users = append(users, &User{
            Name: "user" + strconv.Itoa(i),
            Age:  i,
        })
    }
    return users
}

func UpdateUsers(users []*User) {
    for _, user := range users {
        user.Age *= 2
    }
}

编译main.go

go build main.go

运行main二进制文件

./main

我们可以看到生成了3个.prof 文件

.
├── cpu.prof
├── goroutine.prof
├── main
├── main.go
└── mem.prof

0 directories, 5 files

我们使用go tool 工具查看prof 文件

我们先看下cpu.prof
go tool pprof cpu.prof

File: main
Type: cpu
Time: Oct 14, 2021 at 12:52pm (CST)
Duration: 200.38ms, Total samples = 0 
No samples were found with the default sample value type.
Try "sample_index" command to analyze different sample values.
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) 

使用top 命令查看方法耗时

(pprof) top -cum      
Showing nodes accounting for 60ms, 25.00% of 240ms total
Showing top 10 nodes out of 38
      flat  flat%   sum%        cum   cum%
         0     0%     0%      150ms 62.50%  main.main
         0     0%     0%      150ms 62.50%  runtime.main
         0     0%     0%      140ms 58.33%  main.GetUsers
      30ms 12.50% 12.50%       90ms 37.50%  runtime.mallocgc
         0     0% 12.50%       80ms 33.33%  runtime.gcBgMarkWorker
         0     0% 12.50%       70ms 29.17%  runtime.gcBgMarkWorker.func2
      10ms  4.17% 16.67%       70ms 29.17%  runtime.gcDrain
         0     0% 16.67%       70ms 29.17%  runtime.systemstack
         0     0% 16.67%       60ms 25.00%  runtime.newobject
      20ms  8.33% 25.00%       60ms 25.00%  runtime.scanobject

使用list 查看 GetUsers方法

(pprof) list GetUsers 
Total: 240ms
ROUTINE ======================== main.GetUsers in /data/home/lalalala/Desktop/study/main.go
         0      140ms (flat, cum) 58.33% of Total
         .          .     55:}
         .          .     56:
         .          .     57:func GetUsers() []*User {
         .          .     58:    users := []*User{}
         .          .     59:    for i := 0; i < 1000000; i++ {
         .       70ms     60:        users = append(users, &User{
         .       70ms     61:            Name: "user" + strconv.Itoa(i),
         .          .     62:            Age:  i,
         .          .     63:        })
         .          .     64:    }
         .          .     65:    return users
         .          .     66:}

可以清晰的看到那一行耗时最多

生成svg

(pprof) svg
Generating report in profile001.svg

用浏览器打开

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mnhaGQAc-1634202585625)(C:\Users\penggewu\AppData\Roaming\Typora\typora-user-images\image-20211014153440410.png)]

图中可以清晰看到每个方法的耗时和调用关系

生成火焰图

$ go-torch cpu.prof 
INFO[16:56:02] Run pprof command: go tool pprof -raw -seconds 30 cpu.prof
INFO[16:56:02] Writing svg to torch.svg

用浏览器打开
在这里插入图片描述

通过Http方式输出Profile

在服务请启动时导入

import _ "net/http/pprof"

先准备一个例子

package main

import (
   "fmt"
   "net/http"
   _ "net/http/pprof"
   "strconv"
)

// 故意写比较慢的递归形式
func GetFibonacciService(n int) int {
   if n == 1 || n == 2 {
      return 1
   }
   return GetFibonacciService(n-1) + GetFibonacciService(n-2)
}

func main() {
   http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {

   })
   http.HandleFunc("/count", func(writer http.ResponseWriter, request *http.Request) {
      fmt.Fprintf(writer, strconv.Itoa(GetFibonacciService(25)))
   })
   http.ListenAndServe(":9999", nil)

}

可以直接在浏览器查看http://localhost:9999/debug/pprof/

在这里插入图片描述

Profile Descriptions:

  • allocs: A sampling of all past memory allocations
  • block: Stack traces that led to blocking on synchronization primitives
  • cmdline: The command line invocation of the current program
  • goroutine: Stack traces of all current goroutines
  • heap:A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.
  • mutex:Stack traces of holders of contended mutexes
  • profile: CPU profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool pprof command to investigate the profile.
  • threadcreate:Stack traces that led to the creation of new OS threads
  • trace:A trace of execution of the current program. You can specify the duration in the seconds GET parameter. After you get the trace file, use the go tool trace command to investigate the trace.

也可以用命令行查看

go tool pprof http://localhost:9999/debug/pprof/profile?seconds=10

Fetching profile over HTTP from http://localhost:9999/debug/pprof/profile?seconds=10
Saved profile in C:\Users\penggewu\pprof\pprof.samples.cpu.003.pb.gz
Type: cpu
Time: Oct 14, 2021 at 4:59pm (CST)
Duration: 10s, Total samples = 0
No samples were found with the default sample value type.
Try "sample_index" command to analyze different sample values.
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

其他操作和pprof操作基本一样

生成svg和火焰图操作相同。

优秀文章推荐:

https://www.liwenzhou.com/posts/Go/performance_optimisation/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值