react/perf/lib/BrowserPerfRunnerApp.react.js
2014-01-06 12:26:40 -05:00

206 lines
5.8 KiB
JavaScript

var BrowserPerfRunnerApp = React.createClass({
propTypes: {
tests: React.PropTypes.array.isRequired,
react: React.PropTypes.array.isRequired,
maxTime: React.PropTypes.number,
onCompleteEach: React.PropTypes.func,
onComplete: React.PropTypes.func,
onError: React.PropTypes.func,
headless: React.PropTypes.bool
},
getInitialState: function(){
var queue = [];
this.props.tests.forEach(function(testName){
this.props.react.forEach(function(version){
queue.push({
test: testName,
react: version
});
},this);
},this);
return {
queue: queue,
results: {}
};
},
handleResults: function(results){
this.state.results[results.test + '@' + results.react] = results;
this.replaceState(this.state);
},
handleComplete: function(queueItem){
queueItem.completed = true;
if (!this.props.onCompleteEach) {
return;
}
// Can't get the resultsForAllVersions if there are still some queued
var incompleteCount = 0;
for (var index = this.state.queue.length; --index >= 0;){
if (this.state.queue[index].completed) {
continue;
}
if (this.state.queue[index].test === queueItem.test) {
return;
}
incompleteCount ++;
}
var resultsForAllVersions = Object.keys(this.state.results)
.filter(function(key){return key.indexOf(queueItem.test) === 0;})
.map(function(key){return this.state.results[key];}, this)
;
this.props.onCompleteEach(resultsForAllVersions);
if (this.props.onComplete && incompleteCount === 0) {
this.props.onComplete(this.state.results);
}
},
render: function(){
var grid = null;
if (!this.props.headless) {
grid = GridViewTable({
rows: this.props.tests,
cols: this.props.react,
renderCell: BrowserPerfRunnerApp.renderBenchmarkCell,
value: this.state.results
});
}
return React.DOM.div(null,
BenchmarkQueue({
initialQueue: this.state.queue,
onChange: this.handleResults,
maxTime: this.props.maxTime,
onCompleteEach: this.handleComplete,
onError: this.props.onError
}),
grid
);
}
});
BrowserPerfRunnerApp.renderBenchmarkCell = function(props, row, col){
if (col == null && row == null) return React.DOM.th(null);
if (row == null) return React.DOM.th({style:{verticalAlign:'top', textAlign:'center'}}, col);
var benchmarks = Object.keys(props.value)
.filter(function(key){
return key.indexOf(row) === 0;
})
.map(function(key){
return props.value[key];
})
.filter(function(benchmark){
return benchmark && !benchmark.isRunning && benchmark.stats;
})
;
if (col == null) return React.DOM.th({style:{verticalAlign:'top', textAlign:'right'}},
React.DOM.a({href:'?test=' + row}, benchmarks[0] && benchmarks[0].name || row)
);
var key = row + '@' + col;
var benchmark = props.value[key];
if (!(benchmark && benchmark.stats)) return React.DOM.td({key:key});
var colors = [
'000000',
'AA0000',
'00AA00',
'AA5500',
'0000AA',
'AA00AA',
'00AAAA',
'AAAAAA',
'555555',
'FF5555',
'55FF55',
'FFFF55',
'5555FF',
'FF55FF',
'55FFFF',
'FFFFFF'
];
function chartValue(value){
return Math.round(valueFromRangeToRange(value, chartValue.min, chartValue.max, 0, 100));
}
chartValue.min = Math.min.apply(Math, benchmarks.map(function(benchmark){return Math.min.apply(Math, benchmark.stats.sample);}));
chartValue.max = Math.max.apply(Math, benchmarks.map(function(benchmark){return Math.max.apply(Math, benchmark.stats.sample);}));
var means = benchmarks.map(function(benchmark){
return benchmark.stats.mean;
});
benchmarks.forEach(function(benchmark){
benchmark.isTheWinner = benchmark.stats.mean <= Math.min.apply(Math, means);
});
var chartValues = benchmarks.map(function(benchmark){
// benchmark.stats.sample.sort(function(a,b){return b - a;});
return benchmark.stats.sample.map(chartValue).join(',');
}).join('|');
return (
React.DOM.td({key:key, style:{textAlign:'center', width:234, verticalAlign:'top'}},
benchmark.error && benchmark.error.message || '',
React.DOM.div({style: benchmark.isTheWinner ? { backgroundColor:'#0A5', color:'#AFA' } : {backgroundColor:'transparent', color:'inherit'}},
Math.round(1 / benchmark.stats.mean * 100) / 100, " op/s ",
React.DOM.strong(null, Math.round(benchmark.stats.mean * 1000 * 100) / 100, " ms/op "),
React.DOM.small(null, "(±" + (Math.round(benchmark.stats.rme * 10) / 10) + "%)")
),
benchmark.isRunning && 'Running' || React.DOM.img({
style: {
borderWidth: 2,
borderStyle: 'solid',
color: '#' + colors[benchmarks.indexOf(benchmark)]
},
width: 230,
height: 50,
src: 'https://chart.googleapis.com/chart?cht=ls&chs=460x100&chd=t:' + chartValues + '&chco=' + colors.join(',')
})
)
);
}
function valueFromRangeToRange(value, fromMin, fromMax, toMin, toMax){
var fromRange = fromMax - fromMin;
var toRange = toMax - toMin;
return (((value - fromMin) * toRange) / fromRange) + toMin;
}
var GridViewTable = React.createClass({
propTypes: {
rows: React.PropTypes.array.isRequired,
cols: React.PropTypes.array.isRequired,
renderCell: React.PropTypes.func.isRequired
},
_renderCell: function(col){
return this.props.renderCell({ value:this.props.value }, this._row, col);
},
_renderRow: function(row){
this._row = row;
return React.DOM.tr({key:row},
this._renderCell(null, 0),
this.props.cols.map(this._renderCell, this)
);
},
render: function(){
return React.DOM.table(null,
this._renderRow(null, 0),
this.props.rows.map(this._renderRow, this)
);
}
});