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