I am going to talk about golang profiling in this article.

All you need to do to profile your code performance is to import “net/http/pprof” package and add the line http.ListenAndServe(“:8081”, nil) if your application is based on http.

Here’s the test code which is an implementation of Finding the Max Subarry algorithm by using divide-and-conquer paradigm:

divcon-debug0

divcon-1

divcon-2

First things first, the go tool pprof command will be used to profile.

$> go tool pprof  http://localhost:8081/debug/pprof/profile

go-tool-pprof-httpaddr

Here, we can view the CPU usage through top command of pprof, and we can generate pdf or svg by using command pdf or svg.

pdf:

go-tool-pprof-pdf

svg:

go-tool-pprof-svg-0

go-tool-pprof-svg

Request the address below to get go routines information:

http://localhost:8081/debug/pprof/goroutine?debug=1

web-show-pprof-goroutine-debug

Except for these simple commands, you can go deeper. You can list the CPU time consuming of each function or by search specific function to view:

pprof-list

Find specific function and view the CPU time to consume. Here we search the function main.findMaxCrossingSubArray shows in the svg diagram:

svg-find-the-max-subarray

pprof-list-find

And show heap allocation and GC information:

pprof-heap

The above methods of go profiling are not very human-friendly, there’s a uber’s go-torch can show the graphic information of time-consuming of each function:

Use below command to generate profile info:

go-torch-seconds-httpaddr

Once the profile information collected, it will generate as SVG file:

uber-torch-flame-graph-svg

Open the SVG file:

uber-torch-flame-graph-svg

uber-torch-flame-graph-svg-performance-grapth

The x bar width longer, the time the function consumes more.

svg-flame-graph-go-torch-small

P.S: If you use custom routers, you need register those default RESTful API yourself:

func main() {
    r := http.NewServeMux()
    r.HandleFunc("/", hiHandler)
    // Register pprof handlers
    r.HandleFunc("/debug/pprof/", pprof.Index)
    r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
    r.HandleFunc("/debug/pprof/profile", pprof.Profile)
    r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
    r.HandleFunc("/debug/pprof/trace", pprof.Trace)

    http.ListenAndServe(":8080", r)
}

Or you just add the code block like below to serve on another port:

go func() {
    http.ListenAndServe(":8080", nil)
}()

Conclusion

I now know there are tools can tune your go code performance, especially the standard libraries the go language provides. We should improve our code performance use these tools out there day in day out, to find out what code block consume much CPU or memory. By using those tools the go language and thirty libs provide us can make us more professional and do our work efficiently.

Reference

https://blog.golang.org/profiling-go-programs

https://software.intel.com/en-us/blogs/2014/05/10/debugging-performance-issues-in-go-programs

https://medium.com/@hackintoshrao/daily-code-optimization-using-benchmarks-and-profiling-in-golang-gophercon-india-2016-talk-874c8b4dc3c5

http://artem.krylysov.com/blog/2017/03/13/profiling-and-optimizing-go-web-applications/