diff --git a/bin/node-mysql-benchmarks.js b/bin/node-mysql-benchmarks.js index aebadfd..d56ef3b 100755 --- a/bin/node-mysql-benchmarks.js +++ b/bin/node-mysql-benchmarks.js @@ -8,16 +8,6 @@ "use strict"; var - bindings_list = [ - 'C', - 'PHP', - 'db-mysql', - 'mysql', - 'mysql-libmysqlclient', - 'mysql-native', - 'odbc', - 'mariasql' - ], util = require('util'), ArgumentParser = require('argparse').ArgumentParser, Table = require('cli-table'), @@ -43,7 +33,7 @@ parser.addArgument( { action: 'append', defaultValue: [], - help: 'Benchmark name to skip.' + help: 'Module to skip.' } ); parser.addArgument( @@ -71,8 +61,8 @@ if (args.quiet) { function printResults() { var table = new Table({ - head: ["Module name", "Init", "Escapes", "Reconnects", "Inserts", "Selects"], - colWidths: [22, 7, 11, 12, 9, 9], + head: ["Name", "Async", "TypeCast", "Init", "Escapes", "Reconnects", "Inserts", "Selects"], + colWidths: [30, 7, 10, 7, 11, 12, 9, 9], chars: { 'top': '-', 'top-mid':'+', @@ -95,6 +85,10 @@ function printResults() { if (results.hasOwnProperty(name)) { table.push([ name, + + cfg.benchmarksO[name].async ? 'V' : '', + cfg.benchmarksO[name].typeCast ? 'V' : '', + results[name].init || '-', results[name].escapes || '-', results[name].reconnects || '-', @@ -107,7 +101,7 @@ function printResults() { // Output results util.print("\n\u001B[1mResults:\u001B[22m\n"); console.log(table.toString()); - util.print("\u001B[1mInit time in seconds (less is better), other values are operations per second (more is better).\u001B[22m\n"); + util.print("\u001B[1mInit time in seconds (doesn't matter), other values are operations/rows per second (more is better).\u001B[22m\n"); } function inArray(what, where) { @@ -119,32 +113,34 @@ function inArray(what, where) { return false; } +var benchmarksA = cfg.benchmarksA; + function runNextBenchmark() { - if (bindings_list.length > 0) { - var - binding_name = bindings_list.shift(), - benchmark = require("../src/" + binding_name); + if (benchmarksA.length > 0) { + var benchmark = benchmarksA.shift(); - if (args.skip.length === 0 || !inArray(binding_name, args.skip)) { - printProgress("Benchmarking " + binding_name + "... "); + if (args.skip.length === 0 || !inArray(benchmark.module, args.skip)) { + printProgress("Benchmarking '" + benchmark.name + "'... "); - benchmark.run(function (binding_results) { + require("../src/" + benchmark.module).run(function (benchmark_results) { printProgress("Done.\n"); - results[binding_name] = binding_results; + results[benchmark.name] = benchmark_results; printProgress("Cooldown...\n"); - setTimeout(function () { - runNextBenchmark(); - }, cfg.cooldown); - }, cfg); + if (benchmarksA.length > 0) { + setTimeout(function () { + runNextBenchmark(); + }, cfg.cooldown); + } else { + printResults(); + } + }, cfg, benchmark); } else { - printProgress("Skipping " + binding_name + ".\n"); - + printProgress("Skipping '" + benchmark.name + "'.\n"); + runNextBenchmark(); } } else { - printProgress("\u001B[1mAll benchmarks finished.\u001B[22m\n"); - printResults(); } } diff --git a/src/config.js b/src/config.js index e60299b..25d5fa3 100644 --- a/src/config.js +++ b/src/config.js @@ -12,6 +12,19 @@ GRANT ALL PRIVILEGES ON test.* TO 'test'@'127.0.0.1' IDENTIFIED BY ''; "use strict"; +function addBenchmark(cfg, module, async, typeCast, name) { + if (!name) { + name = module; + } + cfg.benchmarksO[name] = { + name: name, + module: module, + async: async, + typeCast: typeCast + }; + cfg.benchmarksA.push(cfg.benchmarksO[name]); +} + exports.getConfig = function (factor) { var cfg = { // Database connection settings @@ -23,13 +36,13 @@ exports.getConfig = function (factor) { test_table: "test_table", // Benchmarks parameters - escape_count: 1000000 * factor, + escapes_count: 1000000 * factor, string_to_escape: "str\\str\"str\'str\x00str", reconnect_count: 1000 * factor, insert_rows_count: 10000 * factor, // Delay before assertion check (ms) - delay_before_select: 1000, + delay_before_select: 10000 * factor, cooldown: 10000 * factor }; @@ -42,5 +55,19 @@ exports.getConfig = function (factor) { cfg.select_query = "SELECT * FROM " + cfg.test_table; + cfg.benchmarksA = []; + cfg.benchmarksO = {}; + + addBenchmark(cfg, "C", false, false); + addBenchmark(cfg, "PHP", false, false); + addBenchmark(cfg, "db-mysql", false, false); + addBenchmark(cfg, "mysql", true, true, "mysql"); + addBenchmark(cfg, "mysql", true, false, "mysql *"); + addBenchmark(cfg, "mysql-libmysqlclient", true, true, "mysql-libmysqlclient"); + addBenchmark(cfg, "mysql-libmysqlclient", false, true, "mysql-libmysqlclient *"); + addBenchmark(cfg, "mysql-native", false, false); + addBenchmark(cfg, "mariasql", true, false); + addBenchmark(cfg, "odbc", false, false); + return cfg; }; diff --git a/src/db-mysql.js b/src/db-mysql.js index 7511abb..fe66dd5 100644 --- a/src/db-mysql.js +++ b/src/db-mysql.js @@ -76,13 +76,13 @@ function benchmark() { start_time = Date.now(); - for (i = 0; i < cfg.escape_count; i += 1) { + for (i = 0; i < cfg.escapes_count; i += 1) { escaped_string = conn.escape(cfg.string_to_escape); } total_time = (Date.now() - start_time) / 1000; - results.escapes = Math.round(cfg.escape_count / total_time); + results.escapes = Math.round(cfg.escapes_count / total_time); insertAsyncBenchmark(results, callback, cfg); } diff --git a/src/helper.js b/src/helper.js index dadc585..04914df 100644 --- a/src/helper.js +++ b/src/helper.js @@ -6,7 +6,7 @@ "use strict"; -exports.spawnBenchmark = function (file, args, callback, cfg) { +exports.spawnBenchmark = function (file, args, callback, cfg, benchmark) { var child = require('child_process').spawn(file, args), exitEvent = (require('semver').gt(process.versions.node, '0.8.0') ? 'close' : 'exit'), out = ''; @@ -25,5 +25,8 @@ exports.spawnBenchmark = function (file, args, callback, cfg) { child.on(exitEvent, function () { callback(JSON.parse(out)); }); + if (benchmark) { + cfg.benchmark = benchmark; + } child.stdin.end(JSON.stringify(cfg)); }; diff --git a/src/mariasql.js b/src/mariasql.js index 46be6ae..22522ad 100644 --- a/src/mariasql.js +++ b/src/mariasql.js @@ -80,13 +80,13 @@ function benchmark () { start_time = Date.now(); - for (i = 0; i < cfg.escape_count; i += 1) { + for (i = 0; i < cfg.escapes_count; i += 1) { escaped_string = conn.escape(cfg.string_to_escape); } total_time = (Date.now() - start_time) / 1000; - results['escapes'] = Math.round(cfg.escape_count / total_time); + results['escapes'] = Math.round(cfg.escapes_count / total_time); insertAsyncBenchmark(results, callback, cfg); } diff --git a/src/mysql-libmysqlclient.js b/src/mysql-libmysqlclient.js index f972938..ca85d9d 100644 --- a/src/mysql-libmysqlclient.js +++ b/src/mysql-libmysqlclient.js @@ -12,13 +12,11 @@ function benchmark() { mysql = require('mysql-libmysqlclient'), conn; - function fetchAllAsyncBenchmark(results, callback, cfg) { + function selectAsyncBenchmark(results, callback, cfg, benchmark) { var start_time, total_time, - factor = cfg.do_not_run_sync_if_async_exists ? 1 : 2, - res, - rows; + res; start_time = Date.now(); @@ -42,40 +40,7 @@ function benchmark() { }); } - function fetchRowLoopSyncBenchmark(results, callback, cfg) { - var - start_time, - total_time, - factor = cfg.do_not_run_sync_if_async_exists ? 1 : 2, - res, - row, - rows = []; - - start_time = Date.now(); - - res = conn.querySync("SELECT * FROM " + cfg.test_table + ";"); - if (!res) { - console.error("Query error " + conn.errnoSync() + ": " + conn.errorSync()); - } - - row = res.fetchRowSync(); - - while (row) { - rows.push(row); - - row = res.fetchRowSync(); - } - - res.freeSync(); - - total_time = (Date.now() - start_time) / 1000; - - results['selectsWAT'] = Math.round(cfg.insert_rows_count / total_time); - - fetchAllAsyncBenchmark(results, callback, cfg); - } - - function insertAsyncBenchmark(results, callback, cfg) { + function insertAsyncBenchmark(results, callback, cfg, benchmark) { var start_time, total_time, @@ -97,10 +62,10 @@ function benchmark() { } else { total_time = (Date.now() - start_time) / 1000; - results['inserts'] = Math.round(cfg.insert_rows_count / total_time); + results.inserts = Math.round(cfg.insert_rows_count / total_time); setTimeout(function () { - fetchRowLoopSyncBenchmark(results, callback, cfg); + selectAsyncBenchmark(results, callback, cfg, benchmark); }, cfg.delay_before_select); } } @@ -108,12 +73,34 @@ function benchmark() { insertAsync(); } - function insertSyncBenchmark(results, callback, cfg) { + function selectSyncBenchmark(results, callback, cfg, benchmark) { var start_time, total_time, - i = 0, res; + + start_time = Date.now(); + + res = conn.querySync(cfg.select_query); + + var rows = res.fetchAllSync(); + + total_time = (Date.now() - start_time) / 1000; + + results.selects = Math.round(cfg.insert_rows_count / total_time); + + // Close connection + conn.closeSync(); + + // Finish benchmark + callback(results); + } + + function insertSyncBenchmark(results, callback, cfg, benchmark) { + var + start_time, + total_time, + i; start_time = Date.now(); @@ -126,16 +113,16 @@ function benchmark() { total_time = (Date.now() - start_time) / 1000; - results['insertsSync'] = Math.round(cfg.insert_rows_count / total_time); - - insertAsyncBenchmark(results, callback, cfg); + results.inserts = Math.round(cfg.insert_rows_count / total_time); + + selectSyncBenchmark(results, callback, cfg, benchmark); } - function reconnectSyncBenchmark(results, callback, cfg) { + function reconnectBenchmark(results, callback, cfg, benchmark) { var start_time, total_time, - i = 0; + i; start_time = Date.now(); @@ -149,32 +136,36 @@ function benchmark() { total_time = (Date.now() - start_time) / 1000; - results['reconnects'] = Math.round(cfg.reconnect_count / total_time); - - insertSyncBenchmark(results, callback, cfg); + results.reconnects = Math.round(cfg.reconnect_count / total_time); + + if (benchmark.async) { + insertAsyncBenchmark(results, callback, cfg, benchmark); + } else { + insertSyncBenchmark(results, callback, cfg, benchmark); + } } - function escapeBenchmark(results, callback, cfg) { + function escapeBenchmark(results, callback, cfg, benchmark) { var start_time, total_time, - i = 0, + i, escaped_string; start_time = Date.now(); - for (i = 0; i < cfg.escape_count; i += 1) { + for (i = 0; i < cfg.escapes_count; i += 1) { escaped_string = conn.escapeSync(cfg.string_to_escape); } total_time = (Date.now() - start_time) / 1000; - results['escapes'] = Math.round(cfg.escape_count / total_time); + results.escapes = Math.round(cfg.escapes_count / total_time); - reconnectSyncBenchmark(results, callback, cfg); + reconnectBenchmark(results, callback, cfg, benchmark); } - function startBenchmark(results, callback, cfg) { + function initBenchmark(results, callback, cfg, benchmark) { var start_time, total_time; @@ -199,9 +190,9 @@ function benchmark() { total_time = (Date.now() - start_time) / 1000; - results['init'] = total_time; + results.init = total_time; - escapeBenchmark(results, callback, cfg); + escapeBenchmark(results, callback, cfg, benchmark); } var cfg = ''; @@ -214,7 +205,9 @@ function benchmark() { callback = function() { process.stdout.write(JSON.stringify(results)); }; - startBenchmark(results, callback, JSON.parse(cfg)); + + cfg = JSON.parse(cfg); + initBenchmark(results, callback, cfg, cfg.benchmark); }); process.stdin.resume(); } @@ -223,6 +216,6 @@ if (!module.parent) { benchmark(); } -exports.run = function (callback, cfg) { - require('./helper').spawnBenchmark('node', [__filename], callback, cfg); +exports.run = function (callback, cfg, benchmark) { + require('./helper').spawnBenchmark('node', [__filename], callback, cfg, benchmark); }; diff --git a/src/mysql.js b/src/mysql.js index 6b456cf..b25f74f 100644 --- a/src/mysql.js +++ b/src/mysql.js @@ -11,7 +11,7 @@ function benchmark() { var mysql = require('mysql'), conn; - function selectAsyncBenchmark(results, callback, cfg) { + function selectAsyncBenchmark(results, callback, cfg, benchmark) { var start_time, total_time; @@ -40,7 +40,7 @@ function benchmark() { }); } - function insertAsyncBenchmark(results, callback, cfg) { + function insertAsyncBenchmark(results, callback, cfg, benchmark) { var start_time, total_time, @@ -63,7 +63,7 @@ function benchmark() { results['inserts'] = Math.round(cfg.insert_rows_count / total_time) setTimeout(function () { - selectAsyncBenchmark(results, callback, cfg); + selectAsyncBenchmark(results, callback, cfg, benchmark); }, cfg.delay_before_select); } } @@ -71,7 +71,7 @@ function benchmark() { insertAsync(); } - function escapeBenchmark(results, callback, cfg) { + function escapeBenchmark(results, callback, cfg, benchmark) { var start_time, total_time, @@ -80,18 +80,18 @@ function benchmark() { start_time = Date.now(); - for (i = 0; i < cfg.escape_count; i += 1) { + for (i = 0; i < cfg.escapes_count; i += 1) { escaped_string = conn.escape(cfg.string_to_escape); } total_time = (Date.now() - start_time) / 1000; - results['escapes'] = Math.round(cfg.escape_count / total_time) + results['escapes'] = Math.round(cfg.escapes_count / total_time) - insertAsyncBenchmark(results, callback, cfg); + insertAsyncBenchmark(results, callback, cfg, benchmark); } - function startBenchmark(results, callback, cfg) { + function initBenchmark(results, callback, cfg, benchmark) { var start_time, total_time; @@ -104,7 +104,7 @@ function benchmark() { user: cfg.user, password: cfg.password, database: cfg.database, - typeCast: true + typeCast: benchmark.typeCast }); conn.query("DROP TABLE IF EXISTS " + cfg.test_table) .on('error', function(err) { @@ -119,7 +119,7 @@ function benchmark() { .on('end', function() { total_time = (Date.now() - start_time) / 1000; results['init'] = total_time; - escapeBenchmark(results, callback, cfg); + escapeBenchmark(results, callback, cfg, benchmark); }); } @@ -133,7 +133,9 @@ function benchmark() { callback = function() { process.stdout.write(JSON.stringify(results)); }; - startBenchmark(results, callback, JSON.parse(cfg)); + + cfg = JSON.parse(cfg); + initBenchmark(results, callback, cfg, cfg.benchmark); }); process.stdin.resume(); } @@ -142,6 +144,6 @@ if (!module.parent) { benchmark(); } -exports.run = function (callback, cfg) { - require('./helper').spawnBenchmark('node', [__filename], callback, cfg); +exports.run = function (callback, cfg, benchmark) { + require('./helper').spawnBenchmark('node', [__filename], callback, cfg, benchmark); }; diff --git a/src/other/benchmark.cc b/src/other/benchmark.cc index 1db6d5d..7fa3273 100644 --- a/src/other/benchmark.cc +++ b/src/other/benchmark.cc @@ -169,7 +169,7 @@ int main(int argc, char *argv[]) {"test_table", required_argument, NULL, 0}, {"create_table_query", required_argument, NULL, 0}, {"select_query", required_argument, NULL, 0}, - {"escape_count", required_argument, NULL, 0}, + {"escapes_count", required_argument, NULL, 0}, {"string_to_escape", required_argument, NULL, 0}, {"reconnect_count", required_argument, NULL, 0}, {"insert_rows_count", required_argument, NULL, 0}, @@ -202,7 +202,7 @@ int main(int argc, char *argv[]) do_benchmark(do_benchmark_initialization, "init", count); // Benchmark 1: Escapes - count = atol(cfg["escape_count"].c_str()); + count = atol(cfg["escapes_count"].c_str()); do_benchmark(do_benchmark_escape_string, "escapes", count); // Benchmark 2: Reconnects diff --git a/src/other/benchmark.php b/src/other/benchmark.php index da49e4e..5c4b047 100755 --- a/src/other/benchmark.php +++ b/src/other/benchmark.php @@ -80,13 +80,13 @@ function do_benchmark_escapes() $start = microtime(true); - for ($i = 0; $i < $cfg['escape_count']; $i++) { + for ($i = 0; $i < $cfg['escapes_count']; $i++) { $escaped_string = mysql_real_escape_string($cfg['string_to_escape'], $conn); } $finish = microtime(true); - return round($cfg['escape_count']/($finish - $start), 0); + return round($cfg['escapes_count']/($finish - $start), 0); } function do_benchmark_init() @@ -98,7 +98,7 @@ function do_benchmark_init() $conn = mysql_connect("{$cfg['host']}:{$cfg['port']}", $cfg['user'], $cfg['password']); mysql_select_db($cfg['database'], $conn); - mysql_query("DROP TABLE IF EXISTS ".$cfg['test_table']); + mysql_query("DROP TABLE IF EXISTS " . $cfg['test_table']); mysql_query($cfg['create_table_query']); $finish = microtime(true);