1 #ifdef lint 2 #define WANT_UNIX 3 #define DIRTY 4 #define WANT_INTERVALS 5 #endif /* lint */ 6 7 #ifdef HAVE_CONFIG_H 8 #include <config.h> 9 #endif 10 11 #ifdef WANT_UNIX 12 char nettest_unix_id[]="\ 13 @(#)nettest_unix.c (c) Copyright 1994-2007 Hewlett-Packard Co. Version 2.4.3"; 14 15 /****************************************************************/ 16 /* */ 17 /* nettest_bsd.c */ 18 /* */ 19 /* the BSD sockets parsing routine... */ 20 /* */ 21 /* scan_unix_args() */ 22 /* */ 23 /* the actual test routines... */ 24 /* */ 25 /* send_stream_stream() perform a stream stream test */ 26 /* recv_stream_stream() */ 27 /* send_stream_rr() perform a stream request/response */ 28 /* recv_stream_rr() */ 29 /* send_dg_stream() perform a dg stream test */ 30 /* recv_dg_stream() */ 31 /* send_dg_rr() perform a dg request/response */ 32 /* recv_dg_rr() */ 33 /* loc_cpu_rate() determine the local cpu maxrate */ 34 /* rem_cpu_rate() find the remote cpu maxrate */ 35 /* */ 36 /****************************************************************/ 37 38 /* at some point, I might want to go-in and see if I really need all */ 39 /* these includes, but for the moment, we'll let them all just sit */ 40 /* there. raj 8/94 */ 41 #include <sys/types.h> 42 #include <fcntl.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #ifndef WIN32 46 #include <sys/ipc.h> 47 #include <sys/socket.h> 48 #include <errno.h> 49 #include <signal.h> 50 #include <sys/un.h> 51 #include <unistd.h> 52 #else /* WIN32 */ 53 #include <process.h> 54 #include <winsock2.h> 55 #include <windows.h> 56 #endif /* WIN32 */ 57 #include <string.h> 58 #include <time.h> 59 #include <sys/time.h> 60 61 #ifdef NOSTDLIBH 62 #include <malloc.h> 63 #else /* NOSTDLIBH */ 64 #include <stdlib.h> 65 #endif /* NOSTDLIBH */ 66 67 #include <sys/stat.h> 68 69 70 #include "netlib.h" 71 #include "netsh.h" 72 #include "nettest_unix.h" 73 74 75 77 /* these variables are specific to the UNIX sockets tests. declare */ 78 /* them static to make them global only to this file. */ 79 80 #define UNIX_PRFX "netperf." 81 #define UNIX_LENGTH_MAX 0xFFFF - 28 82 83 static char 84 path_prefix[32]; 85 86 static int 87 rss_size, /* remote socket send buffer size */ 88 rsr_size, /* remote socket recv buffer size */ 89 lss_size_req, /* requested local socket send buffer size */ 90 lsr_size_req, /* requested local socket recv buffer size */ 91 lss_size, /* local socket send buffer size */ 92 lsr_size, /* local socket recv buffer size */ 93 req_size = 1, /* request size */ 94 rsp_size = 1, /* response size */ 95 send_size, /* how big are individual sends */ 96 recv_size; /* how big are individual receives */ 97 98 /* different options for the sockets */ 99 100 101 char unix_usage[] = "\n\ 102 Usage: netperf [global options] -- [test options] \n\ 103 \n\ 104 STREAM/DG UNIX Sockets Test Options:\n\ 105 -h Display this text\n\ 106 -m bytes Set the send size (STREAM_STREAM, DG_STREAM)\n\ 107 -M bytes Set the recv size (STREAM_STREAM, DG_STREAM)\n\ 108 -p dir Set the directory where pipes are created\n\ 109 -r req,res Set request,response size (STREAM_RR, DG_RR)\n\ 110 -s send[,recv] Set local socket send/recv buffer sizes\n\ 111 -S send[,recv] Set remote socket send/recv buffer sizes\n\ 112 \n\ 113 For those options taking two parms, at least one must be specified;\n\ 114 specifying one value without a comma will set both parms to that\n\ 115 value, specifying a value with a leading comma will set just the second\n\ 116 parm, a value with a trailing comma will set just the first. To set\n\ 117 each parm to unique values, specify both and separate them with a\n\ 118 comma.\n"; 119 120 /* this routing initializes all the test specific variables */ 122 123 static void 124 init_test_vars() 125 { 126 rss_size = 0; 127 rsr_size = 0; 128 lss_size_req = 0; 129 lsr_size_req = 0; 130 lss_size = 0; 131 lsr_size = 0; 132 req_size = 1; 133 rsp_size = 1; 134 send_size = 0; 135 recv_size = 0; 136 137 strcpy(path_prefix,"/tmp"); 138 139 } 140 141 /* This routine will create a data (listen) socket with the apropriate */ 143 /* options set and return it to the caller. this replaces all the */ 144 /* duplicate code in each of the test routines and should help make */ 145 /* things a little easier to understand. since this routine can be */ 146 /* called by either the netperf or netserver programs, all output */ 147 /* should be directed towards "where." family is generally AF_UNIX, */ 148 /* and type will be either SOCK_STREAM or SOCK_DGRAM */ 149 SOCKET 150 create_unix_socket(int family, int type) 151 { 152 153 SOCKET temp_socket; 154 int sock_opt_len; 155 156 /*set up the data socket */ 157 temp_socket = socket(family, 158 type, 159 0); 160 161 if (temp_socket == INVALID_SOCKET){ 162 fprintf(where, 163 "netperf: create_unix_socket: socket: %d\n", 164 errno); 165 fflush(where); 166 exit(1); 167 } 168 169 if (debug) { 170 fprintf(where,"create_unix_socket: socket %d obtained...\n",temp_socket); 171 fflush(where); 172 } 173 174 /* Modify the local socket size. The reason we alter the send buffer */ 175 /* size here rather than when the connection is made is to take care */ 176 /* of decreases in buffer size. Decreasing the window size after */ 177 /* connection establishment is a STREAM no-no. Also, by setting the */ 178 /* buffer (window) size before the connection is established, we can */ 179 /* control the STREAM MSS (segment size). The MSS is never more that 1/2 */ 180 /* the minimum receive buffer size at each half of the connection. */ 181 /* This is why we are altering the receive buffer size on the sending */ 182 /* size of a unidirectional transfer. If the user has not requested */ 183 /* that the socket buffers be altered, we will try to find-out what */ 184 /* their values are. If we cannot touch the socket buffer in any way, */ 185 /* we will set the values to -1 to indicate that. */ 186 187 set_sock_buffer(temp_socket, SEND_BUFFER, lss_size_req, &lss_size); 188 set_sock_buffer(temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size); 189 190 return(temp_socket); 191 192 } 193 194 195 /* This routine implements the STREAM unidirectional data transfer test */ 197 /* (a.k.a. stream) for the sockets interface. It receives its */ 198 /* parameters via global variables from the shell and writes its */ 199 /* output to the standard output. */ 200 201 202 void 203 send_stream_stream(char remote_host[]) 204 { 205 206 char *tput_title = "\ 207 Recv Send Send \n\ 208 Socket Socket Message Elapsed \n\ 209 Size Size Size Time Throughput \n\ 210 bytes bytes bytes secs. %s/sec \n\n"; 211 212 char *tput_fmt_0 = 213 "%7.2f\n"; 214 215 char *tput_fmt_1 = 216 "%5d %5d %6d %-6.2f %7.2f \n"; 217 218 char *cpu_title = "\ 219 Recv Send Send Utilization Service Demand\n\ 220 Socket Socket Message Elapsed Send Recv Send Recv\n\ 221 Size Size Size Time Throughput local remote local remote\n\ 222 bytes bytes bytes secs. %-8.8s/s %% %% us/KB us/KB\n\n"; 223 224 char *cpu_fmt_0 = 225 "%6.3f\n"; 226 227 char *cpu_fmt_1 = 228 "%5d %5d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; 229 230 char *ksink_fmt = "\n\ 231 Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ 232 Local Remote Local Remote Xfered Per Per\n\ 233 Send Recv Send Recv Send (avg) Recv (avg)\n\ 234 %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; 235 236 237 float elapsed_time; 238 239 #ifdef WANT_INTERVALS 240 int interval_count; 241 #endif 242 243 /* what we want is to have a buffer space that is at least one */ 244 /* send-size greater than our send window. this will insure that we */ 245 /* are never trying to re-use a buffer that may still be in the hands */ 246 /* of the transport. This buffer will be malloc'd after we have found */ 247 /* the size of the local senc socket buffer. We will want to deal */ 248 /* with alignment and offset concerns as well. */ 249 250 #ifdef DIRTY 251 int *message_int_ptr; 252 #endif 253 #include <sys/stat.h> 254 255 struct ring_elt *send_ring; 256 257 int len = 0; 258 int nummessages; 259 SOCKET send_socket; 260 int bytes_remaining; 261 /* with links like fddi, one can send > 32 bits worth of bytes */ 262 /* during a test... ;-) */ 263 double bytes_sent; 264 265 #ifdef DIRTY 266 int i; 267 #endif /* DIRTY */ 268 269 float local_cpu_utilization; 270 float local_service_demand; 271 float remote_cpu_utilization; 272 float remote_service_demand; 273 double thruput; 274 275 struct sockaddr_un server; 276 277 struct stream_stream_request_struct *stream_stream_request; 278 struct stream_stream_response_struct *stream_stream_response; 279 struct stream_stream_results_struct *stream_stream_result; 280 281 stream_stream_request = 282 (struct stream_stream_request_struct *)netperf_request.content.test_specific_data; 283 stream_stream_response = 284 (struct stream_stream_response_struct *)netperf_response.content.test_specific_data; 285 stream_stream_result = 286 (struct stream_stream_results_struct *)netperf_response.content.test_specific_data; 287 288 /* since we are now disconnected from the code that established the */ 289 /* control socket, and since we want to be able to use different */ 290 /* protocols and such, we are passed the name of the remote host and */ 291 /* must turn that into the test specific addressing information. */ 292 293 bzero((char *)&server, 294 sizeof(server)); 295 server.sun_family = AF_UNIX; 296 297 298 if ( print_headers ) { 299 fprintf(where,"STREAM STREAM TEST\n"); 300 if (local_cpu_usage || remote_cpu_usage) 301 fprintf(where,cpu_title,format_units()); 302 else 303 fprintf(where,tput_title,format_units()); 304 } 305 306 /* initialize a few counters */ 307 308 nummessages = 0; 309 bytes_sent = 0.0; 310 times_up = 0; 311 312 /*set up the data socket */ 313 send_socket = create_unix_socket(AF_UNIX, 314 SOCK_STREAM); 315 316 if (send_socket == INVALID_SOCKET){ 317 perror("netperf: send_stream_stream: stream stream data socket"); 318 exit(1); 319 } 320 321 if (debug) { 322 fprintf(where,"send_stream_stream: send_socket obtained...\n"); 323 } 324 325 /* at this point, we have either retrieved the socket buffer sizes, */ 326 /* or have tried to set them, so now, we may want to set the send */ 327 /* size based on that (because the user either did not use a -m */ 328 /* option, or used one with an argument of 0). If the socket buffer */ 329 /* size is not available, we will set the send size to 4KB - no */ 330 /* particular reason, just arbitrary... */ 331 if (send_size == 0) { 332 if (lss_size > 0) { 333 send_size = lss_size; 334 } 335 else { 336 send_size = 4096; 337 } 338 } 339 340 /* set-up the data buffer ring with the requested alignment and offset. */ 341 /* note also that we have allocated a quantity */ 342 /* of memory that is at least one send-size greater than our socket */ 343 /* buffer size. We want to be sure that there are at least two */ 344 /* buffers allocated - this can be a bit of a problem when the */ 345 /* send_size is bigger than the socket size, so we must check... the */ 346 /* user may have wanted to explicitly set the "width" of our send */ 347 /* buffers, we should respect that wish... */ 348 if (send_width == 0) { 349 send_width = (lss_size/send_size) + 1; 350 if (send_width == 1) send_width++; 351 } 352 353 send_ring = allocate_buffer_ring(send_width, 354 send_size, 355 local_send_align, 356 local_send_offset); 357 358 /* If the user has requested cpu utilization measurements, we must */ 359 /* calibrate the cpu(s). We will perform this task within the tests */ 360 /* themselves. If the user has specified the cpu rate, then */ 361 /* calibrate_local_cpu will return rather quickly as it will have */ 362 /* nothing to do. If local_cpu_rate is zero, then we will go through */ 363 /* all the "normal" calibration stuff and return the rate back.*/ 364 365 if (local_cpu_usage) { 366 local_cpu_rate = calibrate_local_cpu(local_cpu_rate); 367 } 368 369 /* Tell the remote end to do a listen. The server alters the socket */ 370 /* paramters on the other side at this point, hence the reason for */ 371 /* all the values being passed in the setup message. If the user did */ 372 /* not specify any of the parameters, they will be passed as 0, which */ 373 /* will indicate to the remote that no changes beyond the system's */ 374 /* default should be used. Alignment is the exception, it will */ 375 /* default to 1, which will be no alignment alterations. */ 376 377 netperf_request.content.request_type = DO_STREAM_STREAM; 378 stream_stream_request->send_buf_size = rss_size; 379 stream_stream_request->recv_buf_size = rsr_size; 380 stream_stream_request->receive_size = recv_size; 381 stream_stream_request->recv_alignment = remote_recv_align; 382 stream_stream_request->recv_offset = remote_recv_offset; 383 stream_stream_request->measure_cpu = remote_cpu_usage; 384 stream_stream_request->cpu_rate = remote_cpu_rate; 385 if (test_time) { 386 stream_stream_request->test_length = test_time; 387 } 388 else { 389 stream_stream_request->test_length = test_bytes; 390 } 391 #ifdef DIRTY 392 stream_stream_request->dirty_count = rem_dirty_count; 393 stream_stream_request->clean_count = rem_clean_count; 394 #endif /* DIRTY */ 395 396 397 if (debug > 1) { 398 fprintf(where, 399 "netperf: send_stream_stream: requesting STREAM stream test\n"); 400 } 401 402 send_request(); 403 404 /* The response from the remote will contain all of the relevant */ 405 /* socket parameters for this test type. We will put them back into */ 406 /* the variables here so they can be displayed if desired. The */ 407 /* remote will have calibrated CPU if necessary, and will have done */ 408 /* all the needed set-up we will have calibrated the cpu locally */ 409 /* before sending the request, and will grab the counter value right */ 410 /* after the connect returns. The remote will grab the counter right */ 411 /* after the accept call. This saves the hassle of extra messages */ 412 /* being sent for the STREAM tests. */ 413 414 recv_response(); 415 416 if (!netperf_response.content.serv_errno) { 417 if (debug) 418 fprintf(where,"remote listen done.\n"); 419 rsr_size = stream_stream_response->recv_buf_size; 420 rss_size = stream_stream_response->send_buf_size; 421 remote_cpu_usage = stream_stream_response->measure_cpu; 422 remote_cpu_rate = stream_stream_response->cpu_rate; 423 strcpy(server.sun_path,stream_stream_response->unix_path); 424 } 425 else { 426 Set_errno(netperf_response.content.serv_errno); 427 perror("netperf: send_stream_stream: remote error"); 428 exit(1); 429 } 430 431 /*Connect up to the remote port on the data socket */ 432 if (connect(send_socket, 433 (struct sockaddr *)&server, 434 sizeof(server)) == INVALID_SOCKET){ 435 perror("netperf: send_stream_stream: data socket connect failed"); 436 printf(" path: %s\n",server.sun_path); 437 exit(1); 438 } 439 440 /* Data Socket set-up is finished. If there were problems, either the */ 441 /* connect would have failed, or the previous response would have */ 442 /* indicated a problem. I failed to see the value of the extra */ 443 /* message after the accept on the remote. If it failed, we'll see it */ 444 /* here. If it didn't, we might as well start pumping data. */ 445 446 /* Set-up the test end conditions. For a stream test, they can be */ 447 /* either time or byte-count based. */ 448 449 if (test_time) { 450 /* The user wanted to end the test after a period of time. */ 451 times_up = 0; 452 bytes_remaining = 0; 453 start_timer(test_time); 454 } 455 else { 456 /* The tester wanted to send a number of bytes. */ 457 bytes_remaining = test_bytes; 458 times_up = 1; 459 } 460 461 /* The cpu_start routine will grab the current time and possibly */ 462 /* value of the idle counter for later use in measuring cpu */ 463 /* utilization and/or service demand and thruput. */ 464 465 cpu_start(local_cpu_usage); 466 467 /* We use an "OR" to control test execution. When the test is */ 468 /* controlled by time, the byte count check will always return false. */ 469 /* When the test is controlled by byte count, the time test will */ 470 /* always return false. When the test is finished, the whole */ 471 /* expression will go false and we will stop sending data. */ 472 473 #ifdef DIRTY 474 /* initialize the random number generator for putting dirty stuff */ 475 /* into the send buffer. raj */ 476 srand((int) getpid()); 477 #endif 478 479 while ((!times_up) || (bytes_remaining > 0)) { 480 481 #ifdef DIRTY 482 /* we want to dirty some number of consecutive integers in the buffer */ 483 /* we are about to send. we may also want to bring some number of */ 484 /* them cleanly into the cache. The clean ones will follow any dirty */ 485 /* ones into the cache. at some point, we might want to replace */ 486 /* the rand() call with something from a table to reduce our call */ 487 /* overhead during the test, but it is not a high priority item. */ 488 message_int_ptr = (int *)(send_ring->buffer_ptr); 489 for (i = 0; i < loc_dirty_count; i++) { 490 *message_int_ptr = rand(); 491 message_int_ptr++; 492 } 493 for (i = 0; i < loc_clean_count; i++) { 494 loc_dirty_count = *message_int_ptr; 495 message_int_ptr++; 496 } 497 #endif /* DIRTY */ 498 499 if((len=send(send_socket, 500 send_ring->buffer_ptr, 501 send_size, 502 0)) != send_size) { 503 if ((len >=0) || (errno == EINTR)) { 504 /* the test was interrupted, must be the end of test */ 505 break; 506 } 507 perror("netperf: data send error"); 508 printf("len was %d\n",len); 509 exit(1); 510 } 511 #ifdef WANT_INTERVALS 512 for (interval_count = 0; 513 interval_count < interval_wate; 514 interval_count++); 515 #endif 516 517 /* now we want to move our pointer to the next position in the */ 518 /* data buffer...we may also want to wrap back to the "beginning" */ 519 /* of the bufferspace, so we will mod the number of messages sent */ 520 /* by the send width, and use that to calculate the offset to add */ 521 /* to the base pointer. */ 522 nummessages++; 523 send_ring = send_ring->next; 524 if (bytes_remaining) { 525 bytes_remaining -= send_size; 526 } 527 } 528 529 /* The test is over. Flush the buffers to the remote end. We do a */ 530 /* graceful release to insure that all data has been taken by the */ 531 /* remote. */ 532 533 if (close(send_socket) == -1) { 534 perror("netperf: send_stream_stream: cannot close socket"); 535 exit(1); 536 } 537 538 /* this call will always give us the elapsed time for the test, and */ 539 /* will also store-away the necessaries for cpu utilization */ 540 541 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ 542 /* measured and how */ 543 /* long did we really */ 544 /* run? */ 545 546 /* Get the statistics from the remote end. The remote will have */ 547 /* calculated service demand and all those interesting things. If it */ 548 /* wasn't supposed to care, it will return obvious values. */ 549 550 recv_response(); 551 if (!netperf_response.content.serv_errno) { 552 if (debug) 553 fprintf(where,"remote results obtained\n"); 554 } 555 else { 556 Set_errno(netperf_response.content.serv_errno); 557 perror("netperf: remote error"); 558 559 exit(1); 560 } 561 562 /* We now calculate what our thruput was for the test. In the future, */ 563 /* we may want to include a calculation of the thruput measured by */ 564 /* the remote, but it should be the case that for a STREAM stream test, */ 565 /* that the two numbers should be *very* close... We calculate */ 566 /* bytes_sent regardless of the way the test length was controlled. */ 567 /* If it was time, we needed to, and if it was by bytes, the user may */ 568 /* have specified a number of bytes that wasn't a multiple of the */ 569 /* send_size, so we really didn't send what he asked for ;-) */ 570 571 bytes_sent = ((double) send_size * (double) nummessages) + len; 572 thruput = calc_thruput(bytes_sent); 573 574 if (local_cpu_usage || remote_cpu_usage) { 575 /* We must now do a little math for service demand and cpu */ 576 /* utilization for the system(s) */ 577 /* Of course, some of the information might be bogus because */ 578 /* there was no idle counter in the kernel(s). We need to make */ 579 /* a note of this for the user's benefit...*/ 580 if (local_cpu_usage) { 581 if (local_cpu_rate == 0.0) { 582 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); 583 fprintf(where,"Local CPU usage numbers based on process information only!\n"); 584 fflush(where); 585 } 586 local_cpu_utilization = calc_cpu_util(0.0); 587 local_service_demand = calc_service_demand(bytes_sent, 588 0.0, 589 0.0, 590 0); 591 } 592 else { 593 local_cpu_utilization = -1.0; 594 local_service_demand = -1.0; 595 } 596 597 if (remote_cpu_usage) { 598 if (remote_cpu_rate == 0.0) { 599 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); 600 fprintf(where,"Remote CPU usage numbers based on process information only!\n"); 601 fflush(where); 602 } 603 remote_cpu_utilization = stream_stream_result->cpu_util; 604 remote_service_demand = calc_service_demand(bytes_sent, 605 0.0, 606 remote_cpu_utilization, 607 stream_stream_result->num_cpus); 608 } 609 else { 610 remote_cpu_utilization = -1.0; 611 remote_service_demand = -1.0; 612 } 613 614 /* We are now ready to print all the information. If the user */ 615 /* has specified zero-level verbosity, we will just print the */ 616 /* local service demand, or the remote service demand. If the */ 617 /* user has requested verbosity level 1, he will get the basic */ 618 /* "streamperf" numbers. If the user has specified a verbosity */ 619 /* of greater than 1, we will display a veritable plethora of */ 620 /* background information from outside of this block as it it */ 621 /* not cpu_measurement specific... */ 622 623 switch (verbosity) { 624 case 0: 625 if (local_cpu_usage) { 626 fprintf(where, 627 cpu_fmt_0, 628 local_service_demand); 629 } 630 else { 631 fprintf(where, 632 cpu_fmt_0, 633 remote_service_demand); 634 } 635 break; 636 case 1: 637 case 2: 638 fprintf(where, 639 cpu_fmt_1, /* the format string */ 640 rsr_size, /* remote recvbuf size */ 641 lss_size, /* local sendbuf size */ 642 send_size, /* how large were the sends */ 643 elapsed_time, /* how long was the test */ 644 thruput, /* what was the xfer rate */ 645 local_cpu_utilization, /* local cpu */ 646 remote_cpu_utilization, /* remote cpu */ 647 local_service_demand, /* local service demand */ 648 remote_service_demand); /* remote service demand */ 649 break; 650 } 651 } 652 else { 653 /* The tester did not wish to measure service demand. */ 654 switch (verbosity) { 655 case 0: 656 fprintf(where, 657 tput_fmt_0, 658 thruput); 659 break; 660 case 1: 661 case 2: 662 fprintf(where, 663 tput_fmt_1, /* the format string */ 664 rsr_size, /* remote recvbuf size */ 665 lss_size, /* local sendbuf size */ 666 send_size, /* how large were the sends */ 667 elapsed_time, /* how long did it take */ 668 thruput);/* how fast did it go */ 669 break; 670 } 671 } 672 673 /* it would be a good thing to include information about some of the */ 674 /* other parameters that may have been set for this test, but at the */ 675 /* moment, I do not wish to figure-out all the formatting, so I will */ 676 /* just put this comment here to help remind me that it is something */ 677 /* that should be done at a later time. */ 678 679 if (verbosity > 1) { 680 /* The user wanted to know it all, so we will give it to him. */ 681 /* This information will include as much as we can find about */ 682 /* STREAM statistics, the alignments of the sends and receives */ 683 /* and all that sort of rot... */ 684 685 fprintf(where, 686 ksink_fmt, 687 "Bytes", 688 "Bytes", 689 "Bytes", 690 local_send_align, 691 remote_recv_align, 692 local_send_offset, 693 remote_recv_offset, 694 bytes_sent, 695 bytes_sent / (double)nummessages, 696 nummessages, 697 bytes_sent / (double)stream_stream_result->recv_calls, 698 stream_stream_result->recv_calls); 699 } 700 701 } 702 703 705 /* This is the server-side routine for the stream stream test. It is */ 706 /* implemented as one routine. I could break things-out somewhat, but */ 707 /* didn't feel it was necessary. */ 708 709 void 710 recv_stream_stream() 711 { 712 713 struct sockaddr_un myaddr_un, peeraddr_un; 714 SOCKET s_listen,s_data; 715 int addrlen; 716 int len; 717 int receive_calls = 0; 718 float elapsed_time; 719 int bytes_received; 720 721 struct ring_elt *recv_ring; 722 723 #ifdef DIRTY 724 char *message_ptr; 725 int *message_int_ptr; 726 int dirty_count; 727 int clean_count; 728 int i; 729 #endif 730 731 struct stream_stream_request_struct *stream_stream_request; 732 struct stream_stream_response_struct *stream_stream_response; 733 struct stream_stream_results_struct *stream_stream_results; 734 735 stream_stream_request = 736 (struct stream_stream_request_struct *)netperf_request.content.test_specific_data; 737 stream_stream_response = 738 (struct stream_stream_response_struct *)netperf_response.content.test_specific_data; 739 stream_stream_results = 740 (struct stream_stream_results_struct *)netperf_response.content.test_specific_data; 741 742 if (debug) { 743 fprintf(where,"netserver: recv_stream_stream: entered...\n"); 744 fflush(where); 745 } 746 747 /* We want to set-up the listen socket with all the desired */ 748 /* parameters and then let the initiator know that all is ready. If */ 749 /* socket size defaults are to be used, then the initiator will have */ 750 /* sent us 0's. If the socket sizes cannot be changed, then we will */ 751 /* send-back what they are. If that information cannot be determined, */ 752 /* then we send-back -1's for the sizes. If things go wrong for any */ 753 /* reason, we will drop back ten yards and punt. */ 754 755 /* If anything goes wrong, we want the remote to know about it. It */ 756 /* would be best if the error that the remote reports to the user is */ 757 /* the actual error we encountered, rather than some bogus unexpected */ 758 /* response type message. */ 759 760 if (debug) { 761 fprintf(where,"recv_stream_stream: setting the response type...\n"); 762 fflush(where); 763 } 764 765 netperf_response.content.response_type = STREAM_STREAM_RESPONSE; 766 767 if (debug) { 768 fprintf(where,"recv_stream_stream: the response type is set...\n"); 769 fflush(where); 770 } 771 772 /* We now alter the message_ptr variable to be at the desired */ 773 /* alignment with the desired offset. */ 774 775 if (debug) { 776 fprintf(where,"recv_stream_stream: requested alignment of %d\n", 777 stream_stream_request->recv_alignment); 778 fflush(where); 779 } 780 781 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ 782 /* can put in OUR values !-) At some point, we may want to nail this */ 783 /* socket to a particular network-level address, but for now, */ 784 /* INADDR_ANY should be just fine. */ 785 786 bzero((char *)&myaddr_un, 787 sizeof(myaddr_un)); 788 myaddr_un.sun_family = AF_UNIX; 789 790 /* Grab a socket to listen on, and then listen on it. */ 791 792 if (debug) { 793 fprintf(where,"recv_stream_stream: grabbing a socket...\n"); 794 fflush(where); 795 } 796 797 /* create_unix_socket expects to find some things in the global */ 798 /* variables, so set the globals based on the values in the request. */ 799 /* once the socket has been created, we will set the response values */ 800 /* based on the updated value of those globals. raj 7/94 */ 801 lss_size_req = stream_stream_request->send_buf_size; 802 lsr_size_req = stream_stream_request->recv_buf_size; 803 804 s_listen = create_unix_socket(AF_UNIX, 805 SOCK_STREAM); 806 807 if (s_listen == INVALID_SOCKET) { 808 netperf_response.content.serv_errno = errno; 809 send_response(); 810 exit(1); 811 } 812 813 /* Let's get an address assigned to this socket so we can tell the */ 814 /* initiator how to reach the data socket. There may be a desire to */ 815 /* nail this socket to a specific IP address in a multi-homed, */ 816 /* multi-connection situation, but for now, we'll ignore the issue */ 817 /* and concentrate on single connection testing. */ 818 819 strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf.")); 820 if (debug) { 821 fprintf(where,"selected a path of %s\n",myaddr_un.sun_path); 822 fflush(where); 823 } 824 if (bind(s_listen, 825 (struct sockaddr *)&myaddr_un, 826 sizeof(myaddr_un)) == SOCKET_ERROR) { 827 netperf_response.content.serv_errno = errno; 828 fprintf(where,"could not bind to path\n"); 829 close(s_listen); 830 send_response(); 831 832 exit(1); 833 } 834 835 chmod(myaddr_un.sun_path, 0666); 836 837 /* what sort of sizes did we end-up with? */ 838 if (stream_stream_request->receive_size == 0) { 839 if (lsr_size > 0) { 840 recv_size = lsr_size; 841 } 842 else { 843 recv_size = 4096; 844 } 845 } 846 else { 847 recv_size = stream_stream_request->receive_size; 848 } 849 850 /* we want to set-up our recv_ring in a manner analagous to what we */ 851 /* do on the sending side. this is more for the sake of symmetry */ 852 /* than for the needs of say copy avoidance, but it might also be */ 853 /* more realistic - this way one could conceivably go with a */ 854 /* double-buffering scheme when taking the data an putting it into */ 855 /* the filesystem or something like that. raj 7/94 */ 856 857 if (recv_width == 0) { 858 recv_width = (lsr_size/recv_size) + 1; 859 if (recv_width == 1) recv_width++; 860 } 861 862 recv_ring = allocate_buffer_ring(recv_width, 863 recv_size, 864 stream_stream_request->recv_alignment, 865 stream_stream_request->recv_offset); 866 867 if (debug) { 868 fprintf(where,"recv_stream_stream: receive alignment and offset set...\n"); 869 fflush(where); 870 } 871 872 /* Now, let's set-up the socket to listen for connections */ 873 if (listen(s_listen, 5) == SOCKET_ERROR) { 874 netperf_response.content.serv_errno = errno; 875 close(s_listen); 876 send_response(); 877 878 exit(1); 879 } 880 881 /* now get the port number assigned by the system */ 882 addrlen = sizeof(myaddr_un); 883 if (getsockname(s_listen, 884 (struct sockaddr *)&myaddr_un, 885 &addrlen) == SOCKET_ERROR){ 886 netperf_response.content.serv_errno = errno; 887 close(s_listen); 888 send_response(); 889 890 exit(1); 891 } 892 893 /* Now myaddr_un contains the path */ 894 /* returned to the sender also implicitly telling the sender that the */ 895 /* socket buffer sizing has been done. */ 896 strcpy(stream_stream_response->unix_path,myaddr_un.sun_path); 897 netperf_response.content.serv_errno = 0; 898 899 /* But wait, there's more. If the initiator wanted cpu measurements, */ 900 /* then we must call the calibrate routine, which will return the max */ 901 /* rate back to the initiator. If the CPU was not to be measured, or */ 902 /* something went wrong with the calibration, we will return a -1 to */ 903 /* the initiator. */ 904 905 stream_stream_response->cpu_rate = 0.0; /* assume no cpu */ 906 if (stream_stream_request->measure_cpu) { 907 stream_stream_response->measure_cpu = 1; 908 stream_stream_response->cpu_rate = 909 calibrate_local_cpu(stream_stream_request->cpu_rate); 910 } 911 912 /* before we send the response back to the initiator, pull some of */ 913 /* the socket parms from the globals */ 914 stream_stream_response->send_buf_size = lss_size; 915 stream_stream_response->recv_buf_size = lsr_size; 916 stream_stream_response->receive_size = recv_size; 917 918 send_response(); 919 920 addrlen = sizeof(peeraddr_un); 921 922 if ((s_data=accept(s_listen, 923 (struct sockaddr *)&peeraddr_un, 924 &addrlen)) == INVALID_SOCKET) { 925 /* Let's just punt. The remote will be given some information */ 926 close(s_listen); 927 exit(1); 928 } 929 930 /* Now it's time to start receiving data on the connection. We will */ 931 /* first grab the apropriate counters and then start grabbing. */ 932 933 cpu_start(stream_stream_request->measure_cpu); 934 935 /* The loop will exit when the sender does a shutdown, which will */ 936 /* return a length of zero */ 937 938 #ifdef DIRTY 939 /* we want to dirty some number of consecutive integers in the buffer */ 940 /* we are about to recv. we may also want to bring some number of */ 941 /* them cleanly into the cache. The clean ones will follow any dirty */ 942 /* ones into the cache. */ 943 944 dirty_count = stream_stream_request->dirty_count; 945 clean_count = stream_stream_request->clean_count; 946 message_int_ptr = (int *)recv_ring->buffer_ptr; 947 for (i = 0; i < dirty_count; i++) { 948 *message_int_ptr = rand(); 949 message_int_ptr++; 950 } 951 for (i = 0; i < clean_count; i++) { 952 dirty_count = *message_int_ptr; 953 message_int_ptr++; 954 } 955 #endif /* DIRTY */ 956 bytes_received = 0; 957 958 while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) { 959 if (len == SOCKET_ERROR) { 960 netperf_response.content.serv_errno = errno; 961 send_response(); 962 exit(1); 963 } 964 bytes_received += len; 965 receive_calls++; 966 967 /* more to the next buffer in the recv_ring */ 968 recv_ring = recv_ring->next; 969 970 #ifdef DIRTY 971 message_int_ptr = (int *)(recv_ring->buffer_ptr); 972 for (i = 0; i < dirty_count; i++) { 973 *message_int_ptr = rand(); 974 message_int_ptr++; 975 } 976 for (i = 0; i < clean_count; i++) { 977 dirty_count = *message_int_ptr; 978 message_int_ptr++; 979 } 980 #endif /* DIRTY */ 981 } 982 983 /* The loop now exits due to zero bytes received. we will have */ 984 /* counted one too many messages received, so decrement the */ 985 /* receive_calls counter by one. raj 7/94 */ 986 receive_calls--; 987 988 /* perform a shutdown to signal the sender that */ 989 /* we have received all the data sent. raj 4/93 */ 990 991 if (shutdown(s_data,1) == SOCKET_ERROR) { 992 netperf_response.content.serv_errno = errno; 993 send_response(); 994 exit(1); 995 } 996 997 cpu_stop(stream_stream_request->measure_cpu,&elapsed_time); 998 999 /* send the results to the sender */ 1000 1001 if (debug) { 1002 fprintf(where, 1003 "recv_stream_stream: got %d bytes\n", 1004 bytes_received); 1005 fprintf(where, 1006 "recv_stream_stream: got %d recvs\n", 1007 receive_calls); 1008 fflush(where); 1009 } 1010 1011 stream_stream_results->bytes_received = bytes_received; 1012 stream_stream_results->elapsed_time = elapsed_time; 1013 stream_stream_results->recv_calls = receive_calls; 1014 1015 if (stream_stream_request->measure_cpu) { 1016 stream_stream_results->cpu_util = calc_cpu_util(0.0); 1017 }; 1018 1019 if (debug > 1) { 1020 fprintf(where, 1021 "recv_stream_stream: test complete, sending results.\n"); 1022 fflush(where); 1023 } 1024 1025 send_response(); 1026 unlink(myaddr_un.sun_path); 1027 } 1028 1029 1031 /* this routine implements the sending (netperf) side of the STREAM_RR */ 1032 /* test. */ 1033 1034 void 1035 send_stream_rr(char remote_host[]) 1036 { 1037 1038 char *tput_title = "\ 1039 Local /Remote\n\ 1040 Socket Size Request Resp. Elapsed Trans.\n\ 1041 Send Recv Size Size Time Rate \n\ 1042 bytes Bytes bytes bytes secs. per sec \n\n"; 1043 1044 char *tput_fmt_0 = 1045 "%7.2f\n"; 1046 1047 char *tput_fmt_1_line_1 = "\ 1048 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; 1049 char *tput_fmt_1_line_2 = "\ 1050 %-6d %-6d\n"; 1051 1052 char *cpu_title = "\ 1053 Local /Remote\n\ 1054 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ 1055 Send Recv Size Size Time Rate local remote local remote\n\ 1056 bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; 1057 1058 char *cpu_fmt_0 = 1059 "%6.3f\n"; 1060 1061 char *cpu_fmt_1_line_1 = "\ 1062 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; 1063 1064 char *cpu_fmt_1_line_2 = "\ 1065 %-6d %-6d\n"; 1066 1067 char *ksink_fmt = "\ 1068 Alignment Offset\n\ 1069 Local Remote Local Remote\n\ 1070 Send Recv Send Recv\n\ 1071 %5d %5d %5d %5d\n"; 1072 1073 1074 int timed_out = 0; 1075 float elapsed_time; 1076 1077 int len; 1078 char *temp_message_ptr; 1079 int nummessages; 1080 SOCKET send_socket; 1081 int trans_remaining; 1082 double bytes_xferd; 1083 1084 struct ring_elt *send_ring; 1085 struct ring_elt *recv_ring; 1086 1087 int rsp_bytes_left; 1088 int rsp_bytes_recvd; 1089 1090 float local_cpu_utilization; 1091 float local_service_demand; 1092 float remote_cpu_utilization; 1093 float remote_service_demand; 1094 double thruput; 1095 1096 struct sockaddr_un server; 1097 1098 struct stream_rr_request_struct *stream_rr_request; 1099 struct stream_rr_response_struct *stream_rr_response; 1100 struct stream_rr_results_struct *stream_rr_result; 1101 1102 stream_rr_request = 1103 (struct stream_rr_request_struct *)netperf_request.content.test_specific_data; 1104 stream_rr_response= 1105 (struct stream_rr_response_struct *)netperf_response.content.test_specific_data; 1106 stream_rr_result = 1107 (struct stream_rr_results_struct *)netperf_response.content.test_specific_data; 1108 1109 /* since we are now disconnected from the code that established the */ 1110 /* control socket, and since we want to be able to use different */ 1111 /* protocols and such, we are passed the name of the remote host and */ 1112 /* must turn that into the test specific addressing information. */ 1113 1114 bzero((char *)&server, 1115 sizeof(server)); 1116 1117 server.sun_family = AF_UNIX; 1118 1119 1120 if ( print_headers ) { 1121 fprintf(where,"STREAM REQUEST/RESPONSE TEST\n"); 1122 if (local_cpu_usage || remote_cpu_usage) 1123 fprintf(where,cpu_title,format_units()); 1124 else 1125 fprintf(where,tput_title,format_units()); 1126 } 1127 1128 /* initialize a few counters */ 1129 1130 nummessages = 0; 1131 bytes_xferd = 0.0; 1132 times_up = 0; 1133 1134 /* set-up the data buffers with the requested alignment and offset. */ 1135 /* since this is a request/response test, default the send_width and */ 1136 /* recv_width to 1 and not two raj 7/94 */ 1137 1138 if (send_width == 0) send_width = 1; 1139 if (recv_width == 0) recv_width = 1; 1140 1141 send_ring = allocate_buffer_ring(send_width, 1142 req_size, 1143 local_send_align, 1144 local_send_offset); 1145 1146 recv_ring = allocate_buffer_ring(recv_width, 1147 rsp_size, 1148 local_recv_align, 1149 local_recv_offset); 1150 1151 /*set up the data socket */ 1152 send_socket = create_unix_socket(AF_UNIX, 1153 SOCK_STREAM); 1154 1155 if (send_socket == INVALID_SOCKET){ 1156 perror("netperf: send_stream_rr: stream stream data socket"); 1157 exit(1); 1158 } 1159 1160 if (debug) { 1161 fprintf(where,"send_stream_rr: send_socket obtained...\n"); 1162 } 1163 1164 /* If the user has requested cpu utilization measurements, we must */ 1165 /* calibrate the cpu(s). We will perform this task within the tests */ 1166 /* themselves. If the user has specified the cpu rate, then */ 1167 /* calibrate_local_cpu will return rather quickly as it will have */ 1168 /* nothing to do. If local_cpu_rate is zero, then we will go through */ 1169 /* all the "normal" calibration stuff and return the rate back.*/ 1170 1171 if (local_cpu_usage) { 1172 local_cpu_rate = calibrate_local_cpu(local_cpu_rate); 1173 } 1174 1175 /* Tell the remote end to do a listen. The server alters the socket */ 1176 /* paramters on the other side at this point, hence the reason for */ 1177 /* all the values being passed in the setup message. If the user did */ 1178 /* not specify any of the parameters, they will be passed as 0, which */ 1179 /* will indicate to the remote that no changes beyond the system's */ 1180 /* default should be used. Alignment is the exception, it will */ 1181 /* default to 8, which will be no alignment alterations. */ 1182 1183 netperf_request.content.request_type = DO_STREAM_RR; 1184 stream_rr_request->recv_buf_size = rsr_size; 1185 stream_rr_request->send_buf_size = rss_size; 1186 stream_rr_request->recv_alignment= remote_recv_align; 1187 stream_rr_request->recv_offset = remote_recv_offset; 1188 stream_rr_request->send_alignment= remote_send_align; 1189 stream_rr_request->send_offset = remote_send_offset; 1190 stream_rr_request->request_size = req_size; 1191 stream_rr_request->response_size = rsp_size; 1192 stream_rr_request->measure_cpu = remote_cpu_usage; 1193 stream_rr_request->cpu_rate = remote_cpu_rate; 1194 if (test_time) { 1195 stream_rr_request->test_length = test_time; 1196 } 1197 else { 1198 stream_rr_request->test_length = test_trans * -1; 1199 } 1200 1201 if (debug > 1) { 1202 fprintf(where,"netperf: send_stream_rr: requesting STREAM rr test\n"); 1203 } 1204 1205 send_request(); 1206 1207 /* The response from the remote will contain all of the relevant */ 1208 /* socket parameters for this test type. We will put them back into */ 1209 /* the variables here so they can be displayed if desired. The */ 1210 /* remote will have calibrated CPU if necessary, and will have done */ 1211 /* all the needed set-up we will have calibrated the cpu locally */ 1212 /* before sending the request, and will grab the counter value right */ 1213 /* after the connect returns. The remote will grab the counter right */ 1214 /* after the accept call. This saves the hassle of extra messages */ 1215 /* being sent for the STREAM tests. */ 1216 1217 recv_response(); 1218 1219 if (!netperf_response.content.serv_errno) { 1220 if (debug) 1221 fprintf(where,"remote listen done.\n"); 1222 rsr_size = stream_rr_response->recv_buf_size; 1223 rss_size = stream_rr_response->send_buf_size; 1224 remote_cpu_usage= stream_rr_response->measure_cpu; 1225 remote_cpu_rate = stream_rr_response->cpu_rate; 1226 /* make sure that port numbers are in network order */ 1227 strcpy(server.sun_path,stream_rr_response->unix_path); 1228 } 1229 else { 1230 Set_errno(netperf_response.content.serv_errno); 1231 perror("netperf: remote error"); 1232 1233 exit(1); 1234 } 1235 1236 /*Connect up to the remote port on the data socket */ 1237 if (connect(send_socket, 1238 (struct sockaddr *)&server, 1239 sizeof(server)) == INVALID_SOCKET){ 1240 perror("netperf: data socket connect failed"); 1241 1242 exit(1); 1243 } 1244 1245 /* Data Socket set-up is finished. If there were problems, either the */ 1246 /* connect would have failed, or the previous response would have */ 1247 /* indicated a problem. I failed to see the value of the extra */ 1248 /* message after the accept on the remote. If it failed, we'll see it */ 1249 /* here. If it didn't, we might as well start pumping data. */ 1250 1251 /* Set-up the test end conditions. For a request/response test, they */ 1252 /* can be either time or transaction based. */ 1253 1254 if (test_time) { 1255 /* The user wanted to end the test after a period of time. */ 1256 times_up = 0; 1257 trans_remaining = 0; 1258 start_timer(test_time); 1259 } 1260 else { 1261 /* The tester wanted to send a number of bytes. */ 1262 trans_remaining = test_bytes; 1263 times_up = 1; 1264 } 1265 1266 /* The cpu_start routine will grab the current time and possibly */ 1267 /* value of the idle counter for later use in measuring cpu */ 1268 /* utilization and/or service demand and thruput. */ 1269 1270 cpu_start(local_cpu_usage); 1271 1272 /* We use an "OR" to control test execution. When the test is */ 1273 /* controlled by time, the byte count check will always return false. */ 1274 /* When the test is controlled by byte count, the time test will */ 1275 /* always return false. When the test is finished, the whole */ 1276 /* expression will go false and we will stop sending data. I think I */ 1277 /* just arbitrarily decrement trans_remaining for the timed test, but */ 1278 /* will not do that just yet... One other question is whether or not */ 1279 /* the send buffer and the receive buffer should be the same buffer. */ 1280 1281 while ((!times_up) || (trans_remaining > 0)) { 1282 /* send the request. we assume that if we use a blocking socket, */ 1283 /* the request will be sent at one shot. */ 1284 if((len=send(send_socket, 1285 send_ring->buffer_ptr, 1286 req_size, 1287 0)) != req_size) { 1288 if (errno == EINTR) { 1289 /* we hit the end of a */ 1290 /* timed test. */ 1291 timed_out = 1; 1292 break; 1293 } 1294 perror("send_stream_rr: data send error"); 1295 exit(1); 1296 } 1297 send_ring = send_ring->next; 1298 1299 /* receive the response */ 1300 rsp_bytes_left = rsp_size; 1301 temp_message_ptr = recv_ring->buffer_ptr; 1302 while(rsp_bytes_left > 0) { 1303 if((rsp_bytes_recvd=recv(send_socket, 1304 temp_message_ptr, 1305 rsp_bytes_left, 1306 0)) == SOCKET_ERROR) { 1307 if (errno == EINTR) { 1308 /* We hit the end of a timed test. */ 1309 timed_out = 1; 1310 break; 1311 } 1312 perror("send_stream_rr: data recv error"); 1313 exit(1); 1314 } 1315 rsp_bytes_left -= rsp_bytes_recvd; 1316 temp_message_ptr += rsp_bytes_recvd; 1317 } 1318 recv_ring = recv_ring->next; 1319 1320 if (timed_out) { 1321 /* we may have been in a nested while loop - we need */ 1322 /* another call to break. */ 1323 break; 1324 } 1325 1326 nummessages++; 1327 if (trans_remaining) { 1328 trans_remaining--; 1329 } 1330 1331 if (debug > 3) { 1332 fprintf(where, 1333 "Transaction %d completed\n", 1334 nummessages); 1335 fflush(where); 1336 } 1337 } 1338 1339 /* At this point we used to call shutdown on the data socket to be */ 1340 /* sure all the data was delivered, but this was not germane in a */ 1341 /* request/response test, and it was causing the tests to "hang" when */ 1342 /* they were being controlled by time. So, I have replaced this */ 1343 /* shutdown call with a call to close that can be found later in the */ 1344 /* procedure. */ 1345 1346 /* this call will always give us the elapsed time for the test, and */ 1347 /* will also store-away the necessaries for cpu utilization */ 1348 1349 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ 1350 /* how long did we really run? */ 1351 1352 /* Get the statistics from the remote end. The remote will have */ 1353 /* calculated service demand and all those interesting things. If it */ 1354 /* wasn't supposed to care, it will return obvious values. */ 1355 1356 recv_response(); 1357 if (!netperf_response.content.serv_errno) { 1358 if (debug) 1359 fprintf(where,"remote results obtained\n"); 1360 } 1361 else { 1362 Set_errno(netperf_response.content.serv_errno); 1363 perror("netperf: remote error"); 1364 1365 exit(1); 1366 } 1367 1368 /* We now calculate what our thruput was for the test. In the future, */ 1369 /* we may want to include a calculation of the thruput measured by */ 1370 /* the remote, but it should be the case that for a STREAM stream test, */ 1371 /* that the two numbers should be *very* close... We calculate */ 1372 /* bytes_sent regardless of the way the test length was controlled. */ 1373 /* If it was time, we needed to, and if it was by bytes, the user may */ 1374 /* have specified a number of bytes that wasn't a multiple of the */ 1375 /* send_size, so we really didn't send what he asked for ;-) We use */ 1376 /* Kbytes/s as the units of thruput for a STREAM stream test, where K = */ 1377 /* 1024. A future enhancement *might* be to choose from a couple of */ 1378 /* unit selections. */ 1379 1380 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); 1381 thruput = calc_thruput(bytes_xferd); 1382 1383 if (local_cpu_usage || remote_cpu_usage) { 1384 /* We must now do a little math for service demand and cpu */ 1385 /* utilization for the system(s) */ 1386 /* Of course, some of the information might be bogus because */ 1387 /* there was no idle counter in the kernel(s). We need to make */ 1388 /* a note of this for the user's benefit...*/ 1389 if (local_cpu_usage) { 1390 if (local_cpu_rate == 0.0) { 1391 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); 1392 fprintf(where,"Local CPU usage numbers based on process information only!\n"); 1393 fflush(where); 1394 } 1395 local_cpu_utilization = calc_cpu_util(0.0); 1396 /* since calc_service demand is doing ms/Kunit we will */ 1397 /* multiply the number of transaction by 1024 to get */ 1398 /* "good" numbers */ 1399 local_service_demand = calc_service_demand((double) nummessages*1024, 1400 0.0, 1401 0.0, 1402 0); 1403 } 1404 else { 1405 local_cpu_utilization = -1.0; 1406 local_service_demand = -1.0; 1407 } 1408 1409 if (remote_cpu_usage) { 1410 if (remote_cpu_rate == 0.0) { 1411 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); 1412 fprintf(where,"Remote CPU usage numbers based on process information only!\n"); 1413 fflush(where); 1414 } 1415 remote_cpu_utilization = stream_rr_result->cpu_util; 1416 /* since calc_service demand is doing ms/Kunit we will */ 1417 /* multiply the number of transaction by 1024 to get */ 1418 /* "good" numbers */ 1419 remote_service_demand = calc_service_demand((double) nummessages*1024, 1420 0.0, 1421 remote_cpu_utilization, 1422 stream_rr_result->num_cpus); 1423 } 1424 else { 1425 remote_cpu_utilization = -1.0; 1426 remote_service_demand = -1.0; 1427 } 1428 1429 /* We are now ready to print all the information. If the user */ 1430 /* has specified zero-level verbosity, we will just print the */ 1431 /* local service demand, or the remote service demand. If the */ 1432 /* user has requested verbosity level 1, he will get the basic */ 1433 /* "streamperf" numbers. If the user has specified a verbosity */ 1434 /* of greater than 1, we will display a veritable plethora of */ 1435 /* background information from outside of this block as it it */ 1436 /* not cpu_measurement specific... */ 1437 1438 switch (verbosity) { 1439 case 0: 1440 if (local_cpu_usage) { 1441 fprintf(where, 1442 cpu_fmt_0, 1443 local_service_demand); 1444 } 1445 else { 1446 fprintf(where, 1447 cpu_fmt_0, 1448 remote_service_demand); 1449 } 1450 break; 1451 case 1: 1452 fprintf(where, 1453 cpu_fmt_1_line_1, /* the format string */ 1454 lss_size, /* local sendbuf size */ 1455 lsr_size, 1456 req_size, /* how large were the requests */ 1457 rsp_size, /* guess */ 1458 elapsed_time, /* how long was the test */ 1459 nummessages/elapsed_time, 1460 local_cpu_utilization, /* local cpu */ 1461 remote_cpu_utilization, /* remote cpu */ 1462 local_service_demand, /* local service demand */ 1463 remote_service_demand); /* remote service demand */ 1464 fprintf(where, 1465 cpu_fmt_1_line_2, 1466 rss_size, 1467 rsr_size); 1468 break; 1469 } 1470 } 1471 else { 1472 /* The tester did not wish to measure service demand. */ 1473 switch (verbosity) { 1474 case 0: 1475 fprintf(where, 1476 tput_fmt_0, 1477 nummessages/elapsed_time); 1478 break; 1479 case 1: 1480 fprintf(where, 1481 tput_fmt_1_line_1, /* the format string */ 1482 lss_size, 1483 lsr_size, 1484 req_size, /* how large were the requests */ 1485 rsp_size, /* how large were the responses */ 1486 elapsed_time, /* how long did it take */ 1487 nummessages/elapsed_time); 1488 fprintf(where, 1489 tput_fmt_1_line_2, 1490 rss_size, /* remote recvbuf size */ 1491 rsr_size); 1492 1493 break; 1494 } 1495 } 1496 1497 /* it would be a good thing to include information about some of the */ 1498 /* other parameters that may have been set for this test, but at the */ 1499 /* moment, I do not wish to figure-out all the formatting, so I will */ 1500 /* just put this comment here to help remind me that it is something */ 1501 /* that should be done at a later time. */ 1502 1503 if (verbosity > 1) { 1504 /* The user wanted to know it all, so we will give it to him. */ 1505 /* This information will include as much as we can find about */ 1506 /* STREAM statistics, the alignments of the sends and receives */ 1507 /* and all that sort of rot... */ 1508 1509 fprintf(where, 1510 ksink_fmt); 1511 } 1512 /* The test is over. Kill the data socket */ 1513 1514 if (close(send_socket) == -1) { 1515 perror("send_stream_rr: cannot shutdown stream stream socket"); 1516 } 1517 1518 } 1519 1520 void 1522 send_dg_stream(char remote_host[]) 1523 { 1524 /************************************************************************/ 1525 /* */ 1526 /* DG Unidirectional Send Test */ 1527 /* */ 1528 /************************************************************************/ 1529 char *tput_title = 1530 "Socket Message Elapsed Messages \n\ 1531 Size Size Time Okay Errors Throughput\n\ 1532 bytes bytes secs # # %s/sec\n\n"; 1533 1534 char *tput_fmt_0 = 1535 "%7.2f\n"; 1536 1537 char *tput_fmt_1 = 1538 "%5d %5d %-7.2f %7d %6d %7.2f\n\ 1539 %5d %-7.2f %7d %7.2f\n\n"; 1540 1541 1542 char *cpu_title = 1543 "Socket Message Elapsed Messages CPU Service\n\ 1544 Size Size Time Okay Errors Throughput Util Demand\n\ 1545 bytes bytes secs # # %s/sec %% us/KB\n\n"; 1546 1547 char *cpu_fmt_0 = 1548 "%6.2f\n"; 1549 1550 char *cpu_fmt_1 = 1551 "%5d %5d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\ 1552 %5d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n"; 1553 1554 int messages_recvd; 1555 float elapsed_time, 1556 local_cpu_utilization, 1557 remote_cpu_utilization; 1558 1559 float local_service_demand, remote_service_demand; 1560 double local_thruput, remote_thruput; 1561 double bytes_sent; 1562 double bytes_recvd; 1563 1564 1565 int len; 1566 struct ring_elt *send_ring; 1567 int failed_sends; 1568 int failed_cows; 1569 int messages_sent; 1570 SOCKET data_socket; 1571 1572 1573 #ifdef WANT_INTERVALS 1574 int interval_count; 1575 #endif /* WANT_INTERVALS */ 1576 #ifdef DIRTY 1577 int *message_int_ptr; 1578 int i; 1579 #endif /* DIRTY */ 1580 1581 struct sockaddr_un server; 1582 1583 struct dg_stream_request_struct *dg_stream_request; 1584 struct dg_stream_response_struct *dg_stream_response; 1585 struct dg_stream_results_struct *dg_stream_results; 1586 1587 dg_stream_request = (struct dg_stream_request_struct *)netperf_request.content.test_specific_data; 1588 dg_stream_response = (struct dg_stream_response_struct *)netperf_response.content.test_specific_data; 1589 dg_stream_results = (struct dg_stream_results_struct *)netperf_response.content.test_specific_data; 1590 1591 /* since we are now disconnected from the code that established the */ 1592 /* control socket, and since we want to be able to use different */ 1593 /* protocols and such, we are passed the name of the remote host and */ 1594 /* must turn that into the test specific addressing information. */ 1595 1596 bzero((char *)&server, 1597 sizeof(server)); 1598 1599 server.sun_family = AF_UNIX; 1600 1601 if ( print_headers ) { 1602 printf("DG UNIDIRECTIONAL SEND TEST\n"); 1603 if (local_cpu_usage || remote_cpu_usage) 1604 printf(cpu_title,format_units()); 1605 else 1606 printf(tput_title,format_units()); 1607 } 1608 1609 failed_sends = 0; 1610 failed_cows = 0; 1611 messages_sent = 0; 1612 times_up = 0; 1613 1614 /*set up the data socket */ 1615 data_socket = create_unix_socket(AF_UNIX, 1616 SOCK_DGRAM); 1617 1618 if (data_socket == INVALID_SOCKET){ 1619 perror("dg_send: data socket"); 1620 exit(1); 1621 } 1622 1623 /* now, we want to see if we need to set the send_size */ 1624 if (send_size == 0) { 1625 if (lss_size > 0) { 1626 send_size = (lss_size < UNIX_LENGTH_MAX ? lss_size : UNIX_LENGTH_MAX); 1627 } 1628 else { 1629 send_size = 4096; 1630 } 1631 } 1632 1633 1634 /* set-up the data buffer with the requested alignment and offset, */ 1635 /* most of the numbers here are just a hack to pick something nice */ 1636 /* and big in an attempt to never try to send a buffer a second time */ 1637 /* before it leaves the node...unless the user set the width */ 1638 /* explicitly. */ 1639 if (send_width == 0) send_width = 32; 1640 1641 send_ring = allocate_buffer_ring(send_width, 1642 send_size, 1643 local_send_align, 1644 local_send_offset); 1645 1646 /* At this point, we want to do things like disable DG checksumming */ 1647 /* and measure the cpu rate and all that so we are ready to go */ 1648 /* immediately after the test response message is delivered. */ 1649 1650 /* if the user supplied a cpu rate, this call will complete rather */ 1651 /* quickly, otherwise, the cpu rate will be retured to us for */ 1652 /* possible display. The Library will keep it's own copy of this data */ 1653 /* for use elsewhere. We will only display it. (Does that make it */ 1654 /* "opaque" to us?) */ 1655 1656 if (local_cpu_usage) 1657 local_cpu_rate = calibrate_local_cpu(local_cpu_rate); 1658 1659 /* Tell the remote end to set up the data connection. The server */ 1660 /* sends back the port number and alters the socket parameters there. */ 1661 /* Of course this is a datagram service so no connection is actually */ 1662 /* set up, the server just sets up the socket and binds it. */ 1663 1664 netperf_request.content.request_type = DO_DG_STREAM; 1665 dg_stream_request->recv_buf_size = rsr_size; 1666 dg_stream_request->message_size = send_size; 1667 dg_stream_request->recv_alignment = remote_recv_align; 1668 dg_stream_request->recv_offset = remote_recv_offset; 1669 dg_stream_request->measure_cpu = remote_cpu_usage; 1670 dg_stream_request->cpu_rate = remote_cpu_rate; 1671 dg_stream_request->test_length = test_time; 1672 1673 send_request(); 1674 1675 recv_response(); 1676 1677 if (!netperf_response.content.serv_errno) { 1678 if (debug) 1679 fprintf(where,"send_dg_stream: remote data connection done.\n"); 1680 } 1681 else { 1682 Set_errno(netperf_response.content.serv_errno); 1683 perror("send_dg_stream: error on remote"); 1684 exit(1); 1685 } 1686 1687 /* Place the port number returned by the remote into the sockaddr */ 1688 /* structure so our sends can be sent to the correct place. Also get */ 1689 /* some of the returned socket buffer information for user display. */ 1690 1691 /* make sure that port numbers are in the proper order */ 1692 strcpy(server.sun_path,dg_stream_response->unix_path); 1693 rsr_size = dg_stream_response->recv_buf_size; 1694 rss_size = dg_stream_response->send_buf_size; 1695 remote_cpu_rate = dg_stream_response->cpu_rate; 1696 1697 /* We "connect" up to the remote post to allow is to use the send */ 1698 /* call instead of the sendto call. Presumeably, this is a little */ 1699 /* simpler, and a little more efficient. I think that it also means */ 1700 /* that we can be informed of certain things, but am not sure yet... */ 1701 1702 if (connect(data_socket, 1703 (struct sockaddr *)&server, 1704 sizeof(server)) == INVALID_SOCKET){ 1705 perror("send_dg_stream: data socket connect failed"); 1706 exit(1); 1707 } 1708 1709 /* set up the timer to call us after test_time */ 1710 start_timer(test_time); 1711 1712 /* Get the start count for the idle counter and the start time */ 1713 1714 cpu_start(local_cpu_usage); 1715 1716 #ifdef WANT_INTERVALS 1717 interval_count = interval_burst; 1718 #endif 1719 1720 /* Send datagrams like there was no tomorrow. at somepoint it might */ 1721 /* be nice to set this up so that a quantity of bytes could be sent, */ 1722 /* but we still need some sort of end of test trigger on the receive */ 1723 /* side. that could be a select with a one second timeout, but then */ 1724 /* if there is a test where none of the data arrives for awile and */ 1725 /* then starts again, we would end the test too soon. something to */ 1726 /* think about... */ 1727 while (!times_up) { 1728 1729 #ifdef DIRTY 1730 /* we want to dirty some number of consecutive integers in the buffer */ 1731 /* we are about to send. we may also want to bring some number of */ 1732 /* them cleanly into the cache. The clean ones will follow any dirty */ 1733 /* ones into the cache. */ 1734 message_int_ptr = (int *)(send_ring->buffer_ptr); 1735 for (i = 0; i < loc_dirty_count; i++) { 1736 *message_int_ptr = 4; 1737 message_int_ptr++; 1738 } 1739 for (i = 0; i < loc_clean_count; i++) { 1740 loc_dirty_count = *message_int_ptr; 1741 message_int_ptr++; 1742 } 1743 #endif /* DIRTY */ 1744 1745 if ((len=send(data_socket, 1746 send_ring->buffer_ptr, 1747 send_size, 1748 0)) != send_size) { 1749 if ((len >= 0) || (errno == EINTR)) 1750 break; 1751 if (errno == ENOBUFS) { 1752 failed_sends++; 1753 continue; 1754 } 1755 perror("dg_send: data send error"); 1756 exit(1); 1757 } 1758 messages_sent++; 1759 1760 /* now we want to move our pointer to the next position in the */ 1761 /* data buffer... */ 1762 1763 send_ring = send_ring->next; 1764 1765 1766 #ifdef WANT_INTERVALS 1767 /* in this case, the interval count is the count-down couter */ 1768 /* to decide to sleep for a little bit */ 1769 if ((interval_burst) && (--interval_count == 0)) { 1770 /* call the sleep routine for some milliseconds, if our */ 1771 /* timer popped while we were in there, we want to */ 1772 /* break out of the loop. */ 1773 if (msec_sleep(interval_wate)) { 1774 break; 1775 } 1776 interval_count = interval_burst; 1777 } 1778 1779 #endif 1780 1781 } 1782 1783 /* This is a timed test, so the remote will be returning to us after */ 1784 /* a time. We should not need to send any "strange" messages to tell */ 1785 /* the remote that the test is completed, unless we decide to add a */ 1786 /* number of messages to the test. */ 1787 1788 /* the test is over, so get stats and stuff */ 1789 cpu_stop(local_cpu_usage, 1790 &elapsed_time); 1791 1792 /* Get the statistics from the remote end */ 1793 recv_response(); 1794 if (!netperf_response.content.serv_errno) { 1795 if (debug) 1796 fprintf(where,"send_dg_stream: remote results obtained\n"); 1797 } 1798 else { 1799 Set_errno(netperf_response.content.serv_errno); 1800 perror("send_dg_stream: error on remote"); 1801 exit(1); 1802 } 1803 1804 bytes_sent = send_size * messages_sent; 1805 local_thruput = calc_thruput(bytes_sent); 1806 1807 messages_recvd = dg_stream_results->messages_recvd; 1808 bytes_recvd = send_size * messages_recvd; 1809 1810 /* we asume that the remote ran for as long as we did */ 1811 1812 remote_thruput = calc_thruput(bytes_recvd); 1813 1814 /* print the results for this socket and message size */ 1815 1816 if (local_cpu_usage || remote_cpu_usage) { 1817 /* We must now do a little math for service demand and cpu */ 1818 /* utilization for the system(s) We pass zeros for the local */ 1819 /* cpu utilization and elapsed time to tell the routine to use */ 1820 /* the libraries own values for those. */ 1821 if (local_cpu_usage) { 1822 if (local_cpu_rate == 0.0) { 1823 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); 1824 fprintf(where,"Local CPU usage numbers based on process information only!\n"); 1825 fflush(where); 1826 } 1827 1828 local_cpu_utilization = calc_cpu_util(0.0); 1829 local_service_demand = calc_service_demand(bytes_sent, 1830 0.0, 1831 0.0, 1832 0); 1833 } 1834 else { 1835 local_cpu_utilization = -1.0; 1836 local_service_demand = -1.0; 1837 } 1838 1839 /* The local calculations could use variables being kept by */ 1840 /* the local netlib routines. The remote calcuations need to */ 1841 /* have a few things passed to them. */ 1842 if (remote_cpu_usage) { 1843 if (remote_cpu_rate == 0.0) { 1844 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); 1845 fprintf(where,"REMOTE CPU usage numbers based on process information only!\n"); 1846 fflush(where); 1847 } 1848 1849 remote_cpu_utilization = dg_stream_results->cpu_util; 1850 remote_service_demand = calc_service_demand(bytes_recvd, 1851 0.0, 1852 remote_cpu_utilization, 1853 dg_stream_results->num_cpus); 1854 } 1855 else { 1856 remote_cpu_utilization = -1.0; 1857 remote_service_demand = -1.0; 1858 } 1859 1860 /* We are now ready to print all the information. If the user */ 1861 /* has specified zero-level verbosity, we will just print the */ 1862 /* local service demand, or the remote service demand. If the */ 1863 /* user has requested verbosity level 1, he will get the basic */ 1864 /* "streamperf" numbers. If the user has specified a verbosity */ 1865 /* of greater than 1, we will display a veritable plethora of */ 1866 /* background information from outside of this block as it it */ 1867 /* not cpu_measurement specific... */ 1868 1869 switch (verbosity) { 1870 case 0: 1871 if (local_cpu_usage) { 1872 fprintf(where, 1873 cpu_fmt_0, 1874 local_service_demand); 1875 } 1876 else { 1877 fprintf(where, 1878 cpu_fmt_0, 1879 remote_service_demand); 1880 } 1881 break; 1882 case 1: 1883 fprintf(where, 1884 cpu_fmt_1, /* the format string */ 1885 lss_size, /* local sendbuf size */ 1886 send_size, /* how large were the sends */ 1887 elapsed_time, /* how long was the test */ 1888 messages_sent, 1889 failed_sends, 1890 local_thruput, /* what was the xfer rate */ 1891 local_cpu_utilization, /* local cpu */ 1892 local_service_demand, /* local service demand */ 1893 rsr_size, 1894 elapsed_time, 1895 messages_recvd, 1896 remote_thruput, 1897 remote_cpu_utilization, /* remote cpu */ 1898 remote_service_demand); /* remote service demand */ 1899 break; 1900 } 1901 } 1902 else { 1903 /* The tester did not wish to measure service demand. */ 1904 switch (verbosity) { 1905 case 0: 1906 fprintf(where, 1907 tput_fmt_0, 1908 local_thruput); 1909 break; 1910 case 1: 1911 fprintf(where, 1912 tput_fmt_1, /* the format string */ 1913 lss_size, /* local sendbuf size */ 1914 send_size, /* how large were the sends */ 1915 elapsed_time, /* how long did it take */ 1916 messages_sent, 1917 failed_sends, 1918 local_thruput, 1919 rsr_size, /* remote recvbuf size */ 1920 elapsed_time, 1921 messages_recvd, 1922 remote_thruput 1923 ); 1924 break; 1925 } 1926 } 1927 } 1928 1929 1931 /* this routine implements the receive side (netserver) of the */ 1932 /* DG_STREAM performance test. */ 1933 1934 void 1935 recv_dg_stream() 1936 { 1937 struct ring_elt *recv_ring; 1938 1939 struct sockaddr_un myaddr_un; 1940 SOCKET s_data; 1941 int len = 0; 1942 int bytes_received = 0; 1943 float elapsed_time; 1944 1945 int message_size; 1946 int messages_recvd = 0; 1947 1948 struct dg_stream_request_struct *dg_stream_request; 1949 struct dg_stream_response_struct *dg_stream_response; 1950 struct dg_stream_results_struct *dg_stream_results; 1951 1952 dg_stream_request = 1953 (struct dg_stream_request_struct *)netperf_request.content.test_specific_data; 1954 dg_stream_response = 1955 (struct dg_stream_response_struct *)netperf_response.content.test_specific_data; 1956 dg_stream_results = 1957 (struct dg_stream_results_struct *)netperf_response.content.test_specific_data; 1958 1959 if (debug) { 1960 fprintf(where,"netserver: recv_dg_stream: entered...\n"); 1961 fflush(where); 1962 } 1963 1964 /* We want to set-up the listen socket with all the desired */ 1965 /* parameters and then let the initiator know that all is ready. If */ 1966 /* socket size defaults are to be used, then the initiator will have */ 1967 /* sent us 0's. If the socket sizes cannot be changed, then we will */ 1968 /* send-back what they are. If that information cannot be determined, */ 1969 /* then we send-back -1's for the sizes. If things go wrong for any */ 1970 /* reason, we will drop back ten yards and punt. */ 1971 1972 /* If anything goes wrong, we want the remote to know about it. It */ 1973 /* would be best if the error that the remote reports to the user is */ 1974 /* the actual error we encountered, rather than some bogus unexpected */ 1975 /* response type message. */ 1976 1977 if (debug > 1) { 1978 fprintf(where,"recv_dg_stream: setting the response type...\n"); 1979 fflush(where); 1980 } 1981 1982 netperf_response.content.response_type = DG_STREAM_RESPONSE; 1983 1984 if (debug > 2) { 1985 fprintf(where,"recv_dg_stream: the response type is set...\n"); 1986 fflush(where); 1987 } 1988 1989 /* We now alter the message_ptr variable to be at the desired */ 1990 /* alignment with the desired offset. */ 1991 1992 if (debug > 1) { 1993 fprintf(where,"recv_dg_stream: requested alignment of %d\n", 1994 dg_stream_request->recv_alignment); 1995 fflush(where); 1996 } 1997 1998 if (recv_width == 0) recv_width = 1; 1999 2000 recv_ring = allocate_buffer_ring(recv_width, 2001 dg_stream_request->message_size, 2002 dg_stream_request->recv_alignment, 2003 dg_stream_request->recv_offset); 2004 2005 if (debug > 1) { 2006 fprintf(where,"recv_dg_stream: receive alignment and offset set...\n"); 2007 fflush(where); 2008 } 2009 2010 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ 2011 /* can put in OUR values !-) At some point, we may want to nail this */ 2012 /* socket to a particular network-level address, but for now, */ 2013 /* INADDR_ANY should be just fine. */ 2014 2015 bzero((char *)&myaddr_un, 2016 sizeof(myaddr_un)); 2017 myaddr_un.sun_family = AF_UNIX; 2018 2019 /* Grab a socket to listen on, and then listen on it. */ 2020 2021 if (debug > 1) { 2022 fprintf(where,"recv_dg_stream: grabbing a socket...\n"); 2023 fflush(where); 2024 } 2025 2026 /* create_unix_socket expects to find some things in the global */ 2027 /* variables, so set the globals based on the values in the request. */ 2028 /* once the socket has been created, we will set the response values */ 2029 /* based on the updated value of those globals. raj 7/94 */ 2030 lsr_size = dg_stream_request->recv_buf_size; 2031 2032 s_data = create_unix_socket(AF_UNIX, 2033 SOCK_DGRAM); 2034 2035 if (s_data == INVALID_SOCKET) { 2036 netperf_response.content.serv_errno = errno; 2037 send_response(); 2038 exit(1); 2039 } 2040 2041 /* Let's get an address assigned to this socket so we can tell the */ 2042 /* initiator how to reach the data socket. There may be a desire to */ 2043 /* nail this socket to a specific IP address in a multi-homed, */ 2044 /* multi-connection situation, but for now, we'll ignore the issue */ 2045 /* and concentrate on single connection testing. */ 2046 2047 strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf.")); 2048 if (bind(s_data, 2049 (struct sockaddr *)&myaddr_un, 2050 sizeof(myaddr_un)) == SOCKET_ERROR) { 2051 netperf_response.content.serv_errno = errno; 2052 send_response(); 2053 exit(1); 2054 } 2055 2056 chmod(myaddr_un.sun_path, 0666); 2057 2058 dg_stream_response->test_length = dg_stream_request->test_length; 2059 2060 /* Now myaddr_un contains the port and the internet address this is */ 2061 /* returned to the sender also implicitly telling the sender that the */ 2062 /* socket buffer sizing has been done. */ 2063 2064 strcpy(dg_stream_response->unix_path,myaddr_un.sun_path); 2065 netperf_response.content.serv_errno = 0; 2066 2067 /* But wait, there's more. If the initiator wanted cpu measurements, */ 2068 /* then we must call the calibrate routine, which will return the max */ 2069 /* rate back to the initiator. If the CPU was not to be measured, or */ 2070 /* something went wrong with the calibration, we will return a -1 to */ 2071 /* the initiator. */ 2072 2073 dg_stream_response->cpu_rate = 0.0; /* assume no cpu */ 2074 if (dg_stream_request->measure_cpu) { 2075 /* We will pass the rate into the calibration routine. If the */ 2076 /* user did not specify one, it will be 0.0, and we will do a */ 2077 /* "real" calibration. Otherwise, all it will really do is */ 2078 /* store it away... */ 2079 dg_stream_response->measure_cpu = 1; 2080 dg_stream_response->cpu_rate = 2081 calibrate_local_cpu(dg_stream_request->cpu_rate); 2082 } 2083 2084 message_size = dg_stream_request->message_size; 2085 test_time = dg_stream_request->test_length; 2086 2087 /* before we send the response back to the initiator, pull some of */ 2088 /* the socket parms from the globals */ 2089 dg_stream_response->send_buf_size = lss_size; 2090 dg_stream_response->recv_buf_size = lsr_size; 2091 2092 send_response(); 2093 2094 /* Now it's time to start receiving data on the connection. We will */ 2095 /* first grab the apropriate counters and then start grabbing. */ 2096 2097 cpu_start(dg_stream_request->measure_cpu); 2098 2099 /* The loop will exit when the timer pops, or if we happen to recv a */ 2100 /* message of less than send_size bytes... */ 2101 2102 times_up = 0; 2103 start_timer(test_time + PAD_TIME); 2104 2105 if (debug) { 2106 fprintf(where,"recv_dg_stream: about to enter inner sanctum.\n"); 2107 fflush(where); 2108 } 2109 2110 while (!times_up) { 2111 if ((len = recv(s_data, 2112 recv_ring->buffer_ptr, 2113 message_size, 2114 0)) != message_size) { 2115 if ((len == SOCKET_ERROR) && (errno != EINTR)) { 2116 netperf_response.content.serv_errno = errno; 2117 send_response(); 2118 exit(1); 2119 } 2120 break; 2121 } 2122 messages_recvd++; 2123 recv_ring = recv_ring->next; 2124 } 2125 2126 if (debug) { 2127 fprintf(where,"recv_dg_stream: got %d messages.\n",messages_recvd); 2128 fflush(where); 2129 } 2130 2131 2132 /* The loop now exits due timer or < send_size bytes received. */ 2133 2134 cpu_stop(dg_stream_request->measure_cpu,&elapsed_time); 2135 2136 if (times_up) { 2137 /* we ended on a timer, subtract the PAD_TIME */ 2138 elapsed_time -= (float)PAD_TIME; 2139 } 2140 else { 2141 stop_timer(); 2142 } 2143 2144 if (debug) { 2145 fprintf(where,"recv_dg_stream: test ended in %f seconds.\n",elapsed_time); 2146 fflush(where); 2147 } 2148 2149 2150 /* We will count the "off" message that got us out of the loop */ 2151 bytes_received = (messages_recvd * message_size) + len; 2152 2153 /* send the results to the sender */ 2154 2155 if (debug) { 2156 fprintf(where, 2157 "recv_dg_stream: got %d bytes\n", 2158 bytes_received); 2159 fflush(where); 2160 } 2161 2162 netperf_response.content.response_type = DG_STREAM_RESULTS; 2163 dg_stream_results->bytes_received = bytes_received; 2164 dg_stream_results->messages_recvd = messages_recvd; 2165 dg_stream_results->elapsed_time = elapsed_time; 2166 if (dg_stream_request->measure_cpu) { 2167 dg_stream_results->cpu_util = calc_cpu_util(elapsed_time); 2168 } 2169 else { 2170 dg_stream_results->cpu_util = -1.0; 2171 } 2172 2173 if (debug > 1) { 2174 fprintf(where, 2175 "recv_dg_stream: test complete, sending results.\n"); 2176 fflush(where); 2177 } 2178 2179 send_response(); 2180 2181 } 2182 2183 void 2185 send_dg_rr(char remote_host[]) 2186 { 2187 2188 char *tput_title = "\ 2189 Local /Remote\n\ 2190 Socket Size Request Resp. Elapsed Trans.\n\ 2191 Send Recv Size Size Time Rate \n\ 2192 bytes Bytes bytes bytes secs. per sec \n\n"; 2193 2194 char *tput_fmt_0 = 2195 "%7.2f\n"; 2196 2197 char *tput_fmt_1_line_1 = "\ 2198 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; 2199 char *tput_fmt_1_line_2 = "\ 2200 %-6d %-6d\n"; 2201 2202 char *cpu_title = "\ 2203 Local /Remote\n\ 2204 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ 2205 Send Recv Size Size Time Rate local remote local remote\n\ 2206 bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; 2207 2208 char *cpu_fmt_0 = 2209 "%6.3f\n"; 2210 2211 char *cpu_fmt_1_line_1 = "\ 2212 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; 2213 2214 char *cpu_fmt_1_line_2 = "\ 2215 %-6d %-6d\n"; 2216 2217 float elapsed_time; 2218 2219 /* we add MAXALIGNMENT and MAXOFFSET to insure that there is enough */ 2220 /* space for a maximally aligned, maximally sized message. At some */ 2221 /* point, we may want to actually make this even larger and cycle */ 2222 /* through the thing one piece at a time.*/ 2223 2224 int len; 2225 char *send_message_ptr; 2226 char *recv_message_ptr; 2227 char *temp_message_ptr; 2228 int nummessages; 2229 SOCKET send_socket; 2230 int trans_remaining; 2231 int bytes_xferd; 2232 2233 int rsp_bytes_recvd; 2234 2235 float local_cpu_utilization; 2236 float local_service_demand; 2237 float remote_cpu_utilization; 2238 float remote_service_demand; 2239 double thruput; 2240 2241 #ifdef WANT_INTERVALS 2242 /* timing stuff */ 2243 #define MAX_KEPT_TIMES 1024 2244 int time_index = 0; 2245 int unused_buckets; 2246 int kept_times[MAX_KEPT_TIMES]; 2247 int sleep_usecs; 2248 unsigned int total_times=0; 2249 struct timezone dummy_zone; 2250 struct timeval send_time; 2251 struct timeval recv_time; 2252 struct timeval sleep_timeval; 2253 #endif 2254 2255 struct sockaddr_un server, myaddr_un; 2256 2257 struct dg_rr_request_struct *dg_rr_request; 2258 struct dg_rr_response_struct *dg_rr_response; 2259 struct dg_rr_results_struct *dg_rr_result; 2260 2261 dg_rr_request = 2262 (struct dg_rr_request_struct *)netperf_request.content.test_specific_data; 2263 dg_rr_response= 2264 (struct dg_rr_response_struct *)netperf_response.content.test_specific_data; 2265 dg_rr_result = 2266 (struct dg_rr_results_struct *)netperf_response.content.test_specific_data; 2267 2268 /* we want to zero out the times, so we can detect unused entries. */ 2269 #ifdef WANT_INTERVALS 2270 time_index = 0; 2271 while (time_index < MAX_KEPT_TIMES) { 2272 kept_times[time_index] = 0; 2273 time_index += 1; 2274 } 2275 time_index = 0; 2276 #endif 2277 2278 /* since we are now disconnected from the code that established the */ 2279 /* control socket, and since we want to be able to use different */ 2280 /* protocols and such, we are passed the name of the remote host and */ 2281 /* must turn that into the test specific addressing information. */ 2282 2283 bzero((char *)&server, 2284 sizeof(server)); 2285 server.sun_family = AF_UNIX; 2286 2287 bzero((char *)&myaddr_un, 2288 sizeof(myaddr_un)); 2289 myaddr_un.sun_family = AF_UNIX; 2290 2291 strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf.")); 2292 2293 if ( print_headers ) { 2294 fprintf(where,"DG REQUEST/RESPONSE TEST\n"); 2295 if (local_cpu_usage || remote_cpu_usage) 2296 fprintf(where,cpu_title,format_units()); 2297 else 2298 fprintf(where,tput_title,format_units()); 2299 } 2300 2301 /* initialize a few counters */ 2302 2303 nummessages = 0; 2304 bytes_xferd = 0; 2305 times_up = 0; 2306 2307 /* set-up the data buffer with the requested alignment and offset */ 2308 temp_message_ptr = (char *)malloc(DATABUFFERLEN); 2309 if (temp_message_ptr == NULL) { 2310 printf("malloc(%d) failed!\n", DATABUFFERLEN); 2311 exit(1); 2312 } 2313 send_message_ptr = (char *)(( (long)temp_message_ptr + 2314 (long) local_send_align - 1) & 2315 ~((long) local_send_align - 1)); 2316 send_message_ptr = send_message_ptr + local_send_offset; 2317 temp_message_ptr = (char *)malloc(DATABUFFERLEN); 2318 if (temp_message_ptr == NULL) { 2319 printf("malloc(%d) failed!\n", DATABUFFERLEN); 2320 exit(1); 2321 } 2322 recv_message_ptr = (char *)(( (long)temp_message_ptr + 2323 (long) local_recv_align - 1) & 2324 ~((long) local_recv_align - 1)); 2325 recv_message_ptr = recv_message_ptr + local_recv_offset; 2326 2327 /*set up the data socket */ 2328 send_socket = create_unix_socket(AF_UNIX, 2329 SOCK_DGRAM); 2330 2331 if (send_socket == INVALID_SOCKET){ 2332 perror("netperf: send_dg_rr: dg rr data socket"); 2333 exit(1); 2334 } 2335 2336 if (debug) { 2337 fprintf(where,"send_dg_rr: send_socket obtained...\n"); 2338 } 2339 2340 2341 /* If the user has requested cpu utilization measurements, we must */ 2342 /* calibrate the cpu(s). We will perform this task within the tests */ 2343 /* themselves. If the user has specified the cpu rate, then */ 2344 /* calibrate_local_cpu will return rather quickly as it will have */ 2345 /* nothing to do. If local_cpu_rate is zero, then we will go through */ 2346 /* all the "normal" calibration stuff and return the rate back. If */ 2347 /* there is no idle counter in the kernel idle loop, the */ 2348 /* local_cpu_rate will be set to -1. */ 2349 2350 if (local_cpu_usage) { 2351 local_cpu_rate = calibrate_local_cpu(local_cpu_rate); 2352 } 2353 2354 /* Tell the remote end to do a listen. The server alters the socket */ 2355 /* paramters on the other side at this point, hence the reason for */ 2356 /* all the values being passed in the setup message. If the user did */ 2357 /* not specify any of the parameters, they will be passed as 0, which */ 2358 /* will indicate to the remote that no changes beyond the system's */ 2359 /* default should be used. Alignment is the exception, it will */ 2360 /* default to 8, which will be no alignment alterations. */ 2361 2362 netperf_request.content.request_type = DO_DG_RR; 2363 dg_rr_request->recv_buf_size = rsr_size; 2364 dg_rr_request->send_buf_size = rss_size; 2365 dg_rr_request->recv_alignment = remote_recv_align; 2366 dg_rr_request->recv_offset = remote_recv_offset; 2367 dg_rr_request->send_alignment = remote_send_align; 2368 dg_rr_request->send_offset = remote_send_offset; 2369 dg_rr_request->request_size = req_size; 2370 dg_rr_request->response_size = rsp_size; 2371 dg_rr_request->measure_cpu = remote_cpu_usage; 2372 dg_rr_request->cpu_rate = remote_cpu_rate; 2373 if (test_time) { 2374 dg_rr_request->test_length = test_time; 2375 } 2376 else { 2377 dg_rr_request->test_length = test_trans * -1; 2378 } 2379 2380 if (debug > 1) { 2381 fprintf(where,"netperf: send_dg_rr: requesting DG request/response test\n"); 2382 } 2383 2384 send_request(); 2385 2386 /* The response from the remote will contain all of the relevant */ 2387 /* socket parameters for this test type. We will put them back into */ 2388 /* the variables here so they can be displayed if desired. The */ 2389 /* remote will have calibrated CPU if necessary, and will have done */ 2390 /* all the needed set-up we will have calibrated the cpu locally */ 2391 /* before sending the request, and will grab the counter value right */ 2392 /* after the connect returns. The remote will grab the counter right */ 2393 /* after the accept call. This saves the hassle of extra messages */ 2394 /* being sent for the DG tests. */ 2395 2396 recv_response(); 2397 2398 if (!netperf_response.content.serv_errno) { 2399 if (debug) 2400 fprintf(where,"remote listen done.\n"); 2401 rsr_size = dg_rr_response->recv_buf_size; 2402 rss_size = dg_rr_response->send_buf_size; 2403 remote_cpu_usage= dg_rr_response->measure_cpu; 2404 remote_cpu_rate = dg_rr_response->cpu_rate; 2405 /* port numbers in proper order */ 2406 strcpy(server.sun_path,dg_rr_response->unix_path); 2407 } 2408 else { 2409 Set_errno(netperf_response.content.serv_errno); 2410 perror("netperf: remote error"); 2411 2412 exit(1); 2413 } 2414 2415 /* Connect up to the remote port on the data socket. This will set */ 2416 /* the default destination address on this socket. we need to bind */ 2417 /* out socket so that the remote gets something from a recvfrom */ 2418 if (bind(send_socket, 2419 (struct sockaddr *)&myaddr_un, 2420 sizeof(myaddr_un)) == SOCKET_ERROR) { 2421 perror("netperf: send_dg_rr"); 2422 unlink(myaddr_un.sun_path); 2423 close(send_socket); 2424 exit(1); 2425 } 2426 2427 if (connect(send_socket, 2428 (struct sockaddr *)&server, 2429 sizeof(server)) == INVALID_SOCKET ) { 2430 perror("netperf: data socket connect failed"); 2431 exit(1); 2432 } 2433 2434 /* Data Socket set-up is finished. If there were problems, either the */ 2435 /* connect would have failed, or the previous response would have */ 2436 /* indicated a problem. I failed to see the value of the extra */ 2437 /* message after the accept on the remote. If it failed, we'll see it */ 2438 /* here. If it didn't, we might as well start pumping data. */ 2439 2440 /* Set-up the test end conditions. For a request/response test, they */ 2441 /* can be either time or transaction based. */ 2442 2443 if (test_time) { 2444 /* The user wanted to end the test after a period of time. */ 2445 times_up = 0; 2446 trans_remaining = 0; 2447 start_timer(test_time); 2448 } 2449 else { 2450 /* The tester wanted to send a number of bytes. */ 2451 trans_remaining = test_bytes; 2452 times_up = 1; 2453 } 2454 2455 /* The cpu_start routine will grab the current time and possibly */ 2456 /* value of the idle counter for later use in measuring cpu */ 2457 /* utilization and/or service demand and thruput. */ 2458 2459 cpu_start(local_cpu_usage); 2460 2461 /* We use an "OR" to control test execution. When the test is */ 2462 /* controlled by time, the byte count check will always return false. */ 2463 /* When the test is controlled by byte count, the time test will */ 2464 /* always return false. When the test is finished, the whole */ 2465 /* expression will go false and we will stop sending data. I think I */ 2466 /* just arbitrarily decrement trans_remaining for the timed test, but */ 2467 /* will not do that just yet... One other question is whether or not */ 2468 /* the send buffer and the receive buffer should be the same buffer. */ 2469 while ((!times_up) || (trans_remaining > 0)) { 2470 /* send the request */ 2471 #ifdef WANT_INTERVALS 2472 gettimeofday(&send_time,&dummy_zone); 2473 #endif 2474 if((len=send(send_socket, 2475 send_message_ptr, 2476 req_size, 2477 0)) != req_size) { 2478 if (errno == EINTR) { 2479 /* We likely hit */ 2480 /* test-end time. */ 2481 break; 2482 } 2483 perror("send_dg_rr: data send error"); 2484 exit(1); 2485 } 2486 2487 /* receive the response. with DG we will get it all, or nothing */ 2488 2489 if((rsp_bytes_recvd=recv(send_socket, 2490 recv_message_ptr, 2491 rsp_size, 2492 0)) != rsp_size) { 2493 if (errno == EINTR) { 2494 /* Again, we have likely hit test-end time */ 2495 break; 2496 } 2497 perror("send_dg_rr: data recv error"); 2498 exit(1); 2499 } 2500 #ifdef WANT_INTERVALS 2501 gettimeofday(&recv_time,&dummy_zone); 2502 2503 /* now we do some arithmatic on the two timevals */ 2504 if (recv_time.tv_usec < send_time.tv_usec) { 2505 /* we wrapped around a second */ 2506 recv_time.tv_usec += 1000000; 2507 recv_time.tv_sec -= 1; 2508 } 2509 2510 /* and store it away */ 2511 kept_times[time_index] = (recv_time.tv_sec - send_time.tv_sec) * 1000000; 2512 kept_times[time_index] += (recv_time.tv_usec - send_time.tv_usec); 2513 2514 /* at this point, we may wish to sleep for some period of */ 2515 /* time, so we see how long that last transaction just took, */ 2516 /* and sleep for the difference of that and the interval. We */ 2517 /* will not sleep if the time would be less than a */ 2518 /* millisecond. */ 2519 if (interval_usecs > 0) { 2520 sleep_usecs = interval_usecs - kept_times[time_index]; 2521 if (sleep_usecs > 1000) { 2522 /* we sleep */ 2523 sleep_timeval.tv_sec = sleep_usecs / 1000000; 2524 sleep_timeval.tv_usec = sleep_usecs % 1000000; 2525 select(0, 2526 0, 2527 0, 2528 0, 2529 &sleep_timeval); 2530 } 2531 } 2532 2533 /* now up the time index */ 2534 time_index = (time_index +1)%MAX_KEPT_TIMES; 2535 #endif 2536 nummessages++; 2537 if (trans_remaining) { 2538 trans_remaining--; 2539 } 2540 2541 if (debug > 3) { 2542 fprintf(where,"Transaction %d completed\n",nummessages); 2543 fflush(where); 2544 } 2545 2546 } 2547 2548 /* The test is over. Flush the buffers to the remote end. We do a */ 2549 /* graceful release to insure that all data has been taken by the */ 2550 /* remote. Of course, since this was a request/response test, there */ 2551 /* should be no data outstanding on the socket ;-) */ 2552 2553 if (shutdown(send_socket,1) == SOCKET_ERROR) { 2554 perror("netperf: cannot shutdown dg stream socket"); 2555 2556 exit(1); 2557 } 2558 2559 /* this call will always give us the elapsed time for the test, and */ 2560 /* will also store-away the necessaries for cpu utilization */ 2561 2562 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ 2563 /* how long did we really run? */ 2564 2565 /* Get the statistics from the remote end. The remote will have */ 2566 /* calculated service demand and all those interesting things. If it */ 2567 /* wasn't supposed to care, it will return obvious values. */ 2568 2569 recv_response(); 2570 if (!netperf_response.content.serv_errno) { 2571 if (debug) 2572 fprintf(where,"remote results obtained\n"); 2573 } 2574 else { 2575 Set_errno(netperf_response.content.serv_errno); 2576 perror("netperf: remote error"); 2577 2578 exit(1); 2579 } 2580 2581 /* We now calculate what our thruput was for the test. In the future, */ 2582 /* we may want to include a calculation of the thruput measured by */ 2583 /* the remote, but it should be the case that for a DG stream test, */ 2584 /* that the two numbers should be *very* close... We calculate */ 2585 /* bytes_sent regardless of the way the test length was controlled. */ 2586 /* If it was time, we needed to, and if it was by bytes, the user may */ 2587 /* have specified a number of bytes that wasn't a multiple of the */ 2588 /* send_size, so we really didn't send what he asked for ;-) We use */ 2589 2590 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); 2591 thruput = calc_thruput(bytes_xferd); 2592 2593 if (local_cpu_usage || remote_cpu_usage) { 2594 /* We must now do a little math for service demand and cpu */ 2595 /* utilization for the system(s) */ 2596 /* Of course, some of the information might be bogus because */ 2597 /* there was no idle counter in the kernel(s). We need to make */ 2598 /* a note of this for the user's benefit...*/ 2599 if (local_cpu_usage) { 2600 if (local_cpu_rate == 0.0) { 2601 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); 2602 fprintf(where,"Local CPU usage numbers based on process information only!\n"); 2603 fflush(where); 2604 } 2605 local_cpu_utilization = calc_cpu_util(0.0); 2606 /* since calc_service demand is doing ms/Kunit we will */ 2607 /* multiply the number of transaction by 1024 to get */ 2608 /* "good" numbers */ 2609 local_service_demand = calc_service_demand((double) nummessages*1024, 2610 0.0, 2611 0.0, 2612 0); 2613 } 2614 else { 2615 local_cpu_utilization = -1.0; 2616 local_service_demand = -1.0; 2617 } 2618 2619 if (remote_cpu_usage) { 2620 if (remote_cpu_rate == 0.0) { 2621 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); 2622 fprintf(where,"Remote CPU usage numbers based on process information only!\n"); 2623 fflush(where); 2624 } 2625 remote_cpu_utilization = dg_rr_result->cpu_util; 2626 /* since calc_service demand is doing ms/Kunit we will */ 2627 /* multiply the number of transaction by 1024 to get */ 2628 /* "good" numbers */ 2629 remote_service_demand = calc_service_demand((double) nummessages*1024, 2630 0.0, 2631 remote_cpu_utilization, 2632 dg_rr_result->num_cpus); 2633 } 2634 else { 2635 remote_cpu_utilization = -1.0; 2636 remote_service_demand = -1.0; 2637 } 2638 2639 /* We are now ready to print all the information. If the user */ 2640 /* has specified zero-level verbosity, we will just print the */ 2641 /* local service demand, or the remote service demand. If the */ 2642 /* user has requested verbosity level 1, he will get the basic */ 2643 /* "streamperf" numbers. If the user has specified a verbosity */ 2644 /* of greater than 1, we will display a veritable plethora of */ 2645 /* background information from outside of this block as it it */ 2646 /* not cpu_measurement specific... */ 2647 2648 switch (verbosity) { 2649 case 0: 2650 if (local_cpu_usage) { 2651 fprintf(where, 2652 cpu_fmt_0, 2653 local_service_demand); 2654 } 2655 else { 2656 fprintf(where, 2657 cpu_fmt_0, 2658 remote_service_demand); 2659 } 2660 break; 2661 case 1: 2662 case 2: 2663 fprintf(where, 2664 cpu_fmt_1_line_1, /* the format string */ 2665 lss_size, /* local sendbuf size */ 2666 lsr_size, 2667 req_size, /* how large were the requests */ 2668 rsp_size, /* guess */ 2669 elapsed_time, /* how long was the test */ 2670 nummessages/elapsed_time, 2671 local_cpu_utilization, /* local cpu */ 2672 remote_cpu_utilization, /* remote cpu */ 2673 local_service_demand, /* local service demand */ 2674 remote_service_demand); /* remote service demand */ 2675 fprintf(where, 2676 cpu_fmt_1_line_2, 2677 rss_size, 2678 rsr_size); 2679 break; 2680 } 2681 } 2682 else { 2683 /* The tester did not wish to measure service demand. */ 2684 switch (verbosity) { 2685 case 0: 2686 fprintf(where, 2687 tput_fmt_0, 2688 nummessages/elapsed_time); 2689 break; 2690 case 1: 2691 case 2: 2692 fprintf(where, 2693 tput_fmt_1_line_1, /* the format string */ 2694 lss_size, 2695 lsr_size, 2696 req_size, /* how large were the requests */ 2697 rsp_size, /* how large were the responses */ 2698 elapsed_time, /* how long did it take */ 2699 nummessages/elapsed_time); 2700 fprintf(where, 2701 tput_fmt_1_line_2, 2702 rss_size, /* remote recvbuf size */ 2703 rsr_size); 2704 2705 break; 2706 } 2707 } 2708 2709 /* it would be a good thing to include information about some of the */ 2710 /* other parameters that may have been set for this test, but at the */ 2711 /* moment, I do not wish to figure-out all the formatting, so I will */ 2712 /* just put this comment here to help remind me that it is something */ 2713 /* that should be done at a later time. */ 2714 2715 if (verbosity > 1) { 2716 /* The user wanted to know it all, so we will give it to him. */ 2717 /* This information will include as much as we can find about */ 2718 /* DG statistics, the alignments of the sends and receives */ 2719 /* and all that sort of rot... */ 2720 2721 #ifdef WANT_INTERVALS 2722 kept_times[MAX_KEPT_TIMES] = 0; 2723 time_index = 0; 2724 while (time_index < MAX_KEPT_TIMES) { 2725 if (kept_times[time_index] > 0) { 2726 total_times += kept_times[time_index]; 2727 } 2728 else 2729 unused_buckets++; 2730 time_index += 1; 2731 } 2732 total_times /= (MAX_KEPT_TIMES-unused_buckets); 2733 fprintf(where, 2734 "Average response time %d usecs\n", 2735 total_times); 2736 #endif 2737 } 2738 unlink(myaddr_un.sun_path); 2739 } 2740 2741 /* this routine implements the receive side (netserver) of a DG_RR */ 2743 /* test. */ 2744 void 2745 recv_dg_rr() 2746 { 2747 2748 struct ring_elt *recv_ring; 2749 struct ring_elt *send_ring; 2750 2751 struct sockaddr_un myaddr_un, 2752 peeraddr_un; 2753 SOCKET s_data; 2754 int addrlen; 2755 int trans_received = 0; 2756 int trans_remaining; 2757 float elapsed_time; 2758 2759 struct dg_rr_request_struct *dg_rr_request; 2760 struct dg_rr_response_struct *dg_rr_response; 2761 struct dg_rr_results_struct *dg_rr_results; 2762 2763 dg_rr_request = 2764 (struct dg_rr_request_struct *)netperf_request.content.test_specific_data; 2765 dg_rr_response = 2766 (struct dg_rr_response_struct *)netperf_response.content.test_specific_data; 2767 dg_rr_results = 2768 (struct dg_rr_results_struct *)netperf_response.content.test_specific_data; 2769 2770 if (debug) { 2771 fprintf(where,"netserver: recv_dg_rr: entered...\n"); 2772 fflush(where); 2773 } 2774 2775 /* We want to set-up the listen socket with all the desired */ 2776 /* parameters and then let the initiator know that all is ready. If */ 2777 /* socket size defaults are to be used, then the initiator will have */ 2778 /* sent us 0's. If the socket sizes cannot be changed, then we will */ 2779 /* send-back what they are. If that information cannot be determined, */ 2780 /* then we send-back -1's for the sizes. If things go wrong for any */ 2781 /* reason, we will drop back ten yards and punt. */ 2782 2783 /* If anything goes wrong, we want the remote to know about it. It */ 2784 /* would be best if the error that the remote reports to the user is */ 2785 /* the actual error we encountered, rather than some bogus unexpected */ 2786 /* response type message. */ 2787 2788 if (debug) { 2789 fprintf(where,"recv_dg_rr: setting the response type...\n"); 2790 fflush(where); 2791 } 2792 2793 netperf_response.content.response_type = DG_RR_RESPONSE; 2794 2795 if (debug) { 2796 fprintf(where,"recv_dg_rr: the response type is set...\n"); 2797 fflush(where); 2798 } 2799 2800 /* We now alter the message_ptr variables to be at the desired */ 2801 /* alignments with the desired offsets. */ 2802 2803 if (debug) { 2804 fprintf(where,"recv_dg_rr: requested recv alignment of %d offset %d\n", 2805 dg_rr_request->recv_alignment, 2806 dg_rr_request->recv_offset); 2807 fprintf(where,"recv_dg_rr: requested send alignment of %d offset %d\n", 2808 dg_rr_request->send_alignment, 2809 dg_rr_request->send_offset); 2810 fflush(where); 2811 } 2812 2813 if (send_width == 0) send_width = 1; 2814 if (recv_width == 0) recv_width = 1; 2815 2816 recv_ring = allocate_buffer_ring(recv_width, 2817 dg_rr_request->request_size, 2818 dg_rr_request->recv_alignment, 2819 dg_rr_request->recv_offset); 2820 2821 send_ring = allocate_buffer_ring(send_width, 2822 dg_rr_request->response_size, 2823 dg_rr_request->send_alignment, 2824 dg_rr_request->send_offset); 2825 2826 if (debug) { 2827 fprintf(where,"recv_dg_rr: receive alignment and offset set...\n"); 2828 fflush(where); 2829 } 2830 2831 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ 2832 /* can put in OUR values !-) At some point, we may want to nail this */ 2833 /* socket to a particular network-level address, but for now, */ 2834 /* INADDR_ANY should be just fine. */ 2835 2836 bzero((char *)&myaddr_un, 2837 sizeof(myaddr_un)); 2838 myaddr_un.sun_family = AF_UNIX; 2839 2840 /* Grab a socket to listen on, and then listen on it. */ 2841 2842 if (debug) { 2843 fprintf(where,"recv_dg_rr: grabbing a socket...\n"); 2844 fflush(where); 2845 } 2846 2847 2848 /* create_unix_socket expects to find some things in the global */ 2849 /* variables, so set the globals based on the values in the request. */ 2850 /* once the socket has been created, we will set the response values */ 2851 /* based on the updated value of those globals. raj 7/94 */ 2852 lss_size_req = dg_rr_request->send_buf_size; 2853 lsr_size_req = dg_rr_request->recv_buf_size; 2854 2855 s_data = create_unix_socket(AF_UNIX, 2856 SOCK_DGRAM); 2857 2858 if (s_data == INVALID_SOCKET) { 2859 netperf_response.content.serv_errno = errno; 2860 send_response(); 2861 2862 exit(1); 2863 } 2864 2865 /* Let's get an address assigned to this socket so we can tell the */ 2866 /* initiator how to reach the data socket. There may be a desire to */ 2867 /* nail this socket to a specific IP address in a multi-homed, */ 2868 /* multi-connection situation, but for now, we'll ignore the issue */ 2869 /* and concentrate on single connection testing. */ 2870 2871 strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf.")); 2872 if (bind(s_data, 2873 (struct sockaddr *)&myaddr_un, 2874 sizeof(myaddr_un)) == SOCKET_ERROR) { 2875 netperf_response.content.serv_errno = errno; 2876 unlink(myaddr_un.sun_path); 2877 close(s_data); 2878 send_response(); 2879 2880 exit(1); 2881 } 2882 2883 /* Now myaddr_un contains the port and the internet address this is */ 2884 /* returned to the sender also implicitly telling the sender that the */ 2885 /* socket buffer sizing has been done. */ 2886 2887 strcpy(dg_rr_response->unix_path,myaddr_un.sun_path); 2888 netperf_response.content.serv_errno = 0; 2889 2890 /* But wait, there's more. If the initiator wanted cpu measurements, */ 2891 /* then we must call the calibrate routine, which will return the max */ 2892 /* rate back to the initiator. If the CPU was not to be measured, or */ 2893 /* something went wrong with the calibration, we will return a 0.0 to */ 2894 /* the initiator. */ 2895 2896 dg_rr_response->cpu_rate = 0.0; /* assume no cpu */ 2897 if (dg_rr_request->measure_cpu) { 2898 dg_rr_response->measure_cpu = 1; 2899 dg_rr_response->cpu_rate = calibrate_local_cpu(dg_rr_request->cpu_rate); 2900 } 2901 2902 /* before we send the response back to the initiator, pull some of */ 2903 /* the socket parms from the globals */ 2904 dg_rr_response->send_buf_size = lss_size; 2905 dg_rr_response->recv_buf_size = lsr_size; 2906 2907 send_response(); 2908 2909 2910 /* Now it's time to start receiving data on the connection. We will */ 2911 /* first grab the apropriate counters and then start grabbing. */ 2912 2913 cpu_start(dg_rr_request->measure_cpu); 2914 2915 if (dg_rr_request->test_length > 0) { 2916 times_up = 0; 2917 trans_remaining = 0; 2918 start_timer(dg_rr_request->test_length + PAD_TIME); 2919 } 2920 else { 2921 times_up = 1; 2922 trans_remaining = dg_rr_request->test_length * -1; 2923 } 2924 2925 addrlen = sizeof(peeraddr_un); 2926 bzero((char *)&peeraddr_un, addrlen); 2927 2928 while ((!times_up) || (trans_remaining > 0)) { 2929 2930 /* receive the request from the other side */ 2931 fprintf(where,"socket %d ptr %p size %d\n", 2932 s_data, 2933 recv_ring->buffer_ptr, 2934 dg_rr_request->request_size); 2935 fflush(where); 2936 if (recvfrom(s_data, 2937 recv_ring->buffer_ptr, 2938 dg_rr_request->request_size, 2939 0, 2940 (struct sockaddr *)&peeraddr_un, 2941 &addrlen) != dg_rr_request->request_size) { 2942 if (errno == EINTR) { 2943 /* we must have hit the end of test time. */ 2944 break; 2945 } 2946 netperf_response.content.serv_errno = errno; 2947 fprintf(where,"error on recvfrom errno %d\n",errno); 2948 fflush(where); 2949 send_response(); 2950 unlink(myaddr_un.sun_path); 2951 exit(1); 2952 } 2953 recv_ring = recv_ring->next; 2954 2955 /* Now, send the response to the remote */ 2956 if (sendto(s_data, 2957 send_ring->buffer_ptr, 2958 dg_rr_request->response_size, 2959 0, 2960 (struct sockaddr *)&peeraddr_un, 2961 addrlen) != dg_rr_request->response_size) { 2962 if (errno == EINTR) { 2963 /* we have hit end of test time. */ 2964 break; 2965 } 2966 netperf_response.content.serv_errno = errno; 2967 fprintf(where,"error on recvfrom errno %d\n",errno); 2968 fflush(where); 2969 unlink(myaddr_un.sun_path); 2970 send_response(); 2971 exit(1); 2972 } 2973 send_ring = send_ring->next; 2974 2975 trans_received++; 2976 if (trans_remaining) { 2977 trans_remaining--; 2978 } 2979 2980 if (debug) { 2981 fprintf(where, 2982 "recv_dg_rr: Transaction %d complete.\n", 2983 trans_received); 2984 fflush(where); 2985 } 2986 2987 } 2988 2989 2990 /* The loop now exits due to timeout or transaction count being */ 2991 /* reached */ 2992 2993 cpu_stop(dg_rr_request->measure_cpu,&elapsed_time); 2994 2995 if (times_up) { 2996 /* we ended the test by time, which was at least 2 seconds */ 2997 /* longer than we wanted to run. so, we want to subtract */ 2998 /* PAD_TIME from the elapsed_time. */ 2999 elapsed_time -= PAD_TIME; 3000 } 3001 /* send the results to the sender */ 3002 3003 if (debug) { 3004 fprintf(where, 3005 "recv_dg_rr: got %d transactions\n", 3006 trans_received); 3007 fflush(where); 3008 } 3009 3010 dg_rr_results->bytes_received = (trans_received * 3011 (dg_rr_request->request_size + 3012 dg_rr_request->response_size)); 3013 dg_rr_results->trans_received = trans_received; 3014 dg_rr_results->elapsed_time = elapsed_time; 3015 if (dg_rr_request->measure_cpu) { 3016 dg_rr_results->cpu_util = calc_cpu_util(elapsed_time); 3017 } 3018 3019 if (debug) { 3020 fprintf(where, 3021 "recv_dg_rr: test complete, sending results.\n"); 3022 fflush(where); 3023 } 3024 3025 send_response(); 3026 unlink(myaddr_un.sun_path); 3027 3028 } 3029 /* this routine implements the receive (netserver) side of a STREAM_RR */ 3030 /* test */ 3031 3032 void 3034 recv_stream_rr() 3035 { 3036 3037 struct ring_elt *send_ring; 3038 struct ring_elt *recv_ring; 3039 3040 struct sockaddr_un myaddr_un, 3041 peeraddr_un; 3042 SOCKET s_listen,s_data; 3043 int addrlen; 3044 char *temp_message_ptr; 3045 int trans_received = 0; 3046 int trans_remaining; 3047 int bytes_sent; 3048 int request_bytes_recvd; 3049 int request_bytes_remaining; 3050 int timed_out = 0; 3051 float elapsed_time; 3052 3053 struct stream_rr_request_struct *stream_rr_request; 3054 struct stream_rr_response_struct *stream_rr_response; 3055 struct stream_rr_results_struct *stream_rr_results; 3056 3057 stream_rr_request = 3058 (struct stream_rr_request_struct *)netperf_request.content.test_specific_data; 3059 stream_rr_response = 3060 (struct stream_rr_response_struct *)netperf_response.content.test_specific_data; 3061 stream_rr_results = 3062 (struct stream_rr_results_struct *)netperf_response.content.test_specific_data; 3063 3064 if (debug) { 3065 fprintf(where,"netserver: recv_stream_rr: entered...\n"); 3066 fflush(where); 3067 } 3068 3069 /* We want to set-up the listen socket with all the desired */ 3070 /* parameters and then let the initiator know that all is ready. If */ 3071 /* socket size defaults are to be used, then the initiator will have */ 3072 /* sent us 0's. If the socket sizes cannot be changed, then we will */ 3073 /* send-back what they are. If that information cannot be determined, */ 3074 /* then we send-back -1's for the sizes. If things go wrong for any */ 3075 /* reason, we will drop back ten yards and punt. */ 3076 3077 /* If anything goes wrong, we want the remote to know about it. It */ 3078 /* would be best if the error that the remote reports to the user is */ 3079 /* the actual error we encountered, rather than some bogus unexpected */ 3080 /* response type message. */ 3081 3082 if (debug) { 3083 fprintf(where,"recv_stream_rr: setting the response type...\n"); 3084 fflush(where); 3085 } 3086 3087 netperf_response.content.response_type = STREAM_RR_RESPONSE; 3088 3089 if (debug) { 3090 fprintf(where,"recv_stream_rr: the response type is set...\n"); 3091 fflush(where); 3092 } 3093 3094 /* allocate the recv and send rings with the requested alignments */ 3095 /* and offsets. raj 7/94 */ 3096 if (debug) { 3097 fprintf(where,"recv_stream_rr: requested recv alignment of %d offset %d\n", 3098 stream_rr_request->recv_alignment, 3099 stream_rr_request->recv_offset); 3100 fprintf(where,"recv_stream_rr: requested send alignment of %d offset %d\n", 3101 stream_rr_request->send_alignment, 3102 stream_rr_request->send_offset); 3103 fflush(where); 3104 } 3105 3106 /* at some point, these need to come to us from the remote system */ 3107 if (send_width == 0) send_width = 1; 3108 if (recv_width == 0) recv_width = 1; 3109 3110 send_ring = allocate_buffer_ring(send_width, 3111 stream_rr_request->response_size, 3112 stream_rr_request->send_alignment, 3113 stream_rr_request->send_offset); 3114 3115 recv_ring = allocate_buffer_ring(recv_width, 3116 stream_rr_request->request_size, 3117 stream_rr_request->recv_alignment, 3118 stream_rr_request->recv_offset); 3119 3120 3121 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ 3122 /* can put in OUR values !-) At some point, we may want to nail this */ 3123 /* socket to a particular network-level address, but for now, */ 3124 /* INADDR_ANY should be just fine. */ 3125 3126 bzero((char *)&myaddr_un, 3127 sizeof(myaddr_un)); 3128 myaddr_un.sun_family = AF_UNIX; 3129 3130 /* Grab a socket to listen on, and then listen on it. */ 3131 3132 if (debug) { 3133 fprintf(where,"recv_stream_rr: grabbing a socket...\n"); 3134 fflush(where); 3135 } 3136 3137 /* create_unix_socket expects to find some things in the global */ 3138 /* variables, so set the globals based on the values in the request. */ 3139 /* once the socket has been created, we will set the response values */ 3140 /* based on the updated value of those globals. raj 7/94 */ 3141 lss_size_req = stream_rr_request->send_buf_size; 3142 lsr_size_req = stream_rr_request->recv_buf_size; 3143 3144 s_listen = create_unix_socket(AF_UNIX, 3145 SOCK_STREAM); 3146 3147 if (s_listen == INVALID_SOCKET) { 3148 netperf_response.content.serv_errno = errno; 3149 send_response(); 3150 3151 exit(1); 3152 } 3153 3154 /* Let's get an address assigned to this socket so we can tell the */ 3155 /* initiator how to reach the data socket. There may be a desire to */ 3156 /* nail this socket to a specific IP address in a multi-homed, */ 3157 /* multi-connection situation, but for now, we'll ignore the issue */ 3158 /* and concentrate on single connection testing. */ 3159 3160 strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf.")); 3161 if (bind(s_listen, 3162 (struct sockaddr *)&myaddr_un, 3163 sizeof(myaddr_un)) == SOCKET_ERROR) { 3164 netperf_response.content.serv_errno = errno; 3165 unlink(myaddr_un.sun_path); 3166 close(s_listen); 3167 send_response(); 3168 3169 exit(1); 3170 } 3171 3172 /* Now, let's set-up the socket to listen for connections */ 3173 if (listen(s_listen, 5) == SOCKET_ERROR) { 3174 netperf_response.content.serv_errno = errno; 3175 close(s_listen); 3176 send_response(); 3177 3178 exit(1); 3179 } 3180 3181 /* Now myaddr_un contains the port and the internet address this is */ 3182 /* returned to the sender also implicitly telling the sender that the */ 3183 /* socket buffer sizing has been done. */ 3184 3185 strcpy(stream_rr_response->unix_path,myaddr_un.sun_path); 3186 netperf_response.content.serv_errno = 0; 3187 3188 /* But wait, there's more. If the initiator wanted cpu measurements, */ 3189 /* then we must call the calibrate routine, which will return the max */ 3190 /* rate back to the initiator. If the CPU was not to be measured, or */ 3191 /* something went wrong with the calibration, we will return a 0.0 to */ 3192 /* the initiator. */ 3193 3194 stream_rr_response->cpu_rate = 0.0; /* assume no cpu */ 3195 if (stream_rr_request->measure_cpu) { 3196 stream_rr_response->measure_cpu = 1; 3197 stream_rr_response->cpu_rate = calibrate_local_cpu(stream_rr_request->cpu_rate); 3198 } 3199 3200 3201 /* before we send the response back to the initiator, pull some of */ 3202 /* the socket parms from the globals */ 3203 stream_rr_response->send_buf_size = lss_size; 3204 stream_rr_response->recv_buf_size = lsr_size; 3205 3206 send_response(); 3207 3208 addrlen = sizeof(peeraddr_un); 3209 3210 if ((s_data = accept(s_listen, 3211 (struct sockaddr *)&peeraddr_un, 3212 &addrlen)) == INVALID_SOCKET) { 3213 /* Let's just punt. The remote will be given some information */ 3214 close(s_listen); 3215 3216 exit(1); 3217 } 3218 3219 if (debug) { 3220 fprintf(where,"recv_stream_rr: accept completes on the data connection.\n"); 3221 fflush(where); 3222 } 3223 3224 /* Now it's time to start receiving data on the connection. We will */ 3225 /* first grab the apropriate counters and then start grabbing. */ 3226 3227 cpu_start(stream_rr_request->measure_cpu); 3228 3229 /* The loop will exit when the sender does a shutdown, which will */ 3230 /* return a length of zero */ 3231 3232 if (stream_rr_request->test_length > 0) { 3233 times_up = 0; 3234 trans_remaining = 0; 3235 start_timer(stream_rr_request->test_length + PAD_TIME); 3236 } 3237 else { 3238 times_up = 1; 3239 trans_remaining = stream_rr_request->test_length * -1; 3240 } 3241 3242 while ((!times_up) || (trans_remaining > 0)) { 3243 temp_message_ptr = recv_ring->buffer_ptr; 3244 request_bytes_remaining = stream_rr_request->request_size; 3245 3246 /* receive the request from the other side */ 3247 if (debug) { 3248 fprintf(where,"about to receive for trans %d\n",trans_received); 3249 fprintf(where,"temp_message_ptr is %p\n",temp_message_ptr); 3250 fflush(where); 3251 } 3252 while(request_bytes_remaining > 0) { 3253 if((request_bytes_recvd=recv(s_data, 3254 temp_message_ptr, 3255 request_bytes_remaining, 3256 0)) == SOCKET_ERROR) { 3257 if (errno == EINTR) { 3258 /* the timer popped */ 3259 timed_out = 1; 3260 break; 3261 } 3262 netperf_response.content.serv_errno = errno; 3263 send_response(); 3264 exit(1); 3265 } 3266 else { 3267 request_bytes_remaining -= request_bytes_recvd; 3268 temp_message_ptr += request_bytes_recvd; 3269 } 3270 if (debug) { 3271 fprintf(where,"just received for trans %d\n",trans_received); 3272 fflush(where); 3273 } 3274 } 3275 3276 recv_ring = recv_ring->next; 3277 3278 if (timed_out) { 3279 /* we hit the end of the test based on time - lets */ 3280 /* bail out of here now... */ 3281 fprintf(where,"yo5\n"); 3282 fflush(where); 3283 break; 3284 } 3285 3286 /* Now, send the response to the remote */ 3287 if (debug) { 3288 fprintf(where,"about to send for trans %d\n",trans_received); 3289 fflush(where); 3290 } 3291 if((bytes_sent=send(s_data, 3292 send_ring->buffer_ptr, 3293 stream_rr_request->response_size, 3294 0)) == SOCKET_ERROR) { 3295 if (errno == EINTR) { 3296 /* the test timer has popped */ 3297 timed_out = 1; 3298 fprintf(where,"yo6\n"); 3299 fflush(where); 3300 break; 3301 } 3302 netperf_response.content.serv_errno = 997; 3303 send_response(); 3304 exit(1); 3305 } 3306 3307 send_ring = send_ring->next; 3308 3309 trans_received++; 3310 if (trans_remaining) { 3311 trans_remaining--; 3312 } 3313 3314 if (debug) { 3315 fprintf(where, 3316 "recv_stream_rr: Transaction %d complete\n", 3317 trans_received); 3318 fflush(where); 3319 } 3320 } 3321 3322 3323 /* The loop now exits due to timeout or transaction count being */ 3324 /* reached */ 3325 3326 cpu_stop(stream_rr_request->measure_cpu,&elapsed_time); 3327 3328 if (timed_out) { 3329 /* we ended the test by time, which was at least 2 seconds */ 3330 /* longer than we wanted to run. so, we want to subtract */ 3331 /* PAD_TIME from the elapsed_time. */ 3332 elapsed_time -= PAD_TIME; 3333 } 3334 /* send the results to the sender */ 3335 3336 if (debug) { 3337 fprintf(where, 3338 "recv_stream_rr: got %d transactions\n", 3339 trans_received); 3340 fflush(where); 3341 } 3342 3343 stream_rr_results->bytes_received = (trans_received * 3344 (stream_rr_request->request_size + 3345 stream_rr_request->response_size)); 3346 stream_rr_results->trans_received = trans_received; 3347 stream_rr_results->elapsed_time = elapsed_time; 3348 if (stream_rr_request->measure_cpu) { 3349 stream_rr_results->cpu_util = calc_cpu_util(elapsed_time); 3350 } 3351 3352 if (debug) { 3353 fprintf(where, 3354 "recv_stream_rr: test complete, sending results.\n"); 3355 fflush(where); 3356 } 3357 3358 send_response(); 3359 unlink(myaddr_un.sun_path); 3360 } 3361 3362 void 3364 print_unix_usage() 3365 { 3366 3367 fwrite(unix_usage, sizeof(char), strlen(unix_usage), stdout); 3368 exit(1); 3369 3370 } 3371 void 3372 scan_unix_args(int argc, char *argv[]) 3373 { 3374 #define UNIX_ARGS "hm:M:p:r:s:S:" 3375 extern char *optarg; /* pointer to option string */ 3376 3377 int c; 3378 3379 char 3380 arg1[BUFSIZ], /* argument holders */ 3381 arg2[BUFSIZ]; 3382 3383 init_test_vars(); 3384 3385 if (no_control) { 3386 fprintf(where, 3387 "The UNIX tests do not know how to run with no control connection\n"); 3388 exit(-1); 3389 } 3390 3391 /* Go through all the command line arguments and break them */ 3392 /* out. For those options that take two parms, specifying only */ 3393 /* the first will set both to that value. Specifying only the */ 3394 /* second will leave the first untouched. To change only the */ 3395 /* first, use the form "first," (see the routine break_args.. */ 3396 3397 while ((c= getopt(argc, argv, UNIX_ARGS)) != EOF) { 3398 switch (c) { 3399 case '?': 3400 case 'h': 3401 print_unix_usage(); 3402 exit(1); 3403 case 'p': 3404 /* set the path prefix (directory) that should be used for the */ 3405 /* pipes. at some point, there should be some error checking. */ 3406 strcpy(path_prefix,optarg); 3407 break; 3408 case 's': 3409 /* set local socket sizes */ 3410 break_args(optarg,arg1,arg2); 3411 if (arg1[0]) 3412 lss_size_req = atoi(arg1); 3413 if (arg2[0]) 3414 lsr_size_req = atoi(arg2); 3415 break; 3416 case 'S': 3417 /* set remote socket sizes */ 3418 break_args(optarg,arg1,arg2); 3419 if (arg1[0]) 3420 rss_size = atoi(arg1); 3421 if (arg2[0]) 3422 rsr_size = atoi(arg2); 3423 break; 3424 case 'r': 3425 /* set the request/response sizes */ 3426 break_args(optarg,arg1,arg2); 3427 if (arg1[0]) 3428 req_size = atoi(arg1); 3429 if (arg2[0]) 3430 rsp_size = atoi(arg2); 3431 break; 3432 case 'm': 3433 /* set the send size */ 3434 send_size = atoi(optarg); 3435 break; 3436 case 'M': 3437 /* set the recv size */ 3438 recv_size = atoi(optarg); 3439 break; 3440 }; 3441 } 3442 } 3443 #endif /* WANT_UNIX */ 3444