eruda-benchmark / src /index.js
soiz1's picture
Update src/index.js
8823b5e verified
const defBench = require('./defBench')
// https://github.com/bestiejs/benchmark.js/issues/128
const _ = require('lodash')
const each = require('licia/each')
const $ = require('licia/$')
const isArr = require('licia/isArr')
const escape = require('licia/escape')
const map = require('licia/map')
const process = require('process')
const benchmark = require('benchmark')
const Benchmark = benchmark.runInContext({ _, process })
window.Benchmark = Benchmark
module.exports = function (eruda) {
let { evalCss } = eruda.util
class BenchmarkTool extends eruda.Tool {
constructor() {
super()
this.name = 'benchmark'
this.displayName = 'ベンチマーク'
this._style = evalCss(require('./style.scss'))
this._benches = []
}
init($el, container) {
super.init($el, container)
this._addDefBench()
this._bindEvent()
}
show() {
super.show()
}
hide() {
super.hide()
}
destroy() {
super.destroy()
evalCss.remove(this._style)
}
add(name, fn) {
return isArr(fn)
? this._addBenchSuite(name, fn)
: this._addBench(name, fn)
}
_addBenchSuite(name, fns) {
let benches = this._benches
let self = this
let bench = {
name,
result: null,
stores: [],
status: 'ready',
}
let suite = new Benchmark.Suite(name, {
onStart() {
bench.status = 'running'
bench.stores = []
bench.result = null
self._render()
},
onCycle(e) {
if (bench.status === 'error') return
bench.stores.push(e.target)
bench.result = formatBenches(bench.stores)
self._updateResult(bench, bench.result)
},
onError(e) {
bench.status = 'error'
bench.result = e.message.message
self._render()
},
onAbort() {
if (bench.status === 'error') return
bench.status = 'abort'
self._render()
},
onComplete() {
if (bench.status === 'error') return
bench.status = 'complete'
bench.result = formatBenches(bench.stores)
self._render()
},
})
each(fns, ({ name, fn }) => suite.add(name, fn))
bench.bench = suite
benches.push(bench)
return this._render()
}
_addBench(name, fn) {
let benches = this._benches
let self = this
let bench = {
bench: new Benchmark(name, fn, {
onStart() {
bench.status = 'running'
bench.result = null
self._render()
},
onCycle() {
if (bench.status === 'error') return
bench.result = formatBench(this)
self._updateResult(bench, bench.result)
},
onError(e) {
bench.status = 'error'
bench.result = e.message.message
self._render()
},
onAbort() {
if (bench.status === 'error') return
bench.status = 'abort'
self._render()
},
onComplete() {
if (bench.status === 'error') return
bench.status = 'complete'
bench.result = formatBench(this)
self._render()
},
}),
name,
result: null,
status: 'ready',
}
benches.push(bench)
return this._render()
}
remove(name) {
let benches = this._benches
for (let i = benches.length - 1; i >= 0; i--) {
if (benches[i].name === name) benches.splice(i, 1)
}
return this._render()
}
clear() {
this._benches = []
return this._render()
}
run(name) {
let benches = this._benches
for (let i = 0, len = benches.length; i < len; i++) {
if (benches[i].name === name) this._run(i)
}
return this
}
_render() {
let benches = this._benches
each(benches, (bench) => {
bench.isRunning = bench.status === 'running'
})
const html = `<ul>
${map(benches, (bench, idx) => {
return `<li>
<h2 class="eruda-title">${escape(
bench.name
)}<span class="eruda-status">${bench.status}</span></h2>
<div class="eruda-result" data-idx="${idx}">${
bench.result || ''
}</div>
<div class="eruda-btn ${
bench.isRunning ? 'eruda-disabled' : 'eruda-run'
}" data-idx="${idx}">実行</div>
</li>`
}).join('')}
</ul>`
this._$el.html(html)
return this
}
_run(idx) {
this._benches[idx].bench.run({ async: true })
}
_updateResult(bench, result) {
let benches = this._benches
let i = 0
for (let len = benches.length; i < len; i++) {
if (benches[i] === bench) break
}
this._$el.find(`.eruda-result[data-idx="${i}"]`).html(result)
}
_addDefBench() {
each(defBench, ({ name, fn }) => this.add(name, fn))
}
_bindEvent() {
let self = this
this._$el.on('click', '.eruda-run', function () {
let idx = $(this).data('idx')
self._run(idx)
})
}
}
return new BenchmarkTool()
}
function formatBench(bench, name) {
let { hz, stats } = bench
let ops = hz.toFixed(hz < 100 ? 2 : 0),
deviation = stats.rme.toFixed(2),
size = stats.sample.length
return `
<div class="eruda-result-item">
${
name
? '<div class="eruda-result-item-name">' + name + '</div> x '
: ''
}<div class="eruda-result-number">${ops}</div> ops/sec \xb1<div class="eruda-result-number">${deviation}</div>% (<div class="eruda-result-number">${size}</div> runs sampled)
</div>
`
}
function formatBenches(benches) {
let result = []
for (let i = 0, len = benches.length; i < len; i++) {
let bench = benches[i]
result.push(formatBench(bench, bench.name))
}
return result.join('')
}