Go 库性能分析工具pprof

目录
  • 场景
  • pprof
    • 生成 profile 文件
      • CPU 性能分析
      • 内存性能分析
    • 分析 profile 文件 && 优化代码
    • go tool pprof
      • top 命令
      • list 命令
  • 总结

场景

我们一般没必要过度优化 Go 程序性能。但是真正需要时,Go 提供的 pprof 工具能帮我们快速定位到问题。比如,我们团队之前有一个服务,在本地和测试环境没问题,一到灰度环境,就报 cpu 负载过高,后经排查,发现某处代码死循环了。我把代码简化成如下:

// 处理某些业务,真实的代码中这个死循环很隐蔽
func retrieveSomeThing() {
	for {}
}
// 处理其他的一些业务,无意义,用于后续做例子
func doSomeThing() {
	do1()
	for i := 0; i < 200000000; i++ {}
	do2()
}
// 无意义
func do1() {
	for i := 0; i < 200000000; i++ {}
}
// 无意义
func do2() {
	for i := 0; i < 200000000; i++ {}
}
func main() {
	go retrieveSomeThing()
  go doSomeThing()
	// 阻塞一下
	time.Sleep(3 * time.Second)
}

解决问题前,先介绍下 pprof。

pprof

pprof 包会输出运行时的分析数据(profiling data),这些数据可以被 pprof 的可视化工具解析。Go 标准库主要提供了两个包:

  • runtime/pprof 通过写入到文件的方式暴露 profile 数据;
  • net/http/pprof 通过 http 服务暴露 profile 数据,适用于守护进程。

生成 profile 文件

CPU 性能分析

runtime/pprof 中,使用StartCPUProfile开启 CPU 性能分析。退出程序前,需要调用StopCPUProfile把采样数据 flush 到输出文件。

采样的频率默认是 100 Hz(每秒 100 次)。

// 输出到标准输出,一般是指定文件
if err := pprof.StartCPUProfile(os.Stdout); err != nil {
    log.Fatal("could not start CPU profile: ", err)
}
defer pprof.StopCPUProfile()

内存性能分析

调用 WriteHeapProfile 开启内存性能分析:

// 输出到标准输出,一般是指定文件
if err := pprof.WriteHeapProfile(os.Stdout); err != nil {
    log.Fatal("could not write memory profile: ", err)
}
}

分析 profile 文件 && 优化代码

以开篇的代码为例,由于是 CPU 过载,我们可以在 main 函数开启 CPU Profile:

// 通过参数指定 cpu profile 输出的文件
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
func main() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		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()
	}
	// 业务代码
	go retrieveSomeThing()
  go doSomeThing()
	// 模拟阻塞
	time.Sleep(5 * time.Second)
}

我们执行命令,输出 profile 文件到 cpu.prof。

go run main.go -cpuprofile cpu.prof

go tool pprof

Go 提供性能解析工具:go tool pprof。我们使用 go tool 打开 profile 文件。

