Documentation
¶
Overview ¶
Package sysload is the outpost's considerate system-load profiler. It samples CPU utilization, memory availability, and the load average on a slow cadence (~30s), learns a per-hour-of-day baseline of "normal" load over days, and answers two questions the warm-serving supervisor asks continuously:
- Busy() — is the machine currently doing meaningful non-LLM work? True when the current load is well above this hour's learned baseline OR above absolute safety thresholds (CPU sustained >60%, or available memory <25%). Debounced so a brief spike doesn't flap the answer.
- WarmBudgetBytes(usableMem) — how much memory the host is willing to dedicate to keeping LLM models warm. A conservative fraction of usable memory (default 0.33 — leaves ~2/3 for the OS and the user's own apps), and exactly zero while Busy() so the host fully yields to the user's work.
Pure Go, cgo-free, cross-compile clean. Per-platform probes live in sample_{darwin,linux,windows,other}.go behind build tags; each is best-effort and degrades to "unknown" (a negative sentinel) rather than erroring, so a probe that can't run on some host never breaks the profiler — it just leans on whichever signals are available.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// Path is where the learned per-hour baseline persists across
// restarts (typically <cacheDir>/outpost/sysload.json). Empty
// disables persistence (the baseline is learned fresh each boot).
Path string
// Frac is warm_budget_frac — the fraction of usable memory the host
// will dedicate to warm preload. <=0 or >1 falls back to 0.33.
Frac float64
SampleInterval time.Duration // 0 → 30s
CPUBusyPct float64 // 0 → 60
MinMemAvailFrac float64 // 0 → 0.25
EnterDelay time.Duration // 0 → 2m
ExitDelay time.Duration // 0 → 5m
BaselineFactor float64 // 0 → 1.5
Logger *slog.Logger
// contains filtered or unexported fields
}
Config tunes the profiler. Zero values fall back to the package defaults, so `New(Config{})` is a sensible always-on profiler. The operator-facing knob is Frac (warm_budget_frac); the thresholds are exposed for tests and future config surfaces.
type Profiler ¶
type Profiler struct {
// contains filtered or unexported fields
}
Profiler samples system load, learns the daily baseline, and answers Busy() / WarmBudgetBytes(). Safe for concurrent use: Run() is the single writer; Current()/Busy()/WarmBudgetBytes() read under the mutex.
func (*Profiler) Current ¶
Current returns the most recent sample. Zero-value At means the profiler hasn't sampled yet.
func (*Profiler) Run ¶
Run samples immediately, then on every SampleInterval, until ctx is cancelled. Always returns nil (a slow load probe is never fatal).
func (*Profiler) WarmBudgetBytes ¶
WarmBudgetBytes is the conservative memory the host will dedicate to warm preload: Frac × usableMem, or exactly 0 while Busy() (full yield). usableMem is the host's usable memory in bytes (typically total physical RAM; on unified-memory GPUs that's the shared pool).
func (*Profiler) WarmBudgetFrac ¶
WarmBudgetFrac returns the configured warm-budget fraction.
type Sample ¶
type Sample struct {
At time.Time `json:"at"`
CPUPercent float64 `json:"cpu_percent"` // effective system CPU %, 0..100; -1 unknown
MemAvailFrac float64 `json:"mem_avail_frac"` // available/total memory, 0..1; -1 unknown
Load1 float64 `json:"load1"` // 1-min load average; -1 unknown
Busy bool `json:"busy"`
}
Sample is one instantaneous reading, plus the debounced Busy verdict in effect after it was folded in. Negative fields mean "this host couldn't measure that signal" (e.g. no load average on Windows).