Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100755 224 lines (192 sloc) 6.025 kB
f21949a @pgriess Initial commit of wsbench.
authored
1 #!/bin/env node
2
3 var OptionParser = require('./lib/optparse').OptionParser;
4 var sys = require('sys');
5 var url = require('url');
6 var WebSocket = require('./lib/websocket').WebSocket;
48fd1eb @pgriess Re-work dispatch loop.
authored
7 var assert = require('assert');
f21949a @pgriess Initial commit of wsbench.
authored
8
9 var OPTIONS = {
ba8865b @pgriess Support -r <rate> option.
authored
10 connections : 10,
4bcb967 @pgriess Add '-s' option for custom session logic.
authored
11 rate : 0,
12 session : function(ws) {
4ed3616 @pgriess Support -s and -m options for sending messages.
authored
13 var ALPHABET = function() {
14 var a = '';
15 for (i = 0; i < 100; i++) {
16 a += String.fromCharCode(97 + Math.floor(Math.random() * 26));
17 }
18
19 return a;
20 }();
21
b8fcded @pgriess Add more involved example of -S usage.
authored
22 ws.onopen = function() {
4ed3616 @pgriess Support -s and -m options for sending messages.
authored
23 for (i = 0; i < OPTIONS.msgs; i++) {
24 var m = '';
25 var len = OPTIONS.msgSize;
26 var off = Math.floor(Math.random() * ALPHABET.length);
27 while (len > 0) {
28 var l = Math.min(len, ALPHABET.length - off)
29 m += ALPHABET.substr(off, l);
30 len -= l;
31 }
32
33 ws.send(m);
34 }
35
4bcb967 @pgriess Add '-s' option for custom session logic.
authored
36 ws.close();
417c749 @pgriess Detect and report errors.
authored
37 };
4ed3616 @pgriess Support -s and -m options for sending messages.
authored
38 },
39 msgs : 0,
40 msgSize : 32
f21949a @pgriess Initial commit of wsbench.
authored
41 };
42
43 var op = new OptionParser([
ba8865b @pgriess Support -r <rate> option.
authored
44 ['-c', '--num-conns NUMBER',
45 'number of connections to open (default: 10)'
46 ],
47 ['-h', '--help',
48 'display this help'
49 ],
4ed3616 @pgriess Support -s and -m options for sending messages.
authored
50 ['-m', '--num-msgs NUMBER',
51 'number of messages per connection (dfeault: 0)'
52 ],
f21949a @pgriess Initial commit of wsbench.
authored
53 ['-p', '--protocol PROTO',
54 'set the Web Socket protocol to use (default: empty)'
ba8865b @pgriess Support -r <rate> option.
authored
55 ],
56 ['-r', '--rate NUMBER',
57 'number of connections per second (default: 0)'
4bcb967 @pgriess Add '-s' option for custom session logic.
authored
58 ],
4ed3616 @pgriess Support -s and -m options for sending messages.
authored
59 ['-s', '--msg-size NUMBER',
60 'size of messages to send, in bytes (default: 32)'
61 ],
62 ['-S', '--session FILE',
4bcb967 @pgriess Add '-s' option for custom session logic.
authored
63 'file to use for session logic (default: None)'
f21949a @pgriess Initial commit of wsbench.
authored
64 ]
65 ]);
66
67 op.on('num-conns', function(o, v) {
68 OPTIONS.connections = v;
69 });
70 op.on('help', function() {
71 console.log(op.toString());
72 process.exit(0);
73 });
74 op.on('protocol', function(o, v) {
75 OPTIONS.protocol = v;
76 });
ba8865b @pgriess Support -r <rate> option.
authored
77 op.on('rate', function(o, v) {
78 OPTIONS.rate = v;
79 });
4bcb967 @pgriess Add '-s' option for custom session logic.
authored
80 op.on('session', function(o, v) {
81 if (v.length > 3 && v.substring(v.length - 3) === '.js') {
82 v = v.substring(0, v.length - 3);
83 }
84
85 if (v[0] !== '/') {
86 v = './' + v;
87 }
88
89 OPTIONS.session = require(v);
90 });
4ed3616 @pgriess Support -s and -m options for sending messages.
authored
91 op.on('num-msgs', function(o, v) {
92 OPTIONS.msgs = v;
93 });
94 op.on('msg-size', function(o, v) {
95 OPTIONS.msgSize = v;
96 });
f21949a @pgriess Initial commit of wsbench.
authored
97 op.on(2, function(v) {
98 OPTIONS.url = v;
99 });
100
101 op.banner = 'usage: wsbench [options] <url>\n' +
102 '\n' +
6a722b0 @pgriess Document the -r option a bit better.
authored
103 'Kick off a benchmarking run against the given ws:// URL.\n' +
104 '\n' +
105 'We can execute our workload in one of two ways: serially, wherein each\n' +
106 'connection is closed before the next is initiated; or in parallel, wherein\n' +
107 'a desired rate is specified and connections initiated to meet this rate,\n' +
108 'independent of the state of other connections. Serial execution is the\n' +
5b6b094 @pgriess Bound parallel execution by -c value.
authored
109 'default, and parallel execution can be specified using the -r <rate>\n' +
110 'option. Parallel execution is bounded by the total number of connections\n' +
111 'to be made, specified by the -c option.'
f21949a @pgriess Initial commit of wsbench.
authored
112
113 op.parse(process.argv);
114
115 if (!OPTIONS.url) {
ba8865b @pgriess Support -r <rate> option.
authored
116 console.error('wsbench: missing required <url> parameter');
f21949a @pgriess Initial commit of wsbench.
authored
117 console.log('');
118 console.log(op.toString());
91a0ceb @pgriess Add link to blog.std.in article on wsbench.
authored
119 process.stdout.flush();
120
121 /*
122 // XXX: This is lame. For some reason a single long string is getting
123 op.toString().split('\n').forEach(function(l) {
124 console.log(l);
125 });
126 */
f21949a @pgriess Initial commit of wsbench.
authored
127 process.exit(1);
128 }
129
48fd1eb @pgriess Re-work dispatch loop.
authored
130 var wsOpen = 0;
131 var wsClose = 0;
417c749 @pgriess Detect and report errors.
authored
132 var wsErr = 0;
133
134 var createWebSocket = function() {
135 var ws = new WebSocket(OPTIONS.url, OPTIONS.protocol);
136 OPTIONS.session(ws);
137
48fd1eb @pgriess Re-work dispatch loop.
authored
138 wsOpen++;
417c749 @pgriess Detect and report errors.
authored
139
140 ws.onerror = function(e) {
141 wsErr++;
142 ws.close();
143 };
144
48fd1eb @pgriess Re-work dispatch loop.
authored
145 ws.onclose = function() {
146 wsClose++;
147 };
148
417c749 @pgriess Detect and report errors.
authored
149 return ws;
150 };
151
ba8865b @pgriess Support -r <rate> option.
authored
152 if (!OPTIONS.rate) {
153 // We have no rate; synchronous
417c749 @pgriess Detect and report errors.
authored
154 var f = function() {
155 var ws = createWebSocket();
f21949a @pgriess Initial commit of wsbench.
authored
156
b8fcded @pgriess Add more involved example of -S usage.
authored
157 if (!ws.onclose) {
158 ws.onclose = function() {
48fd1eb @pgriess Re-work dispatch loop.
authored
159 if (wsOpen < OPTIONS.connections) {
417c749 @pgriess Detect and report errors.
authored
160 f();
b8fcded @pgriess Add more involved example of -S usage.
authored
161 }
162 };
163 }
ba8865b @pgriess Support -r <rate> option.
authored
164 }
f21949a @pgriess Initial commit of wsbench.
authored
165
417c749 @pgriess Detect and report errors.
authored
166 f();
ba8865b @pgriess Support -r <rate> option.
authored
167 } else {
48fd1eb @pgriess Re-work dispatch loop.
authored
168 var tickInterval = (OPTIONS.rate > 1000) ? 1 : (1000 / OPTIONS.rate);
169 var connsPerTick = (OPTIONS.rate > 1000) ? (OPTIONS.rate / 1000) : 1;
170 var isUnlim = (OPTIONS.connections == 0);
171
172 assert.ok(tickInterval >= 1);
173 assert.ok(connsPerTick >= 1);
174
ba8865b @pgriess Support -r <rate> option.
authored
175 // We have a rate; parallel
48fd1eb @pgriess Re-work dispatch loop.
authored
176 for (i = 0; i < 1000 / tickInterval; i++) {
177 setTimeout((function() {
178 var rem = 0;
179 var id = i;
180 var iid = undefined;
181
182 var f = function() {
183 for (rem += connsPerTick;
184 rem >= 1 && (isUnlim || wsOpen < OPTIONS.connections);
185 rem--) {
186 createWebSocket();
5b6b094 @pgriess Bound parallel execution by -c value.
authored
187 }
188
48fd1eb @pgriess Re-work dispatch loop.
authored
189 if (!isUnlim &&
190 ((wsOpen + (OPTIONS.rate - connsPerTick)) > OPTIONS.connections)) {
191 if (iid) {
192 clearInterval(iid);
193 }
194
195 // If we're the last worker and we're shutting down, fire
196 // off any remaining requests. We have to do this here
197 // because we may have some fractions of a request
198 // lingering in different worker's 'rem' values.
199 if (id == (1000 / tickInterval) - 1) {
200 while (wsOpen < OPTIONS.connections) {
201 createWebSocket();
202 }
203 }
204 } else if (!iid) {
205 iid = setInterval(f, 1000);
206 }
207 };
208
209 return f;
210 })(), i * tickInterval);
ba8865b @pgriess Support -r <rate> option.
authored
211 }
212 }
f21949a @pgriess Initial commit of wsbench.
authored
213
417c749 @pgriess Detect and report errors.
authored
214 process.addListener('SIGINT', function() {
215 process.exit(0);
216 });
217 process.addListener('exit', function() {
48fd1eb @pgriess Re-work dispatch loop.
authored
218 console.log('Success rate: ' +
219 (Math.round(((1000 * (wsOpen - wsErr - (wsOpen - wsClose))) / wsOpen)) / 10) + '% ' +
220 'from ' + wsOpen + ' connections');
417c749 @pgriess Detect and report errors.
authored
221 });
222
f21949a @pgriess Initial commit of wsbench.
authored
223 // vim: filetype=javascript
Something went wrong with that request. Please try again.