我有一个我试图描述的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
,则根本不显示任何样本。我想我在某个地方错过了一些旗帜;有没有人有任何想法?谢谢!
答案 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个样本在堆栈上有main
和interhash
。你会期望所有样本在堆栈上都有主要内容,但那是软弱的部分。
343/346个样本在堆栈上有Format
。 (为什么除了main
之外还有更多的人,谁知道呢?)
251/346个样本在堆栈上有Unquote
。在这251个样本中,它们也可能在堆栈上有main
,interhash
和Format
。
通过这种侦探工作,你可以慢慢地开始拼凑样本告诉你的内容。
当然,如果您真的可以看到堆栈样本,那么在您知道正好正在发生什么之前,您不必看到很多样本。