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