nsprpub/pr/tests/sel_spd.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7 * Test the speed of select within NSPR
michael@0 8 *
michael@0 9 */
michael@0 10
michael@0 11 #include "nspr.h"
michael@0 12 #include "prpriv.h"
michael@0 13
michael@0 14 #include <stdlib.h>
michael@0 15 #include <stdio.h>
michael@0 16 #include <errno.h>
michael@0 17 #include <string.h>
michael@0 18 #ifdef SYMBIAN
michael@0 19 #include <getopt.h>
michael@0 20 #endif
michael@0 21
michael@0 22 #define PORT_BASE 19000
michael@0 23
michael@0 24 typedef struct timer_slot_t {
michael@0 25 unsigned long d_connect;
michael@0 26 unsigned long d_cl_data;
michael@0 27 unsigned long d_sv_data;
michael@0 28 unsigned long d_close;
michael@0 29 unsigned long d_total;
michael@0 30 unsigned long requests;
michael@0 31 } timer_slot_t;
michael@0 32
michael@0 33 static long _iterations = 5;
michael@0 34 static long _client_data = 8192;
michael@0 35
michael@0 36 #ifdef SYMBIAN
michael@0 37 /*
michael@0 38 * Symbian OS does not scale well specially the requirement for thread stack
michael@0 39 * space and buffer allocation space. It is easy to get into a fragmented
michael@0 40 * memory and not be able to allocate thread stack or client/server data
michael@0 41 * buffer.
michael@0 42 */
michael@0 43 static long _server_data = (8*1024);
michael@0 44 static long _threads_max = 10, _threads = 10;
michael@0 45 #else
michael@0 46 static long _server_data = (128*1024);
michael@0 47 static long _threads_max = 10, _threads = 10;
michael@0 48 #endif
michael@0 49
michael@0 50 static int verbose=0;
michael@0 51 static PRMonitor *exit_cv;
michael@0 52 static long _thread_exit_count;
michael@0 53 static timer_slot_t *timer_data;
michael@0 54 static PRThreadScope scope1, scope2;
michael@0 55
michael@0 56 void tally_results(int);
michael@0 57
michael@0 58 /* return the diff in microseconds */
michael@0 59 unsigned long _delta(PRIntervalTime *start, PRIntervalTime *stop)
michael@0 60 {
michael@0 61 /*
michael@0 62 * Will C do the right thing with unsigned arithemtic?
michael@0 63 */
michael@0 64 return PR_IntervalToMicroseconds(*stop - *start);
michael@0 65 }
michael@0 66
michael@0 67 int _readn(PRFileDesc *sock, char *buf, int len)
michael@0 68 {
michael@0 69 int rem;
michael@0 70 int bytes;
michael@0 71
michael@0 72 for (rem=len; rem; rem -= bytes) {
michael@0 73 bytes = PR_Recv(sock, buf+len-rem, rem, 0, PR_INTERVAL_NO_TIMEOUT);
michael@0 74 if (bytes <= 0)
michael@0 75 return -1;
michael@0 76 }
michael@0 77 return len;
michael@0 78 }
michael@0 79
michael@0 80 void
michael@0 81 _thread_exit(int id)
michael@0 82 {
michael@0 83 PR_EnterMonitor(exit_cv);
michael@0 84 #ifdef DEBUG
michael@0 85 fprintf(stdout, "Thread %d EXIT\n", id);
michael@0 86 #endif
michael@0 87
michael@0 88 _thread_exit_count--;
michael@0 89 if (_thread_exit_count == 0) {
michael@0 90 #ifdef DEBUG
michael@0 91 fprintf(stdout, "Thread %d EXIT triggered notify\n", id);
michael@0 92 #endif
michael@0 93 PR_Notify(exit_cv);
michael@0 94 }
michael@0 95 PR_ExitMonitor(exit_cv);
michael@0 96 }
michael@0 97
michael@0 98 void
michael@0 99 _server_thread(void *arg_id)
michael@0 100 {
michael@0 101 void _client_thread(void *);
michael@0 102 PRThread *thread;
michael@0 103 int *id = (int *)arg_id;
michael@0 104 PRFileDesc *sock;
michael@0 105 PRSocketOptionData sockopt;
michael@0 106 PRNetAddr sa;
michael@0 107 PRFileDesc * newsock;
michael@0 108 char *data_buffer = NULL;
michael@0 109 int data_buffer_size;
michael@0 110 int index;
michael@0 111 PRIntervalTime start,
michael@0 112 connect_done,
michael@0 113 read_done,
michael@0 114 write_done,
michael@0 115 close_done;
michael@0 116
michael@0 117
michael@0 118 #ifdef DEBUG
michael@0 119 fprintf(stdout, "server thread %d alive\n", *id);
michael@0 120 #endif
michael@0 121
michael@0 122 data_buffer_size = (_client_data>_server_data?_client_data:_server_data);
michael@0 123
michael@0 124 if ( (data_buffer = (char *)PR_Malloc(data_buffer_size * sizeof(char))) == NULL ) {
michael@0 125 fprintf(stderr, "Error creating buffer in server thread %d\n", *id);
michael@0 126 goto done;
michael@0 127 }
michael@0 128
michael@0 129
michael@0 130 if ( (sock = PR_NewTCPSocket()) == NULL) {
michael@0 131 fprintf(stderr, "Error creating socket in server thread %d\n", *id);
michael@0 132 goto done;
michael@0 133 }
michael@0 134
michael@0 135 sockopt.option = PR_SockOpt_Reuseaddr;
michael@0 136 sockopt.value.reuse_addr = PR_TRUE;
michael@0 137 if ( PR_SetSocketOption(sock, &sockopt) == PR_FAILURE) {
michael@0 138 fprintf(stderr, "Error setting socket option in server thread %d\n", *id);
michael@0 139 goto done;
michael@0 140 }
michael@0 141
michael@0 142 memset(&sa, 0 , sizeof(sa));
michael@0 143 sa.inet.family = PR_AF_INET;
michael@0 144 sa.inet.port = PR_htons(PORT_BASE + *id);
michael@0 145 sa.inet.ip = PR_htonl(PR_INADDR_ANY);
michael@0 146
michael@0 147 if ( PR_Bind(sock, &sa) < 0) {
michael@0 148 fprintf(stderr, "Error binding socket in server thread %d errno = %d\n", *id, errno);
michael@0 149 goto done;
michael@0 150 }
michael@0 151
michael@0 152 if ( PR_Listen(sock, 32) < 0 ) {
michael@0 153 fprintf(stderr, "Error listening to socket in server thread %d\n", *id);
michael@0 154 goto done;
michael@0 155 }
michael@0 156
michael@0 157 /* Tell the client to start */
michael@0 158 if ( (thread = PR_CreateThread(PR_USER_THREAD,
michael@0 159 _client_thread,
michael@0 160 id,
michael@0 161 PR_PRIORITY_NORMAL,
michael@0 162 scope2,
michael@0 163 PR_UNJOINABLE_THREAD,
michael@0 164 0)) == NULL)
michael@0 165 fprintf(stderr, "Error creating client thread %d\n", *id);
michael@0 166
michael@0 167 for (index = 0; index< _iterations; index++) {
michael@0 168
michael@0 169 #ifdef DEBUG
michael@0 170 fprintf(stdout, "server thread %d loop %d\n", *id, index);
michael@0 171 #endif
michael@0 172
michael@0 173 start = PR_IntervalNow();
michael@0 174
michael@0 175 if ( (newsock = PR_Accept(sock, &sa,
michael@0 176 PR_INTERVAL_NO_TIMEOUT)) == NULL) {
michael@0 177 fprintf(stderr, "Error accepting connection %d in server thread %d\n",
michael@0 178 index, *id);
michael@0 179 goto done;
michael@0 180 }
michael@0 181 #ifdef DEBUG
michael@0 182 fprintf(stdout, "server thread %d got connection %d\n", *id, newsock);
michael@0 183 #endif
michael@0 184
michael@0 185
michael@0 186 connect_done = PR_IntervalNow();
michael@0 187
michael@0 188 if ( _readn(newsock, data_buffer, _client_data) < _client_data) {
michael@0 189 fprintf(stderr, "Error reading client data for iteration %d in server thread %d\n", index, *id );
michael@0 190 goto done;
michael@0 191 }
michael@0 192
michael@0 193 #ifdef DEBUG
michael@0 194 fprintf(stdout, "server thread %d read %d bytes\n", *id, _client_data);
michael@0 195 #endif
michael@0 196 read_done = PR_IntervalNow();
michael@0 197
michael@0 198 if ( PR_Send(newsock, data_buffer, _server_data, 0,
michael@0 199 PR_INTERVAL_NO_TIMEOUT) < _server_data) {
michael@0 200 fprintf(stderr, "Error sending client data for iteration %d in server thread %d\n", index, *id );
michael@0 201 goto done;
michael@0 202 }
michael@0 203
michael@0 204 #ifdef DEBUG
michael@0 205 fprintf(stdout, "server thread %d write %d bytes\n", *id, _server_data);
michael@0 206 #endif
michael@0 207
michael@0 208 write_done = PR_IntervalNow();
michael@0 209
michael@0 210 PR_Close(newsock);
michael@0 211
michael@0 212 close_done = PR_IntervalNow();
michael@0 213
michael@0 214 timer_data[2*(*id)].d_connect += _delta(&start, &connect_done);
michael@0 215 timer_data[2*(*id)].d_cl_data += _delta(&connect_done, &read_done);
michael@0 216 timer_data[2*(*id)].d_sv_data += _delta(&read_done, &write_done);
michael@0 217 timer_data[2*(*id)].d_close += _delta(&write_done, &close_done);
michael@0 218 timer_data[2*(*id)].d_total += _delta(&start, &close_done);
michael@0 219 timer_data[2*(*id)].requests++;
michael@0 220
michael@0 221
michael@0 222 #ifdef DEBUG
michael@0 223 fprintf(stdout, "server: %d %d %d %d %d\n",
michael@0 224 _delta(&start, &connect_done), _delta(&connect_done, &read_done),
michael@0 225 _delta(&read_done, &write_done), _delta(&write_done, &close_done),
michael@0 226 _delta(&start, &close_done));
michael@0 227 #endif
michael@0 228 }
michael@0 229
michael@0 230 done:
michael@0 231 if (data_buffer != NULL) PR_Free (data_buffer);
michael@0 232 if (sock) PR_Close(sock);
michael@0 233 _thread_exit(*id);
michael@0 234 return;
michael@0 235 }
michael@0 236
michael@0 237 void
michael@0 238 _client_thread(void *arg_id)
michael@0 239 {
michael@0 240 int *id = (int *)arg_id;
michael@0 241 int index;
michael@0 242 PRNetAddr sa;
michael@0 243 PRFileDesc *sock_h;
michael@0 244 char *data_buffer = NULL;
michael@0 245 int data_buffer_size;
michael@0 246 int bytes;
michael@0 247 PRIntervalTime start,
michael@0 248 connect_done,
michael@0 249 read_done,
michael@0 250 write_done,
michael@0 251 close_done;
michael@0 252 PRStatus rv;
michael@0 253
michael@0 254 #ifdef DEBUG
michael@0 255 fprintf(stdout, "client thread %d alive\n", *id);
michael@0 256 #endif
michael@0 257
michael@0 258 data_buffer_size = (_client_data>_server_data?_client_data:_server_data);
michael@0 259
michael@0 260 if ( (data_buffer = (char *)PR_Malloc(data_buffer_size * sizeof(char))) == NULL) {
michael@0 261 fprintf(stderr, "Error creating buffer in server thread %d\n", *id);
michael@0 262 goto done;
michael@0 263 }
michael@0 264
michael@0 265 memset(&sa, 0 , sizeof(sa));
michael@0 266 rv = PR_InitializeNetAddr(PR_IpAddrLoopback, PORT_BASE + *id, &sa);
michael@0 267 PR_ASSERT(PR_SUCCESS == rv);
michael@0 268
michael@0 269 for (index = 0; index< _iterations; index++) {
michael@0 270
michael@0 271 #ifdef DEBUG
michael@0 272 fprintf(stdout, "client thread %d loop %d\n", *id, index);
michael@0 273 #endif
michael@0 274
michael@0 275 start = PR_IntervalNow();
michael@0 276 if ( (sock_h = PR_NewTCPSocket()) == NULL) {
michael@0 277 fprintf(stderr, "Error creating socket %d in client thread %d\n",
michael@0 278 index, *id);
michael@0 279 goto done;
michael@0 280 }
michael@0 281
michael@0 282 #ifdef DEBUG
michael@0 283 fprintf(stdout, "client thread %d socket created %d\n", *id, sock_h);
michael@0 284 #endif
michael@0 285
michael@0 286 if ( PR_Connect(sock_h, &sa,
michael@0 287 PR_INTERVAL_NO_TIMEOUT) < 0) {
michael@0 288 fprintf(stderr, "Error accepting connection %d in client thread %d\n",
michael@0 289 index, *id);
michael@0 290 goto done;
michael@0 291 }
michael@0 292
michael@0 293 #ifdef DEBUG
michael@0 294 fprintf(stdout, "client thread %d socket connected %d\n", *id, sock_h);
michael@0 295 #endif
michael@0 296
michael@0 297 connect_done = PR_IntervalNow();
michael@0 298 if ( PR_Send(sock_h, data_buffer, _client_data, 0,
michael@0 299 PR_INTERVAL_NO_TIMEOUT) < _client_data) {
michael@0 300 fprintf(stderr, "Error sending client data for iteration %d in client thread %d\n", index, *id );
michael@0 301 goto done;
michael@0 302 }
michael@0 303
michael@0 304 #ifdef DEBUG
michael@0 305 fprintf(stdout, "client thread %d socket wrote %d\n", *id, _client_data);
michael@0 306 #endif
michael@0 307
michael@0 308 write_done = PR_IntervalNow();
michael@0 309 if ( (bytes = _readn(sock_h, data_buffer, _server_data)) < _server_data) {
michael@0 310 fprintf(stderr, "Error reading server data for iteration %d in client thread %d (read %d bytes)\n", index, *id, bytes );
michael@0 311 goto done;
michael@0 312 }
michael@0 313
michael@0 314 #ifdef DEBUG
michael@0 315 fprintf(stdout, "client thread %d socket read %d\n", *id, _server_data);
michael@0 316 #endif
michael@0 317
michael@0 318 read_done = PR_IntervalNow();
michael@0 319 PR_Close(sock_h);
michael@0 320 close_done = PR_IntervalNow();
michael@0 321
michael@0 322 timer_data[2*(*id)+1].d_connect += _delta(&start, &connect_done);
michael@0 323 timer_data[2*(*id)+1].d_cl_data += _delta(&connect_done, &write_done);
michael@0 324 timer_data[2*(*id)+1].d_sv_data += _delta(&write_done, &read_done);
michael@0 325 timer_data[2*(*id)+1].d_close += _delta(&read_done, &close_done);
michael@0 326 timer_data[2*(*id)+1].d_total += _delta(&start, &close_done);
michael@0 327 timer_data[2*(*id)+1].requests++;
michael@0 328 }
michael@0 329 done:
michael@0 330 if (data_buffer != NULL) PR_Free (data_buffer);
michael@0 331 _thread_exit(*id);
michael@0 332
michael@0 333 return;
michael@0 334 }
michael@0 335
michael@0 336 static
michael@0 337 void do_work(void)
michael@0 338 {
michael@0 339 int index;
michael@0 340
michael@0 341 _thread_exit_count = _threads * 2;
michael@0 342 for (index=0; index<_threads; index++) {
michael@0 343 PRThread *thread;
michael@0 344 int *id = (int *)PR_Malloc(sizeof(int));
michael@0 345
michael@0 346 *id = index;
michael@0 347
michael@0 348 if ( (thread = PR_CreateThread(PR_USER_THREAD,
michael@0 349 _server_thread,
michael@0 350 id,
michael@0 351 PR_PRIORITY_NORMAL,
michael@0 352 scope1,
michael@0 353 PR_UNJOINABLE_THREAD,
michael@0 354 0)) == NULL)
michael@0 355 fprintf(stderr, "Error creating server thread %d\n", index);
michael@0 356 }
michael@0 357
michael@0 358 PR_EnterMonitor(exit_cv);
michael@0 359 while (_thread_exit_count > 0)
michael@0 360 PR_Wait(exit_cv, PR_INTERVAL_NO_TIMEOUT);
michael@0 361 PR_ExitMonitor(exit_cv);
michael@0 362
michael@0 363 fprintf(stdout, "TEST COMPLETE!\n");
michael@0 364
michael@0 365 tally_results(verbose);
michael@0 366
michael@0 367 }
michael@0 368
michael@0 369 static void do_workUU(void)
michael@0 370 {
michael@0 371 scope1 = PR_LOCAL_THREAD;
michael@0 372 scope2 = PR_LOCAL_THREAD;
michael@0 373 do_work();
michael@0 374 }
michael@0 375
michael@0 376 static void do_workUK(void)
michael@0 377 {
michael@0 378 scope1 = PR_LOCAL_THREAD;
michael@0 379 scope2 = PR_GLOBAL_THREAD;
michael@0 380 do_work();
michael@0 381 }
michael@0 382
michael@0 383 static void do_workKU(void)
michael@0 384 {
michael@0 385 scope1 = PR_GLOBAL_THREAD;
michael@0 386 scope2 = PR_LOCAL_THREAD;
michael@0 387 do_work();
michael@0 388 }
michael@0 389
michael@0 390 static void do_workKK(void)
michael@0 391 {
michael@0 392 scope1 = PR_GLOBAL_THREAD;
michael@0 393 scope2 = PR_GLOBAL_THREAD;
michael@0 394 do_work();
michael@0 395 }
michael@0 396
michael@0 397
michael@0 398
michael@0 399 static void Measure(void (*func)(void), const char *msg)
michael@0 400 {
michael@0 401 PRIntervalTime start, stop;
michael@0 402 double d;
michael@0 403
michael@0 404 start = PR_IntervalNow();
michael@0 405 (*func)();
michael@0 406 stop = PR_IntervalNow();
michael@0 407
michael@0 408 d = (double)PR_IntervalToMicroseconds(stop - start);
michael@0 409
michael@0 410 printf("%40s: %6.2f usec\n", msg, d / _iterations);
michael@0 411 }
michael@0 412
michael@0 413
michael@0 414 int main(int argc, char **argv)
michael@0 415 {
michael@0 416 #if defined(XP_UNIX) || defined(XP_OS2)
michael@0 417 int opt;
michael@0 418 PR_IMPORT_DATA(char *) optarg;
michael@0 419 #endif
michael@0 420
michael@0 421 #if defined(XP_UNIX) || defined(XP_OS2)
michael@0 422 while ( (opt = getopt(argc, argv, "c:s:i:t:v")) != EOF) {
michael@0 423 switch(opt) {
michael@0 424 case 'i':
michael@0 425 _iterations = atoi(optarg);
michael@0 426 break;
michael@0 427 case 't':
michael@0 428 _threads_max = _threads = atoi(optarg);
michael@0 429 break;
michael@0 430 case 'c':
michael@0 431 _client_data = atoi(optarg);
michael@0 432 break;
michael@0 433 case 's':
michael@0 434 _server_data = atoi(optarg);
michael@0 435 break;
michael@0 436 case 'v':
michael@0 437 verbose = 1;
michael@0 438 break;
michael@0 439 default:
michael@0 440 break;
michael@0 441 }
michael@0 442 }
michael@0 443 #endif
michael@0 444
michael@0 445 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
michael@0 446 PR_STDIO_INIT();
michael@0 447
michael@0 448 fprintf(stdout, "Running test for %d iterations with %d simultaneous threads.\n",
michael@0 449 _iterations, _threads);
michael@0 450 fprintf(stdout, "\tWill send %d bytes of client data and %d bytes of server data\n",
michael@0 451 _client_data, _server_data);
michael@0 452
michael@0 453 if ( (exit_cv = PR_NewMonitor()) == NULL)
michael@0 454 fprintf(stderr, "Error creating monitor for exit cv\n");
michael@0 455 if ( (timer_data = (timer_slot_t *)PR_Malloc(2*_threads * sizeof(timer_slot_t))) == NULL)
michael@0 456 fprintf(stderr, "error allocating thread time results array\n");
michael@0 457 memset(timer_data, 0 , 2*_threads*sizeof(timer_slot_t));
michael@0 458
michael@0 459 Measure(do_workUU, "select loop user/user");
michael@0 460 Measure(do_workUK, "select loop user/kernel");
michael@0 461 Measure(do_workKU, "select loop kernel/user");
michael@0 462 Measure(do_workKK, "select loop kernel/kernel");
michael@0 463
michael@0 464
michael@0 465 return 0;
michael@0 466 }
michael@0 467
michael@0 468 void
michael@0 469 tally_results(int verbose)
michael@0 470 {
michael@0 471 int index;
michael@0 472 unsigned long tot_connect = 0;
michael@0 473 unsigned long tot_cl_data = 0;
michael@0 474 unsigned long tot_sv_data = 0;
michael@0 475 unsigned long tot_close = 0;
michael@0 476 unsigned long tot_all = 0;
michael@0 477 unsigned long tot_requests = 0;
michael@0 478
michael@0 479 fprintf(stdout, "Server results:\n\n");
michael@0 480 for (index=0; index<_threads_max*2; index+=2) {
michael@0 481
michael@0 482 if (verbose)
michael@0 483 fprintf(stdout, "server thread %u\t%u\t%u\t%u\t%u\t%u\t%u\n",
michael@0 484 index, timer_data[index].requests, timer_data[index].d_connect,
michael@0 485 timer_data[index].d_cl_data, timer_data[index].d_sv_data,
michael@0 486 timer_data[index].d_close, timer_data[index].d_total);
michael@0 487
michael@0 488 tot_connect += timer_data[index].d_connect / _threads;
michael@0 489 tot_cl_data += timer_data[index].d_cl_data / _threads;
michael@0 490 tot_sv_data += timer_data[index].d_sv_data / _threads;
michael@0 491 tot_close += timer_data[index].d_close / _threads;
michael@0 492 tot_all += timer_data[index].d_total / _threads;
michael@0 493 tot_requests += timer_data[index].requests / _threads;
michael@0 494 }
michael@0 495 fprintf(stdout, "----------\n");
michael@0 496 fprintf(stdout, "server per thread totals %u\t%u\t%u\t%u\t%u\n",
michael@0 497 tot_requests, tot_connect, tot_cl_data, tot_sv_data, tot_close);
michael@0 498 fprintf(stdout, "server per thread elapsed time %u\n", tot_all);
michael@0 499 fprintf(stdout, "----------\n");
michael@0 500
michael@0 501 tot_connect = tot_cl_data = tot_sv_data = tot_close = tot_all = tot_requests = 0;
michael@0 502 fprintf(stdout, "Client results:\n\n");
michael@0 503 for (index=1; index<_threads_max*2; index+=2) {
michael@0 504
michael@0 505 if (verbose)
michael@0 506 fprintf(stdout, "client thread %u\t%u\t%u\t%u\t%u\t%u\t%u\n",
michael@0 507 index, timer_data[index].requests, timer_data[index].d_connect,
michael@0 508 timer_data[index].d_cl_data, timer_data[index].d_sv_data,
michael@0 509 timer_data[index].d_close, timer_data[index].d_total);
michael@0 510
michael@0 511 tot_connect += timer_data[index].d_connect / _threads;
michael@0 512 tot_cl_data += timer_data[index].d_cl_data / _threads;
michael@0 513 tot_sv_data += timer_data[index].d_sv_data / _threads;
michael@0 514 tot_close += timer_data[index].d_close / _threads;
michael@0 515 tot_all += timer_data[index].d_total / _threads;
michael@0 516 tot_requests += timer_data[index].requests / _threads;
michael@0 517 }
michael@0 518 fprintf(stdout, "----------\n");
michael@0 519 fprintf(stdout, "client per thread totals %u\t%u\t%u\t%u\t%u\n",
michael@0 520 tot_requests, tot_connect, tot_cl_data, tot_sv_data, tot_close);
michael@0 521 fprintf(stdout, "client per thread elapsed time %u\n", tot_all);
michael@0 522 }
michael@0 523

mercurial