Skip to content

timur-developer/gcscope

Repository files navigation

gcscope — Go Garbage Collector Visualizer

gcscope demo

CI Go License: MIT

Read this in other languages: Russian

gcscope is a terminal UI (TUI) and CLI for visualizing Go GC behavior in real time from gctrace, gcpacertrace, and runtime/metrics: GC cycles, stop-the-world (STW) pauses, heap live/goal dynamics, and GC pacer signals.

It is designed for fast feedback during performance work:

  • spot problematic STW spikes (p99/max) under load
  • see how GC frequency changes across runs
  • see heap live approach heap goal as pacing becomes more aggressive
  • compare two runs using snapshots (diff)

Contents

How It Works

gcscope has two data sources:

  • run (primary): starts your binary, ensures GODEBUG contains gctrace=1,gcpacertrace=1, parses the target stderr.
  • attach (secondary): polls an HTTP endpoint that exports runtime/metrics in a gcscope-friendly JSON format (via pkg/reporter).

No code changes are required for run. For attach, you add a small HTTP endpoint to the target service.

Install

Pick one of the options below.

Install (Go)

Install the gcscope CLI into your GOBIN:

go install github.com/timur-developer/gcscope/cmd/gcscope@latest

After that you can use gcscope as a normal CLI (from any directory):

gcscope lab churn
gcscope run ./path/to/your-binary -- --your-flag value
gcscope attach http://127.0.0.1:8080/gcscope/metrics
gcscope diff ./a.json ./b.json

Built-in help:

gcscope --help
gcscope run --help

Install (Prebuilt binaries)

Download a prebuilt binary from GitHub Releases (Assets), pick the archive for your OS/arch, then extract it.

Run from the extracted folder:

Windows (PowerShell):

.\gcscope.exe lab churn

macOS / Linux:

chmod +x ./gcscope
./gcscope lab churn

To run gcscope from any directory, move it to a folder in your PATH (or add the extracted folder to PATH).

Run From Source (No Install)

From source:

go run ./cmd/gcscope lab churn

Quickstart (1 minute)

gcscope launch

Prerequisites: Go 1.22+ and a reasonably large terminal window.

1) Try the built-in demo workload

From source (no install):

go run ./cmd/gcscope lab churn

Or via Makefile:

make lab-churn

Open in-app help any time: ? / h / f1.

2) Run on your binary (step-by-step)

  1. Build your target app as a binary:
go build -o ./myapp ./cmd/myapp
  1. Run it under observation (note the -- separator for passing args to your program):
go run ./cmd/gcscope run ./myapp -- --your-flag value
  1. In the UI:
  • press ? to see all hotkeys
  • press space to pause/resume
  • when paused, use left/right (and home/end) to scrub history
  • press s to write a snapshot to tmp/snapshots (by default)

If you want to use gcscope as a CLI, install it once and run gcscope ... directly (see Install).

Usage

run (run your binary under observation)

Run your Go program under observation:

gcscope run ./path/to/your-binary

This mode is intended for checking how Go's garbage collector behaves in your project during a real run.

run works with a compiled binary (not a .go file), so build your program first, then pass the resulting executable path to gcscope.

Need flags or want to pass args/flags to your program? See Configuration.

From source (no install):

go run ./cmd/gcscope run ./path/to/your-binary

Makefile shortcut:

make run TARGET=./path/to/your-binary

lab (built-in demo workloads)

Built-in demo presets:

gcscope lab alloc
gcscope lab churn
gcscope lab idle
gcscope lab spike

What the presets mean (synthetic workloads):

  • alloc: steady small/medium allocations with some retention; heap live gradually grows and GC cadence stays relatively stable
  • churn: repeated large bursts with short retention; useful for stressing STW and the pacer
  • idle: mostly idle with occasional bursts; useful for observing low-frequency GC behavior
  • spike: light background traffic with periodic heavy bursts; makes heap and STW spikes easy to see

attach (connect to a runtime/metrics HTTP endpoint)

Attach to a running service that exposes runtime/metrics in gcscope JSON format.

  1. Add pkg/reporter to your service:
package main

import (
	"log"
	"net/http"

	"github.com/timur-developer/gcscope/pkg/reporter"
)

func main() {
	rep := reporter.New()

	mux := http.NewServeMux()
	mux.Handle(rep.Path(), rep.Handler())

	log.Fatal(http.ListenAndServe(":8080", mux))
}
  1. Attach:
gcscope attach http://127.0.0.1:8080/gcscope/metrics

Notes (attach mode):

  • the endpoint payload is based on runtime/metrics, so values differ from run mode
  • the target process environment (GOGC, GOMEMLIMIT, GODEBUG) is not available; UI shows n/a

diff (compare two snapshot files)

Compare two snapshots:

gcscope diff ./a.json ./b.json

What diff prints:

  • a short summary for snapshot A and B (gc_cycles_total, heap_live_mb, stw_p50/p99/max_us)
  • delta (B-A) for heap_live_mb and STW window stats

What You See (Metrics & Panels)

gcscope UI overview

gcscope keeps a sliding window of recent GC events (--window-size, default: 200) and shows both raw per-cycle values and derived stats over that window.

Current Values

  • GC cycles total: current GC cycle number
  • last STW (us): last cycle STW pause (sweep term + mark term, converted to microseconds)
  • heap live (MB) / heap goal (MB): live heap and current goal
  • heap: live/goal: a compact live-vs-goal indicator

