Saturday, May 28, 2016

Visualizing profiling in Go: A different way

Many of you will read these lines and know already a bit about how Go can help you out and profile your applications. If not, you can have a quick look at this article Profiling Go Programs from the Go blog. As a testimony to the language, this article predates the Go 1.0 release by almost a year yet it still works today, 4 years after the initial launch of Go. In the next years it will be able to go to school and make friends. But I digress.

So, profiling in Go is a joy and Go already gives you nice tools to visualize the information. Can we do better? For example some folks at Uber thinks so and they've built https://github.com/uber/go-torch They also have a wonderful presentation about it, check it out here: Profiling and Optimizing Go . But they've built it. Could we use something that exists already?

The answer is Yes! Of course we can. Because it's Go, and it's amazing, we can use KCacheGrind (and it's cousins) to visualize callgrind profiles, not to mention get a nice visualization while at it.

To give you a quick example:
  • first profile your code and save the profile as profile
  • then run go tool pprof -callgrind -output=profile.grind binaryName profile
  • the launch KCacheGrind and open profile.grind

And to give an example of how this looks like for an application, here are a few screenshots. Thank you to Olivier Gagnon for offering his code for this post.

The code below assumes Linux (Ubuntu specifically but you should be able to get it running on other platforms as well):

// First lets install the dependencies
sudo apt-get install libxrandr-dev libxcursor-dev libxinerama-dev libxi-dev

// Fetch the source code
go get github.com/hydroflame/lux_dev_env


cd $GOPATH/src/github.com/hydroflame/lux_dev_env

// In the import () section add:
"os"
"runtime/pprof"

// Right after main() { opens, add:
    f, err := os.Create("./profile")
    if err != nil {
        log.Fatal(err)
    }
    pprof.StartCPUProfile(f)
    defer pprof.StopCPUProfile()

// Build the application
go build -o engine main_dev.go

// And run it
./engine

// Wait at least a few seconds and then press Esc to quit it

// Get the profile in callgrind format
go tool pprof -callgrind -output=profile.grind engine profile

// Finally run KCacheGrind
kcachegrind profile.grind







Note, at the time of writing the code was in flux so I had to change this:

@@ -160,8 +169,8 @@ func main() {

gravity := glm.Vec3{0, -5, 0}
gravFG := tornago.NewGravityForceGenerator(&gravity)
- w.AddForceGenerator(boxBody, &gravFG)
- w.AddForceGenerator(boxBody2, &gravFG)
+ w.AddForceGenerator(boxBody, gravFG)
+ w.AddForceGenerator(boxBody2, gravFG)

_ = str
w.AddConstraint(str)


Thank you.