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 ¶
const M7BudgetMillis = 3.0
M7BudgetMillis is the maximum render-thread GC pause M7 allows.
Variables ¶
This section is empty.
Functions ¶
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 ¶
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 ¶
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.
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.