> go tool pprof cpu.prof
Type: cpu
Time: Nov 16, 2022 at 1:40pm (CST)
Duration: 5.17s, Total samples = 4.54s (87.75%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

这是个交互式的界面,输入help可以查看所有命令。

top 命令

我们使用 topN 命令,查看根据 flat 从大到小排序的前 N 条数据。

(pprof) top10
Showing nodes accounting for 4650ms, 100% of 4650ms total
      flat  flat%   sum%        cum   cum%
    4220ms 90.75% 90.75%     4450ms 95.70%  main.retrieveSomeThing
     230ms  4.95% 95.70%      230ms  4.95%  runtime.asyncPreempt
      80ms  1.72% 97.42%      200ms  4.30%  main.doSomeThing
      70ms  1.51% 98.92%       70ms  1.51%  main.do2 (inline)
      50ms  1.08%   100%       50ms  1.08%  main.do1 (inline)

top 命令返回数据有5个指标:

  • flat : 本函数占用的 CPU 时间,不包括调用函数的时间;
  • flat% : flat 占的百分比;
  • sum% : 前面 flat% 的总和;
  • cum : 累计时间,包括调用的函数的时间;
  • cum% : cum 的百分比。

main.doSomeThing(排第三的函数)为例子,耗时为:

func doSomeThing() {                   // flat: 80ms  cum: 200ms
	do1()                                // 执行时间 50ms
	for i := 0; i < 200000000; i++ {}    // 执行时间 80ms
	do2()                                // 执行时间 70ms
}

doSomeThing 的 flat 的值为:

for i := 0; i < 200000000; i++ {}的执行时间(80ms),不包括do1和do2的时间。

doSomeThing 的 cum 的值为:

cum(200ms) = doSomething的flat(80ms) + do1的flat(50ms) + do2的flat(70ms)

ps: top 可以使用 -cum 参数来指定,根据 cum 排序。

list 命令

明白了 top 的指标的意思,我们关注到,排在 top1 的函数是 retrieveSomeThing。可以使用 list 命令,查看 retrieveSomeThing 耗时:

(pprof) list retrieveSomeThing
Total: 4.65s
ROUTINE ======================== main.retrieveSomeThing in /xxxx/pprof_note/pprof/main.go
     4.22s      4.45s (flat, cum) 95.70% of Total
      10ms       10ms      1:package main
         .          .      2:
         .          .      3:import (
         .          .      4:   "flag"
         .          .      5:   "log"
         .          .      6:   "os"
         .          .      7:   "runtime/pprof"
         .          .      8:   "time"
         .          .      9:)
         .          .     10:
         .          .     11:// 处理某些业务,真实的代码中这个死循环很隐蔽
         .          .     12:func retrieveSomeThing() {
     4.21s      4.44s     13:   for {
         .          .     14:   }
         .          .     15:}
         .          .     16:
         .          .     17:// 处理其他的一些业务,无意义,用于后续做例子
         .          .     18:func doSomeThing() {

我们定位到13行需要优化。

总结

pprof 还有很多玩法,包括其他的性能指标,go tool 的其他命令,profile 文件的可视化等。这个留给读者自行扩展阅读。

本文主要参考了 Russ Cox 大神的文章:《Profiling Go Programs》 (go.dev/blog/pprof)… 文章为反驳 "Go性能不如其他语言"的观点,借助 pprof 大幅度优化了程序的运行时间和内存。

以上就是Go 库性能分析工具pprof的详细内容,更多关于Go pprof性能分析的资料请关注我们其它相关文章!

(0)

相关推荐

  • go slice不同初始化方式性能及数组比较详解

    目录 正文 各种场景代码 使用benchmark测试 正文 go语言开发中,slice是我们常用的数据类型之一,也是因为它的灵活性,自己也很少使用数组,当然我也知道它的一些特性,不过没有真实的去验证它,因为大多数使用场景没必要对code太过苛刻,但是如果封装作为包为其他逻辑提供使用的时候,我觉得还是要在意这些事的,毕竟作为公共包使用时,也就证明了使用的频率的频繁性.那么有些事还是指的记录一下,上周闲来无事跑一下吧,今天做一下记录 各种场景代码 其实我们也都知道slice的底层逻辑是一个动态数组,

  • web项目中golang性能监控解析

    目录 性能监控 一.web项目(如gin中) 二.单个的go文件如果查看gc 性能监控 一.web项目(如gin中) 1.使用ginpprof import "github.com/DeanThompson/ginpprof" router := gin.Default() ginpprof.Wrap(router) 2.使用pprof 只需要在main.go中引入:_ “net/http/pprof” 访问:127.0.0.1:8080/debug/pprof /debug/ppro

  • Golang高性能持久化解决方案BoltDB数据库介绍

    目录 1. 介绍Bolt 2. 示例 3. 示例分析 4. 总结 1. 介绍Bolt BoltDB是纯Go语言实现的持久化解决方案,保存数据至内存映射文件.称之为持久化解决方案不是数据库,因为数据库这个词有很多额外功能是bolt所不具备的.正是因为缺乏这些功能使得bolt如此优雅.好用. Bolt就是一个Go包.无需在系统中安装,开始编码前也无需配置,什么都不需要,仅需要go get github.com/boltdb/bolt,然后import "github.com/boltdb/bolt&

  • go zero微服务实战性能优化极致秒杀

    目录 引言 批量数据聚合 降低消息的消费延迟 怎么保证不会超卖 结束语 引言 上一篇文章中引入了消息队列对秒杀流量做削峰的处理,我们使用的是Kafka,看起来似乎工作的不错,但其实还是有很多隐患存在,如果这些隐患不优化处理掉,那么秒杀抢购活动开始后可能会出现消息堆积.消费延迟.数据不一致.甚至服务崩溃等问题,那么后果可想而知.本篇文章我们就一起来把这些隐患解决掉. 批量数据聚合 在SeckillOrder这个方法中,每来一次秒杀抢购请求都往往Kafka中发送一条消息.假如这个时候有一千万的用户同

  • go原生库的中bytes.Buffer用法

    1 bytes.Buffer定义 bytes.Buffer提供可扩容的字节缓冲区,实质是对切片的封装:结构中包含一个64字节的小切片,避免小内存分配: // A Buffer is a variable-sized buffer of bytes with Read and Write methods. // The zero value for Buffer is an empty buffer ready to use. type Buffer struct { buf []byte //

  • GoLang strings.Builder底层实现方法详解

    目录 1.strings.Builder结构体 1.1strings.Builder结构体 1.2Write方法 1.3WriteByte方法 1.4WriteRune方法 1.5.WriteString方法 1.6String方法 1.7Len方法 1.8Cap方法 1.9Reset方法 1.10Grow方法 1.11grow方法 1.12copyCheck方法 2.strings.Builder介绍 3.存储原理 4.拷贝问题 5.不能与nil作比较 6.Grow深入 7.不支持并行读写 1

  • GoFrame基于性能测试得知grpool使用场景

    目录 前言摘要 先说结论 测试性能代码 运行结果 总结 前言摘要 之前写了一篇 grpool goroutine池详解 | 协程管理 收到了大家积极的反馈,今天这篇来做一下grpool的性能测试分析,让大家更好的了解什么场景下使用grpool比较好. 先说结论 grpool相比于goroutine更节省内存,但是耗时更长: 原因也很简单:grpool复用了协程,减少了协程的创建和销毁,减少了内存消耗:也因为协程的复用,总的goroutine数量更少,导致耗时更多. 测试性能代码 开启for循环,

  • Go 库性能分析工具pprof

    目录 场景 pprof 生成 profile 文件 CPU 性能分析 内存性能分析 分析 profile 文件 && 优化代码 go tool pprof top 命令 list 命令 总结 场景 我们一般没必要过度优化 Go 程序性能.但是真正需要时,Go 提供的 pprof 工具能帮我们快速定位到问题.比如,我们团队之前有一个服务,在本地和测试环境没问题,一到灰度环境,就报 cpu 负载过高,后经排查,发现某处代码死循环了.我把代码简化成如下: // 处理某些业务,真实的代码中这个死循

  • go性能分析工具pprof的用途及使用详解

    目录 pprof的用途 利用runtime/pprof包实现cpu分析的步骤 利用runtime/pprof包实现内存分析的步骤: 利用net/http/pprof包进行性能分析 总结 pprof的用途 CPU Profiling:CPU 分析,按照一定的频率采集所监听的应用程序 CPU(含寄存器)的使用情况,可确定应用程序在主动消耗CPU 周期时花费时间的位置 Memory Profiling:内存分析,在应用程序进行堆分配时记录堆栈跟踪,用于监视当前和历史内存使用情况,以及检查内存泄漏 Bl

  • .NET Visual Studio 代码性能分析工具

    下面通过图文并茂的方式给大家介绍下,具体内容如下: 软件开发中的性能优化对程序员来说是一个非常重要的问题.一个小问题可能成为一个大的系统的瓶颈.但是对于程序员来说,通过自身去优化代码是十分困难的.幸运的是,有一些非常棒的工具可以帮助程序员进行代码分析和性能测试,从而大大简化程序员进行代码性能优化的过程.MSDN杂志2011年7月份曾发布主题为".NET代码分析工具和技术"的那一期,让广大程序员收获颇丰.四年过去之后,这些工具又进一步做出了很多改进,同时也出现了更多的选择.本文对当前主流

  • Python性能分析工具Profile使用实例

    这篇文章主要介绍了Python性能分析工具Profile使用实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码优化的前提是需要了解性能瓶颈在什么地方,程序运行的主要时间是消耗在哪里,对于比较复杂的代码可以借助一些工具来定位,python 内置了丰富的性能分析工具,如 profile,cProfile 与 hotshot 等.其中 Profiler 是 python 自带的一组程序,能够描述程序运行时候的性能,并提供各种统计帮助用户定位程序

  • Python性能分析工具py-spy原理用法解析

    Py-Spy介绍 引用官方的介绍: Py-Spy是Python程序的抽样分析器. 它允许您可视化查看Python程序在哪些地方花了更多时间,整个监控方式无需重新启动程序或以任何方式修改工程代码. Py-Spy的开销非常低:它是用Rust编写的,速度与编译的Python程序不在同一个进程中运行. 这意味着Py-Spy可以安全地用于生成生产环境中的Python应用调优分析. github:https://github.com/benfred/py-spy 安装 pip install py-spy

  • Python性能分析工具pyinstrument提高代码效率

    目录 安装 简单的使用 分析 Flask 代码 分析 Django 代码 分析异步代码 工作原理 最后的话 天下武功,唯快不破. 编程也不例外,你的代码跑的快,你能快速找出代码慢的原因,你的码功就高. 安装 pip install pyinstrument 简单的使用 在程序的开始,启动 pyinstrument 的 Profiler,结束时关闭 Profiler 并打印分析结果如下: from pyinstrument import Profiler profiler = Profiler()

  • .NET  Visual Studio 代码性能分析工具

    下面通过图文并茂的方式给大家介绍下,具体内容如下: 软件开发中的性能优化对程序员来说是一个非常重要的问题.一个小问题可能成为一个大的系统的瓶颈.但是对于程序员来说,通过自身去优化代码是十分困难的.幸运的是,有一些非常棒的工具可以帮助程序员进行代码分析和性能测试,从而大大简化程序员进行代码性能优化的过程.MSDN杂志2011年7月份曾发布主题为".NET代码分析工具和技术"的那一期,让广大程序员收获颇丰.四年过去之后,这些工具又进一步做出了很多改进,同时也出现了更多的选择.本文对当前主流

  • PHP调试及性能分析工具Xdebug详解

    程序开发过程中,一般用得最多的调试方法就是用echo.print_r().var_dump().printf()等将语句打印出来.对PHP脚本的执行效率,通常是脚本执行时间.对数据库SQL的效率,通常是数据库Query时间,但这样并不能真正定位和分析脚本执行和数据库查询的瓶颈所在?对此,有一个叫Xdebug(www.xdebug.org)的PHP程序调试器(即一个Debug工具),可以用来跟踪,调试和分析PHP程序的运行状况. 一.以windows平台对此模块的安装做简单的介绍: 1. 下载PH

  • php轻量级的性能分析工具xhprof的安装使用

    一.前言 有用的东西还是记录下来吧,也方便以后的查询:这次记录一下xhprof的安装使用: xhprof是facebook开源出来的一个php轻量级的性能分析工具,跟Xdebug类似,但性能开销更低, 还可以用在生产环境中,也可以由程序开 关来控制是否进行profile. 二.安装 wget http://pecl.php.net/get/xhprof-0.9.3.tgz tar zxf xhprof-0.9.3.tgz cd xhprof-0.9.3/extension /usr/bin/ph

  • PHP性能分析工具XHProf安装使用教程

    HProf是facebook开源出来的一个php轻量级的性能分析工具,跟Xdebug类似,但性能开销更低,还可以用在生产环境中,也可以由程序开关来控制是否进行profile.基于浏览 器的性能分析用户界面能更容易查看,或是与同行们分享成果.也能绘制调用关系图.在数据收集阶段,它记录调用次数的追踪和包容性的指标弧在动态callgraph的一个程序. 它独有的数据计算的报告/后处理阶段.在数据收集时,XHProfd通过检测循环来处理递归的函数调用,并通过给递归调用中每个深度的调用一个有用的命名来避开

随机推荐