Browse Source

version bump, added support for printing errors and status code distribution, updated readme

master
Brett Langdon 13 years ago
parent
commit
6aa89695b7
3 changed files with 75 additions and 30 deletions
  1. +12
    -5
      Readme.md
  2. +62
    -24
      lib/index.js
  3. +1
    -1
      package.json

+ 12
- 5
Readme.md View File

@ -18,14 +18,10 @@ npm install -g
## Configuration ## Configuration
Tommygun uses ini files to specify what urls and settings to test. Each section corresponds to the url to test and Tommygun uses ini files to specify what urls and settings to test. Each section corresponds to the url to test and
each property corresponds to specific settings for that given url. If the property occurs outside of a section then
tommygun those settings are used by tommygun.
each property corresponds to specific settings for that given url.
### Example ### Example
```ini ```ini
;this setting is used by tommygun globally
random = false
[localhost] [localhost]
port = 8000 port = 8000
num = 5 num = 5
@ -46,6 +42,17 @@ num = 2
### Get Help ### Get Help
```bash ```bash
tommygun --help tommygun --help
Usage: tommygun [config] [config]...
Options:
-c, --concurrency Number of Concurrent Clients to Use [default: 1]
-n, --requests Total Number Of Requests To Make
-r, --random Whether Or Not To Randomize The Url Order [boolean] [default: false]
-k, --keepalive Whether Or Not To Enable Keep Alive Support [boolean] [default: false]
-l, --log Log File To Write All Request Data To [string]
-s, --stats Whether or Not Print Result Stats [boolean] [default: true]
-q, --quiet Whether Or Not To Silence stdout [boolean] [default: false]
-h, --help Show This Help Text [boolean]
``` ```
### Simple Usage ### Simple Usage


+ 62
- 24
lib/index.js View File

