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