As is commonly the case with Go, the usual library comes with an excellent instrument for profiling your applications – pprof. It samples your name stack, permitting you to later generate reviews that make it easier to analyze and visualize your software program’s efficiency with out putting in any plugins. Every part you want is within the Go growth equipment.
The issue? It’s a little bit of a problem. In our discussions with Go builders, we’ve heard that some truly keep away from it if they’ll. There might be a couple of causes for this. For a lot of builders, typical Go companies carry out properly sufficient with out optimizations, so once they do want to make use of profiling, it turns into a fancy “rescue mission” instrument they aren’t actually skilled with. For some, the difficulty isn’t profiling in itself, however slightly what to do with the outcomes. Since pprof simply reveals builders numerous low-level profiling knowledge, it’s on them to make sense of it and discover the foundation of the difficulty. On the opposite finish of the spectrum, there are those that follow steady profiling and use devoted instruments for it.
This text serves as a sensible information for these builders who would slightly keep away from coping with Go’s complicated profiling instruments. Profiling is extremely helpful – it helps you determine CPU bottlenecks, reminiscence points, and concurrency issues, all of which have an effect on each your and your customers’ expertise along with your product. So that can assist you make the most effective use of it, we’ll clarify a few of the major profiling varieties in Go (CPU, heap, allocs, mutex, block, and goroutine), in addition to tips on how to run and interpret them. And since you’re on the JetBrains weblog, we’ll additionally present you ways GoLand makes profiling as simple as urgent a single button. However first…
How does profiling work in Go?
Go profilers observe program efficiency by sampling the decision stack and extra knowledge at both common time intervals or upon particular runtime occasions, relying on the profile. They generate profile information that may then be analyzed utilizing instruments just like the pprof CLI or its net interface, so you possibly can see the place your program spends time and reminiscence. This helps you discover features that use pointless assets and decelerate this system, with out having to guess. For instance, Go’s diagnostic documentation recommends profiling to determine costly or continuously known as code paths.
Sorts of profiles in Go
As talked about within the intro, Go comes pre-equipped with a profiling instrument known as pprof, so that you don’t want any exterior libraries. There are various things you possibly can analyze with it, relying in your wants. The most well-liked profiles that we’ll be discussing on this article are:
- CPU: Samples the decision stack and tracks the place CPU time was spent.
- Reminiscence (allocs / heap): Tracks allocations (whole / at the moment in use) to point out you the place reminiscence is getting used.
- Block: Tracks blocking occasions, exhibiting you the place goroutines had been blocked.
- Mutex: Captures which goroutines blocked different goroutines, revealing lock rivalry.
- Goroutine: Takes snapshots of stack traces of goroutines to point out you what number of there are for the time being, and what they’re doing.
- Goroutine leak: Surfaces goroutines which can be confirmed to be completely blocked ready on synchronization primitives, corresponding to channels,
sync.Mutex, orsync.Cond.
It’s maybe price mentioning right here that Go additionally has the runtime/hint package deal – an execution tracer that information particular runtime occasions, capturing the timeline slightly than snapshots. runtime/hint won’t be coated on this article.
CPU
CPU profiling is commonly step one when diagnosing efficiency points in Go applications. It information the place your program spends CPU time by periodically sampling the stack of the goroutines which can be being executed.
It’s good for issues like discovering scorching paths in CPU-bound code (e.g. costly parsing, serialization, hashing, or tight loops), understanding why a benchmark is slower than anticipated below real looking load, investigating the foundation reason for a Grafana alert, or producing enter for profile-guided optimization.
What this profile does not let you know is the place your program spends time ready on locks or the community. Since CPU profiling samples lively execution, blocking and rivalry want different profiles, just like the block and mutex ones described beneath. This implies the precise operating time of a goroutine won’t match its execution time on the CPU.
Reminiscence profiles – heap and allocs
The reminiscence profiles – heap and allocs – are maybe probably the most complicated, even for seasoned Go builders. To make clear: heap and allocs are each kinds of reminiscence profiling that offer you insights into reminiscence consumption, allocation patterns, and rubbish assortment (GC). Beneath the hood, each retailer the identical knowledge. The one distinction is which pattern sort they current because the default.
The sampling varieties accessible in each profiles are:
inuse_space: The quantity of reminiscence (in bytes) that’s at the moment allotted and has not but been rubbish collected.inuse_objects: The entire variety of particular person objects at the moment on the heap.alloc_space: The cumulative quantity of reminiscence (in bytes) allotted for the reason that program began (together with reminiscence that has already been freed).alloc_objects: The cumulative depend of objects allotted for the reason that program began (together with those who have already been collected).
The heap profile reveals inuse_space because the default view, and the allocs profile reveals alloc_space. You may, nonetheless, swap between all 4 sampling varieties freely.
An vital level about reminiscence profiles is that they’re sampled, not actual. Go’s A Information to the Go Rubbish Collector explains that, by default, these profiles solely pattern a subset of heap objects that’s adequate to seek out hotspots.
One other factor to recollect is that reminiscence profiles don’t truly cowl all reminiscence, as Go can allocate some values to the stack and outdoors the heap that’s managed by GC, relying on the end result of escape evaluation.
Block profile
The block profile reveals you the place goroutines are blocked ready for synchronization primitives corresponding to sync.Mutex, sync.RWMutex, sync.WaitGroup, sync.Cond, and channel ship/obtain/choose. A block profile tracks blocking occasions, measures how lengthy they final, after which aggregates them by stack hint as soon as they’re accomplished. It tells you the place your program hung out ready as an alternative of doing helpful work and helps you optimize inefficient synchronization patterns.
The block profile tracks two pattern varieties:
- Contentions: This reveals the variety of occasions a block occasion occurred (i.e. a number of goroutines tried to entry a shared useful resource concurrently and just one might proceed).
- Delay (latency): This reveals the full time spent being blocked (i.e. the precise period of time a goroutine spent in a blocked state earlier than it might resume execution).
This is a crucial distinction as a result of you possibly can have low rivalry with excessive delay (and vice versa); for instance, when just one goroutine waits for a lock, but it surely takes 10 seconds as a result of the holder is performing a sluggish community name.
Block profiling is disabled by default within the Go runtime, because it introduces overhead. In manufacturing, it is best to allow block profiling just for very quick intervals and at a really lengthy sampling interval to research identified points.
Mutex profile
In distinction to the block profile, the mutex profile captures goroutines that block different goroutines and focuses particularly on sync.Mutex and sync.RwMutex rivalry. You might say that, whereas the block profile tells you what’s ready, the mutex profile tells you what’s inflicting the wait. One other important distinction is that mutex profiling makes use of event-based sampling slightly than time-based sampling.
Then again, the mutex profile behaves equally to the block profile in that it solely information accomplished occasions and can be disabled by default. It additionally tracks two pattern varieties – contentions and delay.
It’s best to attain for a mutex profile once you suppose your software throughput or latency is being restricted by lock rivalry. The Go diagnostic docs explicitly advocate utilizing it when the CPU is just not totally utilized due to mutex rivalry.
Goroutine profile
Because the identify would counsel, goroutine profiling helps you examine what number of goroutines exist in your program and what they’re doing for the time being by taking a snapshot of their stack traces. The goroutine profile helps you debug concurrency points by figuring out goroutine leaks or deadlocks as they’re taking place
Within the context of block and mutex profiles, it’s vital to do not forget that the goroutine profile offers with present goroutines. Each entry within the profile reveals the present perform name stack, whether or not the goroutine is operating, ready, or blocked, and the place it’s caught (channel, mutex, I/O, and so on.). The profile is uncovered in web/http/pprof by default, which makes it the go-to selection for troubleshooting your program when it’s hanging or experiencing a pile-up.
That mentioned, once you’re investigating issues along with your program, it’s greatest to have a look at all three profiles – goroutine, block, and mutex – to get the complete image. For instance, if you happen to see a pile-up within the goroutine profile that reveals a number of goroutines parked in sync.Mutex.Lock, the block profile will let you know which callers hung out blocked there, and the mutex profile will let you know which part made the wait costly.
Goroutine leak profile
The goroutine profile reveals you all dwell goroutines and leaves it as much as you to determine if there’s something fallacious with them. In Go 1.27, the Go workforce launched a goroutineleak profile that detects leaked goroutines.
Goroutines which have leaked are blocked and, in keeping with the runtime, can’t be “unstuck”, inflicting them to sit down there for the lifetime of the method and maintain on to their stacks and references. They turn into blocked because of concurrency points with primitives corresponding to channels, sync.Mutex, or sync.Cond that may’t be reached straight or not directly by a runnable goroutine. That is decided utilizing the rubbish collector’s reachability evaluation.
This profile won’t catch all leaked goroutines, however “a big class of [these] leaks”, as the parents at Google admit. Nevertheless, if you happen to run the profile and discover it fully empty, it’s not a mistake – it signifies that your program merely doesn’t have any goroutine leaks detectable by runtime.
How one can gather Go profiles
Now that we all know what the primary profiles in Go are, let’s see how one can gather and interpret them to truly enhance your software program.
There are alternative ways to gather the profiles – with runtime/pprof, web/http/pprof, and… GoLand. All of them produce pprof-compatible profiles you can then visualize with both go instrument pprof or GoLand.
Whereas the “conventional” methods are considerably tedious, if you know the way to run one profile, you know the way to run the others – for probably the most half. We’ll undergo the overall steps and level out variations and exceptions the place vital.
And for these of you who’ve GoLand model 2026.1.2 or increased, we’ll present you tips on how to run and examine the profiles with out having to recollect any instructions or a single line of code.
runtime/pprof
For express, code-controlled profiling, runtime/pprof is the way in which to go. For many functions, that is probably the most direct API:
import (
"os"
"runtime"
"runtime/pprof"
)
func captureCPU() error {
f, err := os.Create("cpu.pb.gz")
if err != nil {
return err
}
defer f.Shut()
if err := pprof.StartCPUProfile(f); err != nil {
return err
}
defer pprof.StopCPUProfile()
runLoad()
return nil
}
func captureHeap() error {
runtime.GC() // run GC first to seize solely probably the most present objects
f, err := os.Create("heap.pb.gz")
if err != nil {
return err
}
defer f.Shut()
return pprof.Lookup("heap").WriteTo(f, 0)
}
func captureAllocs() error {
f, err := os.Create("allocs.pb.gz")
if err != nil {
return err
}
defer f.Shut()
return pprof.Lookup("allocs").WriteTo(f, 0)
}
func dumpGoroutines() error {
return pprof.Lookup("goroutine").WriteTo(os.Stdout, 2)
}
- As you possibly can see, the CPU profile makes use of
StartCPUProfile/StopCPUProfile. It has its personal begin/cease API as a result of it streams throughout a time window – you flip it on, run the workload, after which cease it when it’s completed. - The heap profile captures knowledge for the reason that final GC, so it is best to name
runtime.GC()earlier than writing a profile. Forcing the GC offers you probably the most up-to-date stats, however there are some eventualities the place you may need to keep away from that. - For goroutine profile, textual content output is often higher than
pprofgraphs once you’re debugging a leak or a impasse, thereforepprof.Lookup("goroutine").WriteTo(os.Stdout, 2).
web/http/pprof
The usual selection for long-running companies is web/http/pprof. You begin by importing the package deal:
import (
"log"
"web/http"
_ "web/http/pprof"
)
func major() {
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
runServer()
}
Listed here are the standard dwell instructions:
# CPU: 30-second profile go instrument pprof http://localhost:6060/debug/pprof/profile?seconds=30 # Stay heap, forcing a GC first go instrument pprof http://localhost:6060/debug/pprof/heap?gc=1 # Whole allocations since course of begin go instrument pprof http://localhost:6060/debug/pprof/allocs # Block profile (solely helpful if SetBlockProfileRate was configured) go instrument pprof http://localhost:6060/debug/pprof/block # Mutex profile (solely helpful if SetMutexProfileFraction was configured) go instrument pprof http://localhost:6060/debug/pprof/mutex # Human-readable goroutine dump curl http://localhost:6060/debug/pprof/goroutine?debug=2
- For CPU,
seconds=Nmeans “file the CPU profile for N seconds”. The HTTP handler for CPU defaults to 30 seconds if you happen to omit the parameter. - For heap,
heap?gc=1will run the GC, whereas heap andheap?gc=0won’t. debug=1switches the profile to textual content (except for the CPU profile).
If you’d like a fast and simple means to try the profiles, head straight to http://localhost:6060/debug/pprof – you’ll discover an HTML index itemizing all of the accessible profiles there.
Capturing profiles with GoLand
In case you don’t work with profiles repeatedly, gathering them the standard means often requires you to search for the documentation or tutorials to first keep in mind what, the place, and when. That’s why, in GoLand 2026.1.2, we carried out a brand new profiler instrument that makes it simpler so that you can each gather and examine profiles – all from the consolation of your IDE.
The instrument at the moment means that you can seize CPU, heap, allocs, goroutine, block, mutex, and goroutine leak profiles, and consider their imports.
Opening the profiler
There are a number of methods to begin the profiler instrument.
- Go Optimization instrument window: Within the instrument window bar, you will notice a brand new icon for the Go Optimization instrument, which is the place profiling actions could be carried out. From there, you possibly can select which configuration to run, view profiles you already captured, or import profiles captured by another person.