@ -12,10 +12,16 @@ var argv = require('optimist')
default: 1, default: 1,
describe: 'Number of Concurrent Clients to Use' describe: 'Number of Concurrent Clients to Use'
}) })
.options('r', {
.options('n', {
alias: 'requests', alias: 'requests',
describe: 'Total Number Of Requests To Make' describe: 'Total Number Of Requests To Make'
}) })
.options('r', {
alias: 'random',
describe: 'Whether Or Not To Randomize The Url Order',
default: false,
boolean: true
})
.options('k', { .options('k', {
alias: 'keepalive', alias: 'keepalive',
describe: 'Whether Or Not To Enable Keep Alive Support', describe: 'Whether Or Not To Enable Keep Alive Support',
@ -61,7 +67,6 @@ if( argv.log ){
} }
var config = { var config = {
random: false,
urls: {}, urls: {},
}; };
var defaults = { var defaults = {
@ -93,6 +98,10 @@ argv._.forEach(function(file){
} }
}); });
var results = [];
var results_length = 0;
var errors = [];
var errors_length = 0;
var urls = []; var urls = [];
for( var key in config.urls ){ for( var key in config.urls ){
var url = config.urls[key]; var url = config.urls[key];
@ -101,10 +110,7 @@ for( var key in config.urls ){
} }
} }
if( typeof(config.random) !== 'boolean' ){
config.random = config.random.toLowerCase() === 'true';
}
if( config.random ){
if( argv.random ){
console.log('Randomizing Url List'); console.log('Randomizing Url List');
var i = urls.length; var i = urls.length;
if ( i == 0 ) return false; if ( i == 0 ) return false;
@ -121,11 +127,12 @@ if( !argv.requests ){
argv.requests = urls.length; argv.requests = urls.length;
} }
var results = [];
var errors = [];
var save_result = function(result){ var save_result = function(result){
results.push(result);
var url = result.url;
results[url] = (results[url])?results[url]:[];
results[url].push(result);
results_length += 1;
if( argv.log ){ if( argv.log ){
var tmp = []; var tmp = [];
for( var i in result ){ for( var i in result ){
@ -138,7 +145,15 @@ var save_result = function(result){
} }
fs.writeSync(argv.log, tmp.join() + '\r\n'); fs.writeSync(argv.log, tmp.join() + '\r\n');
} }
}
};
var save_error = function(error){
var url = error.url;
errors[url] = (errors[url])?errors[url] : [];
errors[url].push(error);
errors_length += 1;
};
var run = function(options, done){ var run = function(options, done){
var start = new Date().getTime(); var start = new Date().getTime();
@ -168,37 +183,59 @@ var run = function(options, done){
console.log('Starting Up ' + argv.concurrency + ' Clients'); console.log('Starting Up ' + argv.concurrency + ' Clients');
var queue = async.queue(run, argv.concurrency); var queue = async.queue(run, argv.concurrency);
var percentiles = [.7, .8, .85, .9, .94, .96, .99];
var percentiles = [.5, .6, .7, .8, .9, .95, .98, .99];
queue.drain = function(){ queue.drain = function(){
var end_time = new Date().getTime();
var elapsed = end_time - start_time;
console.log('Finished'); console.log('Finished');
console.log('Elapsed Time (sec): ' + (elapsed/1000));
console.log('Completed Requests: ' + results_length);
console.log('Errors: ' + errors_length);
var req_sec = results_length / (elapsed/1000);
console.log('Requests per Second: ' + req_sec);
if( argv.stats ){ if( argv.stats ){
console.log('Processing Results'); console.log('Processing Results');
var tmp = results;
results = {};
tmp.forEach( function(result){
var key = result.url;
delete result.url;
if( results[key] == undefined ){
results[key] = []
}
results[key].push(result);
});
for( var url in results ){ for( var url in results ){
if( typeof(results[url]) === 'function' ){
continue;
}
console.log('Results For: ' + url); console.log('Results For: ' + url);
console.log('\tTotal Requests: ' + results[url].length); console.log('\tTotal Requests: ' + results[url].length);
var ms_data = results[url].map( function(a){ return a.ms; } ); var ms_data = results[url].map( function(a){ return a.ms; } );
ms_data = ms_data.sort(); ms_data = ms_data.sort();
var ms_set = new gauss.Vector(ms_data); var ms_set = new gauss.Vector(ms_data);
var ms_total = ms_set.sum();
console.log('\tMean Time (ms): ' + ms_set.mean()); console.log('\tMean Time (ms): ' + ms_set.mean());
console.log('\tMin Time (ms): ' + ms_set.min()); console.log('\tMin Time (ms): ' + ms_set.min());
console.log('\tMax Time (ms): ' + ms_set.max()); console.log('\tMax Time (ms): ' + ms_set.max());
console.log('\tTotal Time (ms): ' + ms_set.sum());
console.log('\tTotal Time (ms): ' + ms_total);
percentiles.forEach( function(percent){ percentiles.forEach( function(percent){
console.log('\t' + (percent*100) + 'th Percentile: ' + ms_set.percentile(percent));
console.log('\t' + (percent*100) + '% (ms): ' + ms_set.percentile(percent));
}); });
var status_data = results[url].map( function(a){ return a.status; } );
var status_set = new gauss.Vector(status_data);
var status_dist = status_set.distribution();
console.log('\tStatus Code Distribution:');
for( var status in status_dist ){
console.log('\t\t' + status + '\t' + status_dist[status]);
}
} }
for( var url in errors){
if( typeof(errors[url]) == 'function' ){
continue;
}
console.log('Errors For: ' + url);
console.log('\tErrors: ' + errors[url].length);
var code_errors = errors[url].map( function(a){ return a.error.code; });
var code_set = new gauss.Vector(code_errors);
var code_dist = code_set.distribution();
console.log('\tError Code Distribution:');
for( var code in code_dist ){
console.log('\t\t' + code + '\t' + code_dist[code]);
}
}
} }
if( argv.log ){ if( argv.log ){
@ -209,6 +246,7 @@ queue.drain = function(){
console.log('Queuing Up ' + argv.requests + ' Requests'); console.log('Queuing Up ' + argv.requests + ' Requests');
var offset = 0; var offset = 0;
var start_time = new Date().getTime();
for( var i = 0; i < argv.requests; ++i ){ for( var i = 0; i < argv.requests; ++i ){
if( offset >= urls.length ){ if( offset >= urls.length ){
offset = 0; offset = 0;


+ 1
- 1
package.json View File

@ -1,6 +1,6 @@
{ {
"name": "tommygun", "name": "tommygun",
"version": "0.0.1",
"version": "0.0.2",
"description": "HTTP Benchmarking Tool", "description": "HTTP Benchmarking Tool",
"keywords": [ "keywords": [
"http", "http",


Loading…
Cancel
Save