Skip to content

Package for simplifying runtime profiling and tracing in golang

License

Notifications You must be signed in to change notification settings

symonk/profiler

Repository files navigation

Profiler

profiler is an abstraction layer around the golang profiling stdlib, namely runtime/pprof and runtime/trace to simplify and make profiling configuration easy and fast. It offers an assortment of options and configurations as well as various non stdlib options such as the fgprof wall clock option, which pieces together a single .pprof file which includes both cpu ON and OFF data. A basic example for each of the profilers is outlined below.

By default profiler will listen for SIGTERM & SIGINT in order to close out the pprof/trace files correctly, however in some cases this is undesirable. If you would like full control of cleaning up then use the WithoutSignalHandling() functional option to any invocation of .Start().


1️⃣ CPU Profiling

Profiling CPU can help identify areas of your code where most CPU cycle execution time is spent. For programs with a lot of IO wait etc, the graph may not be extremely useful, trace may be of better benefit there.

import (
    "github.com/symonk/profiler"
)

func main() {
    defer profiler.Start(profiler.WithCPUProfiler()).Stop()
    /* your code here */
}

2️⃣ Heap Profiling

Heap profiling reports memory allocation samples, useful for monitoring current and historical memory usage and to check for potential memory leaks in your program. Heap profiling tracks the allocation sites for all live objects in the application memory and for all objects allocated since the program has started. By default heap profiling will display live objects, scaled by size.

package main

import (
    "github.com/symonk/profiler"
)

func main() {
    // additional options available here are: `profiler.WithMemoryProfileRate(...)`
    defer profiler.Start(profiler.WithHeapProfiler()).Stop()
    /* your code here */
}

3️⃣ Alloc Profiling

Alloc profiling is essentially the same as heap profiling except rather than the default of live objects scaled by size, it reports the -alloc_space data, that is the total number of bytes allocated since the program has began (including garbage collected bytes).

package main

import (
    "github.com/symonk/profiler"
)

func main() {
    // additional options available here are: `profiler.WithMemoryProfileRate(...)`
    defer profiler.Start(profiler.WithAllocProfiler()).Stop()
    /* your code here */
}

4️⃣ Block Profiling

Block profiling captures how long a program spends off CPU blocked by either a mutex or a channel operation. The following events are recorded:

  • select operations
  • channel send operations
  • channel receive operations
  • semacquire operations (sync -> Mutex.Lock(), sync -> RWMutex.RLock(), sync -> RWMutex.Lock(), sync -> WaitGroup.Wait())
  • notify list operations (sync -> Conf.Wait())

Caution

Block profiles do not include time in sleep, IO wait etc and block events are only recorded when the block has cleared, as such they are not appropriate to see why a program is currently hanging.

package main

import (
    "github.com/symonk/profiler"    
)

func main() {
    defer profiler.Start(profiler.WithBlockProfiler()).Stop()
    /* your code here */
}

5️⃣ Thread Profiling

Thread profiling shows stack traces of code that caused new OS level threads to be created by the go scheduler. This is implemented in this library but it has been broken since 2013. Should it be fixed in future or if you wish to use it now, consider it experimental.

Caution

This has been broken since 2013, do not use it!

package main

import (
    "github.com/symonk/profiler"
)

func main() {
    defer profiler.Start(profiler.WithThreadProfiler()).Stop()
    /* your code here */
}

6️⃣ Goroutine Profiling

The go runtime keeps track of all goroutines internally in a slice. This tracks both active and dead goroutines (dead goros are reused later if requested). Active goroutines are routines waiting on io, blocking or executing. Profiling goroutines causes a 'stop-the-world' event which is o(n) depending on how many goroutines you have so caution is advised when profiling goroutines at scale in production.

package main

import (
    "github.com/symonk/profiler"
)

func main() {
    defer profiler.Start(profiler.WithGoroutineProfiler()).Stop()
    /* your code here */
}

7️⃣ Mutex Profiling

Mutex profiling differs from block profiling in the sense that block profiling records how long a goroutine took to acquire a .Lock() but the mutex profile tracks how long a goroutine was waiting for an .Unlock(). Contention is not recorded until the mutexes are unlocked, so again this is not viable for checking why a program is currently hanging/blocking 'now'.

package main

import (
    "github.com/symonk/profiler"
)

func main() {
    defer profiler.Start(profiler.WithMutexProfiler()).Stop()
    /* your code here */
}

8️⃣ Clock Profiling

Clock profiling allows monitoring of both off and on CPU time collectively, this paints a nice picture of where CPU cycles are spent, but also where IO perhaps is causing delays too.

package main

import (
    "github.com/symonk/profiler"
)

func main() {
    defer profiler.Start(profiler.WithClockProfiling()).Stop()
    /* your code here */
}

Available Options

  • WithAllocProfiler => Enables allocation (memory) profiling.
  • WithBlockProfiler => Enables block profiling.
  • WithCPUProfiler => Enables CPU profiling (default).
  • WithCallback => User defined callback that has the profiler in scope, invoked after teardown.
  • WithClockProfiling => Enables CPU on & off profiling (non stdlib).
  • WithHeapProfiler => Enables heap (memory) profiling.
  • WithMemoryProfilingRate => Sets the profiling rate for memory related profiling samples.
  • WithMutexFraction => Sets the fraction rate used in conjunction with mutex profiling.
  • WithProfileFileLocation => Sets the custom folder location for the pprof / trace files.
  • WithQuietOutput => Suppresses writing to stdout/printing.
  • WithRealTimeData => Spins a http server for the lifetime of the profiling for real curl/fetching if desired.
  • WithThreadProfiler => Enables the os thread creation profiling.
  • WithTracing => Enables the tracing.
  • WithoutSignalHandling => Prevents the profiler tool signal handling, allow more fine grained user control.

About

Package for simplifying runtime profiling and tracing in golang

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages