diff options
author | Zach Bjornson <bjornson@stanford.edu> | 2016-06-04 13:38:08 -0700 |
---|---|---|
committer | Trevor Norris <trev.norris@gmail.com> | 2016-06-27 14:38:37 -0600 |
commit | a1059afd3963a2a8f916aa0874865658c0479672 (patch) | |
tree | 767edfaa430a6aaab1e57ed544e3c3455dcb9902 /benchmark/buffers | |
parent | 561548702e3ee30525dd3a72a9cdf0dd923d0beb (diff) | |
download | android-node-v8-a1059afd3963a2a8f916aa0874865658c0479672.tar.gz android-node-v8-a1059afd3963a2a8f916aa0874865658c0479672.tar.bz2 android-node-v8-a1059afd3963a2a8f916aa0874865658c0479672.zip |
buffer: speed up swap16/32, add swap64
* Speed up buffer.swap16 and swap32 by using builtins. Up to ~6x gain.
Drop transition point between JS and C++ implementations accordingly.
Amount of performance improvement not only depends on buffer size but
also memory alignment.
* Fix tests: C++ impl tests were testing 0-filled buffers so were
always passing.
* Add similar buffer.swap64 method.
* Make buffer-swap benchmark mirror JS impl.
doc/api/buffer.markdown has an entry of "added: REPLACEME" that should
be changed to the correct release number before tagged.
Because node is currently using a very old version of cpplint.py it
doesn't know that std::swap() has moved from <algorithm> to <utility> in
c++11. So until cpplint.py is updated simply NOLINT the line.
Technically it should be NOLINT(build/include_what_you_use), but that
puts the line over 80 characters causing another lint error.
PR-URL: https://github.com/nodejs/node/pull/7157
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'benchmark/buffers')
-rw-r--r-- | benchmark/buffers/buffer-swap.js | 75 |
1 files changed, 52 insertions, 23 deletions
diff --git a/benchmark/buffers/buffer-swap.js b/benchmark/buffers/buffer-swap.js index 4ff9a23d41..0793c77c8f 100644 --- a/benchmark/buffers/buffer-swap.js +++ b/benchmark/buffers/buffer-swap.js @@ -1,61 +1,90 @@ 'use strict'; const common = require('../common.js'); +const v8 = require('v8'); const bench = common.createBenchmark(main, { - method: ['swap16', 'swap32', 'htons', 'htonl'], - len: [4, 64, 512, 768, 1024, 1536, 2056, 4096, 8192], - n: [1e6] + aligned: ['true', 'false'], + method: ['swap16', 'swap32', 'swap64'/*, 'htons', 'htonl', 'htonll'*/], + len: [8, 64, 128, 256, 512, 768, 1024, 1536, 2056, 4096, 8192], + n: [5e7] }); // The htons and htonl methods below are used to benchmark the // performance difference between doing the byteswap in pure // javascript regardless of Buffer size as opposed to dropping -// down to the native layer for larger Buffer sizes. +// down to the native layer for larger Buffer sizes. Commented +// out by default because they are slow for big buffers. If +// re-evaluating the crossover point, uncomment those methods +// and comment out their implementations in lib/buffer.js so +// C++ version will always be used. + +function swap(b, n, m) { + const i = b[n]; + b[n] = b[m]; + b[m] = i; +} Buffer.prototype.htons = function htons() { if (this.length % 2 !== 0) throw new RangeError(); - for (var i = 0, n = 0; i < this.length; i += 2) { - n = this[i]; - this[i] = this[i + 1]; - this[i + 1] = n; + for (var i = 0; i < this.length; i += 2) { + swap(this, i, i + 1); } return this; }; Buffer.prototype.htonl = function htonl() { - if (this.length % 2 !== 0) + if (this.length % 4 !== 0) + throw new RangeError(); + for (var i = 0; i < this.length; i += 4) { + swap(this, i, i + 3); + swap(this, i + 1, i + 2); + } + return this; +}; + +Buffer.prototype.htonll = function htonl() { + if (this.length % 8 !== 0) throw new RangeError(); - for (var i = 0, n = 0; i < this.length; i += 4) { - n = this[i]; - this[i] = this[i + 3]; - this[i + 3] = n; - n = this[i + 1]; - this[i + 1] = this[i + 2]; - this[i + 2] = n; + for (var i = 0; i < this.length; i += 8) { + swap(this, i, i + 7); + swap(this, i + 1, i + 6); + swap(this, i + 2, i + 5); + swap(this, i + 3, i + 4); } return this; }; -function createBuffer(len) { +function createBuffer(len, aligned) { + len += aligned ? 0 : 1; const buf = Buffer.allocUnsafe(len); for (var i = 1; i <= len; i++) buf[i - 1] = i; - return buf; + return aligned ? buf : buf.slice(1); } -function bufferSwap(n, buf, method) { - for (var i = 1; i <= n; i++) - buf[method](); +function genMethod(method) { + const fnString = + 'return function ' + method + '(n, buf) {' + + ' for (var i = 0; i <= n; i++)' + + ' buf.' + method + '();' + + '}'; + return (new Function(fnString))(); } function main(conf) { const method = conf.method; const len = conf.len | 0; const n = conf.n | 0; - const buf = createBuffer(len); + const aligned = conf.aligned || 'true'; + const buf = createBuffer(len, aligned === 'true'); + const bufferSwap = genMethod(method); + + v8.setFlagsFromString('--allow_natives_syntax'); + eval('%OptimizeFunctionOnNextCall(bufferSwap)'); + bench.start(); - bufferSwap(n, buf, method); + bufferSwap(n, buf); bench.end(n); } |