来自Go Profiler的混淆(和不正确的?)输出

时间:2012-10-08 03:15:19

标签: profiling go

我有一个我试图描述的Go二进制文件,我得到了令人惊讶的结果。代码在main.go中包含以下内容(已截断),其余代码位于包monte中:

package main

import (
  "monte"
  "runtime/pprof"
)

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(err)
    }
    pprof.StartCPUProfile(f)
  }

  monte.ExpensiveOperation()

  pprof.StopCPUProfile()
}

我使用go build src/main.go构建可执行文件,然后使用./main -cpuprofile=monte.prof运行它。当我用go tool pprof main monte.prof检查输出时,我得到以下输出:

(pprof) top10 --cum
Total: 346 samples
     280  80.9%  80.9%      343  99.1% time.Time.Format
       0   0.0%  80.9%      341  98.6% runtime.interhash
       0   0.0%  80.9%      341  98.6% runtime.main
       0   0.0%  80.9%      251  72.5% strconv.Unquote
      13   3.8%  84.7%       31   9.0% strconv.roundShortest
      11   3.2%  87.9%       18   5.2% strconv.fmtE
       9   2.6%  90.5%        9   2.6% runtime.markallocated
       1   0.3%  90.8%        8   2.3% math/rand.Float64
       2   0.6%  91.3%        8   2.3% runtime.FixAlloc_Free
       7   2.0%  93.4%        8   2.3% time.nextStdChunk

累积时间最长的函数是time.Time.Format,这对我来说似乎不对(不应该是main?)而且根本没有提到monte,尽管事实上,“昂贵的操作”需要大约10秒才能完成,采样者有足够的时间看到它。如果我将--focus=monte标记传递给go tool pprof,则根本不显示任何样本。我想我在某个地方错过了一些旗帜;有没有人有任何想法?谢谢!

2 个答案:

答案 0 :(得分:2)

您的main软件包无法编译,您也没有为monte软件包提供源代码。因此,我们无法重现您的结果。这是调试的第一步。

这是一些有效的源代码和结果。

package monte

func ExpensiveOperation() {
    var t float64
    for i := int64(0); i < 1e10; i++ {
        t += 1
    }
}

package main

import (
    "flag"
    "log"
    "monte"
    "os"
    "runtime/pprof"
)

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(err)
        }
        pprof.StartCPUProfile(f)
    }

    monte.ExpensiveOperation()

    pprof.StopCPUProfile()
}

(pprof) top10 --cum
Total: 1166 samples
       0   0.0%   0.0%     1166 100.0% main.main
    1166 100.0% 100.0%     1166 100.0% monte.ExpensiveOperation
       0   0.0% 100.0%     1166 100.0% runtime.main
       0   0.0% 100.0%     1166 100.0% schedunlock

更新:

github.com/haldean/monte处的代码未提供有意义的结果。它只需要时间0m0.506s,只需要48个样本。

(pprof) top10 --cum
Total: 48 samples
       0   0.0%   0.0%       45  93.8% main.main
       0   0.0%   0.0%       45  93.8% monte.(*Scene).Evaluate
       0   0.0%   0.0%       45  93.8% monte.(*Scene).Render
       0   0.0%   0.0%       45  93.8% monte.(*Scene).SetColor
       0   0.0%   0.0%       45  93.8% runtime.main
       0   0.0%   0.0%       45  93.8% schedunlock
       0   0.0%   0.0%       44  91.7% monte.(*Scene).RayCast
       4   8.3%   8.3%       31  64.6% runtime.new
      13  27.1%  35.4%       27  56.2% runtime.mallocgc
       3   6.2%  41.7%       26  54.2% monte.(*Scene).DirectionAt

答案 1 :(得分:1)

它看起来像一个仅限CPU的探查器,所以如果你的ExpensiveOperation通过I / O或睡眠或类似的东西花费时间,它将是不可见的。 (这是“cpu”分析器的问题。)

就数字的含义而言,总共有346个样本。 根据探查器的工作原理,这些数字有点软弱并不太令人惊讶,但如果它是真正的堆栈采样器,数字就意味着:

341/346个样本在堆栈上有maininterhash。你会期望所有样本在堆栈上都有主要内容,但那是软弱的部分。

343/346个样本在堆栈上有Format。 (为什么除了main之外还有更多的人,谁知道呢?)

251/346个样本在堆栈上有Unquote。在这251个样本中,它们也可能在堆栈上有maininterhashFormat

通过这种侦探工作,你可以慢慢地开始拼凑样本告诉你的内容。

当然,如果您真的可以看到堆栈样本,那么在您知道正好正在发生什么之前,您不必看到很多样本。

More about all that.