Documentation
¶
Overview ¶
Package footprint bounds and measures the control plane's idle cost: a default memory limit, a registry of background loops, and process stats.
Index ¶
- Constants
- func ApplyGCPercent(getenv func(string) string) int
- func Attribute(name string) func()
- func BootTotal() time.Duration
- func CPUWindowFromEnv(get func(string) string) time.Duration
- func Every(ctx context.Context, name string, interval time.Duration, logger *slog.Logger, ...) error
- func LimitFor(total int64, percent int) int64
- func Percent(getenv func(string) string) int
- func RecordBootStage(name string, d time.Duration)
- func Run(ctx context.Context, name string, fn func(context.Context))
- func RunTrim(ctx context.Context, logger *slog.Logger, getenv func(string) string, ...)
- func Stream(ctx context.Context, name string) func()
- func TimeBootStage(name string, fn func() error) error
- func WindowCPU(window time.Duration, now time.Time, cpuSeconds float64) (percent, covered float64)
- type Assessment
- type BaselineRow
- type BootStage
- type LiveSettings
- type Loop
- type LoopInfo
- type MemoryLimit
- type MetricCheck
- type Proc
- type Reading
- type SubsystemCount
- type Tolerance
Constants ¶
const ( EnvTolRSSPct = "IDLE_TOL_RSS_PCT" EnvTolGoroutines = "IDLE_TOL_GOROUTINES" EnvTolFDs = "IDLE_TOL_FDS" EnvTolCPUPoints = "IDLE_TOL_CPU_POINTS" EnvCPUWindowSecs = "APP_FOOTPRINT_CPU_WINDOW_SECONDS" )
Environment variables shared with scripts/idle-footprint, which has no defaults on purpose.
const ( StatusWithin = "within_tolerance" StatusOver = "over_tolerance" StatusNoBaseline = "no_baseline" StatusToleranceOff = "tolerance_unset" )
Assessment statuses.
const ( EnvMemLimit = "GOMEMLIMIT" EnvMemLimitPercent = "APP_GOMEMLIMIT_PERCENT" DefaultPercent = 80 )
Env vars read by ApplyMemoryLimit.
const ( EnvGCPercent = "APP_GC_PERCENT" EnvTrimInterval = "APP_MEM_TRIM_INTERVAL" EnvTrimMinIdleMB = "APP_MEM_TRIM_MIN_IDLE_MB" EnvTrimBootDelay = "APP_MEM_TRIM_BOOT_DELAY" DefaultTrimBoot = 12 * time.Second DefaultGCPercent = 50 DefaultTrimEvery = 2 * time.Minute DefaultTrimIdleMB = 24 )
Env vars read by ApplyGCPercent and RunTrim.
const DefaultSettingsPoll = 30 * time.Second
DefaultSettingsPoll is how often RunTrim re-reads the live settings; the trim itself still runs on its own interval.
Variables ¶
This section is empty.
Functions ¶
func ApplyGCPercent ¶
ApplyGCPercent returns the percent it set, or 0 when GOGC already decides. It lowers the GC target below Go's 100 default unless GOGC or APP_GC_PERCENT is set; the live heap is small, so the extra GC cost is negligible.
func Attribute ¶
func Attribute(name string) func()
Attribute counts the calling goroutine under name until the returned func runs.
func CPUWindowFromEnv ¶
CPUWindowFromEnv returns the CPU averaging window, matching the baseline run's 60 seconds when unset.
func Every ¶
func Every(ctx context.Context, name string, interval time.Duration, logger *slog.Logger, tick func(context.Context) error) error
Every runs tick on interval until ctx ends. The first tick is delayed by a random jitter of up to a tenth of the interval so loops do not wake together, and each tick is recorded.
func LimitFor ¶
LimitFor returns percent of total bytes, or 0 when the result would be too small to be safe.
func RecordBootStage ¶
RecordBootStage notes one finished startup step. Past the bound it only adds to the total.
func RunTrim ¶
func RunTrim(ctx context.Context, logger *slog.Logger, getenv func(string) string, live *LiveSettings)
RunTrim returns heap the runtime is holding but not using to the OS. Boot allocates transient hundreds of MB (catalog parse, password hashing) and the scavenger gives it back slowly, so RSS stays high for no reason. With live set it also re-reads the GC target, memory limit and trim knobs on every poll, in the same loop.
func Stream ¶
Stream labels the calling goroutine and counts it under name until the returned func runs, for handlers that cannot hand their body to Run.
func TimeBootStage ¶
TimeBootStage runs fn and records its duration, returning fn's error unchanged.
Types ¶
type Assessment ¶
type Assessment struct {
Status string `json:"status"`
Detail string `json:"detail,omitempty"`
Platform string `json:"platform"`
Current Reading `json:"current"`
Baseline *BaselineRow `json:"baseline,omitempty"`
Tolerance *Tolerance `json:"tolerance,omitempty"`
Checks []MetricCheck `json:"checks"`
// BootStages and BootTotalMS are additive and filled by the API layer; unmeasured until a real host reports them.
BootStages []BootStage `json:"boot_stages,omitempty"`
BootTotalMS float64 `json:"boot_total_ms,omitempty"`
}
Assessment is the live footprint judged against the committed idle baseline.
func Assess ¶
func Assess(cur Reading, rows []BaselineRow, goos, goarch string, tol Tolerance, tolErr error) Assessment
Assess compares a reading with the baseline row for this platform. The baseline records a peak RSS, so live RSS is held to the peak limit.
type BaselineRow ¶
type BaselineRow struct {
OS string `json:"os"`
Arch string `json:"arch"`
Apps int `json:"apps"`
AppMode string `json:"app_mode"`
WindowSeconds int `json:"window_seconds"`
RSSMB float64 `json:"rss_mb"`
PeakRSSMB float64 `json:"peak_rss_mb"`
CPUPercent float64 `json:"cpu_percent"`
Goroutines int `json:"goroutines"`
OpenFDs int `json:"open_fds"`
Threads int `json:"threads"`
Loops int `json:"loops"`
}
BaselineRow is one committed idle measurement from scripts/idle-footprint-baseline.json.
func Baseline ¶
func Baseline() []BaselineRow
Baseline returns the committed idle measurements compiled into the binary.
func SelectBaseline ¶
func SelectBaseline(rows []BaselineRow, goos, goarch string, apps int) (BaselineRow, bool)
SelectBaseline picks the stopped-app row for this platform closest to the live app count.
type BootStage ¶
BootStage is how long one named startup step took.
func BootStages ¶
func BootStages() []BootStage
BootStages returns a copy of the recorded steps in start order.
type LiveSettings ¶
type LiveSettings struct {
GCPercent func(context.Context) int
MemLimitPercent func(context.Context) int
TrimInterval func(context.Context) time.Duration
TrimMinIdleMB func(context.Context) int
}
LiveSettings reads the runtime settings that tune the Go runtime. Nil funcs are skipped. footprint cannot import the settings package, so the caller supplies the readers.
type Loop ¶
type Loop struct {
// contains filtered or unexported fields
}
Loop records the runs of one background loop.
type LoopInfo ¶
type LoopInfo struct {
Name string `json:"name"`
IntervalSecs float64 `json:"interval_seconds"`
Runs int64 `json:"runs"`
Errors int64 `json:"errors"`
LastRunAt time.Time `json:"last_run_at"`
LastDuration float64 `json:"last_duration_ms"`
BusyMS float64 `json:"busy_ms_total"`
CostPercent float64 `json:"cost_percent"`
Running bool `json:"running"`
LastError string `json:"last_error,omitempty"`
// contains filtered or unexported fields
}
LoopInfo is the observable state of one background loop.
type MemoryLimit ¶
type MemoryLimit struct {
LimitBytes int64 `json:"limit_bytes"`
Source string `json:"source"`
Percent int `json:"percent"`
}
MemoryLimit describes what ApplyMemoryLimit decided.
func ApplyMemoryLimit ¶
func ApplyMemoryLimit(getenv func(string) string, logger *slog.Logger) MemoryLimit
ApplyMemoryLimit sets a soft Go memory limit from the container or host memory unless GOMEMLIMIT is already set.
func ApplyMemoryLimitPercent ¶
func ApplyMemoryLimitPercent(pct int, logger *slog.Logger) MemoryLimit
ApplyMemoryLimitPercent sets the soft limit to pct of system memory, or lifts it when pct is 0 or the result is too small to be safe. The caller checks GOMEMLIMIT first.
func CurrentMemoryLimit ¶
func CurrentMemoryLimit() MemoryLimit
CurrentMemoryLimit returns what the last ApplyMemoryLimit call decided.
type MetricCheck ¶
type MetricCheck struct {
Name string `json:"name"`
Unit string `json:"unit"`
Current float64 `json:"current"`
Baseline float64 `json:"baseline"`
Limit float64 `json:"limit"`
OK bool `json:"ok"`
}
MetricCheck is one live value next to its baseline and the limit the tolerance allows.
type Proc ¶
type Proc struct {
RSSBytes uint64 `json:"rss_bytes"`
HeapBytes uint64 `json:"heap_bytes"`
Goroutines int `json:"goroutines"`
Threads int `json:"threads"`
OpenFDs int `json:"open_fds"`
CPUSeconds float64 `json:"cpu_seconds"`
CPUPercent float64 `json:"cpu_percent"`
}
Proc is a point in time reading of the process footprint.
type Reading ¶
type Reading struct {
RSSBytes uint64 `json:"rss_bytes"`
CPUPercent float64 `json:"cpu_percent"`
CPUWindowSeconds float64 `json:"cpu_window_seconds"`
Goroutines int `json:"goroutines"`
OpenFDs int `json:"open_fds"`
Threads int `json:"threads"`
Apps int `json:"apps"`
}
Reading is the live control plane footprint compared against a baseline.
type SubsystemCount ¶
SubsystemCount is the number of live goroutines attributed to one subsystem.
func Subsystems ¶
func Subsystems() []SubsystemCount
Subsystems lists non-zero counts, largest first.