Benckmark.js で node.js 環境 と ブラウザ（PhantomJS）でベンチマーク

これまで ブラウザ側でベンチマーク取ったことなかったので、node.js と ブラウザの両方で動作するモジュールでベンチマーク取ってみた。

構成は以下のとおり

```
.
|-- b/
|   |-- bench.html     
|   |-- bench.js
|   |-- drive.js
|   `-- run-phantom.js
|-- index.js
|-- node_modules/
     `-- benchmark/
         `-- benchmark.js
```

+ `b/` ベンチマーク関係のディレクトリ
+ `b/bench.html` htmlファイル
+ `b/bench.js` ベンチマークスイートファイル
+ `b/driver.js` htmlにベンチマークの結果を表示するドライバーjs
+ `b/run-phantom.js` phantomjs で *.html を開くランナーjs
+ `index.js` モジュール本体



```js:index.js
(function (global) {
    'use strict'
    var isBrowser = !! global.self
    var isNodeJS  = !! global.global

    function curry (f) {
        var args = []
        var bind = function (x) {
            args.push(x)
            return (args.length >= f.length) ? f.apply(null, args) : bind
        }

        return bind
    }

    if (isNodeJS) {
        module.exports = curry
    }
    else {
        global.curry = curry
    }
})(this.self || global)
```

```js:bench.js
(function (global) {
    'use strict'
    var isBrowser = !! global.self
    var isNodeJS  = !! global.global

    var Benchmark, suite, path, curry, onError
    if (isNodeJS) {
        path = require('path')
        curry = require(path.join( __dirname, '../index'))
        Benchmark = require('benchmark').Benchmark
        suite = new Benchmark.Suite
        onError = function (err) {
            console.error(err)
            process.exit(1)
        }
    }
    else {
        curry = global.curry
        Benchmark = global.Benchmark
        suite = global.suite = new Benchmark.Suite
        onError = function (err) {
            console.log(err)
        }
    }

    function area (x, y) { return x * y }
    function sq (x, y, z) { return area(area(x, y), z) }

    var x = 2, y = 3, z = 4
    suite.add('(x * y * z)', function () {
        (x * y * z) === 24
    })
    .add('sq(x, y, z)', function () {
        sq(x, y, z) === 24
    })
    .add('curry(sq)(x)(y)(z)', function () {
        curry(sq)(x)(y)(z) === 24
    })

    .on('error', onError)
    .on('cycle', function (ev) {
        console.log(String(ev.target))
    })
    .on('complete', function () {
        console.log('Fastest is ' + this.filter('fastest').pluck('name')
    })

    .run({async: true})
})(this.self || global)
```

```js:dirve.js
(function (global) {
    'use strict'

    if ((! console) || typeof console.log !== 'function')
        throw new Error('"console.log" not found')

    var x = {
        count: 0
      , dom: document.querySelector('#status')
      , toString: function (x) { return Object.prototype.toString.apply(x) }
    }

    var colors = {
        complete: '#00ff00'
      , error:    '#ff0000'
      , cycle:    '#ffff00'
    }

    Object.keys(colors).forEach(function (level) {
        x[level] = function (msg) {
            if (this.toString(msg) === '[object Error]')
                msg = msg.toString()

            document.title = this.dom.innerHTML = msg
            this.dom.setAttribute('style', 'background-color:' + colors[level])
        }
    })

    var y = {
        dom: document.querySelector('#tests')
      , append: function (str) {
            var li = document.createElement('li')
            li.innerHTML = str
            this.dom.appendChild(li)
        }
    }

    var log = console.log
    console.log = function (str) {
        y.append(str)
        log.apply(console, arguments)
    }

    global.suite.on('error', function (err) {
        x.error(err)
    })
    .on('cycle', function () {
        x.cycle( 'Running Benchmark [' + (x.count += 1) + '/'
               + this.length + ']' )
    })
    .on('complete', function () {
        x.complete( 'Running Benchmark [' + this.length + '/'
               + this.length + ']' )
    })
})(this)
```

```html:bench.html
<!doctype html>
<head>
<meta charset="utf-8" />
<script src="../index.js"></script>
<script src="../node_modules/benchmark/benchmark.js"></script>
<title>Benchmark - curry</title>
</head>
<body>
  <div id="status"></div>
  <div id="contents">
    <div id="result"></div>
    <ol id="tests"></ol>
  </div>
</body>
<script src="./bench.js"></script>
<script src="./drive.js"></script>
```

```js:run-phantom.js
#!/usr/bin/env phantomjs

var system = require('system')

if (system.args.length !== 2) {
    console.log('usage: ./run-phantom.js URL')
    phantom.exit(1)
}

var page = require('webpage').create()
page.onConsoleMessage = function (msg) {
    console.log(msg)
}

page.open(system.args[1], function (isStatus) {
    if (isStatus !== 'success') {
        console.log('can not access network')
        return process.exit(1)
    }

    console.log('fetch ok ... ' + system.args[1])

    setInterval(function () {
        var completed = page.evaluate(function () {
            return /^Complete\s/.test(document.title)
        })

        if (completed) phantom.exit(0)
    }, 250)
})
```

### ベンチマークを取る

#### node.js 環境

```
$ node b/bench.js
```

#### PhantomJS 環境

```
$ phantomjs b/run-phantom.js b/bench.html
```