/// import * as LibUtil from "util"; import {exec} from "child_process"; import Timer = NodeJS.Timer; import CpuUsage = NodeJS.CpuUsage; const execp = LibUtil.promisify(exec) as (cmd: string) => Promise<{stdout: string, stderr: string}>; export declare type Hrtime = [number, number]; export interface LoadInfo { hrtime: Hrtime; usage: CpuUsage; } export interface LoadResult { user: number; system: number; total: number; } export declare type LoadListener = (totalPercentage: number, userPercentage: number, systemPercentage: number) => void; export class ProcessCPULoad { private _mode: "node" | "linux" = "node"; private _interval: number = 1000; // 1s private _psCommand: string = 'ps -p $PID -o %cpu | grep -v "%CPU"'; private _timer: Timer = null; private _prevLoadInfo: LoadInfo = null; constructor(mode: "node" | "linux" = "node") { this._mode = mode; } public start(listener: LoadListener, interval: number = this._interval): void { if (this._timer !== null) { // already running, have to stop first return; } this._timer = setInterval(async () => { const usage = await this._calc(); if (usage !== null) { // means correct data listener(usage.total, usage.user, usage.system); } }, interval); } public stop(): void { clearInterval(this._timer); this._timer = null; } private async _calc(): Promise { if (this._mode === "node") { return await this._calcModeNode(); } else { return await this._calcModeLinux(); } } private async _calcModeNode(): Promise { if (this._prevLoadInfo === null) { // no previous data, init it this._setLoadInfo(); return Promise.resolve(null); } const elapTime: Hrtime = process.hrtime(this._prevLoadInfo.hrtime); const elapUsage: CpuUsage = process.cpuUsage(this._prevLoadInfo.usage); const elapTimeMS = this._hrtimeToMs(elapTime); const elapUserMS = this._usageTimeToMs(elapUsage.user); const elapSystMS = this._usageTimeToMs(elapUsage.system); const total = this._calcPercentage(elapUserMS + elapSystMS, elapTimeMS); const user = this._calcPercentage(elapUserMS, elapTimeMS); const system = this._calcPercentage(elapSystMS, elapTimeMS); this._setLoadInfo(); return Promise.resolve({ total: total, user: user, system: system, } as LoadResult); } private async _calcModeLinux(): Promise { const {stdout} = await execp(this._psCommand.replace("$PID", process.pid.toString())); return Promise.resolve({ total: parseFloat(stdout.trim()), user: null, system: null, } as LoadResult); } private _setLoadInfo(): void { this._prevLoadInfo = { hrtime: process.hrtime(), usage: process.cpuUsage(), } as LoadInfo; } private _hrtimeToMs(time: Hrtime): number { return Math.round(time[0] * 1000 + time[1] / 1000000); // secondToMs + nanosecondToMs } private _usageTimeToMs(time: number): number { return Math.round(time / 1000); // microsecondToMs } private _calcPercentage(numerator: number, denominator: number): number { return parseFloat((100 * numerator / denominator).toFixed(1)) } }