Sunday, July 29, 2012

Profiling Go with pprof under Windows

First post on a new blog! Ring the bell.
But no time for chitchat now... :)

So, I was trying to write some computationally intensive code in Go (gc 1.0.2 Win64) in the past few days and a couple of things about performance didn't seem quite right (more on this later).
Hence I looked into profiling options and found references to pprof and a nice article by Russ Cox about it. I eagerly dove into it, only to be quickly disappointed by an output that looked like this:

(pprof) top10
Total: 2113 samples
     298  14.1%  14.1%      298  14.1% 0000000000464d34
     179   8.5%  22.6%      179   8.5% 0000000000418e83
     157   7.4%  30.0%      157   7.4% 0000000000418e60
     112   5.3%  35.3%      112   5.3% 0000000000403293
     101   4.8%  40.1%      101   4.8% 0000000000464d4f
      83   3.9%  44.0%       83   3.9% 000000000040329c
      77   3.6%  47.7%       77   3.6% 0000000000418e7a
      62   2.9%  50.6%       62   2.9% 0000000000456a38
      37   1.8%  52.3%       37   1.8% 0000000000418e41
      37   1.8%  54.1%       37   1.8% 0000000000435f57


No function names, only addresses. A quick Googling led to a couple of unsolved forum questions about the same problem, pointing at Windows as a common factor. Reluctant at the prospect of rebooting and moving my work over to Ubuntu I set out to see if pprof (a Perl script under Go\pkg\tool\[platform]) could be easily fixed.

Suprises suprise, it was.

Two issues were preventing the script from working under Windows:
  1. The use of /tmp for temp files. I used $ENV{'TEMP'} instead.
  2. Redirecting to /dev/null to test availability of external commands. Using the NUL file instead works under Win, in principle (if the command line options of those commands, such as nm, are the same). It turns out that's not quite enough, but adding one command ("$nm -n $image") to the list of candidates in the sub GetProcedureBoundaries does the trick.
Finally I was able to get some readable output:

(pprof) top
Total: 3361 samples
    1043  31.0%  31.0%     1043  31.0% main.For5
     333   9.9%  40.9%      333   9.9% CompareAndSwapUint32
     303   9.0%  50.0%      303   9.0% runtime.procyield
     252   7.5%  57.5%      252   7.5% runtime.casp
     166   4.9%  62.4%     1068  31.8% sync.(*Mutex).Lock
     124   3.7%  66.1%      124   3.7% runtime.atomicload
     113   3.4%  69.4%      113   3.4% runtime.xadd
     110   3.3%  72.7%      110   3.3% runtime.atomicloadp
     104   3.1%  75.8%      104   3.1% math/rand.Int63
      83   2.5%  78.3%       83   2.5% sync/atomic.AddUint32

Nice!

The fixes above are just enough to get the text output working. A couple more were needed for the web/graph visualisation.
A modified script can be found here.
A simple DIFF with the supplied version can reveal my changes.

If you're just getting started with Go, in order to get all this to work, you will need to:
  1. Install Perl (e.g. ActivePerl).
  2. Add [YourPerl]\bin to your system or user PATH variable.
  3. Add Go\bin to your system or user PATH variable.
  4. Add  Go\pkg\tool\[platform] to your system or user PATH variable.
  5. Under Windows, launch pprof with:
    > perl  [...]\Go\pkg\tool\[platform]\pprof_win.pl [executable] [profile]
  6. Optional: if you want the web option to work, install graphviz and add its bin folder to your system or user PATH variable.
Ignore the error messages about files not found, and everything should work from the Windows command prompt. You may also be able to use the version of pprof supplied with go with shells like cygwin, MinGW, or Gow.

Enjoy!

5 comments:

e.m. lazzarin said...

Thanks for this - you saved me at least a day's worth of tinkering.

I still get some strange complaints about:

The system cannot find the path specified.
usage: addr2line binary
reads addresses from standard input and writes two lines for each:
function name
file:line

But things seem to work as advertised. Let's hope the Go dev team irons these wrinkles out.

Mau said...

Good point, I forgot to mention to ignore the error messages :)

Kevin Lansard said...

I used the pprof_win.pl on

https://code.google.com/p/go/issues/detail?id=3879

and I still got the issue of "No function names, only addresses":
(pprof) top3
Total: 2 samples
1 50.0% 50.0% 1 50.0% 0000000000464987
1 50.0% 100.0% 1 50.0% 000000000048c0ec
0 0.0% 100.0% 2 100.0% 0000000000416e0f

Do you have an idea of where to investiguate next ?

Carl said...
This comment has been removed by the author.
Carl said...

Let's try this again...

On Windows 7, using go 1.1.2, pprof has been fixed.

In other words, the following command works:

go tool pprof path_to_executable path_to_profile_data

Make sure you use forward slashes in the path though.