- Run widget: Now, along with operating and debugging, this widget additionally consists of an choice to profile your program, accessible below the Extra Actions icon. Clicking on the Profile with… choice will arrange the method and open the Go Optimization instrument window.

- Gutter icon: Wherever you see the run icon within the gutter, you possibly can launch the profiler instrument from the dropdown that seems once you click on on it.

Capturing profiles
Capturing profiles is fairly simple. To launch your program in profiling mode, click on the Run with Profiler button – GoLand will arrange the whole course of for you. To seize the profile you’re taken with, merely click on on the corresponding button.
An vital caveat is that when profiling is initiated, GoLand modifies the executable throughout compilation to show the required profiling API. Your code and your program won’t be affected, however for that purpose, the profiler can’t be connected to a program that’s at the moment operating.
Capturing a CPU profile
Since a CPU profile is just not collected constantly or by default, it really works slightly in a different way from the opposite profiles. So as to run it, you must click on Begin CPU recording, let the profiler run for the specified period of time, after which cease the recording to examine the outcomes.
Capturing a heap profile
GoLand means that you can seize a heap profile with or with out forcing rubbish assortment first. Usually, the recommendation is to run the GC earlier than gathering a heap profile because it reviews reminiscence stats as of probably the most just lately accomplished GC cycle and skips more moderen allocations to keep away from skewing the profile towards short-lived rubbish. Due to this fact, if you wish to see the heap objects which can be at the moment dwell, it is best to drive GC first.
There are, nonetheless, eventualities the place you don’t need that, after which it is smart so that you can gather the heap profile with out GC:
- You need to see the method in its pure state. Forcing GC adjustments the heap, GC pacing, and short-term reminiscence habits. If you wish to see what the service appears to be like like below regular load, keep away from it.
- You’re trying into allocation stress or reminiscence spikes. While you need to examine how a lot work the GC has to truly do, forcing a cleanup will conceal the “mess” that you simply’re making an attempt to research.
- You’re evaluating the states earlier than and after compelled GC. If reminiscence disappears after rubbish assortment, it was most likely rubbish that was ready for assortment or GC pacing. If it stays, you’ve retained objects.
Observe that if you happen to seize the heap profile with GC first, GoLand will truly drive rubbish assortment, so capturing a heap profile with out GC proper after will seemingly not present significant insights.
Importing and exporting profiles
The Profiler instrument additionally means that you can open and consider profiles captured by others (not essentially utilizing GoLand), so long as they’re in a pprof-compatible format. Merely drag and drop the file, or click on the Import button within the Go Optimization instrument window and choose the file from there.
Profiles captured with GoLand are pprof-compatible and saved in a delegated listing. If you wish to share a profile you captured in GoLand, go to Latest profiles and right-click on the one you need to share to disclose its location.
How one can examine profiles
Upon getting a Go profile, inspection is generally the identical, regardless of the way it was collected, since go instrument pprof can learn both a saved file or a dwell HTTP URL.
Within the terminal
In case you have a saved profile file collected with runtime/pprof, you possibly can entry it within the terminal:
go instrument pprof ./your-binary cpu.pb.gz
This may begin pprof’s interactive shell within the terminal. The principle textual content reviews are prime, listing, tree, peek, and traces.
If you’d like a one-shot terminal report as an alternative of an interactive shell, add a format flag:
go instrument pprof -text ./your-binary cpu.pb.gz go instrument pprof -tree ./your-binary mutex.pb.gz go instrument pprof -peek='mypkg.(*Cache).Get' ./your-binary cpu.pb.gz go instrument pprof -list="mypkg.(*Cache).Get" ./your-binary cpu.pb.gz
This may print the report and exit the profile.
From the online interface
That is the simplest means if you wish to see graphs and flame graphs, and transfer between prime, peek, and supply views.
# saved native profile go instrument pprof -http=localhost:8081 ./server cpu.pb.gz # dwell profile from a operating service, with the native binary for symbols/supply go instrument pprof -http=localhost:8081 ./server 'http://localhost:6060/debug/pprof/profile?seconds=30'
With -http=host:port, pprof begins a neighborhood net server and opens a browser. The online UI gives a number of views of the identical profile:
- Graph: Visualizes the decision graph.
- Flame Graph: Gives an interactive flame graph (the bigger the node and the thicker the sting, the upper the useful resource consumption is).
- Prime: Lists the features consuming probably the most assets in a desk format.
- Supply: Shows supply code annotated with useful resource consumption.
- Peek: Gives a statistical peek at perform samples.
Inspecting profiles with GoLand
Navigating between your code and totally different endpoints, as is the case with go instrument pprof, could be fairly distracting. The profiling instrument in GoLand enables you to see and handle every part associated to profiling in a single place – your IDE.
When you gather or import your profiles, you should have entry to views that you simply most likely acknowledge from the online interface – (name) graph, flame graph, and prime – in addition to a tree view. You may entry these views for all of the profiles (CPU, heap, allocs, goroutine, block, mutex, goroutine leak) and choose totally different pattern varieties:
- The CPU profile can present you both CPU time or samples.
- The heap profile, by default, reveals you in-use house, however it could actually additionally present in-use objects, allotted house, or allotted objects.
- The allocs profile, by default, reveals allotted house, however it could actually additionally present you every part that the heap profile does. That’s as a result of these two are each representations of the identical reminiscence profile, which we mentioned earlier.
- Mutex and block each can present both contentions or delay.
- The goroutine profile solely has one pattern sort – variety of goroutines – so there is no such thing as a selector for that profile.
You may simply navigate on to the related line of code from any of the views, just by clicking on the related perform. The instrument will even spotlight any hotspots in your code with a fireplace icon within the editor’s gutter.
Now that you already know what profiles you possibly can visualize, let’s talk about in additional element what the totally different views present and tips on how to use them.
Prime
The Prime view reveals you an ordered desk of the highest features within the profile. The values on this view symbolize totally different items, relying on the profile (e.g. CPU time, reminiscence bytes, or goroutine counts).
- Flat and Flat%: The quantity of the useful resource consumed straight by that perform, excluding callees. Flat values let you know if the perform itself is pricey.
- Sum%: Operating sum of Flat%.
- Cumulative and Cumulative%: The entire quantity of the useful resource consumed by this perform and every part it calls. This tells you if the perform creates numerous work total.

