I'm following this tutorial on Go profiling and did as advised:
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
I then started my code with the flag -cpuprofile=myprogram.prof
and the file got created. Then I started the pprof tool
with
go tool pprof myprogram myprogram.prof
Well, myprogram
reads a big json file and maps it to a big map[string]string, so there is a lot going on in my program, but when I do like top10
in pprof
, I get:
Entering interactive mode (type "help" for commands)
(pprof) top10
profile is empty
Most probably your code is executing too fast, even if you think it's doing a lot. Happened to me several times.
You can play with changing the sampling rate via runtime.SetCPUProfileRate. - set it to the value above default 100, unit is Hz. Please note the Go authors don't recommend values above 500 - see explanation.
Do it just before pprof.StartCPUProfile
. You will also see the warning runtime: cannot set cpu profile rate until previous profile has finished
- please see this answer for explanation.
HTH
For profiling go programs you can use pprof as a web server. You need to add a bit of code to your main file of your go program/application to start the pprof server which will continuously serve the resource usage details for your program on the server and you can easily get all the relevant details. If you follow the code below the you can see the details of your program on your browser at http://localhost:6060/debug/pprof/ (Need to refresh the page to see the updated data)
You may see the code snippet below or go to the following link for the complete code: 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()
}
}()
Hope it helps!
If you use ctrl-c to stop the program, make sure you pass in profile.NoShutdownHook param in profile.Start().
Most probably you are not handling the System Interrupt signal. You should explicitly handle it in order for "pprof.StopCPUProfile()" to write the profile data successfully, otherwise, the program exits to fast when exited with "ctrl+c". Here is an example solution:
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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With