-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0feaa28
commit a447ca5
Showing
16 changed files
with
364 additions
and
148 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
/* eslint-disable no-param-reassign */ | ||
import { mean, isValue, isObject } from 'myrmidon'; | ||
import PlainReporter from './reporters/PlainReporter'; | ||
|
||
export default class BaseBenchMark { | ||
constructor({ | ||
counter, | ||
shortSingleObservations = true | ||
}) { | ||
this._labels = []; | ||
this.counter = counter; | ||
this._start = this.counter.bench(); | ||
this._config = { shortSingleObservations }; | ||
this._iterations = []; | ||
} | ||
|
||
start(label, payload) { | ||
const item = { start: this.counter.bench(), label }; | ||
|
||
if (payload) item.payload = payload; | ||
const len = this._labels.push(item); | ||
|
||
return len - 1; | ||
} | ||
|
||
end(pointer) { | ||
this._labels[pointer].end = this.counter.bench(); | ||
} | ||
|
||
iteration() { | ||
const benchmark = new this.constructor({ | ||
counter : this.counter, | ||
...this._config | ||
}); | ||
|
||
this._iterations.push(benchmark); | ||
|
||
return benchmark; | ||
} | ||
|
||
sequence(label) { | ||
const item = { end: this.counter.bench(), label, sequence: true }; | ||
|
||
this._labels.push(item); | ||
} | ||
|
||
static metrics = { | ||
total : arr => arr.length, | ||
mean : arr => mean(arr) | ||
}; | ||
|
||
static items = {}; | ||
|
||
calculateIntervals() { | ||
this._labels.filter(l => l.sequence) | ||
.forEach((item, index, sequence) => { | ||
const startPoint = index === 0 ? this._start : sequence[index - 1].end; | ||
|
||
item.bench = this.counter.diff(startPoint, item.end); | ||
}); | ||
|
||
this._labels.filter(l => !l.sequence && l.start && l.end).forEach(item => { | ||
item.bench = this.counter.diff(item.start, item.end); | ||
}); | ||
} | ||
|
||
_prepareMultiObservationReport(bench, metrics, report) { | ||
for (const key of Object.keys(bench[0])) { | ||
const arr = bench.map(b => b[key]); | ||
|
||
report[key] = {}; | ||
this._prepareSingleObservationReport(arr, metrics, report[key]); | ||
} | ||
} | ||
|
||
_prepareSingleObservationReport(bench, metrics, report) { | ||
const metricNames = Object.keys(metrics) | ||
.filter(metricName => metrics[metricName]); | ||
|
||
for (const metricName of metricNames) { | ||
report[metricName] = metrics[metricName](bench); | ||
} | ||
} | ||
|
||
prepareReport(label, labels, { metrics, items }) { | ||
const filtered = labels.filter(ll => ll.label === label && isValue(ll.bench)); | ||
|
||
if (filtered.length === 0) return; | ||
const report = { label }; | ||
|
||
const bench = filtered.map(item => item.bench); | ||
const multiObservation = isObject(bench[0]); | ||
|
||
if (filtered.length === 1 && this._config.shortSingleObservations) { | ||
if (multiObservation) { | ||
for (const key of Object.keys(bench[0])) { | ||
report[key] = bench[0][key]; | ||
} | ||
} else { | ||
report.benchmark = bench[0]; | ||
} | ||
|
||
|
||
return report; | ||
} | ||
|
||
|
||
const mergedMetrics = { | ||
...this.constructor.metrics, | ||
...metrics | ||
}; | ||
|
||
if (multiObservation) { | ||
this._prepareMultiObservationReport(bench, mergedMetrics, report); | ||
} else { | ||
this._prepareSingleObservationReport(bench, mergedMetrics, report); | ||
} | ||
|
||
const mergedItems = { | ||
...this.constructor.items, | ||
...items | ||
}; | ||
|
||
for (const itemLabel of Object.keys(mergedItems)) { | ||
if (!mergedItems[itemLabel]) continue; | ||
report[itemLabel] = mergedItems[itemLabel]( | ||
filtered, | ||
report | ||
); | ||
} | ||
|
||
return report; | ||
} | ||
|
||
calculate({ | ||
force = false, | ||
metrics = {}, | ||
items = {} | ||
} = {}) { | ||
if (this._reports && !force) return this._reports; | ||
this._reports = []; | ||
const labels = [ ...this._labels ]; | ||
|
||
this._iterations.forEach(benchmark => labels.push(...benchmark._labels)); | ||
const labelsList = new Set(labels.map(l => l.label)); | ||
|
||
this.calculateIntervals(); | ||
this._iterations.forEach(b => b.calculateIntervals()); | ||
|
||
for (const label of labelsList) { | ||
const report = this.prepareReport(label, labels, { metrics, items }); | ||
|
||
if (!report) continue; | ||
this._reports.push(report); | ||
} | ||
} | ||
|
||
report(reporter = new PlainReporter(), { pretty = false } = {}) { | ||
this.calculate(); | ||
|
||
return reporter.run(this._reports, { | ||
prettify : pretty && this.counter.constructor.prettify | ||
}); | ||
} | ||
} |
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 |
---|---|---|
@@ -1,130 +1,18 @@ | ||
import { mean, quantile } from 'myrmidon'; | ||
import { quantile } from 'myrmidon'; | ||
import autoDetectCounter from './counters/autoDetector'; | ||
import PlainReporter from './reporters/PlainReporter'; | ||
import Base from './BaseBenchMark'; | ||
|
||
export default class BenchMark { | ||
export default class BenchMark extends Base { | ||
constructor({ | ||
counter = autoDetectCounter(), | ||
shortSingleObservations = true | ||
} = {}) { | ||
this._labels = []; | ||
this.counter = counter; | ||
this._start = this.counter.bench(); | ||
this._config = { shortSingleObservations }; | ||
this._iterations = []; | ||
} | ||
|
||
start(label, payload) { | ||
const item = { start: this.counter.bench(), label }; | ||
|
||
if (payload) item.payload = payload; | ||
const len = this._labels.push(item); | ||
|
||
return len - 1; | ||
} | ||
|
||
end(pointer) { | ||
this._labels[pointer].end = this.counter.bench(); | ||
} | ||
|
||
iteration() { | ||
const benchmark = new BenchMark({ | ||
counter : this.counter, | ||
...this._config | ||
}); | ||
|
||
this._iterations.push(benchmark); | ||
|
||
return benchmark; | ||
} | ||
|
||
sequence(label) { | ||
const item = { end: this.counter.bench(), label, sequence: true }; | ||
|
||
this._labels.push(item); | ||
super({ counter, shortSingleObservations }); | ||
} | ||
|
||
static metrics = { | ||
total : arr => arr.length, | ||
mean : arr => mean(arr), | ||
q25 : arr => quantile(arr, 0.25), // eslint-disable-line no-magic-numbers | ||
q75 : arr => quantile(arr, 0.75) // eslint-disable-line no-magic-numbers | ||
...Base.metrics, | ||
q25 : arr => quantile(arr, 0.25), // eslint-disable-line no-magic-numbers | ||
q75 : arr => quantile(arr, 0.75) // eslint-disable-line no-magic-numbers | ||
}; | ||
|
||
calculateIntervals() { | ||
/* eslint-disable no-param-reassign */ | ||
this._labels.filter(l => l.sequence).forEach((item, index, sequence) => { | ||
const startPoint = index === 0 ? this._start : sequence[index - 1].end; | ||
|
||
item.bench = this.counter.diff(startPoint, item.end); | ||
}); | ||
|
||
this._labels.filter(l => !l.sequence && l.start && l.end).forEach(item => { | ||
item.bench = this.counter.diff(item.start, item.end); | ||
}); | ||
/* eslint-enable no-param-reassign */ | ||
} | ||
|
||
prepareReport(label, labels, { metrics, items }) { | ||
const filtered = labels.filter(ll => ll.label === label && ll.bench >= 0); | ||
|
||
if (filtered.length === 0) return; | ||
const report = { label }; | ||
|
||
if (filtered.length === 1 && this._config.shortSingleObservations) { | ||
report.benchmark = filtered[0].bench; | ||
|
||
return report; | ||
} | ||
|
||
const numbers = filtered.map(item => item.bench); | ||
const mergedMetrics = { | ||
...this.constructor.metrics, | ||
...metrics | ||
}; | ||
|
||
for (const metricName of Object.keys(mergedMetrics)) { | ||
if (!mergedMetrics[metricName]) continue; | ||
report[metricName] = mergedMetrics[metricName](numbers); | ||
} | ||
|
||
for (const itemLabel of Object.keys(items)) { | ||
if (!items[itemLabel]) continue; | ||
report[itemLabel] = items[itemLabel]( | ||
filtered, | ||
report | ||
); | ||
} | ||
|
||
return report; | ||
} | ||
|
||
calculate({ | ||
force = false, | ||
metrics = {}, | ||
items = {} | ||
} = {}) { | ||
if (this._reports && !force) return this._reports; | ||
this._reports = []; | ||
const labels = [ ...this._labels ]; | ||
|
||
this._iterations.forEach(benchmark => labels.push(...benchmark._labels)); | ||
const labelsList = new Set(labels.map(l => l.label)); | ||
|
||
this.calculateIntervals(); | ||
this._iterations.forEach(b => b.calculateIntervals()); | ||
|
||
for (const label of labelsList) { | ||
const report = this.prepareReport(label, labels, { metrics, items }); | ||
|
||
if (!report) continue; | ||
this._reports.push(report); | ||
} | ||
} | ||
|
||
report(reporter = new PlainReporter()) { | ||
this.calculate(); | ||
|
||
return reporter.run(this._reports); | ||
} | ||
} |
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,19 @@ | ||
import ProcessMemory from './counters/ProcessMemory'; | ||
import Base from './BaseBenchMark'; | ||
|
||
export default class Memory extends Base { | ||
constructor({ | ||
counter = new ProcessMemory(), | ||
shortSingleObservations = true | ||
} = {}) { | ||
super({ counter, shortSingleObservations }); | ||
} | ||
|
||
static metrics = { | ||
mean : Base.metrics.mean | ||
}; | ||
|
||
static items = { | ||
total : arr => arr.length | ||
}; | ||
} |
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 @@ | ||
export default class Counter {} |
Oops, something went wrong.