Skip to content

Commit 5e798c6

Browse files
tboschmhevery
authored andcommitted
refactor(bench press): wrap measure values into an object with time and iteration number.
Closes angular#689
1 parent e163eb2 commit 5e798c6

11 files changed

Lines changed: 106 additions & 52 deletions

File tree

modules/benchpress/benchpress.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ export { PerflogMetric } from './src/metric/perflog_metric';
1212
export { ChromeDriverExtension } from './src/webdriver/chrome_driver_extension';
1313
export { Runner } from './src/runner';
1414
export { Options } from './src/sample_options';
15+
export { MeasureValues } from './src/measure_values';
1516

1617
export { bind, Injector, OpaqueToken } from 'angular2/di';
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Date } from 'angular2/src/facade/lang';
2+
3+
export class MeasureValues {
4+
timeStamp:Date;
5+
runIndex:number;
6+
values:any;
7+
8+
constructor(runIndex:number, timeStamp:Date, values:any) {
9+
this.timeStamp = timeStamp;
10+
this.runIndex = runIndex;
11+
this.values = values;
12+
}
13+
}

modules/benchpress/src/reporter.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@ import {
55
ABSTRACT, BaseException
66
} from 'angular2/src/facade/lang';
77

8+
import { MeasureValues } from './measure_values';
9+
810
/**
911
* A reporter reports measure values and the valid sample.
1012
*/
1113
@ABSTRACT()
1214
export class Reporter {
13-
reportMeasureValues(index:number, values:any):Promise {
15+
reportMeasureValues(values:MeasureValues):Promise {
1416
throw new BaseException('NYI');
1517
}
1618

17-
reportSample(completeSample:List, validSample:List):Promise {
19+
reportSample(completeSample:List<MeasureValues>, validSample:List<MeasureValues>):Promise {
1820
throw new BaseException('NYI');
1921
}
2022
}

modules/benchpress/src/reporter/console_reporter.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { bind, OpaqueToken } from 'angular2/di';
77
import { Statistic } from '../statistic';
88
import { Reporter } from '../reporter';
99
import { SampleDescription } from '../sample_description';
10+
import { MeasureValues } from '../measure_values';
1011

1112
/**
1213
* A reporter for the console
@@ -72,20 +73,20 @@ export class ConsoleReporter extends Reporter {
7273
this._printStringRow(this._metricNames.map( (_) => '' ), '-');
7374
}
7475

75-
reportMeasureValues(index:number, measuredValues:any):Promise {
76+
reportMeasureValues(measureValues:MeasureValues):Promise {
7677
var formattedValues = ListWrapper.map(this._metricNames, (metricName) => {
77-
var value = measuredValues[metricName];
78+
var value = measureValues.values[metricName];
7879
return ConsoleReporter._formatNum(value);
7980
});
8081
this._printStringRow(formattedValues);
8182
return PromiseWrapper.resolve(null);
8283
}
8384

84-
reportSample(completeSample:List, validSample:List):Promise {
85+
reportSample(completeSample:List<MeasureValues>, validSample:List<MeasureValues>):Promise {
8586
this._printStringRow(this._metricNames.map( (_) => '' ), '=');
8687
this._printStringRow(
8788
ListWrapper.map(this._metricNames, (metricName) => {
88-
var sample = ListWrapper.map(validSample, (measuredValues) => measuredValues[metricName]);
89+
var sample = ListWrapper.map(validSample, (measureValues) => measureValues.values[metricName]);
8990
var mean = Statistic.calculateMean(sample);
9091
var cv = Statistic.calculateCoefficientOfVariation(sample, mean);
9192
return `${ConsoleReporter._formatNum(mean)}\u00B1${Math.floor(cv)}%`;

modules/benchpress/src/sampler.js

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isPresent, isBlank } from 'angular2/src/facade/lang';
1+
import { isPresent, isBlank, Date, DateWrapper } from 'angular2/src/facade/lang';
22
import { Promise, PromiseWrapper } from 'angular2/src/facade/async';
33
import { StringMapWrapper, List, ListWrapper } from 'angular2/src/facade/collection';
44
import { bind, OpaqueToken } from 'angular2/di';
@@ -10,6 +10,7 @@ import { WebDriverExtension } from './web_driver_extension';
1010
import { WebDriverAdapter } from './web_driver_adapter';
1111

1212
import { Options } from './sample_options';
13+
import { MeasureValues} from './measure_values';
1314

1415
/**
1516
* The Sampler owns the sample loop:
@@ -22,6 +23,8 @@ import { Options } from './sample_options';
2223
export class Sampler {
2324
// TODO(tbosch): use static values when our transpiler supports them
2425
static get BINDINGS() { return _BINDINGS; }
26+
// TODO(tbosch): use static values when our transpiler supports them
27+
static get TIME() { return _TIME; }
2528

2629
_driver:WebDriverAdapter;
2730
_driverExtension:WebDriverExtension;
@@ -31,13 +34,14 @@ export class Sampler {
3134
_forceGc:boolean;
3235
_prepare:Function;
3336
_execute:Function;
37+
_time:Function;
3438

3539
constructor({
36-
driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute
40+
driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, time
3741
}:{
3842
driver: WebDriverAdapter,
3943
driverExtension: WebDriverExtension, metric: Metric, reporter: Reporter,
40-
validator: Validator, prepare: Function, execute: Function
44+
validator: Validator, prepare: Function, execute: Function, time: Function
4145
}={}) {
4246
this._driver = driver;
4347
this._driverExtension = driverExtension;
@@ -47,6 +51,7 @@ export class Sampler {
4751
this._forceGc = forceGc;
4852
this._prepare = prepare;
4953
this._execute = execute;
54+
this._time = time;
5055
}
5156

5257
sample():Promise<SampleState> {
@@ -90,10 +95,11 @@ export class Sampler {
9095
.then( (measureValues) => this._report(lastState, measureValues) );
9196
}
9297

93-
_report(state:SampleState, measuredValues:any):Promise<SampleState> {
94-
var completeSample = ListWrapper.concat(state.completeSample, [measuredValues]);
98+
_report(state:SampleState, metricValues:any):Promise<SampleState> {
99+
var measureValues = new MeasureValues(state.completeSample.length, this._time(), metricValues);
100+
var completeSample = ListWrapper.concat(state.completeSample, [measureValues]);
95101
var validSample = this._validator.validate(completeSample);
96-
var resultPromise = this._reporter.reportMeasureValues(completeSample.length - 1, measuredValues);
102+
var resultPromise = this._reporter.reportMeasureValues(measureValues);
97103
if (isPresent(validSample)) {
98104
resultPromise = resultPromise.then( (_) => this._reporter.reportSample(completeSample, validSample) )
99105
}
@@ -112,9 +118,11 @@ export class SampleState {
112118
}
113119
}
114120

121+
var _TIME = new OpaqueToken('Sampler.time');
122+
115123
var _BINDINGS = [
116124
bind(Sampler).toFactory(
117-
(driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute) => new Sampler({
125+
(driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, time) => new Sampler({
118126
driver: driver,
119127
driverExtension: driverExtension,
120128
reporter: reporter,
@@ -125,10 +133,12 @@ var _BINDINGS = [
125133
// Mostly because the cache would have to be initialized with a
126134
// special null object, which is expensive.
127135
prepare: prepare !== false ? prepare : null,
128-
execute: execute
136+
execute: execute,
137+
time: time
129138
}),
130-
[WebDriverAdapter, WebDriverExtension, Metric, Reporter, Validator, Options.FORCE_GC, Options.PREPARE, Options.EXECUTE]
139+
[WebDriverAdapter, WebDriverExtension, Metric, Reporter, Validator, Options.FORCE_GC, Options.PREPARE, Options.EXECUTE, _TIME]
131140
),
132141
bind(Options.FORCE_GC).toValue(false),
133-
bind(Options.PREPARE).toValue(false)
142+
bind(Options.PREPARE).toValue(false),
143+
bind(_TIME).toValue( () => DateWrapper.now() )
134144
];

modules/benchpress/src/validator.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {
33
ABSTRACT, BaseException
44
} from 'angular2/src/facade/lang';
55

6+
import { MeasureValues } from './measure_values';
7+
68
/**
79
* A Validator calculates a valid sample out of the complete sample.
810
* A valid sample is a sample that represents the population that should be observed
@@ -13,7 +15,7 @@ export class Validator {
1315
/**
1416
* Calculates a valid sample out of the complete sample
1517
*/
16-
validate(completeSample:List<any>):List<any> {
18+
validate(completeSample:List<MeasureValues>):List<MeasureValues> {
1719
throw new BaseException('NYI');
1820
}
1921

modules/benchpress/src/validator/regression_slope_validator.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { bind, OpaqueToken } from 'angular2/di';
33

44
import { Validator } from '../validator';
55
import { Statistic } from '../statistic';
6+
import { MeasureValues } from '../measure_values';
67

78
/**
89
* A validator that checks the regression slope of a specific metric.
@@ -32,7 +33,7 @@ export class RegressionSlopeValidator extends Validator {
3233
};
3334
}
3435

35-
validate(completeSample:List<any>):List<any> {
36+
validate(completeSample:List<MeasureValues>):List<MeasureValues> {
3637
if (completeSample.length >= this._sampleSize) {
3738
var latestSample =
3839
ListWrapper.slice(completeSample, completeSample.length - this._sampleSize, completeSample.length);
@@ -42,7 +43,7 @@ export class RegressionSlopeValidator extends Validator {
4243
// For now, we only use the array index as x value.
4344
// TODO(tbosch): think about whether we should use time here instead
4445
ListWrapper.push(xValues, i);
45-
ListWrapper.push(yValues, latestSample[i][this._metric]);
46+
ListWrapper.push(yValues, latestSample[i].values[this._metric]);
4647
}
4748
var regressionSlope = Statistic.calculateRegressionSlope(
4849
xValues, Statistic.calculateMean(xValues),

modules/benchpress/test/reporter/console_reporter_spec.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import {describe, ddescribe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
22

3-
import { isBlank, isPresent } from 'angular2/src/facade/lang';
3+
import { isBlank, isPresent, Date, DateWrapper } from 'angular2/src/facade/lang';
44
import { List, ListWrapper } from 'angular2/src/facade/collection';
55

66
import {
77
SampleState, Reporter, bind, Injector,
8-
ConsoleReporter, SampleDescription
8+
ConsoleReporter, SampleDescription, MeasureValues
99
} from 'benchpress/benchpress';
1010

1111
export function main() {
@@ -68,9 +68,9 @@ export function main() {
6868
}
6969
});
7070
log = [];
71-
reporter.reportMeasureValues(0, {
71+
reporter.reportMeasureValues(mv(0, 0, {
7272
'a': 1.23, 'b': 2
73-
});
73+
}));
7474
expect(log).toEqual([
7575
' 1.23 | 2.00'
7676
]);
@@ -85,11 +85,11 @@ export function main() {
8585
}
8686
});
8787
log = [];
88-
reporter.reportSample([], [{
88+
reporter.reportSample([], [mv(0,0,{
8989
'a': 3, 'b': 6
90-
},{
90+
}), mv(1,1,{
9191
'a': 5, 'b': 9
92-
}]);
92+
})]);
9393
expect(log).toEqual([
9494
'======== | ========',
9595
'4.00±25% | 7.50±20%'
@@ -99,3 +99,6 @@ export function main() {
9999
});
100100
}
101101

102+
function mv(runIndex, time, values) {
103+
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
104+
}

modules/benchpress/test/sampler_spec.js

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import {describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
22

3-
import { isBlank, isPresent, BaseException, stringify } from 'angular2/src/facade/lang';
3+
import { isBlank, isPresent, BaseException, stringify, Date, DateWrapper } from 'angular2/src/facade/lang';
44
import { ListWrapper, List } from 'angular2/src/facade/collection';
55
import { PromiseWrapper, Promise } from 'angular2/src/facade/async';
66

77
import {
88
Sampler, WebDriverAdapter, WebDriverExtension,
99
Validator, Metric, Reporter, Browser,
10-
bind, Injector, Options
10+
bind, Injector, Options, MeasureValues
1111
} from 'benchpress/benchpress';
1212

1313
export function main() {
@@ -26,6 +26,7 @@ export function main() {
2626
prepare,
2727
execute
2828
} = {}) {
29+
var time = 1000;
2930
if (isBlank(metric)) {
3031
metric = new MockMetric([]);
3132
}
@@ -44,7 +45,8 @@ export function main() {
4445
bind(WebDriverAdapter).toValue(driver),
4546
bind(WebDriverExtension).toValue(driverExtension),
4647
bind(Options.EXECUTE).toValue(execute),
47-
bind(Validator).toValue(validator)
48+
bind(Validator).toValue(validator),
49+
bind(Sampler.TIME).toValue( () => DateWrapper.fromMillis(time++) )
4850
]);
4951
if (isPresent(prepare)) {
5052
ListWrapper.push(bindings, bind(Options.PREPARE).toValue(prepare));
@@ -181,8 +183,8 @@ export function main() {
181183
});
182184
sampler.sample().then( (state) => {
183185
expect(state.completeSample.length).toBe(2);
184-
expect(state.completeSample[0]).toEqual({'script': 10});
185-
expect(state.completeSample[1]).toEqual({'script': 20});
186+
expect(state.completeSample[0]).toEqual(mv(0, 1000, {'script': 10}));
187+
expect(state.completeSample[1]).toEqual(mv(1, 1001, {'script': 20}));
186188
done();
187189
});
188190
});
@@ -206,10 +208,10 @@ export function main() {
206208

207209
expect(log.length).toBe(2);
208210
expect(log[0]).toEqual(
209-
['validate', [{'script': 0}], null]
211+
['validate', [mv(0, 1000, {'script': 0})], null]
210212
);
211213
expect(log[1]).toEqual(
212-
['validate', [{'script': 0}, {'script': 1}], validSample]
214+
['validate', [mv(0, 1000, {'script': 0}), mv(1, 1001, {'script': 1})], validSample]
213215
);
214216

215217
done();
@@ -234,13 +236,13 @@ export function main() {
234236
// ]);
235237
expect(log.length).toBe(3);
236238
expect(log[0]).toEqual(
237-
['reportMeasureValues', 0, {'script': 0}]
239+
['reportMeasureValues', mv(0, 1000, {'script': 0})]
238240
);
239241
expect(log[1]).toEqual(
240-
['reportMeasureValues', 1, {'script': 1}]
242+
['reportMeasureValues', mv(1, 1001, {'script': 1})]
241243
);
242244
expect(log[2]).toEqual(
243-
['reportSample', [{'script': 0}, {'script': 1}], validSample]
245+
['reportSample', [mv(0, 1000, {'script': 0}), mv(1, 1001, {'script': 1})], validSample]
244246
);
245247

246248
done();
@@ -250,6 +252,10 @@ export function main() {
250252
});
251253
}
252254

255+
function mv(runIndex, time, values) {
256+
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
257+
}
258+
253259
function createCountingValidator(count, validSample = null, log = null) {
254260
return new MockValidator(log, (completeSample) => {
255261
count--;
@@ -315,7 +321,7 @@ class MockValidator extends Validator {
315321
}
316322
this._log = log;
317323
}
318-
validate(completeSample:List<Object>):List<Object> {
324+
validate(completeSample:List<MeasureValues>):List<MeasureValues> {
319325
var stableSample = isPresent(this._validate) ? this._validate(completeSample) : completeSample;
320326
ListWrapper.push(this._log, ['validate', completeSample, stableSample]);
321327
return stableSample;
@@ -353,8 +359,8 @@ class MockReporter extends Reporter {
353359
}
354360
this._log = log;
355361
}
356-
reportMeasureValues(index, values):Promise {
357-
ListWrapper.push(this._log, ['reportMeasureValues', index, values]);
362+
reportMeasureValues(values):Promise {
363+
ListWrapper.push(this._log, ['reportMeasureValues', values]);
358364
return PromiseWrapper.resolve(null);
359365
}
360366
reportSample(completeSample, validSample):Promise {

0 commit comments

Comments
 (0)