Go 程序的性能调试问题 - CPU 篇

注:本文的原文 Debugging performance issues in Go programsDmitry Vyukov 在 05/10/2014 - 07:06 编写
注:原文太长,你们要看所有的请看原文,其余的部分,后续慢慢翻译。php

让咱们假设你想提高你的GO程序的性能。这里有一些工具能够帮助你完成这个任务。这些工具能帮助你定位多种类型的热点(CPU,IO,内存),你为了可以显著提高程序性能,你必须专一于热点发生的地方。尽管如此,另一个结果是可能的--这些工具能帮助你肯定程序中明显的性能缺陷。例如,当你在每一个程序启动的时候,你能够在每次查询的以前准备一个 SQL 语句。另一个例子是若是一个 O(N^2) 算法在某种程度上陷入了一个明显存在而且指望的 O(N) 状况。为了肯定这样的状况,你须要完整性的检查你在 profiles 中看到的。例如第一种状况下大量的时间花费在 SQL 语句的准备上,这已经超越了告警线了。html

一样重要的是要理解性能影响的各类边界因素。例如,一个程序经过 100 Mbps 的带宽链接通信,而且它已经使用超过 90 Mbps,这里就没有什么能够对这程序作的来提高它的性能了。这些相似的边界因素包括 磁盘 IO,内存消耗和计算任务。golang

考虑到这一点,咱们能够查看这些可用的工具。web

注意:这些工具可能相互干扰,例如,精确的内存分析可能影响CPU分析。goroutine 阻塞分析可能影响调度追踪等等,隔离地使用这些工具以便获得更加精确的信息。算法

注意:这里全部的描述都是基于 Go1.3 版本的windows

CPU 分析器

Go runtime 包含了内建的 CPU 分析器,这显示了函数消耗的 CPU 时间百分比,这里你有3种方式访问它:服务器

  1. 最简单的一个方式是使用 go test 命令的 -cpuprofile 标记。例如,以下命令:
    $ go test -run=none -bench=ClientServerParallel4 -cpuprofile=cprof net/http
    将配置给出的基准和 CPU 的概要分析写入 cprof 文件。
    而后:
    $ go tool pprof --text http.test cprof
    将打印一份热点函数列表。
    这有几个可用的输出类型,最有用的几个为: --text,--web 和 --list 。运行 go tool pprof 来获得最完整的列表。
    这个选项最明显的特色就是它只适用于测试。
  2. net/http/pprof 包。这是网络服务的理想解决方案。你仅仅只须要 import net/http/pprof 而且用以下命令收集概要文件:
$ go tool pprof --text mybin http://myserver:6060:/debug/pprof/profile
  1. 手工配置收集。你须要 import runtime/pprof 而且 把以下代码加入 main 函数中:
if *flagCpuprofile != "" {
    f, err := os.Create(*flagCpuprofile)
    if err != nil {
        log.Fatal(err)
    }
    pprof.StartCPUProfile(f)
    defer pprof.StopCPUProfile()
}

这份概要文件会被写入指定的文件中,想象它和第一个选项同样的命令行方式。网络

这里是一个使用 --web 选项产生的直观的概要文件示例:
此处输入图片的描述app

你可使用 -list=funcname 选项来研究单个函数,下面的 概要文件显示了在 append 函数中所花费的时间:svg

.      .   93: func (bp *buffer) WriteRune(r rune) error {
.      .   94:     if r < utf8.RuneSelf {
5      5   95:         *bp = append(*bp, byte(r))
.      .   96:         return nil
.      .   97:     }
.      .   98: 
.      .   99:     b := *bp
.      .  100:     n := len(b)
.      .  101:     for n+utf8.UTFMax > cap(b) {
.      .  102:         b = append(b, 0)
.      .  103:     }
.      .  104:     w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r)
.      .  105:     *bp = b[:n+w]
.      .  106:     return nil
.      .  107: }

你能够在这里找到 pprof 工具的详细信息和描述的数字图。

当它不能解锁堆栈的时候,这里有关于分析器使用的3条特别条目:GC, System and ExternalCode。GC 表示内存垃圾回收的时间花费,见下面的内存分析器和垃圾收集器跟踪优化建议部分。System 表示 goroutine 调度花费的时间,堆栈管理代码以及其余辅助的 runtime 代码。ExternalCode 表示本地动态库花费的时间。

这里有些提示关于如何解释说明你在 profile 中看到的信息。

若是不少时间花费在 runtime.mallocgc 函数,程序可能在小内存分配上面花费过多。 profile 会告诉你分配从哪里来,看内存分析器建议如何优化的部分。

若是不少时间花费在 channel 操做部分,sync.Mutex 代码和其余 synchronization primitives或者是系统组件,程序可能在承受资源竞争。考虑重构程序,以消除对共享资源的频繁访问。常见的技术包括分片、分区,本地缓冲/批量处理和写时拷贝技术。

若是不少时间花费在 syscall.Read/Write 上面,程序可能在小读写上面花费代价太大。Bufio 包装 os.File 或是 net.Conn 能对这种状况有帮助。

若是不少时间花费在 GC 组件上面,程序不是分配了太多的临时对象就是 heap size 设置太小致使垃圾回收频繁发生。请看垃圾收集器跟踪和内存分析器优化建议部分。

注意: CPU profiler 目前不能在 darwin 上工做
注意: 在 windows 服务器上你须要安装 Cygwin, Perl and Graphviz 来生成 svg/web 格式的概要文件
注意: 在 Linux 上你能够尝试 perf system profiler,它不能解锁 GO 的堆栈,可是它能分析而且解锁 cgo/SWIG 代码和内核。因此它在定位分析本地/内核性能瓶颈上很是有用。

相关文章
相关标签/搜索