CPU and state topology is cached for 30s.
This commit is contained in:
@@ -216,6 +216,7 @@ export class CgroupsCollector extends EventEmitter {
|
||||
/** @type {Array<{ id: string, title: string, path: string }>|null} */
|
||||
this._cgCache = null
|
||||
this._cgTs = 0
|
||||
this._cgTick = 0
|
||||
}
|
||||
|
||||
start() {
|
||||
@@ -285,6 +286,9 @@ export class CgroupsCollector extends EventEmitter {
|
||||
}
|
||||
}
|
||||
const cgList = this._cgCache
|
||||
const doMemDetail = this._cgTick % 5 === 0
|
||||
const doPressure = this._cgTick % 3 === 0
|
||||
this._cgTick++
|
||||
|
||||
for (const cg of cgList) {
|
||||
const title = resolveContainerLabel(cg.title, this._names)
|
||||
@@ -347,7 +351,10 @@ export class CgroupsCollector extends EventEmitter {
|
||||
},
|
||||
})
|
||||
|
||||
const memStat = profile('memStat:' + cg.id.slice(0,20), () => parseMemoryStat(cg.path))
|
||||
let memStat = null
|
||||
if (doMemDetail) {
|
||||
memStat = profile('memStat:' + cg.id.slice(0,20), () => parseMemoryStat(cg.path))
|
||||
}
|
||||
if (memStat) {
|
||||
batch.push({
|
||||
chart: memDetailDef.id,
|
||||
@@ -374,6 +381,7 @@ export class CgroupsCollector extends EventEmitter {
|
||||
values: { throttled: throttlePct },
|
||||
})
|
||||
|
||||
if (doPressure) {
|
||||
for (const kind of ['cpu', 'memory', 'io']) {
|
||||
const some10 = parsePressureSome10(cg.path, kind)
|
||||
if (some10 == null) continue
|
||||
@@ -386,6 +394,7 @@ export class CgroupsCollector extends EventEmitter {
|
||||
values: { some10 },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.prev.set(cg.id, {
|
||||
usage: usageUsec,
|
||||
|
||||
@@ -208,6 +208,10 @@ export function collectNumaNodes(batch, ts) {
|
||||
*/
|
||||
export function collectCpuidle(batch, ts, dtSec, state) {
|
||||
if (os.platform() !== 'linux') return
|
||||
// cache cpuidle state paths for 30s — topology doesn't change at runtime
|
||||
let cpuidlePaths = state._cpuidlePaths
|
||||
const now = Date.now()
|
||||
if (!cpuidlePaths || now - cpuidlePaths.ts > 30000) {
|
||||
const cpuRoot = '/sys/devices/system/cpu'
|
||||
let dirs
|
||||
try {
|
||||
@@ -215,10 +219,8 @@ export function collectCpuidle(batch, ts, dtSec, state) {
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
const prevAll = state.lastIdle || {}
|
||||
/** @type {Record<string, Record<string, number>>} */
|
||||
const nextAll = {}
|
||||
|
||||
/** @type {Record<string, Array<{ nameFile: string, timeFile: string }>>} */
|
||||
const entries = {}
|
||||
for (const d of dirs) {
|
||||
const coreId = d.slice(3)
|
||||
const idleDir = path.join(cpuRoot, d, 'cpuidle')
|
||||
@@ -228,12 +230,31 @@ export function collectCpuidle(batch, ts, dtSec, state) {
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
const files = []
|
||||
for (const s of states) {
|
||||
files.push({
|
||||
nameFile: path.join(idleDir, s, 'name'),
|
||||
timeFile: path.join(idleDir, s, 'time'),
|
||||
})
|
||||
}
|
||||
if (files.length) entries[coreId] = files
|
||||
}
|
||||
cpuidlePaths = { ts: now, entries, cpuDirs: dirs }
|
||||
state._cpuidlePaths = cpuidlePaths
|
||||
}
|
||||
const { entries } = cpuidlePaths
|
||||
const prevAll = state.lastIdle || {}
|
||||
/** @type {Record<string, Record<string, number>>} */
|
||||
const nextAll = {}
|
||||
|
||||
for (const coreId of Object.keys(entries)) {
|
||||
const files = entries[coreId]
|
||||
/** @type {Record<string, number>} */
|
||||
const times = {}
|
||||
for (const s of states) {
|
||||
const name = (readFile(path.join(idleDir, s, 'name')) || s).trim().toLowerCase().replace(/\s+/g, '_')
|
||||
const t = Number(readFile(path.join(idleDir, s, 'time')) || 0) // µs
|
||||
times[name || s] = t
|
||||
for (const { nameFile, timeFile } of files) {
|
||||
const name = (readFile(nameFile) || '').trim().toLowerCase().replace(/\s+/g, '_')
|
||||
const t = Number(readFile(timeFile) || 0) // µs
|
||||
times[name || 'state'] = t
|
||||
}
|
||||
nextAll[coreId] = times
|
||||
const prev = prevAll[coreId]
|
||||
|
||||
Reference in New Issue
Block a user