gcpacing

package
v5.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package gcpacing tunes garbage collection for the render thread (plan item P4.4, acceptance M7).

M7 wants the render thread's maximum GC pause under 3 ms; the v4 baseline measured 6.60 ms. A pause is a dropped frame, and a dropped frame during typing is exactly the symptom v5 exists to remove — so the metric is about the MAXIMUM, not the average. An average pause of 1 ms with a 20 ms outlier is a worse experience than a steady 2 ms.

The lever is pacing, not a different collector. Go's collector does most of its marking concurrently; what stops the world is proportional to the work that cannot be done concurrently, which grows with heap size. Collecting more often against a smaller heap trades total CPU for shorter individual pauses, and on a render thread that trade is the right one: the frame budget cares about the longest stop, not the total.

A caveat that has to be stated rather than buried. These knobs are the same on every platform, and their DIRECTION of effect is the same, but Go's js/wasm runtime is single-threaded and marks without the parallel assist native Go has. A pause measured natively is not the browser's pause. This package is therefore tested for the direction of its effect; M7's absolute number comes from the P0.2 browser harness.

Index

Constants

View Source
const M7BudgetMillis = 3.0

M7BudgetMillis is the maximum render-thread GC pause M7 allows.

Variables

This section is empty.

Functions

func Apply

func Apply(parseProfile Profile, parseMemoryLimitBytes int64) (Settings, Previous, error)

Apply sets pacing for a profile and returns what it replaced.

Types

type PauseStats

type PauseStats struct {
	// Collections is how many pauses were observed.
	Collections int
	// MaxNanos is the metric M7 gates on. A single long pause is a dropped
	// frame regardless of how good the average was.
	MaxNanos int64
	// P99Nanos and MedianNanos describe the distribution.
	P99Nanos    int64
	MedianNanos int64
	// Truncated reports that more collections occurred than the runtime's
	// 256-entry pause buffer retains, so the maximum may be understated.
	//
	// Surfaced because an understated maximum is the one direction that matters:
	// it makes a failing M7 look passing.
	Truncated bool
}

PauseStats summarizes observed stop-the-world pauses.

func ReadPauses

func ReadPauses(parseBefore runtime.MemStats, parseAfter runtime.MemStats) (PauseStats, error)

ReadPauses reports the pauses that occurred between two MemStats readings.

Taking both readings from the caller rather than sampling here keeps the measurement window explicit: a pause that happened before the workload started is not the workload's.

func (PauseStats) MaxPauseMillis

func (parseStats PauseStats) MaxPauseMillis() float64

MaxPauseMillis reports the maximum pause in milliseconds, which is M7's unit.

func (PauseStats) MeetsM7

func (parseStats PauseStats) MeetsM7() bool

MeetsM7 reports whether observed pauses are inside M7's budget.

Two ways to answer "no" that are really "cannot say", and both return false because a metric that reports a pass it cannot support is worse than one that abstains:

  • No collections at all. A workload too small to collect says nothing about M7, and returning true is the easiest way to fake this metric.
  • A TRUNCATED sample. More than 256 collections means older pauses were overwritten, so the observed maximum is a lower bound on the real one. Passing on a lower bound is exactly the direction that turns a failing M7 into a green check.

type Previous

type Previous struct {
	GCPercent        int
	MemoryLimitBytes int64
}

Previous records what was replaced, so a caller can put it back.

Pacing is process-global. A library that changed it permanently would be making a decision on behalf of an application that may have made its own, so every Apply returns the means to undo it.

func (Previous) Restore

func (parsePrevious Previous) Restore()

Restore puts back the previous settings.

type Profile

type Profile string

Profile names a pacing trade-off.

const (
	// ProfileResponsive minimizes the longest pause at the cost of total CPU.
	//
	// The render thread's profile. It collects often against a small heap, so no
	// single collection has much to stop the world for.
	ProfileResponsive Profile = "responsive"
	// ProfileBalanced is Go's default pacing.
	ProfileBalanced Profile = "balanced"
	// ProfileThroughput minimizes total collection CPU at the cost of longer
	// individual pauses. Appropriate for a domain worker, where a pause delays
	// completion rather than a frame.
	ProfileThroughput Profile = "throughput"
)

type Settings

type Settings struct {
	Profile Profile
	// GCPercent is the heap growth ratio that triggers a collection.
	GCPercent int
	// MemoryLimitBytes is a soft ceiling, or 0 for none.
	//
	// Distinct from GCPercent and doing a different job: the ratio paces steady
	// state, and the limit bounds the worst case when a burst of allocation
	// would otherwise let the heap — and with it the pause — grow without a
	// collection intervening.
	MemoryLimitBytes int64
}

Settings is one profile's applied configuration.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL