Living Systems_

Profiling and creating call graphs for Go programs

In trying to get my head around the code of the very interesting GoFlow library, (for flow-based programming in Go), and the accompanying flow-based bioinformatics library I started hacking on, I needed to get some kind of visualization (like a call graph) … something like this:

Call graph

(And in the end, that is what I got … read on … ) :)

I then found out about the go tool pprof command, for which the Go team published a blog post on here .

Being a Go newbie, I must admit I had quite a hard time deciphering the blog post though. Maybe it was just a psychological barrier because of all the technological anechdotes, that made it look harder than it actually was. Anyhow, it didn’t help that go run pprof didn’t produce any output if I didn’t run processing on a large enough file that it would have time to collect data.

Anyways, with this in mind I wanted to make a slightly easier-to-follow instruction for newbies like me, on how to use go tool pprof for profiling and producing call graphs … but then after I published this post, Dave Cheney pinged me about his excellent profile package, which makes the process even easier, so I went away and updated the blog post to include how to do it both with the profile package, AND with the pprof library itself! :)

Ok, so enough blather, let’s get started:

Easy option: Profiling Go programs with the profile package

Easy option Overview: What you will do

Easy option Step 0: Install profile

If you have your GOROOT and GOPATH environment variables correctly setup, you should be able to install it with this simple command:

go get github.com/davecheney/profile

… otherwise you’ll have to install it manually from http://github.com/davecheney/profile

Easy option Step 1: Add a line of code, to produce a profile file

… the result should be something like:

func main() {
    defer profile.Start(profile.CPUProfile).Stop()

    // ... your main code here ...
}

Easy option Step 2: Build your program as usual

Something like:

go build [your program].go

Easy option, Step 3: Run your program long enough to get some profiling data

Easy option, Step 4: Copy the cpu.pprof file from /tmp/…

When running the program in the previous step, you will have seen some output like this:

2013/08/08 16:45:58 profile: cpu profiling enabled, /tmp/profile882806532/cpu.pprof

Copy this file to where you are standing right now, with:

cp /tmp/profile[some number]/cpu.pprof .

Read on from step 4 , for the rest of the steps …

Hard option: Using the pprof library directly

Hard option Overview: What you will do

Hard option Step 1: Add some code snippets to your code, to produce a profile file

import (
        ... your other imports ...
        "flag"
        "fmt"
        "runtime/pprof"
)

… the result should be something like:

// Profiling stuff ... from http://blog.golang.org/profiling-go-programs
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

func main() {
    flag.Parse()
    if *cpuprofile != "" {
        f, err := os.Create(*cpuprofile)
        if err != nil {
            fmt.Println("Error: ", err)
        }
        pprof.StartCPUProfile(f)
        defer pprof.StopCPUProfile()
    }

       // ... your main code here ...
}

This will add a command line flag -cpuprofile, which you can later use to specify a filename where to write the profiling data.

Hard option Step 2: Build your program as usual

Something like:

go build [your program].go

Hard option Step 3: Run your program long enough to get some profiling data

The rest (Same for easy and hard option!)

Step 4: Get some nice output from your profile data

Step 5: Enjoy your callgraph

Let’s see what that looks like:

Call graph

Not too bad, no? (Find the PDF version below as well)

Step 6: Try some other commands

Some other output you might want to do:

(Isn’t there a nicer way to get a paginated help screen?)

Step 7: Go back to the Go team blog post and learn the advanced options

Now, this might have been an easier start if you are a newbie, but then Dave Cheney’s post on profile, and the Go team blog post on runtime/pprof contains info on more advanced use of the pprof tool, so be sure to go back and study it: