diff --git a/multi_bench.js b/multi_bench.js index 8a1191331b..a0e0ba0ff3 100644 --- a/multi_bench.js +++ b/multi_bench.js @@ -1,218 +1,123 @@ -/*global require console setTimeout process */ - var redis = require("./index"), - request = require("request"), - stats_url = "mjr.couchone.com/bench", - client_count = process.argv[2] || 50, - ops_count = 20000, - clients = new Array(client_count), - i, tests = {}, results = {}, test_list; + num_clients = parseInt(process.argv[2]) || 50, + active_clients = 0, + clients = new Array(num_clients), + num_requests = 20000, + issued_requests = 0, + latency = new Array(num_requests), + tests = [], + test_start; redis.debug_mode = false; -function init_test(name) { - results[name] = { - test_start: new Date(), - starts: new Array(client_count), - ends: new Array(client_count), - completed: 0 - }; -} +tests.push({ + descr: "PING", + command: ["ping"] +}); -function test_complete(name) { - var min, max, sum, avg, res, i, sample, total_time, op_rate, buckets = {}, max_bucket; +tests.push({ + descr: "SET", + command: ["set", "foo_rand000000000000", "bar"] +}); - results[name].test_end = new Date(); +tests.push({ + descr: "GET", + command: ["get", "foo_rand000000000000"] +}); - total_time = results[name].test_end - results[name].test_start; - - res = results[name]; +tests.push({ + descr: "INCR", + command: ["incr", "counter_rand000000000000"] +}); - max_bucket = Number.MIN_VALUE; - min = Number.MAX_VALUE; - max = Number.MIN_VALUE; - sum = 0; +tests.push({ + descr: "LPUSH", + command: ["lpush", "mylist", Array(8).join("-")] +}); - for (i = 0, len = results[name].ends.length; i < len; i += 1) { - sample = results[name].ends[i] - results[name].starts[i]; - if (isNaN(sample)) { - console.log("NaN: " + i + ", " + results[name].ends[i] + ", " + results[name].starts[i]); - } - sum += sample; - if (sample < min) { - min = sample; - } - if (sample > max) { - max = sample; - } - if (buckets[sample] === undefined) { - buckets[sample] = 0; - } - buckets[sample] += 1; - if (buckets[sample] > max_bucket) { - max_bucket = buckets[sample]; - } - } +tests.push({ + descr: "LRANGE (10 elements)", + command: ["lrange", "mylist", "0", "9"] +}); - avg = (sum / ops_count).toFixed(2); - op_rate = ((i + 1) / (total_time/1000)).toFixed(2); +tests.push({ + descr: "LRANGE (100 elements)", + command: ["lrange", "mylist", "0", "99"] +}); - console.log(name + ": " + i + " ops " + op_rate + " ops/sec " + min + "/" + max + "/" + avg); +function create_clients(callback) { + if (active_clients == num_clients) { + callback(); + } else { + var client; + var connected = active_clients; - function lpad(val) { - var ret = val.toString(); - while (ret.length < max_bucket.toString().length) { - ret = " " + ret; - } - return ret; - } - - // Object.keys(buckets).forEach(function (bucket) { - // var bar = "", i, max_width = 100, cur_val = buckets[bucket]; - // - // i = Math.round((cur_val / max_bucket) * max_width); - // - // while (i >= 0) { - // bar += "*"; - // i--; - // } - // console.log(lpad(bucket) + ": " + bar); - // }); - - run_next(); -} - -function get_result(name, index) { - results[name].starts[index] = new Date(); - return function (err, reply) { - results[name].ends[index] = new Date(); - results[name].completed += 1; - if (results[name].completed === ops_count) { - test_complete(name); - } - } -} - -function spread_command(name, command, args) { - var remaining = ops_count - 1, - current = 0; - - while (remaining >= 0) { - clients[current][command](args, get_result(name, remaining)); - current += 1; - if (current >= client_count) { - current = 0; - } - remaining -= 1; - } -} - -tests.connections = function () { - var name = "connections"; - - function handle_connection (num) { - return function () { - results[name].ends[num] = new Date(); - results[name].completed += 1; - start_connection(num + 1); - } - } - - function start_connection (num) { - results[name].starts[num] = new Date(); - clients[num] = redis.createClient(); - if (num < (client_count - 1)) { - clients[num].on("connect", handle_connection(num)); - } else { - clients[num].on("connect", function () { - results[name].ends[num] = new Date(); - results[name].completed += 1; - test_complete(name); + while (active_clients < num_clients) { + client = clients[active_clients++] = redis.createClient(); + client.on("connect", function() { + /* Fire callback when all clients are connected */ + if (++connected == num_clients) + callback(); + }); + client.on("error", function (msg) { + console.log("Connect problem:" + msg.stack); }); } - - clients[num].on("error", function (msg) { - console.log("Connect problem:" + msg.stack); - }); - } - - console.log("Starting " + client_count + " connections."); - init_test(name); - start_connection(0); -}; - -tests.ping = function () { - var name = "PING (mb)"; - - init_test(name); - spread_command(name, "ping", []); -}; - -tests.set = function () { - var name = "SET"; - - init_test(name); - spread_command(name, "set", ["foo_rand000000000000", ops_count]); -}; - -tests.get = function () { - var name = "GET"; - - init_test(name); - spread_command(name, "get", ["foo_rand000000000000"]); -}; - -tests.incr = function () { - var name = "incr"; - - init_test(name); - spread_command(name, "incr", ["counter_rand000000000000"]); -}; - -tests.lpush = function () { - var name = "lpush"; - - init_test(name); - spread_command(name, "lpush", ["mylist", "bar"]); -}; - -tests.lpop = function () { - var name = "lpop"; - - init_test(name); - spread_command(name, "lpop", ["mylist"]); -}; - -tests.sadd = function () { - var name = "sadd"; - - init_test(name); - spread_command(name, "sadd", ["myset", "counter_rand000000000000"]); -}; - -// need to randomize the counter - -// tests.spop = function () { -// var name = "lpop"; -// -// init_test(name); -// spread_command(name, "lpop", ["mylist"]); -// }; - - -test_list = Object.keys(tests); - -function run_next() { - var cur_test = test_list.shift(); - if (typeof tests[cur_test] === "function") { - tests[cur_test](); - } else { - console.log("End of tests."); - clients.forEach(function (client) { - client.quit(); - }); } } +function issue_request(client, test, cmd, args) { + var i = issued_requests++; + latency[i] = new Date; + + client[cmd](args, function() { + latency[i] = (new Date) - latency[i]; + if (issued_requests < num_requests) { + issue_request(client, test, cmd, args); + } else { + client.end(); + if (--active_clients == 0) + test_complete(test); + } + }); +} + +function test_run(test) { + create_clients(function() { + var i = num_clients; + var cmd = test.command[0]; + var args = test.command.slice(1); + + test_start = new Date; + issued_requests = 0; + while(i-- && issued_requests < num_requests) { + issue_request(clients[i], test, cmd, args); + } + }); +} + +function test_complete(test) { + var min, max, sum, avg; + var total_time = (new Date) - test_start; + var op_rate = (issued_requests / (total_time / 1000.0)).toFixed(2); + var i; + + latency.sort(); + min = latency[0]; + max = latency[issued_requests-1]; + for (sum = 0, i = 0; i < issued_requests; i++) + sum += latency[i]; + avg = (sum / issued_requests).toFixed(3); + + console.log(test.descr + ": " + issued_requests + " ops " + op_rate + " ops/sec " + min + "/" + max + "/" + avg); + + next(); +} + +function next() { + var test = tests.shift(); + if (test) test_run(test); +} + +next(); -run_next(); diff --git a/test.js b/test.js index 7d2430cc61..09d5c6cd82 100644 --- a/test.js +++ b/test.js @@ -68,6 +68,10 @@ function require_error(label) { }; } +function is_empty_array(obj) { + return Array.isArray(obj) && obj.length === 0; +} + function last(name, fn) { return function (err, results) { fn(err, results); @@ -154,7 +158,7 @@ tests.MULTI_3 = function () { ]) .scard("some set") .exec(function (err, replies) { - assert.deepEqual(replies[2][0], [], name); + assert.strictEqual(true, is_empty_array(replies[2][0]), name); next(name); }); }; @@ -360,7 +364,7 @@ tests.MULTIBULK_ZERO_LENGTH = function () { var name = "MULTIBULK_ZERO_LENGTH"; client.KEYS(['users:*'], function (err, results) { assert.strictEqual(null, err, 'error on empty multibulk reply'); - assert.deepEqual([], results); + assert.strictEqual(true, is_empty_array(results), "not an empty array"); next(name); }); };