Introduction
touchstone is a metadata-driven benchmarking framework, built on top of benchmark.js
Declarative Benchmarks
With touchstone you define your benchmark like this:
import { Suite, Case } from '@pebula/touchstone';
@Suite({ name: 'My First Benchmark Suite' })
class MyFirstBenchmarkSuite {
@Case({ name: 'my-first-benchmark' })
firstBenchmark() {
/* Benchmarking... */
}
@Case()
async secondBenchmark() {
// Will automatically detect that it's async. Name is taken from method name.
/* Benchmarking... */
}
}
Life Cycle Events
All benchmark.js event are wrapped and delivered in a normalized manner:
@Suite()
class TestSuite {
@OnStart() start(event: SuiteStartEvent) { }
@OnCaseComplete() caseComplete(event: CaseCompleteEvent) { }
@OnComplete() complete(event: SuiteCompleteEvent) { }
// @OnReset, @OnAbort, @OnError
}
There are additional, touchstone specific, events...
Composition & Re-use
touchstone is fully extensible through inheritance or composition (mixins):
import { Suite, Case, Mixin, VegaLiteReporter, SimpleConsoleReporter } from '@pebula/touchstone';
@Suite({ name: 'My First Benchmark Suite' })
class MyFirstBenchmarkSuite extends Mixin(SimpleConsoleReporter, VegaLiteReporter) {
@Case({ name: 'my-first-benchmark' })
firstBenchmark() {
/* Benchmarking... */
}
}
In the example above we Mixin reporting behavior from 2 built-in reporters:
SimpleConsoleReporter- Will log progress to the consoleVegaLiteReporter- Will output HTML, SVG and PNG charts using vega-lite
TouchStone Events
There are 2 touchstone events:
@OnTouchStoneStart()- Fired with theTouchStoneStartEventevent context parameter@OnTouchStoneEnd()- Fired with theTouchStoneEndEventevent context parameter (which contains theSuiteResult[]property)
Both events can be registered on any suite.
Multiple Suites
You can declare multiple suite's, touchstone will execute them one after the other.
Because multiple suites can be used for a single run it might not make sense to register mixins on the suite. For suite events this might be ok but the touchstone start/end events will trigger multiple times, once for every suite.
For this scenario, and in general, we recommend using a container to manage all mixins, configuration, etc... The container events will invoke once for all of the events in the system. (i.e. A case complete event, from any suite, will fire once on the container)
Execute
To execute the suite/s and start benchmarking you need to invoke the touchStone() function.
import { Suite, Case, touchStone } from '@pebula/touchstone';
@Suite({ name: 'My First Benchmark Suite' })
class MyFirstBenchmarkSuite {
@Case({ name: 'my-first-benchmark' })
firstBenchmark() {
/* Benchmarking... */
}
@Case()
async secondBenchmark() {
// Will automatically detect that it's async. Name is taken from method name.
/* Benchmarking... */
}
}
await touchStone();
When using a touchstone configuration container you don't need to call touchStone(), the benchmark
will automatically execute.
Demo
The following is the output of the a demo benchmark application: benchmark-chart