1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
// Copyright 2020 Campbell Crowley. All rights reserved.
// Author: Campbell Crowley (dev@campbellcrowley.com)
const SubModule = require('./subModule.js');
/**
* @description Manages watching loop timings to help find causes of
* inconsistent event loops.
* @augments SubModule
*/
class CpuWatcher extends SubModule {
/**
* @description Manages watching loop timings to help find causes of
* inconsistent event loops.
*/
constructor() {
super();
/** @inheritdoc */
this.myName = 'CpuWatcher';
/**
* @description If a single event loop takes longer than this time, log that
* something went wrong.
* @private
* @type {number}
* @default 1000000 nanoseconds
* @constant
*/
this._loopWarnThresh = 1000000;
/**
* @description Flag of whether to keep monitoring the event loop timing.
* @private
* @type {boolean}
* @default
*/
this._watchLoop = false;
/**
* @description The timestamp of the last event loop start.
* @private
* @type {number}
* @default
*/
this._lastLoopTime = 0;
/**
* @description How often to log periodic event loop statistics.
* @private
* @type {number}
* @default 60 seconds
* @constant
*/
this._loopLogFrequency = 60000000;
/**
* @description Timestamp of the last time loop timings were logged.
* @private
* @type {number}
* @default
*/
this._loopLogTime = 0;
/**
* @description The amount of time the longest event loop took during the
* last interval.
* @private
* @type {number}
* @default
*/
this._maxLoopTime = 0;
/**
* @description The sum of all event loop delays during the last interval
* for averaging.
* @private
* @type {bigint}
* @default
*/
this._totalLoopTime = BigInt(0);
/**
* @description The number of event loops that took place during the last
* interval.
* @private
* @type {bigint}
* @default
*/
this._numLoops = BigInt(0);
this._queueLoopCheck = this._queueLoopCheck.bind(this);
}
/** @inheritdoc */
initialize() {
this._watchLoop = true;
setImmediate(this._queueLoopCheck);
}
/** @inheritdoc */
shutdown() {
this._watchLoop = false;
}
/**
* @description Time how long the next event loop will take. Calls itself
* every event loop until {@see _watchLoop} is set to false.
* @private
*/
_queueLoopCheck() {
const now = process.hrtime.bigint();
if (this._lastLoopTime != 0) {
const delta = now - this._lastLoopTime;
if (delta > this._loopWarnThresh) {
this.warn(`Previous event loop took: ${delta} nano seconds!`);
}
this._maxLoopTime =
(delta > this._maxLoopTime && this._maxLoopTime) || delta;
this._totalLoopTime += delta;
this._numLoops++;
} else {
this._loopLogTime = now;
}
if (now - this._loopLogTime > this._loopLogFrequency) {
this.debug(
'Loop Timings: Max: ' + this._maxLoopTime + ' Avg: ' +
(this._totalLoopTime / this._numLoops) + ' Sum: ' +
this._totalLoopTime + ' Duration: ' + this._loopLogFrequency);
this._maxLoopTime = 0;
this._totalLoopTime = BigInt(0);
this._numLoops = BigInt(0);
this._loopLogTime = now;
}
if (!this._watchLoop) return;
this._lastLoopTime = now;
setImmediate(this._queueLoopCheck);
}
}
module.exports = new CpuWatcher();