@@ -30,6 +30,56 @@ class RunData {
30
30
this . options = options ;
31
31
this . runs = runs ;
32
32
}
33
+
34
+ static resultsDataFromSingleRunData ( singleRunData )
35
+ {
36
+ RunData . #migrateImportedData( singleRunData ) ;
37
+
38
+ if ( ! singleRunData . data instanceof Array ) {
39
+ console . error ( 'Imported singleRunData.data is not an array. Bailing' ) ;
40
+ return null ;
41
+ }
42
+
43
+ return new RunData ( singleRunData . version , singleRunData . options , singleRunData . data ) ;
44
+ }
45
+
46
+ static resultsDataFromBenchmarkRunnerData ( benchmarkData )
47
+ {
48
+ if ( ! benchmarkData instanceof Array ) {
49
+ console . log ( 'Imported benchmarkData is not an array. Bailing' ) ;
50
+ return null ;
51
+ }
52
+
53
+ const runData = [ ] ;
54
+ for ( const run of benchmarkData ) {
55
+ RunData . #migrateImportedData( run ) ;
56
+ if ( run . data . length !== 1 ) {
57
+ console . error ( 'Imported benchmarkData has a "data" array with an unexpected number of items. Bailing' ) ;
58
+ return null ;
59
+ }
60
+
61
+ runData . push ( run . data [ 0 ] ) ;
62
+ }
63
+
64
+ // Version and options data should be these same for each run. Use the first run's information.
65
+ return new RunData ( benchmarkData [ 0 ] . version , benchmarkData [ 0 ] . options , runData ) ;
66
+ }
67
+
68
+ static #migrateImportedData( options )
69
+ {
70
+ if ( ! ( "version" in options ) )
71
+ options . version = "1.0" ;
72
+
73
+ if ( ! ( "frame-rate" in options ) ) {
74
+ options . options [ "frame-rate" ] = 60 ;
75
+ console . log ( "No frame-rate data; assuming 60fps" )
76
+ }
77
+
78
+ if ( ! ( "system-frame-rate" in options ) ) {
79
+ options . options [ "system-frame-rate" ] = 60 ;
80
+ console . log ( "No system-frame-rate data; assuming 60fps" )
81
+ }
82
+ }
33
83
}
34
84
35
85
class ScoreCalculator {
@@ -109,36 +159,37 @@ class ScoreCalculator {
109
159
110
160
calculateScore ( data )
111
161
{
112
- var result = { } ;
162
+ const result = { } ;
113
163
data [ Strings . json . result ] = result ;
114
- var samples = data [ Strings . json . samples ] ;
164
+ const samples = data [ Strings . json . samples ] ;
115
165
const desiredFrameLength = 1000 / this . _targetFrameRate ;
166
+ const complexityKey = Strings . json . complexity ;
116
167
117
168
function findRegression ( series , profile ) {
118
- var minIndex = Math . round ( .025 * series . length ) ;
119
- var maxIndex = Math . round ( .975 * ( series . length - 1 ) ) ;
120
- var minComplexity = series . getFieldInDatum ( minIndex , Strings . json . complexity ) ;
121
- var maxComplexity = series . getFieldInDatum ( maxIndex , Strings . json . complexity ) ;
169
+ const minIndex = Math . round ( .025 * series . length ) ;
170
+ const maxIndex = Math . round ( .975 * ( series . length - 1 ) ) ;
171
+ const minComplexity = series . getFieldInDatum ( minIndex , complexityKey ) ;
172
+ const maxComplexity = series . getFieldInDatum ( maxIndex , complexityKey ) ;
122
173
123
174
if ( Math . abs ( maxComplexity - minComplexity ) < 20 && maxIndex - minIndex < 20 ) {
124
175
minIndex = 0 ;
125
176
maxIndex = series . length - 1 ;
126
- minComplexity = series . getFieldInDatum ( minIndex , Strings . json . complexity ) ;
127
- maxComplexity = series . getFieldInDatum ( maxIndex , Strings . json . complexity ) ;
177
+ minComplexity = series . getFieldInDatum ( minIndex , complexityKey ) ;
178
+ maxComplexity = series . getFieldInDatum ( maxIndex , complexityKey ) ;
128
179
}
129
180
130
- var frameTypeIndex = series . fieldMap [ Strings . json . frameType ] ;
131
- var complexityIndex = series . fieldMap [ Strings . json . complexity ] ;
132
- var frameLengthIndex = series . fieldMap [ Strings . json . frameLength ] ;
133
- var regressionOptions = { desiredFrameLength : desiredFrameLength } ;
181
+ const frameTypeIndex = series . fieldMap [ Strings . json . frameType ] ;
182
+ const complexityIndex = series . fieldMap [ complexityKey ] ;
183
+ const frameLengthIndex = series . fieldMap [ Strings . json . frameLength ] ;
184
+ const regressionOptions = { desiredFrameLength : desiredFrameLength } ;
134
185
if ( profile )
135
186
regressionOptions . preferredProfile = profile ;
136
187
137
- var regressionSamples = series . slice ( minIndex , maxIndex + 1 ) ;
138
- var animationSamples = regressionSamples . data . filter ( ( sample ) => sample [ frameTypeIndex ] == Strings . json . animationFrameType ) ;
139
- var regressionData = animationSamples . map ( ( sample ) => [ sample [ complexityIndex ] , sample [ frameLengthIndex ] ] ) ;
188
+ const regressionSamples = series . slice ( minIndex , maxIndex + 1 ) ;
189
+ const animationSamples = regressionSamples . data . filter ( ( sample ) => sample [ frameTypeIndex ] == Strings . json . animationFrameType ) ;
190
+ const regressionData = animationSamples . map ( ( sample ) => [ sample [ complexityIndex ] , sample [ frameLengthIndex ] ] ) ;
140
191
141
- var regression = new Regression ( regressionData , minIndex , maxIndex , regressionOptions ) ;
192
+ const regression = new Regression ( regressionData , minIndex , maxIndex , regressionOptions ) ;
142
193
return {
143
194
minComplexity : minComplexity ,
144
195
maxComplexity : maxComplexity ,
@@ -148,14 +199,14 @@ class ScoreCalculator {
148
199
}
149
200
150
201
// Convert these samples into SampleData objects if needed
151
- [ Strings . json . complexity , Strings . json . controller ] . forEach ( function ( seriesName ) {
152
- var series = samples [ seriesName ] ;
202
+ [ complexityKey , Strings . json . controller ] . forEach ( function ( seriesName ) {
203
+ const series = samples [ seriesName ] ;
153
204
if ( series && ! ( series instanceof SampleData ) )
154
205
samples [ seriesName ] = new SampleData ( series . fieldMap , series . data ) ;
155
206
} ) ;
156
207
157
- var isRampController = this . _runData . options [ Strings . json . controller ] == "ramp" ;
158
- var predominantProfile = "" ;
208
+ const isRampController = this . _runData . options [ Strings . json . controller ] == "ramp" ;
209
+ let predominantProfile = "" ;
159
210
if ( isRampController ) {
160
211
var profiles = { } ;
161
212
data [ Strings . json . controller ] . forEach ( function ( regression ) {
@@ -174,44 +225,44 @@ class ScoreCalculator {
174
225
}
175
226
}
176
227
177
- var regressionResult = findRegression ( samples [ Strings . json . complexity ] , predominantProfile ) ;
178
- var calculation = regressionResult . regression ;
179
- result [ Strings . json . complexity ] = { } ;
180
- result [ Strings . json . complexity ] [ Strings . json . regressions . segment1 ] = [
228
+ const regressionResult = findRegression ( samples [ complexityKey ] , predominantProfile ) ;
229
+ const calculation = regressionResult . regression ;
230
+ result [ complexityKey ] = { } ;
231
+ result [ complexityKey ] [ Strings . json . regressions . segment1 ] = [
181
232
[ regressionResult . minComplexity , calculation . s1 + calculation . t1 * regressionResult . minComplexity ] ,
182
233
[ calculation . complexity , calculation . s1 + calculation . t1 * calculation . complexity ]
183
234
] ;
184
- result [ Strings . json . complexity ] [ Strings . json . regressions . segment2 ] = [
235
+ result [ complexityKey ] [ Strings . json . regressions . segment2 ] = [
185
236
[ calculation . complexity , calculation . s2 + calculation . t2 * calculation . complexity ] ,
186
237
[ regressionResult . maxComplexity , calculation . s2 + calculation . t2 * regressionResult . maxComplexity ]
187
238
] ;
188
- result [ Strings . json . complexity ] [ Strings . json . complexity ] = calculation . complexity ;
189
- result [ Strings . json . complexity ] [ Strings . json . measurements . stdev ] = Math . sqrt ( calculation . error / samples [ Strings . json . complexity ] . length ) ;
239
+ result [ complexityKey ] [ complexityKey ] = calculation . complexity ;
240
+ result [ complexityKey ] [ Strings . json . measurements . stdev ] = Math . sqrt ( calculation . error / samples [ complexityKey ] . length ) ;
190
241
191
242
result [ Strings . json . fps ] = data . targetFPS ;
192
243
193
244
if ( isRampController ) {
194
- var timeComplexity = new Experiment ;
245
+ const timeComplexity = new Experiment ;
195
246
data [ Strings . json . controller ] . forEach ( function ( regression ) {
196
- timeComplexity . sample ( regression [ Strings . json . complexity ] ) ;
247
+ timeComplexity . sample ( regression [ complexityKey ] ) ;
197
248
} ) ;
198
249
199
- var experimentResult = { } ;
250
+ const experimentResult = { } ;
200
251
result [ Strings . json . controller ] = experimentResult ;
201
252
experimentResult [ Strings . json . score ] = timeComplexity . mean ( ) ;
202
253
experimentResult [ Strings . json . measurements . average ] = timeComplexity . mean ( ) ;
203
254
experimentResult [ Strings . json . measurements . stdev ] = timeComplexity . standardDeviation ( ) ;
204
255
experimentResult [ Strings . json . measurements . percent ] = timeComplexity . percentage ( ) ;
205
256
206
257
const bootstrapIterations = this . _runData . options [ Strings . json . bootstrapIterations ] ;
207
- var bootstrapResult = Regression . bootstrap ( regressionResult . samples . data , bootstrapIterations , function ( resampleData ) {
208
- var complexityIndex = regressionResult . samples . fieldMap [ Strings . json . complexity ] ;
258
+ const bootstrapResult = Regression . bootstrap ( regressionResult . samples . data , bootstrapIterations , function ( resampleData ) {
259
+ const complexityIndex = regressionResult . samples . fieldMap [ complexityKey ] ;
209
260
resampleData . sort ( function ( a , b ) {
210
261
return a [ complexityIndex ] - b [ complexityIndex ] ;
211
262
} ) ;
212
263
213
- var resample = new SampleData ( regressionResult . samples . fieldMap , resampleData ) ;
214
- var bootstrapRegressionResult = findRegression ( resample , predominantProfile ) ;
264
+ const resample = new SampleData ( regressionResult . samples . fieldMap , resampleData ) ;
265
+ const bootstrapRegressionResult = findRegression ( resample , predominantProfile ) ;
215
266
if ( bootstrapRegressionResult . regression . t2 < 0 ) {
216
267
// A positive slope means the frame rate decreased with increased complexity (which is the expected
217
268
// benavior). OTOH, a negative slope means the framerate increased as the complexity increased. This
@@ -224,24 +275,24 @@ class ScoreCalculator {
224
275
return bootstrapRegressionResult . regression . complexity ;
225
276
} , .8 ) ;
226
277
227
- result [ Strings . json . complexity ] [ Strings . json . bootstrap ] = bootstrapResult ;
278
+ result [ complexityKey ] [ Strings . json . bootstrap ] = bootstrapResult ;
228
279
result [ Strings . json . score ] = bootstrapResult . median ;
229
280
result [ Strings . json . scoreLowerBound ] = bootstrapResult . confidenceLow ;
230
281
result [ Strings . json . scoreUpperBound ] = bootstrapResult . confidenceHigh ;
231
282
} else {
232
- var marks = data [ Strings . json . marks ] ;
233
- var samplingStartIndex = 0 , samplingEndIndex = - 1 ;
283
+ const marks = data [ Strings . json . marks ] ;
284
+ let samplingStartIndex = 0 , samplingEndIndex = - 1 ;
234
285
if ( Strings . json . samplingStartTimeOffset in marks )
235
286
samplingStartIndex = marks [ Strings . json . samplingStartTimeOffset ] . index ;
236
287
if ( Strings . json . samplingEndTimeOffset in marks )
237
288
samplingEndIndex = marks [ Strings . json . samplingEndTimeOffset ] . index ;
238
289
239
- var averageComplexity = new Experiment ;
240
- var averageFrameLength = new Experiment ;
241
- var controllerSamples = samples [ Strings . json . controller ] ;
290
+ const averageComplexity = new Experiment ;
291
+ const averageFrameLength = new Experiment ;
292
+ const controllerSamples = samples [ Strings . json . controller ] ;
242
293
controllerSamples . forEach ( function ( sample , i ) {
243
294
if ( i >= samplingStartIndex && ( samplingEndIndex == - 1 || i < samplingEndIndex ) ) {
244
- averageComplexity . sample ( controllerSamples . getFieldInDatum ( sample , Strings . json . complexity ) ) ;
295
+ averageComplexity . sample ( controllerSamples . getFieldInDatum ( sample , complexityKey ) ) ;
245
296
var smoothedFrameLength = controllerSamples . getFieldInDatum ( sample , Strings . json . smoothedFrameLength ) ;
246
297
if ( smoothedFrameLength && smoothedFrameLength != - 1 )
247
298
averageFrameLength . sample ( smoothedFrameLength ) ;
@@ -346,14 +397,14 @@ class ResultsTable {
346
397
347
398
_addHeader ( )
348
399
{
349
- var thead = Utilities . createElement ( "thead" , { } , this . element ) ;
350
- var row = Utilities . createElement ( "tr" , { } , thead ) ;
400
+ const thead = Utilities . createElement ( "thead" , { } , this . element ) ;
401
+ const row = Utilities . createElement ( "tr" , { } , thead ) ;
351
402
352
403
this . _headers . forEach ( function ( header ) {
353
404
if ( header . disabled )
354
405
return ;
355
406
356
- var th = Utilities . createElement ( "th" , { } , row ) ;
407
+ const th = Utilities . createElement ( "th" , { } , row ) ;
357
408
if ( header . title != Strings . text . graph )
358
409
th . innerHTML = header . title ;
359
410
if ( header . children )
@@ -368,18 +419,18 @@ class ResultsTable {
368
419
369
420
_addEmptyRow ( )
370
421
{
371
- var row = Utilities . createElement ( "tr" , { } , this . tbody ) ;
422
+ const row = Utilities . createElement ( "tr" , { } , this . tbody ) ;
372
423
this . _flattenedHeaders . forEach ( function ( header ) {
373
424
return Utilities . createElement ( "td" , { class : "suites-separator" } , row ) ;
374
425
} ) ;
375
426
}
376
427
377
428
_addTest ( testName , testResult , options )
378
429
{
379
- var row = Utilities . createElement ( "tr" , { } , this . tbody ) ;
430
+ const row = Utilities . createElement ( "tr" , { } , this . tbody ) ;
380
431
381
432
this . _flattenedHeaders . forEach ( function ( header ) {
382
- var td = Utilities . createElement ( "td" , { } , row ) ;
433
+ const td = Utilities . createElement ( "td" , { } , row ) ;
383
434
if ( header . text == Strings . text . testName ) {
384
435
td . textContent = testName ;
385
436
} else if ( typeof header . text == "string" ) {
@@ -394,12 +445,12 @@ class ResultsTable {
394
445
395
446
_addIteration ( iterationResult , iterationData , options )
396
447
{
397
- var testsResults = iterationResult [ Strings . json . results . tests ] ;
398
- for ( var suiteName in testsResults ) {
448
+ const testsResults = iterationResult [ Strings . json . results . tests ] ;
449
+ for ( const suiteName in testsResults ) {
399
450
this . _addEmptyRow ( ) ;
400
- var suiteResult = testsResults [ suiteName ] ;
401
- var suiteData = iterationData [ suiteName ] ;
402
- for ( var testName in suiteResult )
451
+ const suiteResult = testsResults [ suiteName ] ;
452
+ const suiteData = iterationData [ suiteName ] ;
453
+ for ( let testName in suiteResult )
403
454
this . _addTest ( testName , suiteResult [ testName ] , options , suiteData [ testName ] ) ;
404
455
}
405
456
}
@@ -410,7 +461,7 @@ class ResultsTable {
410
461
this . _addHeader ( ) ;
411
462
this . _addBody ( ) ;
412
463
413
- var iterationsResults = scoreCalculator . results ;
464
+ const iterationsResults = scoreCalculator . results ;
414
465
iterationsResults . forEach ( function ( iterationResult , index ) {
415
466
this . _addIteration ( iterationResult , scoreCalculator . data [ index ] , scoreCalculator . options ) ;
416
467
} , this ) ;
0 commit comments