From c79a8fb6c93e51a0026aafdfacbe0c88e82ba9f5 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Tue, 17 Jun 2014 19:20:41 -0400 Subject: [PATCH] version bump 0.2.0: performance - used Int32Array for storing CRC32 table when possible - buf/array impl 4-step unrolling - integration performance tests --- .gitignore | 1 + Makefile | 4 ++ README.md | 7 +++- bits/01_version.js | 2 +- bits/20_crctable.js | 2 +- bits/40_crc.js | 24 +++++++++--- crc32.js | 28 ++++++++++---- ctest/crc32.js | 28 ++++++++++---- ctest/fixtures.js | 92 +++++++++++++++++++++++++++++++++++++++++++++ misc/integration.js | 92 +++++++++++++++++++++++++++++++++++++++++++++ misc/perf.sh | 18 +++++++++ package.json | 2 +- perf.txt | 82 ++++++++++++++++++++++++++++++++++++++++ perf/bm.js | 15 ++++++-- 14 files changed, 367 insertions(+), 30 deletions(-) create mode 100644 misc/integration.js create mode 100755 misc/perf.sh create mode 100644 perf.txt diff --git a/.gitignore b/.gitignore index 865fd19..4247ef3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules misc/coverage.html +misc/*/ diff --git a/Makefile b/Makefile index d7e56d7..59428c2 100644 --- a/Makefile +++ b/Makefile @@ -51,3 +51,7 @@ coveralls-spin: .PHONY: perf perf: bash perf/perf.sh + +.PHONY: perf-all +perf-all: + bash misc/perf.sh diff --git a/README.md b/README.md index 2e0f69b..a1e91df 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,12 @@ run `make ctest`. ## Performance -`make perf` will run performance tests. +`make perf` will run algorithmic performance tests (which should justify certain +decisions in the code). + +`make perf-all` compares the performance of various crc-32 algorithms that +implement the correct form (note that the SSE intrinsic is designed for the +CRC32C checksum and uses a different polynomial). Unexpected code patterns were based on performance testing in node and browser: diff --git a/bits/01_version.js b/bits/01_version.js index 40b2592..7057794 100644 --- a/bits/01_version.js +++ b/bits/01_version.js @@ -1 +1 @@ -CRC32.version = '0.1.0'; +CRC32.version = '0.2.0'; diff --git a/bits/20_crctable.js b/bits/20_crctable.js index e1a41eb..57cdb60 100644 --- a/bits/20_crctable.js +++ b/bits/20_crctable.js @@ -15,7 +15,7 @@ function signed_crc_table() { table[n] = c; } - return table; + return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table; } var table = signed_crc_table(); diff --git a/bits/40_crc.js b/bits/40_crc.js index 486a7b9..40e3593 100644 --- a/bits/40_crc.js +++ b/bits/40_crc.js @@ -1,17 +1,29 @@ /* charCodeAt is the best approach for binary strings */ +var use_buffer = typeof Buffer !== 'undefined'; function crc32_bstr(bstr) { - for(var crc = -1, i = 0, L=bstr.length-1; i < L;) { - crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i++)) & 0xFF]; - crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i++)) & 0xFF]; + if(bstr.length > 32768) if(use_buffer) return crc32_buf(Buffer(bstr)); + var crc = -1, L = bstr.length - 1; + for(var i = 0; i < L;) { + crc = table[(crc ^ bstr.charCodeAt(i++)) & 0xFF] ^ (crc >>> 8); + crc = table[(crc ^ bstr.charCodeAt(i++)) & 0xFF] ^ (crc >>> 8); } - if(i === L) crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i++)) & 0xFF]; + if(i === L) crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i)) & 0xFF]; return crc ^ -1; } function crc32_buf(buf) { - for(var crc = -1, i = 0; i != buf.length; ++i) { - crc = (crc >>> 8) ^ table[(crc ^ buf[i]) & 0xFF]; + for(var crc = -1, i = 0, L=buf.length-3; i < L;) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; } + if(i < L+3) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + if(i < L+3) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + if(i < L+3) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; }}} return crc ^ -1; } diff --git a/crc32.js b/crc32.js index f1f8bf1..37a1186 100644 --- a/crc32.js +++ b/crc32.js @@ -2,7 +2,7 @@ /* vim: set ts=2: */ var CRC32 = {}; (function(CRC32) { -CRC32.version = '0.1.0'; +CRC32.version = '0.2.0'; /* see perf/crc32table.js */ function signed_crc_table() { var c, table = new Array(256); @@ -20,24 +20,36 @@ function signed_crc_table() { table[n] = c; } - return table; + return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table; } var table = signed_crc_table(); /* charCodeAt is the best approach for binary strings */ +var use_buffer = typeof Buffer !== 'undefined'; function crc32_bstr(bstr) { - for(var crc = -1, i = 0, L=bstr.length-1; i < L;) { - crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i++)) & 0xFF]; - crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i++)) & 0xFF]; + if(bstr.length > 32768) if(use_buffer) return crc32_buf(Buffer(bstr)); + var crc = -1, L = bstr.length - 1; + for(var i = 0; i < L;) { + crc = table[(crc ^ bstr.charCodeAt(i++)) & 0xFF] ^ (crc >>> 8); + crc = table[(crc ^ bstr.charCodeAt(i++)) & 0xFF] ^ (crc >>> 8); } - if(i === L) crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i++)) & 0xFF]; + if(i === L) crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i)) & 0xFF]; return crc ^ -1; } function crc32_buf(buf) { - for(var crc = -1, i = 0; i != buf.length; ++i) { - crc = (crc >>> 8) ^ table[(crc ^ buf[i]) & 0xFF]; + for(var crc = -1, i = 0, L=buf.length-3; i < L;) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; } + if(i < L+3) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + if(i < L+3) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + if(i < L+3) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; }}} return crc ^ -1; } diff --git a/ctest/crc32.js b/ctest/crc32.js index f1f8bf1..37a1186 100644 --- a/ctest/crc32.js +++ b/ctest/crc32.js @@ -2,7 +2,7 @@ /* vim: set ts=2: */ var CRC32 = {}; (function(CRC32) { -CRC32.version = '0.1.0'; +CRC32.version = '0.2.0'; /* see perf/crc32table.js */ function signed_crc_table() { var c, table = new Array(256); @@ -20,24 +20,36 @@ function signed_crc_table() { table[n] = c; } - return table; + return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table; } var table = signed_crc_table(); /* charCodeAt is the best approach for binary strings */ +var use_buffer = typeof Buffer !== 'undefined'; function crc32_bstr(bstr) { - for(var crc = -1, i = 0, L=bstr.length-1; i < L;) { - crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i++)) & 0xFF]; - crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i++)) & 0xFF]; + if(bstr.length > 32768) if(use_buffer) return crc32_buf(Buffer(bstr)); + var crc = -1, L = bstr.length - 1; + for(var i = 0; i < L;) { + crc = table[(crc ^ bstr.charCodeAt(i++)) & 0xFF] ^ (crc >>> 8); + crc = table[(crc ^ bstr.charCodeAt(i++)) & 0xFF] ^ (crc >>> 8); } - if(i === L) crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i++)) & 0xFF]; + if(i === L) crc = (crc >>> 8) ^ table[(crc ^ bstr.charCodeAt(i)) & 0xFF]; return crc ^ -1; } function crc32_buf(buf) { - for(var crc = -1, i = 0; i != buf.length; ++i) { - crc = (crc >>> 8) ^ table[(crc ^ buf[i]) & 0xFF]; + for(var crc = -1, i = 0, L=buf.length-3; i < L;) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; } + if(i < L+3) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + if(i < L+3) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; + if(i < L+3) { + crc = (crc >>> 8) ^ table[(crc^buf[i++])&0xFF]; }}} return crc ^ -1; } diff --git a/ctest/fixtures.js b/ctest/fixtures.js index b849c78..58a6e0a 100644 --- a/ctest/fixtures.js +++ b/ctest/fixtures.js @@ -6,6 +6,98 @@ var bits = [ [ "foo bar baz٪☃🍣", 1531648243] ]; if(typeof module !== "undefined") module.exports = bits; +if(typeof require !== 'undefined') { +var js_crc32 = require('../'); +var buffer_crc32 = require('./buffer-crc32'); +var crc32 = require('./crc32'); +var node_crc = require('./node-crc'); + +function z1(bstr) { return js_crc32.bstr(bstr); } +function z2(bstr) { return buffer_crc32.signed(bstr); } +function z3(bstr) { return crc32(bstr); } +function z4(bstr) { return node_crc.crc32(bstr);} + +function b1(buf) { return js_crc32.buf(buf); } +function b2(buf) { return buffer_crc32.signed(buf); } +function b3(buf) { return crc32(buf); } +function b4(buf) { return node_crc.crc32(buf); } + +function u1(str) { return js_crc32.str(str); } +function u2(str) { return buffer_crc32.signed(str); } + +var ntests, len_max; +switch(process.env.MODE) { + case "A": ntests = 100000; len_max = 256; break; + case "B": ntests = 10000; len_max = 1024; break; + case "C": ntests = 10000; len_max = 4096; break; + case "D": ntests = 1000; len_max = 16384; break; + case "E": ntests = 1000; len_max = 65536; break; + case "F": ntests = 100; len_max = 262144; break; + default: ntests = 10000; len_max = 1024; break; +} + +var btest = true, utest = true; + +var bstr_tests = []; +var ustr_tests = []; +var len_min = 1; + +var corpus = new Array(0x0800); +for(var k = 0; k < 0x0800; ++k) corpus[k] = String.fromCharCode(k) +len_max --; + +k = (Math.random()*0x800)|0; +for(var i = 0; i < ntests; ++i) { + var l = (Math.random() * (len_max - len_min))|0 + len_min; + var s = new Array(l), t = new Array(l); + if(btest) for(var j = 0; j < l; ++j) s[j] = corpus[(i+j+k)&127]; + if(utest) for(var j = 0; j < l; ++j) t[j] = corpus[(i+j+k)&0x7FF]; + var ss = s.join(""); + bstr_tests[i] = [ss, new Buffer(ss)]; + ustr_tests[i] = t.join(""); +} + +var assert = require('assert'); +function fix(str) { return parseInt(str, 16)|0; } +if(btest) for(var j = 0; j != ntests; ++j) { + assert.equal(z1(bstr_tests[j][0]), b1(bstr_tests[j][1])); + + assert.equal(z1(bstr_tests[j][0]), z2(bstr_tests[j][0])); + assert.equal(z1(bstr_tests[j][0]), fix(z3(bstr_tests[j][0]))); + assert.equal(z1(bstr_tests[j][0]), fix(z4(bstr_tests[j][0]))); + + assert.equal(b1(bstr_tests[j][1]), b2(bstr_tests[j][1])); + assert.equal(b1(bstr_tests[j][1]), fix(b3(bstr_tests[j][1]))); + assert.equal(b1(bstr_tests[j][1]), fix(b4(bstr_tests[j][1]))); +} +if(utest) for(var j = 0; j != ntests; ++j) { + assert.equal(u1(ustr_tests[j]), u2(ustr_tests[j])); +} + +var BM = require('../perf/bm'); +var suite = new BM('binary string (' + len_max + ')'); +suite.add('js-crc32', function() { for(var j = 0; j != ntests; ++j) z1(bstr_tests[j][0]); }); +suite.add('buffer-crc32', function() { for(var j = 0; j != ntests; ++j) z2(bstr_tests[j][0]); }); +if(len_max < 4096) { + suite.add('crc32', function() { for(var j = 0; j != ntests; ++j) z3(bstr_tests[j][0]); }); + suite.add('node_crc', function() { for(var j = 0; j != ntests; ++j) z4(bstr_tests[j][0]); }); +} +suite.run(); + +suite = new BM('buffer (' + len_max + ')'); +suite.add('js-crc32', function() { for(var j = 0; j != ntests; ++j) b1(bstr_tests[j][1]); }); +suite.add('buffer-crc32', function() { for(var j = 0; j != ntests; ++j) b2(bstr_tests[j][1]); }); +if(len_max < 1024) { + suite.add('crc32', function() { for(var j = 0; j != ntests; ++j) b3(bstr_tests[j][1]); }); + suite.add('node_crc', function() { for(var j = 0; j != ntests; ++j) b4(bstr_tests[j][1]); }); +} +suite.run(); + +var suite = new BM('unicode string (' + len_max + ')'); +suite.add('js-crc32', function() { for(var j = 0; j != ntests; ++j) u1(ustr_tests[j]); }); +suite.add('buffer-crc32', function() { for(var j = 0; j != ntests; ++j) u2(ustr_tests[j]); }); +suite.run(); +} crc32table = [ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, diff --git a/misc/integration.js b/misc/integration.js new file mode 100644 index 0000000..22b59b7 --- /dev/null +++ b/misc/integration.js @@ -0,0 +1,92 @@ +if(typeof require !== 'undefined') { +var js_crc32 = require('../'); +var buffer_crc32 = require('./buffer-crc32'); +var crc32 = require('./crc32'); +var node_crc = require('./node-crc'); + +function z1(bstr) { return js_crc32.bstr(bstr); } +function z2(bstr) { return buffer_crc32.signed(bstr); } +function z3(bstr) { return crc32(bstr); } +function z4(bstr) { return node_crc.crc32(bstr);} + +function b1(buf) { return js_crc32.buf(buf); } +function b2(buf) { return buffer_crc32.signed(buf); } +function b3(buf) { return crc32(buf); } +function b4(buf) { return node_crc.crc32(buf); } + +function u1(str) { return js_crc32.str(str); } +function u2(str) { return buffer_crc32.signed(str); } + +var ntests, len_max; +switch(process.env.MODE) { + case "A": ntests = 100000; len_max = 256; break; + case "B": ntests = 10000; len_max = 1024; break; + case "C": ntests = 10000; len_max = 4096; break; + case "D": ntests = 1000; len_max = 16384; break; + case "E": ntests = 1000; len_max = 65536; break; + case "F": ntests = 100; len_max = 262144; break; + default: ntests = 10000; len_max = 1024; break; +} + +var btest = true, utest = true; + +var bstr_tests = []; +var ustr_tests = []; +var len_min = 1; + +var corpus = new Array(0x0800); +for(var k = 0; k < 0x0800; ++k) corpus[k] = String.fromCharCode(k) +len_max --; + +k = (Math.random()*0x800)|0; +for(var i = 0; i < ntests; ++i) { + var l = (Math.random() * (len_max - len_min))|0 + len_min; + var s = new Array(l), t = new Array(l); + if(btest) for(var j = 0; j < l; ++j) s[j] = corpus[(i+j+k)&127]; + if(utest) for(var j = 0; j < l; ++j) t[j] = corpus[(i+j+k)&0x7FF]; + var ss = s.join(""); + bstr_tests[i] = [ss, new Buffer(ss)]; + ustr_tests[i] = t.join(""); +} + +var assert = require('assert'); +function fix(str) { return parseInt(str, 16)|0; } +if(btest) for(var j = 0; j != ntests; ++j) { + assert.equal(z1(bstr_tests[j][0]), b1(bstr_tests[j][1])); + + assert.equal(z1(bstr_tests[j][0]), z2(bstr_tests[j][0])); + assert.equal(z1(bstr_tests[j][0]), fix(z3(bstr_tests[j][0]))); + assert.equal(z1(bstr_tests[j][0]), fix(z4(bstr_tests[j][0]))); + + assert.equal(b1(bstr_tests[j][1]), b2(bstr_tests[j][1])); + assert.equal(b1(bstr_tests[j][1]), fix(b3(bstr_tests[j][1]))); + assert.equal(b1(bstr_tests[j][1]), fix(b4(bstr_tests[j][1]))); +} +if(utest) for(var j = 0; j != ntests; ++j) { + assert.equal(u1(ustr_tests[j]), u2(ustr_tests[j])); +} + +var BM = require('../perf/bm'); +var suite = new BM('binary string (' + len_max + ')'); +suite.add('js-crc32', function() { for(var j = 0; j != ntests; ++j) z1(bstr_tests[j][0]); }); +suite.add('buffer-crc32', function() { for(var j = 0; j != ntests; ++j) z2(bstr_tests[j][0]); }); +if(len_max < 4096) { + suite.add('crc32', function() { for(var j = 0; j != ntests; ++j) z3(bstr_tests[j][0]); }); + suite.add('node_crc', function() { for(var j = 0; j != ntests; ++j) z4(bstr_tests[j][0]); }); +} +suite.run(); + +suite = new BM('buffer (' + len_max + ')'); +suite.add('js-crc32', function() { for(var j = 0; j != ntests; ++j) b1(bstr_tests[j][1]); }); +suite.add('buffer-crc32', function() { for(var j = 0; j != ntests; ++j) b2(bstr_tests[j][1]); }); +if(len_max < 1024) { + suite.add('crc32', function() { for(var j = 0; j != ntests; ++j) b3(bstr_tests[j][1]); }); + suite.add('node_crc', function() { for(var j = 0; j != ntests; ++j) b4(bstr_tests[j][1]); }); +} +suite.run(); + +var suite = new BM('unicode string (' + len_max + ')'); +suite.add('js-crc32', function() { for(var j = 0; j != ntests; ++j) u1(ustr_tests[j]); }); +suite.add('buffer-crc32', function() { for(var j = 0; j != ntests; ++j) u2(ustr_tests[j]); }); +suite.run(); +} diff --git a/misc/perf.sh b/misc/perf.sh new file mode 100755 index 0000000..357935c --- /dev/null +++ b/misc/perf.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +cd misc &>/dev/null + +git_module() { + if [ ! -e "$1/" ]; then git clone $2; fi + cd "$1" + git pull + cd - &>/dev/null +} + +echo "::: downloading modules" +git_module node-crc https://github.com/alexgorbatchev/node-crc 2>/dev/null # crc +git_module crc32 https://github.com/beatgammit/crc32 2>/dev/null # crc32 +git_module buffer-crc32 https://github.com/brianloveswords/buffer-crc32 2>/dev/null # buffer-crc32 + +for i in A B C D E F; do MODE="$i" node integration.js; done +# for i in E F; do MODE="$i" node integration.js; done diff --git a/package.json b/package.json index 1316745..b547bc5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "crc-32", - "version": "0.1.0", + "version": "0.2.0", "author": "sheetjs", "description": "Pure-JS CRC-32", "keywords": [ "crc32", "checksum", "crc" ], diff --git a/perf.txt b/perf.txt new file mode 100644 index 0000000..1907ae5 --- /dev/null +++ b/perf.txt @@ -0,0 +1,82 @@ +--- binary string (255) --- +✓ js-crc32 x 25.41 ops/sec ±0.40% (45 runs sampled) +✓ buffer-crc32 x 6.63 ops/sec ±1.09% (20 runs sampled) +✓ crc32 x 0.84 ops/sec ±1.17% (6 runs sampled) +✓ node_crc x 1.99 ops/sec ±0.59% (8 runs sampled) +Fastest is js-crc32 +--- buffer (255) --- +✓ js-crc32 x 30.68 ops/sec ±0.40% (55 runs sampled) +✓ buffer-crc32 x 26.15 ops/sec ±0.36% (47 runs sampled) +✓ crc32 x 7.58 ops/sec ±0.61% (22 runs sampled) +✓ node_crc x 3.51 ops/sec ±0.56% (12 runs sampled) +Fastest is js-crc32 +--- unicode string (255) --- +✓ js-crc32 x 11.65 ops/sec ±0.35% (32 runs sampled) +✓ buffer-crc32 x 3.17 ops/sec ±4.01% (12 runs sampled) +Fastest is js-crc32 +--- binary string (1023) --- +✓ js-crc32 x 65.10 ops/sec ±0.36% (68 runs sampled) +✓ buffer-crc32 x 25.63 ops/sec ±3.38% (60 runs sampled) +✓ crc32 x 2.52 ops/sec ±0.65% (10 runs sampled) +✓ node_crc x 9.41 ops/sec ±0.55% (27 runs sampled) +Fastest is js-crc32 +--- buffer (1023) --- +✓ js-crc32 x 78.58 ops/sec ±0.42% (82 runs sampled) +✓ buffer-crc32 x 73.15 ops/sec ±0.41% (76 runs sampled) +✓ crc32 x 21.28 ops/sec ±0.37% (39 runs sampled) +✓ node_crc x 12.46 ops/sec ±0.42% (34 runs sampled) +Fastest is js-crc32 +--- unicode string (1023) --- +✓ js-crc32 x 29.07 ops/sec ±0.51% (51 runs sampled) +✓ buffer-crc32 x 9.25 ops/sec ±6.61% (35 runs sampled) +Fastest is js-crc32 +--- binary string (4095) --- +✓ js-crc32 x 16.57 ops/sec ±0.47% (44 runs sampled) +✓ buffer-crc32 x 13.30 ops/sec ±8.05% (34 runs sampled) +✓ crc32 x 0.60 ops/sec ±0.46% (5 runs sampled) +✓ node_crc x 3.01 ops/sec ±0.52% (11 runs sampled) +Fastest is js-crc32 +--- buffer (4095) --- +✓ js-crc32 x 20.35 ops/sec ±0.45% (37 runs sampled) +✓ buffer-crc32 x 18.86 ops/sec ±0.45% (50 runs sampled) +Fastest is js-crc32 +--- unicode string (4095) --- +✓ js-crc32 x 7.20 ops/sec ±0.96% (22 runs sampled) +✓ buffer-crc32 x 4.20 ops/sec ±5.73% (13 runs sampled) +Fastest is js-crc32 +--- binary string (16383) --- +✓ js-crc32 x 41.40 ops/sec ±0.15% (55 runs sampled) +✓ buffer-crc32 x 39.18 ops/sec ±5.86% (63 runs sampled) +Fastest is js-crc32 +--- buffer (16383) --- +✓ js-crc32 x 51.36 ops/sec ±0.34% (67 runs sampled) +✓ buffer-crc32 x 47.72 ops/sec ±0.31% (63 runs sampled) +Fastest is js-crc32 +--- unicode string (16383) --- +✓ js-crc32 x 18.47 ops/sec ±0.74% (49 runs sampled) +✓ buffer-crc32 x 11.29 ops/sec ±3.94% (31 runs sampled) +Fastest is js-crc32 +--- binary string (65535) --- +✓ js-crc32 x 10.14 ops/sec ±4.43% (28 runs sampled) +✓ buffer-crc32 x 7.29 ops/sec ±5.49% (27 runs sampled) +Fastest is js-crc32 +--- buffer (65535) --- +✓ js-crc32 x 12.34 ops/sec ±0.26% (34 runs sampled) +✓ buffer-crc32 x 11.29 ops/sec ±0.56% (32 runs sampled) +Fastest is js-crc32 +--- unicode string (65535) --- +✓ js-crc32 x 4.28 ops/sec ±1.17% (14 runs sampled) +✓ buffer-crc32 x 2.73 ops/sec ±3.73% (10 runs sampled) +Fastest is js-crc32 +--- binary string (262143) --- +✓ js-crc32 x 21.41 ops/sec ±3.43% (43 runs sampled) +✓ buffer-crc32 x 23.56 ops/sec ±4.02% (41 runs sampled) +Fastest is js-crc32 +--- buffer (262143) --- +✓ js-crc32 x 31.51 ops/sec ±0.49% (55 runs sampled) +✓ buffer-crc32 x 27.56 ops/sec ±0.60% (51 runs sampled) +Fastest is js-crc32 +--- unicode string (262143) --- +✓ js-crc32 x 11.00 ops/sec ±0.98% (31 runs sampled) +✓ buffer-crc32 x 6.70 ops/sec ±2.99% (19 runs sampled) +Fastest is js-crc32 diff --git a/perf/bm.js b/perf/bm.js index 9c7fb3b..a742008 100644 --- a/perf/bm.js +++ b/perf/bm.js @@ -1,4 +1,4 @@ -/* ssf.js (C) 2014 SheetJS -- http://sheetjs.com */ +/* bm.js (C) 2014 SheetJS -- http://sheetjs.com */ var Benchmark = require('benchmark'); var c = require('ansi')(process.stdout); @@ -12,17 +12,24 @@ function BM(name) { if(!(this instanceof BM)) return new BM(name); console.log("--- " + name + " ---"); this.suite = new Benchmark.Suite(name, { onComplete: suite_end }); + this.suites = []; + this.maxlen = 0; } -BM.prototype.run = function() { this.suite.run(); }; +BM.prototype.run = function() { + var maxlen = this.maxlen, ss = this.suite; + this.suites.forEach(function(s) { ss.add(s[0] + new Array(maxlen-s[0].length+1).join(" "), s[1]); }); + if(this.suites.length > 0) this.suite.run(); +}; BM.prototype.add = function(msg, test) { - this.suite.add(msg, { + this.suites.push([msg, { onCycle: test_cycle, onComplete: test_end, defer: false, fn: test - }); + }]); + this.maxlen = Math.max(this.maxlen, msg.length); }; module.exports = BM;