Skip to content

Commit e76523d

Browse files
committed
test(benchmark): add ability to run 25 iterations of test, sampling only the last 20
This commit also breaks the functionality into smaller, more testable functions, and adds some basic tests for the benchmarking too.
1 parent b2c050b commit e76523d

File tree

2 files changed

+495
-68
lines changed

2 files changed

+495
-68
lines changed

benchmark/web/bp.js

+126-66
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,32 @@
11
var bp = window.bp = {};
22
bp.steps = window.benchmarkSteps = [];
3-
bp.timesPerAction = {};
4-
bp.running = false;
5-
bp.numSamples = 10;
3+
bp.runState = {};
4+
5+
bp.setRunState = function (samples, iterations, ignoreCount) {
6+
bp.runState.numSamples = samples;
7+
bp.runState.iterations = iterations;
8+
bp.runState.ignoreCount = ignoreCount;
9+
bp.runState.recentTimePerStep = {};
10+
bp.runState.timesPerAction = {};
11+
};
12+
13+
bp.resetRunState = function() {
14+
bp.runState = {
15+
numSamples: 0,
16+
iterations: 0,
17+
ignoreCount: 0,
18+
recentTimePerStep: {},
19+
timesPerAction: {}
20+
};
21+
};
22+
23+
bp.interpolateHtml = function(string, list) {
24+
list.forEach(function(item, i) {
25+
var exp = new RegExp('%' + i, ['g']);
26+
string = string.replace(exp, item);
27+
});
28+
return string;
29+
}
630

