Documentation
¶
Overview ¶
Package hostload measures how busy a machine is, as a percent of all its cores: the CPU busy percent over an interval (the number Activity Monitor and top print), or, where that cannot be measured, the one-minute load average over the logical cores. A load average counts threads waiting as well as running, so it passes 100% on a machine that is not saturated; it is the fallback only.
Linux reads /proc/stat and /proc/loadavg. darwin asks top for its CPU usage line (a process of its own, so at most once every TopEvery) and reads vm.loadavg with sysctl, in Go. Elsewhere only a given value is known.
A member does not measure at its beat: a Sampler takes the busy percent once a second (Linux: /proc/stat counters, a read of a file; darwin: iostat, which takes its own second at about 4 ms of CPU, where top costs 300) and a Ring keeps the last ten, so the beat can carry the highest of them.
Every read of the machine is a Source function, so a caller measures with Local and a test with its own inputs; Measure is a pure function of the source, the state the previous measurement left, and the clock.
Beside the load, every measurement reads the machine's open file descriptors and, over a warn bound, the processes holding the most (files.go): the fleet beat carries the reading in the state it keeps.
Index ¶
- Constants
- func BusyPercent(prev, cur Ticks) (float64, bool)
- func FilesBounds(src Source) (warn, alarm int)
- func HoldersTimedOut(tool string) error
- func LoadPercent(load1 float64, ncpu int) float64
- func ParseFileNr(s string) (open, limit int, ok bool)
- func ParseProcLoadavg(s string) (float64, bool)
- func ParseTopCPU(s string) (float64, bool)
- type Files
- type Holder
- type Ring
- type Sampler
- type Source
- type State
- type Ticks
Constants ¶
const ( FilesWarnDefault = 50000 FilesAlarmDefault = 150000 )
The default bounds, the workshop tool's (fd-watch --warn and --alarm, 2026-10-03): a count of open descriptors above which the reading says warn, and alarm.
const ( LevelOK = "ok" LevelWarn = "warn" LevelAlarm = "alarm" )
The levels of a reading against its bounds.
const ( HowCPU = "cpu" // CPU busy percent over an interval HowLoad1 = "load1" // one-minute load average over the logical cores HowGiven = "given" // a load another meter gave (fleet beat --load) )
The ways a percent was measured.
const FilesTop = 10
FilesTop is how many holders a reading lists.
const HoldersEvery = 30 * time.Second
HoldersEvery is the least time between two reads of the holders: between them the last list stands.
const HoldersTimeout = 10 * time.Second
HoldersTimeout bounds one read of the holders, under a beat window: a read that runs over says so and the count stands with no list.
const MaxPercent = 1000.0
MaxPercent caps a measured percent: a load average over cores has no upper bound, and a cell wants a number that fits.
const RingSize = 10
RingSize is how many one-second samples the ring holds: the ten seconds the fleet table's load cell shows the highest of.
const TopEvery = 10 * time.Second
TopEvery is the least time between two runs of top on darwin: between them the last reading stands.
Variables ¶
This section is empty.
Functions ¶
func BusyPercent ¶
BusyPercent is the busy percent between two readings of the counters: false when the counters did not move forward (the same reading, or a reboot between them).
func FilesBounds ¶
FilesBounds is a source's bounds, each zero or less its default.
func HoldersTimedOut ¶
HoldersTimedOut is the reason a holders' read that ran past HoldersTimeout gives.
func LoadPercent ¶
LoadPercent is a load average over the logical cores as a percent, capped at MaxPercent; ncpu zero or less is runtime.NumCPU.
func ParseFileNr ¶
ParseFileNr is Linux's /proc/sys/fs/file-nr: the handles allocated, the unused (0 since 2.6) and the maximum.
func ParseProcLoadavg ¶
ParseProcLoadavg is the one-minute load average, the first field of /proc/loadavg ("0.52 0.58 0.59 1/389 12345").
func ParseTopCPU ¶
ParseTopCPU is darwin top's "CPU usage: a% user, b% sys, c% idle" line; busy is 100 minus idle.
Types ¶
type Files ¶
type Files struct {
At time.Time `json:"at"`
Open int `json:"open"`
Max int `json:"max,omitempty"`
Warn int `json:"warn"`
Alarm int `json:"alarm"`
Top []Holder `json:"top,omitempty"`
TopAt time.Time `json:"top_at,omitzero"`
TopErr string `json:"top_err,omitempty"`
}
Files is one reading of the machine's open file descriptors: when it was taken, the count and the system's limit (0 when not known), the bounds it was read against, and, over the warn bound, the processes holding the most, most first, when they were read, or why they could not be.
func MeasureFiles ¶
MeasureFiles is the reading at now: nil when the source cannot count the machine's descriptors. Over the warn bound it lists the top holders, read again once HoldersEvery has passed since the last read (the last reading's, prev), else kept.
type Holder ¶
type Holder struct {
PID int `json:"pid"`
Command string `json:"cmd"`
User string `json:"user,omitempty"`
Open int `json:"open"`
}
Holder is one process and how many file descriptors it has open.
func ProcHolders ¶
ProcHolders is every process under root (/proc) with its open descriptors: the entries of <pid>/fd, its command from <pid>/comm and its user from the owner of <pid>. A process this user cannot read, or that ended during the walk, is skipped; a walk still going at the deadline stops and says so.
func TopHolders ¶
TopHolders is the n holders with the most open, most first, the lower pid first of a tie.
type Ring ¶
type Ring struct {
// contains filtered or unexported fields
}
Ring is the last RingSize samples of a busy percent, each capped at MaxPercent. The zero Ring is empty.
type Sampler ¶
type Sampler struct {
// contains filtered or unexported fields
}
Sampler takes the machine's busy percent once a second into a Ring. Its readings are the Source's: ProcStat counters (the percent between two readings), else CPUSecond (a meter that takes its own second). Safe for use from the goroutine that runs it and the one that reads it.
func NewSampler ¶
NewSampler is a Sampler over src with nothing sampled yet.
func (*Sampler) Peak ¶
Peak is the highest sample added after the first since of them (at most the last RingSize), and how many samples there have been in all, which the caller passes as since next time once its beat is written; false when none is new.
func (*Sampler) Run ¶
Run steps once a second until ctx ends. A source that takes its own second sets the pace; one that does not is waited on for the rest of the second.
type Source ¶
type Source struct {
// NCPU is the logical cores; zero is runtime.NumCPU.
NCPU int
// ProcStat is the text of /proc/stat (Linux).
ProcStat func() (string, error)
// Top is the output of top's one-sample header (darwin).
Top func() (string, error)
// CPUSecond is the busy percent over the next second, taking that second
// (darwin: iostat). The Sampler's source where there is no ProcStat.
CPUSecond func() (float64, error)
// Load1 is the one-minute load average.
Load1 func() (float64, bool)
// Given is a load another meter gave, a percent of all the cores (fleet beat
// --load: a member's one-second samples): the measurement's load, HowGiven,
// with the open files measured beside it.
Given func() (float64, bool)
// OpenFiles is the system's open file descriptors and its limit (0 when not
// known): darwin's kern.num_files and kern.maxfiles, Linux's
// /proc/sys/fs/file-nr.
OpenFiles func() (open, limit int, err error)
// Holders is every process this user can see with its open descriptors
// (darwin: lsof; Linux: /proc/<pid>/fd), bounded by HoldersTimeout; read only
// over the warn bound.
Holders func() ([]Holder, error)
// FilesWarn and FilesAlarm are the bounds of the open descriptors, each zero
// or less its default (FilesWarnDefault, FilesAlarmDefault).
FilesWarn, FilesAlarm int
}
Source is how a machine is read. A nil function is a reading this machine does not have.
type State ¶
type State struct {
Ticks *Ticks `json:"ticks,omitempty"`
TopAt time.Time `json:"top_at,omitzero"`
TopPct float64 `json:"top_pct,omitempty"`
Files *Files `json:"files,omitempty"`
}
State is what one measurement leaves for the next: the last CPU counters (Linux, where the busy percent is the change between two readings), and the last top reading and when it was taken (darwin), and the last reading of the machine's open file descriptors (files.go), whose holders stand for HoldersEvery.
type Ticks ¶
Ticks is one reading of the kernel's cumulative CPU counters: busy is every tick but idle and iowait, total is every tick.
func ParseProcStat ¶
ParseProcStat is the cpu line of /proc/stat: user nice system idle iowait irq softirq steal guest guest_nice. guest and guest_nice overlap user and nice (Linux account_guest_time adds each guest interval to both USER/NICE and GUEST/GUEST_NICE, so /proc/stat emits the redundant fields), so they are parsed and validated but omitted from the total: counting them would sum the guest time twice and inflate the load. The guest tick stays inside user/nice, which is busy, so busy is every tick but idle and iowait as before.