Information (window stats)

  • max STW (us): max STW over the visible window
  • gc: rate as GCs/min and/or average GC interval
  • stw: bad STW count/percent (based on thresholds) and forced GC count
  • time since last GC, uptime
  • stw thresholds: warn / bad (see Configuration)
  • snapshot status and snapshot directory
  • env context (GOGC, GOMEMLIMIT, GODEBUG) in run/lab (not available in attach)

Charts

  • Heap live over time (MB): time-series of heap live
  • STW p50/p99/max over time (us): time-series derived from the sliding window
  • STW per cycle: per-cycle bar chart; labels can show STW or heap live (toggle with l)

Cycle Details (selected GC event)

For the currently selected cycle (live cursor, or scrubbed history when paused):

  • GC #, time since start, forced
  • STW total (us) + breakdown: sweep term / mark term
  • heap (MB): start/end and live/goal
  • gc cpu (%)
  • pacer signals (when available): assist ratio, assist workers, pages swept

Controls

gcscope features

Full list of hotkeys is always available in the in-app Help (? / h / f1).

Core:

  • ? / h / f1 toggle Help
  • q / ctrl+c quit
  • space pause/resume live updates
  • left / right scrub history when paused
  • home / end jump to first/last event when paused
  • s write a snapshot

Layout and labels:

  • g toggle layout (spaced/tight)
  • l toggle STW bar labels mode (GC+STW -> GC+Heap -> GC-only)

Charts:

  • z switch focused chart (Heap/STW). Zoom/pan applies to the focused chart.
  • + / - zoom Y for focused chart
  • 0 reset Y zoom/pan for focused chart
  • shift+up / shift+down pan Y for focused chart
  • [ / ] zoom time span (X axis): all -> 1h -> 15m -> 5m -> 1m (and back)
  • r reset focus, zoom/pan, and time span

Configuration

Global flags (and their env overrides):

  • --window-size (GCSCOPE_WINDOW_SIZE) samples kept in memory (default: 200)
  • --snapshot-path (GCSCOPE_SNAPSHOT_PATH) snapshot directory (default: tmp/snapshots)
  • --exit-snapshot (GCSCOPE_EXIT_SNAPSHOT) write a snapshot on exit (default: true)
  • --no-alt-screen (GCSCOPE_NO_ALT_SCREEN) disable alt screen buffer
  • --stw-warn-us (GCSCOPE_STW_WARN_US) STW warning threshold (default: 200)
  • --stw-bad-us (GCSCOPE_STW_BAD_US) STW bad threshold (default: 1000)

Mode-specific env vars:

  • GCSCOPE_RUN_TARGET
  • GCSCOPE_ATTACH_URL, GCSCOPE_POLL_INTERVAL
  • GCSCOPE_LAB_PRESET
  • GCSCOPE_DIFF_A, GCSCOPE_DIFF_B

All flags can be provided via their GCSCOPE_* env equivalents listed above.

Flags & Argument Passing

Global flags (like --window-size, --stw-bad-us) go before the subcommand because they apply to all modes.

In run mode, -- separates gcscope arguments from the target program arguments. Everything after -- is passed to your binary unchanged.

Template:

gcscope [global flags] run <target-binary> -- [target args...]

Example:

gcscope --window-size 500 --stw-bad-us 2000 run ./path/to/your-binary -- --your-flag value

Snapshots

  • Default directory: tmp/snapshots
  • Manual snapshot: press s
  • Exit snapshot: enabled by default; skipped if a manual snapshot was created recently

What a snapshot contains:

  • current values (gc_cycles_total, last_stw_us, heap_live_mb, heap_goal_mb)
  • window stats (stw_p50_us, stw_p99_us, stw_max_us)
  • the list of recent GC events (the same window used by the UI), including parsed pacer fields when available

Snapshots are plain JSON files. They are useful for sharing, tracking regressions, and comparing two runs with gcscope diff.

Makefile Commands

make help prints all commands. Most common ones:

  • make ci: run lint + tests + build
  • make lint: run golangci-lint
  • make test: run go test ./...
  • make build: run go build ./... (sanity check)
  • make install: install gcscope into your Go bin directory
  • make lab (or make lab-churn, etc.): run demo workloads
  • make run TARGET=... ARGS="-- ...": run your binary under observation
  • make attach URL=...: attach to a running service (default URL is http://127.0.0.1:8080/gcscope/metrics)
  • make diff A=... B=...: compare two snapshot files

Maintainers:

  • make testbin: rebuild embedded lab binaries for all supported OS/arch
  • make release-snapshot: local GoReleaser build (--snapshot --clean)

Notes / FAQ

  • attach mode cannot see the target process env (GOGC, GOMEMLIMIT, GODEBUG), so UI shows n/a for these fields.
  • If you see no updates, your program might simply not be hitting GC cycles yet (try a workload that allocates more, or use lab churn).
  • If your terminal behaves oddly, try --no-alt-screen (or GCSCOPE_NO_ALT_SCREEN=true).
  • Very small STW values may display as 0 due to gctrace formatting.

Development

make ci
make lint
make test
make build

Maintainers:

make testbin
make release-snapshot

License

MIT. See LICENSE.

About

Go GC visualizer TUI for gctrace, runtime/metrics, STW pauses, heap live/goal, and pacer signals.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors