我在关于Go分析的this tutorial之后,按照建议行事:
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
然后我用标志-cpuprofile=myprogram.prof
启动了我的代码并创建了文件。然后我用
pprof tool
go tool pprof myprogram myprogram.prof
好吧,myprogram
读取一个大的json文件并将其映射到一个大的map [string]字符串,所以我的程序中有很多内容,但是当我喜欢top10
时{ {1}},我明白了:
pprof
答案 0 :(得分:0)
很可能你的代码执行得太快了,即使你认为它做得很多。好几次发生在我身上。
您可以通过runtime.SetCPUProfileRate更改采样率。 - 将其设置为默认值100以上的值,单位为Hz。请注意,Go作者不建议高于500的值 - see explanation。
在pprof.StartCPUProfile
之前完成。您还会看到警告runtime: cannot set cpu profile rate until previous profile has finished
- 请参阅this answer以获取解释。
HTH
答案 1 :(得分:0)
您是否处理了ctrl-c信号? 如果还没有,程序将被OS停止。您必须确保程序正常退出,然后配置文件才会写入文件。 您还可以检查netprof模块。
答案 2 :(得分:0)
对于配置go程序,您可以将pprof用作Web服务器。您需要在go程序/应用程序的主文件中添加一些代码以启动pprof服务器,该服务器将不断在服务器上为您的程序提供资源使用详细信息,并且您可以轻松获取所有相关详细信息。如果您遵循下面的代码,则可以在浏览器上的 http://localhost:6060/debug/pprof/ 上查看程序的详细信息。 (需要刷新页面以查看更新的数据)
您可能会在下面看到代码片段,或转到以下链接以获取完整的代码: github.com/arbaaz-khan/GoLangLearning/blob/master/ProfilingGoProgram/profile_go_prog.go
go func() {
log.Printf("Starting Server! \t Go to http://localhost:6060/debug/pprof/\n")
err := http.ListenAndServe("localhost:6060", nil)
if err != nil {
log.Printf("Failed to start the server! Error: %v", err)
wg.Done()
}
}()
希望有帮助!
答案 3 :(得分:0)
如果使用ctrl-c停止程序,请确保在profile.Start()中传入profile.NoShutdownHook参数。
答案 4 :(得分:0)
很可能您没有处理系统中断信号。您应该显式处理它,以便“ pprof.StopCPUProfile()”成功写入配置文件数据,否则,当使用“ ctrl + c”退出时,程序将快速退出。 这是一个示例解决方案:
var f *os.File
func main() {
flag.Parse()
if *cpuProfile != "" {
cpuProfileFile, err := os.Create(*cpuProfile)
if err != nil {
log.Fatal(err)
}
defer f.Close()
pprof.StartCPUProfile(cpuProfileFile)
}
c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM) // subscribe to system signals
onKill := func(c chan os.Signal) {
select {
case <-c:
defer f.Close()
defer pprof.StopCPUProfile()
defer os.Exit(0)
}
// try to handle os interrupt(signal terminated)
go onKill(c)
}
答案 5 :(得分:0)
对我来说,问题在于我的代码执行得太快。我所做的是使用runtime.SetCPUProfileRate更改采样率。请注意,在runtime.pprof.StartCPUProfile中,采样率为100 Hz,建议最大为500 Hz。
func StartCPUProfile(w io.Writer) error {
// The runtime routines allow a variable profiling rate,
// but in practice operating systems cannot trigger signals
// at more than about 500 Hz, and our processing of the
// signal is not cheap (mostly getting the stack trace).
// 100 Hz is a reasonable choice: it is frequent enough to
// produce useful data, rare enough not to bog down the
// system, and a nice round number to make it easy to
// convert sample counts to seconds. Instead of requiring
// each client to specify the frequency, we hard code it.
const hz = 100
cpu.Lock()
defer cpu.Unlock()
if cpu.done == nil {
cpu.done = make(chan bool)
}
// Double-check.
if cpu.profiling {
return fmt.Errorf("cpu profiling already in use")
}
cpu.profiling = true
runtime.SetCPUProfileRate(hz)
go profileWriter(w)
return nil
}
但是在我的情况下,将其设置为500 Hz的速度还不够快。查看runtime.SetCPUProfileRate的代码后,似乎可以提供高达1000000 Hz的频率。将其设置为足够大的值后,它解决了我的问题。
// SetCPUProfileRate sets the CPU profiling rate to hz samples per second.
// If hz <= 0, SetCPUProfileRate turns off profiling.
// If the profiler is on, the rate cannot be changed without first turning it off.
//
// Most clients should use the runtime/pprof package or
// the testing package's -test.cpuprofile flag instead of calling
// SetCPUProfileRate directly.
func SetCPUProfileRate(hz int) {
// Clamp hz to something reasonable.
if hz < 0 {
hz = 0
}
if hz > 1000000 {
hz = 1000000
}
lock(&cpuprof.lock)
if hz > 0 {
if cpuprof.on || cpuprof.log != nil {
print("runtime: cannot set cpu profile rate until previous profile has finished.\n")
unlock(&cpuprof.lock)
return
}
cpuprof.on = true
cpuprof.log = newProfBuf(1, 1<<17, 1<<14)
hdr := [1]uint64{uint64(hz)}
cpuprof.log.write(nil, nanotime(), hdr[:], nil)
setcpuprofilerate(int32(hz))
} else if cpuprof.on {
setcpuprofilerate(0)
cpuprof.on = false
cpuprof.addExtra()
cpuprof.log.close()
}
unlock(&cpuprof.lock)
}