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