By default, the features on this view are ordered from the best to lowest Flat. Nevertheless, you possibly can reorder the view nonetheless you want – clicking on another header will make it the default for ordering, and clicking on the identical header once more will reverse the order.
Clicking on a perform’s row will even take you to the related line of code within the editor.
Graph
Within the net interface, a name graph is the default means of visualizing the info as a community. We’ve taken efforts to make the Graph view extra visually inviting and interactive.
The nodes of the graph are features – the redder the field, the extra resource-intensive the perform. The sides are perform calls labeled with how a lot knowledge (e.g. CPU time or reminiscence) flows in that decision – the bolder and redder the arrow, the extra assets the decision consumes. The dashed traces symbolize paths by nodes which were faraway from view due to the graph settings (corresponding to node depend). You may transfer each the perimeters and the nodes to enhance visibility if the graph appears to be like too dense.

The Graph view in GoLand means that you can regulate the view to your wants by modifying the node and edge fractions:
- Node depend: Limits the variety of nodes proven on the graph to the highest N nodes. For instance, if you happen to set your node depend to N=80, the graph will solely present 80 nodes (whatever the remaining settings). Seen nodes are decided by a particular entropy-based algorithm from the
pprofinstrument (for instance, the algorithm favors nodes with excessive cumulative or flat values and various name patterns, whereas deprioritizing easy passthrough nodes). - Node fraction: Controls which nodes will likely be proven, based mostly on how a lot of the full pattern worth a node accounts for. For instance, if you happen to set the node fraction to 0.01, the graph will solely present features accountable for 1% or extra of the full samples. The smaller the worth, the extra element you will notice, however this will additionally result in extra litter that may make it more durable so that you can discover hotspots.
- Edge fraction: This setting works equally to the node fraction, however controls which edges (the decision paths between features) are proven. For instance, if you happen to set it to 0.005, the graph will solely present name edges that contribute 0.5% of the full samples.
- Name tree: This toggle adjustments how the info is introduced by exhibiting the precise paths, which implies the identical perform can seem a number of occasions in several contexts. By default, as an alternative of a name tree, the graph reveals a name graph, the place features are merged so there’s just one node per perform.
In case you have a look at the default graph and discover it overwhelming, attempt growing the fractions to see fewer nodes or edges, or scale back the node depend. In case you really feel like vital paths are lacking, lower the node or edge fractions.
Flame graph
The Flame graph is the default view once you open a profile, as our analysis has established that that is the view builders entry probably the most typically.
A flame graph is a visualization of the decision stack the place value is introduced as width, i.e. the longer the bar, the extra assets the perform and its kids are utilizing. The peak solely signifies the depth of the decision chain, so a tall however skinny tower won’t be your offender in relation to useful resource consumption.

