├── index.js ├── logo.png ├── .npmignore ├── .travis.yml ├── lib ├── tpl │ ├── head.txt │ └── report.txt └── ab.js ├── .gitignore ├── AUTHORS ├── test └── ab.test.js ├── example ├── fs.js ├── fs-report.js └── dns.js ├── Makefile ├── History.md ├── LICENSE.txt ├── package.json └── README.md /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/ab'); -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/node-modules/ab/HEAD/logo.png -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | coverage.html 3 | lib-cov/ 4 | Makefile 5 | .travis.yml 6 | logo.png 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.11' 4 | - '0.10' 5 | - '0.8' 6 | script: make test-coveralls 7 | -------------------------------------------------------------------------------- /lib/tpl/head.txt: -------------------------------------------------------------------------------- 1 | This is %s, %s Version %s 2 | Copyright (c) 2013 %s 3 | The %s License 4 | 5 | Benchmarking ... (be patient) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage.html 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | node_modules 15 | npm-debug.log -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Ordered by date of first contribution. 2 | # Auto-generated by 'contributors' on Sat, 08 Feb 2014 10:44:16 GMT. 3 | # https://github.com/xingrz/node-contributors 4 | 5 | fengmk2 (https://github.com/fengmk2) 6 | AndrewRademacher (https://github.com/AndrewRademacher) 7 | -------------------------------------------------------------------------------- /test/ab.test.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * ab - test/ab.test.js 3 | * Copyright(c) 2013 fengmk2 (http://fengmk2.github.com) 4 | * MIT Licensed 5 | */ 6 | 7 | "use strict"; 8 | 9 | /** 10 | * Module dependencies. 11 | */ 12 | 13 | var ab = require('../'); 14 | var should = require('should'); 15 | 16 | describe('ab.test.js', function () { 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /example/fs.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * ab - example/fs.js 3 | * Copyright(c) 2013 fengmk2 (http://fengmk2.github.com) 4 | * MIT Licensed 5 | */ 6 | 7 | "use strict"; 8 | 9 | /** 10 | * Module dependencies. 11 | */ 12 | 13 | var ab = require('../'); 14 | var fs = require('fs'); 15 | 16 | var fn = function (callback) { 17 | fs.exists(__filename, function (exists) { 18 | callback(null, exists); 19 | }); 20 | }; 21 | 22 | ab.run(fn, { 23 | name: 'fs.exists(__filename)', 24 | concurrency: 50, 25 | requests: 200000 26 | }); 27 | -------------------------------------------------------------------------------- /example/fs-report.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * ab - example/fs.js 3 | * Copyright(c) 2013 fengmk2 (http://fengmk2.github.com) 4 | * MIT Licensed 5 | */ 6 | 7 | "use strict"; 8 | 9 | /** 10 | * Module dependencies. 11 | */ 12 | 13 | var ab = require('../'); 14 | var fs = require('fs'); 15 | 16 | var fn = function (callback) { 17 | fs.exists(__filename, function (exists) { 18 | callback(null, exists); 19 | }); 20 | }; 21 | 22 | ab.run(fn, { 23 | name: 'fs.exists(__filename)', 24 | concurrency: 50, 25 | requests: 200000, 26 | filename: 'fs_exists.txt' 27 | }, function(err, result) { 28 | if (err) return console.error(err); 29 | console.log(result); 30 | }); 31 | -------------------------------------------------------------------------------- /example/dns.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * ab - example/dns.js 3 | * Copyright(c) 2013 fengmk2 (http://fengmk2.github.com) 4 | * MIT Licensed 5 | */ 6 | 7 | "use strict"; 8 | 9 | /** 10 | * Module dependencies. 11 | */ 12 | 13 | var ab = require('../'); 14 | var dns = require('dns'); 15 | 16 | var domain = process.argv[2]; 17 | if (!domain) { 18 | console.log('Usage: $ node dns.js [domain] [concurrency=10] [requests=10000]'); 19 | process.exit(-1); 20 | } 21 | 22 | console.log('dns.resolve(%j) Benchmark\n', domain); 23 | 24 | var fn = function (callback) { 25 | dns.resolve(domain, function (err, addresses) { 26 | // err, success 27 | callback(err, addresses && addresses.length > 0, {reqSize: 100, resSize: 200}); 28 | }); 29 | }; 30 | 31 | // fn must follow `fn(callback)` format. 32 | ab.run(fn, { 33 | name: 'dns.js', 34 | concurrency: parseInt(process.argv[3], 10) || 10, 35 | requests: parseInt(process.argv[4], 10) || 10000, 36 | }); 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TESTS = test/*.test.js 2 | REPORTER = spec 3 | TIMEOUT = 1000 4 | MOCHA_OPTS = 5 | 6 | install: 7 | @npm install --registry=http://registry.npm.taobao.org --disturl=http://npm.taobao.org/dist 8 | 9 | test: install 10 | @NODE_ENV=test ./node_modules/.bin/mocha \ 11 | --reporter $(REPORTER) \ 12 | --timeout $(TIMEOUT) \ 13 | $(MOCHA_OPTS) \ 14 | $(TESTS) 15 | 16 | test-cov: 17 | @$(MAKE) test MOCHA_OPTS='--require blanket' REPORTER=travis-cov 18 | 19 | test-cov-html: 20 | @rm -f coverage.html 21 | @$(MAKE) test MOCHA_OPTS='--require blanket' REPORTER=html-cov > coverage.html 22 | @ls -lh coverage.html 23 | 24 | test-coveralls: test 25 | @echo TRAVIS_JOB_ID $(TRAVIS_JOB_ID) 26 | @-$(MAKE) test MOCHA_OPTS='--require blanket' REPORTER=mocha-lcov-reporter | ./node_modules/.bin/coveralls 27 | 28 | test-all: test test-cov 29 | 30 | autod: install 31 | @./node_modules/.bin/autod -w --prefix "~" 32 | 33 | contributors: install 34 | @./node_modules/.bin/contributors -f plain -o AUTHORS 35 | 36 | .PHONY: test 37 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 1.0.0 / 2014-09-25 3 | ================== 4 | 5 | * update microtime to support node 0.11.14 6 | 7 | 0.1.0 / 2014-06-10 8 | ================== 9 | 10 | * deps on microtime 0.5.x 11 | * update readme 12 | 13 | 0.0.8 / 2014-02-08 14 | ================== 15 | 16 | * Added callback to library. 17 | * Added feature to write benchmark report to file. (@AndrewRademacher) 18 | * install from cnpm 19 | 20 | 0.0.7 / 2013-11-19 21 | ================== 22 | 23 | * update microtime to 0.5.0 24 | 25 | 0.0.6 / 2013-11-05 26 | ================== 27 | 28 | * add benchmark name 29 | 30 | 0.0.5 / 2013-10-29 31 | ================== 32 | 33 | * add bytes support 34 | 35 | 0.0.4 / 2013-10-28 36 | ================== 37 | 38 | * rt percent 39 | 40 | 0.0.3 / 2013-10-16 41 | ================== 42 | 43 | * update concurrency 44 | 45 | 0.0.2 / 2013-10-15 46 | ================== 47 | 48 | * fix use time bug 49 | 50 | 0.0.1 / 2013-10-15 51 | ================== 52 | 53 | * add fs and dns demo 54 | * first commit 55 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | This software is licensed under the MIT License. 2 | 3 | Copyright (C) 2013 fengmk2 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ab", 3 | "version": "1.0.0", 4 | "description": "A benchmark tool.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "make test-all", 8 | "blanket": { 9 | "pattern": "ab/lib", 10 | "data-cover-flags": { 11 | "debug": false 12 | } 13 | }, 14 | "travis-cov": { 15 | "threshold": 90 16 | } 17 | }, 18 | "dependencies": { 19 | "debug": "~2.6.7", 20 | "microtime": "~1.0.1" 21 | }, 22 | "devDependencies": { 23 | "autod": "*", 24 | "blanket": "*", 25 | "contributors": "*", 26 | "coveralls": "*", 27 | "mocha": "*", 28 | "mocha-lcov-reporter": "*", 29 | "should": "~4.0.4", 30 | "travis-cov": "*" 31 | }, 32 | "homepage": "https://github.com/node-modules/ab", 33 | "repository": { 34 | "type": "git", 35 | "url": "git://github.com/node-modules/ab.git", 36 | "web": "https://github.com/node-modules/ab" 37 | }, 38 | "bugs": { 39 | "url": "https://github.com/node-modules/ab/issues", 40 | "email": "fengmk2@gmail.com" 41 | }, 42 | "keywords": [ 43 | "ab" 44 | ], 45 | "engines": { 46 | "node": ">= 0.8.0" 47 | }, 48 | "author": { 49 | "name": "fengmk2", 50 | "email": "fengmk2@gmail.com", 51 | "url": "http://fengmk2.github.com" 52 | }, 53 | "license": "MIT" 54 | } 55 | -------------------------------------------------------------------------------- /lib/tpl/report.txt: -------------------------------------------------------------------------------- 1 | Finished %d requests 2 | 3 | 4 | Date: %s 5 | Concurrency Level: %d 6 | Time taken for tests: %s seconds 7 | Complete requests: %d 8 | Failed requests: %d 9 | Errors: %d 10 | Total transferred: %s, %s [Kbytes/sec] 11 | Sent transferred: %s, %s [Kbytes/sec] 12 | Receive transferred: %s, %s [Kbytes/sec] 13 | Requests per second: %s [#/sec] 14 | Average RT: %s [ms] 15 | Min RT: %s [ms] 16 | Max RT: %s [ms] 17 | 18 | RT ranges: 19 | 20 | 0 ~ 0.5 [ms]: %d (%s%) 21 | 0.5 ~ 1 [ms]: %d (%s%) 22 | 1 ~ 1.5 [ms]: %d (%s%) 23 | 1.5 ~ 2 [ms]: %d (%s%) 24 | 2 ~ 2.5 [ms]: %d (%s%) 25 | 2.5 ~ 3 [ms]: %d (%s%) 26 | 3 ~ 3.5 [ms]: %d (%s%) 27 | 3.5 ~ 4 [ms]: %d (%s%) 28 | 4 ~ 5 [ms]: %d (%s%) 29 | 5 ~ 6 [ms]: %d (%s%) 30 | 6 ~ 7 [ms]: %d (%s%) 31 | 7 ~ 8 [ms]: %d (%s%) 32 | 8 ~ 9 [ms]: %d (%s%) 33 | 9 ~ 10 [ms]: %d (%s%) 34 | 10 ~ 15 [ms]: %d (%s%) 35 | 15 ~ 20 [ms]: %d (%s%) 36 | 20 ~ 30 [ms]: %d (%s%) 37 | 30 ~ 50 [ms]: %d (%s%) 38 | 50 ~ 100 [ms]: %d (%s%) 39 | 100 ~ 200 [ms]: %d (%s%) 40 | 200 ~ 500 [ms]: %d (%s%) 41 | 500 ~ 1000 [ms]: %d (%s%) 42 | 1000+ [ms]: %d (%s%) 43 | 44 | Percent: 45 | 46 | 99.9%: <= %s ms 47 | 99.5%: <= %s ms 48 | 99%: <= %s ms 49 | 98%: <= %s ms 50 | 97%: <= %s ms 51 | 96%: <= %s ms 52 | 95%: <= %s ms 53 | 90%: <= %s ms 54 | 85%: <= %s ms 55 | 80%: <= %s ms 56 | 70%: <= %s ms 57 | 60%: <= %s ms 58 | 50%: <= %s ms 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ab 2 | ======= 3 | 4 | [![NPM](https://nodei.co/npm/ab.png?downloads=true&stars=true)](https://nodei.co/npm/ab/) 5 | 6 | ![logo](https://raw.github.com/node-modules/ab/master/logo.png) 7 | 8 | A benchmark tool. 9 | 10 | ## Install 11 | 12 | ```bash 13 | $ npm install ab 14 | ``` 15 | 16 | ## Usage 17 | 18 | ```js 19 | var ab = require('ab'); 20 | var fs = require('fs'); 21 | 22 | var fn = function (callback) { 23 | fs.exists(__filename, function (exists) { 24 | callback(null, exists); 25 | }); 26 | }; 27 | 28 | ab.run(fn, { 29 | concurrency: 50, 30 | requests: 100000 31 | }); 32 | ``` 33 | 34 | ## Result example 35 | 36 | ```bash 37 | $ node example/fs.js 38 | This is ab, A benchmark tool. Version 0.0.1 39 | Copyright (c) 2013 fengmk2 (http://fengmk2.github.com) 40 | The MIT License 41 | 42 | Benchmarking ... (be patient) 43 | Completed 10000 requests 44 | Completed 20000 requests 45 | Completed 30000 requests 46 | Completed 40000 requests 47 | Completed 50000 requests 48 | Completed 60000 requests 49 | Completed 70000 requests 50 | Completed 80000 requests 51 | Completed 90000 requests 52 | Completed 100000 requests 53 | Finished 100000 requests 54 | 55 | 56 | Date: Tue Oct 15 2013 22:58:35 GMT+0800 (CST) 57 | Concurrency Level: 50 58 | Time taken for tests: 2.630 seconds 59 | Complete requests: 100000 60 | Failed requests: 0 61 | Errors: 0 62 | Requests per second: 38022.814 [#/sec] 63 | Average RT: 1.313 [ms] 64 | Min RT: 0.038 [ms] 65 | Max RT: 50.989 [ms] 66 | 67 | RT ranges: 68 | 69 | 0 ~ 0.5 [ms]: 48 (0.0%) 70 | 0.5 ~ 1 [ms]: 53440 (53.4%) 71 | 1 ~ 2 [ms]: 39781 (39.8%) 72 | 2 ~ 3 [ms]: 4188 (4.2%) 73 | 3 ~ 4 [ms]: 736 (0.7%) 74 | 4 ~ 5 [ms]: 486 (0.5%) 75 | 5 ~ 6 [ms]: 272 (0.3%) 76 | 6 ~ 7 [ms]: 154 (0.2%) 77 | 7 ~ 8 [ms]: 258 (0.3%) 78 | 8 ~ 9 [ms]: 90 (0.1%) 79 | 9 ~ 10 [ms]: 65 (0.1%) 80 | 10 ~ 15 [ms]: 196 (0.2%) 81 | 15 ~ 20 [ms]: 172 (0.2%) 82 | 20 ~ 30 [ms]: 19 (0.0%) 83 | 30 ~ 50 [ms]: 93 (0.1%) 84 | 50 ~ 100 [ms]: 2 (0.0%) 85 | 100 ~ 200 [ms]: 0 (0.0%) 86 | 200 ~ 500 [ms]: 0 (0.0%) 87 | 500 ~ 1000 [ms]: 0 (0.0%) 88 | 1000+ [ms]: 0 (0.0%) 89 | ``` 90 | 91 | ## License 92 | 93 | (The MIT License) 94 | 95 | Copyright (c) 2013 - 2014 fengmk2 <fengmk2@gmail.com> and other contributors 96 | 97 | Permission is hereby granted, free of charge, to any person obtaining 98 | a copy of this software and associated documentation files (the 99 | 'Software'), to deal in the Software without restriction, including 100 | without limitation the rights to use, copy, modify, merge, publish, 101 | distribute, sublicense, and/or sell copies of the Software, and to 102 | permit persons to whom the Software is furnished to do so, subject to 103 | the following conditions: 104 | 105 | The above copyright notice and this permission notice shall be 106 | included in all copies or substantial portions of the Software. 107 | 108 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 109 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 110 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 111 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 112 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 113 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 114 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 115 | -------------------------------------------------------------------------------- /lib/ab.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * ab - lib/ab.js 3 | * 4 | * Copyright(c) 2013 fengmk2 (http://fengmk2.github.com) 5 | * MIT Licensed 6 | */ 7 | 8 | "use strict"; 9 | 10 | /** 11 | * Module dependencies. 12 | */ 13 | 14 | var debug = require('debug')('ab'); 15 | var EventEmitter = require('events').EventEmitter; 16 | var microtime = require('microtime'); 17 | var util = require('util'); 18 | var fs = require('fs'); 19 | var path = require('path'); 20 | 21 | var pkg = require('../package.json'); 22 | var HEAD = fs.readFileSync(path.join(__dirname, 'tpl', 'head.txt'), 'utf8'); 23 | var REPORT = fs.readFileSync(path.join(__dirname, 'tpl', 'report.txt'), 'utf8'); 24 | 25 | exports.run = function (fn, options, callback) { 26 | if (callback) options.callback = callback; 27 | 28 | return new Benchmark(fn, options).run(); 29 | }; 30 | 31 | function Benchmark(fn, options) { 32 | EventEmitter.call(this); 33 | this.fn = fn; 34 | options = options || {}; 35 | this._name = options.name || ''; 36 | this.requests = options.requests || 100; 37 | this.filename = options.filename || ''; 38 | this.callback = options.callback || null; 39 | this._stageCount = Math.floor(this.requests / 10); 40 | if (this._stageCount > 10000) { 41 | this._stageCount = 10000; 42 | } 43 | this.concurrency = options.concurrency || 5; 44 | this._finished = 0; 45 | this._sent = 0; 46 | this._reqSize = 0; 47 | this._resSize = 0; 48 | this._fail = 0; 49 | this._errors = 0; 50 | this._rts = []; 51 | this._startTime = 0; 52 | this._totalRT = 0; 53 | } 54 | 55 | util.inherits(Benchmark, EventEmitter); 56 | 57 | Benchmark.prototype.formatSize = function (size) { 58 | var unit = 'bytes'; 59 | if (size >= 1024) { 60 | unit = 'KB'; 61 | size /= 1024; 62 | } 63 | if (size >= 1024) { 64 | unit = 'MB'; 65 | size /= 1024; 66 | } 67 | if (size >= 1024) { 68 | unit = 'GB'; 69 | size /= 1024; 70 | } 71 | return size.toFixed(2) + ' ' + unit; 72 | }; 73 | 74 | Benchmark.prototype.run = function () { 75 | var that = this; 76 | var startTime = that._startTime = Date.now(); 77 | this.on('done', function (id) { 78 | debug('#%d done', id); 79 | if (that._finished !== that.requests) { 80 | return; 81 | } 82 | 83 | var totalUse = Date.now() - startTime; 84 | var minRT = null; 85 | var maxRT = null; 86 | var rtCounts = {'1000+': 0}; 87 | var times = [ 88 | 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 89 | 4, 5, 6, 7, 8, 9, 10, 90 | 15, 20, 30, 50, 100, 200, 500, 1000 91 | ]; 92 | for (var i = 0; i < times.length; i++) { 93 | rtCounts[times[i]] = 0; 94 | } 95 | 96 | var rts = that._rts; 97 | var totalRT = 0; 98 | for (var i = 0; i < rts.length; i++) { 99 | var rt = rts[i] / 1000; 100 | totalRT += rt; 101 | if (minRT === null || minRT > rt) { 102 | minRT = rt; 103 | } 104 | if (maxRT === null || maxRT < rt) { 105 | maxRT = rt; 106 | } 107 | var hit = false; 108 | for (var j = 0; j < times.length; j++) { 109 | var t = times[j]; 110 | if (rt <= t) { 111 | rtCounts[t] = (rtCounts[t] || 0) + 1; 112 | hit = true; 113 | break; 114 | } 115 | } 116 | if (!hit) { 117 | rtCounts['1000+']++; 118 | } 119 | } 120 | 121 | var avgRT = (totalRT / that.requests).toFixed(3); 122 | var qps = (that.requests / totalUse * 1000).toFixed(3); 123 | var total = that._finished; 124 | var rates = {}; 125 | for (var t in rtCounts) { 126 | var r = rtCounts[t] / total * 100; 127 | rates[t] = r; 128 | } 129 | 130 | var rtRates = {}; 131 | var totalRate = 0; 132 | for (var i = 0; i < times.length; i++) { 133 | var t = times[i]; 134 | totalRate += (rates[t] || 0); 135 | if (totalRate >= 99.9 && !rtRates[99.9]) { 136 | rtRates[99.9] = t; 137 | } 138 | if (totalRate >= 99.5 && !rtRates[99.5]) { 139 | rtRates[99.5] = t; 140 | } 141 | if (totalRate >= 99 && !rtRates[99]) { 142 | rtRates[99] = t; 143 | } 144 | if (totalRate >= 98 && !rtRates[98]) { 145 | rtRates[98] = t; 146 | } 147 | if (totalRate >= 97 && !rtRates[97]) { 148 | rtRates[97] = t; 149 | } 150 | if (totalRate >= 96 && !rtRates[96]) { 151 | rtRates[96] = t; 152 | } 153 | if (totalRate >= 95 && !rtRates[95]) { 154 | rtRates[95] = t; 155 | } 156 | if (totalRate >= 90 && !rtRates[90]) { 157 | rtRates[90] = t; 158 | } 159 | if (totalRate >= 85 && !rtRates[85]) { 160 | rtRates[85] = t; 161 | } 162 | if (totalRate >= 80 && !rtRates[80]) { 163 | rtRates[80] = t; 164 | } 165 | if (totalRate >= 70 && !rtRates[70]) { 166 | rtRates[70] = t; 167 | } 168 | if (totalRate >= 60 && !rtRates[60]) { 169 | rtRates[60] = t; 170 | } 171 | if (totalRate >= 50 && !rtRates[50]) { 172 | rtRates[50] = t; 173 | } 174 | } 175 | 176 | for (var t in rates) { 177 | rates[t] = rates[t].toFixed(1); 178 | } 179 | 180 | var totalSize = that._reqSize + that._resSize; 181 | var totalSizeRate = (totalSize / totalUse).toFixed(2); 182 | var reqSizeRate= (that._reqSize / totalUse).toFixed(2); 183 | var resSizeRate = (that._resSize / totalUse).toFixed(2); 184 | 185 | var report = util.format(REPORT, total, Date(), that.concurrency, (totalUse / 1000).toFixed(3), 186 | total, that._fail, that._errors, 187 | that.formatSize(totalSize), totalSizeRate, 188 | that.formatSize(that._reqSize), reqSizeRate, 189 | that.formatSize(that._resSize), resSizeRate, 190 | qps, avgRT, minRT, maxRT, 191 | rtCounts['0.5'], rates['0.5'], 192 | rtCounts['1'], rates['1'], 193 | rtCounts['1.5'], rates['1.5'], 194 | rtCounts['2'], rates['2'], 195 | rtCounts['2.5'], rates['2.5'], 196 | rtCounts['3'], rates['3'], 197 | rtCounts['3.5'], rates['3.5'], 198 | rtCounts['4'], rates['4'], 199 | rtCounts['5'], rates['5'], 200 | rtCounts['6'], rates['6'], 201 | rtCounts['7'], rates['7'], 202 | rtCounts['8'], rates['8'], 203 | rtCounts['9'], rates['9'], 204 | rtCounts['10'], rates['10'], 205 | rtCounts['15'], rates['15'], 206 | rtCounts['20'], rates['20'], 207 | rtCounts['30'], rates['30'], 208 | rtCounts['50'], rates['50'], 209 | rtCounts['100'], rates['100'], 210 | rtCounts['200'], rates['200'], 211 | rtCounts['500'], rates['500'], 212 | rtCounts['1000'], rates['1000'], 213 | rtCounts['1000+'], rates['1000+'], 214 | rtRates[99.9], rtRates[99.5], 215 | rtRates[99], rtRates[98], rtRates[97], rtRates[96], rtRates[95], rtRates[90], 216 | rtRates[85], rtRates[80], rtRates[70], rtRates[60], rtRates[50] 217 | ); 218 | if (this.filename) { 219 | fs.writeFileSync(this.filename, report, 'utf8'); 220 | } else { 221 | console.log(report); 222 | } 223 | if (that.callback) that.callback(null); 224 | that.emit('end'); 225 | }); 226 | 227 | for (var i = 0; i < that.concurrency; i++) { 228 | that.next(i); 229 | } 230 | 231 | var author = pkg.author.name + ' ' + pkg.author.email + ' ' + pkg.author.url; 232 | console.log(HEAD, pkg.name, pkg.description, pkg.version, author, pkg.license); 233 | return this; 234 | }; 235 | 236 | Benchmark.prototype.next = function (id) { 237 | var fn = this.fn; 238 | var that = this; 239 | var start = microtime.now(); 240 | if (that._sent === that.requests) { 241 | return that.emit('done', id); 242 | } 243 | that._sent++; 244 | fn(function (err, success, info) { 245 | var use = microtime.now() - start; 246 | that._rts.push(use); 247 | that._totalRT += use; 248 | that._finished++; 249 | if (info) { 250 | if (info.reqSize) { 251 | that._reqSize += info.reqSize; 252 | } 253 | if (info.resSize) { 254 | that._resSize += info.resSize; 255 | } 256 | } 257 | if (that._finished % that._stageCount === 0) { 258 | var totalUse = Date.now() - that._startTime; 259 | 260 | console.log('%sCompleted %s%, %d requests, qps: %s, rt: %s ms, speed: %s (%s / %s) [Kbytes/sec]', 261 | that._name ? (that._name + ': ') : '', 262 | (that._finished / that.requests * 100).toFixed(0), 263 | that._finished, (that._finished / totalUse * 1000).toFixed(3), 264 | (that._totalRT / that._finished / 1000).toFixed(3), 265 | ((that._reqSize + that._resSize) / totalUse).toFixed(2), 266 | (that._reqSize / totalUse).toFixed(2), 267 | (that._resSize / totalUse).toFixed(2) 268 | ); 269 | } 270 | 271 | if (err) { 272 | that._errors++; 273 | that.emit('error', err); 274 | } 275 | if (!success) { 276 | that._fail++; 277 | } 278 | that.next(id); 279 | }); 280 | }; 281 | --------------------------------------------------------------------------------