-
Notifications
You must be signed in to change notification settings - Fork 102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
realloc is slow #77
Comments
You could likely achieve a similar win by using a pool of buffers. |
@kjvalencik thanks! How could I do that? |
In node, Buffers are already pooled unless you use a slow buffer. In this case, your example would already be pooling. I'm not sure if browsers do this, but you could also explicitly do it with an object pooling library. In that case, you may get better performance pooling const Pbf = require("pbf");
const Bluebird = require("bluebird");
const MemoryPool = require("memory-pool");
function PbfPool({ size = 0, growBy = 256 } = {}) {
const pool = new MemoryPool(size, () => new Pbf(), growBy);
return Bluebird
.resolve(pool.allocate())
.disposer(pbf => pool.free(Object.assign(pbf, {
pos : 0
})));
}
const getPbf = PbfPool();
function encodeResponse(message) {
return Bluebird.using(getPbf(), pbf => Response.write(message.pbf).finish());
} |
I am working on node.js (v4) currently, I am doing this: function encode(message) {
const pbf = new PBF();
Response.write(message, pbf);
return new Buffer(pbf.finish());
} Then I end up writing the result in a socket (every message is length prefixed). Is this the right thing to do? I think the // 300,000 ops/secs:
const pbf = new PBF();
Response.write(message, pbf);
return new Buffer(pbf.finish());
// 600,000 ops/secs:
const pbf = new PBF(32);
Response.write(message, pbf);
return new Buffer(pbf.finish());
// 1,100,000 ops/secs:
const pbf = new PBF(typedArray);
Response.write(message, pbf);
return new Buffer(pbf.finish());
//typedArray is a Uint8Array(32) defined at the beginning of the application. Given that the code is always sync, running on the same thread etc and the slice of the array is copied by |
The |
@mourner I agree with you, it seems to me that this is not an issue on pbf. I was using this issue to try to figure the fastest way to encode with your help. I hope someone find this info useful, but here is how I understand it so far.
with all the above in mind, I wrote this benchmark of the different ways I could imagine encoding a message into a buffer: const Benchmark = require('benchmark');
const suite = new Benchmark.Suite();
const PBF = require('pbf');
const toBuffer = require('typedarray-to-buffer');
//this is the PBF generated file:
const Response = require('../messages/Response').Response;
//this is a sample message:
const response = {
request_id: 'abcdefg',
'take': {
conformant: false,
remaining: 10,
reset: 20,
limit: 30
}
};
//this is used in the 3rd test
const array = new Uint8Array(32);
const poolSize = 1024 * 5000;
var pool = new Uint8Array(poolSize);
suite
.add('Encoding with reallocs', function() {
const pbf = new PBF();
Response.write(response, pbf);
return toBuffer(pbf.finish());
})
.add('Encoding with an starting size', function() {
const pbf = new PBF(32);
Response.write(response, pbf);
return toBuffer(pbf.finish());
})
.add('Encoding on an existing array and copy to buffer', function() {
const pbf = new PBF(array);
Response.write(response, pbf);
//this copy the array into a new buffer iterating over
return new Buffer(pbf.finish());
})
.add('Encoding using a pool', function() {
const pbf = new PBF(pool);
Response.write(response, pbf);
const view = pbf.finish();
//remove the used part of the pool
pool = pool.subarray(view.length);
if (pool.length < 32) {
// console.log('allocating pool', pool.length);
pool = new Uint8Array(poolSize);
}
//convert the ArrayBufferView to buffer.
return toBuffer(view);
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
.run({ 'async': true }); The result of this benchmark on my machine is this:
Does this benchmark looks good to you, can you think on a faster way? My code is here: |
It seems to me that doing this:
Is slow because it does a bunch of
realloc
internally, i.e. it creates a bigger aUint8Array
and copy the content inside.If the length of your messages is similar or constant it seems better to do this:
I got a big win by doing this.
The text was updated successfully, but these errors were encountered: