PEARDATA_PROCESSES_MS = 3k
This commit is contained in:
@@ -199,6 +199,9 @@ export class CgroupsCollector extends EventEmitter {
|
|||||||
/** @type {Map<string, string>} */
|
/** @type {Map<string, string>} */
|
||||||
this._names = new Map()
|
this._names = new Map()
|
||||||
this._nameRefreshAt = 0
|
this._nameRefreshAt = 0
|
||||||
|
/** @type {Array<{ id: string, title: string, path: string }>|null} */
|
||||||
|
this._cgCache = null
|
||||||
|
this._cgTs = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
@@ -253,18 +256,28 @@ export class CgroupsCollector extends EventEmitter {
|
|||||||
/** @type {Array<{ chart: string, context: string, ts: number, values: object }>} */
|
/** @type {Array<{ chart: string, context: string, ts: number, values: object }>} */
|
||||||
const batch = []
|
const batch = []
|
||||||
|
|
||||||
for (const cg of discoverCgroups()) {
|
const now = Date.now()
|
||||||
|
if (!this._cgCache || now - this._cgTs > 30000) {
|
||||||
|
this._cgCache = discoverCgroups()
|
||||||
|
this._cgTs = now
|
||||||
|
for (const cg of this._cgCache) {
|
||||||
|
const title = resolveContainerLabel(cg.title, this._names)
|
||||||
|
registerChart(makeCgroupCpuChart(cg.id, title))
|
||||||
|
registerChart(makeCgroupMemChart(cg.id, title))
|
||||||
|
registerChart(makeCgroupIoChart(cg.id, title))
|
||||||
|
registerChart(makeCgroupMemDetailChart(cg.id, title))
|
||||||
|
registerChart(makeCgroupThrottleChart(cg.id, title))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const cgList = this._cgCache
|
||||||
|
|
||||||
|
for (const cg of cgList) {
|
||||||
const title = resolveContainerLabel(cg.title, this._names)
|
const title = resolveContainerLabel(cg.title, this._names)
|
||||||
const cpuDef = makeCgroupCpuChart(cg.id, title)
|
const cpuDef = makeCgroupCpuChart(cg.id, title)
|
||||||
const memDef = makeCgroupMemChart(cg.id, title)
|
const memDef = makeCgroupMemChart(cg.id, title)
|
||||||
const ioDef = makeCgroupIoChart(cg.id, title)
|
const ioDef = makeCgroupIoChart(cg.id, title)
|
||||||
const memDetailDef = makeCgroupMemDetailChart(cg.id, title)
|
const memDetailDef = makeCgroupMemDetailChart(cg.id, title)
|
||||||
const throttleDef = makeCgroupThrottleChart(cg.id, title)
|
const throttleDef = makeCgroupThrottleChart(cg.id, title)
|
||||||
registerChart(cpuDef)
|
|
||||||
registerChart(memDef)
|
|
||||||
registerChart(ioDef)
|
|
||||||
registerChart(memDetailDef)
|
|
||||||
registerChart(throttleDef)
|
|
||||||
|
|
||||||
const cpu = parseCpuStat(cg.path)
|
const cpu = parseCpuStat(cg.path)
|
||||||
let usageUsec = cpu?.usage_usec ?? 0
|
let usageUsec = cpu?.usage_usec ?? 0
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ function registerTopChart(names, kind) {
|
|||||||
export class ProcessCollector extends EventEmitter {
|
export class ProcessCollector extends EventEmitter {
|
||||||
constructor(opts = {}) {
|
constructor(opts = {}) {
|
||||||
super()
|
super()
|
||||||
this.intervalMs = opts.intervalMs || Number(process.env.PEARDATA_PROCESSES_MS) || Number(process.env.PEARDATA_SAMPLE_MS) || SAMPLE_INTERVAL_MS
|
this.intervalMs = opts.intervalMs || Number(process.env.PEARDATA_PROCESSES_MS) || Number(process.env.PEARDATA_SAMPLE_MS) || 3000
|
||||||
this._timer = null
|
this._timer = null
|
||||||
/** @type {Map<number, { ticks: number, wallMs: number, name: string, readBytes: number, writeBytes: number }>|null} */
|
/** @type {Map<number, { ticks: number, wallMs: number, name: string, readBytes: number, writeBytes: number }>|null} */
|
||||||
this._prev = null
|
this._prev = null
|
||||||
|
|||||||
@@ -78,16 +78,66 @@ function makeSensorPowerChart(chip, label) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Array<{ chartId: string, context: string, values: Record<string, number> }>}
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* @returns {Array<{ chartId: string, context: string, values: Record<string, number> }>}
|
* @returns {Array<{ chartId: string, context: string, values: Record<string, number> }>}
|
||||||
*/
|
*/
|
||||||
export function sampleSensors() {
|
export function sampleSensors() {
|
||||||
/** @type {Array<{ chartId: string, context: string, values: Record<string, number> }>} */
|
/** @type {Array<{ chartId: string, context: string, values: Record<string, number> }>} */
|
||||||
const out = []
|
const out = []
|
||||||
|
|
||||||
|
for (const entry of getSensorPaths()) {
|
||||||
|
let raw
|
||||||
|
if (entry._type === 'temp') {
|
||||||
|
raw = readFile(entry._inputPath)
|
||||||
|
if (raw == null) continue
|
||||||
|
const milli = Number(raw.trim())
|
||||||
|
if (!Number.isFinite(milli)) continue
|
||||||
|
out.push({ chartId: entry.chartId, context: entry.context, values: { temperature: milli / 1000 } })
|
||||||
|
} else if (entry._type === 'fan') {
|
||||||
|
raw = readFile(entry._inputPath)
|
||||||
|
if (raw == null) continue
|
||||||
|
const rpm = Number(raw.trim())
|
||||||
|
if (!Number.isFinite(rpm)) continue
|
||||||
|
out.push({ chartId: entry.chartId, context: entry.context, values: { rpm } })
|
||||||
|
} else if (entry._type === 'volt') {
|
||||||
|
raw = readFile(entry._inputPath)
|
||||||
|
if (raw == null) continue
|
||||||
|
const mv = Number(raw.trim())
|
||||||
|
if (!Number.isFinite(mv)) continue
|
||||||
|
out.push({ chartId: entry.chartId, context: entry.context, values: { millivolts: mv } })
|
||||||
|
} else if (entry._type === 'power') {
|
||||||
|
raw = readFile(entry._inputPath)
|
||||||
|
if (raw == null) continue
|
||||||
|
const uw = Number(raw.trim())
|
||||||
|
if (!Number.isFinite(uw)) continue
|
||||||
|
out.push({ chartId: entry.chartId, context: entry.context, values: { microwatts: uw } })
|
||||||
|
} else if (entry._type === 'thermal') {
|
||||||
|
raw = readFile(entry._inputPath)
|
||||||
|
if (raw == null) continue
|
||||||
|
const milli = Number(raw.trim())
|
||||||
|
if (!Number.isFinite(milli) || milli === 0) continue
|
||||||
|
const celsius = milli > 1000 ? milli / 1000 : milli
|
||||||
|
out.push({ chartId: entry.chartId, context: entry.context, values: { temperature: celsius } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
let _sensorPaths = null
|
||||||
|
let _sensorPathsTs = 0
|
||||||
|
|
||||||
|
function getSensorPaths() {
|
||||||
|
const now = Date.now()
|
||||||
|
if (_sensorPaths && now - _sensorPathsTs < 30000) return _sensorPaths
|
||||||
|
_sensorPaths = []
|
||||||
|
_sensorPathsTs = now
|
||||||
|
|
||||||
const hwmonRoot = '/sys/class/hwmon'
|
const hwmonRoot = '/sys/class/hwmon'
|
||||||
try {
|
try {
|
||||||
const chips = fs.readdirSync(hwmonRoot)
|
for (const chip of fs.readdirSync(hwmonRoot)) {
|
||||||
for (const chip of chips) {
|
|
||||||
const dir = path.join(hwmonRoot, chip)
|
const dir = path.join(hwmonRoot, chip)
|
||||||
const name = (readFile(path.join(dir, 'name')) || chip).trim()
|
const name = (readFile(path.join(dir, 'name')) || chip).trim()
|
||||||
let ents
|
let ents
|
||||||
@@ -98,60 +148,40 @@ export function sampleSensors() {
|
|||||||
}
|
}
|
||||||
for (const ent of ents) {
|
for (const ent of ents) {
|
||||||
const m = ent.match(/^temp(\d+)_input$/)
|
const m = ent.match(/^temp(\d+)_input$/)
|
||||||
if (!m) continue
|
if (m) {
|
||||||
const n = m[1]
|
const n = m[1]
|
||||||
const raw = readFile(path.join(dir, ent))
|
const label = (readFile(path.join(dir, `temp${n}_label`)) || `temp${n}`).trim() || `temp${n}`
|
||||||
if (raw == null) continue
|
const def = makeSensorTempChart(name, label)
|
||||||
const milli = Number(raw.trim())
|
registerChart(def)
|
||||||
if (!Number.isFinite(milli)) continue
|
_sensorPaths.push({ chartId: def.id, context: def.context, _type: 'temp', _inputPath: path.join(dir, ent) })
|
||||||
const label =
|
continue
|
||||||
(readFile(path.join(dir, `temp${n}_label`)) || `temp${n}`).trim() || `temp${n}`
|
}
|
||||||
const def = makeSensorTempChart(name, label)
|
const fan = ent.match(/^fan(\d+)_input$/)
|
||||||
registerChart(def)
|
if (fan) {
|
||||||
out.push({
|
const n = fan[1]
|
||||||
chartId: def.id,
|
const label = (readFile(path.join(dir, `fan${n}_label`)) || `fan${n}`).trim() || `fan${n}`
|
||||||
context: def.context,
|
const def = makeSensorFanChart(name, label)
|
||||||
values: { temperature: milli / 1000 },
|
registerChart(def)
|
||||||
})
|
_sensorPaths.push({ chartId: def.id, context: def.context, _type: 'fan', _inputPath: path.join(dir, ent) })
|
||||||
}
|
continue
|
||||||
const fan = ent.match(/^fan(\d+)_input$/)
|
}
|
||||||
if (fan) {
|
const vin = ent.match(/^in(\d+)_input$/)
|
||||||
const n = fan[1]
|
if (vin) {
|
||||||
const raw = readFile(path.join(dir, ent))
|
const n = vin[1]
|
||||||
if (raw == null) continue
|
const label = (readFile(path.join(dir, `in${n}_label`)) || `in${n}`).trim() || `in${n}`
|
||||||
const rpm = Number(raw.trim())
|
const def = makeSensorVoltageChart(name, label)
|
||||||
if (!Number.isFinite(rpm)) continue
|
registerChart(def)
|
||||||
const label =
|
_sensorPaths.push({ chartId: def.id, context: def.context, _type: 'volt', _inputPath: path.join(dir, ent) })
|
||||||
(readFile(path.join(dir, `fan${n}_label`)) || `fan${n}`).trim() || `fan${n}`
|
continue
|
||||||
const def = makeSensorFanChart(name, label)
|
}
|
||||||
registerChart(def)
|
const pwr = ent.match(/^power(\d+)_input$/)
|
||||||
out.push({ chartId: def.id, context: def.context, values: { rpm } })
|
if (pwr) {
|
||||||
}
|
const n = pwr[1]
|
||||||
const vin = ent.match(/^in(\d+)_input$/)
|
const label = (readFile(path.join(dir, `power${n}_label`)) || `power${n}`).trim() || `power${n}`
|
||||||
if (vin) {
|
const def = makeSensorPowerChart(name, label)
|
||||||
const n = vin[1]
|
registerChart(def)
|
||||||
const raw = readFile(path.join(dir, ent))
|
_sensorPaths.push({ chartId: def.id, context: def.context, _type: 'power', _inputPath: path.join(dir, ent) })
|
||||||
if (raw == null) continue
|
}
|
||||||
const mv = Number(raw.trim())
|
|
||||||
if (!Number.isFinite(mv)) continue
|
|
||||||
const label =
|
|
||||||
(readFile(path.join(dir, `in${n}_label`)) || `in${n}`).trim() || `in${n}`
|
|
||||||
const def = makeSensorVoltageChart(name, label)
|
|
||||||
registerChart(def)
|
|
||||||
out.push({ chartId: def.id, context: def.context, values: { millivolts: mv } })
|
|
||||||
}
|
|
||||||
const pwr = ent.match(/^power(\d+)_input$/)
|
|
||||||
if (pwr) {
|
|
||||||
const n = pwr[1]
|
|
||||||
const raw = readFile(path.join(dir, ent))
|
|
||||||
if (raw == null) continue
|
|
||||||
const uw = Number(raw.trim())
|
|
||||||
if (!Number.isFinite(uw)) continue
|
|
||||||
const label =
|
|
||||||
(readFile(path.join(dir, `power${n}_label`)) || `power${n}`).trim() || `power${n}`
|
|
||||||
const def = makeSensorPowerChart(name, label)
|
|
||||||
registerChart(def)
|
|
||||||
out.push({ chartId: def.id, context: def.context, values: { microwatts: uw } })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
@@ -164,20 +194,15 @@ export function sampleSensors() {
|
|||||||
if (!zone.startsWith('thermal_zone')) continue
|
if (!zone.startsWith('thermal_zone')) continue
|
||||||
const dir = path.join(thermalRoot, zone)
|
const dir = path.join(thermalRoot, zone)
|
||||||
const type = (readFile(path.join(dir, 'type')) || zone).trim()
|
const type = (readFile(path.join(dir, 'type')) || zone).trim()
|
||||||
const raw = readFile(path.join(dir, 'temp'))
|
|
||||||
if (raw == null) continue
|
|
||||||
const milli = Number(raw.trim())
|
|
||||||
if (!Number.isFinite(milli) || milli === 0) continue
|
|
||||||
// some platforms report already in C
|
|
||||||
const celsius = milli > 1000 ? milli / 1000 : milli
|
|
||||||
const def = makeThermalZoneChart(zone, type)
|
const def = makeThermalZoneChart(zone, type)
|
||||||
registerChart(def)
|
registerChart(def)
|
||||||
out.push({ chartId: def.id, context: def.context, values: { temperature: celsius } })
|
_sensorPaths.push({ chartId: def.id, context: def.context, _type: 'thermal', _inputPath: path.join(dir, 'temp') })
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// no thermal
|
// no thermal
|
||||||
}
|
}
|
||||||
return out
|
|
||||||
|
return _sensorPaths
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SensorsCollector extends EventEmitter {
|
export class SensorsCollector extends EventEmitter {
|
||||||
|
|||||||
Reference in New Issue
Block a user