benchmark.js icon indicating copy to clipboard operation
benchmark.js copied to clipboard

Document how to get an array of all suite results

Open gajus opened this issue 9 years ago • 1 comments

I have tried:

suite
  .on('complete', function () {
    // eslint-disable-next-line babel/no-invalid-this
    const benchmarks = Object.values(this);
  });

However, here this is an object that contains each suite as {[benchmark index]: results, plus some arbitrary properties}.

I cannot not find anything in the https://benchmarkjs.com/ that says getSuiteResultList or anything along those lines.

The only reasonable way I have found to do this is to built the results array using the cycle event.

suite
  .on('cycle', (event) => {
    results.push(event.target);
  })
  .on('complete', () => {
    console.log(results);
  });

gajus avatar Dec 03 '16 12:12 gajus

I have a proposal for a code sample that may help the documentation:

const Benchmark = require('benchmark');

const MIN_INPUT_SIZE = 1;
const MAX_INPUT_SIZE = 10000;
const INPUT_SIZE_INCREMENTOR = inputSize => inputSize * 10;
const PRECISION = 2;

for (
  let INPUT_SIZE = MIN_INPUT_SIZE;
  INPUT_SIZE <= MAX_INPUT_SIZE;
  INPUT_SIZE = INPUT_SIZE_INCREMENTOR(INPUT_SIZE)
) {
  const results = [];
  const suite = new Benchmark.Suite();

  const array = [];
  const set = new Set();
  const map = new Map();

  for (let i = 0; i < INPUT_SIZE; ++i) {
    array.push(Math.random());
    set.add(Math.random());
    map.set(Math.random(), true);
  }

  suite

    // add tests
    .add('array.includes', () => {
      array.includes(Math.random());
    })
    .add('set.has', () => {
      set.has(Math.random());
    })
    .add('map.has', () => {
      map.has(Math.random());
    })

    // add listeners
    .on('start', () => console.log(`\nStarting benchmarks for INPUT_SIZE ${INPUT_SIZE}`))
    .on('cycle', event =>
      results.push({
        name: event.target.name,
        hz: event.target.hz,
        'margin of error': `±${Number(event.target.stats.rme).toFixed(2)}%`,
        'runs sampled': event.target.stats.sample.length,
      })
    )
    .on('complete', function() {
      const lowestHz = results.slice().sort((a, b) => a.hz - b.hz)[0].hz;

      console.table(
        results
          .sort((a, b) => b.hz - a.hz)
          .map(result => ({
            ...result,
            hz: Math.round(result.hz).toLocaleString(),
            numTimesFaster: Math.round((10 ** PRECISION * result.hz) / lowestHz) / 10 ** PRECISION,
          }))
          .sort((a, b) => a.INPUT_SIZE - b.INPUT_SIZE)
          .reduce((acc, { name, ...cur }) => ({ ...acc, [name]: cur }), {})
      );
      console.log('Fastest is ' + this.filter('fastest').map('name'));
    })

    .run({ async: false });
}

This code produces results that look like this:

Starting benchmarks for INPUT_SIZE 1
┌────────────────┬──────────────┬─────────────────┬──────────────┬────────────────┐
│    (index)     │      hz      │ margin of error │ runs sampled │ numTimesFaster │
├────────────────┼──────────────┼─────────────────┼──────────────┼────────────────┤
│    map.has     │ '93,039,281' │    '±1.68%'     │      89      │      3.11      │
│ array.includes │ '78,448,191' │    '±5.49%'     │      80      │      2.62      │
│    set.has     │ '29,912,341' │    '±1.29%'     │      90      │       1        │
└────────────────┴──────────────┴─────────────────┴──────────────┴────────────────┘
Fastest is map.has

Starting benchmarks for INPUT_SIZE 10
┌────────────────┬──────────────┬─────────────────┬──────────────┬────────────────┐
│    (index)     │      hz      │ margin of error │ runs sampled │ numTimesFaster │
├────────────────┼──────────────┼─────────────────┼──────────────┼────────────────┤
│    map.has     │ '94,382,136' │    '±1.83%'     │      85      │      6.32      │
│ array.includes │ '87,067,046' │    '±1.69%'     │      92      │      5.83      │
│    set.has     │ '14,934,322' │    '±5.86%'     │      59      │       1        │
└────────────────┴──────────────┴─────────────────┴──────────────┴────────────────┘
Fastest is map.has

Starting benchmarks for INPUT_SIZE 100
┌────────────────┬──────────────┬─────────────────┬──────────────┬────────────────┐
│    (index)     │      hz      │ margin of error │ runs sampled │ numTimesFaster │
├────────────────┼──────────────┼─────────────────┼──────────────┼────────────────┤
│    map.has     │ '95,336,202' │    '±1.51%'     │      89      │      3.82      │
│ array.includes │ '85,730,663' │    '±2.51%'     │      89      │      3.44      │
│    set.has     │ '24,943,802' │    '±0.75%'     │      93      │       1        │
└────────────────┴──────────────┴─────────────────┴──────────────┴────────────────┘
Fastest is map.has

Starting benchmarks for INPUT_SIZE 1000
┌────────────────┬──────────────┬─────────────────┬──────────────┬────────────────┐
│    (index)     │      hz      │ margin of error │ runs sampled │ numTimesFaster │
├────────────────┼──────────────┼─────────────────┼──────────────┼────────────────┤
│    map.has     │ '91,862,613' │    '±3.26%'     │      85      │      4.1       │
│ array.includes │ '85,239,920' │    '±1.86%'     │      85      │      3.81      │
│    set.has     │ '22,390,868' │    '±0.74%'     │      93      │       1        │
└────────────────┴──────────────┴─────────────────┴──────────────┴────────────────┘
Fastest is map.has

Starting benchmarks for INPUT_SIZE 10000
┌────────────────┬──────────────┬─────────────────┬──────────────┬────────────────┐
│    (index)     │      hz      │ margin of error │ runs sampled │ numTimesFaster │
├────────────────┼──────────────┼─────────────────┼──────────────┼────────────────┤
│ array.includes │ '81,607,364' │    '±7.37%'     │      82      │      4.82      │
│    map.has     │ '53,299,601' │    '±5.18%'     │      53      │      3.15      │
│    set.has     │ '16,922,667' │    '±1.85%'     │      88      │       1        │
└────────────────┴──────────────┴─────────────────┴──────────────┴────────────────┘
Fastest is array.includes

The major features of this code:

  • It produces a concise summary of a single test's results.
  • It shows how a test performs at different orders of magnitude.

Is this worth including in the documentation? If so, which section would be most appropriate? I think that the example on the main page https://benchmarkjs.com/ is good because it is so simple. Maybe there could be a section of examples of different complextity?

@jdalton @gajus

beaunus avatar Feb 23 '20 06:02 beaunus