You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

244 lines
8.2 KiB

var Class = require('./Class');
var defaults = require('./defaults');
var Promise = require('./Promise');
var perfNow = require('./perfNow');
var delay = require('./delay');
var average = require('./average');
var reduce = require('./reduce');
var each = require('./each');
var map = require('./map');
var table = require('./table');
var toStr = require('./toStr');
exports = Class(
{
initialize: function Benchmark(fn) {
var options =
arguments.length > 1 && arguments[1] !== undefined
? arguments[1]
: {};
defaults(options, defOpts);
this._fn = fn;
this._isRunning = false;
this._options = options;
},
run: function() {
var _this = this;
if (this._isRunning) {
return this._pendingPromise;
}
this._reset();
this._isRunning = true;
var options = this._options;
var pendingPromise = new Promise(function(resolve, reject) {
var runSample = function() {
var initCount =
arguments.length > 0 && arguments[0] !== undefined
? arguments[0]
: 1;
delay(function() {
_this
._runSample(initCount)
.then(function(_ref) {
var period = _ref.period,
count = _ref.count;
var sample = _this._sample;
sample.push(period);
if (
perfNow() - _this._timeStamp <
options.maxTime ||
sample.length < options.minSamples
) {
runSample(count);
} else {
resolve(_this._calcResult());
}
})
.catch(function(err) {
reject(err);
});
}, options.delay);
};
runSample();
});
function complete() {
this._isRunning = false;
delete this._pendingPromise;
}
pendingPromise.then(complete).catch(complete);
this._pendingPromise = pendingPromise;
return pendingPromise;
},
_reset: function() {
this._timeStamp = perfNow();
this._sample = [];
},
_calcResult: function() {
var sample = this._sample;
var result = {
sample: sample,
toString: function() {
var hz = this.hz,
rme = this.rme,
name = this.name;
var size = this.sample.length;
return ''
.concat(name, ' x ')
.concat(
formatNumber(hz.toFixed(hz < 100 ? 2 : 0)),
' ops/sec \xB1'
)
.concat(rme.toFixed(2), '% (')
.concat(size, ' run')
.concat(size === 1 ? '' : 's', ' sampled)');
}
};
var size = sample.length;
result.name = this._options.name || this._fn.name || 'anonymous';
result.mean = average.apply(null, sample);
function varOf(sum, x) {
return sum + Math.pow(x - result.mean, 2);
}
result.variance = reduce(sample, varOf, 0) / (size - 1) || 0;
result.deviation = Math.sqrt(result.variance);
result.sem = result.deviation / Math.sqrt(size);
var critical = tTable[Math.round(size - 1) || 1] || tTable.infinity;
result.moe = result.sem * critical;
result.rme = (result.moe / result.mean) * 100 || 0;
result.hz = 1000 / result.mean;
return result;
},
_runSample: function(count) {
var _this2 = this;
var options = this._options;
var minTime = options.minTime;
return new Promise(function(resolve, reject) {
var runCycle = function(count) {
delay(function() {
var elapsed = 0;
try {
elapsed = _this2._runCycle(count);
} catch (e) {
return reject(e);
}
var period = elapsed / count;
if (elapsed < minTime) {
if (elapsed === 0) {
count *= 100;
} else {
count += Math.ceil(
(minTime - elapsed) / period
);
}
runCycle(count);
} else {
resolve({
count: count,
period: period
});
}
}, options.delay);
};
runCycle(count);
});
},
_runCycle: function(count) {
var fn = this._fn;
var now = perfNow();
while (count--) {
fn();
}
return perfNow() - now;
}
},
{
all: function(benches, options) {
var promises = [];
each(benches, function(bench) {
if (!(bench instanceof exports)) {
bench = new exports(bench, options);
}
promises.push(bench.run());
});
return Promise.all(promises).then(function(results) {
results.toString = function() {
var data = map(results, function(_ref2, idx) {
var name = _ref2.name,
sample = _ref2.sample,
hz = _ref2.hz,
rme = _ref2.rme;
var columns = [];
var size = sample.length;
columns.push(
toStr(idx + 1),
name || 'anonymous',
formatNumber(hz.toFixed(hz < 100 ? 2 : 0)),
'\xB1'.concat(rme.toFixed(2), '%'),
''
.concat(size, ' run')
.concat(size === 1 ? '' : 's')
);
return columns;
});
data.unshift([
'index',
'name',
'ops/sec',
'rme',
'sampled'
]);
return table(data);
};
return results;
});
}
}
);
var defOpts = {
minTime: 50,
maxTime: 5000,
minSamples: 5,
delay: 5,
name: ''
};
var tTable = {
'1': 12.706,
'2': 4.303,
'3': 3.182,
'4': 2.776,
'5': 2.571,
'6': 2.447,
'7': 2.365,
'8': 2.306,
'9': 2.262,
'10': 2.228,
'11': 2.201,
'12': 2.179,
'13': 2.16,
'14': 2.145,
'15': 2.131,
'16': 2.12,
'17': 2.11,
'18': 2.101,
'19': 2.093,
'20': 2.086,
'21': 2.08,
'22': 2.074,
'23': 2.069,
'24': 2.064,
'25': 2.06,
'26': 2.056,
'27': 2.052,
'28': 2.048,
'29': 2.045,
'30': 2.042,
infinity: 1.96
};
function formatNumber(number) {
number = String(number).split('.');
return (
number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') +
(number[1] ? '.' + number[1] : '')
);
}
module.exports = exports;