1 #ifdef HAVE_CONFIG_H 2 #include <config.h> 3 #endif 4 5 #ifdef WANT_XTI 6 #ifndef lint 7 char nettest_xti_id[]="\ 8 @(#)nettest_xti.c (c) Copyright 1995-2012 Hewlett-Packard Co. Version 2.6.0"; 9 #else 10 #define DIRTY 11 #define WANT_HISTOGRAM 12 #define WANT_INTERVALS 13 #endif /* lint */ 14 15 #ifdef WIN32 16 #error XTI Interface tests are not available under Windows 17 #endif 18 19 /****************************************************************/ 20 /* */ 21 /* nettest_xti.c */ 22 /* */ 23 /* the XTI args parsing routine... */ 24 /* */ 25 /* scan_xti_args() */ 26 /* */ 27 /* the actual test routines... */ 28 /* */ 29 /* send_xti_tcp_stream() perform a tcp stream test */ 30 /* recv_xti_tcp_stream() */ 31 /* send_xti_tcp_rr() perform a tcp request/response */ 32 /* recv_xti_tcp_rr() */ 33 /* send_xti_tcp_conn_rr() an RR test including connect */ 34 /* recv_xti_tcp_conn_rr() */ 35 /* send_xti_udp_stream() perform a udp stream test */ 36 /* recv_xti_udp_stream() */ 37 /* send_xti_udp_rr() perform a udp request/response */ 38 /* recv_xti_udp_rr() */ 39 /* */ 40 /****************************************************************/ 41 42 #ifdef HAVE_CONFIG_H 43 #include <config.h> 44 #endif 45 46 #include <sys/types.h> 47 #include <fcntl.h> 48 #include <sys/ipc.h> 49 #include <sys/socket.h> 50 #include <netinet/in.h> 51 #include <netdb.h> 52 #include <errno.h> 53 #include <signal.h> 54 #include <stdio.h> 55 #include <time.h> 56 #include <malloc.h> 57 /* xti.h should be included *after* in.h because there are name */ 58 /* conflicts!( Silly standards people... raj 2/95 fortuenately, the */ 59 /* confilcts are on IP_TOP and IP_TTL, whcih netperf does not yet use */ 60 #include <xti.h> 61 62 #include "netlib.h" 63 #include "netsh.h" 64 #include "nettest_xti.h" 65 66 #ifdef WANT_HISTOGRAM 67 #ifdef __sgi 68 #include <sys/time.h> 69 #endif /* __sgi */ 70 #include "hist.h" 71 #endif /* WANT_HISTOGRAM */ 72 73 74 76 /* these variables are specific to the XTI sockets tests. declare */ 77 /* them static to make them global only to this file. */ 78 79 static int 80 rss_size, /* remote socket send buffer size */ 81 rsr_size, /* remote socket recv buffer size */ 82 lss_size, /* local socket send buffer size */ 83 lsr_size, /* local socket recv buffer size */ 84 req_size = 1, /* request size */ 85 rsp_size = 1, /* response size */ 86 send_size, /* how big are individual sends */ 87 recv_size; /* how big are individual receives */ 88 89 static int confidence_iteration; 90 static char local_cpu_method; 91 static char remote_cpu_method; 92 93 /* different options for the xti */ 94 95 static int 96 loc_nodelay, /* don't/do use NODELAY locally */ 97 rem_nodelay, /* don't/do use NODELAY remotely */ 98 loc_sndavoid, /* avoid send copies locally */ 99 loc_rcvavoid, /* avoid recv copies locally */ 100 rem_sndavoid, /* avoid send copies remotely */ 101 rem_rcvavoid; /* avoid recv_copies remotely */ 102 103 static struct t_info info_struct; 104 105 #ifdef WANT_HISTOGRAM 106 #ifdef HAVE_GETHRTIME 107 hrtime_t time_one; 108 hrtime_t time_two; 109 #else 110 static struct timeval time_one; 111 static struct timeval time_two; 112 #endif /* HAVE_GETHRTIME */ 113 static HIST time_hist; 114 #endif /* WANT_HISTOGRAM */ 115 116 static char loc_xti_device[32] = "/dev/tcp"; 117 static char rem_xti_device[32] = "/dev/tcp"; 118 119 static int xti_flags = 0; 120 121 char xti_usage[] = "\n\ 122 Usage: netperf [global options] -- [test options] \n\ 123 \n\ 124 TCP/UDP XTI API Test Options:\n\ 125 -D [L][,R] Set XTI_TCP_NODELAY locally and/or remotely (XTI_TCP_*)\n\ 126 -h Display this text\n\ 127 -m bytes Set the send size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\ 128 -M bytes Set the recv size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\ 129 -r bytes Set request size (XTI_TCP_RR, XTI_UDP_RR)\n\ 130 -R bytes Set response size (XTI_TCP_RR, XTI_UDP_RR)\n\ 131 -s send[,recv] Set local socket send/recv buffer sizes\n\ 132 -S send[,recv] Set remote socket send/recv buffer sizes\n\ 133 -X dev[,dev] Set the local/remote XTI device file name\n\ 134 \n\ 135 For those options taking two parms, at least one must be specified;\n\ 136 specifying one value without a comma will set both parms to that\n\ 137 value, specifying a value with a leading comma will set just the second\n\ 138 parm, a value with a trailing comma will set just the first. To set\n\ 139 each parm to unique values, specify both and separate them with a\n\ 140 comma.\n"; 141 142 143 /* This routine is intended to retrieve interesting aspects of tcp */ 145 /* for the data connection. at first, it attempts to retrieve the */ 146 /* maximum segment size. later, it might be modified to retrieve */ 147 /* other information, but it must be information that can be */ 148 /* retrieved quickly as it is called during the timing of the test. */ 149 /* for that reason, a second routine may be created that can be */ 150 /* called outside of the timing loop */ 151 void 152 get_xti_info(socket, info_struct) 153 int socket; 154 struct t_info *info_struct; 155 { 156 157 } 158 159 160 /* This routine will create a data (listen) socket with the apropriate */ 162 /* options set and return it to the caller. this replaces all the */ 163 /* duplicate code in each of the test routines and should help make */ 164 /* things a little easier to understand. since this routine can be */ 165 /* called by either the netperf or netserver programs, all output */ 166 /* should be directed towards "where." family is generally AF_INET, */ 167 /* and type will be either SOCK_STREAM or SOCK_DGRAM */ 168 SOCKET 169 create_xti_endpoint(char *name) 170 { 171 172 SOCKET temp_socket; 173 174 struct t_optmgmt *opt_req; /* we request an option */ 175 struct t_optmgmt *opt_ret; /* it tells us what we got */ 176 177 /* we use this to pass-in BSD-like socket options through t_optmgmt. */ 178 /* it ends up being about as clear as mud. raj 2/95 */ 179 struct sock_option { 180 struct t_opthdr myopthdr; 181 long value; 182 } *sock_option; 183 184 if (debug) { 185 fprintf(where,"create_xti_endpoint: attempting to open %s\n", 186 name); 187 fflush(where); 188 } 189 190 /*set up the data socket */ 191 temp_socket = t_open(name,O_RDWR,NULL); 192 193 if (temp_socket == INVALID_SOCKET){ 194 fprintf(where, 195 "netperf: create_xti_endpoint: t_open %s: errno %d t_errno %d\n", 196 name, 197 errno, 198 t_errno); 199 fflush(where); 200 exit(1); 201 } 202 203 if (debug) { 204 fprintf(where,"create_xti_endpoint: socket %d obtained...\n",temp_socket); 205 fflush(where); 206 } 207 208 /* allocate what we need for option mgmt */ 209 if ((opt_req = (struct t_optmgmt *)t_alloc(temp_socket,T_OPTMGMT,T_ALL)) == 210 NULL) { 211 fprintf(where, 212 "netperf: create_xti_endpoint: t_alloc: opt_req errno %d\n", 213 errno); 214 fflush(where); 215 exit(1); 216 } 217 218 if (debug) { 219 fprintf(where, 220 "create_xti_endpoint: opt_req->opt.buf %x maxlen %d len %d\n", 221 opt_req->opt.buf, 222 opt_req->opt.maxlen, 223 opt_req->opt.len); 224 225 fflush(where); 226 } 227 228 if ((opt_ret = (struct t_optmgmt *) t_alloc(temp_socket,T_OPTMGMT,T_ALL)) == 229 NULL) { 230 fprintf(where, 231 "netperf: create_xti_endpoint: t_alloc: opt_ret errno %d\n", 232 errno); 233 fflush(where); 234 exit(1); 235 } 236 237 if (debug) { 238 fprintf(where, 239 "create_xti_endpoint: opt_ret->opt.buf %x maxlen %d len %d\n", 240 opt_ret->opt.buf, 241 opt_ret->opt.maxlen, 242 opt_ret->opt.len); 243 fflush(where); 244 } 245 246 /* Modify the local socket size. The reason we alter the send buffer */ 247 /* size here rather than when the connection is made is to take care */ 248 /* of decreases in buffer size. Decreasing the window size after */ 249 /* connection establishment is a TCP no-no. Also, by setting the */ 250 /* buffer (window) size before the connection is established, we can */ 251 /* control the TCP MSS (segment size). The MSS is never more that 1/2 */ 252 /* the minimum receive buffer size at each half of the connection. */ 253 /* This is why we are altering the receive buffer size on the sending */ 254 /* size of a unidirectional transfer. If the user has not requested */ 255 /* that the socket buffers be altered, we will try to find-out what */ 256 /* their values are. If we cannot touch the socket buffer in any way, */ 257 /* we will set the values to -1 to indicate that. */ 258 259 #ifdef XTI_SNDBUF 260 if (lss_size > 0) { 261 /* we want to "negotiate" the option */ 262 opt_req->flags = T_NEGOTIATE; 263 } 264 else { 265 /* we want to accept the default, and know what it is. I assume */ 266 /* that when nothing has been changed, that T_CURRENT will return */ 267 /* the same as T_DEFAULT raj 3/95 */ 268 opt_req->flags = T_CURRENT; 269 } 270 271 /* the first part is for the netbuf that holds the option we want */ 272 /* to negotiate or check */ 273 /* the buffer of the netbuf points at the socket options structure */ 274 275 /* we assume that the t_alloc call allocated a buffer that started */ 276 /* on a proper alignment */ 277 sock_option = (struct sock_option *)opt_req->opt.buf; 278 279 /* and next, set the fields in the sock_option structure */ 280 sock_option->myopthdr.level = XTI_GENERIC; 281 sock_option->myopthdr.name = XTI_SNDBUF; 282 sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long); 283 sock_option->value = lss_size; 284 285 opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long); 286 287 /* now, set-up the stuff to return the value in the end */ 288 /* we assume that the t_alloc call allocated a buffer that started */ 289 /* on a proper alignment */ 290 sock_option = (struct sock_option *)opt_ret->opt.buf; 291 292 /* finally, call t_optmgmt. clear as mud. */ 293 if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) { 294 fprintf(where, 295 "netperf: create_xti_endpoint: XTI_SNDBUF option: t_errno %d\n", 296 t_errno); 297 fflush(where); 298 exit(1); 299 } 300 301 if (sock_option->myopthdr.status == T_SUCCESS) { 302 lss_size = sock_option->value; 303 } 304 else { 305 fprintf(where,"create_xti_endpoint: XTI_SNDBUF option status 0x%.4x", 306 sock_option->myopthdr.status); 307 fprintf(where," value %d\n", 308 sock_option->value); 309 fflush(where); 310 lss_size = -1; 311 } 312 313 if (lsr_size > 0) { 314 /* we want to "negotiate" the option */ 315 opt_req->flags = T_NEGOTIATE; 316 } 317 else { 318 /* we want to accept the default, and know what it is. I assume */ 319 /* that when nothing has been changed, that T_CURRENT will return */ 320 /* the same as T_DEFAULT raj 3/95 */ 321 opt_req->flags = T_CURRENT; 322 } 323 324 /* the first part is for the netbuf that holds the option we want */ 325 /* to negotiate or check */ 326 /* the buffer of the netbuf points at the socket options structure */ 327 328 /* we assume that the t_alloc call allocated a buffer that started */ 329 /* on a proper alignment */ 330 sock_option = (struct sock_option *)opt_req->opt.buf; 331 332 /* and next, set the fields in the sock_option structure */ 333 sock_option->myopthdr.level = XTI_GENERIC; 334 sock_option->myopthdr.name = XTI_RCVBUF; 335 sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long); 336 sock_option->value = lsr_size; 337 338 opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long); 339 340 /* now, set-up the stuff to return the value in the end */ 341 /* we assume that the t_alloc call allocated a buffer that started */ 342 /* on a proper alignment */ 343 sock_option = (struct sock_option *)opt_ret->opt.buf; 344 345 /* finally, call t_optmgmt. clear as mud. */ 346 if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) { 347 fprintf(where, 348 "netperf: create_xti_endpoint: XTI_RCVBUF option: t_errno %d\n", 349 t_errno); 350 fflush(where); 351 exit(1); 352 } 353 lsr_size = sock_option->value; 354 355 /* this needs code */ 356 357 if (debug) { 358 fprintf(where,"netperf: create_xti_endpoint: socket sizes determined...\n"); 359 fprintf(where," send: %d recv: %d\n", 360 lss_size,lsr_size); 361 fflush(where); 362 } 363 364 #else /* XTI_SNDBUF */ 365 366 lss_size = -1; 367 lsr_size = -1; 368 369 #endif /* XTI_SNDBUF */ 370 371 /* now, we may wish to enable the copy avoidance features on the */ 372 /* local system. of course, this may not be possible... */ 373 374 if (loc_rcvavoid) { 375 fprintf(where, 376 "netperf: create_xti_endpoint: Could not enable receive copy avoidance"); 377 fflush(where); 378 loc_rcvavoid = 0; 379 } 380 381 if (loc_sndavoid) { 382 fprintf(where, 383 "netperf: create_xti_endpoint: Could not enable send copy avoidance"); 384 fflush(where); 385 loc_sndavoid = 0; 386 } 387 388 /* Now, we will see about setting the TCP_NODELAY flag on the local */ 389 /* socket. We will only do this for those systems that actually */ 390 /* support the option. If it fails, note the fact, but keep going. */ 391 /* If the user tries to enable TCP_NODELAY on a UDP socket, this */ 392 /* will cause an error to be displayed */ 393 394 #ifdef TCP_NODELAY 395 if ((strcmp(test_name,"XTI_TCP_STREAM") == 0) || 396 (strcmp(test_name,"XTI_TCP_RR") == 0) || 397 (strcmp(test_name,"XTI_TCP_CRR") == 0)) { 398 if (loc_nodelay) { 399 /* we want to "negotiate" the option */ 400 opt_req->flags = T_NEGOTIATE; 401 } 402 else { 403 /* we want to accept the default, and know what it is. I assume */ 404 /* that when nothing has been changed, that T_CURRENT will return */ 405 /* the same as T_DEFAULT raj 3/95 */ 406 opt_req->flags = T_CURRENT; 407 } 408 409 /* the first part is for the netbuf that holds the option we want */ 410 /* to negotiate or check the buffer of the netbuf points at the */ 411 /* socket options structure */ 412 413 /* we assume that the t_alloc call allocated a buffer that started */ 414 /* on a proper alignment */ 415 sock_option = (struct sock_option *)opt_req->opt.buf; 416 417 /* and next, set the fields in the sock_option structure */ 418 sock_option->myopthdr.level = INET_TCP; 419 sock_option->myopthdr.name = TCP_NODELAY; 420 sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long); 421 sock_option->value = T_YES; 422 423 opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long); 424 425 /* now, set-up the stuff to return the value in the end */ 426 /* we assume that the t_alloc call allocated a buffer that started */ 427 /* on a proper alignment */ 428 sock_option = (struct sock_option *)opt_ret->opt.buf; 429 430 /* finally, call t_optmgmt. clear as mud. */ 431 if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) { 432 fprintf(where, 433 "create_xti_endpoint: TCP_NODELAY option: errno %d t_errno %d\n", 434 errno, 435 t_errno); 436 fflush(where); 437 exit(1); 438 } 439 loc_nodelay = sock_option->value; 440 } 441 #else /* TCP_NODELAY */ 442 443 loc_nodelay = 0; 444 445 #endif /* TCP_NODELAY */ 446 447 return(temp_socket); 448 449 } 450 451 452 /* This routine implements the TCP unidirectional data transfer test */ 454 /* (a.k.a. stream) for the xti interface. It receives its */ 455 /* parameters via global variables from the shell and writes its */ 456 /* output to the standard output. */ 457 458 459 void 460 send_xti_tcp_stream(char remote_host[]) 461 { 462 463 char *tput_title = "\ 464 Recv Send Send \n\ 465 Socket Socket Message Elapsed \n\ 466 Size Size Size Time Throughput \n\ 467 bytes bytes bytes secs. %s/sec \n\n"; 468 469 char *tput_fmt_0 = 470 "%7.2f\n"; 471 472 char *tput_fmt_1 = 473 "%6d %6d %6d %-6.2f %7.2f \n"; 474 475 char *cpu_title = "\ 476 Recv Send Send Utilization Service Demand\n\ 477 Socket Socket Message Elapsed Send Recv Send Recv\n\ 478 Size Size Size Time Throughput local remote local remote\n\ 479 bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n"; 480 481 char *cpu_fmt_0 = 482 "%6.3f %c\n"; 483 484 char *cpu_fmt_1 = 485 "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; 486 487 char *ksink_fmt = "\n\ 488 Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ 489 Local Remote Local Remote Xfered Per Per\n\ 490 Send Recv Send Recv Send (avg) Recv (avg)\n\ 491 %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; 492 493 char *ksink_fmt2 = "\n\ 494 Maximum\n\ 495 Segment\n\ 496 Size (bytes)\n\ 497 %6d\n"; 498 499 500 float elapsed_time; 501 502 #ifdef WANT_INTERVALS 503 int interval_count; 504 sigset_t signal_set; 505 #endif 506 507 /* what we want is to have a buffer space that is at least one */ 508 /* send-size greater than our send window. this will insure that we */ 509 /* are never trying to re-use a buffer that may still be in the hands */ 510 /* of the transport. This buffer will be malloc'd after we have found */ 511 /* the size of the local senc socket buffer. We will want to deal */ 512 /* with alignment and offset concerns as well. */ 513 514 int *message_int_ptr; 515 516 struct ring_elt *send_ring; 517 518 int len; 519 unsigned int nummessages; 520 SOCKET send_socket; 521 int bytes_remaining; 522 int tcp_mss = -1; /* possibly uninitialized on printf far below */ 523 524 /* with links like fddi, one can send > 32 bits worth of bytes */ 525 /* during a test... ;-) at some point, this should probably become a */ 526 /* 64bit integral type, but those are not entirely common yet */ 527 528 double bytes_sent; 529 530 float local_cpu_utilization; 531 float local_service_demand; 532 float remote_cpu_utilization; 533 float remote_service_demand; 534 535 double thruput; 536 537 /* some addressing information */ 538 struct hostent *hp; 539 struct sockaddr_in server; 540 unsigned int addr; 541 542 struct t_call server_call; 543 544 struct xti_tcp_stream_request_struct *xti_tcp_stream_request; 545 struct xti_tcp_stream_response_struct *xti_tcp_stream_response; 546 struct xti_tcp_stream_results_struct *xti_tcp_stream_result; 547 548 xti_tcp_stream_request = 549 (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data; 550 xti_tcp_stream_response = 551 (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data; 552 xti_tcp_stream_result = 553 (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data; 554 555 #ifdef WANT_HISTOGRAM 556 time_hist = HIST_new(); 557 #endif /* WANT_HISTOGRAM */ 558 /* since we are now disconnected from the code that established the */ 559 /* control socket, and since we want to be able to use different */ 560 /* protocols and such, we are passed the name of the remote host and */ 561 /* must turn that into the test specific addressing information. */ 562 563 bzero((char *)&server, 564 sizeof(server)); 565 566 /* it would seem that while HP-UX will allow an IP address (as a */ 567 /* string) in a call to gethostbyname, other, less enlightened */ 568 /* systems do not. fix from awjacks (at) ca.sandia.gov raj 10/95 */ 569 /* order changed to check for IP address first. raj 7/96 */ 570 571 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) { 572 /* it was not an IP address, try it as a name */ 573 if ((hp = gethostbyname(remote_host)) == NULL) { 574 /* we have no idea what it is */ 575 fprintf(where, 576 "establish_control: could not resolve the destination %s\n", 577 remote_host); 578 fflush(where); 579 exit(1); 580 } 581 else { 582 /* it was a valid remote_host */ 583 bcopy(hp->h_addr, 584 (char *)&server.sin_addr, 585 hp->h_length); 586 server.sin_family = hp->h_addrtype; 587 } 588 } 589 else { 590 /* it was a valid IP address */ 591 server.sin_addr.s_addr = addr; 592 server.sin_family = AF_INET; 593 } 594 595 if ( print_headers ) { 596 /* we want to have some additional, interesting information in */ 597 /* the headers. we know some of it here, but not all, so we will */ 598 /* only print the test title here and will print the results */ 599 /* titles after the test is finished */ 600 fprintf(where,"XTI TCP STREAM TEST"); 601 fprintf(where," to %s", remote_host); 602 if (iteration_max > 1) { 603 fprintf(where, 604 " : +/-%3.1f%% @ %2d%% conf.", 605 interval/0.02, 606 confidence_level); 607 } 608 if (loc_nodelay || rem_nodelay) { 609 fprintf(where," : nodelay"); 610 } 611 if (loc_sndavoid || 612 loc_rcvavoid || 613 rem_sndavoid || 614 rem_rcvavoid) { 615 fprintf(where," : copy avoidance"); 616 } 617 #ifdef WANT_HISTOGRAM 618 fprintf(where," : histogram"); 619 #endif /* WANT_HISTOGRAM */ 620 #ifdef WANT_INTERVALS 621 fprintf(where," : interval"); 622 #endif /* WANT_INTERVALS */ 623 #ifdef DIRTY 624 fprintf(where," : dirty data"); 625 #endif /* DIRTY */ 626 fprintf(where,"\n"); 627 } 628 629 send_ring = NULL; 630 confidence_iteration = 1; 631 init_stat(); 632 633 /* we have a great-big while loop which controls the number of times */ 634 /* we run a particular test. this is for the calculation of a */ 635 /* confidence interval (I really should have stayed awake during */ 636 /* probstats :). If the user did not request confidence measurement */ 637 /* (no confidence is the default) then we will only go though the */ 638 /* loop once. the confidence stuff originates from the folks at IBM */ 639 640 while (((confidence < 0) && (confidence_iteration < iteration_max)) || 641 (confidence_iteration <= iteration_min)) { 642 643 /* initialize a few counters. we have to remember that we might be */ 644 /* going through the loop more than once. */ 645 646 nummessages = 0; 647 bytes_sent = 0.0; 648 times_up = 0; 649 650 /*set up the data socket */ 651 send_socket = create_xti_endpoint(loc_xti_device); 652 653 if (send_socket == INVALID_SOCKET) { 654 perror("netperf: send_xti_tcp_stream: tcp stream data socket"); 655 exit(1); 656 } 657 658 if (debug) { 659 fprintf(where,"send_xti_tcp_stream: send_socket obtained...\n"); 660 } 661 662 /* it would seem that with XTI, there is no implicit bind on a */ 663 /* connect, so we have to make a call to t_bind. this is not */ 664 /* terribly convenient, but I suppose that "standard is better */ 665 /* than better" :) raj 2/95 */ 666 667 if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) { 668 t_error("send_xti_tcp_stream: t_bind"); 669 exit(1); 670 } 671 672 /* at this point, we have either retrieved the socket buffer sizes, */ 673 /* or have tried to set them, so now, we may want to set the send */ 674 /* size based on that (because the user either did not use a -m */ 675 /* option, or used one with an argument of 0). If the socket buffer */ 676 /* size is not available, we will set the send size to 4KB - no */ 677 /* particular reason, just arbitrary... */ 678 if (send_size == 0) { 679 if (lss_size > 0) { 680 send_size = lss_size; 681 } 682 else { 683 send_size = 4096; 684 } 685 } 686 687 /* set-up the data buffer ring with the requested alignment and offset. */ 688 /* note also that we have allocated a quantity */ 689 /* of memory that is at least one send-size greater than our socket */ 690 /* buffer size. We want to be sure that there are at least two */ 691 /* buffers allocated - this can be a bit of a problem when the */ 692 /* send_size is bigger than the socket size, so we must check... the */ 693 /* user may have wanted to explicitly set the "width" of our send */ 694 /* buffers, we should respect that wish... */ 695 696 if (send_width == 0) { 697 send_width = (lss_size/send_size) + 1; 698 if (send_width == 1) send_width++; 699 } 700 701 if (send_ring == NULL) { 702 /* only allocate the send ring once. this is a networking test, */ 703 /* not a memory allocation test. this way, we do not need a */ 704 /* deallocate_buffer_ring() routine, and I don't feel like */ 705 /* writing one anyway :) raj 11/94 */ 706 send_ring = allocate_buffer_ring(send_width, 707 send_size, 708 local_send_align, 709 local_send_offset); 710 } 711 712 /* If the user has requested cpu utilization measurements, we must */ 713 /* calibrate the cpu(s). We will perform this task within the tests */ 714 /* themselves. If the user has specified the cpu rate, then */ 715 /* calibrate_local_cpu will return rather quickly as it will have */ 716 /* nothing to do. If local_cpu_rate is zero, then we will go through */ 717 /* all the "normal" calibration stuff and return the rate back. */ 718 719 if (local_cpu_usage) { 720 local_cpu_rate = calibrate_local_cpu(local_cpu_rate); 721 } 722 723 /* Tell the remote end to do a listen. The server alters the socket */ 724 /* paramters on the other side at this point, hence the reason for */ 725 /* all the values being passed in the setup message. If the user did */ 726 /* not specify any of the parameters, they will be passed as 0, which */ 727 /* will indicate to the remote that no changes beyond the system's */ 728 /* default should be used. Alignment is the exception, it will */ 729 /* default to 1, which will be no alignment alterations. */ 730 731 netperf_request.content.request_type = DO_XTI_TCP_STREAM; 732 xti_tcp_stream_request->send_buf_size = rss_size; 733 xti_tcp_stream_request->recv_buf_size = rsr_size; 734 xti_tcp_stream_request->receive_size = recv_size; 735 xti_tcp_stream_request->no_delay = rem_nodelay; 736 xti_tcp_stream_request->recv_alignment = remote_recv_align; 737 xti_tcp_stream_request->recv_offset = remote_recv_offset; 738 xti_tcp_stream_request->measure_cpu = remote_cpu_usage; 739 xti_tcp_stream_request->cpu_rate = remote_cpu_rate; 740 if (test_time) { 741 xti_tcp_stream_request->test_length = test_time; 742 } 743 else { 744 xti_tcp_stream_request->test_length = test_bytes; 745 } 746 xti_tcp_stream_request->so_rcvavoid = rem_rcvavoid; 747 xti_tcp_stream_request->so_sndavoid = rem_sndavoid; 748 749 strcpy(xti_tcp_stream_request->xti_device, rem_xti_device); 750 751 #ifdef __alpha 752 753 /* ok - even on a DEC box, strings are strings. I didn't really want */ 754 /* to ntohl the words of a string. since I don't want to teach the */ 755 /* send_ and recv_ _request and _response routines about the types, */ 756 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ 757 /* solution would be to use XDR, but I am still leary of being able */ 758 /* to find XDR libs on all platforms I want running netperf. raj */ 759 { 760 int *charword; 761 int *initword; 762 int *lastword; 763 764 initword = (int *) xti_tcp_stream_request->xti_device; 765 lastword = initword + ((strlen(rem_xti_device) + 3) / 4); 766 767 for (charword = initword; 768 charword < lastword; 769 charword++) { 770 771 *charword = ntohl(*charword); 772 } 773 } 774 #endif /* __alpha */ 775 776 #ifdef DIRTY 777 xti_tcp_stream_request->dirty_count = rem_dirty_count; 778 xti_tcp_stream_request->clean_count = rem_clean_count; 779 #endif /* DIRTY */ 780 781 782 if (debug > 1) { 783 fprintf(where, 784 "netperf: send_xti_tcp_stream: requesting TCP stream test\n"); 785 } 786 787 send_request(); 788 789 /* The response from the remote will contain all of the relevant */ 790 /* socket parameters for this test type. We will put them back into */ 791 /* the variables here so they can be displayed if desired. The */ 792 /* remote will have calibrated CPU if necessary, and will have done */ 793 /* all the needed set-up we will have calibrated the cpu locally */ 794 /* before sending the request, and will grab the counter value right*/ 795 /* after the connect returns. The remote will grab the counter right*/ 796 /* after the accept call. This saves the hassle of extra messages */ 797 /* being sent for the TCP tests. */ 798 799 recv_response(); 800 801 if (!netperf_response.content.serv_errno) { 802 if (debug) 803 fprintf(where,"remote listen done.\n"); 804 rsr_size = xti_tcp_stream_response->recv_buf_size; 805 rss_size = xti_tcp_stream_response->send_buf_size; 806 rem_nodelay = xti_tcp_stream_response->no_delay; 807 remote_cpu_usage = xti_tcp_stream_response->measure_cpu; 808 remote_cpu_rate = xti_tcp_stream_response->cpu_rate; 809 810 /* we have to make sure that the server port number is in */ 811 /* network order */ 812 server.sin_port = (short)xti_tcp_stream_response->data_port_number; 813 server.sin_port = htons(server.sin_port); 814 rem_rcvavoid = xti_tcp_stream_response->so_rcvavoid; 815 rem_sndavoid = xti_tcp_stream_response->so_sndavoid; 816 } 817 else { 818 Set_errno(netperf_response.content.serv_errno); 819 perror("netperf: remote error"); 820 821 exit(1); 822 } 823 824 /*Connect up to the remote port on the data socket */ 825 memset (&server_call, 0, sizeof(server_call)); 826 server_call.addr.maxlen = sizeof(struct sockaddr_in); 827 server_call.addr.len = sizeof(struct sockaddr_in); 828 server_call.addr.buf = (char *)&server; 829 830 if (t_connect(send_socket, 831 &server_call, 832 NULL) == INVALID_SOCKET){ 833 t_error("netperf: send_xti_tcp_stream: data socket connect failed"); 834 printf(" port: %d\n",ntohs(server.sin_port)); 835 exit(1); 836 } 837 838 /* Data Socket set-up is finished. If there were problems, either */ 839 /* the connect would have failed, or the previous response would */ 840 /* have indicated a problem. I failed to see the value of the */ 841 /* extra message after the accept on the remote. If it failed, */ 842 /* we'll see it here. If it didn't, we might as well start pumping */ 843 /* data. */ 844 845 /* Set-up the test end conditions. For a stream test, they can be */ 846 /* either time or byte-count based. */ 847 848 if (test_time) { 849 /* The user wanted to end the test after a period of time. */ 850 times_up = 0; 851 bytes_remaining = 0; 852 /* in previous revisions, we had the same code repeated throught */ 853 /* all the test suites. this was unnecessary, and meant more */ 854 /* work for me when I wanted to switch to POSIX signals, so I */ 855 /* have abstracted this out into a routine in netlib.c. if you */ 856 /* are experiencing signal problems, you might want to look */ 857 /* there. raj 11/94 */ 858 start_timer(test_time); 859 } 860 else { 861 /* The tester wanted to send a number of bytes. */ 862 bytes_remaining = test_bytes; 863 times_up = 1; 864 } 865 866 /* The cpu_start routine will grab the current time and possibly */ 867 /* value of the idle counter for later use in measuring cpu */ 868 /* utilization and/or service demand and thruput. */ 869 870 cpu_start(local_cpu_usage); 871 872 #ifdef WANT_INTERVALS 873 if ((interval_burst) || (demo_mode)) { 874 /* zero means that we never pause, so we never should need the */ 875 /* interval timer, unless we are in demo_mode */ 876 start_itimer(interval_wate); 877 } 878 interval_count = interval_burst; 879 /* get the signal set for the call to sigsuspend */ 880 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { 881 fprintf(where, 882 "send_xti_tcp_stream: unable to get sigmask errno %d\n", 883 errno); 884 fflush(where); 885 exit(1); 886 } 887 #endif /* WANT_INTERVALS */ 888 889 /* before we start, initialize a few variables */ 890 891 /* We use an "OR" to control test execution. When the test is */ 892 /* controlled by time, the byte count check will always return false. */ 893 /* When the test is controlled by byte count, the time test will */ 894 /* always return false. When the test is finished, the whole */ 895 /* expression will go false and we will stop sending data. */ 896 897 while ((!times_up) || (bytes_remaining > 0)) { 898 899 #ifdef DIRTY 900 /* we want to dirty some number of consecutive integers in the buffer */ 901 /* we are about to send. we may also want to bring some number of */ 902 /* them cleanly into the cache. The clean ones will follow any dirty */ 903 /* ones into the cache. at some point, we might want to replace */ 904 /* the rand() call with something from a table to reduce our call */ 905 /* overhead during the test, but it is not a high priority item. */ 906 access_buffer(send_ring->buffer_ptr, 907 send_size, 908 loc_dirty_count, 909 loc_clean_count); 910 #endif /* DIRTY */ 911 912 #ifdef WANT_HISTOGRAM 913 /* timestamp just before we go into send and then again just after */ 914 /* we come out raj 8/94 */ 915 HIST_timestamp(&time_one); 916 #endif /* WANT_HISTOGRAM */ 917 918 if((len=t_snd(send_socket, 919 send_ring->buffer_ptr, 920 send_size, 921 0)) != send_size) { 922 if ((len >=0) || (errno == EINTR)) { 923 /* the test was interrupted, must be the end of test */ 924 break; 925 } 926 fprintf(where, 927 "send_xti_tcp_stream: t_snd: errno %d t_errno %d t_look 0x%.4x\n", 928 errno, 929 t_errno, 930 t_look(send_socket)); 931 fflush(where); 932 exit(1); 933 } 934 935 #ifdef WANT_HISTOGRAM 936 /* timestamp the exit from the send call and update the histogram */ 937 HIST_timestamp(&time_two); 938 HIST_add(time_hist,delta_micro(&time_one,&time_two)); 939 #endif /* WANT_HISTOGRAM */ 940 941 #ifdef WANT_INTERVALS 942 if (demo_mode) { 943 units_this_tick += send_size; 944 } 945 /* in this case, the interval count is the count-down couter */ 946 /* to decide to sleep for a little bit */ 947 if ((interval_burst) && (--interval_count == 0)) { 948 /* call sigsuspend and wait for the interval timer to get us */ 949 /* out */ 950 if (debug) { 951 fprintf(where,"about to suspend\n"); 952 fflush(where); 953 } 954 if (sigsuspend(&signal_set) == EFAULT) { 955 fprintf(where, 956 "send_xti_tcp_stream: fault with signal set!\n"); 957 fflush(where); 958 exit(1); 959 } 960 interval_count = interval_burst; 961 } 962 #endif /* WANT_INTERVALS */ 963 964 /* now we want to move our pointer to the next position in the */ 965 /* data buffer...we may also want to wrap back to the "beginning" */ 966 /* of the bufferspace, so we will mod the number of messages sent */ 967 /* by the send width, and use that to calculate the offset to add */ 968 /* to the base pointer. */ 969 nummessages++; 970 send_ring = send_ring->next; 971 if (bytes_remaining) { 972 bytes_remaining -= send_size; 973 } 974 } 975 976 /* The test is over. Flush the buffers to the remote end. We do a */ 977 /* graceful release to insure that all data has been taken by the */ 978 /* remote. */ 979 980 /* but first, if the verbosity is greater than 1, find-out what */ 981 /* the TCP maximum segment_size was (if possible) */ 982 if (verbosity > 1) { 983 tcp_mss = -1; 984 get_xti_info(send_socket,info_struct); 985 } 986 987 if (t_sndrel(send_socket) == -1) { 988 t_error("netperf: cannot shutdown tcp stream socket"); 989 exit(1); 990 } 991 992 /* hang a t_rcvrel() off the socket to block until the remote has */ 993 /* brought all the data up into the application. it will do a */ 994 /* t_sedrel to cause a FIN to be sent our way. We will assume that */ 995 /* any exit from the t_rcvrel() call is good... raj 2/95 */ 996 997 if (debug > 1) { 998 fprintf(where,"about to hang a receive for graceful release.\n"); 999 fflush(where); 1000 } 1001 1002 t_rcvrel(send_socket); 1003 1004 /* this call will always give us the elapsed time for the test, and */ 1005 /* will also store-away the necessaries for cpu utilization */ 1006 1007 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ 1008 /* measured and how */ 1009 /* long did we really */ 1010 /* run? */ 1011 1012 /* Get the statistics from the remote end. The remote will have */ 1013 /* calculated service demand and all those interesting things. If it */ 1014 /* wasn't supposed to care, it will return obvious values. */ 1015 1016 recv_response(); 1017 if (!netperf_response.content.serv_errno) { 1018 if (debug) 1019 fprintf(where,"remote results obtained\n"); 1020 } 1021 else { 1022 Set_errno(netperf_response.content.serv_errno); 1023 perror("netperf: remote error"); 1024 1025 exit(1); 1026 } 1027 1028 /* We now calculate what our thruput was for the test. In the future, */ 1029 /* we may want to include a calculation of the thruput measured by */ 1030 /* the remote, but it should be the case that for a TCP stream test, */ 1031 /* that the two numbers should be *very* close... We calculate */ 1032 /* bytes_sent regardless of the way the test length was controlled. */ 1033 /* If it was time, we needed to, and if it was by bytes, the user may */ 1034 /* have specified a number of bytes that wasn't a multiple of the */ 1035 /* send_size, so we really didn't send what he asked for ;-) */ 1036 1037 bytes_sent = xti_tcp_stream_result->bytes_received; 1038 1039 thruput = calc_thruput(bytes_sent); 1040 1041 if (local_cpu_usage || remote_cpu_usage) { 1042 /* We must now do a little math for service demand and cpu */ 1043 /* utilization for the system(s) */ 1044 /* Of course, some of the information might be bogus because */ 1045 /* there was no idle counter in the kernel(s). We need to make */ 1046 /* a note of this for the user's benefit...*/ 1047 if (local_cpu_usage) { 1048 1049 local_cpu_utilization = calc_cpu_util(0.0); 1050 local_service_demand = calc_service_demand(bytes_sent, 1051 0.0, 1052 0.0, 1053 0); 1054 } 1055 else { 1056 local_cpu_utilization = -1.0; 1057 local_service_demand = -1.0; 1058 } 1059 1060 if (remote_cpu_usage) { 1061 1062 remote_cpu_utilization = xti_tcp_stream_result->cpu_util; 1063 remote_service_demand = calc_service_demand(bytes_sent, 1064 0.0, 1065 remote_cpu_utilization, 1066 xti_tcp_stream_result->num_cpus); 1067 } 1068 else { 1069 remote_cpu_utilization = -1.0; 1070 remote_service_demand = -1.0; 1071 } 1072 } 1073 else { 1074 /* we were not measuring cpu, for the confidence stuff, we */ 1075 /* should make it -1.0 */ 1076 local_cpu_utilization = -1.0; 1077 local_service_demand = -1.0; 1078 remote_cpu_utilization = -1.0; 1079 remote_service_demand = -1.0; 1080 } 1081 1082 /* at this point, we want to calculate the confidence information. */ 1083 /* if debugging is on, calculate_confidence will print-out the */ 1084 /* parameters we pass it */ 1085 1086 calculate_confidence(confidence_iteration, 1087 elapsed_time, 1088 thruput, 1089 local_cpu_utilization, 1090 remote_cpu_utilization, 1091 local_service_demand, 1092 remote_service_demand); 1093 1094 1095 confidence_iteration++; 1096 } 1097 1098 /* at this point, we have finished making all the runs that we */ 1099 /* will be making. so, we should extract what the calcuated values */ 1100 /* are for all the confidence stuff. we could make the values */ 1101 /* global, but that seemed a little messy, and it did not seem worth */ 1102 /* all the mucking with header files. so, we create a routine much */ 1103 /* like calcualte_confidence, which just returns the mean values. */ 1104 /* raj 11/94 */ 1105 1106 retrieve_confident_values(&elapsed_time, 1107 &thruput, 1108 &local_cpu_utilization, 1109 &remote_cpu_utilization, 1110 &local_service_demand, 1111 &remote_service_demand); 1112 1113 /* We are now ready to print all the information. If the user */ 1114 /* has specified zero-level verbosity, we will just print the */ 1115 /* local service demand, or the remote service demand. If the */ 1116 /* user has requested verbosity level 1, he will get the basic */ 1117 /* "streamperf" numbers. If the user has specified a verbosity */ 1118 /* of greater than 1, we will display a veritable plethora of */ 1119 /* background information from outside of this block as it it */ 1120 /* not cpu_measurement specific... */ 1121 1122 if (confidence < 0) { 1123 /* we did not hit confidence, but were we asked to look for it? */ 1124 if (iteration_max > 1) { 1125 display_confidence(); 1126 } 1127 } 1128 1129 if (local_cpu_usage || remote_cpu_usage) { 1130 local_cpu_method = format_cpu_method(cpu_method); 1131 remote_cpu_method = format_cpu_method(xti_tcp_stream_result->cpu_method); 1132 1133 switch (verbosity) { 1134 case 0: 1135 if (local_cpu_usage) { 1136 fprintf(where, 1137 cpu_fmt_0, 1138 local_service_demand, 1139 local_cpu_method); 1140 } 1141 else { 1142 fprintf(where, 1143 cpu_fmt_0, 1144 remote_service_demand, 1145 remote_cpu_method); 1146 } 1147 break; 1148 case 1: 1149 case 2: 1150 if (print_headers) { 1151 fprintf(where, 1152 cpu_title, 1153 format_units(), 1154 local_cpu_method, 1155 remote_cpu_method); 1156 } 1157 1158 fprintf(where, 1159 cpu_fmt_1, /* the format string */ 1160 rsr_size, /* remote recvbuf size */ 1161 lss_size, /* local sendbuf size */ 1162 send_size, /* how large were the sends */ 1163 elapsed_time, /* how long was the test */ 1164 thruput, /* what was the xfer rate */ 1165 local_cpu_utilization, /* local cpu */ 1166 remote_cpu_utilization, /* remote cpu */ 1167 local_service_demand, /* local service demand */ 1168 remote_service_demand); /* remote service demand */ 1169 break; 1170 } 1171 } 1172 else { 1173 /* The tester did not wish to measure service demand. */ 1174 1175 switch (verbosity) { 1176 case 0: 1177 fprintf(where, 1178 tput_fmt_0, 1179 thruput); 1180 break; 1181 case 1: 1182 case 2: 1183 if (print_headers) { 1184 fprintf(where,tput_title,format_units()); 1185 } 1186 fprintf(where, 1187 tput_fmt_1, /* the format string */ 1188 rsr_size, /* remote recvbuf size */ 1189 lss_size, /* local sendbuf size */ 1190 send_size, /* how large were the sends */ 1191 elapsed_time, /* how long did it take */ 1192 thruput);/* how fast did it go */ 1193 break; 1194 } 1195 } 1196 1197 /* it would be a good thing to include information about some of the */ 1198 /* other parameters that may have been set for this test, but at the */ 1199 /* moment, I do not wish to figure-out all the formatting, so I will */ 1200 /* just put this comment here to help remind me that it is something */ 1201 /* that should be done at a later time. */ 1202 1203 if (verbosity > 1) { 1204 /* The user wanted to know it all, so we will give it to him. */ 1205 /* This information will include as much as we can find about */ 1206 /* TCP statistics, the alignments of the sends and receives */ 1207 /* and all that sort of rot... */ 1208 1209 /* this stuff needs to be worked-out in the presence of confidence */ 1210 /* intervals and multiple iterations of the test... raj 11/94 */ 1211 1212 fprintf(where, 1213 ksink_fmt, 1214 "Bytes", 1215 "Bytes", 1216 "Bytes", 1217 local_send_align, 1218 remote_recv_align, 1219 local_send_offset, 1220 remote_recv_offset, 1221 bytes_sent, 1222 bytes_sent / (double)nummessages, 1223 nummessages, 1224 bytes_sent / (double)xti_tcp_stream_result->recv_calls, 1225 xti_tcp_stream_result->recv_calls); 1226 fprintf(where, 1227 ksink_fmt2, 1228 tcp_mss); 1229 fflush(where); 1230 #ifdef WANT_HISTOGRAM 1231 fprintf(where,"\n\nHistogram of time spent in send() call.\n"); 1232 fflush(where); 1233 HIST_report(time_hist); 1234 #endif /* WANT_HISTOGRAM */ 1235 } 1236 1237 } 1238 1239 1241 /* This is the server-side routine for the tcp stream test. It is */ 1242 /* implemented as one routine. I could break things-out somewhat, but */ 1243 /* didn't feel it was necessary. */ 1244 1245 void 1246 recv_xti_tcp_stream() 1247 { 1248 1249 struct sockaddr_in myaddr_in, peeraddr_in; 1250 struct t_bind bind_req, bind_resp; 1251 struct t_call call_req; 1252 1253 SOCKET s_listen,s_data; 1254 int addrlen; 1255 int len; 1256 unsigned int receive_calls; 1257 float elapsed_time; 1258 double bytes_received; 1259 1260 struct ring_elt *recv_ring; 1261 1262 int *message_int_ptr; 1263 int i; 1264 1265 struct xti_tcp_stream_request_struct *xti_tcp_stream_request; 1266 struct xti_tcp_stream_response_struct *xti_tcp_stream_response; 1267 struct xti_tcp_stream_results_struct *xti_tcp_stream_results; 1268 1269 xti_tcp_stream_request = 1270 (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data; 1271 xti_tcp_stream_response = 1272 (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data; 1273 xti_tcp_stream_results = 1274 (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data; 1275 1276 if (debug) { 1277 fprintf(where,"netserver: recv_xti_tcp_stream: entered...\n"); 1278 fflush(where); 1279 } 1280 1281 /* We want to set-up the listen socket with all the desired */ 1282 /* parameters and then let the initiator know that all is ready. If */ 1283 /* socket size defaults are to be used, then the initiator will have */ 1284 /* sent us 0's. If the socket sizes cannot be changed, then we will */ 1285 /* send-back what they are. If that information cannot be determined, */ 1286 /* then we send-back -1's for the sizes. If things go wrong for any */ 1287 /* reason, we will drop back ten yards and punt. */ 1288 1289 /* If anything goes wrong, we want the remote to know about it. It */ 1290 /* would be best if the error that the remote reports to the user is */ 1291 /* the actual error we encountered, rather than some bogus unexpected */ 1292 /* response type message. */ 1293 1294 if (debug) { 1295 fprintf(where,"recv_xti_tcp_stream: setting the response type...\n"); 1296 fflush(where); 1297 } 1298 1299 netperf_response.content.response_type = XTI_TCP_STREAM_RESPONSE; 1300 1301 if (debug) { 1302 fprintf(where,"recv_xti_tcp_stream: the response type is set...\n"); 1303 fflush(where); 1304 } 1305 1306 /* We now alter the message_ptr variable to be at the desired */ 1307 /* alignment with the desired offset. */ 1308 1309 if (debug) { 1310 fprintf(where,"recv_xti_tcp_stream: requested alignment of %d\n", 1311 xti_tcp_stream_request->recv_alignment); 1312 fflush(where); 1313 } 1314 1315 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ 1316 /* can put in OUR values !-) At some point, we may want to nail this */ 1317 /* socket to a particular network-level address, but for now, */ 1318 /* INADDR_ANY should be just fine. */ 1319 1320 bzero((char *)&myaddr_in, 1321 sizeof(myaddr_in)); 1322 myaddr_in.sin_family = AF_INET; 1323 myaddr_in.sin_addr.s_addr = INADDR_ANY; 1324 myaddr_in.sin_port = 0; 1325 1326 /* Grab a socket to listen on, and then listen on it. */ 1327 1328 if (debug) { 1329 fprintf(where,"recv_xti_tcp_stream: grabbing a socket...\n"); 1330 fflush(where); 1331 } 1332 1333 /* create_xti_endpoint expects to find some things in the global */ 1334 /* variables, so set the globals based on the values in the request. */ 1335 /* once the socket has been created, we will set the response values */ 1336 /* based on the updated value of those globals. raj 7/94 */ 1337 lss_size = xti_tcp_stream_request->send_buf_size; 1338 lsr_size = xti_tcp_stream_request->recv_buf_size; 1339 loc_nodelay = xti_tcp_stream_request->no_delay; 1340 loc_rcvavoid = xti_tcp_stream_request->so_rcvavoid; 1341 loc_sndavoid = xti_tcp_stream_request->so_sndavoid; 1342 1343 #ifdef __alpha 1344 1345 /* ok - even on a DEC box, strings are strings. I din't really want */ 1346 /* to ntohl the words of a string. since I don't want to teach the */ 1347 /* send_ and recv_ _request and _response routines about the types, */ 1348 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ 1349 /* solution would be to use XDR, but I am still leary of being able */ 1350 /* to find XDR libs on all platforms I want running netperf. raj */ 1351 { 1352 int *charword; 1353 int *initword; 1354 int *lastword; 1355 1356 initword = (int *) xti_tcp_stream_request->xti_device; 1357 lastword = initword + ((xti_tcp_stream_request->dev_name_len + 3) / 4); 1358 1359 for (charword = initword; 1360 charword < lastword; 1361 charword++) { 1362 1363 *charword = htonl(*charword); 1364 } 1365 } 1366 1367 #endif /* __alpha */ 1368 1369 s_listen = create_xti_endpoint(xti_tcp_stream_request->xti_device); 1370 1371 if (s_listen == INVALID_SOCKET) { 1372 netperf_response.content.serv_errno = errno; 1373 send_response(); 1374 exit(1); 1375 } 1376 1377 /* Let's get an address assigned to this socket so we can tell the */ 1378 /* initiator how to reach the data socket. There may be a desire to */ 1379 /* nail this socket to a specific IP address in a multi-homed, */ 1380 /* multi-connection situation, but for now, we'll ignore the issue */ 1381 /* and concentrate on single connection testing. */ 1382 1383 bind_req.addr.maxlen = sizeof(struct sockaddr_in); 1384 bind_req.addr.len = sizeof(struct sockaddr_in); 1385 bind_req.addr.buf = (char *)&myaddr_in; 1386 bind_req.qlen = 1; 1387 1388 bind_resp.addr.maxlen = sizeof(struct sockaddr_in); 1389 bind_resp.addr.len = sizeof(struct sockaddr_in); 1390 bind_resp.addr.buf = (char *)&myaddr_in; 1391 bind_resp.qlen = 1; 1392 1393 if (t_bind(s_listen, 1394 &bind_req, 1395 &bind_resp) == SOCKET_ERROR) { 1396 netperf_response.content.serv_errno = t_errno; 1397 close(s_listen); 1398 send_response(); 1399 1400 exit(1); 1401 } 1402 1403 if (debug) { 1404 fprintf(where, 1405 "recv_xti_tcp_stream: t_bind complete port %d\n", 1406 ntohs(myaddr_in.sin_port)); 1407 fflush(where); 1408 } 1409 1410 /* what sort of sizes did we end-up with? */ 1411 if (xti_tcp_stream_request->receive_size == 0) { 1412 if (lsr_size > 0) { 1413 recv_size = lsr_size; 1414 } 1415 else { 1416 recv_size = 4096; 1417 } 1418 } 1419 else { 1420 recv_size = xti_tcp_stream_request->receive_size; 1421 } 1422 1423 /* we want to set-up our recv_ring in a manner analagous to what we */ 1424 /* do on the sending side. this is more for the sake of symmetry */ 1425 /* than for the needs of say copy avoidance, but it might also be */ 1426 /* more realistic - this way one could conceivably go with a */ 1427 /* double-buffering scheme when taking the data an putting it into */ 1428 /* the filesystem or something like that. raj 7/94 */ 1429 1430 if (recv_width == 0) { 1431 recv_width = (lsr_size/recv_size) + 1; 1432 if (recv_width == 1) recv_width++; 1433 } 1434 1435 recv_ring = allocate_buffer_ring(recv_width, 1436 recv_size, 1437 xti_tcp_stream_request->recv_alignment, 1438 xti_tcp_stream_request->recv_offset); 1439 1440 if (debug) { 1441 fprintf(where,"recv_xti_tcp_stream: recv alignment and offset set...\n"); 1442 fflush(where); 1443 } 1444 1445 /* Now myaddr_in contains the port and the internet address this is */ 1446 /* returned to the sender also implicitly telling the sender that the */ 1447 /* socket buffer sizing has been done. */ 1448 1449 xti_tcp_stream_response->data_port_number = 1450 (int) ntohs(myaddr_in.sin_port); 1451 netperf_response.content.serv_errno = 0; 1452 1453 /* But wait, there's more. If the initiator wanted cpu measurements, */ 1454 /* then we must call the calibrate routine, which will return the max */ 1455 /* rate back to the initiator. If the CPU was not to be measured, or */ 1456 /* something went wrong with the calibration, we will return a -1 to */ 1457 /* the initiator. */ 1458 1459 xti_tcp_stream_response->cpu_rate = 0.0; /* assume no cpu */ 1460 if (xti_tcp_stream_request->measure_cpu) { 1461 xti_tcp_stream_response->measure_cpu = 1; 1462 xti_tcp_stream_response->cpu_rate = 1463 calibrate_local_cpu(xti_tcp_stream_request->cpu_rate); 1464 } 1465 else { 1466 xti_tcp_stream_response->measure_cpu = 0; 1467 } 1468 1469 /* before we send the response back to the initiator, pull some of */ 1470 /* the socket parms from the globals */ 1471 xti_tcp_stream_response->send_buf_size = lss_size; 1472 xti_tcp_stream_response->recv_buf_size = lsr_size; 1473 xti_tcp_stream_response->no_delay = loc_nodelay; 1474 xti_tcp_stream_response->so_rcvavoid = loc_rcvavoid; 1475 xti_tcp_stream_response->so_sndavoid = loc_sndavoid; 1476 xti_tcp_stream_response->receive_size = recv_size; 1477 1478 send_response(); 1479 1480 /* Now, let's set-up the socket to listen for connections. for xti, */ 1481 /* the t_listen call is blocking by default - this is different */ 1482 /* semantics from BSD - probably has to do with being able to reject */ 1483 /* a call before an accept */ 1484 call_req.addr.maxlen = sizeof(struct sockaddr_in); 1485 call_req.addr.len = sizeof(struct sockaddr_in); 1486 call_req.addr.buf = (char *)&peeraddr_in; 1487 call_req.opt.maxlen = 0; 1488 call_req.opt.len = 0; 1489 call_req.opt.buf = NULL; 1490 call_req.udata.maxlen= 0; 1491 call_req.udata.len = 0; 1492 call_req.udata.buf = 0; 1493 1494 if (t_listen(s_listen, &call_req) == -1) { 1495 fprintf(where, 1496 "recv_xti_tcp_stream: t_listen: errno %d t_errno %d\n", 1497 errno, 1498 t_errno); 1499 fflush(where); 1500 netperf_response.content.serv_errno = t_errno; 1501 close(s_listen); 1502 send_response(); 1503 exit(1); 1504 } 1505 1506 if (debug) { 1507 fprintf(where, 1508 "recv_xti_tcp_stream: t_listen complete t_look 0x%.4x\n", 1509 t_look(s_listen)); 1510 fflush(where); 1511 } 1512 1513 /* now just rubber stamp the thing. we want to use the same fd? so */ 1514 /* we will just equate s_data with s_listen. this seems a little */ 1515 /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */ 1516 s_data = s_listen; 1517 if (t_accept(s_listen, 1518 s_data, 1519 &call_req) == -1) { 1520 fprintf(where, 1521 "recv_xti_tcp_stream: t_accept: errno %d t_errno %d\n", 1522 errno, 1523 t_errno); 1524 fflush(where); 1525 close(s_listen); 1526 exit(1); 1527 } 1528 1529 if (debug) { 1530 fprintf(where, 1531 "recv_xti_tcp_stream: t_accept complete t_look 0x%.4x\n", 1532 t_look(s_data)); 1533 fprintf(where, 1534 " remote is %s port %d\n", 1535 inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr), 1536 ntohs(peeraddr_in.sin_port)); 1537 fflush(where); 1538 } 1539 1540 /* Now it's time to start receiving data on the connection. We will */ 1541 /* first grab the apropriate counters and then start grabbing. */ 1542 1543 cpu_start(xti_tcp_stream_request->measure_cpu); 1544 1545 /* The loop will exit when the sender does a t_sndrel, which will */ 1546 /* return T_LOOK error from the t_recv */ 1547 1548 #ifdef DIRTY 1549 /* we want to dirty some number of consecutive integers in the buffer */ 1550 /* we are about to recv. we may also want to bring some number of */ 1551 /* them cleanly into the cache. The clean ones will follow any dirty */ 1552 /* ones into the cache. */ 1553 1554 access_buffer(recv_ring->buffer_ptr, 1555 recv_size, 1556 xti_tcp_stream_request->dirty_count, 1557 xti_tcp_stream_request->clean_count); 1558 1559 #endif /* DIRTY */ 1560 1561 bytes_received = 0; 1562 receive_calls = 0; 1563 1564 while ((len = t_rcv(s_data, 1565 recv_ring->buffer_ptr, 1566 recv_size, 1567 &xti_flags)) != -1) { 1568 bytes_received += len; 1569 receive_calls++; 1570 1571 /* more to the next buffer in the recv_ring */ 1572 recv_ring = recv_ring->next; 1573 1574 #ifdef DIRTY 1575 1576 access_buffer(recv_ring->buffer_ptr, 1577 recv_size, 1578 xti_tcp_stream_request->dirty_count, 1579 xti_tcp_stream_request->clean_count); 1580 1581 #endif /* DIRTY */ 1582 } 1583 1584 if (t_look(s_data) == T_ORDREL) { 1585 /* this is a normal exit path */ 1586 if (debug) { 1587 fprintf(where, 1588 "recv_xti_tcp_stream: t_rcv T_ORDREL indicated\n"); 1589 fflush(where); 1590 } 1591 } 1592 else { 1593 /* something went wrong */ 1594 fprintf(where, 1595 "recv_xti_tcp_stream: t_rcv: errno %d t_errno %d len %d", 1596 errno, 1597 t_errno, 1598 len); 1599 fprintf(where, 1600 " t_look 0x%.4x", 1601 t_look(s_data)); 1602 fflush(where); 1603 netperf_response.content.serv_errno = t_errno; 1604 send_response(); 1605 exit(1); 1606 } 1607 1608 /* receive the release and let the initiator know that we have */ 1609 /* received all the data. raj 3/95 */ 1610 1611 if (t_rcvrel(s_data) == -1) { 1612 netperf_response.content.serv_errno = errno; 1613 send_response(); 1614 exit(1); 1615 } 1616 1617 if (debug) { 1618 fprintf(where, 1619 "recv_xti_tcp_stream: t_rcvrel complete\n"); 1620 fflush(where); 1621 } 1622 1623 if (t_sndrel(s_data) == -1) { 1624 netperf_response.content.serv_errno = errno; 1625 send_response(); 1626 exit(1); 1627 } 1628 1629 if (debug) { 1630 fprintf(where, 1631 "recv_xti_tcp_stream: t_sndrel complete\n"); 1632 fflush(where); 1633 } 1634 1635 cpu_stop(xti_tcp_stream_request->measure_cpu,&elapsed_time); 1636 1637 /* send the results to the sender */ 1638 1639 if (debug) { 1640 fprintf(where, 1641 "recv_xti_tcp_stream: got %g bytes\n", 1642 bytes_received); 1643 fprintf(where, 1644 "recv_xti_tcp_stream: got %d recvs\n", 1645 receive_calls); 1646 fflush(where); 1647 } 1648 1649 xti_tcp_stream_results->bytes_received = bytes_received; 1650 xti_tcp_stream_results->elapsed_time = elapsed_time; 1651 xti_tcp_stream_results->recv_calls = receive_calls; 1652 1653 if (xti_tcp_stream_request->measure_cpu) { 1654 xti_tcp_stream_results->cpu_util = calc_cpu_util(0.0); 1655 }; 1656 1657 if (debug) { 1658 fprintf(where, 1659 "recv_xti_tcp_stream: test complete, sending results.\n"); 1660 fprintf(where, 1661 " bytes_received %g receive_calls %d\n", 1662 bytes_received, 1663 receive_calls); 1664 fprintf(where, 1665 " len %d\n", 1666 len); 1667 fflush(where); 1668 } 1669 1670 xti_tcp_stream_results->cpu_method = cpu_method; 1671 send_response(); 1672 1673 /* we are now done with the socket */ 1674 t_close(s_data); 1675 1676 } 1677 1678 1680 /* this routine implements the sending (netperf) side of the XTI_TCP_RR */ 1681 /* test. */ 1682 1683 void 1684 send_xti_tcp_rr(char remote_host[]) 1685 { 1686 1687 char *tput_title = "\ 1688 Local /Remote\n\ 1689 Socket Size Request Resp. Elapsed Trans.\n\ 1690 Send Recv Size Size Time Rate \n\ 1691 bytes Bytes bytes bytes secs. per sec \n\n"; 1692 1693 char *tput_fmt_0 = 1694 "%7.2f\n"; 1695 1696 char *tput_fmt_1_line_1 = "\ 1697 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; 1698 char *tput_fmt_1_line_2 = "\ 1699 %-6d %-6d\n"; 1700 1701 char *cpu_title = "\ 1702 Local /Remote\n\ 1703 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ 1704 Send Recv Size Size Time Rate local remote local remote\n\ 1705 bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; 1706 1707 char *cpu_fmt_0 = 1708 "%6.3f %c\n"; 1709 1710 char *cpu_fmt_1_line_1 = "\ 1711 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; 1712 1713 char *cpu_fmt_1_line_2 = "\ 1714 %-6d %-6d\n"; 1715 1716 char *ksink_fmt = "\ 1717 Alignment Offset\n\ 1718 Local Remote Local Remote\n\ 1719 Send Recv Send Recv\n\ 1720 %5d %5d %5d %5d\n"; 1721 1722 1723 int timed_out = 0; 1724 float elapsed_time; 1725 1726 int len; 1727 char *temp_message_ptr; 1728 int nummessages; 1729 SOCKET send_socket; 1730 int trans_remaining; 1731 double bytes_xferd; 1732 1733 struct ring_elt *send_ring; 1734 struct ring_elt *recv_ring; 1735 1736 int rsp_bytes_left; 1737 int rsp_bytes_recvd; 1738 1739 float local_cpu_utilization; 1740 float local_service_demand; 1741 float remote_cpu_utilization; 1742 float remote_service_demand; 1743 double thruput; 1744 1745 struct hostent *hp; 1746 struct sockaddr_in server; 1747 unsigned int addr; 1748 1749 struct t_call server_call; 1750 1751 struct xti_tcp_rr_request_struct *xti_tcp_rr_request; 1752 struct xti_tcp_rr_response_struct *xti_tcp_rr_response; 1753 struct xti_tcp_rr_results_struct *xti_tcp_rr_result; 1754 1755 #ifdef WANT_INTERVALS 1756 int interval_count; 1757 sigset_t signal_set; 1758 #endif /* WANT_INTERVALS */ 1759 1760 xti_tcp_rr_request = 1761 (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data; 1762 xti_tcp_rr_response= 1763 (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data; 1764 xti_tcp_rr_result = 1765 (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data; 1766 1767 #ifdef WANT_HISTOGRAM 1768 time_hist = HIST_new(); 1769 #endif /* WANT_HISTOGRAM */ 1770 1771 /* since we are now disconnected from the code that established the */ 1772 /* control socket, and since we want to be able to use different */ 1773 /* protocols and such, we are passed the name of the remote host and */ 1774 /* must turn that into the test specific addressing information. */ 1775 1776 bzero((char *)&server, 1777 sizeof(server)); 1778 1779 /* it would seem that while HP-UX will allow an IP address (as a */ 1780 /* string) in a call to gethostbyname, other, less enlightened */ 1781 /* systems do not. fix from awjacks (at) ca.sandia.gov raj 10/95 */ 1782 /* order changed to check for IP address first. raj 7/96 */ 1783 1784 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) { 1785 /* it was not an IP address, try it as a name */ 1786 if ((hp = gethostbyname(remote_host)) == NULL) { 1787 /* we have no idea what it is */ 1788 fprintf(where, 1789 "establish_control: could not resolve the destination %s\n", 1790 remote_host); 1791 fflush(where); 1792 exit(1); 1793 } 1794 else { 1795 /* it was a valid remote_host */ 1796 bcopy(hp->h_addr, 1797 (char *)&server.sin_addr, 1798 hp->h_length); 1799 server.sin_family = hp->h_addrtype; 1800 } 1801 } 1802 else { 1803 /* it was a valid IP address */ 1804 server.sin_addr.s_addr = addr; 1805 server.sin_family = AF_INET; 1806 } 1807 1808 if ( print_headers ) { 1809 fprintf(where,"XTI TCP REQUEST/RESPONSE TEST"); 1810 fprintf(where," to %s", remote_host); 1811 if (iteration_max > 1) { 1812 fprintf(where, 1813 " : +/-%3.1f%% @ %2d%% conf.", 1814 interval/0.02, 1815 confidence_level); 1816 } 1817 if (loc_nodelay || rem_nodelay) { 1818 fprintf(where," : nodelay"); 1819 } 1820 if (loc_sndavoid || 1821 loc_rcvavoid || 1822 rem_sndavoid || 1823 rem_rcvavoid) { 1824 fprintf(where," : copy avoidance"); 1825 } 1826 #ifdef WANT_HISTOGRAM 1827 fprintf(where," : histogram"); 1828 #endif /* WANT_HISTOGRAM */ 1829 #ifdef WANT_INTERVALS 1830 fprintf(where," : interval"); 1831 #endif /* WANT_INTERVALS */ 1832 #ifdef DIRTY 1833 fprintf(where," : dirty data"); 1834 #endif /* DIRTY */ 1835 fprintf(where,"\n"); 1836 } 1837 1838 /* initialize a few counters */ 1839 1840 send_ring = NULL; 1841 recv_ring = NULL; 1842 confidence_iteration = 1; 1843 init_stat(); 1844 1845 /* we have a great-big while loop which controls the number of times */ 1846 /* we run a particular test. this is for the calculation of a */ 1847 /* confidence interval (I really should have stayed awake during */ 1848 /* probstats :). If the user did not request confidence measurement */ 1849 /* (no confidence is the default) then we will only go though the */ 1850 /* loop once. the confidence stuff originates from the folks at IBM */ 1851 1852 while (((confidence < 0) && (confidence_iteration < iteration_max)) || 1853 (confidence_iteration <= iteration_min)) { 1854 1855 /* initialize a few counters. we have to remember that we might be */ 1856 /* going through the loop more than once. */ 1857 1858 nummessages = 0; 1859 bytes_xferd = 0.0; 1860 times_up = 0; 1861 timed_out = 0; 1862 trans_remaining = 0; 1863 1864 /* set-up the data buffers with the requested alignment and offset. */ 1865 /* since this is a request/response test, default the send_width and */ 1866 /* recv_width to 1 and not two raj 7/94 */ 1867 1868 if (send_width == 0) send_width = 1; 1869 if (recv_width == 0) recv_width = 1; 1870 1871 if (send_ring == NULL) { 1872 send_ring = allocate_buffer_ring(send_width, 1873 req_size, 1874 local_send_align, 1875 local_send_offset); 1876 } 1877 1878 if (recv_ring == NULL) { 1879 recv_ring = allocate_buffer_ring(recv_width, 1880 rsp_size, 1881 local_recv_align, 1882 local_recv_offset); 1883 } 1884 1885 /*set up the data socket */ 1886 send_socket = create_xti_endpoint(loc_xti_device); 1887 1888 if (send_socket == INVALID_SOCKET){ 1889 perror("netperf: send_xti_tcp_rr: tcp stream data socket"); 1890 exit(1); 1891 } 1892 1893 if (debug) { 1894 fprintf(where,"send_xti_tcp_rr: send_socket obtained...\n"); 1895 } 1896 1897 /* it would seem that with XTI, there is no implicit bind on a */ 1898 /* connect, so we have to make a call to t_bind. this is not */ 1899 /* terribly convenient, but I suppose that "standard is better */ 1900 /* than better" :) raj 2/95 */ 1901 1902 if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) { 1903 t_error("send_xti_tcp_stream: t_bind"); 1904 exit(1); 1905 } 1906 1907 /* If the user has requested cpu utilization measurements, we must */ 1908 /* calibrate the cpu(s). We will perform this task within the tests */ 1909 /* themselves. If the user has specified the cpu rate, then */ 1910 /* calibrate_local_cpu will return rather quickly as it will have */ 1911 /* nothing to do. If local_cpu_rate is zero, then we will go through */ 1912 /* all the "normal" calibration stuff and return the rate back.*/ 1913 1914 if (local_cpu_usage) { 1915 local_cpu_rate = calibrate_local_cpu(local_cpu_rate); 1916 } 1917 1918 /* Tell the remote end to do a listen. The server alters the socket */ 1919 /* paramters on the other side at this point, hence the reason for */ 1920 /* all the values being passed in the setup message. If the user did */ 1921 /* not specify any of the parameters, they will be passed as 0, which */ 1922 /* will indicate to the remote that no changes beyond the system's */ 1923 /* default should be used. Alignment is the exception, it will */ 1924 /* default to 8, which will be no alignment alterations. */ 1925 1926 netperf_request.content.request_type = DO_XTI_TCP_RR; 1927 xti_tcp_rr_request->recv_buf_size = rsr_size; 1928 xti_tcp_rr_request->send_buf_size = rss_size; 1929 xti_tcp_rr_request->recv_alignment = remote_recv_align; 1930 xti_tcp_rr_request->recv_offset = remote_recv_offset; 1931 xti_tcp_rr_request->send_alignment = remote_send_align; 1932 xti_tcp_rr_request->send_offset = remote_send_offset; 1933 xti_tcp_rr_request->request_size = req_size; 1934 xti_tcp_rr_request->response_size = rsp_size; 1935 xti_tcp_rr_request->no_delay = rem_nodelay; 1936 xti_tcp_rr_request->measure_cpu = remote_cpu_usage; 1937 xti_tcp_rr_request->cpu_rate = remote_cpu_rate; 1938 xti_tcp_rr_request->so_rcvavoid = rem_rcvavoid; 1939 xti_tcp_rr_request->so_sndavoid = rem_sndavoid; 1940 if (test_time) { 1941 xti_tcp_rr_request->test_length = test_time; 1942 } 1943 else { 1944 xti_tcp_rr_request->test_length = test_trans * -1; 1945 } 1946 1947 strcpy(xti_tcp_rr_request->xti_device, rem_xti_device); 1948 1949 #ifdef __alpha 1950 1951 /* ok - even on a DEC box, strings are strings. I didn't really want */ 1952 /* to ntohl the words of a string. since I don't want to teach the */ 1953 /* send_ and recv_ _request and _response routines about the types, */ 1954 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ 1955 /* solution would be to use XDR, but I am still leary of being able */ 1956 /* to find XDR libs on all platforms I want running netperf. raj */ 1957 { 1958 int *charword; 1959 int *initword; 1960 int *lastword; 1961 1962 initword = (int *) xti_tcp_rr_request->xti_device; 1963 lastword = initword + ((strlen(rem_xti_device) + 3) / 4); 1964 1965 for (charword = initword; 1966 charword < lastword; 1967 charword++) { 1968 1969 *charword = ntohl(*charword); 1970 } 1971 } 1972 #endif /* __alpha */ 1973 1974 if (debug > 1) { 1975 fprintf(where,"netperf: send_xti_tcp_rr: requesting TCP rr test\n"); 1976 } 1977 1978 send_request(); 1979 1980 /* The response from the remote will contain all of the relevant */ 1981 /* socket parameters for this test type. We will put them back into */ 1982 /* the variables here so they can be displayed if desired. The */ 1983 /* remote will have calibrated CPU if necessary, and will have done */ 1984 /* all the needed set-up we will have calibrated the cpu locally */ 1985 /* before sending the request, and will grab the counter value right*/ 1986 /* after the connect returns. The remote will grab the counter right*/ 1987 /* after the accept call. This saves the hassle of extra messages */ 1988 /* being sent for the TCP tests. */ 1989 1990 recv_response(); 1991 1992 if (!netperf_response.content.serv_errno) { 1993 if (debug) 1994 fprintf(where,"remote listen done.\n"); 1995 rsr_size = xti_tcp_rr_response->recv_buf_size; 1996 rss_size = xti_tcp_rr_response->send_buf_size; 1997 rem_nodelay = xti_tcp_rr_response->no_delay; 1998 remote_cpu_usage = xti_tcp_rr_response->measure_cpu; 1999 remote_cpu_rate = xti_tcp_rr_response->cpu_rate; 2000 /* make sure that port numbers are in network order */ 2001 server.sin_port = (short)xti_tcp_rr_response->data_port_number; 2002 server.sin_port = htons(server.sin_port); 2003 } 2004 else { 2005 Set_errno(netperf_response.content.serv_errno); 2006 perror("netperf: remote error"); 2007 2008 exit(1); 2009 } 2010 2011 /*Connect up to the remote port on the data socket */ 2012 memset (&server_call, 0, sizeof(server_call)); 2013 server_call.addr.maxlen = sizeof(struct sockaddr_in); 2014 server_call.addr.len = sizeof(struct sockaddr_in); 2015 server_call.addr.buf = (char *)&server; 2016 2017 if (t_connect(send_socket, 2018 &server_call, 2019 NULL) == INVALID_SOCKET){ 2020 t_error("netperf: send_xti_tcp_rr: data socket connect failed"); 2021 printf(" port: %d\n",ntohs(server.sin_port)); 2022 exit(1); 2023 } 2024 2025 /* Data Socket set-up is finished. If there were problems, either the */ 2026 /* connect would have failed, or the previous response would have */ 2027 /* indicated a problem. I failed to see the value of the extra */ 2028 /* message after the accept on the remote. If it failed, we'll see it */ 2029 /* here. If it didn't, we might as well start pumping data. */ 2030 2031 /* Set-up the test end conditions. For a request/response test, they */ 2032 /* can be either time or transaction based. */ 2033 2034 if (test_time) { 2035 /* The user wanted to end the test after a period of time. */ 2036 times_up = 0; 2037 trans_remaining = 0; 2038 start_timer(test_time); 2039 } 2040 else { 2041 /* The tester wanted to send a number of bytes. */ 2042 trans_remaining = test_bytes; 2043 times_up = 1; 2044 } 2045 2046 /* The cpu_start routine will grab the current time and possibly */ 2047 /* value of the idle counter for later use in measuring cpu */ 2048 /* utilization and/or service demand and thruput. */ 2049 2050 cpu_start(local_cpu_usage); 2051 2052 #ifdef WANT_INTERVALS 2053 if ((interval_burst) || (demo_mode)) { 2054 /* zero means that we never pause, so we never should need the */ 2055 /* interval timer, unless we are in demo_mode */ 2056 start_itimer(interval_wate); 2057 } 2058 interval_count = interval_burst; 2059 /* get the signal set for the call to sigsuspend */ 2060 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { 2061 fprintf(where, 2062 "send_xti_tcp_rr: unable to get sigmask errno %d\n", 2063 errno); 2064 fflush(where); 2065 exit(1); 2066 } 2067 #endif /* WANT_INTERVALS */ 2068 2069 /* We use an "OR" to control test execution. When the test is */ 2070 /* controlled by time, the byte count check will always return false. */ 2071 /* When the test is controlled by byte count, the time test will */ 2072 /* always return false. When the test is finished, the whole */ 2073 /* expression will go false and we will stop sending data. I think I */ 2074 /* just arbitrarily decrement trans_remaining for the timed test, but */ 2075 /* will not do that just yet... One other question is whether or not */ 2076 /* the send buffer and the receive buffer should be the same buffer. */ 2077 2078 while ((!times_up) || (trans_remaining > 0)) { 2079 /* send the request. we assume that if we use a blocking socket, */ 2080 /* the request will be sent at one shot. */ 2081 2082 #ifdef WANT_HISTOGRAM 2083 /* timestamp just before our call to send, and then again just */ 2084 /* after the receive raj 8/94 */ 2085 HIST_timestamp(&time_one); 2086 #endif /* WANT_HISTOGRAM */ 2087 2088 if((len=t_snd(send_socket, 2089 send_ring->buffer_ptr, 2090 req_size, 2091 0)) != req_size) { 2092 if ((errno == EINTR) || (errno == 0)) { 2093 /* we hit the end of a */ 2094 /* timed test. */ 2095 timed_out = 1; 2096 break; 2097 } 2098 fprintf(where, 2099 "send_xti_tcp_rr: t_snd: errno %d t_errno %d t_look 0x%.4x\n", 2100 errno, 2101 t_errno, 2102 t_look(send_socket)); 2103 fflush(where); 2104 exit(1); 2105 } 2106 send_ring = send_ring->next; 2107 2108 /* receive the response */ 2109 rsp_bytes_left = rsp_size; 2110 temp_message_ptr = recv_ring->buffer_ptr; 2111 while(rsp_bytes_left > 0) { 2112 if((rsp_bytes_recvd=t_rcv(send_socket, 2113 temp_message_ptr, 2114 rsp_bytes_left, 2115 &xti_flags)) == SOCKET_ERROR) { 2116 if (errno == EINTR) { 2117 /* We hit the end of a timed test. */ 2118 timed_out = 1; 2119 break; 2120 } 2121 fprintf(where, 2122 "send_xti_tcp_rr: t_rcv: errno %d t_errno %d t_look 0x%x\n", 2123 errno, 2124 t_errno, 2125 t_look(send_socket)); 2126 fflush(where); 2127 exit(1); 2128 } 2129 rsp_bytes_left -= rsp_bytes_recvd; 2130 temp_message_ptr += rsp_bytes_recvd; 2131 } 2132 recv_ring = recv_ring->next; 2133 2134 if (timed_out) { 2135 /* we may have been in a nested while loop - we need */ 2136 /* another call to break. */ 2137 break; 2138 } 2139 2140 #ifdef WANT_HISTOGRAM 2141 HIST_timestamp(&time_two); 2142 HIST_add(time_hist,delta_micro(&time_one,&time_two)); 2143 #endif /* WANT_HISTOGRAM */ 2144 #ifdef WANT_INTERVALS 2145 if (demo_mode) { 2146 units_this_tick += 1; 2147 } 2148 /* in this case, the interval count is the count-down couter */ 2149 /* to decide to sleep for a little bit */ 2150 if ((interval_burst) && (--interval_count == 0)) { 2151 /* call sigsuspend and wait for the interval timer to get us */ 2152 /* out */ 2153 if (debug) { 2154 fprintf(where,"about to suspend\n"); 2155 fflush(where); 2156 } 2157 if (sigsuspend(&signal_set) == EFAULT) { 2158 fprintf(where, 2159 "send_xti_udp_rr: fault with signal set!\n"); 2160 fflush(where); 2161 exit(1); 2162 } 2163 interval_count = interval_burst; 2164 } 2165 #endif /* WANT_INTERVALS */ 2166 2167 nummessages++; 2168 if (trans_remaining) { 2169 trans_remaining--; 2170 } 2171 2172 if (debug > 3) { 2173 if ((nummessages % 100) == 0) { 2174 fprintf(where, 2175 "Transaction %d completed\n", 2176 nummessages); 2177 fflush(where); 2178 } 2179 } 2180 } 2181 2182 2183 /* this call will always give us the elapsed time for the test, and */ 2184 /* will also store-away the necessaries for cpu utilization */ 2185 2186 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ 2187 /* measured? how long */ 2188 /* did we really run? */ 2189 2190 /* Get the statistics from the remote end. The remote will have */ 2191 /* calculated service demand and all those interesting things. If it */ 2192 /* wasn't supposed to care, it will return obvious values. */ 2193 2194 recv_response(); 2195 if (!netperf_response.content.serv_errno) { 2196 if (debug) 2197 fprintf(where,"remote results obtained\n"); 2198 } 2199 else { 2200 Set_errno(netperf_response.content.serv_errno); 2201 perror("netperf: remote error"); 2202 2203 exit(1); 2204 } 2205 2206 /* We now calculate what our thruput was for the test. */ 2207 2208 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); 2209 thruput = nummessages/elapsed_time; 2210 2211 if (local_cpu_usage || remote_cpu_usage) { 2212 /* We must now do a little math for service demand and cpu */ 2213 /* utilization for the system(s) */ 2214 /* Of course, some of the information might be bogus because */ 2215 /* there was no idle counter in the kernel(s). We need to make */ 2216 /* a note of this for the user's benefit...*/ 2217 if (local_cpu_usage) { 2218 local_cpu_utilization = calc_cpu_util(0.0); 2219 /* since calc_service demand is doing ms/Kunit we will */ 2220 /* multiply the number of transaction by 1024 to get */ 2221 /* "good" numbers */ 2222 local_service_demand = calc_service_demand((double) nummessages*1024, 2223 0.0, 2224 0.0, 2225 0); 2226 } 2227 else { 2228 local_cpu_utilization = -1.0; 2229 local_service_demand = -1.0; 2230 } 2231 2232 if (remote_cpu_usage) { 2233 remote_cpu_utilization = xti_tcp_rr_result->cpu_util; 2234 /* since calc_service demand is doing ms/Kunit we will */ 2235 /* multiply the number of transaction by 1024 to get */ 2236 /* "good" numbers */ 2237 remote_service_demand = calc_service_demand((double) nummessages*1024, 2238 0.0, 2239 remote_cpu_utilization, 2240 xti_tcp_rr_result->num_cpus); 2241 } 2242 else { 2243 remote_cpu_utilization = -1.0; 2244 remote_service_demand = -1.0; 2245 } 2246 2247 } 2248 else { 2249 /* we were not measuring cpu, for the confidence stuff, we */ 2250 /* should make it -1.0 */ 2251 local_cpu_utilization = -1.0; 2252 local_service_demand = -1.0; 2253 remote_cpu_utilization = -1.0; 2254 remote_service_demand = -1.0; 2255 } 2256 2257 /* at this point, we want to calculate the confidence information. */ 2258 /* if debugging is on, calculate_confidence will print-out the */ 2259 /* parameters we pass it */ 2260 2261 calculate_confidence(confidence_iteration, 2262 elapsed_time, 2263 thruput, 2264 local_cpu_utilization, 2265 remote_cpu_utilization, 2266 local_service_demand, 2267 remote_service_demand); 2268 2269 2270 confidence_iteration++; 2271 2272 /* we are now done with the socket, so close it */ 2273 t_close(send_socket); 2274 2275 } 2276 2277 retrieve_confident_values(&elapsed_time, 2278 &thruput, 2279 &local_cpu_utilization, 2280 &remote_cpu_utilization, 2281 &local_service_demand, 2282 &remote_service_demand); 2283 2284 /* We are now ready to print all the information. If the user */ 2285 /* has specified zero-level verbosity, we will just print the */ 2286 /* local service demand, or the remote service demand. If the */ 2287 /* user has requested verbosity level 1, he will get the basic */ 2288 /* "streamperf" numbers. If the user has specified a verbosity */ 2289 /* of greater than 1, we will display a veritable plethora of */ 2290 /* background information from outside of this block as it it */ 2291 /* not cpu_measurement specific... */ 2292 2293 if (confidence < 0) { 2294 /* we did not hit confidence, but were we asked to look for it? */ 2295 if (iteration_max > 1) { 2296 display_confidence(); 2297 } 2298 } 2299 2300 if (local_cpu_usage || remote_cpu_usage) { 2301 local_cpu_method = format_cpu_method(cpu_method); 2302 remote_cpu_method = format_cpu_method(xti_tcp_rr_result->cpu_method); 2303 2304 switch (verbosity) { 2305 case 0: 2306 if (local_cpu_usage) { 2307 fprintf(where, 2308 cpu_fmt_0, 2309 local_service_demand, 2310 local_cpu_method); 2311 } 2312 else { 2313 fprintf(where, 2314 cpu_fmt_0, 2315 remote_service_demand, 2316 remote_cpu_method); 2317 } 2318 break; 2319 case 1: 2320 case 2: 2321 if (print_headers) { 2322 fprintf(where, 2323 cpu_title, 2324 local_cpu_method, 2325 remote_cpu_method); 2326 } 2327 2328 fprintf(where, 2329 cpu_fmt_1_line_1, /* the format string */ 2330 lss_size, /* local sendbuf size */ 2331 lsr_size, 2332 req_size, /* how large were the requests */ 2333 rsp_size, /* guess */ 2334 elapsed_time, /* how long was the test */ 2335 thruput, 2336 local_cpu_utilization, /* local cpu */ 2337 remote_cpu_utilization, /* remote cpu */ 2338 local_service_demand, /* local service demand */ 2339 remote_service_demand); /* remote service demand */ 2340 fprintf(where, 2341 cpu_fmt_1_line_2, 2342 rss_size, 2343 rsr_size); 2344 break; 2345 } 2346 } 2347 else { 2348 /* The tester did not wish to measure service demand. */ 2349 2350 switch (verbosity) { 2351 case 0: 2352 fprintf(where, 2353 tput_fmt_0, 2354 thruput); 2355 break; 2356 case 1: 2357 case 2: 2358 if (print_headers) { 2359 fprintf(where,tput_title,format_units()); 2360 } 2361 2362 fprintf(where, 2363 tput_fmt_1_line_1, /* the format string */ 2364 lss_size, 2365 lsr_size, 2366 req_size, /* how large were the requests */ 2367 rsp_size, /* how large were the responses */ 2368 elapsed_time, /* how long did it take */ 2369 thruput); 2370 fprintf(where, 2371 tput_fmt_1_line_2, 2372 rss_size, /* remote recvbuf size */ 2373 rsr_size); 2374 2375 break; 2376 } 2377 } 2378 2379 /* it would be a good thing to include information about some of the */ 2380 /* other parameters that may have been set for this test, but at the */ 2381 /* moment, I do not wish to figure-out all the formatting, so I will */ 2382 /* just put this comment here to help remind me that it is something */ 2383 /* that should be done at a later time. */ 2384 2385 /* how to handle the verbose information in the presence of */ 2386 /* confidence intervals is yet to be determined... raj 11/94 */ 2387 if (verbosity > 1) { 2388 /* The user wanted to know it all, so we will give it to him. */ 2389 /* This information will include as much as we can find about */ 2390 /* TCP statistics, the alignments of the sends and receives */ 2391 /* and all that sort of rot... */ 2392 2393 fprintf(where, 2394 ksink_fmt, 2395 local_send_align, 2396 remote_recv_offset, 2397 local_send_offset, 2398 remote_recv_offset); 2399 2400 #ifdef WANT_HISTOGRAM 2401 fprintf(where,"\nHistogram of request/response times\n"); 2402 fflush(where); 2403 HIST_report(time_hist); 2404 #endif /* WANT_HISTOGRAM */ 2405 2406 } 2407 2408 } 2409 2410 void 2412 send_xti_udp_stream(char remote_host[]) 2413 { 2414 /**********************************************************************/ 2415 /* */ 2416 /* UDP Unidirectional Send Test */ 2417 /* */ 2418 /**********************************************************************/ 2419 char *tput_title = "\ 2420 Socket Message Elapsed Messages \n\ 2421 Size Size Time Okay Errors Throughput\n\ 2422 bytes bytes secs # # %s/sec\n\n"; 2423 2424 char *tput_fmt_0 = 2425 "%7.2f\n"; 2426 2427 char *tput_fmt_1 = "\ 2428 %6d %6d %-7.2f %7d %6d %7.2f\n\ 2429 %6d %-7.2f %7d %7.2f\n\n"; 2430 2431 2432 char *cpu_title = "\ 2433 Socket Message Elapsed Messages CPU Service\n\ 2434 Size Size Time Okay Errors Throughput Util Demand\n\ 2435 bytes bytes secs # # %s/sec %% %c%c us/KB\n\n"; 2436 2437 char *cpu_fmt_0 = 2438 "%6.2f %c\n"; 2439 2440 char *cpu_fmt_1 = "\ 2441 %6d %6d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\ 2442 %6d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n"; 2443 2444 unsigned int messages_recvd; 2445 unsigned int messages_sent; 2446 unsigned int failed_sends; 2447 2448 float elapsed_time, 2449 recv_elapsed, 2450 local_cpu_utilization, 2451 remote_cpu_utilization; 2452 2453 float local_service_demand, remote_service_demand; 2454 double local_thruput, remote_thruput; 2455 double bytes_sent; 2456 double bytes_recvd; 2457 2458 2459 int len; 2460 int *message_int_ptr; 2461 struct ring_elt *send_ring; 2462 SOCKET data_socket; 2463 2464 unsigned int sum_messages_sent; 2465 unsigned int sum_messages_recvd; 2466 unsigned int sum_failed_sends; 2467 double sum_local_thruput; 2468 2469 #ifdef WANT_INTERVALS 2470 int interval_count; 2471 sigset_t signal_set; 2472 #endif /* WANT_INTERVALS */ 2473 2474 struct hostent *hp; 2475 struct sockaddr_in server; 2476 unsigned int addr; 2477 2478 struct t_unitdata unitdata; 2479 2480 struct xti_udp_stream_request_struct *xti_udp_stream_request; 2481 struct xti_udp_stream_response_struct *xti_udp_stream_response; 2482 struct xti_udp_stream_results_struct *xti_udp_stream_results; 2483 2484 xti_udp_stream_request = 2485 (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data; 2486 xti_udp_stream_response = 2487 (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data; 2488 xti_udp_stream_results = 2489 (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data; 2490 2491 #ifdef WANT_HISTOGRAM 2492 time_hist = HIST_new(); 2493 #endif /* WANT_HISTOGRAM */ 2494 2495 /* since we are now disconnected from the code that established the */ 2496 /* control socket, and since we want to be able to use different */ 2497 /* protocols and such, we are passed the name of the remote host and */ 2498 /* must turn that into the test specific addressing information. */ 2499 2500 bzero((char *)&server, 2501 sizeof(server)); 2502 2503 /* it would seem that while HP-UX will allow an IP address (as a */ 2504 /* string) in a call to gethostbyname, other, less enlightened */ 2505 /* systems do not. fix from awjacks (at) ca.sandia.gov raj 10/95 */ 2506 /* order changed to check for IP address first. raj 7/96 */ 2507 2508 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) { 2509 /* it was not an IP address, try it as a name */ 2510 if ((hp = gethostbyname(remote_host)) == NULL) { 2511 /* we have no idea what it is */ 2512 fprintf(where, 2513 "establish_control: could not resolve the destination %s\n", 2514 remote_host); 2515 fflush(where); 2516 exit(1); 2517 } 2518 else { 2519 /* it was a valid remote_host */ 2520 bcopy(hp->h_addr, 2521 (char *)&server.sin_addr, 2522 hp->h_length); 2523 server.sin_family = hp->h_addrtype; 2524 } 2525 } 2526 else { 2527 /* it was a valid IP address */ 2528 server.sin_addr.s_addr = addr; 2529 server.sin_family = AF_INET; 2530 } 2531 2532 if ( print_headers ) { 2533 fprintf(where,"UDP UNIDIRECTIONAL SEND TEST"); 2534 fprintf(where," to %s", remote_host); 2535 if (iteration_max > 1) { 2536 fprintf(where, 2537 " : +/-%3.1f%% @ %2d%% conf.", 2538 interval/0.02, 2539 confidence_level); 2540 } 2541 if (loc_sndavoid || 2542 loc_rcvavoid || 2543 rem_sndavoid || 2544 rem_rcvavoid) { 2545 fprintf(where," : copy avoidance"); 2546 } 2547 #ifdef WANT_HISTOGRAM 2548 fprintf(where," : histogram"); 2549 #endif /* WANT_HISTOGRAM */ 2550 #ifdef WANT_INTERVALS 2551 fprintf(where," : interval"); 2552 #endif /* WANT_INTERVALS */ 2553 #ifdef DIRTY 2554 fprintf(where," : dirty data"); 2555 #endif /* DIRTY */ 2556 fprintf(where,"\n"); 2557 } 2558 2559 send_ring = NULL; 2560 confidence_iteration = 1; 2561 init_stat(); 2562 sum_messages_sent = 0; 2563 sum_messages_recvd = 0; 2564 sum_failed_sends = 0; 2565 sum_local_thruput = 0.0; 2566 2567 /* we have a great-big while loop which controls the number of times */ 2568 /* we run a particular test. this is for the calculation of a */ 2569 /* confidence interval (I really should have stayed awake during */ 2570 /* probstats :). If the user did not request confidence measurement */ 2571 /* (no confidence is the default) then we will only go though the */ 2572 /* loop once. the confidence stuff originates from the folks at IBM */ 2573 2574 while (((confidence < 0) && (confidence_iteration < iteration_max)) || 2575 (confidence_iteration <= iteration_min)) { 2576 2577 /* initialize a few counters. we have to remember that we might be */ 2578 /* going through the loop more than once. */ 2579 messages_sent = 0; 2580 messages_recvd = 0; 2581 failed_sends = 0; 2582 times_up = 0; 2583 2584 /*set up the data socket */ 2585 data_socket = create_xti_endpoint(loc_xti_device); 2586 2587 if (data_socket == INVALID_SOCKET) { 2588 perror("send_xti_udp_stream: create_xti_endpoint"); 2589 exit(1); 2590 } 2591 2592 if (t_bind(data_socket, NULL, NULL) == SOCKET_ERROR) { 2593 t_error("send_xti_udp_stream: t_bind"); 2594 exit(1); 2595 } 2596 2597 /* now, we want to see if we need to set the send_size */ 2598 if (send_size == 0) { 2599 if (lss_size > 0) { 2600 send_size = lss_size; 2601 } 2602 else { 2603 send_size = 4096; 2604 } 2605 } 2606 2607 /* set-up the data buffer with the requested alignment and offset, */ 2608 /* most of the numbers here are just a hack to pick something nice */ 2609 /* and big in an attempt to never try to send a buffer a second time */ 2610 /* before it leaves the node...unless the user set the width */ 2611 /* explicitly. */ 2612 if (send_width == 0) send_width = 32; 2613 2614 if (send_ring == NULL ) { 2615 send_ring = allocate_buffer_ring(send_width, 2616 send_size, 2617 local_send_align, 2618 local_send_offset); 2619 } 2620 2621 2622 /* if the user supplied a cpu rate, this call will complete rather */ 2623 /* quickly, otherwise, the cpu rate will be retured to us for */ 2624 /* possible display. The Library will keep it's own copy of this data */ 2625 /* for use elsewhere. We will only display it. (Does that make it */ 2626 /* "opaque" to us?) */ 2627 2628 if (local_cpu_usage) 2629 local_cpu_rate = calibrate_local_cpu(local_cpu_rate); 2630 2631 /* Tell the remote end to set up the data connection. The server */ 2632 /* sends back the port number and alters the socket parameters there. */ 2633 /* Of course this is a datagram service so no connection is actually */ 2634 /* set up, the server just sets up the socket and binds it. */ 2635 2636 netperf_request.content.request_type = DO_XTI_UDP_STREAM; 2637 xti_udp_stream_request->recv_buf_size = rsr_size; 2638 xti_udp_stream_request->message_size = send_size; 2639 xti_udp_stream_request->recv_alignment = remote_recv_align; 2640 xti_udp_stream_request->recv_offset = remote_recv_offset; 2641 xti_udp_stream_request->measure_cpu = remote_cpu_usage; 2642 xti_udp_stream_request->cpu_rate = remote_cpu_rate; 2643 xti_udp_stream_request->test_length = test_time; 2644 xti_udp_stream_request->so_rcvavoid = rem_rcvavoid; 2645 xti_udp_stream_request->so_sndavoid = rem_sndavoid; 2646 2647 strcpy(xti_udp_stream_request->xti_device, rem_xti_device); 2648 2649 #ifdef __alpha 2650 2651 /* ok - even on a DEC box, strings are strings. I didn't really want */ 2652 /* to ntohl the words of a string. since I don't want to teach the */ 2653 /* send_ and recv_ _request and _response routines about the types, */ 2654 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ 2655 /* solution would be to use XDR, but I am still leary of being able */ 2656 /* to find XDR libs on all platforms I want running netperf. raj */ 2657 { 2658 int *charword; 2659 int *initword; 2660 int *lastword; 2661 2662 initword = (int *) xti_udp_stream_request->xti_device; 2663 lastword = initword + ((strlen(rem_xti_device) + 3) / 4); 2664 2665 for (charword = initword; 2666 charword < lastword; 2667 charword++) { 2668 2669 *charword = ntohl(*charword); 2670 } 2671 } 2672 #endif /* __alpha */ 2673 2674 send_request(); 2675 2676 recv_response(); 2677 2678 if (!netperf_response.content.serv_errno) { 2679 if (debug) 2680 fprintf(where,"send_xti_udp_stream: remote data connection done.\n"); 2681 } 2682 else { 2683 Set_errno(netperf_response.content.serv_errno); 2684 perror("send_xti_udp_stream: error on remote"); 2685 exit(1); 2686 } 2687 2688 /* Place the port number returned by the remote into the sockaddr */ 2689 /* structure so our sends can be sent to the correct place. Also get */ 2690 /* some of the returned socket buffer information for user display. */ 2691 2692 /* make sure that port numbers are in the proper order */ 2693 server.sin_port = (short)xti_udp_stream_response->data_port_number; 2694 server.sin_port = htons(server.sin_port); 2695 rsr_size = xti_udp_stream_response->recv_buf_size; 2696 rss_size = xti_udp_stream_response->send_buf_size; 2697 remote_cpu_rate = xti_udp_stream_response->cpu_rate; 2698 2699 /* it would seem that XTI does not allow the expedient of */ 2700 /* "connecting" a UDP end-point the way BSD does. so, we will do */ 2701 /* everything with t_sndudata and t_rcvudata. Our "virtual" */ 2702 /* connect here will be to assign the destination portion of the */ 2703 /* t_unitdata struct here, where we would have otherwise called */ 2704 /* t_connect() raj 3/95 */ 2705 2706 memset (&unitdata, 0, sizeof(unitdata)); 2707 unitdata.addr.maxlen = sizeof(struct sockaddr_in); 2708 unitdata.addr.len = sizeof(struct sockaddr_in); 2709 unitdata.addr.buf = (char *)&server; 2710 2711 /* we don't use any options, so might as well set that part here */ 2712 /* too */ 2713 2714 unitdata.opt.maxlen = 0; 2715 unitdata.opt.len = 0; 2716 unitdata.opt.buf = NULL; 2717 2718 /* we need to initialize the send buffer for the first time as */ 2719 /* well since we move to the next pointer after the send call. */ 2720 2721 unitdata.udata.maxlen = send_size; 2722 unitdata.udata.len = send_size; 2723 unitdata.udata.buf = send_ring->buffer_ptr; 2724 2725 /* set up the timer to call us after test_time. one of these days, */ 2726 /* it might be nice to figure-out a nice reliable way to have the */ 2727 /* test controlled by a byte count as well, but since UDP is not */ 2728 /* reliable, that could prove difficult. so, in the meantime, we */ 2729 /* only allow a XTI_UDP_STREAM test to be a timed test. */ 2730 2731 if (test_time) { 2732 times_up = 0; 2733 start_timer(test_time); 2734 } 2735 else { 2736 fprintf(where,"Sorry, XTI_UDP_STREAM tests must be timed.\n"); 2737 fflush(where); 2738 exit(1); 2739 } 2740 2741 /* Get the start count for the idle counter and the start time */ 2742 2743 cpu_start(local_cpu_usage); 2744 2745 #ifdef WANT_INTERVALS 2746 if ((interval_burst) || (demo_mode)) { 2747 /* zero means that we never pause, so we never should need the */ 2748 /* interval timer, unless we are in demo_mode */ 2749 start_itimer(interval_wate); 2750 } 2751 interval_count = interval_burst; 2752 /* get the signal set for the call to sigsuspend */ 2753 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { 2754 fprintf(where, 2755 "send_xti_udp_stream: unable to get sigmask errno %d\n", 2756 errno); 2757 fflush(where); 2758 exit(1); 2759 } 2760 #endif /* WANT_INTERVALS */ 2761 2762 /* Send datagrams like there was no tomorrow. at somepoint it might */ 2763 /* be nice to set this up so that a quantity of bytes could be sent, */ 2764 /* but we still need some sort of end of test trigger on the receive */ 2765 /* side. that could be a select with a one second timeout, but then */ 2766 /* if there is a test where none of the data arrives for awile and */ 2767 /* then starts again, we would end the test too soon. something to */ 2768 /* think about... */ 2769 while (!times_up) { 2770 2771 #ifdef DIRTY 2772 /* we want to dirty some number of consecutive integers in the buffer */ 2773 /* we are about to send. we may also want to bring some number of */ 2774 /* them cleanly into the cache. The clean ones will follow any dirty */ 2775 /* ones into the cache. */ 2776 2777 access_buffer(send_ring->buffer_ptr, 2778 send_size, 2779 loc_dirty_count, 2780 loc_clean_count); 2781 2782 #endif /* DIRTY */ 2783 2784 #ifdef WANT_HISTOGRAM 2785 HIST_timestamp(&time_one); 2786 #endif /* WANT_HISTOGRAM */ 2787 2788 if ((t_sndudata(data_socket, 2789 &unitdata)) != 0) { 2790 if (errno == EINTR) 2791 break; 2792 if (errno == ENOBUFS) { 2793 failed_sends++; 2794 continue; 2795 } 2796 perror("xti_udp_send: data send error"); 2797 t_error("xti_udp_send: data send error"); 2798 exit(1); 2799 } 2800 messages_sent++; 2801 2802 /* now we want to move our pointer to the next position in the */ 2803 /* data buffer...and update the unitdata structure */ 2804 2805 send_ring = send_ring->next; 2806 unitdata.udata.buf = send_ring->buffer_ptr; 2807 2808 #ifdef WANT_HISTOGRAM 2809 /* get the second timestamp */ 2810 HIST_timestamp(&time_two); 2811 HIST_add(time_hist,delta_micro(&time_one,&time_two)); 2812 #endif /* WANT_HISTOGRAM */ 2813 #ifdef WANT_INTERVALS 2814 if (demo_mode) { 2815 units_this_tick += send_size; 2816 } 2817 /* in this case, the interval count is the count-down couter */ 2818 /* to decide to sleep for a little bit */ 2819 if ((interval_burst) && (--interval_count == 0)) { 2820 /* call sigsuspend and wait for the interval timer to get us */ 2821 /* out */ 2822 if (debug) { 2823 fprintf(where,"about to suspend\n"); 2824 fflush(where); 2825 } 2826 if (sigsuspend(&signal_set) == EFAULT) { 2827 fprintf(where, 2828 "send_xti_udp_stream: fault with signal set!\n"); 2829 fflush(where); 2830 exit(1); 2831 } 2832 interval_count = interval_burst; 2833 } 2834 #endif /* WANT_INTERVALS */ 2835 2836 } 2837 2838 /* This is a timed test, so the remote will be returning to us after */ 2839 /* a time. We should not need to send any "strange" messages to tell */ 2840 /* the remote that the test is completed, unless we decide to add a */ 2841 /* number of messages to the test. */ 2842 2843 /* the test is over, so get stats and stuff */ 2844 cpu_stop(local_cpu_usage, 2845 &elapsed_time); 2846 2847 /* Get the statistics from the remote end */ 2848 recv_response(); 2849 if (!netperf_response.content.serv_errno) { 2850 if (debug) 2851 fprintf(where,"send_xti_udp_stream: remote results obtained\n"); 2852 } 2853 else { 2854 Set_errno(netperf_response.content.serv_errno); 2855 perror("send_xti_udp_stream: error on remote"); 2856 exit(1); 2857 } 2858 2859 bytes_sent = (double) send_size * (double) messages_sent; 2860 local_thruput = calc_thruput(bytes_sent); 2861 2862 messages_recvd = xti_udp_stream_results->messages_recvd; 2863 bytes_recvd = (double) send_size * (double) messages_recvd; 2864 2865 /* we asume that the remote ran for as long as we did */ 2866 2867 remote_thruput = calc_thruput(bytes_recvd); 2868 2869 /* print the results for this socket and message size */ 2870 2871 if (local_cpu_usage || remote_cpu_usage) { 2872 /* We must now do a little math for service demand and cpu */ 2873 /* utilization for the system(s) We pass zeros for the local */ 2874 /* cpu utilization and elapsed time to tell the routine to use */ 2875 /* the libraries own values for those. */ 2876 if (local_cpu_usage) { 2877 local_cpu_utilization = calc_cpu_util(0.0); 2878 /* shouldn't this really be based on bytes_recvd, since that is */ 2879 /* the effective throughput of the test? I think that it should, */ 2880 /* so will make the change raj 11/94 */ 2881 local_service_demand = calc_service_demand(bytes_recvd, 2882 0.0, 2883 0.0, 2884 0); 2885 } 2886 else { 2887 local_cpu_utilization = -1.0; 2888 local_service_demand = -1.0; 2889 } 2890 2891 /* The local calculations could use variables being kept by */ 2892 /* the local netlib routines. The remote calcuations need to */ 2893 /* have a few things passed to them. */ 2894 if (remote_cpu_usage) { 2895 remote_cpu_utilization = xti_udp_stream_results->cpu_util; 2896 remote_service_demand = calc_service_demand(bytes_recvd, 2897 0.0, 2898 remote_cpu_utilization, 2899 xti_udp_stream_results->num_cpus); 2900 } 2901 else { 2902 remote_cpu_utilization = -1.0; 2903 remote_service_demand = -1.0; 2904 } 2905 } 2906 else { 2907 /* we were not measuring cpu, for the confidence stuff, we */ 2908 /* should make it -1.0 */ 2909 local_cpu_utilization = -1.0; 2910 local_service_demand = -1.0; 2911 remote_cpu_utilization = -1.0; 2912 remote_service_demand = -1.0; 2913 } 2914 2915 /* at this point, we want to calculate the confidence information. */ 2916 /* if debugging is on, calculate_confidence will print-out the */ 2917 /* parameters we pass it */ 2918 2919 calculate_confidence(confidence_iteration, 2920 elapsed_time, 2921 remote_thruput, 2922 local_cpu_utilization, 2923 remote_cpu_utilization, 2924 local_service_demand, 2925 remote_service_demand); 2926 2927 /* since the routine calculate_confidence is rather generic, and */ 2928 /* we have a few other parms of interest, we will do a little work */ 2929 /* here to caclulate their average. */ 2930 sum_messages_sent += messages_sent; 2931 sum_messages_recvd += messages_recvd; 2932 sum_failed_sends += failed_sends; 2933 sum_local_thruput += local_thruput; 2934 2935 confidence_iteration++; 2936 2937 /* this datapoint is done, so we don't need the socket any longer */ 2938 close(data_socket); 2939 2940 } 2941 2942 /* we should reach this point once the test is finished */ 2943 2944 retrieve_confident_values(&elapsed_time, 2945 &remote_thruput, 2946 &local_cpu_utilization, 2947 &remote_cpu_utilization, 2948 &local_service_demand, 2949 &remote_service_demand); 2950 2951 /* some of the interesting values aren't covered by the generic */ 2952 /* confidence routine */ 2953 messages_sent = sum_messages_sent / (confidence_iteration -1); 2954 messages_recvd = sum_messages_recvd / (confidence_iteration -1); 2955 failed_sends = sum_failed_sends / (confidence_iteration -1); 2956 local_thruput = sum_local_thruput / (confidence_iteration -1); 2957 2958 /* We are now ready to print all the information. If the user */ 2959 /* has specified zero-level verbosity, we will just print the */ 2960 /* local service demand, or the remote service demand. If the */ 2961 /* user has requested verbosity level 1, he will get the basic */ 2962 /* "streamperf" numbers. If the user has specified a verbosity */ 2963 /* of greater than 1, we will display a veritable plethora of */ 2964 /* background information from outside of this block as it it */ 2965 /* not cpu_measurement specific... */ 2966 2967 2968 if (confidence < 0) { 2969 /* we did not hit confidence, but were we asked to look for it? */ 2970 if (iteration_max > 1) { 2971 display_confidence(); 2972 } 2973 } 2974 2975 if (local_cpu_usage || remote_cpu_usage) { 2976 local_cpu_method = format_cpu_method(cpu_method); 2977 remote_cpu_method = format_cpu_method(xti_udp_stream_results->cpu_method); 2978 2979 switch (verbosity) { 2980 case 0: 2981 if (local_cpu_usage) { 2982 fprintf(where, 2983 cpu_fmt_0, 2984 local_service_demand, 2985 local_cpu_method); 2986 } 2987 else { 2988 fprintf(where, 2989 cpu_fmt_0, 2990 remote_service_demand, 2991 local_cpu_method); 2992 } 2993 break; 2994 case 1: 2995 case 2: 2996 if (print_headers) { 2997 fprintf(where, 2998 cpu_title, 2999 format_units(), 3000 local_cpu_method, 3001 remote_cpu_method); 3002 } 3003 3004 fprintf(where, 3005 cpu_fmt_1, /* the format string */ 3006 lss_size, /* local sendbuf size */ 3007 send_size, /* how large were the sends */ 3008 elapsed_time, /* how long was the test */ 3009 messages_sent, 3010 failed_sends, 3011 local_thruput, /* what was the xfer rate */ 3012 local_cpu_utilization, /* local cpu */ 3013 local_service_demand, /* local service demand */ 3014 rsr_size, 3015 elapsed_time, 3016 messages_recvd, 3017 remote_thruput, 3018 remote_cpu_utilization, /* remote cpu */ 3019 remote_service_demand); /* remote service demand */ 3020 break; 3021 } 3022 } 3023 else { 3024 /* The tester did not wish to measure service demand. */ 3025 switch (verbosity) { 3026 case 0: 3027 fprintf(where, 3028 tput_fmt_0, 3029 local_thruput); 3030 break; 3031 case 1: 3032 case 2: 3033 if (print_headers) { 3034 fprintf(where,tput_title,format_units()); 3035 } 3036 fprintf(where, 3037 tput_fmt_1, /* the format string */ 3038 lss_size, /* local sendbuf size */ 3039 send_size, /* how large were the sends */ 3040 elapsed_time, /* how long did it take */ 3041 messages_sent, 3042 failed_sends, 3043 local_thruput, 3044 rsr_size, /* remote recvbuf size */ 3045 elapsed_time, 3046 messages_recvd, 3047 remote_thruput); 3048 break; 3049 } 3050 } 3051 3052 fflush(where); 3053 #ifdef WANT_HISTOGRAM 3054 if (verbosity > 1) { 3055 fprintf(where,"\nHistogram of time spent in send() call\n"); 3056 fflush(where); 3057 HIST_report(time_hist); 3058 } 3059 #endif /* WANT_HISTOGRAM */ 3060 3061 } 3062 3063 3065 /* this routine implements the receive side (netserver) of the */ 3066 /* XTI_UDP_STREAM performance test. */ 3067 3068 void 3069 recv_xti_udp_stream() 3070 { 3071 struct ring_elt *recv_ring; 3072 3073 struct t_bind bind_req, bind_resp; 3074 struct t_unitdata unitdata; 3075 int flags = 0; 3076 3077 struct sockaddr_in myaddr_in; 3078 struct sockaddr_in fromaddr_in; 3079 3080 SOCKET s_data; 3081 int addrlen; 3082 unsigned int bytes_received = 0; 3083 float elapsed_time; 3084 3085 unsigned int message_size; 3086 unsigned int messages_recvd = 0; 3087 3088 struct xti_udp_stream_request_struct *xti_udp_stream_request; 3089 struct xti_udp_stream_response_struct *xti_udp_stream_response; 3090 struct xti_udp_stream_results_struct *xti_udp_stream_results; 3091 3092 xti_udp_stream_request = 3093 (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data; 3094 xti_udp_stream_response = 3095 (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data; 3096 xti_udp_stream_results = 3097 (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data; 3098 3099 if (debug) { 3100 fprintf(where,"netserver: recv_xti_udp_stream: entered...\n"); 3101 fflush(where); 3102 } 3103 3104 /* We want to set-up the listen socket with all the desired */ 3105 /* parameters and then let the initiator know that all is ready. If */ 3106 /* socket size defaults are to be used, then the initiator will have */ 3107 /* sent us 0's. If the socket sizes cannot be changed, then we will */ 3108 /* send-back what they are. If that information cannot be determined, */ 3109 /* then we send-back -1's for the sizes. If things go wrong for any */ 3110 /* reason, we will drop back ten yards and punt. */ 3111 3112 /* If anything goes wrong, we want the remote to know about it. It */ 3113 /* would be best if the error that the remote reports to the user is */ 3114 /* the actual error we encountered, rather than some bogus unexpected */ 3115 /* response type message. */ 3116 3117 if (debug > 1) { 3118 fprintf(where,"recv_xti_udp_stream: setting the response type...\n"); 3119 fflush(where); 3120 } 3121 3122 netperf_response.content.response_type = XTI_UDP_STREAM_RESPONSE; 3123 3124 if (debug > 2) { 3125 fprintf(where,"recv_xti_udp_stream: the response type is set...\n"); 3126 fflush(where); 3127 } 3128 3129 /* We now alter the message_ptr variable to be at the desired */ 3130 /* alignment with the desired offset. */ 3131 3132 if (debug > 1) { 3133 fprintf(where,"recv_xti_udp_stream: requested alignment of %d\n", 3134 xti_udp_stream_request->recv_alignment); 3135 fflush(where); 3136 } 3137 3138 if (recv_width == 0) recv_width = 1; 3139 3140 recv_ring = allocate_buffer_ring(recv_width, 3141 xti_udp_stream_request->message_size, 3142 xti_udp_stream_request->recv_alignment, 3143 xti_udp_stream_request->recv_offset); 3144 3145 if (debug > 1) { 3146 fprintf(where,"recv_xti_udp_stream: receive alignment and offset set...\n"); 3147 fflush(where); 3148 } 3149 3150 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ 3151 /* can put in OUR values !-) At some point, we may want to nail this */ 3152 /* socket to a particular network-level address, but for now, */ 3153 /* INADDR_ANY should be just fine. */ 3154 3155 bzero((char *)&myaddr_in, 3156 sizeof(myaddr_in)); 3157 myaddr_in.sin_family = AF_INET; 3158 myaddr_in.sin_addr.s_addr = INADDR_ANY; 3159 myaddr_in.sin_port = 0; 3160 3161 /* Grab a socket to listen on, and then listen on it. */ 3162 3163 if (debug > 1) { 3164 fprintf(where,"recv_xti_udp_stream: grabbing a socket...\n"); 3165 fflush(where); 3166 } 3167 3168 /* create_xti_endpoint expects to find some things in the global */ 3169 /* variables, so set the globals based on the values in the request. */ 3170 /* once the socket has been created, we will set the response values */ 3171 /* based on the updated value of those globals. raj 7/94 */ 3172 lsr_size = xti_udp_stream_request->recv_buf_size; 3173 loc_rcvavoid = xti_udp_stream_request->so_rcvavoid; 3174 loc_sndavoid = xti_udp_stream_request->so_sndavoid; 3175 3176 #ifdef __alpha 3177 3178 /* ok - even on a DEC box, strings are strings. I din't really want */ 3179 /* to ntohl the words of a string. since I don't want to teach the */ 3180 /* send_ and recv_ _request and _response routines about the types, */ 3181 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ 3182 /* solution would be to use XDR, but I am still leary of being able */ 3183 /* to find XDR libs on all platforms I want running netperf. raj */ 3184 { 3185 int *charword; 3186 int *initword; 3187 int *lastword; 3188 3189 initword = (int *) xti_udp_stream_request->xti_device; 3190 lastword = initword + ((xti_udp_stream_request->dev_name_len + 3) / 4); 3191 3192 for (charword = initword; 3193 charword < lastword; 3194 charword++) { 3195 3196 *charword = htonl(*charword); 3197 } 3198 } 3199 3200 #endif /* __alpha */ 3201 3202 s_data = create_xti_endpoint(xti_udp_stream_request->xti_device); 3203 3204 if (s_data == INVALID_SOCKET) { 3205 netperf_response.content.serv_errno = errno; 3206 send_response(); 3207 exit(1); 3208 } 3209 3210 /* Let's get an address assigned to this socket so we can tell the */ 3211 /* initiator how to reach the data socket. There may be a desire to */ 3212 /* nail this socket to a specific IP address in a multi-homed, */ 3213 /* multi-connection situation, but for now, we'll ignore the issue */ 3214 /* and concentrate on single connection testing. */ 3215 3216 bind_req.addr.maxlen = sizeof(struct sockaddr_in); 3217 bind_req.addr.len = sizeof(struct sockaddr_in); 3218 bind_req.addr.buf = (char *)&myaddr_in; 3219 bind_req.qlen = 1; 3220 3221 bind_resp.addr.maxlen = sizeof(struct sockaddr_in); 3222 bind_resp.addr.len = sizeof(struct sockaddr_in); 3223 bind_resp.addr.buf = (char *)&myaddr_in; 3224 bind_resp.qlen = 1; 3225 3226 if (t_bind(s_data, 3227 &bind_req, 3228 &bind_resp) == SOCKET_ERROR) { 3229 netperf_response.content.serv_errno = t_errno; 3230 send_response(); 3231 3232 exit(1); 3233 } 3234 3235 xti_udp_stream_response->test_length = 3236 xti_udp_stream_request->test_length; 3237 3238 /* Now myaddr_in contains the port and the internet address this is */ 3239 /* returned to the sender also implicitly telling the sender that the */ 3240 /* socket buffer sizing has been done. */ 3241 3242 xti_udp_stream_response->data_port_number = 3243 (int) ntohs(myaddr_in.sin_port); 3244 netperf_response.content.serv_errno = 0; 3245 3246 /* But wait, there's more. If the initiator wanted cpu measurements, */ 3247 /* then we must call the calibrate routine, which will return the max */ 3248 /* rate back to the initiator. If the CPU was not to be measured, or */ 3249 /* something went wrong with the calibration, we will return a -1 to */ 3250 /* the initiator. */ 3251 3252 xti_udp_stream_response->cpu_rate = 0.0; /* assume no cpu */ 3253 xti_udp_stream_response->measure_cpu = 0; 3254 if (xti_udp_stream_request->measure_cpu) { 3255 /* We will pass the rate into the calibration routine. If the */ 3256 /* user did not specify one, it will be 0.0, and we will do a */ 3257 /* "real" calibration. Otherwise, all it will really do is */ 3258 /* store it away... */ 3259 xti_udp_stream_response->measure_cpu = 1; 3260 xti_udp_stream_response->cpu_rate = 3261 calibrate_local_cpu(xti_udp_stream_request->cpu_rate); 3262 } 3263 3264 message_size = xti_udp_stream_request->message_size; 3265 test_time = xti_udp_stream_request->test_length; 3266 3267 /* before we send the response back to the initiator, pull some of */ 3268 /* the socket parms from the globals */ 3269 xti_udp_stream_response->send_buf_size = lss_size; 3270 xti_udp_stream_response->recv_buf_size = lsr_size; 3271 xti_udp_stream_response->so_rcvavoid = loc_rcvavoid; 3272 xti_udp_stream_response->so_sndavoid = loc_sndavoid; 3273 3274 /* since we are going to call t_rcvudata() instead of t_rcv() we */ 3275 /* need to init the unitdata structure raj 3/95 */ 3276 3277 unitdata.addr.maxlen = sizeof(fromaddr_in); 3278 unitdata.addr.len = sizeof(fromaddr_in); 3279 unitdata.addr.buf = (char *)&fromaddr_in; 3280 3281 unitdata.opt.maxlen = 0; 3282 unitdata.opt.len = 0; 3283 unitdata.opt.buf = NULL; 3284 3285 unitdata.udata.maxlen = xti_udp_stream_request->message_size; 3286 unitdata.udata.len = xti_udp_stream_request->message_size; 3287 unitdata.udata.buf = recv_ring->buffer_ptr; 3288 3289 send_response(); 3290 3291 /* Now it's time to start receiving data on the connection. We will */ 3292 /* first grab the apropriate counters and then start grabbing. */ 3293 3294 cpu_start(xti_udp_stream_request->measure_cpu); 3295 3296 /* The loop will exit when the timer pops, or if we happen to recv a */ 3297 /* message of less than send_size bytes... */ 3298 3299 times_up = 0; 3300 start_timer(test_time + PAD_TIME); 3301 3302 if (debug) { 3303 fprintf(where,"recv_xti_udp_stream: about to enter inner sanctum.\n"); 3304 fflush(where); 3305 } 3306 3307 while (!times_up) { 3308 #ifdef RAJ_DEBUG 3309 if (debug) { 3310 fprintf(where,"t_rcvudata, errno %d, t_errno %d", 3311 errno, 3312 t_errno); 3313 fprintf(where," after %d messages\n",messages_recvd); 3314 fprintf(where,"addrmax %d addrlen %d addrbuf %x\n", 3315 unitdata.addr.maxlen, 3316 unitdata.addr.len, 3317 unitdata.addr.buf); 3318 fprintf(where,"optmax %d optlen %d optbuf %x\n", 3319 unitdata.opt.maxlen, 3320 unitdata.opt.len, 3321 unitdata.opt.buf); 3322 fprintf(where,"udatamax %d udatalen %d udatabuf %x\n", 3323 unitdata.udata.maxlen, 3324 unitdata.udata.len, 3325 unitdata.udata.buf); 3326 fflush(where); 3327 } 3328 #endif /* RAJ_DEBUG */ 3329 if (t_rcvudata(s_data, 3330 &unitdata, 3331 &flags) != 0) { 3332 if (errno == TNODATA) { 3333 continue; 3334 } 3335 if (errno != EINTR) { 3336 netperf_response.content.serv_errno = t_errno; 3337 send_response(); 3338 exit(1); 3339 } 3340 break; 3341 } 3342 messages_recvd++; 3343 recv_ring = recv_ring->next; 3344 unitdata.udata.buf = recv_ring->buffer_ptr; 3345 } 3346 3347 if (debug) { 3348 fprintf(where,"recv_xti_udp_stream: got %d messages.\n",messages_recvd); 3349 fflush(where); 3350 } 3351 3352 3353 /* The loop now exits due timer or < send_size bytes received. */ 3354 3355 cpu_stop(xti_udp_stream_request->measure_cpu,&elapsed_time); 3356 3357 if (times_up) { 3358 /* we ended on a timer, subtract the PAD_TIME */ 3359 elapsed_time -= (float)PAD_TIME; 3360 } 3361 else { 3362 stop_timer(); 3363 } 3364 3365 if (debug) { 3366 fprintf(where,"recv_xti_udp_stream: test ended in %f seconds.\n",elapsed_time); 3367 fflush(where); 3368 } 3369 3370 bytes_received = (messages_recvd * message_size); 3371 3372 /* send the results to the sender */ 3373 3374 if (debug) { 3375 fprintf(where, 3376 "recv_xti_udp_stream: got %d bytes\n", 3377 bytes_received); 3378 fflush(where); 3379 } 3380 3381 netperf_response.content.response_type = XTI_UDP_STREAM_RESULTS; 3382 xti_udp_stream_results->bytes_received = bytes_received; 3383 xti_udp_stream_results->messages_recvd = messages_recvd; 3384 xti_udp_stream_results->elapsed_time = elapsed_time; 3385 xti_udp_stream_results->cpu_method = cpu_method; 3386 if (xti_udp_stream_request->measure_cpu) { 3387 xti_udp_stream_results->cpu_util = calc_cpu_util(elapsed_time); 3388 } 3389 else { 3390 xti_udp_stream_results->cpu_util = -1.0; 3391 } 3392 3393 if (debug > 1) { 3394 fprintf(where, 3395 "recv_xti_udp_stream: test complete, sending results.\n"); 3396 fflush(where); 3397 } 3398 3399 send_response(); 3400 3401 } 3402 3403 void send_xti_udp_rr(char remote_host[]) 3405 { 3406 3407 char *tput_title = "\ 3408 Local /Remote\n\ 3409 Socket Size Request Resp. Elapsed Trans.\n\ 3410 Send Recv Size Size Time Rate \n\ 3411 bytes Bytes bytes bytes secs. per sec \n\n"; 3412 3413 char *tput_fmt_0 = 3414 "%7.2f\n"; 3415 3416 char *tput_fmt_1_line_1 = "\ 3417 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; 3418 char *tput_fmt_1_line_2 = "\ 3419 %-6d %-6d\n"; 3420 3421 char *cpu_title = "\ 3422 Local /Remote\n\ 3423 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ 3424 Send Recv Size Size Time Rate local remote local remote\n\ 3425 bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; 3426 3427 char *cpu_fmt_0 = 3428 "%6.3f %c\n"; 3429 3430 char *cpu_fmt_1_line_1 = "\ 3431 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; 3432 3433 char *cpu_fmt_1_line_2 = "\ 3434 %-6d %-6d\n"; 3435 3436 char *ksink_fmt = "\ 3437 Alignment Offset\n\ 3438 Local Remote Local Remote\n\ 3439 Send Recv Send Recv\n\ 3440 %5d %5d %5d %5d\n"; 3441 3442 3443 float elapsed_time; 3444 3445 struct ring_elt *send_ring; 3446 struct ring_elt *recv_ring; 3447 3448 struct t_bind bind_req, bind_resp; 3449 struct t_unitdata unitdata; 3450 struct t_unitdata send_unitdata; 3451 struct t_unitdata recv_unitdata; 3452 int flags = 0; 3453 3454 int len; 3455 int nummessages; 3456 SOCKET send_socket; 3457 int trans_remaining; 3458 int bytes_xferd; 3459 3460 int rsp_bytes_recvd; 3461 3462 float local_cpu_utilization; 3463 float local_service_demand; 3464 float remote_cpu_utilization; 3465 float remote_service_demand; 3466 double thruput; 3467 3468 struct hostent *hp; 3469 struct sockaddr_in server, myaddr_in; 3470 unsigned int addr; 3471 int addrlen; 3472 3473 struct xti_udp_rr_request_struct *xti_udp_rr_request; 3474 struct xti_udp_rr_response_struct *xti_udp_rr_response; 3475 struct xti_udp_rr_results_struct *xti_udp_rr_result; 3476 3477 #ifdef WANT_INTERVALS 3478 int interval_count; 3479 sigset_t signal_set; 3480 #endif /* WANT_INTERVALS */ 3481 3482 xti_udp_rr_request = 3483 (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data; 3484 xti_udp_rr_response = 3485 (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data; 3486 xti_udp_rr_result = 3487 (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data; 3488 3489 #ifdef WANT_HISTOGRAM 3490 time_hist = HIST_new(); 3491 #endif 3492 3493 /* since we are now disconnected from the code that established the */ 3494 /* control socket, and since we want to be able to use different */ 3495 /* protocols and such, we are passed the name of the remote host and */ 3496 /* must turn that into the test specific addressing information. */ 3497 3498 bzero((char *)&server, 3499 sizeof(server)); 3500 3501 /* it would seem that while HP-UX will allow an IP address (as a */ 3502 /* string) in a call to gethostbyname, other, less enlightened */ 3503 /* systems do not. fix from awjacks (at) ca.sandia.gov raj 10/95 */ 3504 /* order changed to check for IP address first. raj 7/96 */ 3505 3506 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) { 3507 /* it was not an IP address, try it as a name */ 3508 if ((hp = gethostbyname(remote_host)) == NULL) { 3509 /* we have no idea what it is */ 3510 fprintf(where, 3511 "establish_control: could not resolve the destination %s\n", 3512 remote_host); 3513 fflush(where); 3514 exit(1); 3515 } 3516 else { 3517 /* it was a valid remote_host */ 3518 bcopy(hp->h_addr, 3519 (char *)&server.sin_addr, 3520 hp->h_length); 3521 server.sin_family = hp->h_addrtype; 3522 } 3523 } 3524 else { 3525 /* it was a valid IP address */ 3526 server.sin_addr.s_addr = addr; 3527 server.sin_family = AF_INET; 3528 } 3529 3530 if ( print_headers ) { 3531 fprintf(where,"XTI UDP REQUEST/RESPONSE TEST"); 3532 fprintf(where," to %s", remote_host); 3533 if (iteration_max > 1) { 3534 fprintf(where, 3535 " : +/-%3.1f%% @ %2d%% conf.", 3536 interval/0.02, 3537 confidence_level); 3538 } 3539 if (loc_sndavoid || 3540 loc_rcvavoid || 3541 rem_sndavoid || 3542 rem_rcvavoid) { 3543 fprintf(where," : copy avoidance"); 3544 } 3545 #ifdef WANT_HISTOGRAM 3546 fprintf(where," : histogram"); 3547 #endif /* WANT_HISTOGRAM */ 3548 #ifdef WANT_INTERVALS 3549 fprintf(where," : interval"); 3550 #endif /* WANT_INTERVALS */ 3551 #ifdef DIRTY 3552 fprintf(where," : dirty data"); 3553 #endif /* DIRTY */ 3554 fprintf(where,"\n"); 3555 } 3556 3557 /* initialize a few counters */ 3558 3559 send_ring = NULL; 3560 recv_ring = NULL; 3561 nummessages = 0; 3562 bytes_xferd = 0; 3563 times_up = 0; 3564 confidence_iteration = 1; 3565 init_stat(); 3566 3567 3568 /* we have a great-big while loop which controls the number of times */ 3569 /* we run a particular test. this is for the calculation of a */ 3570 /* confidence interval (I really should have stayed awake during */ 3571 /* probstats :). If the user did not request confidence measurement */ 3572 /* (no confidence is the default) then we will only go though the */ 3573 /* loop once. the confidence stuff originates from the folks at IBM */ 3574 3575 while (((confidence < 0) && (confidence_iteration < iteration_max)) || 3576 (confidence_iteration <= iteration_min)) { 3577 3578 nummessages = 0; 3579 bytes_xferd = 0.0; 3580 times_up = 0; 3581 trans_remaining = 0; 3582 3583 /* set-up the data buffers with the requested alignment and offset */ 3584 3585 if (send_width == 0) send_width = 1; 3586 if (recv_width == 0) recv_width = 1; 3587 3588 if (send_ring == NULL) { 3589 send_ring = allocate_buffer_ring(send_width, 3590 req_size, 3591 local_send_align, 3592 local_send_offset); 3593 } 3594 3595 if (recv_ring == NULL) { 3596 recv_ring = allocate_buffer_ring(recv_width, 3597 rsp_size, 3598 local_recv_align, 3599 local_recv_offset); 3600 } 3601 3602 /* since we are going to call t_rcvudata() instead of t_rcv() we */ 3603 /* need to init the unitdata structure raj 8/95 */ 3604 3605 memset (&recv_unitdata, 0, sizeof(recv_unitdata)); 3606 recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in); 3607 recv_unitdata.addr.len = sizeof(struct sockaddr_in); 3608 recv_unitdata.addr.buf = (char *)&server; 3609 3610 recv_unitdata.opt.maxlen = 0; 3611 recv_unitdata.opt.len = 0; 3612 recv_unitdata.opt.buf = NULL; 3613 3614 recv_unitdata.udata.maxlen = rsp_size; 3615 recv_unitdata.udata.len = rsp_size; 3616 recv_unitdata.udata.buf = recv_ring->buffer_ptr; 3617 3618 /* since we are going to call t_sndudata() instead of t_snd() we */ 3619 /* need to init the unitdata structure raj 8/95 */ 3620 3621 memset (&send_unitdata, 0, sizeof(send_unitdata)); 3622 send_unitdata.addr.maxlen = sizeof(struct sockaddr_in); 3623 send_unitdata.addr.len = sizeof(struct sockaddr_in); 3624 send_unitdata.addr.buf = (char *)&server; 3625 3626 send_unitdata.opt.maxlen = 0; 3627 send_unitdata.opt.len = 0; 3628 send_unitdata.opt.buf = NULL; 3629 3630 send_unitdata.udata.maxlen = req_size; 3631 send_unitdata.udata.len = req_size; 3632 send_unitdata.udata.buf = send_ring->buffer_ptr; 3633 3634 /*set up the data socket */ 3635 send_socket = create_xti_endpoint(loc_xti_device); 3636 3637 if (send_socket == INVALID_SOCKET){ 3638 perror("netperf: send_xti_udp_rr: udp rr data socket"); 3639 exit(1); 3640 } 3641 3642 if (debug) { 3643 fprintf(where,"send_xti_udp_rr: send_socket obtained...\n"); 3644 } 3645 3646 /* it would seem that with XTI, there is no implicit bind */ 3647 /* so we have to make a call to t_bind. this is not */ 3648 /* terribly convenient, but I suppose that "standard is better */ 3649 /* than better" :) raj 2/95 */ 3650 3651 if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) { 3652 t_error("send_xti_tcp_stream: t_bind"); 3653 exit(1); 3654 } 3655 3656 /* If the user has requested cpu utilization measurements, we must */ 3657 /* calibrate the cpu(s). We will perform this task within the tests */ 3658 /* themselves. If the user has specified the cpu rate, then */ 3659 /* calibrate_local_cpu will return rather quickly as it will have */ 3660 /* nothing to do. If local_cpu_rate is zero, then we will go through */ 3661 /* all the "normal" calibration stuff and return the rate back. If */ 3662 /* there is no idle counter in the kernel idle loop, the */ 3663 /* local_cpu_rate will be set to -1. */ 3664 3665 if (local_cpu_usage) { 3666 local_cpu_rate = calibrate_local_cpu(local_cpu_rate); 3667 } 3668 3669 /* Tell the remote end to do a listen. The server alters the socket */ 3670 /* paramters on the other side at this point, hence the reason for */ 3671 /* all the values being passed in the setup message. If the user did */ 3672 /* not specify any of the parameters, they will be passed as 0, which */ 3673 /* will indicate to the remote that no changes beyond the system's */ 3674 /* default should be used. Alignment is the exception, it will */ 3675 /* default to 8, which will be no alignment alterations. */ 3676 3677 netperf_request.content.request_type = DO_XTI_UDP_RR; 3678 xti_udp_rr_request->recv_buf_size = rsr_size; 3679 xti_udp_rr_request->send_buf_size = rss_size; 3680 xti_udp_rr_request->recv_alignment = remote_recv_align; 3681 xti_udp_rr_request->recv_offset = remote_recv_offset; 3682 xti_udp_rr_request->send_alignment = remote_send_align; 3683 xti_udp_rr_request->send_offset = remote_send_offset; 3684 xti_udp_rr_request->request_size = req_size; 3685 xti_udp_rr_request->response_size = rsp_size; 3686 xti_udp_rr_request->measure_cpu = remote_cpu_usage; 3687 xti_udp_rr_request->cpu_rate = remote_cpu_rate; 3688 xti_udp_rr_request->so_rcvavoid = rem_rcvavoid; 3689 xti_udp_rr_request->so_sndavoid = rem_sndavoid; 3690 if (test_time) { 3691 xti_udp_rr_request->test_length = test_time; 3692 } 3693 else { 3694 xti_udp_rr_request->test_length = test_trans * -1; 3695 } 3696 3697 strcpy(xti_udp_rr_request->xti_device, rem_xti_device); 3698 3699 #ifdef __alpha 3700 3701 /* ok - even on a DEC box, strings are strings. I didn't really want */ 3702 /* to ntohl the words of a string. since I don't want to teach the */ 3703 /* send_ and recv_ _request and _response routines about the types, */ 3704 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ 3705 /* solution would be to use XDR, but I am still leary of being able */ 3706 /* to find XDR libs on all platforms I want running netperf. raj */ 3707 { 3708 int *charword; 3709 int *initword; 3710 int *lastword; 3711 3712 initword = (int *) xti_udp_rr_request->xti_device; 3713 lastword = initword + ((strlen(rem_xti_device) + 3) / 4); 3714 3715 for (charword = initword; 3716 charword < lastword; 3717 charword++) { 3718 3719 *charword = ntohl(*charword); 3720 } 3721 } 3722 #endif /* __alpha */ 3723 3724 if (debug > 1) { 3725 fprintf(where,"netperf: send_xti_udp_rr: requesting UDP r/r test\n"); 3726 } 3727 3728 send_request(); 3729 3730 /* The response from the remote will contain all of the relevant */ 3731 /* socket parameters for this test type. We will put them back into */ 3732 /* the variables here so they can be displayed if desired. The */ 3733 /* remote will have calibrated CPU if necessary, and will have done */ 3734 /* all the needed set-up we will have calibrated the cpu locally */ 3735 /* before sending the request, and will grab the counter value right*/ 3736 /* after the connect returns. The remote will grab the counter right*/ 3737 /* after the accept call. This saves the hassle of extra messages */ 3738 /* being sent for the UDP tests. */ 3739 3740 recv_response(); 3741 3742 if (!netperf_response.content.serv_errno) { 3743 if (debug) 3744 fprintf(where,"remote listen done.\n"); 3745 rsr_size = xti_udp_rr_response->recv_buf_size; 3746 rss_size = xti_udp_rr_response->send_buf_size; 3747 remote_cpu_usage = xti_udp_rr_response->measure_cpu; 3748 remote_cpu_rate = xti_udp_rr_response->cpu_rate; 3749 /* port numbers in proper order */ 3750 server.sin_port = (short)xti_udp_rr_response->data_port_number; 3751 server.sin_port = htons(server.sin_port); 3752 } 3753 else { 3754 Set_errno(netperf_response.content.serv_errno); 3755 perror("netperf: remote error"); 3756 3757 exit(1); 3758 } 3759 3760 /* Data Socket set-up is finished. If there were problems, either the */ 3761 /* connect would have failed, or the previous response would have */ 3762 /* indicated a problem. I failed to see the value of the extra */ 3763 /* message after the accept on the remote. If it failed, we'll see it */ 3764 /* here. If it didn't, we might as well start pumping data. */ 3765 3766 /* Set-up the test end conditions. For a request/response test, they */ 3767 /* can be either time or transaction based. */ 3768 3769 if (test_time) { 3770 /* The user wanted to end the test after a period of time. */ 3771 times_up = 0; 3772 trans_remaining = 0; 3773 start_timer(test_time); 3774 } 3775 else { 3776 /* The tester wanted to send a number of bytes. */ 3777 trans_remaining = test_bytes; 3778 times_up = 1; 3779 } 3780 3781 /* The cpu_start routine will grab the current time and possibly */ 3782 /* value of the idle counter for later use in measuring cpu */ 3783 /* utilization and/or service demand and thruput. */ 3784 3785 cpu_start(local_cpu_usage); 3786 3787 #ifdef WANT_INTERVALS 3788 if ((interval_burst) || (demo_mode)) { 3789 /* zero means that we never pause, so we never should need the */ 3790 /* interval timer, unless we are in demo_mode */ 3791 start_itimer(interval_wate); 3792 } 3793 interval_count = interval_burst; 3794 /* get the signal set for the call to sigsuspend */ 3795 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { 3796 fprintf(where, 3797 "send_xti_udp_rr: unable to get sigmask errno %d\n", 3798 errno); 3799 fflush(where); 3800 exit(1); 3801 } 3802 #endif /* WANT_INTERVALS */ 3803 3804 /* We use an "OR" to control test execution. When the test is */ 3805 /* controlled by time, the byte count check will always return */ 3806 /* false. When the test is controlled by byte count, the time test */ 3807 /* will always return false. When the test is finished, the whole */ 3808 /* expression will go false and we will stop sending data. I think */ 3809 /* I just arbitrarily decrement trans_remaining for the timed */ 3810 /* test, but will not do that just yet... One other question is */ 3811 /* whether or not the send buffer and the receive buffer should be */ 3812 /* the same buffer. */ 3813 3814 while ((!times_up) || (trans_remaining > 0)) { 3815 /* send the request */ 3816 #ifdef WANT_HISTOGRAM 3817 HIST_timestamp(&time_one); 3818 #endif 3819 if((t_sndudata(send_socket, 3820 &send_unitdata)) != 0) { 3821 if (errno == EINTR) { 3822 /* We likely hit */ 3823 /* test-end time. */ 3824 break; 3825 } 3826 fprintf(where, 3827 "send_xti_udp_rr: t_sndudata: errno %d t_errno %d t_look 0x%.4x\n", 3828 errno, 3829 t_errno, 3830 t_look(send_socket)); 3831 fflush(where); 3832 exit(1); 3833 } 3834 send_ring = send_ring->next; 3835 3836 /* receive the response. with UDP we will get it all, or nothing */ 3837 3838 if((t_rcvudata(send_socket, 3839 &recv_unitdata, 3840 &flags)) != 0) { 3841 if (errno == TNODATA) { 3842 continue; 3843 } 3844 if (errno == EINTR) { 3845 /* Again, we have likely hit test-end time */ 3846 break; 3847 } 3848 fprintf(where, 3849 "send_xti_udp_rr: t_rcvudata: errno %d t_errno %d t_look 0x%x\n", 3850 errno, 3851 t_errno, 3852 t_look(send_socket)); 3853 fprintf(where, 3854 "recv_unitdata.udata.buf %x\n",recv_unitdata.udata.buf); 3855 fprintf(where, 3856 "recv_unitdata.udata.maxlen %x\n",recv_unitdata.udata.maxlen); 3857 fprintf(where, 3858 "recv_unitdata.udata.len %x\n",recv_unitdata.udata.len); 3859 fprintf(where, 3860 "recv_unitdata.addr.buf %x\n",recv_unitdata.addr.buf); 3861 fprintf(where, 3862 "recv_unitdata.addr.maxlen %x\n",recv_unitdata.addr.maxlen); 3863 fprintf(where, 3864 "recv_unitdata.addr.len %x\n",recv_unitdata.addr.len); 3865 fflush(where); 3866 exit(1); 3867 } 3868 recv_ring = recv_ring->next; 3869 3870 #ifdef WANT_HISTOGRAM 3871 HIST_timestamp(&time_two); 3872 HIST_add(time_hist,delta_micro(&time_one,&time_two)); 3873 3874 /* at this point, we may wish to sleep for some period of */ 3875 /* time, so we see how long that last transaction just took, */ 3876 /* and sleep for the difference of that and the interval. We */ 3877 /* will not sleep if the time would be less than a */ 3878 /* millisecond. */ 3879 #endif 3880 #ifdef WANT_INTERVALS 3881 if (demo_mode) { 3882 units_this_tick += 1; 3883 } 3884 /* in this case, the interval count is the count-down couter */ 3885 /* to decide to sleep for a little bit */ 3886 if ((interval_burst) && (--interval_count == 0)) { 3887 /* call sigsuspend and wait for the interval timer to get us */ 3888 /* out */ 3889 if (debug) { 3890 fprintf(where,"about to suspend\n"); 3891 fflush(where); 3892 } 3893 if (sigsuspend(&signal_set) == EFAULT) { 3894 fprintf(where, 3895 "send_xti_udp_rr: fault with signal set!\n"); 3896 fflush(where); 3897 exit(1); 3898 } 3899 interval_count = interval_burst; 3900 } 3901 #endif /* WANT_INTERVALS */ 3902 3903 nummessages++; 3904 if (trans_remaining) { 3905 trans_remaining--; 3906 } 3907 3908 if (debug > 3) { 3909 if ((nummessages % 100) == 0) { 3910 fprintf(where,"Transaction %d completed\n",nummessages); 3911 fflush(where); 3912 } 3913 } 3914 3915 } 3916 3917 /* this call will always give us the elapsed time for the test, and */ 3918 /* will also store-away the necessaries for cpu utilization */ 3919 3920 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ 3921 /* measured? how long */ 3922 /* did we really run? */ 3923 3924 /* Get the statistics from the remote end. The remote will have */ 3925 /* calculated service demand and all those interesting things. If */ 3926 /* it wasn't supposed to care, it will return obvious values. */ 3927 3928 recv_response(); 3929 if (!netperf_response.content.serv_errno) { 3930 if (debug) 3931 fprintf(where,"remote results obtained\n"); 3932 } 3933 else { 3934 Set_errno(netperf_response.content.serv_errno); 3935 perror("netperf: remote error"); 3936 3937 exit(1); 3938 } 3939 3940 /* We now calculate what our thruput was for the test. In the */ 3941 /* future, we may want to include a calculation of the thruput */ 3942 /* measured by the remote, but it should be the case that for a */ 3943 /* UDP rr test, that the two numbers should be *very* close... */ 3944 /* We calculate bytes_sent regardless of the way the test length */ 3945 /* was controlled. */ 3946 3947 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); 3948 thruput = nummessages / elapsed_time; 3949 3950 if (local_cpu_usage || remote_cpu_usage) { 3951 3952 /* We must now do a little math for service demand and cpu */ 3953 /* utilization for the system(s) Of course, some of the */ 3954 /* information might be bogus because there was no idle counter */ 3955 /* in the kernel(s). We need to make a note of this for the */ 3956 /* user's benefit by placing a code for the metod used in the */ 3957 /* test banner */ 3958 3959 if (local_cpu_usage) { 3960 local_cpu_utilization = calc_cpu_util(0.0); 3961 3962 /* since calc_service demand is doing ms/Kunit we will */ 3963 /* multiply the number of transaction by 1024 to get */ 3964 /* "good" numbers */ 3965 3966 local_service_demand = calc_service_demand((double) nummessages*1024, 3967 0.0, 3968 0.0, 3969 0); 3970 } 3971 else { 3972 local_cpu_utilization = -1.0; 3973 local_service_demand = -1.0; 3974 } 3975 3976 if (remote_cpu_usage) { 3977 remote_cpu_utilization = xti_udp_rr_result->cpu_util; 3978 3979 /* since calc_service demand is doing ms/Kunit we will */ 3980 /* multiply the number of transaction by 1024 to get */ 3981 /* "good" numbers */ 3982 3983 remote_service_demand = calc_service_demand((double) nummessages*1024, 3984 0.0, 3985 remote_cpu_utilization, 3986 xti_udp_rr_result->num_cpus); 3987 } 3988 else { 3989 remote_cpu_utilization = -1.0; 3990 remote_service_demand = -1.0; 3991 } 3992 } 3993 else { 3994 /* we were not measuring cpu, for the confidence stuff, we */ 3995 /* should make it -1.0 */ 3996 local_cpu_utilization = -1.0; 3997 local_service_demand = -1.0; 3998 remote_cpu_utilization = -1.0; 3999 remote_service_demand = -1.0; 4000 } 4001 4002 /* at this point, we want to calculate the confidence information. */ 4003 /* if debugging is on, calculate_confidence will print-out the */ 4004 /* parameters we pass it */ 4005 4006 calculate_confidence(confidence_iteration, 4007 elapsed_time, 4008 thruput, 4009 local_cpu_utilization, 4010 remote_cpu_utilization, 4011 local_service_demand, 4012 remote_service_demand); 4013 4014 4015 confidence_iteration++; 4016 4017 /* we are done with the socket */ 4018 t_close(send_socket); 4019 } 4020 4021 /* at this point, we have made all the iterations we are going to */ 4022 /* make. */ 4023 retrieve_confident_values(&elapsed_time, 4024 &thruput, 4025 &local_cpu_utilization, 4026 &remote_cpu_utilization, 4027 &local_service_demand, 4028 &remote_service_demand); 4029 4030 /* We are now ready to print all the information. If the user */ 4031 /* has specified zero-level verbosity, we will just print the */ 4032 /* local service demand, or the remote service demand. If the */ 4033 /* user has requested verbosity level 1, he will get the basic */ 4034 /* "streamperf" numbers. If the user has specified a verbosity */ 4035 /* of greater than 1, we will display a veritable plethora of */ 4036 /* background information from outside of this block as it it */ 4037 /* not cpu_measurement specific... */ 4038 4039 if (confidence < 0) { 4040 /* we did not hit confidence, but were we asked to look for it? */ 4041 if (iteration_max > 1) { 4042 display_confidence(); 4043 } 4044 } 4045 4046 if (local_cpu_usage || remote_cpu_usage) { 4047 local_cpu_method = format_cpu_method(cpu_method); 4048 remote_cpu_method = format_cpu_method(xti_udp_rr_result->cpu_method); 4049 4050 switch (verbosity) { 4051 case 0: 4052 if (local_cpu_usage) { 4053 fprintf(where, 4054 cpu_fmt_0, 4055 local_service_demand, 4056 local_cpu_method); 4057 } 4058 else { 4059 fprintf(where, 4060 cpu_fmt_0, 4061 remote_service_demand, 4062 remote_cpu_method); 4063 } 4064 break; 4065 case 1: 4066 case 2: 4067 if (print_headers) { 4068 fprintf(where, 4069 cpu_title, 4070 local_cpu_method, 4071 remote_cpu_method); 4072 } 4073 4074 fprintf(where, 4075 cpu_fmt_1_line_1, /* the format string */ 4076 lss_size, /* local sendbuf size */ 4077 lsr_size, 4078 req_size, /* how large were the requests */ 4079 rsp_size, /* guess */ 4080 elapsed_time, /* how long was the test */ 4081 nummessages/elapsed_time, 4082 local_cpu_utilization, /* local cpu */ 4083 remote_cpu_utilization, /* remote cpu */ 4084 local_service_demand, /* local service demand */ 4085 remote_service_demand); /* remote service demand */ 4086 fprintf(where, 4087 cpu_fmt_1_line_2, 4088 rss_size, 4089 rsr_size); 4090 break; 4091 } 4092 } 4093 else { 4094 /* The tester did not wish to measure service demand. */ 4095 switch (verbosity) { 4096 case 0: 4097 fprintf(where, 4098 tput_fmt_0, 4099 nummessages/elapsed_time); 4100 break; 4101 case 1: 4102 case 2: 4103 if (print_headers) { 4104 fprintf(where,tput_title,format_units()); 4105 } 4106 4107 fprintf(where, 4108 tput_fmt_1_line_1, /* the format string */ 4109 lss_size, 4110 lsr_size, 4111 req_size, /* how large were the requests */ 4112 rsp_size, /* how large were the responses */ 4113 elapsed_time, /* how long did it take */ 4114 nummessages/elapsed_time); 4115 fprintf(where, 4116 tput_fmt_1_line_2, 4117 rss_size, /* remote recvbuf size */ 4118 rsr_size); 4119 4120 break; 4121 } 4122 } 4123 fflush(where); 4124 4125 /* it would be a good thing to include information about some of the */ 4126 /* other parameters that may have been set for this test, but at the */ 4127 /* moment, I do not wish to figure-out all the formatting, so I will */ 4128 /* just put this comment here to help remind me that it is something */ 4129 /* that should be done at a later time. */ 4130 4131 /* how to handle the verbose information in the presence of */ 4132 /* confidence intervals is yet to be determined... raj 11/94 */ 4133 4134 if (verbosity > 1) { 4135 /* The user wanted to know it all, so we will give it to him. */ 4136 /* This information will include as much as we can find about */ 4137 /* UDP statistics, the alignments of the sends and receives */ 4138 /* and all that sort of rot... */ 4139 4140 #ifdef WANT_HISTOGRAM 4141 fprintf(where,"\nHistogram of request/reponse times.\n"); 4142 fflush(where); 4143 HIST_report(time_hist); 4144 #endif /* WANT_HISTOGRAM */ 4145 } 4146 } 4147 4148 /* this routine implements the receive side (netserver) of a XTI_UDP_RR */ 4150 /* test. */ 4151 void 4152 recv_xti_udp_rr() 4153 { 4154 4155 struct ring_elt *recv_ring; 4156 struct ring_elt *send_ring; 4157 4158 struct t_bind bind_req, bind_resp; 4159 struct t_unitdata send_unitdata; 4160 struct t_unitdata recv_unitdata; 4161 int flags = 0; 4162 4163 struct sockaddr_in myaddr_in, peeraddr_in; 4164 SOCKET s_data; 4165 int addrlen; 4166 int trans_received; 4167 int trans_remaining; 4168 float elapsed_time; 4169 4170 struct xti_udp_rr_request_struct *xti_udp_rr_request; 4171 struct xti_udp_rr_response_struct *xti_udp_rr_response; 4172 struct xti_udp_rr_results_struct *xti_udp_rr_results; 4173 4174 4175 /* a little variable initialization */ 4176 memset (&myaddr_in, 0, sizeof(struct sockaddr_in)); 4177 myaddr_in.sin_family = AF_INET; 4178 myaddr_in.sin_addr.s_addr = INADDR_ANY; 4179 myaddr_in.sin_port = 0; 4180 memset (&peeraddr_in, 0, sizeof(struct sockaddr_in)); 4181 4182 /* and some not so paranoid :) */ 4183 xti_udp_rr_request = 4184 (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data; 4185 xti_udp_rr_response = 4186 (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data; 4187 xti_udp_rr_results = 4188 (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data; 4189 4190 if (debug) { 4191 fprintf(where,"netserver: recv_xti_udp_rr: entered...\n"); 4192 fflush(where); 4193 } 4194 4195 /* We want to set-up the listen socket with all the desired */ 4196 /* parameters and then let the initiator know that all is ready. If */ 4197 /* socket size defaults are to be used, then the initiator will have */ 4198 /* sent us 0's. If the socket sizes cannot be changed, then we will */ 4199 /* send-back what they are. If that information cannot be determined, */ 4200 /* then we send-back -1's for the sizes. If things go wrong for any */ 4201 /* reason, we will drop back ten yards and punt. */ 4202 4203 /* If anything goes wrong, we want the remote to know about it. It */ 4204 /* would be best if the error that the remote reports to the user is */ 4205 /* the actual error we encountered, rather than some bogus unexpected */ 4206 /* response type message. */ 4207 4208 if (debug) { 4209 fprintf(where,"recv_xti_udp_rr: setting the response type...\n"); 4210 fflush(where); 4211 } 4212 4213 netperf_response.content.response_type = XTI_UDP_RR_RESPONSE; 4214 4215 if (debug) { 4216 fprintf(where,"recv_xti_udp_rr: the response type is set...\n"); 4217 fflush(where); 4218 } 4219 4220 /* We now alter the message_ptr variables to be at the desired */ 4221 /* alignments with the desired offsets. */ 4222 4223 if (debug) { 4224 fprintf(where,"recv_xti_udp_rr: requested recv alignment of %d offset %d\n", 4225 xti_udp_rr_request->recv_alignment, 4226 xti_udp_rr_request->recv_offset); 4227 fprintf(where,"recv_xti_udp_rr: requested send alignment of %d offset %d\n", 4228 xti_udp_rr_request->send_alignment, 4229 xti_udp_rr_request->send_offset); 4230 fflush(where); 4231 } 4232 4233 if (send_width == 0) send_width = 1; 4234 if (recv_width == 0) recv_width = 1; 4235 4236 recv_ring = allocate_buffer_ring(recv_width, 4237 xti_udp_rr_request->request_size, 4238 xti_udp_rr_request->recv_alignment, 4239 xti_udp_rr_request->recv_offset); 4240 4241 send_ring = allocate_buffer_ring(send_width, 4242 xti_udp_rr_request->response_size, 4243 xti_udp_rr_request->send_alignment, 4244 xti_udp_rr_request->send_offset); 4245 4246 if (debug) { 4247 fprintf(where,"recv_xti_udp_rr: receive alignment and offset set...\n"); 4248 fflush(where); 4249 } 4250 4251 /* create_xti_endpoint expects to find some things in the global */ 4252 /* variables, so set the globals based on the values in the request. */ 4253 /* once the socket has been created, we will set the response values */ 4254 /* based on the updated value of those globals. raj 7/94 */ 4255 lss_size = xti_udp_rr_request->send_buf_size; 4256 lsr_size = xti_udp_rr_request->recv_buf_size; 4257 loc_rcvavoid = xti_udp_rr_request->so_rcvavoid; 4258 loc_sndavoid = xti_udp_rr_request->so_sndavoid; 4259 4260 #ifdef __alpha 4261 4262 /* ok - even on a DEC box, strings are strings. I din't really want */ 4263 /* to ntohl the words of a string. since I don't want to teach the */ 4264 /* send_ and recv_ _request and _response routines about the types, */ 4265 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ 4266 /* solution would be to use XDR, but I am still leary of being able */ 4267 /* to find XDR libs on all platforms I want running netperf. raj */ 4268 { 4269 int *charword; 4270 int *initword; 4271 int *lastword; 4272 4273 initword = (int *) xti_udp_rr_request->xti_device; 4274 lastword = initword + ((xti_udp_rr_request->dev_name_len + 3) / 4); 4275 4276 for (charword = initword; 4277 charword < lastword; 4278 charword++) { 4279 4280 *charword = htonl(*charword); 4281 } 4282 } 4283 4284 #endif /* __alpha */ 4285 4286 s_data = create_xti_endpoint(xti_udp_rr_request->xti_device); 4287 4288 if (s_data == INVALID_SOCKET) { 4289 netperf_response.content.serv_errno = errno; 4290 send_response(); 4291 exit(1); 4292 } 4293 4294 if (debug) { 4295 fprintf(where,"recv_xti_udp_rr: endpoint created...\n"); 4296 fflush(where); 4297 } 4298 4299 /* Let's get an address assigned to this socket so we can tell the */ 4300 /* initiator how to reach the data socket. There may be a desire to */ 4301 /* nail this socket to a specific IP address in a multi-homed, */ 4302 /* multi-connection situation, but for now, we'll ignore the issue */ 4303 /* and concentrate on single connection testing. */ 4304 4305 bind_req.addr.maxlen = sizeof(struct sockaddr_in); 4306 bind_req.addr.len = sizeof(struct sockaddr_in); 4307 bind_req.addr.buf = (char *)&myaddr_in; 4308 bind_req.qlen = 1; 4309 4310 bind_resp.addr.maxlen = sizeof(struct sockaddr_in); 4311 bind_resp.addr.len = sizeof(struct sockaddr_in); 4312 bind_resp.addr.buf = (char *)&myaddr_in; 4313 bind_resp.qlen = 1; 4314 4315 if (t_bind(s_data, 4316 &bind_req, 4317 &bind_resp) == SOCKET_ERROR) { 4318 if (debug) { 4319 fprintf(where, 4320 "recv_xti_udp_rr: t_bind failed, t_errno %d errno %d\n", 4321 t_errno, 4322 errno); 4323 fflush(where); 4324 } 4325 4326 netperf_response.content.serv_errno = t_errno; 4327 send_response(); 4328 4329 exit(1); 4330 } 4331 4332 if (debug) { 4333 fprintf(where, 4334 "recv_xti_udp_rr: endpoint bound to port %d...\n", 4335 ntohs(myaddr_in.sin_port)); 4336 fflush(where); 4337 } 4338 4339 xti_udp_rr_response->test_length = 4340 xti_udp_rr_request->test_length; 4341 4342 4343 /* Now myaddr_in contains the port and the internet address this is */ 4344 /* returned to the sender also implicitly telling the sender that the */ 4345 /* socket buffer sizing has been done. */ 4346 4347 xti_udp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); 4348 netperf_response.content.serv_errno = 0; 4349 4350 fprintf(where,"recv port number %d\n",myaddr_in.sin_port); 4351 fflush(where); 4352 4353 /* But wait, there's more. If the initiator wanted cpu measurements, */ 4354 /* then we must call the calibrate routine, which will return the max */ 4355 /* rate back to the initiator. If the CPU was not to be measured, or */ 4356 /* something went wrong with the calibration, we will return a 0.0 to */ 4357 /* the initiator. */ 4358 4359 xti_udp_rr_response->cpu_rate = 0.0; /* assume no cpu */ 4360 xti_udp_rr_response->measure_cpu = 0; 4361 if (xti_udp_rr_request->measure_cpu) { 4362 xti_udp_rr_response->measure_cpu = 1; 4363 xti_udp_rr_response->cpu_rate = 4364 calibrate_local_cpu(xti_udp_rr_request->cpu_rate); 4365 } 4366 4367 /* before we send the response back to the initiator, pull some of */ 4368 /* the socket parms from the globals */ 4369 xti_udp_rr_response->send_buf_size = lss_size; 4370 xti_udp_rr_response->recv_buf_size = lsr_size; 4371 xti_udp_rr_response->so_rcvavoid = loc_rcvavoid; 4372 xti_udp_rr_response->so_sndavoid = loc_sndavoid; 4373 4374 /* since we are going to call t_rcvudata() instead of t_rcv() we */ 4375 /* need to init the unitdata structure raj 3/95 */ 4376 4377 memset (&recv_unitdata, 0, sizeof(recv_unitdata)); 4378 recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in); 4379 recv_unitdata.addr.len = sizeof(struct sockaddr_in); 4380 recv_unitdata.addr.buf = (char *)&peeraddr_in; 4381 4382 recv_unitdata.opt.maxlen = 0; 4383 recv_unitdata.opt.len = 0; 4384 recv_unitdata.opt.buf = NULL; 4385 4386 recv_unitdata.udata.maxlen = xti_udp_rr_request->request_size; 4387 recv_unitdata.udata.len = xti_udp_rr_request->request_size; 4388 recv_unitdata.udata.buf = recv_ring->buffer_ptr; 4389 4390 /* since we are going to call t_sndudata() instead of t_snd() we */ 4391 /* need to init the unitdata structure raj 8/95 */ 4392 4393 memset (&send_unitdata, 0, sizeof(send_unitdata)); 4394 send_unitdata.addr.maxlen = sizeof(struct sockaddr_in); 4395 send_unitdata.addr.len = sizeof(struct sockaddr_in); 4396 send_unitdata.addr.buf = (char *)&peeraddr_in; 4397 4398 send_unitdata.opt.maxlen = 0; 4399 send_unitdata.opt.len = 0; 4400 send_unitdata.opt.buf = NULL; 4401 4402 send_unitdata.udata.maxlen = xti_udp_rr_request->response_size; 4403 send_unitdata.udata.len = xti_udp_rr_request->response_size; 4404 send_unitdata.udata.buf = send_ring->buffer_ptr; 4405 4406 send_response(); 4407 4408 4409 /* Now it's time to start receiving data on the connection. We will */ 4410 /* first grab the apropriate counters and then start grabbing. */ 4411 4412 cpu_start(xti_udp_rr_request->measure_cpu); 4413 4414 if (xti_udp_rr_request->test_length > 0) { 4415 times_up = 0; 4416 trans_remaining = 0; 4417 start_timer(xti_udp_rr_request->test_length + PAD_TIME); 4418 } 4419 else { 4420 times_up = 1; 4421 trans_remaining = xti_udp_rr_request->test_length * -1; 4422 } 4423 4424 addrlen = sizeof(peeraddr_in); 4425 bzero((char *)&peeraddr_in, addrlen); 4426 4427 trans_received = 0; 4428 4429 while ((!times_up) || (trans_remaining > 0)) { 4430 4431 /* receive the request from the other side */ 4432 if (t_rcvudata(s_data, 4433 &recv_unitdata, 4434 &flags) != 0) { 4435 if (errno == TNODATA) { 4436 continue; 4437 } 4438 if (errno == EINTR) { 4439 /* we must have hit the end of test time. */ 4440 break; 4441 } 4442 if (debug) { 4443 fprintf(where, 4444 "recv_xti_udp_rr: t_rcvudata failed, t_errno %d errno %d\n", 4445 t_errno, 4446 errno); 4447 fflush(where); 4448 } 4449 netperf_response.content.serv_errno = t_errno; 4450 send_response(); 4451 exit(1); 4452 } 4453 recv_ring = recv_ring->next; 4454 recv_unitdata.udata.buf = recv_ring->buffer_ptr; 4455 4456 /* Now, send the response to the remote */ 4457 if (t_sndudata(s_data, 4458 &send_unitdata) != 0) { 4459 if (errno == EINTR) { 4460 /* we have hit end of test time. */ 4461 break; 4462 } 4463 if (debug) { 4464 fprintf(where, 4465 "recv_xti_udp_rr: t_sndudata failed, t_errno %d errno %d\n", 4466 t_errno, 4467 errno); 4468 fflush(where); 4469 } 4470 netperf_response.content.serv_errno = errno; 4471 send_response(); 4472 exit(1); 4473 } 4474 send_ring = send_ring->next; 4475 send_unitdata.udata.buf = send_ring->buffer_ptr; 4476 4477 trans_received++; 4478 if (trans_remaining) { 4479 trans_remaining--; 4480 } 4481 4482 if (debug) { 4483 fprintf(where, 4484 "recv_xti_udp_rr: Transaction %d complete.\n", 4485 trans_received); 4486 fflush(where); 4487 } 4488 4489 } 4490 4491 4492 /* The loop now exits due to timeout or transaction count being */ 4493 /* reached */ 4494 4495 cpu_stop(xti_udp_rr_request->measure_cpu,&elapsed_time); 4496 4497 if (times_up) { 4498 /* we ended the test by time, which was at least 2 seconds */ 4499 /* longer than we wanted to run. so, we want to subtract */ 4500 /* PAD_TIME from the elapsed_time. */ 4501 elapsed_time -= PAD_TIME; 4502 } 4503 /* send the results to the sender */ 4504 4505 if (debug) { 4506 fprintf(where, 4507 "recv_xti_udp_rr: got %d transactions\n", 4508 trans_received); 4509 fflush(where); 4510 } 4511 4512 xti_udp_rr_results->bytes_received = (trans_received * 4513 (xti_udp_rr_request->request_size + 4514 xti_udp_rr_request->response_size)); 4515 xti_udp_rr_results->trans_received = trans_received; 4516 xti_udp_rr_results->elapsed_time = elapsed_time; 4517 xti_udp_rr_results->cpu_method = cpu_method; 4518 if (xti_udp_rr_request->measure_cpu) { 4519 xti_udp_rr_results->cpu_util = calc_cpu_util(elapsed_time); 4520 } 4521 4522 if (debug) { 4523 fprintf(where, 4524 "recv_xti_udp_rr: test complete, sending results.\n"); 4525 fflush(where); 4526 } 4527 4528 send_response(); 4529 4530 /* we are done with the socket now */ 4531 close(s_data); 4532 4533 } 4534 4535 /* this routine implements the receive (netserver) side of a XTI_TCP_RR */ 4537 /* test */ 4538 void 4539 recv_xti_tcp_rr() 4540 { 4541 4542 struct ring_elt *send_ring; 4543 struct ring_elt *recv_ring; 4544 4545 struct sockaddr_in myaddr_in, peeraddr_in; 4546 struct t_bind bind_req, bind_resp; 4547 struct t_call call_req; 4548 4549 SOCKET s_listen,s_data; 4550 int addrlen; 4551 char *temp_message_ptr; 4552 int trans_received; 4553 int trans_remaining; 4554 int bytes_sent; 4555 int request_bytes_recvd; 4556 int request_bytes_remaining; 4557 int timed_out = 0; 4558 float elapsed_time; 4559 4560 struct xti_tcp_rr_request_struct *xti_tcp_rr_request; 4561 struct xti_tcp_rr_response_struct *xti_tcp_rr_response; 4562 struct xti_tcp_rr_results_struct *xti_tcp_rr_results; 4563 4564 xti_tcp_rr_request = 4565 (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data; 4566 xti_tcp_rr_response = 4567 (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data; 4568 xti_tcp_rr_results = 4569 (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data; 4570 4571 if (debug) { 4572 fprintf(where,"netserver: recv_xti_tcp_rr: entered...\n"); 4573 fflush(where); 4574 } 4575 4576 /* We want to set-up the listen socket with all the desired */ 4577 /* parameters and then let the initiator know that all is ready. If */ 4578 /* socket size defaults are to be used, then the initiator will have */ 4579 /* sent us 0's. If the socket sizes cannot be changed, then we will */ 4580 /* send-back what they are. If that information cannot be determined, */ 4581 /* then we send-back -1's for the sizes. If things go wrong for any */ 4582 /* reason, we will drop back ten yards and punt. */ 4583 4584 /* If anything goes wrong, we want the remote to know about it. It */ 4585 /* would be best if the error that the remote reports to the user is */ 4586 /* the actual error we encountered, rather than some bogus unexpected */ 4587 /* response type message. */ 4588 4589 if (debug) { 4590 fprintf(where,"recv_xti_tcp_rr: setting the response type...\n"); 4591 fflush(where); 4592 } 4593 4594 netperf_response.content.response_type = XTI_TCP_RR_RESPONSE; 4595 4596 if (debug) { 4597 fprintf(where,"recv_xti_tcp_rr: the response type is set...\n"); 4598 fflush(where); 4599 } 4600 4601 /* allocate the recv and send rings with the requested alignments */ 4602 /* and offsets. raj 7/94 */ 4603 if (debug) { 4604 fprintf(where,"recv_xti_tcp_rr: requested recv alignment of %d offset %d\n", 4605 xti_tcp_rr_request->recv_alignment, 4606 xti_tcp_rr_request->recv_offset); 4607 fprintf(where,"recv_xti_tcp_rr: requested send alignment of %d offset %d\n", 4608 xti_tcp_rr_request->send_alignment, 4609 xti_tcp_rr_request->send_offset); 4610 fflush(where); 4611 } 4612 4613 /* at some point, these need to come to us from the remote system */ 4614 if (send_width == 0) send_width = 1; 4615 if (recv_width == 0) recv_width = 1; 4616 4617 send_ring = allocate_buffer_ring(send_width, 4618 xti_tcp_rr_request->response_size, 4619 xti_tcp_rr_request->send_alignment, 4620 xti_tcp_rr_request->send_offset); 4621 4622 recv_ring = allocate_buffer_ring(recv_width, 4623 xti_tcp_rr_request->request_size, 4624 xti_tcp_rr_request->recv_alignment, 4625 xti_tcp_rr_request->recv_offset); 4626 4627 4628 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ 4629 /* can put in OUR values !-) At some point, we may want to nail this */ 4630 /* socket to a particular network-level address, but for now, */ 4631 /* INADDR_ANY should be just fine. */ 4632 4633 bzero((char *)&myaddr_in, 4634 sizeof(myaddr_in)); 4635 myaddr_in.sin_family = AF_INET; 4636 myaddr_in.sin_addr.s_addr = INADDR_ANY; 4637 myaddr_in.sin_port = 0; 4638 4639 /* Grab a socket to listen on, and then listen on it. */ 4640 4641 if (debug) { 4642 fprintf(where,"recv_xti_tcp_rr: grabbing a socket...\n"); 4643 fflush(where); 4644 } 4645 4646 /* create_xti_endpoint expects to find some things in the global */ 4647 /* variables, so set the globals based on the values in the request. */ 4648 /* once the socket has been created, we will set the response values */ 4649 /* based on the updated value of those globals. raj 7/94 */ 4650 lss_size = xti_tcp_rr_request->send_buf_size; 4651 lsr_size = xti_tcp_rr_request->recv_buf_size; 4652 loc_nodelay = xti_tcp_rr_request->no_delay; 4653 loc_rcvavoid = xti_tcp_rr_request->so_rcvavoid; 4654 loc_sndavoid = xti_tcp_rr_request->so_sndavoid; 4655 4656 #ifdef __alpha 4657 4658 /* ok - even on a DEC box, strings are strings. I din't really want */ 4659 /* to ntohl the words of a string. since I don't want to teach the */ 4660 /* send_ and recv_ _request and _response routines about the types, */ 4661 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ 4662 /* solution would be to use XDR, but I am still leary of being able */ 4663 /* to find XDR libs on all platforms I want running netperf. raj */ 4664 { 4665 int *charword; 4666 int *initword; 4667 int *lastword; 4668 4669 initword = (int *) xti_tcp_rr_request->xti_device; 4670 lastword = initword + ((xti_tcp_rr_request->dev_name_len + 3) / 4); 4671 4672 for (charword = initword; 4673 charword < lastword; 4674 charword++) { 4675 4676 *charword = htonl(*charword); 4677 } 4678 } 4679 4680 #endif /* __alpha */ 4681 4682 s_listen = create_xti_endpoint(xti_tcp_rr_request->xti_device); 4683 4684 if (s_listen == INVALID_SOCKET) { 4685 netperf_response.content.serv_errno = errno; 4686 send_response(); 4687 4688 exit(1); 4689 } 4690 4691 /* Let's get an address assigned to this socket so we can tell the */ 4692 /* initiator how to reach the data socket. There may be a desire to */ 4693 /* nail this socket to a specific IP address in a multi-homed, */ 4694 /* multi-connection situation, but for now, we'll ignore the issue */ 4695 /* and concentrate on single connection testing. */ 4696 4697 bind_req.addr.maxlen = sizeof(struct sockaddr_in); 4698 bind_req.addr.len = sizeof(struct sockaddr_in); 4699 bind_req.addr.buf = (char *)&myaddr_in; 4700 bind_req.qlen = 1; 4701 4702 bind_resp.addr.maxlen = sizeof(struct sockaddr_in); 4703 bind_resp.addr.len = sizeof(struct sockaddr_in); 4704 bind_resp.addr.buf = (char *)&myaddr_in; 4705 bind_resp.qlen = 1; 4706 4707 if (t_bind(s_listen, 4708 &bind_req, 4709 &bind_resp) == SOCKET_ERROR) { 4710 netperf_response.content.serv_errno = t_errno; 4711 close(s_listen); 4712 send_response(); 4713 4714 exit(1); 4715 } 4716 4717 if (debug) { 4718 fprintf(where, 4719 "recv_xti_tcp_rr: t_bind complete port %d\n", 4720 ntohs(myaddr_in.sin_port)); 4721 fflush(where); 4722 } 4723 4724 /* Now myaddr_in contains the port and the internet address this is */ 4725 /* returned to the sender also implicitly telling the sender that the */ 4726 /* socket buffer sizing has been done. */ 4727 4728 xti_tcp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); 4729 netperf_response.content.serv_errno = 0; 4730 4731 /* But wait, there's more. If the initiator wanted cpu measurements, */ 4732 /* then we must call the calibrate routine, which will return the max */ 4733 /* rate back to the initiator. If the CPU was not to be measured, or */ 4734 /* something went wrong with the calibration, we will return a 0.0 to */ 4735 /* the initiator. */ 4736 4737 xti_tcp_rr_response->cpu_rate = 0.0; /* assume no cpu */ 4738 xti_tcp_rr_response->measure_cpu = 0; 4739 4740 if (xti_tcp_rr_request->measure_cpu) { 4741 xti_tcp_rr_response->measure_cpu = 1; 4742 xti_tcp_rr_response->cpu_rate = calibrate_local_cpu(xti_tcp_rr_request->cpu_rate); 4743 } 4744 4745 4746 /* before we send the response back to the initiator, pull some of */ 4747 /* the socket parms from the globals */ 4748 xti_tcp_rr_response->send_buf_size = lss_size; 4749 xti_tcp_rr_response->recv_buf_size = lsr_size; 4750 xti_tcp_rr_response->no_delay = loc_nodelay; 4751 xti_tcp_rr_response->so_rcvavoid = loc_rcvavoid; 4752 xti_tcp_rr_response->so_sndavoid = loc_sndavoid; 4753 xti_tcp_rr_response->test_length = xti_tcp_rr_request->test_length; 4754 send_response(); 4755 4756 /* Now, let's set-up the socket to listen for connections. for xti, */ 4757 /* the t_listen call is blocking by default - this is different */ 4758 /* semantics from BSD - probably has to do with being able to reject */ 4759 /* a call before an accept */ 4760 call_req.addr.maxlen = sizeof(struct sockaddr_in); 4761 call_req.addr.len = sizeof(struct sockaddr_in); 4762 call_req.addr.buf = (char *)&peeraddr_in; 4763 call_req.opt.maxlen = 0; 4764 call_req.opt.len = 0; 4765 call_req.opt.buf = NULL; 4766 call_req.udata.maxlen= 0; 4767 call_req.udata.len = 0; 4768 call_req.udata.buf = 0; 4769 4770 if (t_listen(s_listen, &call_req) == -1) { 4771 fprintf(where, 4772 "recv_xti_tcp_rr: t_listen: errno %d t_errno %d\n", 4773 errno, 4774 t_errno); 4775 fflush(where); 4776 netperf_response.content.serv_errno = t_errno; 4777 close(s_listen); 4778 send_response(); 4779 exit(1); 4780 } 4781 4782 if (debug) { 4783 fprintf(where, 4784 "recv_xti_tcp_rr: t_listen complete t_look 0x%.4x\n", 4785 t_look(s_listen)); 4786 fflush(where); 4787 } 4788 4789 /* now just rubber stamp the thing. we want to use the same fd? so */ 4790 /* we will just equate s_data with s_listen. this seems a little */ 4791 /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */ 4792 s_data = s_listen; 4793 if (t_accept(s_listen, 4794 s_data, 4795 &call_req) == -1) { 4796 fprintf(where, 4797 "recv_xti_tcp_rr: t_accept: errno %d t_errno %d\n", 4798 errno, 4799 t_errno); 4800 fflush(where); 4801 close(s_listen); 4802 exit(1); 4803 } 4804 4805 if (debug) { 4806 fprintf(where, 4807 "recv_xti_tcp_rr: t_accept complete t_look 0x%.4x", 4808 t_look(s_data)); 4809 fprintf(where, 4810 " remote is %s port %d\n", 4811 inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr), 4812 ntohs(peeraddr_in.sin_port)); 4813 fflush(where); 4814 } 4815 4816 /* Now it's time to start receiving data on the connection. We will */ 4817 /* first grab the apropriate counters and then start grabbing. */ 4818 4819 cpu_start(xti_tcp_rr_request->measure_cpu); 4820 4821 if (xti_tcp_rr_request->test_length > 0) { 4822 times_up = 0; 4823 trans_remaining = 0; 4824 start_timer(xti_tcp_rr_request->test_length + PAD_TIME); 4825 } 4826 else { 4827 times_up = 1; 4828 trans_remaining = xti_tcp_rr_request->test_length * -1; 4829 } 4830 4831 trans_received = 0; 4832 4833 while ((!times_up) || (trans_remaining > 0)) { 4834 temp_message_ptr = recv_ring->buffer_ptr; 4835 request_bytes_remaining = xti_tcp_rr_request->request_size; 4836 while(request_bytes_remaining > 0) { 4837 if((request_bytes_recvd=t_rcv(s_data, 4838 temp_message_ptr, 4839 request_bytes_remaining, 4840 &xti_flags)) == SOCKET_ERROR) { 4841 if (errno == EINTR) { 4842 /* the timer popped */ 4843 timed_out = 1; 4844 break; 4845 } 4846 fprintf(where, 4847 "recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d", 4848 errno, 4849 t_errno, 4850 request_bytes_recvd); 4851 fprintf(where, 4852 " t_look 0x%x", 4853 t_look(s_data)); 4854 fflush(where); 4855 netperf_response.content.serv_errno = t_errno; 4856 send_response(); 4857 exit(1); 4858 } 4859 else { 4860 request_bytes_remaining -= request_bytes_recvd; 4861 temp_message_ptr += request_bytes_recvd; 4862 } 4863 } 4864 4865 recv_ring = recv_ring->next; 4866 4867 if (timed_out) { 4868 /* we hit the end of the test based on time - lets */ 4869 /* bail out of here now... */ 4870 if (debug) { 4871 fprintf(where,"yo5\n"); 4872 fflush(where); 4873 } 4874 break; 4875 } 4876 4877 /* Now, send the response to the remote */ 4878 if((bytes_sent=t_snd(s_data, 4879 send_ring->buffer_ptr, 4880 xti_tcp_rr_request->response_size, 4881 0)) == -1) { 4882 if (errno == EINTR) { 4883 /* the test timer has popped */ 4884 timed_out = 1; 4885 if (debug) { 4886 fprintf(where,"yo6\n"); 4887 fflush(where); 4888 } 4889 break; 4890 } 4891 fprintf(where, 4892 "recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d", 4893 errno, 4894 t_errno, 4895 bytes_sent); 4896 fprintf(where, 4897 " t_look 0x%x", 4898 t_look(s_data)); 4899 fflush(where); 4900 netperf_response.content.serv_errno = t_errno; 4901 send_response(); 4902 exit(1); 4903 } 4904 4905 send_ring = send_ring->next; 4906 4907 trans_received++; 4908 if (trans_remaining) { 4909 trans_remaining--; 4910 } 4911 } 4912 4913 4914 /* The loop now exits due to timeout or transaction count being */ 4915 /* reached */ 4916 4917 cpu_stop(xti_tcp_rr_request->measure_cpu,&elapsed_time); 4918 4919 stop_timer(); /* this is probably unnecessary, but it shouldn't hurt */ 4920 4921 if (timed_out) { 4922 /* we ended the test by time, which was at least 2 seconds */ 4923 /* longer than we wanted to run. so, we want to subtract */ 4924 /* PAD_TIME from the elapsed_time. */ 4925 elapsed_time -= PAD_TIME; 4926 } 4927 4928 /* send the results to the sender */ 4929 4930 if (debug) { 4931 fprintf(where, 4932 "recv_xti_tcp_rr: got %d transactions\n", 4933 trans_received); 4934 fflush(where); 4935 } 4936 4937 xti_tcp_rr_results->bytes_received = (trans_received * 4938 (xti_tcp_rr_request->request_size + 4939 xti_tcp_rr_request->response_size)); 4940 xti_tcp_rr_results->trans_received = trans_received; 4941 xti_tcp_rr_results->elapsed_time = elapsed_time; 4942 xti_tcp_rr_results->cpu_method = cpu_method; 4943 if (xti_tcp_rr_request->measure_cpu) { 4944 xti_tcp_rr_results->cpu_util = calc_cpu_util(elapsed_time); 4945 } 4946 4947 if (debug) { 4948 fprintf(where, 4949 "recv_xti_tcp_rr: test complete, sending results.\n"); 4950 fflush(where); 4951 } 4952 4953 /* we are done with the socket, free it */ 4954 t_close(s_data); 4955 4956 send_response(); 4957 4958 } 4959 4960 4961 4963 /* this test is intended to test the performance of establishing a */ 4964 /* connection, exchanging a request/response pair, and repeating. it */ 4965 /* is expected that this would be a good starting-point for */ 4966 /* comparision of T/TCP with classic TCP for transactional workloads. */ 4967 /* it will also look (can look) much like the communication pattern */ 4968 /* of http for www access. */ 4969 4970 void 4971 send_xti_tcp_conn_rr(char remote_host[]) 4972 { 4973 4974 char *tput_title = "\ 4975 Local /Remote\n\ 4976 Socket Size Request Resp. Elapsed Trans.\n\ 4977 Send Recv Size Size Time Rate \n\ 4978 bytes Bytes bytes bytes secs. per sec \n\n"; 4979 4980 char *tput_fmt_0 = 4981 "%7.2f\n"; 4982 4983 char *tput_fmt_1_line_1 = "\ 4984 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; 4985 char *tput_fmt_1_line_2 = "\ 4986 %-6d %-6d\n"; 4987 4988 char *cpu_title = "\ 4989 Local /Remote\n\ 4990 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ 4991 Send Recv Size Size Time Rate local remote local remote\n\ 4992 bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; 4993 4994 char *cpu_fmt_0 = 4995 "%6.3f\n"; 4996 4997 char *cpu_fmt_1_line_1 = "\ 4998 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; 4999 5000 char *cpu_fmt_1_line_2 = "\ 5001 %-6d %-6d\n"; 5002 5003 char *ksink_fmt = "\ 5004 Alignment Offset\n\ 5005 Local Remote Local Remote\n\ 5006 Send Recv Send Recv\n\ 5007 %5d %5d %5d %5d\n"; 5008 5009 5010 int one = 1; 5011 int timed_out = 0; 5012 float elapsed_time; 5013 5014 int len; 5015 struct ring_elt *send_ring; 5016 struct ring_elt *recv_ring; 5017 char *temp_message_ptr; 5018 int nummessages; 5019 SOCKET send_socket; 5020 int trans_remaining; 5021 double bytes_xferd; 5022 int sock_opt_len = sizeof(int); 5023 int rsp_bytes_left; 5024 int rsp_bytes_recvd; 5025 5026 float local_cpu_utilization; 5027 float local_service_demand; 5028 float remote_cpu_utilization; 5029 float remote_service_demand; 5030 double thruput; 5031 5032 struct hostent *hp; 5033 struct sockaddr_in server; 5034 struct sockaddr_in *myaddr; 5035 unsigned int addr; 5036 int myport; 5037 5038 struct xti_tcp_conn_rr_request_struct *xti_tcp_conn_rr_request; 5039 struct xti_tcp_conn_rr_response_struct *xti_tcp_conn_rr_response; 5040 struct xti_tcp_conn_rr_results_struct *xti_tcp_conn_rr_result; 5041 5042 xti_tcp_conn_rr_request = 5043 (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data; 5044 xti_tcp_conn_rr_response = 5045 (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data; 5046 xti_tcp_conn_rr_result = 5047 (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data; 5048 5049 /* since we are now disconnected from the code that established the */ 5050 /* control socket, and since we want to be able to use different */ 5051 /* protocols and such, we are passed the name of the remote host and */ 5052 /* must turn that into the test specific addressing information. */ 5053 5054 myaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in)); 5055 if (myaddr == NULL) { 5056 printf("malloc(%d) failed!\n", sizeof(struct sockaddr_in)); 5057 exit(1); 5058 } 5059 5060 bzero((char *)&server, 5061 sizeof(server)); 5062 bzero((char *)myaddr, 5063 sizeof(struct sockaddr_in)); 5064 myaddr->sin_family = AF_INET; 5065 5066 /* it would seem that while HP-UX will allow an IP address (as a */ 5067 /* string) in a call to gethostbyname, other, less enlightened */ 5068 /* systems do not. fix from awjacks (at) ca.sandia.gov raj 10/95 */ 5069 /* order changed to check for IP address first. raj 7/96 */ 5070 5071 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) { 5072 /* it was not an IP address, try it as a name */ 5073 if ((hp = gethostbyname(remote_host)) == NULL) { 5074 /* we have no idea what it is */ 5075 fprintf(where, 5076 "establish_control: could not resolve the destination %s\n", 5077 remote_host); 5078 fflush(where); 5079 exit(1); 5080 } 5081 else { 5082 /* it was a valid remote_host */ 5083 bcopy(hp->h_addr, 5084 (char *)&server.sin_addr, 5085 hp->h_length); 5086 server.sin_family = hp->h_addrtype; 5087 } 5088 } 5089 else { 5090 /* it was a valid IP address */ 5091 server.sin_addr.s_addr = addr; 5092 server.sin_family = AF_INET; 5093 } 5094 5095 if ( print_headers ) { 5096 fprintf(where,"TCP Connect/Request/Response Test\n"); 5097 if (local_cpu_usage || remote_cpu_usage) 5098 fprintf(where,cpu_title,format_units()); 5099 else 5100 fprintf(where,tput_title,format_units()); 5101 } 5102 5103 /* initialize a few counters */ 5104 5105 nummessages = 0; 5106 bytes_xferd = 0.0; 5107 times_up = 0; 5108 5109 /* set-up the data buffers with the requested alignment and offset */ 5110 if (send_width == 0) send_width = 1; 5111 if (recv_width == 0) recv_width = 1; 5112 5113 send_ring = allocate_buffer_ring(send_width, 5114 req_size, 5115 local_send_align, 5116 local_send_offset); 5117 5118 recv_ring = allocate_buffer_ring(recv_width, 5119 rsp_size, 5120 local_recv_align, 5121 local_recv_offset); 5122 5123 5124 if (debug) { 5125 fprintf(where,"send_xti_tcp_conn_rr: send_socket obtained...\n"); 5126 } 5127 5128 /* If the user has requested cpu utilization measurements, we must */ 5129 /* calibrate the cpu(s). We will perform this task within the tests */ 5130 /* themselves. If the user has specified the cpu rate, then */ 5131 /* calibrate_local_cpu will return rather quickly as it will have */ 5132 /* nothing to do. If local_cpu_rate is zero, then we will go through */ 5133 /* all the "normal" calibration stuff and return the rate back.*/ 5134 5135 if (local_cpu_usage) { 5136 local_cpu_rate = calibrate_local_cpu(local_cpu_rate); 5137 } 5138 5139 /* Tell the remote end to do a listen. The server alters the socket */ 5140 /* paramters on the other side at this point, hence the reason for */ 5141 /* all the values being passed in the setup message. If the user did */ 5142 /* not specify any of the parameters, they will be passed as 0, which */ 5143 /* will indicate to the remote that no changes beyond the system's */ 5144 /* default should be used. Alignment is the exception, it will */ 5145 /* default to 8, which will be no alignment alterations. */ 5146 5147 netperf_request.content.request_type = DO_XTI_TCP_CRR; 5148 xti_tcp_conn_rr_request->recv_buf_size = rsr_size; 5149 xti_tcp_conn_rr_request->send_buf_size = rss_size; 5150 xti_tcp_conn_rr_request->recv_alignment = remote_recv_align; 5151 xti_tcp_conn_rr_request->recv_offset = remote_recv_offset; 5152 xti_tcp_conn_rr_request->send_alignment = remote_send_align; 5153 xti_tcp_conn_rr_request->send_offset = remote_send_offset; 5154 xti_tcp_conn_rr_request->request_size = req_size; 5155 xti_tcp_conn_rr_request->response_size = rsp_size; 5156 xti_tcp_conn_rr_request->no_delay = rem_nodelay; 5157 xti_tcp_conn_rr_request->measure_cpu = remote_cpu_usage; 5158 xti_tcp_conn_rr_request->cpu_rate = remote_cpu_rate; 5159 xti_tcp_conn_rr_request->so_rcvavoid = rem_rcvavoid; 5160 xti_tcp_conn_rr_request->so_sndavoid = rem_sndavoid; 5161 if (test_time) { 5162 xti_tcp_conn_rr_request->test_length = test_time; 5163 } 5164 else { 5165 xti_tcp_conn_rr_request->test_length = test_trans * -1; 5166 } 5167 5168 if (debug > 1) { 5169 fprintf(where,"netperf: send_xti_tcp_conn_rr: requesting TCP crr test\n"); 5170 } 5171 5172 send_request(); 5173 5174 /* The response from the remote will contain all of the relevant */ 5175 /* socket parameters for this test type. We will put them back into */ 5176 /* the variables here so they can be displayed if desired. The */ 5177 /* remote will have calibrated CPU if necessary, and will have done */ 5178 /* all the needed set-up we will have calibrated the cpu locally */ 5179 /* before sending the request, and will grab the counter value right */ 5180 /* after the connect returns. The remote will grab the counter right */ 5181 /* after the accept call. This saves the hassle of extra messages */ 5182 /* being sent for the TCP tests. */ 5183 5184 recv_response(); 5185 5186 if (!netperf_response.content.serv_errno) { 5187 rsr_size = xti_tcp_conn_rr_response->recv_buf_size; 5188 rss_size = xti_tcp_conn_rr_response->send_buf_size; 5189 rem_nodelay = xti_tcp_conn_rr_response->no_delay; 5190 remote_cpu_usage= xti_tcp_conn_rr_response->measure_cpu; 5191 remote_cpu_rate = xti_tcp_conn_rr_response->cpu_rate; 5192 /* make sure that port numbers are in network order */ 5193 server.sin_port = (short)xti_tcp_conn_rr_response->data_port_number; 5194 server.sin_port = htons(server.sin_port); 5195 if (debug) { 5196 fprintf(where,"remote listen done.\n"); 5197 fprintf(where,"remote port is %d\n",ntohs(server.sin_port)); 5198 fflush(where); 5199 } 5200 } 5201 else { 5202 Set_errno(netperf_response.content.serv_errno); 5203 perror("netperf: remote error"); 5204 5205 exit(1); 5206 } 5207 5208 /* Set-up the test end conditions. For a request/response test, they */ 5209 /* can be either time or transaction based. */ 5210 5211 if (test_time) { 5212 /* The user wanted to end the test after a period of time. */ 5213 times_up = 0; 5214 trans_remaining = 0; 5215 start_timer(test_time); 5216 } 5217 else { 5218 /* The tester wanted to send a number of bytes. */ 5219 trans_remaining = test_bytes; 5220 times_up = 1; 5221 } 5222 5223 /* The cpu_start routine will grab the current time and possibly */ 5224 /* value of the idle counter for later use in measuring cpu */ 5225 /* utilization and/or service demand and thruput. */ 5226 5227 cpu_start(local_cpu_usage); 5228 5229 /* We use an "OR" to control test execution. When the test is */ 5230 /* controlled by time, the byte count check will always return false. */ 5231 /* When the test is controlled by byte count, the time test will */ 5232 /* always return false. When the test is finished, the whole */ 5233 /* expression will go false and we will stop sending data. I think I */ 5234 /* just arbitrarily decrement trans_remaining for the timed test, but */ 5235 /* will not do that just yet... One other question is whether or not */ 5236 /* the send buffer and the receive buffer should be the same buffer. */ 5237 5238 /* just for grins, start the port numbers at 65530. this should */ 5239 /* quickly flush-out those broken implementations of TCP which treat */ 5240 /* the port number as a signed 16 bit quantity. */ 5241 myport = 65530; 5242 myaddr->sin_port = htons(myport); 5243 5244 while ((!times_up) || (trans_remaining > 0)) { 5245 5246 /* set up the data socket */ 5247 send_socket = create_xti_endpoint(loc_xti_device); 5248 5249 if (send_socket == INVALID_SOCKET) { 5250 perror("netperf: send_xti_tcp_conn_rr: tcp stream data socket"); 5251 exit(1); 5252 } 5253 5254 /* we set SO_REUSEADDR on the premis that no unreserved port */ 5255 /* number on the local system is going to be already connected to */ 5256 /* the remote netserver's port number. we might still have a */ 5257 /* problem if there is a port in the unconnected state. In that */ 5258 /* case, we might want to throw-in a goto to the point where we */ 5259 /* increment the port number by one and try again. of course, this */ 5260 /* could lead to a big load of spinning. one thing that I might */ 5261 /* try later is to have the remote actually allocate a couple of */ 5262 /* port numbers and cycle through those as well. depends on if we */ 5263 /* can get through all the unreserved port numbers in less than */ 5264 /* the length of the TIME_WAIT state raj 8/94 */ 5265 one = 1; 5266 if(setsockopt(send_socket, SOL_SOCKET, SO_REUSEADDR, 5267 (char *)&one, sock_opt_len) == SOCKET_ERROR) { 5268 perror("netperf: send_xti_tcp_conn_rr: so_reuseaddr"); 5269 exit(1); 5270 } 5271 5272 /* we want to bind our socket to a particular port number. */ 5273 if (bind(send_socket, 5274 (struct sockaddr *)myaddr, 5275 sizeof(struct sockaddr_in)) == SOCKET_ERROR) { 5276 printf("netperf: send_xti_tcp_conn_rr: tried to bind to port %d\n", 5277 ntohs(myaddr->sin_port)); 5278 perror("netperf: send_xti_tcp_conn_rr: bind"); 5279 exit(1); 5280 } 5281 5282 /* Connect up to the remote port on the data socket */ 5283 if (connect(send_socket, 5284 (struct sockaddr *)&server, 5285 sizeof(server)) == INVALID_SOCKET){ 5286 if (errno == EINTR) { 5287 /* we hit the end of a */ 5288 /* timed test. */ 5289 timed_out = 1; 5290 break; 5291 } 5292 perror("netperf: data socket connect failed"); 5293 printf("\tattempted to connect on socket %d to port %d", 5294 send_socket, 5295 ntohs(server.sin_port)); 5296 printf(" from port %d \n",ntohs(myaddr->sin_port)); 5297 exit(1); 5298 } 5299 5300 /* send the request */ 5301 if((len=send(send_socket, 5302 send_ring->buffer_ptr, 5303 req_size, 5304 0)) != req_size) { 5305 if (errno == EINTR) { 5306 /* we hit the end of a */ 5307 /* timed test. */ 5308 timed_out = 1; 5309 break; 5310 } 5311 perror("send_xti_tcp_conn_rr: data send error"); 5312 exit(1); 5313 } 5314 send_ring = send_ring->next; 5315 5316 /* receive the response */ 5317 rsp_bytes_left = rsp_size; 5318 temp_message_ptr = recv_ring->buffer_ptr; 5319 while(rsp_bytes_left > 0) { 5320 if((rsp_bytes_recvd=recv(send_socket, 5321 temp_message_ptr, 5322 rsp_bytes_left, 5323 0)) == SOCKET_ERROR) { 5324 if (errno == EINTR) { 5325 /* We hit the end of a timed test. */ 5326 timed_out = 1; 5327 break; 5328 } 5329 perror("send_xti_tcp_conn_rr: data recv error"); 5330 exit(1); 5331 } 5332 rsp_bytes_left -= rsp_bytes_recvd; 5333 temp_message_ptr += rsp_bytes_recvd; 5334 } 5335 recv_ring = recv_ring->next; 5336 5337 if (timed_out) { 5338 /* we may have been in a nested while loop - we need */ 5339 /* another call to break. */ 5340 break; 5341 } 5342 5343 close(send_socket); 5344 5345 nummessages++; 5346 if (trans_remaining) { 5347 trans_remaining--; 5348 } 5349 5350 if (debug > 3) { 5351 fprintf(where, 5352 "Transaction %d completed on local port %d\n", 5353 nummessages, 5354 ntohs(myaddr->sin_port)); 5355 fflush(where); 5356 } 5357 5358 newport: 5359 /* pick a new port number */ 5360 myport = ntohs(myaddr->sin_port); 5361 myport++; 5362 /* we do not want to use the port number that the server is */ 5363 /* sitting at - this would cause us to fail in a loopback test */ 5364 5365 if (myport == ntohs(server.sin_port)) myport++; 5366 5367 /* wrap the port number when we get to 65535. NOTE, some broken */ 5368 /* TCP's might treat the port number as a signed 16 bit quantity. */ 5369 /* we aren't interested in testing such broekn implementations :) */ 5370 /* raj 8/94 */ 5371 if (myport == 65535) { 5372 myport = 5000; 5373 } 5374 myaddr->sin_port = htons(myport); 5375 5376 if (debug) { 5377 if ((myport % 1000) == 0) { 5378 printf("port %d\n",myport); 5379 } 5380 } 5381 5382 } 5383 5384 /* this call will always give us the elapsed time for the test, and */ 5385 /* will also store-away the necessaries for cpu utilization */ 5386 5387 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ 5388 /* how long did we really run? */ 5389 5390 /* Get the statistics from the remote end. The remote will have */ 5391 /* calculated service demand and all those interesting things. If it */ 5392 /* wasn't supposed to care, it will return obvious values. */ 5393 5394 recv_response(); 5395 if (!netperf_response.content.serv_errno) { 5396 if (debug) 5397 fprintf(where,"remote results obtained\n"); 5398 } 5399 else { 5400 Set_errno(netperf_response.content.serv_errno); 5401 perror("netperf: remote error"); 5402 5403 exit(1); 5404 } 5405 5406 /* We now calculate what our thruput was for the test. In the future, */ 5407 /* we may want to include a calculation of the thruput measured by */ 5408 /* the remote, but it should be the case that for a TCP stream test, */ 5409 /* that the two numbers should be *very* close... We calculate */ 5410 /* bytes_sent regardless of the way the test length was controlled. */ 5411 /* If it was time, we needed to, and if it was by bytes, the user may */ 5412 /* have specified a number of bytes that wasn't a multiple of the */ 5413 /* send_size, so we really didn't send what he asked for ;-) We use */ 5414 /* Kbytes/s as the units of thruput for a TCP stream test, where K = */ 5415 /* 1024. A future enhancement *might* be to choose from a couple of */ 5416 /* unit selections. */ 5417 5418 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); 5419 thruput = calc_thruput(bytes_xferd); 5420 5421 if (local_cpu_usage || remote_cpu_usage) { 5422 /* We must now do a little math for service demand and cpu */ 5423 /* utilization for the system(s) */ 5424 /* Of course, some of the information might be bogus because */ 5425 /* there was no idle counter in the kernel(s). We need to make */ 5426 /* a note of this for the user's benefit...*/ 5427 if (local_cpu_usage) { 5428 if (local_cpu_rate == 0.0) { 5429 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); 5430 fprintf(where,"Local CPU usage numbers based on process information only!\n"); 5431 fflush(where); 5432 } 5433 local_cpu_utilization = calc_cpu_util(0.0); 5434 /* since calc_service demand is doing ms/Kunit we will */ 5435 /* multiply the number of transaction by 1024 to get */ 5436 /* "good" numbers */ 5437 local_service_demand = calc_service_demand((double) nummessages*1024, 5438 0.0, 5439 0.0, 5440 0); 5441 } 5442 else { 5443 local_cpu_utilization = -1.0; 5444 local_service_demand = -1.0; 5445 } 5446 5447 if (remote_cpu_usage) { 5448 if (remote_cpu_rate == 0.0) { 5449 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); 5450 fprintf(where,"Remote CPU usage numbers based on process information only!\n"); 5451 fflush(where); 5452 } 5453 remote_cpu_utilization = xti_tcp_conn_rr_result->cpu_util; 5454 /* since calc_service demand is doing ms/Kunit we will */ 5455 /* multiply the number of transaction by 1024 to get */ 5456 /* "good" numbers */ 5457 remote_service_demand = calc_service_demand((double) nummessages*1024, 5458 0.0, 5459 remote_cpu_utilization, 5460 xti_tcp_conn_rr_result->num_cpus); 5461 } 5462 else { 5463 remote_cpu_utilization = -1.0; 5464 remote_service_demand = -1.0; 5465 } 5466 5467 /* We are now ready to print all the information. If the user */ 5468 /* has specified zero-level verbosity, we will just print the */ 5469 /* local service demand, or the remote service demand. If the */ 5470 /* user has requested verbosity level 1, he will get the basic */ 5471 /* "streamperf" numbers. If the user has specified a verbosity */ 5472 /* of greater than 1, we will display a veritable plethora of */ 5473 /* background information from outside of this block as it it */ 5474 /* not cpu_measurement specific... */ 5475 5476 switch (verbosity) { 5477 case 0: 5478 if (local_cpu_usage) { 5479 fprintf(where, 5480 cpu_fmt_0, 5481 local_service_demand); 5482 } 5483 else { 5484 fprintf(where, 5485 cpu_fmt_0, 5486 remote_service_demand); 5487 } 5488 break; 5489 case 1: 5490 fprintf(where, 5491 cpu_fmt_1_line_1, /* the format string */ 5492 lss_size, /* local sendbuf size */ 5493 lsr_size, 5494 req_size, /* how large were the requests */ 5495 rsp_size, /* guess */ 5496 elapsed_time, /* how long was the test */ 5497 nummessages/elapsed_time, 5498 local_cpu_utilization, /* local cpu */ 5499 remote_cpu_utilization, /* remote cpu */ 5500 local_service_demand, /* local service demand */ 5501 remote_service_demand); /* remote service demand */ 5502 fprintf(where, 5503 cpu_fmt_1_line_2, 5504 rss_size, 5505 rsr_size); 5506 break; 5507 } 5508 } 5509 else { 5510 /* The tester did not wish to measure service demand. */ 5511 switch (verbosity) { 5512 case 0: 5513 fprintf(where, 5514 tput_fmt_0, 5515 nummessages/elapsed_time); 5516 break; 5517 case 1: 5518 fprintf(where, 5519 tput_fmt_1_line_1, /* the format string */ 5520 lss_size, 5521 lsr_size, 5522 req_size, /* how large were the requests */ 5523 rsp_size, /* how large were the responses */ 5524 elapsed_time, /* how long did it take */ 5525 nummessages/elapsed_time); 5526 fprintf(where, 5527 tput_fmt_1_line_2, 5528 rss_size, /* remote recvbuf size */ 5529 rsr_size); 5530 5531 break; 5532 } 5533 } 5534 5535 /* it would be a good thing to include information about some of the */ 5536 /* other parameters that may have been set for this test, but at the */ 5537 /* moment, I do not wish to figure-out all the formatting, so I will */ 5538 /* just put this comment here to help remind me that it is something */ 5539 /* that should be done at a later time. */ 5540 5541 if (verbosity > 1) { 5542 /* The user wanted to know it all, so we will give it to him. */ 5543 /* This information will include as much as we can find about */ 5544 /* TCP statistics, the alignments of the sends and receives */ 5545 /* and all that sort of rot... */ 5546 5547 fprintf(where, 5548 ksink_fmt); 5549 } 5550 5551 } 5552 5553 5554 void 5556 recv_xti_tcp_conn_rr() 5557 { 5558 5559 char *message; 5560 struct sockaddr_in myaddr_in, 5561 peeraddr_in; 5562 SOCKET s_listen,s_data; 5563 int addrlen; 5564 char *recv_message_ptr; 5565 char *send_message_ptr; 5566 char *temp_message_ptr; 5567 int trans_received; 5568 int trans_remaining; 5569 int bytes_sent; 5570 int request_bytes_recvd; 5571 int request_bytes_remaining; 5572 int timed_out = 0; 5573 float elapsed_time; 5574 5575 struct xti_tcp_conn_rr_request_struct *xti_tcp_conn_rr_request; 5576 struct xti_tcp_conn_rr_response_struct *xti_tcp_conn_rr_response; 5577 struct xti_tcp_conn_rr_results_struct *xti_tcp_conn_rr_results; 5578 5579 xti_tcp_conn_rr_request = 5580 (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data; 5581 xti_tcp_conn_rr_response = 5582 (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data; 5583 xti_tcp_conn_rr_results = 5584 (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data; 5585 5586 if (debug) { 5587 fprintf(where,"netserver: recv_xti_tcp_conn_rr: entered...\n"); 5588 fflush(where); 5589 } 5590 5591 /* We want to set-up the listen socket with all the desired */ 5592 /* parameters and then let the initiator know that all is ready. If */ 5593 /* socket size defaults are to be used, then the initiator will have */ 5594 /* sent us 0's. If the socket sizes cannot be changed, then we will */ 5595 /* send-back what they are. If that information cannot be determined, */ 5596 /* then we send-back -1's for the sizes. If things go wrong for any */ 5597 /* reason, we will drop back ten yards and punt. */ 5598 5599 /* If anything goes wrong, we want the remote to know about it. It */ 5600 /* would be best if the error that the remote reports to the user is */ 5601 /* the actual error we encountered, rather than some bogus unexpected */ 5602 /* response type message. */ 5603 5604 if (debug) { 5605 fprintf(where,"recv_xti_tcp_conn_rr: setting the response type...\n"); 5606 fflush(where); 5607 } 5608 5609 netperf_response.content.response_type = XTI_TCP_CRR_RESPONSE; 5610 5611 if (debug) { 5612 fprintf(where,"recv_xti_tcp_conn_rr: the response type is set...\n"); 5613 fflush(where); 5614 } 5615 5616 /* set-up the data buffer with the requested alignment and offset */ 5617 message = (char *)malloc(DATABUFFERLEN); 5618 if (message == NULL) { 5619 printf("malloc(%d) failed!\n", DATABUFFERLEN); 5620 exit(1); 5621 } 5622 5623 /* We now alter the message_ptr variables to be at the desired */ 5624 /* alignments with the desired offsets. */ 5625 5626 if (debug) { 5627 fprintf(where, 5628 "recv_xti_tcp_conn_rr: requested recv alignment of %d offset %d\n", 5629 xti_tcp_conn_rr_request->recv_alignment, 5630 xti_tcp_conn_rr_request->recv_offset); 5631 fprintf(where, 5632 "recv_xti_tcp_conn_rr: requested send alignment of %d offset %d\n", 5633 xti_tcp_conn_rr_request->send_alignment, 5634 xti_tcp_conn_rr_request->send_offset); 5635 fflush(where); 5636 } 5637 5638 recv_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->recv_alignment, xti_tcp_conn_rr_request->recv_offset); 5639 5640 send_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->send_alignment, xti_tcp_conn_rr_request->send_offset); 5641 5642 if (debug) { 5643 fprintf(where,"recv_xti_tcp_conn_rr: receive alignment and offset set...\n"); 5644 fflush(where); 5645 } 5646 5647 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ 5648 /* can put in OUR values !-) At some point, we may want to nail this */ 5649 /* socket to a particular network-level address, but for now, */ 5650 /* INADDR_ANY should be just fine. */ 5651 5652 bzero((char *)&myaddr_in, 5653 sizeof(myaddr_in)); 5654 myaddr_in.sin_family = AF_INET; 5655 myaddr_in.sin_addr.s_addr = INADDR_ANY; 5656 myaddr_in.sin_port = 0; 5657 5658 /* Grab a socket to listen on, and then listen on it. */ 5659 5660 if (debug) { 5661 fprintf(where,"recv_xti_tcp_conn_rr: grabbing a socket...\n"); 5662 fflush(where); 5663 } 5664 5665 /* create_xti_endpoint expects to find some things in the global */ 5666 /* variables, so set the globals based on the values in the request. */ 5667 /* once the socket has been created, we will set the response values */ 5668 /* based on the updated value of those globals. raj 7/94 */ 5669 lss_size = xti_tcp_conn_rr_request->send_buf_size; 5670 lsr_size = xti_tcp_conn_rr_request->recv_buf_size; 5671 loc_nodelay = xti_tcp_conn_rr_request->no_delay; 5672 loc_rcvavoid = xti_tcp_conn_rr_request->so_rcvavoid; 5673 loc_sndavoid = xti_tcp_conn_rr_request->so_sndavoid; 5674 5675 s_listen = create_xti_endpoint(loc_xti_device); 5676 5677 if (s_listen == INVALID_SOCKET) { 5678 netperf_response.content.serv_errno = errno; 5679 send_response(); 5680 if (debug) { 5681 fprintf(where,"could not create data socket\n"); 5682 fflush(where); 5683 } 5684 exit(1); 5685 } 5686 5687 /* Let's get an address assigned to this socket so we can tell the */ 5688 /* initiator how to reach the data socket. There may be a desire to */ 5689 /* nail this socket to a specific IP address in a multi-homed, */ 5690 /* multi-connection situation, but for now, we'll ignore the issue */ 5691 /* and concentrate on single connection testing. */ 5692 5693 if (bind(s_listen, 5694 (struct sockaddr *)&myaddr_in, 5695 sizeof(myaddr_in)) == SOCKET_ERROR) { 5696 netperf_response.content.serv_errno = errno; 5697 close(s_listen); 5698 send_response(); 5699 if (debug) { 5700 fprintf(where,"could not bind\n"); 5701 fflush(where); 5702 } 5703 exit(1); 5704 } 5705 5706 /* Now, let's set-up the socket to listen for connections */ 5707 if (listen(s_listen, 5) == SOCKET_ERROR) { 5708 netperf_response.content.serv_errno = errno; 5709 close(s_listen); 5710 send_response(); 5711 if (debug) { 5712 fprintf(where,"could not listen\n"); 5713 fflush(where); 5714 } 5715 exit(1); 5716 } 5717 5718 /* now get the port number assigned by the system */ 5719 addrlen = sizeof(myaddr_in); 5720 if (getsockname(s_listen, 5721 (struct sockaddr *)&myaddr_in, 5722 &addrlen) == SOCKET_ERROR){ 5723 netperf_response.content.serv_errno = errno; 5724 close(s_listen); 5725 send_response(); 5726 if (debug) { 5727 fprintf(where,"could not geetsockname\n"); 5728 fflush(where); 5729 } 5730 exit(1); 5731 } 5732 5733 /* Now myaddr_in contains the port and the internet address this is */ 5734 /* returned to the sender also implicitly telling the sender that the */ 5735 /* socket buffer sizing has been done. */ 5736 5737 xti_tcp_conn_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); 5738 if (debug) { 5739 fprintf(where,"telling the remote to call me at %d\n", 5740 xti_tcp_conn_rr_response->data_port_number); 5741 fflush(where); 5742 } 5743 netperf_response.content.serv_errno = 0; 5744 5745 /* But wait, there's more. If the initiator wanted cpu measurements, */ 5746 /* then we must call the calibrate routine, which will return the max */ 5747 /* rate back to the initiator. If the CPU was not to be measured, or */ 5748 /* something went wrong with the calibration, we will return a 0.0 to */ 5749 /* the initiator. */ 5750 5751 xti_tcp_conn_rr_response->cpu_rate = 0.0; /* assume no cpu */ 5752 if (xti_tcp_conn_rr_request->measure_cpu) { 5753 xti_tcp_conn_rr_response->measure_cpu = 1; 5754 xti_tcp_conn_rr_response->cpu_rate = 5755 calibrate_local_cpu(xti_tcp_conn_rr_request->cpu_rate); 5756 } 5757 5758 5759 5760 /* before we send the response back to the initiator, pull some of */ 5761 /* the socket parms from the globals */ 5762 xti_tcp_conn_rr_response->send_buf_size = lss_size; 5763 xti_tcp_conn_rr_response->recv_buf_size = lsr_size; 5764 xti_tcp_conn_rr_response->no_delay = loc_nodelay; 5765 xti_tcp_conn_rr_response->so_rcvavoid = loc_rcvavoid; 5766 xti_tcp_conn_rr_response->so_sndavoid = loc_sndavoid; 5767 5768 send_response(); 5769 5770 addrlen = sizeof(peeraddr_in); 5771 5772 /* Now it's time to start receiving data on the connection. We will */ 5773 /* first grab the apropriate counters and then start grabbing. */ 5774 5775 cpu_start(xti_tcp_conn_rr_request->measure_cpu); 5776 5777 /* The loop will exit when the sender does a shutdown, which will */ 5778 /* return a length of zero */ 5779 5780 if (xti_tcp_conn_rr_request->test_length > 0) { 5781 times_up = 0; 5782 trans_remaining = 0; 5783 start_timer(xti_tcp_conn_rr_request->test_length + PAD_TIME); 5784 } 5785 else { 5786 times_up = 1; 5787 trans_remaining = xti_tcp_conn_rr_request->test_length * -1; 5788 } 5789 5790 trans_received = 0; 5791 5792 while ((!times_up) || (trans_remaining > 0)) { 5793 5794 /* accept a connection from the remote */ 5795 if ((s_data=accept(s_listen, 5796 (struct sockaddr *)&peeraddr_in, 5797 &addrlen)) == INVALID_SOCKET) { 5798 if (errno == EINTR) { 5799 /* the timer popped */ 5800 timed_out = 1; 5801 break; 5802 } 5803 fprintf(where,"recv_xti_tcp_conn_rr: accept: errno = %d\n",errno); 5804 fflush(where); 5805 close(s_listen); 5806 5807 exit(1); 5808 } 5809 5810 if (debug) { 5811 fprintf(where,"recv_xti_tcp_conn_rr: accepted data connection.\n"); 5812 fflush(where); 5813 } 5814 5815 temp_message_ptr = recv_message_ptr; 5816 request_bytes_remaining = xti_tcp_conn_rr_request->request_size; 5817 5818 /* receive the request from the other side */ 5819 while(request_bytes_remaining > 0) { 5820 if((request_bytes_recvd=recv(s_data, 5821 temp_message_ptr, 5822 request_bytes_remaining, 5823 0)) == SOCKET_ERROR) { 5824 if (errno == EINTR) { 5825 /* the timer popped */ 5826 timed_out = 1; 5827 break; 5828 } 5829 netperf_response.content.serv_errno = errno; 5830 send_response(); 5831 exit(1); 5832 } 5833 else { 5834 request_bytes_remaining -= request_bytes_recvd; 5835 temp_message_ptr += request_bytes_recvd; 5836 } 5837 } 5838 5839 if (timed_out) { 5840 /* we hit the end of the test based on time - lets */ 5841 /* bail out of here now... */ 5842 fprintf(where,"yo5\n"); 5843 fflush(where); 5844 break; 5845 } 5846 5847 /* Now, send the response to the remote */ 5848 if((bytes_sent=send(s_data, 5849 send_message_ptr, 5850 xti_tcp_conn_rr_request->response_size, 5851 0)) == SOCKET_ERROR) { 5852 if (errno == EINTR) { 5853 /* the test timer has popped */ 5854 timed_out = 1; 5855 fprintf(where,"yo6\n"); 5856 fflush(where); 5857 break; 5858 } 5859 netperf_response.content.serv_errno = 99; 5860 send_response(); 5861 exit(1); 5862 } 5863 5864 trans_received++; 5865 if (trans_remaining) { 5866 trans_remaining--; 5867 } 5868 5869 if (debug) { 5870 fprintf(where, 5871 "recv_xti_tcp_conn_rr: Transaction %d complete\n", 5872 trans_received); 5873 fflush(where); 5874 } 5875 5876 /* close the connection */ 5877 close(s_data); 5878 5879 } 5880 5881 5882 /* The loop now exits due to timeout or transaction count being */ 5883 /* reached */ 5884 5885 cpu_stop(xti_tcp_conn_rr_request->measure_cpu,&elapsed_time); 5886 5887 if (timed_out) { 5888 /* we ended the test by time, which was at least 2 seconds */ 5889 /* longer than we wanted to run. so, we want to subtract */ 5890 /* PAD_TIME from the elapsed_time. */ 5891 elapsed_time -= PAD_TIME; 5892 } 5893 /* send the results to the sender */ 5894 5895 if (debug) { 5896 fprintf(where, 5897 "recv_xti_tcp_conn_rr: got %d transactions\n", 5898 trans_received); 5899 fflush(where); 5900 } 5901 5902 xti_tcp_conn_rr_results->bytes_received = (trans_received * 5903 (xti_tcp_conn_rr_request->request_size + 5904 xti_tcp_conn_rr_request->response_size)); 5905 xti_tcp_conn_rr_results->trans_received = trans_received; 5906 xti_tcp_conn_rr_results->elapsed_time = elapsed_time; 5907 if (xti_tcp_conn_rr_request->measure_cpu) { 5908 xti_tcp_conn_rr_results->cpu_util = calc_cpu_util(elapsed_time); 5909 } 5910 5911 if (debug) { 5912 fprintf(where, 5913 "recv_xti_tcp_conn_rr: test complete, sending results.\n"); 5914 fflush(where); 5915 } 5916 5917 send_response(); 5918 5919 } 5920 5921 void 5923 print_xti_usage() 5924 { 5925 5926 fwrite(xti_usage, sizeof(char), strlen(xti_usage), stdout); 5927 exit(1); 5928 5929 } 5930 5931 void 5932 scan_xti_args(int argc, char *argv[]) 5933 { 5934 #define XTI_ARGS "Dhm:M:r:s:S:Vw:W:X:" 5935 extern int optind, opterrs; /* index of first unused arg */ 5936 extern char *optarg; /* pointer to option string */ 5937 5938 int c; 5939 5940 char 5941 arg1[BUFSIZ], /* argument holders */ 5942 arg2[BUFSIZ]; 5943 5944 if (no_control) { 5945 fprintf(where, 5946 "The XTI tests do not know how to run with no control connection\n"); 5947 exit(-1); 5948 } 5949 5950 /* Go through all the command line arguments and break them */ 5951 /* out. For those options that take two parms, specifying only */ 5952 /* the first will set both to that value. Specifying only the */ 5953 /* second will leave the first untouched. To change only the */ 5954 /* first, use the form "first," (see the routine break_args.. */ 5955 5956 while ((c= getopt(argc, argv, XTI_ARGS)) != EOF) { 5957 switch (c) { 5958 case '?': 5959 case 'h': 5960 print_xti_usage(); 5961 exit(1); 5962 case 'D': 5963 /* set the TCP nodelay flag */ 5964 loc_nodelay = 1; 5965 rem_nodelay = 1; 5966 break; 5967 case 's': 5968 /* set local socket sizes */ 5969 break_args(optarg,arg1,arg2); 5970 if (arg1[0]) 5971 lss_size = convert(arg1); 5972 if (arg2[0]) 5973 lsr_size = convert(arg2); 5974 break; 5975 case 'S': 5976 /* set remote socket sizes */ 5977 break_args(optarg,arg1,arg2); 5978 if (arg1[0]) 5979 rss_size = convert(arg1); 5980 if (arg2[0]) 5981 rsr_size = convert(arg2); 5982 break; 5983 case 'r': 5984 /* set the request/response sizes */ 5985 break_args(optarg,arg1,arg2); 5986 if (arg1[0]) 5987 req_size = convert(arg1); 5988 if (arg2[0]) 5989 rsp_size = convert(arg2); 5990 break; 5991 case 'm': 5992 /* set the send size */ 5993 send_size = convert(optarg); 5994 break; 5995 case 'M': 5996 /* set the recv size */ 5997 recv_size = convert(optarg); 5998 break; 5999 case 'W': 6000 /* set the "width" of the user space data */ 6001 /* buffer. This will be the number of */ 6002 /* send_size buffers malloc'd in the */ 6003 /* *_STREAM test. It may be enhanced to set */ 6004 /* both send and receive "widths" but for now */ 6005 /* it is just the sending *_STREAM. */ 6006 send_width = convert(optarg); 6007 break; 6008 case 'V' : 6009 /* we want to do copy avoidance and will set */ 6010 /* it for everything, everywhere, if we really */ 6011 /* can. of course, we don't know anything */ 6012 /* about the remote... */ 6013 #ifdef SO_SND_COPYAVOID 6014 loc_sndavoid = 1; 6015 #else 6016 loc_sndavoid = 0; 6017 printf("Local send copy avoidance not available.\n"); 6018 #endif 6019 #ifdef SO_RCV_COPYAVOID 6020 loc_rcvavoid = 1; 6021 #else 6022 loc_rcvavoid = 0; 6023 printf("Local recv copy avoidance not available.\n"); 6024 #endif 6025 rem_sndavoid = 1; 6026 rem_rcvavoid = 1; 6027 break; 6028 case 'X': 6029 /* set the xti device file name(s) */ 6030 break_args(optarg,arg1,arg2); 6031 if (arg1[0]) 6032 strcpy(loc_xti_device,arg1); 6033 if (arg2[0]) 6034 strcpy(rem_xti_device,arg2); 6035 break; 6036 }; 6037 } 6038 } 6039 #endif /* WANT_XTI */ 6040