/** * Linux ResourceMonitor backend. * * Reads: * - `/proc/pressure/memory` — global PSI (some + full) * - `/memory.pressure` — cleo.slice scoped PSI * - `/proc/meminfo` — MemAvailable * - `` size stat — WAL growth signal (DHQ-050 starvation class) * - `/proc//smaps_rollup` — per-child RSS (SEPARATE low-frequency path) * * ## Read-count discipline (Amendment 1) * * `sample()` calls the injected reader at most: * - 1× for `/proc/pressure/memory` * - 1× for the slice `memory.pressure` (if configured) * - 1× for `/proc/meminfo` * - N× stat calls for N configured WAL paths * * smaps_rollup reads are on a SEPARATE `sweepChildRss()` method and are * structurally impossible to reach from the `sample()` hot path. * * ## oomd threshold facts (Amendment 4) * * systemd-oomd on Fedora defaults to 80%/20s on user@1000.service. * Our hold/backoff thresholds (some avg10 >10% / full avg10 >5%) sit far * below that line, ensuring cleo always throttles before oomd kills. * * @module resources/linux-backend * @task T11994 * @epic T11992 */ import type { ChildRssSweep, PressureLine, PsiData, ResourceBackend, ResourceSample } from './backend.js'; /** * Injectable file-read function. Defaults to `fs/promises.readFile`. * * Tests inject a counting wrapper to assert bounded read-count without * relying on wall-clock timing (Amendment 1 — CI-stable formulation). */ export type ReadFileFn = (path: string, encoding: 'utf-8') => Promise; /** * Injectable stat function. Defaults to `fs/promises.stat`. * * Returns `null` when the file does not exist (ENOENT) or is unreadable. */ export type StatFileFn = (path: string) => Promise<{ size: number; } | null>; /** * Parse a single PSI line. * * Format: `some avg10=0.42 avg60=0.31 avg300=0.20 total=1234567` * * Returns `null` when the line does not match the expected format. */ export declare function parsePressureLine(line: string): PressureLine | null; /** * Parse a PSI file (two lines: `some ...` and `full ...`). * * Returns `null` when the content is unreadable / unparseable — callers * treat this as "pressure interface absent" (degraded mode). */ export declare function parsePsiFile(content: string): PsiData | null; /** * Parse `MemAvailable` from `/proc/meminfo`. * * Format: `MemAvailable: 42233788 kB` * * Returns `null` when the field is absent (non-Linux / old kernel). * Reuses the same parsing pattern as `packages/core/src/llm/local-model-fit.ts:269`. */ export declare function parseMemAvailable(content: string): number | null; /** * Parse a `/proc//smaps_rollup` file for RSS and PSS. * * Relevant fields: * `Rss: 12345 kB` * `Pss: 9876 kB` * * Returns `null` when either field is absent. */ export declare function parseSmapsRollup(content: string): { rssBytes: number; pssBytes: number; } | null; /** * Options for {@link LinuxResourceBackend}. */ export interface LinuxBackendOptions { /** * Path to the global PSI memory pressure file. * @defaultValue '/proc/pressure/memory' */ readonly globalPressurePath?: string; /** * Path to the cleo.slice cgroup v2 `memory.pressure` file. * * Common paths: * `/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/cleo.slice/memory.pressure` * * Set to `null` to disable slice-scoped sampling. * @defaultValue undefined (auto-detect disabled; callers supply the path) */ readonly cgroupSlicePressurePath?: string | null; /** * Absolute paths to SQLite `-wal` sidecar files to watch. * * WAL growth is a starvation signal (DHQ-050 class): a throttled reader * holding a read-mark prevents checkpoint → WAL regrows unboundedly. * Monitoring WAL size lets the governor correlate write-stall with * memory pressure. * * @defaultValue [] */ readonly walPaths?: readonly string[]; /** * Injectable file-read function (for testing). * @defaultValue fs/promises.readFile */ readonly readFileFn?: ReadFileFn; /** * Injectable stat function (for testing). * @defaultValue fs/promises.stat (ENOENT → null) */ readonly statFileFn?: StatFileFn; } /** * Linux implementation of {@link ResourceBackend}. * * Uses injected `readFileFn` / `statFileFn` so unit tests can: * 1. Fake file contents (threshold-crossing, degraded mode) * 2. Count reads to assert the bounded-read contract (Amendment 1) */ export declare class LinuxResourceBackend implements ResourceBackend { private readonly globalPressurePath; private readonly cgroupSlicePressurePath; private readonly walPaths; private readonly readFileFn; private readonly statFileFn; constructor(opts?: LinuxBackendOptions); /** * Take a bounded point-in-time resource sample. * * Read-count (bounded by Amendment 1): * - 1 read: `/proc/pressure/memory` * - 0–1 reads: slice `memory.pressure` (if configured) * - 1 read: `/proc/meminfo` * - N stat calls: one per WAL path in `walPaths` * * Never spawns a child process. */ sample(): Promise; /** * Sweep per-child RSS via `/proc//smaps_rollup`. * * **STRUCTURALLY SEPARATED from sample()** — smaps_rollup reads are * ms-scale per multi-GB process and must never appear in the hot path. * Call on a separate low-frequency cadence (e.g. every 60s or on * backoff→hold state transition). * * @param pids - PIDs to sweep. Dead/unknown PIDs are silently skipped. */ sweepChildRss(pids: readonly number[]): Promise; private _readPsi; private _readMemAvailable; private _readWalObservations; } //# sourceMappingURL=linux-backend.d.ts.map