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