-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* bitswap stats: async updater * linter happy * pre-commit hook for linting and tests * stats: support dataReceived * stats: data received * stats: blocks sent and data sent * stats: using bignum * stats: compute throttle with threshold * stats: update timeout is now dynamic based on queue size * stats: moving averages * stats: providesBufferLength * stats: support for providesBufferLength and wantListLength * stats: support for peerCount * stats: enable / disable * increased test timeout
- Loading branch information
Showing
11 changed files
with
493 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
'use strict' | ||
|
||
const EventEmitter = require('events') | ||
const Big = require('big.js') | ||
const MovingAverage = require('moving-average') | ||
|
||
const defaultOptions = { | ||
movingAverageIntervals: [ | ||
60 * 1000, // 1 minute | ||
5 * 60 * 1000, // 5 minutes | ||
15 * 60 * 1000 // 15 minutes | ||
] | ||
} | ||
|
||
class Stats extends EventEmitter { | ||
constructor (initialCounters, _options) { | ||
super() | ||
|
||
const options = Object.assign({}, defaultOptions, _options) | ||
|
||
if (typeof options.computeThrottleTimeout !== 'number') { | ||
throw new Error('need computeThrottleTimeout') | ||
} | ||
|
||
if (typeof options.computeThrottleMaxQueueSize !== 'number') { | ||
throw new Error('need computeThrottleMaxQueueSize') | ||
} | ||
|
||
this._options = options | ||
this._queue = [] | ||
this._stats = {} | ||
|
||
this._frequencyLastTime = Date.now() | ||
this._frequencyAccumulators = {} | ||
this._movingAverages = {} | ||
|
||
this._update = this._update.bind(this) | ||
|
||
initialCounters.forEach((key) => { | ||
this._stats[key] = Big(0) | ||
this._movingAverages[key] = {} | ||
this._options.movingAverageIntervals.forEach((interval) => { | ||
const ma = this._movingAverages[key][interval] = MovingAverage(interval) | ||
ma.push(this._frequencyLastTime, 0) | ||
}) | ||
}) | ||
|
||
this._enabled = this._options.enabled | ||
} | ||
|
||
enable () { | ||
this._enabled = true | ||
} | ||
|
||
disable () { | ||
this._disabled = true | ||
} | ||
|
||
get snapshot () { | ||
return Object.assign({}, this._stats) | ||
} | ||
|
||
get movingAverages () { | ||
return Object.assign({}, this._movingAverages) | ||
} | ||
|
||
push (counter, inc) { | ||
if (this._enabled) { | ||
this._queue.push([counter, inc, Date.now()]) | ||
this._resetComputeTimeout() | ||
} | ||
} | ||
|
||
_resetComputeTimeout () { | ||
if (this._timeout) { | ||
clearTimeout(this._timeout) | ||
} | ||
this._timeout = setTimeout(this._update, this._nextTimeout()) | ||
} | ||
|
||
_nextTimeout () { | ||
// calculate the need for an update, depending on the queue length | ||
const urgency = this._queue.length / this._options.computeThrottleMaxQueueSize | ||
return Math.max(this._options.computeThrottleTimeout * (1 - urgency), 0) | ||
} | ||
|
||
_update () { | ||
this._timeout = null | ||
if (this._queue.length) { | ||
let last | ||
while (this._queue.length) { | ||
const op = last = this._queue.shift() | ||
this._applyOp(op) | ||
} | ||
|
||
this._updateFrequency(last[2]) // contains timestamp of last op | ||
|
||
this.emit('update', this._stats) | ||
} | ||
} | ||
|
||
_updateFrequency (latestTime) { | ||
const timeDiff = latestTime - this._frequencyLastTime | ||
|
||
Object.keys(this._stats).forEach((key) => { | ||
this._updateFrequencyFor(key, timeDiff, latestTime) | ||
}) | ||
|
||
this._frequencyLastTime = latestTime | ||
} | ||
|
||
_updateFrequencyFor (key, timeDiffMS, latestTime) { | ||
const count = this._frequencyAccumulators[key] || 0 | ||
this._frequencyAccumulators[key] = 0 | ||
const hz = (count / timeDiffMS) * 1000 | ||
|
||
let movingAverages = this._movingAverages[key] | ||
if (!movingAverages) { | ||
movingAverages = this._movingAverages[key] = {} | ||
} | ||
this._options.movingAverageIntervals.forEach((movingAverageInterval) => { | ||
let movingAverage = movingAverages[movingAverageInterval] | ||
if (!movingAverage) { | ||
movingAverage = movingAverages[movingAverageInterval] = MovingAverage(movingAverageInterval) | ||
} | ||
movingAverage.push(latestTime, hz) | ||
}) | ||
} | ||
|
||
_applyOp (op) { | ||
const key = op[0] | ||
const inc = op[1] | ||
|
||
if (typeof inc !== 'number') { | ||
throw new Error('invalid increment number:', inc) | ||
} | ||
|
||
let n | ||
|
||
if (!this._stats.hasOwnProperty(key)) { | ||
n = this._stats[key] = Big(0) | ||
} else { | ||
n = this._stats[key] | ||
} | ||
this._stats[key] = n.plus(inc) | ||
|
||
if (!this._frequencyAccumulators[key]) { | ||
this._frequencyAccumulators[key] = 0 | ||
} | ||
this._frequencyAccumulators[key] += inc | ||
} | ||
} | ||
|
||
module.exports = Stats |
Oops, something went wrong.