1 | (function (factory) {
|
2 | if (typeof module === "object" && typeof module.exports === "object") {
|
3 | var v = factory(require, exports);
|
4 | if (v !== undefined) module.exports = v;
|
5 | }
|
6 | else if (typeof define === "function" && define.amd) {
|
7 | define(["require", "exports", "tslib", "fs", "./Reporter"], factory);
|
8 | }
|
9 | })(function (require, exports) {
|
10 | "use strict";
|
11 | Object.defineProperty(exports, "__esModule", { value: true });
|
12 | var tslib_1 = require("tslib");
|
13 | var fs_1 = require("fs");
|
14 | var Reporter_1 = tslib_1.__importStar(require("./Reporter"));
|
15 | var BenchmarkReporter = (function (_super) {
|
16 | tslib_1.__extends(BenchmarkReporter, _super);
|
17 | function BenchmarkReporter(executor, options) {
|
18 | if (options === void 0) { options = {}; }
|
19 | var _this = _super.call(this, executor, options) || this;
|
20 | _this.mode = options.mode || 'test';
|
21 | _this.filename = options.filename || '';
|
22 | _this.thresholds = options.thresholds || {};
|
23 | if (_this.mode === 'test') {
|
24 | try {
|
25 | _this.baseline = JSON.parse(fs_1.readFileSync(_this.filename, { encoding: 'utf8' }));
|
26 | }
|
27 | catch (error) {
|
28 | _this.console.warn('Unable to load benchmark baseline data from ' + _this.filename);
|
29 | _this.console.warn('Switching to "baseline" mode');
|
30 | _this.mode = 'baseline';
|
31 | }
|
32 | }
|
33 | if (!_this.baseline) {
|
34 | _this.baseline = {};
|
35 | }
|
36 | _this.sessions = {};
|
37 | return _this;
|
38 | }
|
39 | BenchmarkReporter.prototype._getSession = function (testOrSuite) {
|
40 | var sessionId = testOrSuite.sessionId || 'local';
|
41 | var session = this.sessions[sessionId];
|
42 | if (!session) {
|
43 | var client = void 0;
|
44 | var version = void 0;
|
45 | var platform_1;
|
46 | if (testOrSuite.sessionId) {
|
47 | var environmentType = testOrSuite.remote.environmentType;
|
48 | client = environmentType.browserName;
|
49 | version = environmentType.version;
|
50 | platform_1 = environmentType.platform;
|
51 | }
|
52 | else {
|
53 | client = process.title;
|
54 | version = process.version;
|
55 | platform_1 = process.platform;
|
56 | }
|
57 | session = this.sessions[sessionId] = {
|
58 | suites: {},
|
59 | environment: {
|
60 | client: client,
|
61 | version: version,
|
62 | platform: platform_1,
|
63 | id: client + ':' + version + ':' + platform_1
|
64 | }
|
65 | };
|
66 | }
|
67 | return session;
|
68 | };
|
69 | BenchmarkReporter.prototype.runEnd = function () {
|
70 | if (this.mode === 'baseline') {
|
71 | var existingBaseline_1;
|
72 | try {
|
73 | existingBaseline_1 = JSON.parse(fs_1.readFileSync(this.filename, { encoding: 'utf8' }));
|
74 | }
|
75 | catch (error) {
|
76 | existingBaseline_1 = {};
|
77 | }
|
78 | var baseline_1 = this.baseline;
|
79 | Object.keys(baseline_1).forEach(function (environmentId) {
|
80 | existingBaseline_1[environmentId] = baseline_1[environmentId];
|
81 | });
|
82 | fs_1.writeFileSync(this.filename, JSON.stringify(existingBaseline_1, null, ' '));
|
83 | }
|
84 | };
|
85 | BenchmarkReporter.prototype.suiteEnd = function (suite) {
|
86 | var session = this._getSession(suite);
|
87 | if (!suite.hasParent) {
|
88 | var environment = session.environment;
|
89 | this.console.log('Finished benchmarking ' +
|
90 | environment.client +
|
91 | ' ' +
|
92 | environment.version +
|
93 | ' on ' +
|
94 | environment.platform);
|
95 | }
|
96 | else if (this.mode === 'test') {
|
97 | var suiteInfo = session.suites[suite.id];
|
98 | var numTests = suiteInfo.numBenchmarks;
|
99 | if (numTests > 0) {
|
100 | var numFailedTests = suiteInfo.numFailedBenchmarks;
|
101 | var message = numFailedTests + '/' + numTests + ' benchmarks failed in ' + suite.id;
|
102 | if (numFailedTests > 0) {
|
103 | this.console.warn(message);
|
104 | }
|
105 | else {
|
106 | this.console.log(message);
|
107 | }
|
108 | }
|
109 | }
|
110 | };
|
111 | BenchmarkReporter.prototype.suiteStart = function (suite) {
|
112 | var session = this._getSession(suite);
|
113 | if (!suite.hasParent) {
|
114 | var environment = session.environment;
|
115 | var environmentName = environment.client +
|
116 | ' ' +
|
117 | environment.version +
|
118 | ' on ' +
|
119 | environment.platform;
|
120 | var baselineEnvironments = this.baseline;
|
121 | this.console.log((this.mode === 'baseline' ? 'Baselining' : 'Benchmarking') +
|
122 | ' ' +
|
123 | environmentName);
|
124 | if (this.mode === 'baseline') {
|
125 | baselineEnvironments[environment.id] = {
|
126 | client: environment.client,
|
127 | version: environment.version,
|
128 | platform: environment.platform,
|
129 | tests: {}
|
130 | };
|
131 | }
|
132 | else if (!baselineEnvironments[environment.id]) {
|
133 | this.console.warn('No baseline data for ' + environmentName + '!');
|
134 | }
|
135 | }
|
136 | else {
|
137 | session.suites[suite.id] = {
|
138 | numBenchmarks: 0,
|
139 | numFailedBenchmarks: 0
|
140 | };
|
141 | }
|
142 | };
|
143 | BenchmarkReporter.prototype.testEnd = function (test) {
|
144 | var _this = this;
|
145 | var benchmarkTest = test;
|
146 | if (benchmarkTest.benchmark == null) {
|
147 | return;
|
148 | }
|
149 | if (benchmarkTest.error) {
|
150 | var session = this._getSession(benchmarkTest);
|
151 | var suiteInfo = session.suites[benchmarkTest.parentId];
|
152 | suiteInfo.numBenchmarks++;
|
153 | suiteInfo.numFailedBenchmarks++;
|
154 | this.console.error('FAIL: ' + benchmarkTest.id);
|
155 | this.console.error(this.executor.formatError(benchmarkTest.error, { space: ' ' }));
|
156 | }
|
157 | else {
|
158 | var checkTest = function (baseline, benchmark) {
|
159 | var warn = [];
|
160 | var fail = [];
|
161 | var list;
|
162 | var baselineMean = baseline.stats.mean;
|
163 | var thresholds = _this.thresholds || {};
|
164 | var percentDifference = (100 * (benchmark.stats.mean - baselineMean)) / baselineMean;
|
165 | if (thresholds.warn &&
|
166 | thresholds.warn.mean &&
|
167 | Math.abs(percentDifference) > thresholds.warn.mean) {
|
168 | list = warn;
|
169 | if (thresholds.fail &&
|
170 | thresholds.fail.mean &&
|
171 | Math.abs(percentDifference) > thresholds.fail.mean) {
|
172 | list = fail;
|
173 | }
|
174 | list.push('Execution time is ' + percentDifference.toFixed(1) + '% off');
|
175 | }
|
176 | var baselineRme = baseline.stats.rme;
|
177 | percentDifference = benchmark.stats.rme - baselineRme;
|
178 | if (thresholds.warn &&
|
179 | thresholds.warn.rme &&
|
180 | Math.abs(percentDifference) > thresholds.warn.rme) {
|
181 | list = warn;
|
182 | if (thresholds.fail &&
|
183 | thresholds.fail.rme &&
|
184 | Math.abs(percentDifference) > thresholds.fail.rme) {
|
185 | list = fail;
|
186 | }
|
187 | list.push('RME is ' + percentDifference.toFixed(1) + '% off');
|
188 | }
|
189 | if (fail.length) {
|
190 | _this.console.error('FAIL ' + benchmarkTest.id + ' (' + fail.join(', ') + ')');
|
191 | return false;
|
192 | }
|
193 | else if (warn.length) {
|
194 | _this.console.warn('WARN ' + benchmarkTest.id + ' (' + warn.join(', ') + ')');
|
195 | }
|
196 | else {
|
197 | _this.console.log('PASS ' + benchmarkTest.id);
|
198 | }
|
199 | return true;
|
200 | };
|
201 | var benchmark = benchmarkTest.benchmark;
|
202 | var session = this._getSession(benchmarkTest);
|
203 | var environment = session.environment;
|
204 | var suiteInfo = session.suites[benchmarkTest.parentId];
|
205 | suiteInfo.numBenchmarks++;
|
206 | var baseline = this.baseline[environment.id];
|
207 | if (this.mode === 'baseline') {
|
208 | baseline.tests[benchmarkTest.id] = {
|
209 | hz: benchmark.hz,
|
210 | times: benchmark.times,
|
211 | stats: {
|
212 | rme: benchmark.stats.rme,
|
213 | moe: benchmark.stats.moe,
|
214 | mean: benchmark.stats.mean
|
215 | }
|
216 | };
|
217 | this.console.log('Baselined ' + benchmarkTest.name);
|
218 | this.executor.log('Time per run:', formatSeconds(benchmark.stats.mean), '\xb1', benchmark.stats.rme.toFixed(2), '%');
|
219 | }
|
220 | else {
|
221 | if (baseline) {
|
222 | var testData = baseline.tests[benchmarkTest.id];
|
223 | var result = checkTest(testData, benchmark);
|
224 | var baselineStats = testData.stats;
|
225 | var benchmarkStats = benchmark.stats;
|
226 | this.executor.log('Expected time per run:', formatSeconds(baselineStats.mean), '\xb1', baselineStats.rme.toFixed(2), '%');
|
227 | this.executor.log('Actual time per run:', formatSeconds(benchmarkStats.mean), '\xb1', benchmarkStats.rme.toFixed(2), '%');
|
228 | if (!result) {
|
229 | suiteInfo.numFailedBenchmarks++;
|
230 | }
|
231 | }
|
232 | }
|
233 | }
|
234 | };
|
235 | tslib_1.__decorate([
|
236 | Reporter_1.eventHandler()
|
237 | ], BenchmarkReporter.prototype, "runEnd", null);
|
238 | tslib_1.__decorate([
|
239 | Reporter_1.eventHandler()
|
240 | ], BenchmarkReporter.prototype, "suiteEnd", null);
|
241 | tslib_1.__decorate([
|
242 | Reporter_1.eventHandler()
|
243 | ], BenchmarkReporter.prototype, "suiteStart", null);
|
244 | tslib_1.__decorate([
|
245 | Reporter_1.eventHandler()
|
246 | ], BenchmarkReporter.prototype, "testEnd", null);
|
247 | return BenchmarkReporter;
|
248 | }(Reporter_1.default));
|
249 | exports.default = BenchmarkReporter;
|
250 | function formatSeconds(value) {
|
251 | if (value == null) {
|
252 | return null;
|
253 | }
|
254 | var units = 's';
|
255 | if (value < 1) {
|
256 | var places = Math.ceil(Math.log(value) / Math.log(10)) - 1;
|
257 | if (places < -9) {
|
258 | value *= Math.pow(10, 12);
|
259 | units = 'ps';
|
260 | }
|
261 | else if (places < -6) {
|
262 | value *= Math.pow(10, 9);
|
263 | units = 'ns';
|
264 | }
|
265 | else if (places < -3) {
|
266 | value *= Math.pow(10, 6);
|
267 | units = 'µs';
|
268 | }
|
269 | else if (places < 0) {
|
270 | value *= Math.pow(10, 3);
|
271 | units = 'ms';
|
272 | }
|
273 | }
|
274 | return value.toFixed(3) + units;
|
275 | }
|
276 | });
|
277 |
|
\ | No newline at end of file |