Wed, 31 Dec 2014 06:55:46 +0100
Added tag TORBROWSER_REPLICA for changeset 6474c204b198
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /*
7 ** File: thruput.c
8 ** Description: Test server's throughput capability comparing various
9 ** implmentation strategies.
10 **
11 ** Note: Requires a server machine and an aribitrary number of
12 ** clients to bang on it. Trust the numbers on the server
13 ** more than those being displayed by the various clients.
14 */
16 #include "prerror.h"
17 #include "prinrval.h"
18 #include "prinit.h"
19 #include "prio.h"
20 #include "prlock.h"
21 #include "prmem.h"
22 #include "prnetdb.h"
23 #include "prprf.h"
24 #include "prthread.h"
25 #include "pprio.h"
26 #include "plerror.h"
27 #include "plgetopt.h"
29 #define ADDR_BUFFER 100
30 #define PORT_NUMBER 51877
31 #define SAMPLING_INTERVAL 10
32 #define BUFFER_SIZE (32 * 1024)
34 static PRInt32 domain = PR_AF_INET;
35 static PRInt32 protocol = 6; /* TCP */
36 static PRFileDesc *err = NULL;
37 static PRIntn concurrency = 1;
38 static PRInt32 xport_buffer = -1;
39 static PRUint32 initial_streams = 1;
40 static PRInt32 buffer_size = BUFFER_SIZE;
41 static PRThreadScope thread_scope = PR_LOCAL_THREAD;
43 typedef struct Shared
44 {
45 PRLock *ml;
46 PRUint32 sampled;
47 PRUint32 threads;
48 PRIntervalTime timein;
49 PRNetAddr server_address;
50 } Shared;
52 static Shared *shared = NULL;
54 static PRStatus PrintAddress(const PRNetAddr* address)
55 {
56 char buffer[ADDR_BUFFER];
57 PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer));
58 if (PR_SUCCESS == rv)
59 PR_fprintf(err, "%s:%u\n", buffer, PR_ntohs(address->inet.port));
60 else PL_FPrintError(err, "PR_NetAddrToString");
61 return rv;
62 } /* PrintAddress */
65 static void PR_CALLBACK Clientel(void *arg)
66 {
67 PRStatus rv;
68 PRFileDesc *xport;
69 PRInt32 bytes, sampled;
70 PRIntervalTime now, interval;
71 PRBool do_display = PR_FALSE;
72 Shared *shared = (Shared*)arg;
73 char *buffer = (char*)PR_Malloc(buffer_size);
74 PRNetAddr *server_address = &shared->server_address;
75 PRIntervalTime connect_timeout = PR_SecondsToInterval(5);
76 PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL);
78 PR_fprintf(err, "Client connecting to ");
79 (void)PrintAddress(server_address);
81 do
82 {
83 xport = PR_Socket(domain, PR_SOCK_STREAM, protocol);
84 if (NULL == xport)
85 {
86 PL_FPrintError(err, "PR_Socket");
87 return;
88 }
90 if (xport_buffer != -1)
91 {
92 PRSocketOptionData data;
93 data.option = PR_SockOpt_RecvBufferSize;
94 data.value.recv_buffer_size = (PRSize)xport_buffer;
95 rv = PR_SetSocketOption(xport, &data);
96 if (PR_FAILURE == rv)
97 PL_FPrintError(err, "PR_SetSocketOption - ignored");
98 data.option = PR_SockOpt_SendBufferSize;
99 data.value.send_buffer_size = (PRSize)xport_buffer;
100 rv = PR_SetSocketOption(xport, &data);
101 if (PR_FAILURE == rv)
102 PL_FPrintError(err, "PR_SetSocketOption - ignored");
103 }
105 rv = PR_Connect(xport, server_address, connect_timeout);
106 if (PR_FAILURE == rv)
107 {
108 PL_FPrintError(err, "PR_Connect");
109 if (PR_IO_TIMEOUT_ERROR != PR_GetError())
110 PR_Sleep(connect_timeout);
111 PR_Close(xport); /* delete it and start over */
112 }
113 } while (PR_FAILURE == rv);
115 do
116 {
117 bytes = PR_Recv(
118 xport, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT);
119 PR_Lock(shared->ml);
120 now = PR_IntervalNow();
121 shared->sampled += bytes;
122 interval = now - shared->timein;
123 if (interval > sampling_interval)
124 {
125 sampled = shared->sampled;
126 shared->timein = now;
127 shared->sampled = 0;
128 do_display = PR_TRUE;
129 }
130 PR_Unlock(shared->ml);
132 if (do_display)
133 {
134 PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval);
135 PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate);
136 do_display = PR_FALSE;
137 }
139 } while (bytes > 0);
140 } /* Clientel */
142 static void Client(const char *server_name)
143 {
144 PRStatus rv;
145 PRHostEnt host;
146 char buffer[PR_NETDB_BUF_SIZE];
147 PRIntervalTime dally = PR_SecondsToInterval(60);
148 PR_fprintf(err, "Translating the name %s\n", server_name);
149 rv = PR_GetHostByName(server_name, buffer, sizeof(buffer), &host);
150 if (PR_FAILURE == rv)
151 PL_FPrintError(err, "PR_GetHostByName");
152 else
153 {
154 if (PR_EnumerateHostEnt(
155 0, &host, PORT_NUMBER, &shared->server_address) < 0)
156 PL_FPrintError(err, "PR_EnumerateHostEnt");
157 else
158 {
159 do
160 {
161 shared->threads += 1;
162 (void)PR_CreateThread(
163 PR_USER_THREAD, Clientel, shared,
164 PR_PRIORITY_NORMAL, thread_scope,
165 PR_UNJOINABLE_THREAD, 8 * 1024);
166 if (shared->threads == initial_streams)
167 {
168 PR_Sleep(dally);
169 initial_streams += 1;
170 }
171 } while (PR_TRUE);
172 }
173 }
174 }
176 static void PR_CALLBACK Servette(void *arg)
177 {
178 PRInt32 bytes, sampled;
179 PRIntervalTime now, interval;
180 PRBool do_display = PR_FALSE;
181 PRFileDesc *client = (PRFileDesc*)arg;
182 char *buffer = (char*)PR_Malloc(buffer_size);
183 PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL);
185 if (xport_buffer != -1)
186 {
187 PRStatus rv;
188 PRSocketOptionData data;
189 data.option = PR_SockOpt_RecvBufferSize;
190 data.value.recv_buffer_size = (PRSize)xport_buffer;
191 rv = PR_SetSocketOption(client, &data);
192 if (PR_FAILURE == rv)
193 PL_FPrintError(err, "PR_SetSocketOption - ignored");
194 data.option = PR_SockOpt_SendBufferSize;
195 data.value.send_buffer_size = (PRSize)xport_buffer;
196 rv = PR_SetSocketOption(client, &data);
197 if (PR_FAILURE == rv)
198 PL_FPrintError(err, "PR_SetSocketOption - ignored");
199 }
201 do
202 {
203 bytes = PR_Send(
204 client, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT);
206 PR_Lock(shared->ml);
207 now = PR_IntervalNow();
208 shared->sampled += bytes;
209 interval = now - shared->timein;
210 if (interval > sampling_interval)
211 {
212 sampled = shared->sampled;
213 shared->timein = now;
214 shared->sampled = 0;
215 do_display = PR_TRUE;
216 }
217 PR_Unlock(shared->ml);
219 if (do_display)
220 {
221 PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval);
222 PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate);
223 do_display = PR_FALSE;
224 }
225 } while (bytes > 0);
226 } /* Servette */
228 static void Server(void)
229 {
230 PRStatus rv;
231 PRNetAddr server_address, client_address;
232 PRFileDesc *xport = PR_Socket(domain, PR_SOCK_STREAM, protocol);
234 if (NULL == xport)
235 {
236 PL_FPrintError(err, "PR_Socket");
237 return;
238 }
240 rv = PR_InitializeNetAddr(PR_IpAddrAny, PORT_NUMBER, &server_address);
241 if (PR_FAILURE == rv) PL_FPrintError(err, "PR_InitializeNetAddr");
242 else
243 {
244 rv = PR_Bind(xport, &server_address);
245 if (PR_FAILURE == rv) PL_FPrintError(err, "PR_Bind");
246 else
247 {
248 PRFileDesc *client;
249 rv = PR_Listen(xport, 10);
250 PR_fprintf(err, "Server listening on ");
251 (void)PrintAddress(&server_address);
252 do
253 {
254 client = PR_Accept(
255 xport, &client_address, PR_INTERVAL_NO_TIMEOUT);
256 if (NULL == client) PL_FPrintError(err, "PR_Accept");
257 else
258 {
259 PR_fprintf(err, "Server accepting from ");
260 (void)PrintAddress(&client_address);
261 shared->threads += 1;
262 (void)PR_CreateThread(
263 PR_USER_THREAD, Servette, client,
264 PR_PRIORITY_NORMAL, thread_scope,
265 PR_UNJOINABLE_THREAD, 8 * 1024);
266 }
267 } while (PR_TRUE);
269 }
270 }
271 } /* Server */
273 static void Help(void)
274 {
275 PR_fprintf(err, "Usage: [-h] [<server>]\n");
276 PR_fprintf(err, "\t-s <n> Initial # of connections (default: 1)\n");
277 PR_fprintf(err, "\t-C <n> Set 'concurrency' (default: 1)\n");
278 PR_fprintf(err, "\t-b <nK> Client buffer size (default: 32k)\n");
279 PR_fprintf(err, "\t-B <nK> Transport recv/send buffer size (default: sys)\n");
280 PR_fprintf(err, "\t-G Use GLOBAL threads (default: LOCAL)\n");
281 PR_fprintf(err, "\t-X Use XTP transport (default: TCP)\n");
282 PR_fprintf(err, "\t-6 Use IPv6 (default: IPv4)\n");
283 PR_fprintf(err, "\t-h This message and nothing else\n");
284 PR_fprintf(err, "\t<server> DNS name of server\n");
285 PR_fprintf(err, "\t\tIf <server> is not specified, this host will be\n");
286 PR_fprintf(err, "\t\tthe server and not act as a client.\n");
287 } /* Help */
289 int main(int argc, char **argv)
290 {
291 PLOptStatus os;
292 const char *server_name = NULL;
293 PLOptState *opt = PL_CreateOptState(argc, argv, "hGX6C:b:s:B:");
295 err = PR_GetSpecialFD(PR_StandardError);
297 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
298 {
299 if (PL_OPT_BAD == os) continue;
300 switch (opt->option)
301 {
302 case 0: /* Name of server */
303 server_name = opt->value;
304 break;
305 case 'G': /* Globular threads */
306 thread_scope = PR_GLOBAL_THREAD;
307 break;
308 case 'X': /* Use XTP as the transport */
309 protocol = 36;
310 break;
311 case '6': /* Use IPv6 */
312 domain = PR_AF_INET6;
313 break;
314 case 's': /* initial_streams */
315 initial_streams = atoi(opt->value);
316 break;
317 case 'C': /* concurrency */
318 concurrency = atoi(opt->value);
319 break;
320 case 'b': /* buffer size */
321 buffer_size = 1024 * atoi(opt->value);
322 break;
323 case 'B': /* buffer size */
324 xport_buffer = 1024 * atoi(opt->value);
325 break;
326 case 'h': /* user wants some guidance */
327 default:
328 Help(); /* so give him an earful */
329 return 2; /* but not a lot else */
330 }
331 }
332 PL_DestroyOptState(opt);
334 shared = PR_NEWZAP(Shared);
335 shared->ml = PR_NewLock();
337 PR_fprintf(err,
338 "This machine is %s\n",
339 (NULL == server_name) ? "the SERVER" : "a CLIENT");
341 PR_fprintf(err,
342 "Transport being used is %s\n",
343 (6 == protocol) ? "TCP" : "XTP");
345 if (PR_GLOBAL_THREAD == thread_scope)
346 {
347 if (1 != concurrency)
348 {
349 PR_fprintf(err, " **Concurrency > 1 and GLOBAL threads!?!?\n");
350 PR_fprintf(err, " **Ignoring concurrency\n");
351 concurrency = 1;
352 }
353 }
355 if (1 != concurrency)
356 {
357 PR_SetConcurrency(concurrency);
358 PR_fprintf(err, "Concurrency set to %u\n", concurrency);
359 }
361 PR_fprintf(err,
362 "All threads will be %s\n",
363 (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
365 PR_fprintf(err, "Client buffer size will be %u\n", buffer_size);
367 if (-1 != xport_buffer)
368 PR_fprintf(
369 err, "Transport send & receive buffer size will be %u\n", xport_buffer);
372 if (NULL == server_name) Server();
373 else Client(server_name);
375 return 0;
376 } /* main */
378 /* thruput.c */