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