Further CPU Experimental Changes
CI / test (push) Failing after 4s
Release rolling / release (push) Successful in 7m14s

This commit is contained in:
Raven Scott
2026-07-21 12:17:06 -04:00
parent 1d902a89b0
commit ac4718cb66
11 changed files with 87 additions and 85 deletions
+3 -5
View File
@@ -6,6 +6,7 @@ import fs from 'fs'
import path from 'path'
import { CollectorPlugin } from './plugin.js'
import { registerChart } from '../../../shared/metrics.js'
import { readFileBuf } from '../../utils/fd-cache.js'
export function isBcacheEnabled() {
const v = process.env.PEARDATA_BCACHE
@@ -15,11 +16,8 @@ export function isBcacheEnabled() {
}
function readNum(p) {
try {
return Number(fs.readFileSync(p, 'utf8').trim()) || 0
} catch {
return 0
}
const raw = readFileBuf(p)
return raw ? Number(raw.trim()) || 0 : 0
}
export class BcacheCollector extends CollectorPlugin {
+2 -5
View File
@@ -20,6 +20,7 @@ import {
} from '../../../shared/metrics.js'
import { resolveContainerLabel } from '../../../shared/container-names.js'
import { loadContainerNameMap, resolveDockerSocket } from './docker.js'
import { readFileBuf } from '../../utils/fd-cache.js'
import logger from '../../utils/logger.js'
const log = logger.child('cgroups')
@@ -37,11 +38,7 @@ function maxCgroups() {
}
function readFile(p) {
try {
return fs.readFileSync(p, 'utf8')
} catch {
return null
}
return readFileBuf(p)
}
function cgroupRoot() {
+2 -5
View File
@@ -10,6 +10,7 @@ import fs from 'fs'
import path from 'path'
import { CollectorPlugin } from './plugin.js'
import { registerChart } from '../../../shared/metrics.js'
import { readFileBuf } from '../../utils/fd-cache.js'
import { execFile } from '../../utils/exec.js'
import logger from '../../utils/logger.js'
@@ -39,11 +40,7 @@ export function isDmcacheEnabled() {
}
function readFile(p) {
try {
return fs.readFileSync(p, 'utf8')
} catch {
return null
}
return readFileBuf(p)
}
/**
+2 -5
View File
@@ -16,6 +16,7 @@ import net from 'net'
import os from 'os'
import { EventEmitter } from 'events'
import { execFile } from '../../utils/exec.js'
import { readFileBuf } from '../../utils/fd-cache.js'
import {
SAMPLE_INTERVAL_MS,
registerChart,
@@ -59,11 +60,7 @@ export function resolveDockerSocket(preferred) {
}
function readFile(p) {
try {
return fs.readFileSync(p, 'utf8')
} catch {
return null
}
return readFileBuf(p)
}
function bytesToMiB(n) {
+13 -16
View File
@@ -16,6 +16,7 @@ import {
SAMPLE_INTERVAL_MS,
registerChart,
} from '../../../shared/metrics.js'
import { readFileCached, readFileBuf } from '../../utils/fd-cache.js'
import { extractHelper, hasEmbeddedHelper } from '../../native/extract-helper.js'
import logger from '../../utils/logger.js'
@@ -202,13 +203,12 @@ export class EbpfCollector extends EventEmitter {
_readVm() {
/** @type {Record<string, number>} */
const out = {}
try {
for (const line of fs.readFileSync('/proc/vmstat', 'utf8').split('\n')) {
const raw = readFileCached('/proc/vmstat')
if (raw) {
for (const line of raw.split('\n')) {
const [k, v] = line.trim().split(/\s+/)
if (k) out[k] = Number(v) || 0
}
} catch {
// ignore
}
return out
}
@@ -228,30 +228,27 @@ export class EbpfCollector extends EventEmitter {
const den = dHit + dMiss
let fileNr = [0, 0]
try {
const parts = fs.readFileSync('/proc/sys/fs/file-nr', 'utf8').trim().split(/\s+/)
const fileNrRaw = readFileCached('/proc/sys/fs/file-nr')
if (fileNrRaw) {
const parts = fileNrRaw.trim().split(/\s+/)
fileNr = [Number(parts[0]) || 0, Number(parts[2]) || 0]
} catch {
// ignore
}
let forks = 0
let ctxt = 0
try {
for (const line of fs.readFileSync('/proc/stat', 'utf8').split('\n')) {
const statRaw = readFileCached('/proc/stat')
if (statRaw) {
for (const line of statRaw.split('\n')) {
if (line.startsWith('processes ')) forks = Number(line.slice(10)) || 0
if (line.startsWith('ctxt ')) ctxt = Number(line.slice(5)) || 0
}
} catch {
// ignore
}
let tcp = 0
try {
const m = fs.readFileSync('/proc/net/sockstat', 'utf8').match(/TCP:\s+inuse\s+(\d+)/)
const sockRaw = readFileCached('/proc/net/sockstat')
if (sockRaw) {
const m = sockRaw.match(/TCP:\s+inuse\s+(\d+)/)
if (m) tcp = Number(m[1]) || 0
} catch {
// ignore
}
const batch = [
+2 -5
View File
@@ -11,6 +11,7 @@ import path from 'path'
import os from 'os'
import { CollectorPlugin } from './plugin.js'
import { registerChart } from '../../../shared/metrics.js'
import { readFileBuf } from '../../utils/fd-cache.js'
import logger from '../../utils/logger.js'
const log = logger.child('fs-stats')
@@ -23,11 +24,7 @@ export function isFsStatsEnabled() {
}
function readFile(p) {
try {
return fs.readFileSync(p, 'utf8')
} catch {
return null
}
return readFileBuf(p)
}
function readNum(p) {
+2 -5
View File
@@ -9,6 +9,7 @@ import fs from 'fs'
import os from 'os'
import { EventEmitter } from 'events'
import { SAMPLE_INTERVAL_MS, registerChart } from '../../../shared/metrics.js'
import { readFileBuf } from '../../utils/fd-cache.js'
import logger from '../../utils/logger.js'
const log = logger.child('mdstat')
@@ -31,11 +32,7 @@ const CHART_HEALTH = {
}
function readFile(p) {
try {
return fs.readFileSync(p, 'utf8')
} catch {
return null
}
return readFileBuf(p)
}
/**
+29 -19
View File
@@ -17,6 +17,7 @@ import path from 'path'
import os from 'os'
import { EventEmitter } from 'events'
import { SAMPLE_INTERVAL_MS, registerChart } from '../../../shared/metrics.js'
import { readFileBuf } from '../../utils/fd-cache.js'
import logger from '../../utils/logger.js'
const log = logger.child('processes')
@@ -50,6 +51,10 @@ function sanitizeDim(name) {
return s || 'unknown'
}
const PROC_EXTRA_CACHE = new Map()
const PROC_EXTRA_TICK = 5
let procTickCount = 0
/**
* @returns {Array<{ pid: number, name: string, utime: number, stime: number, rssPages: number, threads: number, readBytes: number|null, writeBytes: number|null }>|null}
*/
@@ -61,47 +66,52 @@ export function listProcStats() {
} catch {
return null
}
procTickCount = (procTickCount + 1) % PROC_EXTRA_TICK
const readExtra = procTickCount === 0
/** @type {Array<{ pid: number, name: string, utime: number, stime: number, rssPages: number, threads: number, readBytes: number|null, writeBytes: number|null }>} */
const out = []
for (const ent of dirs) {
if (!/^\d+$/.test(ent)) continue
const pid = Number(ent)
let raw
try {
raw = fs.readFileSync(path.join('/proc', ent, 'stat'), 'utf8')
} catch {
continue
}
const raw = readFileBuf(path.join('/proc', ent, 'stat'))
if (!raw) continue
const open = raw.indexOf('(')
const close = raw.lastIndexOf(')')
if (open < 0 || close < open) continue
const name = raw.slice(open + 1, close)
const rest = raw.slice(close + 2).split(/\s+/)
// fields after comm: state(0) … utime(11) stime(12) … rss(21)
const utime = Number(rest[11])
const stime = Number(rest[12])
const rssPages = Number(rest[21])
if (!Number.isFinite(utime) || !Number.isFinite(stime)) continue
let threads = 0
try {
const status = fs.readFileSync(path.join('/proc', ent, 'status'), 'utf8')
const m = status.match(/^Threads:\s*(\d+)/m)
if (m) threads = Number(m[1]) || 0
} catch {
// ignore
}
let readBytes = null
let writeBytes = null
try {
const ioRaw = fs.readFileSync(path.join('/proc', ent, 'io'), 'utf8')
if (readExtra) {
const status = readFileBuf(path.join('/proc', ent, 'status'))
if (status) {
const m = status.match(/^Threads:\s*(\d+)/m)
if (m) threads = Number(m[1]) || 0
}
const ioRaw = readFileBuf(path.join('/proc', ent, 'io'))
if (ioRaw) {
const rb = ioRaw.match(/^read_bytes:\s*(\d+)/m)
const wb = ioRaw.match(/^write_bytes:\s*(\d+)/m)
if (rb) readBytes = Number(rb[1]) || 0
if (wb) writeBytes = Number(wb[1]) || 0
} catch {
// unreadable for this pid
}
}
const cached = PROC_EXTRA_CACHE.get(pid)
if (cached) {
if (threads === 0) threads = cached.threads
if (readBytes === null) readBytes = cached.readBytes
if (writeBytes === null) writeBytes = cached.writeBytes
}
if (readExtra || !cached) {
PROC_EXTRA_CACHE.set(pid, { threads, readBytes, writeBytes })
}
out.push({
+2 -5
View File
@@ -14,6 +14,7 @@ import {
makeSensorTempChart,
makeThermalZoneChart,
} from '../../../shared/metrics.js'
import { readFileBuf } from '../../utils/fd-cache.js'
import logger from '../../utils/logger.js'
const log = logger.child('sensors')
@@ -26,11 +27,7 @@ export function isSensorsEnabled() {
}
function readFile(p) {
try {
return fs.readFileSync(p, 'utf8')
} catch {
return null
}
return readFileBuf(p)
}
function makeSensorFanChart(chip, label) {
+6 -11
View File
@@ -6,6 +6,7 @@ import fs from 'fs'
import os from 'os'
import { EventEmitter } from 'events'
import { SAMPLE_INTERVAL_MS, registerChart } from '../../../shared/metrics.js'
import { readFileBuf } from '../../utils/fd-cache.js'
import logger from '../../utils/logger.js'
const log = logger.child('sockets')
@@ -42,12 +43,8 @@ function countTcp(file) {
syn_recv: 0,
other: 0,
}
let raw
try {
raw = fs.readFileSync(file, 'utf8')
} catch {
return counts
}
const raw = readFileBuf(file)
if (!raw) return counts
for (const line of raw.split('\n').slice(1)) {
const parts = line.trim().split(/\s+/)
if (parts.length < 4) continue
@@ -60,11 +57,9 @@ function countTcp(file) {
}
function countUdp(file) {
try {
return Math.max(0, fs.readFileSync(file, 'utf8').trim().split('\n').length - 1)
} catch {
return 0
}
const raw = readFileBuf(file)
if (!raw) return 0
return Math.max(0, raw.trim().split('\n').length - 1)
}
export class SocketsCollector extends EventEmitter {
+20
View File
@@ -1,6 +1,7 @@
import fs from 'fs'
const READ_BUF = Buffer.alloc(65536)
const SMALL_BUF = Buffer.alloc(8192)
const fdCache = new Map()
export function readFileCached(path) {
@@ -24,6 +25,25 @@ export function readFileCached(path) {
}
}
/**
* Read a file using the shared small buffer, no FD caching.
* Good for dynamic paths (per-PID, per-cgroup) where open+close each tick is acceptable
* but Buffer allocation is not.
*/
export function readFileBuf(path) {
try {
const fd = fs.openSync(path, 'r')
try {
const bytes = fs.readSync(fd, SMALL_BUF, 0, SMALL_BUF.length, 0)
return SMALL_BUF.toString('utf8', 0, bytes)
} finally {
fs.closeSync(fd)
}
} catch {
return null
}
}
export function closeFdCache() {
for (const [path, entry] of fdCache) {
if (entry) {