Skip to content

Commit

Permalink
perf: add a cache for buffer-to-string conversions
Browse files Browse the repository at this point in the history
The tiny and small benchmarks got quite a boost:

```
+-----------+-------------------+-----------------+----------------+-------------+
|           │ tiny              │ small           │ medium         │ large       |
+-----------+-------------------+-----------------+----------------+-------------+
| before    │ 1,733,059 ops/sec │ 368,476 ops/sec │ 30,497 ops/sec │ 257 ops/sec |
+-----------+-------------------+-----------------+----------------+-------------+
| after     │ 4,278,698 ops/sec │ 701,657 ops/sec │ 34,667 ops/sec │ 249 ops/sec |
+-----------+-------------------+-----------------+----------------+-------------+
```
  • Loading branch information
darrachequesne committed Mar 13, 2020
1 parent 40df3f6 commit d3720ed
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
51 changes: 51 additions & 0 deletions lib/BufferToStringCache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const DEFAULT_MAX_SIZE = process.env.NOTEPACK_DECODE_CACHE_MAX_SIZE || 1024;
const DEFAULT_MAX_LENGTH = process.env.NOTEPACK_DECODE_CACHE_MAX_LENGTH || 16;

/**
* Store the buffer-to-string values in a tree
*/
class BufferToStringCache {
constructor({ maxSize = DEFAULT_MAX_SIZE, maxLength = DEFAULT_MAX_LENGTH } = {}) {
this.size = 0;
this.maxSize = maxSize;
this.maxLength = maxLength;
this.cache = new Map();
for (let i = 1; i <= this.maxLength; i++) {
this.cache.set(i, new Map());
}
}

get(buffer, offset, length) {
if (length > this.maxLength) { return false; }
let node = this.cache.get(length);
for (let i = 0; i < length; i++) {
const byte = buffer[offset + i];
if (node.has(byte)) {
node = node.get(byte);
} else {
return false;
}
}
return node;
}

set(buffer, offset, length, value) {
if (length > this.maxLength || this.size >= this.maxSize) { return; }
this.size++;
let node = this.cache.get(length);
for (let i = 0; i < length; i++) {
const byte = buffer[offset + i];
if (i === length - 1) {
node.set(byte, value);
} else if (node.has(byte)) {
node = node.get(byte);
} else {
const newNode = new Map();
node.set(byte, newNode);
node = newNode;
}
}
}
}

module.exports = BufferToStringCache;
9 changes: 9 additions & 0 deletions lib/decode.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
'use strict';

const BufferToStringCache = require('./BufferToStringCache');
const cache = new BufferToStringCache();

function Decoder(buffer) {
this.offset = 0;
this.buffer = buffer;
Expand All @@ -23,7 +26,13 @@ Decoder.prototype.map = function (length) {
};

Decoder.prototype.str = function (length) {
const valueFromCache = cache.get(this.buffer, this.offset, length);
if (valueFromCache) {
this.offset += length;
return valueFromCache;
}
const value = this.buffer.toString('utf8', this.offset, this.offset + length);
cache.set(this.buffer, this.offset, length, value);
this.offset += length;
return value;
};
Expand Down

0 comments on commit d3720ed

Please sign in to comment.