731
bp.numMilliseconds = function() {
832
if (window.performance != null && typeof window.performance.now == 'function') {
@@ -15,75 +39,117 @@ bp.numMilliseconds = function() {
1539
}
1640
};
1741

18-
bp.loopBenchmark = function loopBenchmark() {
19-
if (bp.running) {
42+
bp.loopBenchmark = function () {
43+
if (bp.runState.iterations <= -1) {
44+
//Time to stop looping
45+
bp.setRunState(10, 0);
2046
bp.loopBtn.innerText = 'Loop';
21-
bp.running = false;
22-
} else {
23-
window.requestAnimationFrame(function() {
24-
bp.loopBtn.innerText = 'Pause';
25-
bp.running = true;
26-
var loopB = function() {
27-
if (bp.running) {
28-
window.requestAnimationFrame(function() {
29-
if (bp.running) bp.runBenchmarkSteps(loopB);
30-
});
31-
}
32-
};
33-
loopB();
34-
});
47+
return;
3548
}
49+
bp.setRunState(10, -1);
50+
bp.loopBtn.innerText = 'Pause';
51+
bp.runAllTests();
3652
};
3753

3854
bp.onceBenchmark = function() {
39-
var btn = bp.onceBtn;
40-
window.requestAnimationFrame(function() {
41-
btn.innerText = '...';
55+
bp.setRunState(10, 1);
56+
bp.onceBtn.innerText = '...';
57+
bp.runAllTests(function() {
58+
bp.onceBtn.innerText = 'Once';
59+
});
60+
};
61+
62+
bp.twentyFiveBenchmark = function() {
63+
var twentyFiveBtn = bp.twentyFiveBtn;
64+
bp.setRunState(20, 25);
65+
twentyFiveBtn.innerText = 'Looping...';
66+
bp.runAllTests(function() {
67+
twentyFiveBtn.innerText = 'Loop 25x';
68+
}, 5);
69+
};
70+
71+
bp.runTimedTest = function (bs) {
72+
if (typeof window.gc === 'function') {
73+
window.gc();
74+
}
75+
var startTime = bp.numMilliseconds();
76+
bs.fn();
77+
return bp.numMilliseconds() - startTime;
78+
};
79+
80+
bp.runAllTests = function (done) {
81+
if (bp.runState.iterations--) {
82+
bp.steps.forEach(function(bs) {
83+
bp.runState.recentTimePerStep[bs.name] = bp.runTimedTest(bs);
84+
});
85+
bp.report = bp.calcStats();
86+
bp.writeReport(bp.report);
4287
window.requestAnimationFrame(function() {
43-
bp.runBenchmarkSteps(function() {
44-
btn.innerText = 'Once';
45-
});
88+
bp.runAllTests(done);
4689
});
47-
});
90+
}
91+
else {
92+
bp.writeReport(bp.report);
93+
bp.resetRunState();
94+
done && done();
95+
}
96+
}
97+
98+
bp.padName = function (name) {
99+
return name.length < 10 ?
100+
(' ' + name).slice(-10).replace(/ /g, '&nbsp;') :
101+
name;
48102
};
49103

50-
bp.runBenchmarkSteps = function runBenchmarkSteps(done) {
51-
// Run all the steps;
52-
var times = {};
53-
bp.steps.forEach(function(bs) {
54-
if (typeof window.gc === 'function') {
55-
window.gc();
56-
}
57-
var startTime = bp.numMilliseconds();
58-
bs.fn();
59-
times[bs.name] = bp.numMilliseconds() - startTime;
60-
});
61-
bp.calcStats(times);
104+
bp.generateReportPartial = function(name, avg, times) {
105+
return bp.interpolateHtml(
106+
'<div>%0: avg-%1:<b>%2ms</b> [%3]ms</div>',
107+
[
108+
bp.padName(name),
109+
bp.runState.numSamples,
110+
('' + avg).substr(0,6),
111+
times.join(', ')
112+
]);
113+
};
62114

63-
done();
115+
bp.getAverage = function (times, runState) {
116+
var avg = 0, ignoreCount = (runState && runState.ignoreCount) || 0;
117+
times = times.slice(ignoreCount);
118+
times.forEach(function(x) { avg += x; });
119+
return avg / times.length;
64120
};
65121

66-
bp.calcStats = function calcStats(times) {
67-
var iH = '';
68-
bp.steps.forEach(function(bs) {
69-
var tpa = bp.timesPerAction[bs.name];
70-
if (!tpa) {
71-
tpa = bp.timesPerAction[bs.name] = {
72-
times: [], // circular buffer
73-
fmtTimes: [],
74-
nextEntry: 0
75-
}
122+
bp.writeReport = function(reportContent) {
123+
bp.infoDiv.innerHTML = reportContent;
124+
};
125+
126+
bp.getTimesPerAction = function(name) {
127+
var tpa = bp.runState.timesPerAction[name];
128+
if (!tpa) {
129+
tpa = bp.runState.timesPerAction[name] = {
130+
times: [], // circular buffer
131+
fmtTimes: [],
132+
nextEntry: 0
76133
}
77-
tpa.fmtTimes[tpa.nextEntry] = ('' + times[bs.name]).substr(0,6);
78-
tpa.times[tpa.nextEntry++] = times[bs.name];
79-
tpa.nextEntry %= bp.numSamples;
80-
var avg = 0;
81-
tpa.times.forEach(function(x) { avg += x; });
82-
avg /= Math.min(bp.numSamples, tpa.times.length);
83-
avg = ('' + avg).substr(0,6);
84-
iH += '<div>' + (' ' + bs.name).slice(-10).replace(/ /g, '&nbsp;') + ': avg-' + bp.numSamples + ':<b>' + avg + 'ms</b> [' + tpa.fmtTimes.join(', ') + ']ms</div>';
134+
}
135+
return tpa;
136+
};
137+
138+
bp.calcStats = function() {
139+
var report = '';
140+
bp.steps.forEach(function(bs) {
141+
var stepName = bs.name,
142+
timeForStep = bp.runState.recentTimePerStep[stepName],
143+
tpa = bp.getTimesPerAction(stepName),
144+
avg;
145+
tpa.fmtTimes[tpa.nextEntry] = ('' + timeForStep).substr(0,6);
146+
tpa.times[tpa.nextEntry++] = timeForStep;
147+
tpa.nextEntry %= bp.runState.numSamples;
148+
avg = bp.getAverage(tpa.times, bp.runState);
149+
150+
report += bp.generateReportPartial(stepName, avg, tpa.fmtTimes);
85151
});
86-
bp.infoDiv.innerHTML = iH;
152+
return report;
87153
};
88154

89155
bp.container = function() {
@@ -118,13 +184,7 @@ bp.addLinks = function() {
118184
// Add new benchmark suites here
119185
['tree.html', 'TreeComponent']
120186
].forEach((function (link) {
121-
linkHtml += [
122-
'<a class=bpLink href=',
123-
link[0],
124-
'>',
125-
link[1],
126-
'</a>'
127-
].join('');
187+
linkHtml += bp.interpolateHtml('<a class=bpLink href=%0>%1</a>', link);
128188
}));
129189

130190
linkDiv.innerHTML = linkHtml;
@@ -141,7 +201,7 @@ bp.onDOMContentLoaded = function() {
141201
bp.addLinks();
142202
bp.addButton('loopBtn', 'Loop', bp.loopBenchmark);
143203
bp.addButton('onceBtn', 'Once', bp.onceBenchmark);
144-
204+
bp.addButton('twentyFiveBtn', 'Loop 25x', bp.twentyFiveBenchmark);
145205
bp.addInfo();
146206
};
147207

0 commit comments

Comments
 (0)