From df766c91346b6dac96a7a460aafd81155ad75eb0 Mon Sep 17 00:00:00 2001 From: brianc Date: Tue, 19 Mar 2013 10:07:13 -0500 Subject: [PATCH 1/4] begin work on benchmarking --- benchmark/index.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 benchmark/index.js diff --git a/benchmark/index.js b/benchmark/index.js new file mode 100644 index 0000000..c3c360a --- /dev/null +++ b/benchmark/index.js @@ -0,0 +1,45 @@ +var profiler = require('profiler'); +var Client = require(__dirname + '/../lib/client'); +var buffers = require(__dirname + '/../test/test-buffers'); +require(__dirname + '/../test/unit/test-helper'); +console.log(''); + +var stream = new MemoryStream(); +stream.readyState = 'open'; +var client = new Client({ + stream: stream +}); + +var rowDescription = new buffers.rowDescription([{ + name: 'name', + tableID: 1, + attributeNumber: 1, + dataTypeID: 25, //text + typeModifer: 0, + formatCode: 0 //text format +}]); +var row1 = buffers.dataRow(['Brian']); +var row2 = buffers.dataRow(['Bob']); +var row3 = buffers.dataRow(['The amazing power of the everlasting gobstopper']); +var complete = buffers.commandComplete('SELECT 3'); +var ready = buffers.readyForQuery(); +var buffer = Buffer.concat([rowDescription, row1, row2, row3, complete, ready]); + +client.connect(assert.calls(function() { + client.connection.emit('readyForQuery'); + + var callCount = 0; + var max = 1000; + profiler.resume(); + for(var i = 0; i < max; i++) { + //BEGIN BENCH + client.query('SELECT * FROM whatever WHERE this = "doesnt even matter"', function(err, res) { + callCount++; + }); + //END BENCH + stream.emit('data', buffer); + } + profiler.pause(); + assert.equal(callCount, max); +})); +client.connection.emit('readyForQuery'); From a28f1563476f18c0000e5efaff855deb54fedf3b Mon Sep 17 00:00:00 2001 From: bmc Date: Thu, 4 Apr 2013 11:40:37 -0500 Subject: [PATCH 2/4] work in benchmark --- benchmark/df766c913.txt | 17 +++++ benchmark/index.js | 83 ++++++++++++------------- benchmark/prepared-statement-parsing.js | 73 ++++++++++++++++++++++ benchmark/simple-query-parsing.js | 59 ++++++++++++++++++ 4 files changed, 189 insertions(+), 43 deletions(-) create mode 100644 benchmark/df766c913.txt create mode 100644 benchmark/prepared-statement-parsing.js create mode 100644 benchmark/simple-query-parsing.js diff --git a/benchmark/df766c913.txt b/benchmark/df766c913.txt new file mode 100644 index 0000000..80f2674 --- /dev/null +++ b/benchmark/df766c913.txt @@ -0,0 +1,17 @@ +benchmark +starting simple-query-parsing +3571 ops/sec - (100/0.028) +7299 ops/sec - (1000/0.137) +8873 ops/sec - (10000/1.127) +8536 ops/sec - (40000/4.686) +8494 ops/sec - (40000/4.709) +7695 ops/sec - (40000/5.198) +starting prepared-statement-parsing +4000 ops/sec - (100/0.025) +6944 ops/sec - (1000/0.144) +7153 ops/sec - (10000/1.398) +7127 ops/sec - (40000/5.612) +7208 ops/sec - (40000/5.549) +6460 ops/sec - (40000/6.191) +done + diff --git a/benchmark/index.js b/benchmark/index.js index c3c360a..75f5fc3 100644 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -1,45 +1,42 @@ -var profiler = require('profiler'); -var Client = require(__dirname + '/../lib/client'); -var buffers = require(__dirname + '/../test/test-buffers'); -require(__dirname + '/../test/unit/test-helper'); -console.log(''); +var async = require('async'); +var max = 40000; +var maxTimes = 3; +var doLoops = function(bench, loops, times, cb) { + var start = new Date(); + var count = 0; -var stream = new MemoryStream(); -stream.readyState = 'open'; -var client = new Client({ - stream: stream -}); - -var rowDescription = new buffers.rowDescription([{ - name: 'name', - tableID: 1, - attributeNumber: 1, - dataTypeID: 25, //text - typeModifer: 0, - formatCode: 0 //text format -}]); -var row1 = buffers.dataRow(['Brian']); -var row2 = buffers.dataRow(['Bob']); -var row3 = buffers.dataRow(['The amazing power of the everlasting gobstopper']); -var complete = buffers.commandComplete('SELECT 3'); -var ready = buffers.readyForQuery(); -var buffer = Buffer.concat([rowDescription, row1, row2, row3, complete, ready]); - -client.connect(assert.calls(function() { - client.connection.emit('readyForQuery'); - - var callCount = 0; - var max = 1000; - profiler.resume(); - for(var i = 0; i < max; i++) { - //BEGIN BENCH - client.query('SELECT * FROM whatever WHERE this = "doesnt even matter"', function(err, res) { - callCount++; - }); - //END BENCH - stream.emit('data', buffer); + var done = function() { + var duration = (new Date() - start) + var seconds = (duration / 1000); + console.log("%d ops/sec - (%d/%d)", ~~(loops/seconds), loops, seconds); + var next = loops * 10; + if(next > max) { + if(times > maxTimes) return cb(); + times++; + next = max; + } + setTimeout(function() { + doLoops(bench, next, times, cb); + }, 100); } - profiler.pause(); - assert.equal(callCount, max); -})); -client.connection.emit('readyForQuery'); + + var run = function() { + if(count++ >= loops){ + return done(); + } + bench(function() { + setImmediate(run); + }); + } + run(); +} +var bench = require(__dirname + '/simple-query-parsing'); +console.log(); +var benches = ['simple-query-parsing', 'prepared-statement-parsing']; +async.forEachSeries(benches, function(name, cb) { + var bench = require(__dirname + '/' + name)(); + console.log('starting ', name); + doLoops(bench, 100, 1, cb); +}, function(err, res) { + console.log('done') +}) diff --git a/benchmark/prepared-statement-parsing.js b/benchmark/prepared-statement-parsing.js new file mode 100644 index 0000000..d869d5c --- /dev/null +++ b/benchmark/prepared-statement-parsing.js @@ -0,0 +1,73 @@ +var Client = require(__dirname + '/../lib/client'); +var buffers = require(__dirname + '/../test/test-buffers'); +require(__dirname + '/../test/unit/test-helper'); + +var stream = new MemoryStream(); +stream.readyState = 'open'; +var client = new Client({ + stream: stream +}); + +var rowDescription = new buffers.rowDescription([{ + name: 'id', + tableID: 1, + attributeNumber: 1, + dataTypeID: 23, //int4 + typeModifer: 0, + formatCode: 0 +},{ + name: 'name', + tableID: 1, + attributeNumber: 2, + dataTypeID: 25, //text + typeModifer: 0, + formatCode: 0 //text format +}, { + name: 'comment', + tableID: 1, + attributeNumber: 3, + dataTypeID: 25, //text + typeModifer: 0, + formatCode: 0 //text format +}]); +var row1 = buffers.dataRow(['1', 'Brian', 'Something groovy']); +var row2 = buffers.dataRow(['2', 'Bob', 'Testint test']); +var row3 = buffers.dataRow(['3', 'The amazing power of the everlasting gobstopper', 'okay now']); +var parseCompleteBuffer = buffers.parseComplete(); +var bindCompleteBuffer = buffers.bindComplete(); +var portalSuspendedBuffer = buffers.portalSuspended(); +var complete = buffers.commandComplete('SELECT 3'); +var ready = buffers.readyForQuery(); +var buffer = Buffer.concat([parseCompleteBuffer, + bindCompleteBuffer, + rowDescription, + row1, + row2, + row3, + portalSuspendedBuffer, + row1, + row2, + row3, + portalSuspendedBuffer, + row1, + row2, + row3, + portalSuspendedBuffer, + complete, ready]); + +var bufferSlice = require('buffer-slice'); +var buffers = bufferSlice(10, buffer); + +client.connect(assert.calls(function() { + client.connection.emit('readyForQuery'); + module.exports = function() { + return function(done) { + client.query('SELECT * FROM whatever WHERE this = "doesnt even matter"', ['whatever'], function(err, res) { + assert.equal(res.rows.length, 9); + done(); + }); + buffers.forEach(stream.emit.bind(stream, 'data')); + }; + }; +})); +client.connection.emit('readyForQuery'); diff --git a/benchmark/simple-query-parsing.js b/benchmark/simple-query-parsing.js new file mode 100644 index 0000000..fb4895d --- /dev/null +++ b/benchmark/simple-query-parsing.js @@ -0,0 +1,59 @@ +var Client = require(__dirname + '/../lib/client'); +var buffers = require(__dirname + '/../test/test-buffers'); +require(__dirname + '/../test/unit/test-helper'); + +var stream = new MemoryStream(); +stream.readyState = 'open'; +var client = new Client({ + stream: stream +}); + +var rowDescription = new buffers.rowDescription([{ + name: 'id', + tableID: 1, + attributeNumber: 1, + dataTypeID: 23, //int4 + typeModifer: 0, + formatCode: 0 +},{ + name: 'name', + tableID: 1, + attributeNumber: 2, + dataTypeID: 25, //text + typeModifer: 0, + formatCode: 0 //text format +}, { + name: 'comment', + tableID: 1, + attributeNumber: 3, + dataTypeID: 25, //text + typeModifer: 0, + formatCode: 0 //text format +}]); +var row1 = buffers.dataRow(['1', 'Brian', 'Something groovy']); +var row2 = buffers.dataRow(['2', 'Bob', 'Testint test']); +var row3 = buffers.dataRow(['3', 'The amazing power of the everlasting gobstopper', 'okay now']); +var complete = buffers.commandComplete('SELECT 3'); +var ready = buffers.readyForQuery(); +var buffer = Buffer.concat([ + rowDescription, + row1, row2, row3, + row1, row2, row3, + row1, row2, row3, + complete, ready]); +var bufferSlice = require('buffer-slice'); +buffers = bufferSlice(10, buffer); + +client.connect(assert.calls(function() { + client.connection.emit('readyForQuery'); + module.exports = function() { + return function(done) { + client.query('SELECT * FROM whatever WHERE this = "doesnt even matter"', function(err, res) { + assert.equal(res.rows.length, 9); + done(); + }); + buffers.forEach(stream.emit.bind(stream, 'data')); + }; + }; +})); +client.connection.emit('readyForQuery'); From 835f71a76f07903db6c7f4f28d9da9cd427a988b Mon Sep 17 00:00:00 2001 From: bmc Date: Thu, 4 Apr 2013 13:50:17 -0500 Subject: [PATCH 3/4] reduce bench itterations --- benchmark/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/index.js b/benchmark/index.js index 75f5fc3..a07fe45 100644 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -1,5 +1,5 @@ var async = require('async'); -var max = 40000; +var max = 10000; var maxTimes = 3; var doLoops = function(bench, loops, times, cb) { var start = new Date(); From ca5c10a02f4709000fbd6cec33ef6e567f505d7b Mon Sep 17 00:00:00 2001 From: bmc Date: Mon, 8 Apr 2013 16:44:41 -0500 Subject: [PATCH 4/4] clean up connection slightly & add initial bench --- benchmark/835f71a76f.txt | 17 +++++++++++++++++ lib/connection.js | 40 +++++++++++++++------------------------- 2 files changed, 32 insertions(+), 25 deletions(-) create mode 100644 benchmark/835f71a76f.txt diff --git a/benchmark/835f71a76f.txt b/benchmark/835f71a76f.txt new file mode 100644 index 0000000..8d35cd4 --- /dev/null +++ b/benchmark/835f71a76f.txt @@ -0,0 +1,17 @@ +benchmark +starting simple-query-parsing +3703 ops/sec - (100/0.027) +7299 ops/sec - (1000/0.137) +8888 ops/sec - (10000/1.125) +8733 ops/sec - (10000/1.145) +8810 ops/sec - (10000/1.135) +8771 ops/sec - (10000/1.14) +starting prepared-statement-parsing +3846 ops/sec - (100/0.026) +7299 ops/sec - (1000/0.137) +7225 ops/sec - (10000/1.384) +7288 ops/sec - (10000/1.372) +7225 ops/sec - (10000/1.384) +7457 ops/sec - (10000/1.341) +done + diff --git a/lib/connection.js b/lib/connection.js index eb42488..b8ebd79 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -474,7 +474,7 @@ Connection.prototype.parseT = function(msg) { msg.fieldCount = this.parseInt16(); var fields = []; for(var i = 0; i < msg.fieldCount; i++){ - fields[i] = this.parseField(); + fields.push(this.parseField()); } msg.fields = fields; return msg; @@ -498,7 +498,11 @@ Connection.prototype.parseD = function(msg) { var fields = []; for(var i = 0; i < fieldCount; i++) { var length = this.parseInt32(); - fields[i] = (length === -1 ? null : this.readBytes(length)); + var value = null; + if(length !== -1) { + value = this.readBytes(length); + } + fields.push(value); } msg.fieldCount = fieldCount; msg.fields = fields; @@ -553,49 +557,35 @@ Connection.prototype.parseA = function(msg) { }; Connection.prototype.parseGH = function (msg) { - msg.binary = Boolean(this.parseInt8()); + var isBinary = this.buffer[this.offset] !== 0; + this.offset++; + msg.binary = isBinary; var columnCount = this.parseInt16(); msg.columnTypes = []; for(var i = 0; i