Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Final benchmark chain

  • Loading branch information...
commit d8b8571396b76d3eb2aa4d08adf5800444246a91 1 parent b50560d
@felixge authored
View
19 figures/mysql2-vs-poc/Makefile
@@ -1,18 +1,27 @@
SHELL := /bin/bash
-tsv_files = $(wildcard esults/*.tsv)
+fixtures = benchmark/fixtures/100k-blog-rows.mysql
+tsv_files = $(wildcard results/*.tsv)
png_files = $(subst pdf,png,$(wildcard pdfs/*.pdf))
-$(info $(png_files))
+all: pdfs pngs tsvs fixtures
-all: pdfs pngs
+fixtures: $(fixtures)
+
+tsvs: $(tsv_files)
+
+$(tsv_files): results/%.tsv: benchmark/%/run.js
+ ./$^ | tee $@
+
+$(fixtures):
+ curl -z '$@' -o '$@' 'http://felixge.s3.amazonaws.com/12/`basename $@`'
pdfs: $(tsv_files)
cd pdfs && ./generate.r
pngs: $(png_files)
-pngs/%.png: pdfs/%.pdf
+$(png_files): pngs/%.png: pdfs/%.pdf
convert -density 300 $^ -resize 1024x $@
-.PHONY: all pdfs pngs
+.PHONY: all fixtures pdfs pngs tsvs $(tsv_files)
View
35 figures/mysql2-vs-poc/benchmark/FixtureStream.js
@@ -0,0 +1,35 @@
+var fs = require('fs');
+var Stream = require('stream').Stream;
+var util = require('util');
+
+module.exports = FixtureStream;
+util.inherits(FixtureStream, Stream);
+function FixtureStream(path, bufferSize) {
+ bufferSize = bufferSize || 64 * 1024;
+
+ this.readable = true;
+ this._buffers = [];
+
+ var buffer = fs.readFileSync(path);
+ var start = 0;
+
+ while (start < buffer.length) {
+ var bytesLeft = buffer.length - start ;
+ var size = (bytesLeft >= bufferSize)
+ ? bufferSize
+ : bytesLeft;
+
+ this._buffers.push(buffer.slice(start, start + size));
+ start += size;
+ }
+
+ this.length = buffer.length;
+}
+
+FixtureStream.prototype.resume = function() {
+ for (var i = 0; i < this._buffers.length; i++) {
+ this.emit('data', this._buffers[i]);
+ }
+
+ this.emit('end');
+};
View
51 figures/mysql2-vs-poc/benchmark/common.js
@@ -0,0 +1,51 @@
+var iterations = 10;
+
+var FixtureStream = require('./FixtureStream');
+
+var fields = [
+ {name: 'id'},
+ {name: 'title'},
+ {name: 'text'},
+ {name: 'created'},
+ {name: 'updated'},
+];
+
+function printHeaders() {
+ console.log(['hz', 'time', 'lib', 'heapUsed', 'heapTotal', 'rss'].join('\t'));
+}
+
+var printedHeaders = false;
+
+exports.run = function(name, benchmark) {
+ if (!printedHeaders) {
+ printHeaders();
+ printedHeaders = true;
+ }
+
+ var stream = new FixtureStream(__dirname + '/fixtures/100k-blog-rows.mysql');
+
+ function iterate() {
+ if (!iterations--) {
+ return;
+ }
+
+ var start = Date.now();
+ benchmark(stream, fields, function(err, rows) {
+ if (err) throw err;
+
+ var duration = Date.now() - start;
+ var hz = Math.round(rows / (duration / 1000));
+ var memory = process.memoryUsage();
+
+ console.log([hz, Date.now(), name, memory.rss, memory.heapUsed, memory.heapTotal].join('\t'));
+
+ stream.removeAllListeners();
+
+ process.nextTick(iterate);
+ });
+
+ stream.resume();
+ }
+
+ iterate();
+};
View
14 figures/mysql2-vs-poc/benchmark/mysql2/npm-shrinkwrap.json
@@ -0,0 +1,14 @@
+{
+ "name": "mysql2",
+ "version": "0.0.0",
+ "dependencies": {
+ "mysql": {
+ "version": "2.0.0-alpha3",
+ "dependencies": {
+ "require-all": {
+ "version": "0.0.3"
+ }
+ }
+ }
+ }
+}
View
7 figures/mysql2-vs-poc/benchmark/mysql2/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "mysql2",
+ "version": "0.0.0",
+ "dependencies": {
+ "mysql": "~2.0.0-alpha3"
+ }
+}
View
26 figures/mysql2-vs-poc/benchmark/mysql2/run.js
@@ -0,0 +1,26 @@
+#!/usr/bin/env node
+
+var common = require('../common');
+var Parser = require('mysql/lib/protocol/Parser');
+var RowDataPacket = require('mysql/lib/protocol/packets/RowDataPacket');
+
+common.run('mysql2', function(stream, fields, cb) {
+ var parser = new Parser({packetParser: onPacket});
+ parser._nextPacketNumber = 8;
+
+ var rows = 0;
+ function onPacket(header) {
+ var row = new RowDataPacket();
+
+ row.parse(parser, fields, true, false);
+ rows++;
+ }
+
+ stream
+ .on('data', function(buffer) {
+ parser.write(buffer);
+ })
+ .on('end', function() {
+ cb(null, rows);
+ });
+});
View
133 figures/mysql2-vs-poc/benchmark/poc/ElementParser.js
@@ -0,0 +1,133 @@
+var IEEE_754_BINARY_64_PRECISION = Math.pow(2, 53);
+var util = require('util');
+
+module.exports = ElementParser;
+function ElementParser() {
+ this.writable = true;
+ this._offset = 0;
+ this._buffer = new Buffer(0);
+}
+
+ElementParser.prototype.write = function(buffer) {
+ this.append(buffer);
+};
+
+ElementParser.prototype.append = function(newBuffer) {
+ // If resume() is called, we don't pass a buffer to write()
+ if (!newBuffer) {
+ return;
+ }
+
+ var oldBuffer = this._buffer;
+ var bufferedBytes = this.bufferedBytes();
+ var newLength = bufferedBytes + newBuffer.length;
+
+ var combinedBuffer = (this._offset > newLength)
+ ? oldBuffer.slice(0, newLength)
+ : new Buffer(newLength);
+
+ oldBuffer.copy(combinedBuffer, 0, this._offset);
+ newBuffer.copy(combinedBuffer, bufferedBytes);
+
+ this._buffer = combinedBuffer;
+ this._offset = 0;
+};
+
+ElementParser.prototype.end = function() {
+ this.emit('end');
+};
+
+ElementParser.prototype.bufferedBytes = function() {
+ return this._buffer.length - this._offset;
+};
+
+
+ElementParser.prototype.unsignedNumber = function(bytes) {
+ var bytesRead = 0;
+ var value = 0;
+
+ while (bytesRead < bytes) {
+ var byte = this._buffer[this._offset++];
+
+ value += byte * Math.pow(256, bytesRead);
+
+ bytesRead++;
+ }
+
+ return value;
+};
+
+ElementParser.prototype.skip = function(bytes) {
+ this._offset += bytes;
+};
+
+ElementParser.prototype.parseLengthCodedIntegerString = function() {
+ var length = this.parseLengthCodedNumber();
+
+ if (length === null) {
+ return null;
+ }
+
+ var number = 0;
+ for (var i = 0; i < length; i++) {
+ number += this._buffer[this._offset++] - 48;
+ }
+
+ return number;
+};
+
+ElementParser.prototype.parseLengthCodedString = function() {
+ var length = this.parseLengthCodedNumber();
+
+ if (length === null) {
+ return null;
+ }
+
+ return this.parseString(length);
+};
+
+ElementParser.prototype.parseLengthCodedNumber = function() {
+ var byte = this._buffer[this._offset++];
+
+ if (byte <= 251) {
+ return (byte === 251)
+ ? null
+ : byte;
+ }
+
+ var length;
+ if (byte === 252) {
+ length = 2;
+ } else if (byte === 253) {
+ length = 3;
+ } else if (byte === 254) {
+ length = 8;
+ } else {
+ throw new Error('parseLengthCodedNumber: Unexpected first byte: ' + byte);
+ }
+
+ var value = 0;
+ for (var bytesRead = 0; bytesRead < length; bytesRead++) {
+ var byte = this._buffer[this._offset++];
+ value += Math.pow(256, bytesRead) * byte;
+ }
+
+ if (value >= IEEE_754_BINARY_64_PRECISION) {
+ throw new Error(
+ 'parseLengthCodedNumber: JS precision range exceeded, ' +
+ 'number is >= 53 bit: "' + value + '"'
+ );
+ }
+
+ return value;
+};
+
+ElementParser.prototype.parseString = function(length) {
+ var offset = this._offset + this._buffer.offset;
+ var end = offset + length;
+
+ var value = this._buffer.parent.utf8Slice(offset, end);
+
+ this._offset = end;
+ return value;
+};
View
5 figures/mysql2-vs-poc/benchmark/poc/PacketHeader.js
@@ -0,0 +1,5 @@
+module.exports = PacketHeader;
+function PacketHeader(length, number) {
+ this.length = length;
+ this.number = number;
+}
View
97 figures/mysql2-vs-poc/benchmark/poc/Protocol.js
@@ -0,0 +1,97 @@
+var util = require('util');
+var Stream = require('stream').Stream;
+var PacketHeader = require('./PacketHeader');
+var ElementParser = require('./ElementParser');
+var Row = eval('(' + require('./Row').toString() + ')');
+
+module.exports = Protocol;
+util.inherits(Protocol, Stream);
+function Protocol() {
+ Stream.call(this);
+
+ this.writable = true;
+ this._elements = new ElementParser();
+ this._header = null;
+ this._rows = [];
+
+}
+
+Protocol.prototype.write = function(buffer) {
+ var elements = this._elements;
+
+ elements.write(buffer);
+
+ while (true) {
+ var header = this.header(elements);
+ if (!header) {
+ break;
+ }
+
+ if (this.parseRow && !this.parseRow()) {
+ break;
+ }
+
+ this._header = null;
+ }
+};
+
+Protocol.prototype.header = function(elements) {
+ if (this._header) {
+ return this._header;
+ }
+
+ if (elements.bufferedBytes() < 4) {
+ return;
+ }
+
+ return this._header = new PacketHeader(
+ elements.unsignedNumber(3),
+ elements.unsignedNumber(1)
+ );
+};
+
+Protocol.prototype.parseRow = function() {
+ if (this._elements.bufferedBytes() < this._header.length) {
+ return false;
+ }
+
+ this.onRow(this._parseRow());
+
+ return true;
+};
+
+
+// Slow: Optimized by eval below
+
+//Protocol.prototype._parseRow = function() {
+ //var row = [];
+
+ //for (var i = 0; i < this._fields.length; i++) {
+ //var field = this._fields[i];
+ //var value = this._elements.parseLengthCodedString();
+ //row[field] = value;
+ //}
+
+ //return row;
+//};
+
+Protocol.prototype._setFields = function(fields) {
+ var code = [
+ 'return {'
+ ];
+
+ fields.forEach(function(field) {
+ code.push('"' + field.name + '":' + 'this._elements.parseLengthCodedString(),');
+ });
+
+ code.push('};');
+
+ // eval for the win!
+ this._parseRow = new Function(code.join('\n'));
+};
+
+//Protocol.prototype.parseRow = eval('(' + Protocol.prototype.parseRow.toString() + ')');
+
+Protocol.prototype.end = function() {
+ this.emit('end');
+};
View
8 figures/mysql2-vs-poc/benchmark/poc/Row.js
@@ -0,0 +1,8 @@
+module.exports = Row;
+function Row(id, title, text, created, updated) {
+ this.id = id;
+ this.title = title;
+ this.text = text;
+ this.created = created;
+ this.updated = updated;
+}
View
24 figures/mysql2-vs-poc/benchmark/poc/run.js
@@ -0,0 +1,24 @@
+#!/usr/bin/env node
+
+var common = require('../common');
+var Protocol = require('./Protocol');
+
+common.run('poc', function(stream, fields, cb) {
+ var protocol = new Protocol();
+
+ // This would normally happen when the fields are received
+ protocol._setFields(fields);
+
+ var rows = 0;
+ protocol.onRow = function() {
+ rows++;
+ };
+
+ stream
+ .on('data', function(buffer) {
+ protocol.write(buffer);
+ })
+ .on('end', function() {
+ cb(null, rows);
+ });
+});
Please sign in to comment.
Something went wrong with that request. Please try again.