Benchmarking your JavaScript code

What is benchmarking? It refers to the process of testing the performance of an implementation with respect to an already established one. For example, in the airspace industry we can assume that an F-16 is the benchmark for the fastest plane. Any new design should then compare (benchmark) itself against the performance of an F-16.

In this way, when we have more than one design, we can choose the best implementation based on its benchmark with the F-16.

However, sometimes its easier just to compare the performance between implementations. This is true especially in software development. If we have two or more implementations of a solution we can run a benchmark and choose the implementation which is the fastest or alternatively the one which consumes the least resources. Whatever suits the requirements. Note here that we don’t have a benchmark, instead we are comparing the results between implementations.

In this article, I’ll show you a super easy way to benchmark your JavaScript code. I have some code which needs to match a string against a list of domain names. Of course, my first thought was to use a RegExp. It works. And then I thought lets iterate over the list, and use String.indexOf(). Which one is faster? Benchmark them!

Requirements:
* Node.js
* Prior experience to npm and ES6

Lets see some code.

Here’s the initial code using a Regexp

let referrer = 'http://bing.com'
let engines = [ 'google', 'bing', 'yahoo', ]

let regex = new RegExp('(' 
              + engines.map(e => { 
                  return e.replace(/\./g, '\\.')
                })
                .join('|') 
              + ')', 'i')
if (referrer.search(regex)) {
  // got a match
}

We basically construct a RegExp object by iterating over engines, then use map to replace a literal period (.) with (\.), and then join the modified list using ‘|’

And then referrer.search(regex) tests whether the domain exists in engines.

Pretty simple and effective. However, its known than String.indexOf() is much faster than using regular expressions. You know the saying –

You see a problem and decide to use a regular expression. Now you have two
problems.

Here’s the code using indexOf():

for (let i = 0; i < engines.length; i++) {
  if (referrer.indexOf(engines[i]) > 0) {
    // got match
    break
  }
}

Benchmarking these two against each other gives us a known observation about which implementation is faster. Note I’m only focusing on execution speed here, and not on other requirements. Good science is experimentation and observation.

We will be using npm to manage our deps, so here’s my package.json

{
  "name": "bench",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "exec": "node o.js",
    "build": "./node_modules/.bin/babel b.js --presets babel-preset-es2015 --out-file o.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "benchmark": "^2.1.3"
  },
  "devDependencies": {
    "babel-cli": "^6.24.0",
    "babel-core": "^6.24.0",
    "babel-preset-es2015": "^6.24.0"
  }
}

In a working directory of your choice, place this package.json file. Then –

$ npm install

Contents of b.js

import Benchmark from 'benchmark'

let referrer = 'http://bing.com'
let engines = [ 'google', 'bing', 'yahoo', ]
let suite = new Benchmark.Suite

suite.add('RegExp', function() {
  let regex = new RegExp('(' 
                    + engines.map(e => { 
                        return e.replace(/\./g, '\\.') 
                      }).join('|') 
                    + ')', 'i')
  if (referrer.search(regex)) {
    // got a match
  }
})
.add('Array', function() {
  for (let i = 0; i < engines.length; i++) {
    if (referrer.indexOf(engines[i]) > 0) {
      // got match
      break
    }
  }
})
.on('cycle', function(e) {
  console.log(String(e.target));
})
.on('complete', function(e) {
  console.log('Fastest is ' + this.filter('fastest').map('name'))
})
.run({"async": true})

Now build your code. Which is basically using Babel to transpile your ES6 code into ES5.

$ npm run build

This will create o.js. Run the benchmark with –

$ npm run exec

This is the output I get

RegExp x 170,024 ops/sec ±2.18% (73 runs sampled)
Array x 2,878,075 ops/sec ±2.48% (73 runs sampled)
Fastest is Array

Awesome!

Using the Benchmark module is extremely easy. The add method adds a new benchmark. It takes two arguments. The first is the name of the benchmark, the second is a function to execute.

When a particular benchmark is done, the cycle event is called. You can output the results here. When all the benchmarks are done, the complete event is called.

I hope you learned something! Thanks for reading.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s