gristlabs_grist-core/test/common/serializeTiming.js

120 lines
4.2 KiB
JavaScript
Raw Normal View History

var _ = require('underscore');
var assert = require('assert');
var Chance = require('chance');
var utils = require('../utils');
var marshal = require('app/common/marshal');
/**
* This test measures the complete encoding/decoding time of several ways to serialize an array of
* data. This is intended both to choose a good serialization format, and to optimize its
* implementation. This test is supposed to work both in Node and in browsers.
*/
describe("Serialization", function() {
function marshalV0(data) {
var m = new marshal.Marshaller({stringToBuffer: true, version: 0});
m.marshal(data);
return m.dump();
}
function marshalV2(data) {
var m = new marshal.Marshaller({stringToBuffer: true, version: 2});
m.marshal(data);
return m.dump();
}
function unmarshal(buffer) {
var m = new marshal.Unmarshaller({bufferToString: true});
var value;
m.on('value', function(v) { value = v; });
m.push(buffer);
m.removeAllListeners();
return value;
}
var encoders = {
"marshal_v0": {enc: marshalV0, dec: unmarshal},
"marshal_v2": {enc: marshalV2, dec: unmarshal},
"json": {enc: JSON.stringify, dec: JSON.parse},
};
describe("correctness", function() {
var data;
before(function() {
// Generate an array of random data using the Chance module
var chance = new Chance(1274323391); // seed is arbitrary
data = {
'floats1k': chance.n(chance.floating, 1000),
'strings1k': chance.n(chance.string, 1000),
};
});
_.each(encoders, function(encoder, name) {
it(name, function() {
assert.deepEqual(encoder.dec(encoder.enc(data.floats1k)), data.floats1k);
assert.deepEqual(encoder.dec(encoder.enc(data.strings1k)), data.strings1k);
});
});
});
utils.timing.describe("timings", function() {
var data, encoded = {}, results = {};
before(function() {
this.timeout(10000);
// Generate an array of random data using the Chance module
var chance = new Chance(1274323391); // seed is arbitrary
data = {
'floats100k': chance.n(chance.floating, 100000),
'strings100k': chance.n(chance.string, 100000),
};
// And prepare an encoded version for each encoder so that we can time decoding.
_.each(data, function(values, key) {
_.each(encoders, function(encoder, name) {
encoded[key + ":" + name] = encoder.enc(values);
});
});
});
function test_encode(name, key, expectedMs) {
utils.timing.it(expectedMs, "encodes " + key + " with " + name, function() {
utils.repeat(5, encoders[name].enc, data[key]);
});
}
function test_decode(name, key, expectedMs) {
utils.timing.it(expectedMs, "decodes " + key + " with " + name, function() {
var ret = utils.repeat(5, encoders[name].dec, encoded[key + ":" + name]);
results[key + ":" + name] = ret;
});
}
after(function() {
// Verify the results of decoding tests outside the timed test case.
_.each(results, function(result, keyName) {
var key = keyName.split(":")[0];
assert.deepEqual(result, data[key], "wrong result decoding " + keyName);
});
});
// Note that these tests take quite a bit longer when running ALL tests than when running them
// separately, so the expected times are artificially inflated below to let them pass. This
// may be because memory allocation is slower due to memory fragmentation. Just running gc()
// before the tests doesn't remove the discrepancy.
// Also note that the expected time needs to be high enough for both node and browser.
test_encode('marshal_v0', 'floats100k', 1600);
test_decode('marshal_v0', 'floats100k', 600);
test_encode('marshal_v0', 'strings100k', 1000);
test_decode('marshal_v0', 'strings100k', 800);
test_encode('marshal_v2', 'floats100k', 160);
test_decode('marshal_v2', 'floats100k', 160);
test_encode('marshal_v2', 'strings100k', 1000);
test_decode('marshal_v2', 'strings100k', 800);
test_encode('json', 'floats100k', 120);
test_decode('json', 'floats100k', 120);
test_encode('json', 'strings100k', 80);
test_decode('json', 'strings100k', 80);
});
});