Fix polling of /proc/stat on Linux by caching (#48750)
Resolves #46461. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. --- Verification command (checks how many times /proc/stat is read): ``` sudo bpftrace -e ' tracepoint:syscalls:sys_enter_openat /str(args->filename) == "/proc/stat" || str(args->filename) == "/proc/uptime"/ { @[comm, str(args->filename)] = count(); } interval:s:60 { exit(); }' ``` 1.57.0 outputs: ``` @[orbit, /proc/stat]: 1084 ``` fleetd built with changes in this PR (and I had to trigger a restart, otherwise it's 0): ``` @[orbit, /proc/stat]: 3 [...] @[fleet-desktop, /proc/stat]: 6 ``` ## Testing - [X] QA'd all new/changed functionality manually ## fleetd/orbit/Fleet Desktop - [x] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [X] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [X] Verified that fleetd runs on macOS, Linux and Windows - [X] Verified auto-update works from the released version of component to the new version (see [tools/tuf/test](../tools/tuf/test/README.md)) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved process listing performance on Linux by reducing repeated system boot-time reads. * Prevented unnecessary refreshes during frequent process checks, helping watchdog-style polling run more efficiently. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- Fixed orbit repeatedly reading `/proc/stat` (and `/proc/uptime` on containerized hosts) once per running process every time it enumerated the process table (for example, the Fleet Desktop watchdog that polls every 15s). Orbit now caches the system boot time, eliminating the redundant reads.
|
||||
@@ -0,0 +1,35 @@
|
||||
//go:build linux
|
||||
|
||||
package platform
|
||||
|
||||
import (
|
||||
gopsutil_process "github.com/shirou/gopsutil/v4/process"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Enable gopsutil's boot-time cache (Linux only).
|
||||
//
|
||||
// gopsutil_process.Processes() builds a Process for every PID, and the
|
||||
// constructor (NewProcess -> CreateTime -> fillFromStat) computes each
|
||||
// process' creation time, which requires the system boot time. By default
|
||||
// gopsutil does NOT cache the boot time, so on Linux it re-reads /proc/stat
|
||||
// (or /proc/uptime on containerized hosts) once per process, on every call.
|
||||
//
|
||||
// orbit enumerates the full process table on a recurring basis (e.g. the
|
||||
// Fleet Desktop watchdog polls every 15s via GetProcessesByName), so this
|
||||
// caused the host-wide /proc/stat file to be read N times per poll, where N
|
||||
// is the total number of running processes. The btime field lives near the
|
||||
// end of /proc/stat, so each read scans the entire file just to recover a
|
||||
// single constant value.
|
||||
//
|
||||
// The system boot time does not change for the lifetime of the orbit
|
||||
// process, so caching it is safe and collapses those repeated reads into a
|
||||
// single one. This is scoped to Linux because that is where the redundant
|
||||
// file reads occur; macOS and Windows obtain boot time via syscall/sysctl.
|
||||
//
|
||||
// Note: orbit only reads process Name/Pid and never a process' CreateTime,
|
||||
// so the cache cannot surface a stale value (the gopsutil README warns that
|
||||
// a cached boot time can drift if NTP steps the clock after boot, which only
|
||||
// affects CreateTime).
|
||||
gopsutil_process.EnableBootTimeCache(true)
|
||||
}
|
||||
Reference in New Issue
Block a user