In case you hover over a perform, you will notice the cumulative share (% of all), the share relative to the mother or father (% of mother or father), and cumulative worth – the identical knowledge it’s also possible to see in Prime and Tree views. Clicking on a perform’s bar will take you to the related line of code, and if that perform is scorching, there will likely be a flame icon within the gutter.
Another fascinating features on this view are:
- Icicle graph: The flame graph by default is introduced in an icicle view, i.e.
majoris on the prime. You may uncheck that choice to show the view the wrong way up. - Seize picture: You may take a snapshot of the graph and reserve it or copy it to the clipboard.
- Search: You may seek for the perform you’re taken with.
It’s also possible to check out the New Flame Graph view choice for a extra fashionable feel and appear.
Tree
It’s also possible to see the Tree view. This view presents the identical knowledge because the Prime view, however organizes all features below their mother or father perform, no matter how resource-intensive they’re.

Line profiler
The line profiler is an alternative choice to the -list command in pprof.
When you run your program with the profiler instrument, GoLand will add runtime hints close to the corresponding traces of code proper within the editor. Strains that took a big period of time to execute may have gray labels, whereas probably the most resource-intensive ones will likely be marked with purple labels with a fireplace icon.
The connection works the opposite means spherical as properly. You may navigate on to a selected line of code within the editor from any of the profiling views, just by clicking on the related perform.

Why attempt GoLand’s profiler?
The profiler instrument in GoLand makes profiling your software program as simple as clicking a button. You not want to recollect instructions or extra steps. The complete course of stays in your IDE, so that you don’t have to leap between the editor and the browser, and you’ll simply examine the problematic traces of code. We hope that each the brand new instrument and this information will take the guesswork out of profiling and assist extra builders make this code optimization approach part of your each day work.
Completely satisfied coding!
The GoLand Crew

