Skip to content

Latest commit

 

History

History
153 lines (117 loc) · 5.1 KB

README.md

File metadata and controls

153 lines (117 loc) · 5.1 KB

How to profile in Go.

This discusses a few go profiling mechanisms and when and where to use each. Which tool you use depends heavily on if the code is local or on a deployed system. Also, it depends on when you need access to the profiles that are generated.

Go profiling basics

Go provides some very useful diagnostic documentation for profiling, tracing, and debugging go code. There are many links off of this documentation that describes how to use the pprof tool.

Here is a great gophercon video from Dave Cheney on profiling that I highly recommend watching. Also, here is a workshop from Dave Cheney that is also excellent.

Another useful link is from DataDog, just know they point out limitations is the hope of selling something.

Lastly, another good link here

Types of profiles

  • CPU Profiler

  • Memory Profiler

  • Block Profiler

  • Mutex Profiler

  • Goroutine Profiler

  • Trace Profiler

Go profiling from unit tests

It is sometimes useful to profile using unit tests. The easiest way to do this is to create a benchmark test. The function should have the signature func BenchmarkXXXXX(b *testing.B). Here are some examples of usage.

There are several testing flags that can help generate the correct profiles needed to pass to the pprof tool.

You can also run like so:

  • go test -cpuprofile cpu.pprof
  • go test -memprofile mem.pprof
  • go test -blockprofile block.pprof
  • go test -mutexprofile mutex.pprof
  • go test -trace trace.out
  • go test -race

Profiling in a standalone program

As mentioned in the pprof documentation, you can embed the creating of profiles into your code. An example can be seen here.

Exposed profiles

Here is a list of profiles in pprof

	profiles.m = map[string]*Profile{
		"goroutine":    goroutineProfile,
		"threadcreate": threadcreateProfile,
		"heap":         heapProfile,
		"allocs":       allocsProfile,
		"block":        blockProfile,
		"mutex":        mutexProfile,
	}

pprof.StartCPUProfile

    import "runtime/pprof"

	f, err := os.Create(*cpuprofile)
	if err != nil {
		log.Fatal("could not create CPU profile: ", err)
	}
	defer f.Close() // error handling omitted for example
	if err := pprof.StartCPUProfile(f); err != nil {
		log.Fatal("could not start CPU profile: ", err)
	}
	defer pprof.StopCPUProfile()

Then run: go tool pprof -http=:8080 cpu.prof

pprof.WriteHeapProfile

    import "runtime/pprof"

	f, err := os.Create(*memprofile)
	if err != nil {
		log.Fatal("could not create memory profile: ", err)
	}
	defer f.Close() // error handling omitted for example
	runtime.GC()    // get up-to-date statistics
	if err := pprof.WriteHeapProfile(f); err != nil {
		log.Fatal("could not write memory profile: ", err)
	}

Then run: go tool pprof -http=:8080 mem.prof

pprof.Lookup("block")

	runtime.SetBlockProfileRate(100000000) // WARNING: Can cause some CPU overhead
	f, err := os.Create(*blockprofile)
	if err != nil {
		log.Fatal("could not create block profile: ", err)
	}
	defer f.Close() // error handling omitted for example
	defer pprof.Lookup("block").WriteTo(f, 0)

Then run: go tool pprof -http=:8080 block.prof

pprof.Lookup("mutex")

    import "runtime/pprof"

	runtime.SetMutexProfileFraction(100)
	f, err := os.Create(*mutexprofile)
	if err != nil {
		log.Fatal("could not create mutex profile: ", err)
	}
	defer pprof.Lookup("mutex").WriteTo(f, 0)

Then run: go tool pprof -http=:8080 mutex.prof

pprof.Lookup("goroutine")

	pprof.Lookup("goroutine")
	f, err := os.Create(*goroutineprofile)
	if err != nil {
		log.Fatal("could not create goroutine profile: ", err)
	}
	defer pprof.Lookup("goroutine").WriteTo(f, 0)

Then run: go tool pprof -http=:8080 goroutine.prof

trace.Start

    import "runtime/trace"

	traceFile, err := os.Create(*traceprofile)
	if err != nil {
		panic(err)
	}
	defer traceFile.Close()

	if err := trace.Start(traceFile); err != nil {
		panic(err)
	}
	defer trace.Stop()

Then run: go tool trace trace.prof

Profiling with a REST handler

You can also enable a REST handler using http pprof to make calls into a running program. There is an example here

Profiling with GoLand

If you have access to GoLand and can simulate the issues locally, you can check out article. There is also a slightly older article that might provide some more information.