1 char netlib_id[]="\ 2 @(#)netlib.c (c) Copyright 1993-2007 Hewlett-Packard Company. Version 2.4.3"; 3 4 5 /****************************************************************/ 6 /* */ 7 /* netlib.c */ 8 /* */ 9 /* the common utility routines available to all... */ 10 /* */ 11 /* establish_control() establish the control socket */ 12 /* calibrate_local_cpu() do local cpu calibration */ 13 /* calibrate_remote_cpu() do remote cpu calibration */ 14 /* send_request() send a request to the remote */ 15 /* recv_response() receive a response from remote */ 16 /* send_response() send a response to the remote */ 17 /* recv_request() recv a request from the remote */ 18 /* dump_request() dump request contents */ 19 /* dump_response() dump response contents */ 20 /* cpu_start() start measuring cpu */ 21 /* cpu_stop() stop measuring cpu */ 22 /* calc_cpu_util() calculate the cpu utilization */ 23 /* calc_service_demand() calculate the service demand */ 24 /* calc_thruput() calulate the tput in units */ 25 /* calibrate() really calibrate local cpu */ 26 /* identify_local() print local host information */ 27 /* identify_remote() print remote host information */ 28 /* format_number() format the number (KB, MB,etc) */ 29 /* format_units() return the format in english */ 30 /* msec_sleep() sleep for some msecs */ 31 /* start_timer() start a timer */ 32 /* */ 33 /* the routines you get when WANT_DLPI is defined... */ 34 /* */ 35 /* dl_open() open a file descriptor and */ 36 /* attach to the card */ 37 /* dl_mtu() find the MTU of the card */ 38 /* dl_bind() bind the sap do the card */ 39 /* dl_connect() sender's have of connect */ 40 /* dl_accpet() receiver's half of connect */ 41 /* dl_set_window() set the window size */ 42 /* dl_stats() retrieve statistics */ 43 /* dl_send_disc() initiate disconnect (sender) */ 44 /* dl_recv_disc() accept disconnect (receiver) */ 45 /****************************************************************/ 46 47 /****************************************************************/ 48 /* */ 49 /* Global include files */ 50 /* */ 51 /****************************************************************/ 52 53 #ifdef HAVE_CONFIG_H 54 #include <config.h> 55 #endif 56 57 /* It would seem that most of the includes being done here from */ 58 /* "sys/" actually have higher-level wrappers at just /usr/include. */ 59 /* This is based on a spot-check of a couple systems at my disposal. */ 60 /* If you have trouble compiling you may want to add "sys/" raj 10/95 */ 61 #include <limits.h> 62 #include <signal.h> 63 #ifdef MPE 64 # define NSIG _NSIG 65 #endif /* MPE */ 66 #include <sys/types.h> 67 #include <fcntl.h> 68 #include <stdio.h> 69 #include <stdlib.h> 70 #include <math.h> 71 #include <string.h> 72 #include <assert.h> 73 #ifdef HAVE_ENDIAN_H 74 #include <endian.h> 75 #endif 76 77 78 #ifndef WIN32 79 /* at some point, I would like to get rid of all these "sys/" */ 80 /* includes where appropriate. if you have a system that requires */ 81 /* them, speak now, or your system may not comile later revisions of */ 82 /* netperf. raj 1/96 */ 83 #include <unistd.h> 84 #include <sys/stat.h> 85 #include <sys/times.h> 86 #ifndef MPE 87 #include <time.h> 88 #include <sys/time.h> 89 #endif /* MPE */ 90 #include <sys/socket.h> 91 #include <netinet/in.h> 92 #include <arpa/inet.h> 93 #include <netdb.h> 94 #include <errno.h> 95 #include <sys/utsname.h> 96 #if !defined(MPE) && !defined(__VMS) 97 #include <sys/param.h> 98 #endif /* MPE */ 99 100 #else /* WIN32 */ 101 102 #include <process.h> 103 #include <time.h> 104 #include <winsock2.h> 105 #define netperf_socklen_t socklen_t 106 #include <windows.h> 107 108 /* the only time someone should need to define DONT_IPV6 in the 109 "sources" file is if they are trying to compile on Windows 2000 or 110 NT4 and I suspect this may not be their only problem :) */ 111 #ifndef DONT_IPV6 112 #include <ws2tcpip.h> 113 #endif 114 115 #include <windows.h> 116 117 #define SIGALRM (14) 118 #define sleep(x) Sleep((x)*1000) 119 120 #endif /* WIN32 */ 121 122 #ifdef _AIX 123 #include <sys/select.h> 124 #include <sys/sched.h> 125 #include <sys/pri.h> 126 #define PRIORITY PRI_LOW 127 #else/* _AIX */ 128 #ifdef __sgi 129 #include <sys/prctl.h> 130 #include <sys/schedctl.h> 131 #define PRIORITY NDPLOMIN 132 #endif /* __sgi */ 133 #endif /* _AIX */ 134 135 #ifdef WANT_DLPI 136 #include <sys/stream.h> 137 #include <sys/stropts.h> 138 #include <sys/poll.h> 139 #ifdef __osf__ 140 #include <sys/dlpihdr.h> 141 #else /* __osf__ */ 142 #include <sys/dlpi.h> 143 #ifdef __hpux 144 #include <sys/dlpi_ext.h> 145 #endif /* __hpux */ 146 #endif /* __osf__ */ 147 #endif /* WANT_DLPI */ 148 149 #ifdef HAVE_MPCTL 150 #include <sys/mpctl.h> 151 #endif 152 153 #if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO) 154 # include "missing/getaddrinfo.h" 155 #endif 156 157 158 #ifdef WANT_HISTOGRAM 159 #include "hist.h" 160 #endif /* WANT_HISTOGRAM */ 161 /****************************************************************/ 162 /* */ 163 /* Local Include Files */ 164 /* */ 165 /****************************************************************/ 166 #define NETLIB 167 #include "netlib.h" 168 #include "netsh.h" 169 #include "netcpu.h" 170 171 /****************************************************************/ 172 /* */ 173 /* Global constants, macros and variables */ 174 /* */ 175 /****************************************************************/ 176 177 #if defined(WIN32) || defined(__VMS) 178 struct timezone { 179 int dummy ; 180 } ; 181 #ifndef __VMS 182 SOCKET win_kludge_socket = INVALID_SOCKET; 183 SOCKET win_kludge_socket2 = INVALID_SOCKET; 184 #endif /* __VMS */ 185 #endif /* WIN32 || __VMS */ 186 187 #ifndef LONG_LONG_MAX 188 #define LONG_LONG_MAX 9223372036854775807LL 189 #endif /* LONG_LONG_MAX */ 190 191 /* older versions of netperf knew about the HP kernel IDLE counter. */ 192 /* this is now obsolete - in favor of either pstat(), times, or a */ 193 /* process-level looper process. we also now require support for the */ 194 /* "long" integer type. raj 4/95. */ 195 196 int 197 lib_num_loc_cpus, /* the number of cpus in the system */ 198 lib_num_rem_cpus; /* how many we think are in the remote */ 199 200 #define PAGES_PER_CHILD 2 201 202 int lib_use_idle; 203 int cpu_method; 204 205 struct timeval time1, time2; 206 struct timezone tz; 207 float lib_elapsed, 208 lib_local_maxrate, 209 lib_remote_maxrate, 210 lib_local_cpu_util, 211 lib_remote_cpu_util; 212 213 float lib_local_per_cpu_util[MAXCPUS]; 214 int lib_cpu_map[MAXCPUS]; 215 216 int *request_array; 217 int *response_array; 218 219 /* INVALID_SOCKET == INVALID_HANDLE_VALUE == (unsigned int)(~0) == -1 */ 220 SOCKET netlib_control = INVALID_SOCKET; 221 SOCKET server_sock = INVALID_SOCKET; 222 223 /* global variables to hold the value for processor affinity */ 224 int local_proc_affinity,remote_proc_affinity = -1; 225 226 /* these are to allow netperf to be run easily through those evil, 227 end-to-end breaking things known as firewalls */ 228 char local_data_port[10]; 229 char remote_data_port[10]; 230 231 char *local_data_address=NULL; 232 char *remote_data_address=NULL; 233 234 int local_data_family=AF_UNSPEC; 235 int remote_data_family=AF_UNSPEC; 236 237 /* in the past, I was overlaying a structure on an array of ints. now */ 238 /* I am going to have a "real" structure, and point an array of ints */ 239 /* at it. the real structure will be forced to the same alignment as */ 240 /* the type "double." this change will mean that pre-2.1 netperfs */ 241 /* cannot be mixed with 2.1 and later. raj 11/95 */ 242 243 union netperf_request_struct netperf_request; 244 union netperf_response_struct netperf_response; 245 246 FILE *where; 247 248 char libfmt = '?'; 249 250 #ifdef WANT_DLPI 251 /* some stuff for DLPI control messages */ 252 #define DLPI_DATA_SIZE 2048 253 254 unsigned long control_data[DLPI_DATA_SIZE]; 255 struct strbuf control_message = {DLPI_DATA_SIZE, 0, (char *)control_data}; 256 257 #endif /* WANT_DLPI */ 258 259 #ifdef WIN32 260 HANDLE hAlarm = INVALID_HANDLE_VALUE; 261 #endif 262 263 int times_up; 264 265 #ifdef WIN32 266 /* we use a getopt implementation from net.sources */ 267 /* 268 * get option letter from argument vector 269 */ 270 int 271 opterr = 1, /* should error messages be printed? */ 272 optind = 1, /* index into parent argv vector */ 273 optopt; /* character checked for validity */ 274 char 275 *optarg; /* argument associated with option */ 276 277 #define EMSG "" 278 279 #endif /* WIN32 */ 280 281 static int measuring_cpu; 282 int 283 netlib_get_page_size(void) { 284 285 /* not all systems seem to have the sysconf for page size. for 286 those which do not, we will assume that the page size is 8192 287 bytes. this should be more than enough to be sure that there is 288 no page or cache thrashing by looper processes on MP 289 systems. otherwise that's really just too bad - such systems 290 should define _SC_PAGE_SIZE - raj 4/95 */ 291 292 #ifndef _SC_PAGE_SIZE 293 #ifdef WIN32 294 295 SYSTEM_INFO SystemInfo; 296 297 GetSystemInfo(&SystemInfo); 298 299 return SystemInfo.dwPageSize; 300 #else 301 return(8192L); 302 #endif /* WIN32 */ 303 #else 304 return(sysconf(_SC_PAGE_SIZE)); 305 #endif /* _SC_PAGE_SIZE */ 306 307 } 308 309 310 #ifdef WANT_INTERVALS 312 static unsigned int usec_per_itvl; 313 314 315 void 316 stop_itimer() 317 318 { 319 320 struct itimerval new_interval; 321 struct itimerval old_interval; 322 323 new_interval.it_interval.tv_sec = 0; 324 new_interval.it_interval.tv_usec = 0; 325 new_interval.it_value.tv_sec = 0; 326 new_interval.it_value.tv_usec = 0; 327 if (setitimer(ITIMER_REAL,&new_interval,&old_interval) != 0) { 328 /* there was a problem arming the interval timer */ 329 perror("netperf: setitimer"); 330 exit(1); 331 } 332 return; 333 } 334 #endif /* WANT_INTERVALS */ 335 336 338 339 #ifdef WIN32 341 static void 342 error(char *pch) 343 { 344 if (!opterr) { 345 return; /* without printing */ 346 } 347 fprintf(stderr, "%s: %s: %c\n", 348 (NULL != program) ? program : "getopt", pch, optopt); 349 } 350 351 int 352 getopt(int argc, char **argv, char *ostr) 353 { 354 static char *place = EMSG; /* option letter processing */ 355 register char *oli; /* option letter list index */ 356 357 if (!*place) { 358 /* update scanning pointer */ 359 if (optind >= argc || *(place = argv[optind]) != '-' || !*++place) { 360 return EOF; 361 } 362 if (*place == '-') { 363 /* found "--" */ 364 ++optind; 365 place = EMSG ; /* Added by shiva for Netperf */ 366 return EOF; 367 } 368 } 369 370 /* option letter okay? */ 371 if ((optopt = (int)*place++) == (int)':' 372 || !(oli = strchr(ostr, optopt))) { 373 if (!*place) { 374 ++optind; 375 } 376 error("illegal option"); 377 return BADCH; 378 } 379 if (*++oli != ':') { 380 /* don't need argument */ 381 optarg = NULL; 382 if (!*place) 383 ++optind; 384 } else { 385 /* need an argument */ 386 if (*place) { 387 optarg = place; /* no white space */ 388 } else if (argc <= ++optind) { 389 /* no arg */ 390 place = EMSG; 391 error("option requires an argument"); 392 return BADCH; 393 } else { 394 optarg = argv[optind]; /* white space */ 395 } 396 place = EMSG; 397 ++optind; 398 } 399 return optopt; /* return option letter */ 400 } 401 #endif /* WIN32 */ 402 403 /*---------------------------------------------------------------------------- 404 * WIN32 implementation of perror, does not deal very well with WSA errors 405 * The stdlib.h version of perror only deals with the ancient XENIX error codes. 406 * 407 * +*+SAF Why can't all WSA errors go through GetLastError? Most seem to... 408 *--------------------------------------------------------------------------*/ 409 410 #ifdef WIN32 411 void PrintWin32Error(FILE *stream, LPSTR text) 412 { 413 LPSTR szTemp; 414 DWORD dwResult; 415 DWORD dwError; 416 417 dwError = GetLastError(); 418 dwResult = FormatMessage( 419 FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY, 420 NULL, 421 dwError, 422 LANG_NEUTRAL, 423 (LPTSTR)&szTemp, 424 0, 425 NULL ); 426 427 if (dwResult) 428 fprintf(stream, "%s: %s\n", text, szTemp); 429 else 430 fprintf(stream, "%s: error 0x%x\n", text, dwError); 431 fflush(stream); 432 433 if (szTemp) 434 LocalFree((HLOCAL)szTemp); 435 } 436 #endif /* WIN32 */ 437 438 439 char * 441 inet_ttos(int type) 442 { 443 switch (type) { 444 case SOCK_DGRAM: 445 return("SOCK_DGRAM"); 446 break; 447 case SOCK_STREAM: 448 return("SOCK_STREAM"); 449 break; 450 default: 451 return("SOCK_UNKNOWN"); 452 } 453 } 454 455 456 457 char unknown[32]; 459 460 char * 461 inet_ptos(int protocol) { 462 switch (protocol) { 463 case IPPROTO_TCP: 464 return("IPPROTO_TCP"); 465 break; 466 case IPPROTO_UDP: 467 return("IPPROTO_UDP"); 468 break; 469 #if defined(IPPROTO_SCTP) 470 case IPPROTO_SCTP: 471 return("IPPROTO_SCTP"); 472 break; 473 #endif 474 default: 475 snprintf(unknown,sizeof(unknown),"IPPROTO_UNKNOWN(%d)",protocol); 476 return(unknown); 477 } 478 } 479 480 /* one of these days, this should not be required */ 481 #ifndef AF_INET_SDP 482 #define AF_INET_SDP 27 483 #define PF_INET_SDP AF_INET_SDP 484 #endif 485 486 char * 487 inet_ftos(int family) 488 { 489 switch(family) { 490 case AF_INET: 491 return("AF_INET"); 492 break; 493 #if defined(AF_INET6) 494 case AF_INET6: 495 return("AF_INET6"); 496 break; 497 #endif 498 #if defined(AF_INET_SDP) 499 case AF_INET_SDP: 500 return("AF_INET_SDP"); 501 break; 502 #endif 503 default: 504 return("AF_UNSPEC"); 505 } 506 } 507 508 int 509 inet_nton(int af, const void *src, char *dst, int cnt) 510 511 { 512 513 switch (af) { 514 case AF_INET: 515 /* magic constants again... :) */ 516 if (cnt >= 4) { 517 memcpy(dst,src,4); 518 return 4; 519 } 520 else { 521 Set_errno(ENOSPC); 522 return(-1); 523 } 524 break; 525 #if defined(AF_INET6) 526 case AF_INET6: 527 if (cnt >= 16) { 528 memcpy(dst,src,16); 529 return(16); 530 } 531 else { 532 Set_errno(ENOSPC); 533 return(-1); 534 } 535 break; 536 #endif 537 default: 538 Set_errno(EAFNOSUPPORT); 539 return(-1); 540 } 541 } 542 543 double 544 ntohd(double net_double) 545 546 { 547 /* we rely on things being nicely packed */ 548 union { 549 double whole_thing; 550 unsigned int words[2]; 551 unsigned char bytes[8]; 552 } conv_rec; 553 554 unsigned char scratch; 555 int i; 556 557 /* on those systems where ntohl is a no-op, we want to return the */ 558 /* original value, unchanged */ 559 560 if (ntohl(1L) == 1L) { 561 return(net_double); 562 } 563 564 conv_rec.whole_thing = net_double; 565 566 /* we know that in the message passing routines that ntohl will have */ 567 /* been called on the 32 bit quantities. we need to put those back */ 568 /* the way they belong before we swap */ 569 conv_rec.words[0] = htonl(conv_rec.words[0]); 570 conv_rec.words[1] = htonl(conv_rec.words[1]); 571 572 /* now swap */ 573 for (i=0; i<= 3; i++) { 574 scratch = conv_rec.bytes[i]; 575 conv_rec.bytes[i] = conv_rec.bytes[7-i]; 576 conv_rec.bytes[7-i] = scratch; 577 } 578 579 #if defined(__FLOAT_WORD_ORDER) && defined(__BYTE_ORDER) 580 if (__FLOAT_WORD_ORDER != __BYTE_ORDER) { 581 /* Fixup mixed endian floating point machines */ 582 unsigned int scratch = conv_rec.words[0]; 583 conv_rec.words[0] = conv_rec.words[1]; 584 conv_rec.words[1] = scratch; 585 } 586 #endif 587 588 return(conv_rec.whole_thing); 589 590 } 591 592 double 593 htond(double host_double) 594 595 { 596 /* we rely on things being nicely packed */ 597 union { 598 double whole_thing; 599 unsigned int words[2]; 600 unsigned char bytes[8]; 601 } conv_rec; 602 603 unsigned char scratch; 604 int i; 605 606 /* on those systems where ntohl is a no-op, we want to return the */ 607 /* original value, unchanged */ 608 609 if (ntohl(1L) == 1L) { 610 return(host_double); 611 } 612 613 conv_rec.whole_thing = host_double; 614 615 /* now swap */ 616 for (i=0; i<= 3; i++) { 617 scratch = conv_rec.bytes[i]; 618 conv_rec.bytes[i] = conv_rec.bytes[7-i]; 619 conv_rec.bytes[7-i] = scratch; 620 } 621 622 #if defined(__FLOAT_WORD_ORDER) && defined(__BYTE_ORDER) 623 if (__FLOAT_WORD_ORDER != __BYTE_ORDER) { 624 /* Fixup mixed endian floating point machines */ 625 unsigned int scratch = conv_rec.words[0]; 626 conv_rec.words[0] = conv_rec.words[1]; 627 conv_rec.words[1] = scratch; 628 } 629 #endif 630 631 /* we know that in the message passing routines htonl will */ 632 /* be called on the 32 bit quantities. we need to set things up so */ 633 /* that when this happens, the proper order will go out on the */ 634 /* network */ 635 conv_rec.words[0] = htonl(conv_rec.words[0]); 636 conv_rec.words[1] = htonl(conv_rec.words[1]); 637 638 return(conv_rec.whole_thing); 639 640 } 641 642 644 /* one of these days, this should be abstracted-out just like the CPU 645 util stuff. raj 2005-01-27 */ 646 int 647 get_num_cpus() 648 649 { 650 651 /* on HP-UX, even when we use the looper procs we need the pstat */ 652 /* call */ 653 654 int temp_cpus; 655 656 #ifdef __hpux 657 #include <sys/pstat.h> 658 659 struct pst_dynamic psd; 660 661 if (pstat_getdynamic((struct pst_dynamic *)&psd, 662 (size_t)sizeof(psd), (size_t)1, 0) != -1) { 663 temp_cpus = psd.psd_proc_cnt; 664 } 665 else { 666 temp_cpus = 1; 667 } 668 669 #else 670 /* MW: <unistd.h> was included for non-Windows systems above. */ 671 /* Thus if _SC_NPROC_ONLN is defined, we should be able to use sysconf. */ 672 #ifdef _SC_NPROCESSORS_ONLN 673 temp_cpus = sysconf(_SC_NPROCESSORS_ONLN); 674 675 #ifdef USE_PERFSTAT 676 temp_cpus = perfstat_cpu(NULL,NULL, sizeof(perfstat_cpu_t), 0); 677 #endif /* USE_PERFSTAT */ 678 679 #else /* no _SC_NPROCESSORS_ONLN */ 680 681 #ifdef WIN32 682 SYSTEM_INFO SystemInfo; 683 GetSystemInfo(&SystemInfo); 684 685 temp_cpus = SystemInfo.dwNumberOfProcessors; 686 #else 687 /* we need to know some other ways to do this, or just fall-back on */ 688 /* a global command line option - raj 4/95 */ 689 temp_cpus = shell_num_cpus; 690 #endif /* WIN32 */ 691 #endif /* _SC_NPROCESSORS_ONLN */ 692 #endif /* __hpux */ 693 694 if (temp_cpus > MAXCPUS) { 695 fprintf(where, 696 "Sorry, this system has more CPUs (%d) than I can handle (%d).\n", 697 temp_cpus, 698 MAXCPUS); 699 fprintf(where, 700 "Please alter MAXCPUS in netlib.h and recompile.\n"); 701 fflush(where); 702 exit(1); 703 } 704 705 return(temp_cpus); 706 707 } 708 709 #ifdef WIN32 710 #ifdef __GNUC__ 711 #define S64_SUFFIX(x) x##LL 712 #else 713 #define S64_SUFFIX(x) x##i64 714 #endif 715 716 /* 717 * Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 718 */ 719 #define EPOCH_BIAS S64_SUFFIX(116444736000000000) 720 721 /* 722 * Union to facilitate converting from FILETIME to unsigned __int64 723 */ 724 typedef union { 725 unsigned __int64 ft_scalar; 726 FILETIME ft_struct; 727 } FT; 728 729 void 730 gettimeofday( struct timeval *tv , struct timezone *not_used ) 731 { 732 FT nt_time; 733 __int64 UnixTime; /* microseconds since 1/1/1970 */ 734 735 GetSystemTimeAsFileTime( &(nt_time.ft_struct) ); 736 737 UnixTime = ((nt_time.ft_scalar - EPOCH_BIAS) / S64_SUFFIX(10)); 738 tv->tv_sec = (long)(time_t)(UnixTime / S64_SUFFIX(1000000)); 739 tv->tv_usec = (unsigned long)(UnixTime % S64_SUFFIX(1000000)); 740 } 741 #endif /* WIN32 */ 742 743 744 746 /************************************************************************/ 747 /* */ 748 /* signal catcher */ 749 /* */ 750 /************************************************************************/ 751 752 void 753 #if defined(__hpux) 754 catcher(sig, code, scp) 755 int sig; 756 int code; 757 struct sigcontext *scp; 758 #else 759 catcher(int sig) 760 #endif /* __hpux || __VMS */ 761 { 762 763 #ifdef __hpux 764 if (debug > 2) { 765 fprintf(where,"caught signal %d ",sig); 766 if (scp) { 767 fprintf(where,"while in syscall %d\n", 768 scp->sc_syscall); 769 } 770 else { 771 fprintf(where,"null scp\n"); 772 } 773 fflush(where); 774 } 775 #endif /* RAJ_DEBUG */ 776 777 switch(sig) { 778 779 case SIGINT: 780 fprintf(where,"netperf: caught SIGINT\n"); 781 fflush(where); 782 exit(1); 783 break; 784 case SIGALRM: 785 if (--test_len_ticks == 0) { 786 /* the test is over */ 787 if (times_up != 0) { 788 fprintf(where,"catcher: timer popped with times_up != 0\n"); 789 fflush(where); 790 } 791 times_up = 1; 792 #if defined(WANT_INTERVALS) && !defined(WANT_SPIN) 793 stop_itimer(); 794 #endif /* WANT_INTERVALS */ 795 break; 796 } 797 else { 798 #ifdef WANT_INTERVALS 799 #ifdef __hpux 800 /* the test is not over yet and we must have been using the */ 801 /* interval timer. if we were in SYS_SIGSUSPEND we want to */ 802 /* re-start the system call. Otherwise, we want to get out of */ 803 /* the sigsuspend call. I NEED TO KNOW HOW TO DO THIS FOR OTHER */ 804 /* OPERATING SYSTEMS. If you know how, please let me know. rick */ 805 /* jones <raj (at) cup.hp.com> */ 806 if (scp->sc_syscall != SYS_SIGSUSPEND) { 807 if (debug > 2) { 808 fprintf(where, 809 "catcher: Time to send burst > interval!\n"); 810 fflush(where); 811 } 812 scp->sc_syscall_action = SIG_RESTART; 813 } 814 #endif /* __hpux */ 815 #else /* WANT_INTERVALS */ 816 fprintf(where, 817 "catcher: interval timer running unexpectedly!\n"); 818 fflush(where); 819 times_up = 1; 820 #endif /* WANT_INTERVALS */ 821 break; 822 } 823 } 824 return; 825 } 826 827 828 void 829 install_signal_catchers() 830 831 { 832 /* just a simple little routine to catch a bunch of signals */ 833 834 #ifndef WIN32 835 struct sigaction action; 836 int i; 837 838 fprintf(where,"installing catcher for all signals\n"); 839 fflush(where); 840 841 sigemptyset(&(action.sa_mask)); 842 action.sa_handler = catcher; 843 844 #ifdef SA_INTERRUPT 845 action.sa_flags = SA_INTERRUPT; 846 #else /* SA_INTERRUPT */ 847 action.sa_flags = 0; 848 #endif /* SA_INTERRUPT */ 849 850 851 for (i = 1; i <= NSIG; i++) { 852 if (i != SIGALRM) { 853 if (sigaction(i,&action,NULL) != 0) { 854 fprintf(where, 855 "Could not install signal catcher for sig %d, errno %d\n", 856 i, 857 errno); 858 fflush(where); 859 860 } 861 } 862 } 863 #else 864 return; 865 #endif /* WIN32 */ 866 } 867 868 870 #ifdef WIN32 871 #define SIGALRM (14) 872 void 873 emulate_alarm( int seconds ) 874 { 875 DWORD ErrorCode; 876 877 /* Wait on this event for parm seconds. */ 878 879 ErrorCode = WaitForSingleObject(hAlarm, seconds*1000); 880 if (ErrorCode == WAIT_FAILED) 881 { 882 perror("WaitForSingleObject failed"); 883 exit(1); 884 } 885 886 if (ErrorCode == WAIT_TIMEOUT) 887 { 888 /* WaitForSingleObject timed out; this means the timer 889 wasn't canceled. */ 890 891 times_up = 1; 892 893 /* We have yet to find a good way to fully emulate the effects */ 894 /* of signals and getting EINTR from system calls under */ 895 /* winsock, so what we do here is close the socket out from */ 896 /* under the other thread. It is rather kludgy, but should be */ 897 /* sufficient to get this puppy shipped. The concept can be */ 898 /* attributed/blamed :) on Robin raj 1/96 */ 899 900 if (win_kludge_socket != INVALID_SOCKET) { 901 closesocket(win_kludge_socket); 902 } 903 if (win_kludge_socket2 != INVALID_SOCKET) { 904 closesocket(win_kludge_socket2); 905 } 906 } 907 } 908 909 #endif /* WIN32 */ 910 911 void 912 start_timer(int time) 913 { 914 915 #ifdef WIN32 916 /*+*+SAF What if StartTimer is called twice without the first timer */ 917 /*+*+SAF expiring? */ 918 919 DWORD thread_id ; 920 HANDLE tHandle; 921 922 if (hAlarm == (HANDLE) INVALID_HANDLE_VALUE) 923 { 924 /* Create the Alarm event object */ 925 hAlarm = CreateEvent( 926 (LPSECURITY_ATTRIBUTES) NULL, /* no security */ 927 FALSE, /* auto reset event */ 928 FALSE, /* init. state = reset */ 929 (void *)NULL); /* unnamed event object */ 930 if (hAlarm == (HANDLE) INVALID_HANDLE_VALUE) 931 { 932 perror("CreateEvent failure"); 933 exit(1); 934 } 935 } 936 else 937 { 938 ResetEvent(hAlarm); 939 } 940 941 942 tHandle = CreateThread(0, 943 0, 944 (LPTHREAD_START_ROUTINE)emulate_alarm, 945 (LPVOID)(ULONG_PTR)time, 946 0, 947 &thread_id ) ; 948 CloseHandle(tHandle); 949 950 #else /* not WIN32 */ 951 952 struct sigaction action; 953 954 if (debug) { 955 fprintf(where,"About to start a timer for %d seconds.\n",time); 956 fflush(where); 957 } 958 959 action.sa_handler = catcher; 960 sigemptyset(&(action.sa_mask)); 961 sigaddset(&(action.sa_mask),SIGALRM); 962 963 #ifdef SA_INTERRUPT 964 /* on some systems (SunOS 4.blah), system calls are restarted. we do */ 965 /* not want that */ 966 action.sa_flags = SA_INTERRUPT; 967 #else /* SA_INTERRUPT */ 968 action.sa_flags = 0; 969 #endif /* SA_INTERRUPT */ 970 971 if (sigaction(SIGALRM, &action, NULL) < 0) { 972 fprintf(where,"start_timer: error installing alarm handler "); 973 fprintf(where,"errno %d\n",errno); 974 fflush(where); 975 exit(1); 976 } 977 978 /* this is the easy case - just set the timer for so many seconds */ 979 if (alarm(time) != 0) { 980 fprintf(where, 981 "error starting alarm timer, errno %d\n", 982 errno); 983 fflush(where); 984 } 985 #endif /* WIN32 */ 986 987 test_len_ticks = 1; 988 989 } 990 991 992 /* this routine will disable any running timer */ 994 void 995 stop_timer() 996 { 997 #ifndef WIN32 998 alarm(0); 999 #else 1000 /* at some point we may need some win32 equivalent */ 1001 if (hAlarm != (HANDLE) INVALID_HANDLE_VALUE) 1002 { 1003 SetEvent(hAlarm); 1004 } 1005 #endif /* WIN32 */ 1006 1007 } 1008 1009 1010 #ifdef WANT_INTERVALS 1012 /* this routine will enable the interval timer and set things up so */ 1013 /* that for a timed test the test will end at the proper time. it */ 1014 /* should detect the presence of POSIX.4 timer_* routines one of */ 1015 /* these days */ 1016 void 1017 start_itimer(unsigned int interval_len_msec ) 1018 { 1019 1020 unsigned int ticks_per_itvl; 1021 1022 struct itimerval new_interval; 1023 struct itimerval old_interval; 1024 1025 /* if -DWANT_INTERVALS was used, we will use the ticking of the itimer to */ 1026 /* tell us when the test is over. while the user will be specifying */ 1027 /* some number of milliseconds, we know that the interval timer is */ 1028 /* really in units of 1/HZ. so, to prevent the test from running */ 1029 /* "long" it would be necessary to keep this in mind when calculating */ 1030 /* the number of itimer events */ 1031 1032 ticks_per_itvl = ((interval_wate * sysconf(_SC_CLK_TCK) * 1000) / 1033 1000000); 1034 1035 if (ticks_per_itvl == 0) ticks_per_itvl = 1; 1036 1037 /* how many usecs in each interval? */ 1038 usec_per_itvl = ticks_per_itvl * (1000000 / sysconf(_SC_CLK_TCK)); 1039 1040 /* how many times will the timer pop before the test is over? */ 1041 if (test_time > 0) { 1042 /* this was a timed test */ 1043 test_len_ticks = (test_time * 1000000) / usec_per_itvl; 1044 } 1045 else { 1046 /* this was not a timed test, use MAXINT */ 1047 test_len_ticks = INT_MAX; 1048 } 1049 1050 if (debug) { 1051 fprintf(where,"setting the interval timer to %d sec %d usec ", 1052 usec_per_itvl / 1000000, 1053 usec_per_itvl % 1000000); 1054 fprintf(where,"test len %d ticks\n", 1055 test_len_ticks); 1056 fflush(where); 1057 } 1058 1059 /* if this was not a timed test, then we really aught to enable the */ 1060 /* signal catcher raj 2/95 */ 1061 1062 new_interval.it_interval.tv_sec = usec_per_itvl / 1000000; 1063 new_interval.it_interval.tv_usec = usec_per_itvl % 1000000; 1064 new_interval.it_value.tv_sec = usec_per_itvl / 1000000; 1065 new_interval.it_value.tv_usec = usec_per_itvl % 1000000; 1066 if (setitimer(ITIMER_REAL,&new_interval,&old_interval) != 0) { 1067 /* there was a problem arming the interval timer */ 1068 perror("netperf: setitimer"); 1069 exit(1); 1070 } 1071 } 1072 #endif /* WANT_INTERVALS */ 1073 1074 void 1075 netlib_init_cpu_map() { 1076 1077 int i; 1078 #ifdef HAVE_MPCTL 1079 int num; 1080 i = 0; 1081 /* I go back and forth on whether this should be the system-wide set 1082 of calls, or if the processor set versions (sans the _SYS) should 1083 be used. at the moment I believe that the system-wide version 1084 should be used. raj 2006-04-03 */ 1085 num = mpctl(MPC_GETNUMSPUS_SYS,0,0); 1086 lib_cpu_map[i] = mpctl(MPC_GETFIRSTSPU_SYS,0,0); 1087 for (i = 1;((i < num) && (i < MAXCPUS)); i++) { 1088 lib_cpu_map[i] = mpctl(MPC_GETNEXTSPU_SYS,lib_cpu_map[i-1],0); 1089 } 1090 /* from here, we set them all to -1 because if we launch more 1091 loopers than actual CPUs, well, I'm not sure why :) */ 1092 for (; i < MAXCPUS; i++) { 1093 lib_cpu_map[i] = -1; 1094 } 1095 1096 #else 1097 /* we assume that there is indeed a contiguous mapping */ 1098 for (i = 0; i < MAXCPUS; i++) { 1099 lib_cpu_map[i] = i; 1100 } 1101 #endif 1102 } 1103 1104 1105 /****************************************************************/ 1107 /* */ 1108 /* netlib_init() */ 1109 /* */ 1110 /* initialize the performance library... */ 1111 /* */ 1112 /****************************************************************/ 1113 1114 void 1115 netlib_init() 1116 { 1117 int i; 1118 1119 where = stdout; 1120 1121 request_array = (int *)(&netperf_request); 1122 response_array = (int *)(&netperf_response); 1123 1124 for (i = 0; i < MAXCPUS; i++) { 1125 lib_local_per_cpu_util[i] = 0.0; 1126 } 1127 1128 /* on those systems where we know that CPU numbers may not start at 1129 zero and be contiguous, we provide a way to map from a 1130 contiguous, starting from 0 CPU id space to the actual CPU ids. 1131 at present this is only used for the netcpu_looper stuff because 1132 we ass-u-me that someone setting processor affinity from the 1133 netperf commandline will provide a "proper" CPU identifier. raj 1134 2006-04-03 */ 1135 1136 netlib_init_cpu_map(); 1137 1138 if (debug) { 1139 fprintf(where, 1140 "netlib_init: request_array at %p\n", 1141 request_array); 1142 fprintf(where, 1143 "netlib_init: response_array at %p\n", 1144 response_array); 1145 1146 fflush(where); 1147 } 1148 1149 } 1150 1151 /* this routine will conver the string into an unsigned integer. it */ 1153 /* is used primarily for the command-line options taking a number */ 1154 /* (such as the socket size) which could be rather large. If someone */ 1155 /* enters 32M, then the number will be converted to 32 * 1024 * 1024. */ 1156 /* If they inter 32m, the number will be converted to 32 * 1000 * */ 1157 /* 1000 */ 1158 unsigned int 1159 convert(char *string) 1160 1161 { 1162 unsigned int base; 1163 base = atoi(string); 1164 if (strstr(string,"K")) { 1165 base *= 1024; 1166 } 1167 if (strstr(string,"M")) { 1168 base *= (1024 * 1024); 1169 } 1170 if (strstr(string,"G")) { 1171 base *= (1024 * 1024 * 1024); 1172 } 1173 if (strstr(string,"k")) { 1174 base *= (1000); 1175 } 1176 if (strstr(string,"m")) { 1177 base *= (1000 * 1000); 1178 } 1179 if (strstr(string,"g")) { 1180 base *= (1000 * 1000 * 1000); 1181 } 1182 return(base); 1183 } 1184 1185 /* this routine is like convert, but it is used for an interval time 1186 specification instead of stuff like socket buffer or send sizes. 1187 it converts everything to microseconds for internal use. if there 1188 is an 'm' at the end it assumes the user provided milliseconds, s 1189 will imply seconds, u will imply microseconds. in the future n 1190 will imply nanoseconds but for now it will be ignored. if there is 1191 no suffix or an unrecognized suffix, it will be assumed the user 1192 provided milliseconds, which was the long-time netperf default. one 1193 of these days, we should probably revisit that nanosecond business 1194 wrt the return value being just an int rather than a uint64_t or 1195 something. raj 2006-02-06 */ 1196 1197 unsigned int 1198 convert_timespec(char *string) { 1199 1200 unsigned int base; 1201 base = atoi(string); 1202 if (strstr(string,"m")) { 1203 base *= 1000; 1204 } 1205 else if (strstr(string,"u")) { 1206 base *= (1); 1207 } 1208 else if (strstr(string,"s")) { 1209 base *= (1000 * 1000); 1210 } 1211 else { 1212 base *= (1000); 1213 } 1214 return(base); 1215 } 1216 1217 1218 /* this routine will allocate a circular list of buffers for either */ 1220 /* send or receive operations. each of these buffers will be aligned */ 1221 /* and offset as per the users request. the circumference of this */ 1222 /* ring will be controlled by the setting of send_width. the buffers */ 1223 /* will be filled with data from the file specified in fill_file. if */ 1224 /* fill_file is an empty string, the buffers will not be filled with */ 1225 /* any particular data */ 1226 1227 struct ring_elt * 1228 allocate_buffer_ring(int width, int buffer_size, int alignment, int offset) 1229 { 1230 1231 struct ring_elt *first_link = NULL; 1232 struct ring_elt *temp_link = NULL; 1233 struct ring_elt *prev_link; 1234 1235 int i; 1236 int malloc_size; 1237 int bytes_left; 1238 int bytes_read; 1239 int do_fill; 1240 1241 FILE *fill_source; 1242 char default_fill[] = "netperf"; 1243 int fill_cursor = 0; 1244 1245 malloc_size = buffer_size + alignment + offset; 1246 1247 /* did the user wish to have the buffers pre-filled with data from a */ 1248 /* particular source? */ 1249 if (strcmp(fill_file,"") == 0) { 1250 do_fill = 0; 1251 fill_source = NULL; 1252 } 1253 else { 1254 do_fill = 1; 1255 fill_source = (FILE *)fopen(fill_file,"r"); 1256 if (fill_source == (FILE *)NULL) { 1257 perror("Could not open requested fill file"); 1258 exit(1); 1259 } 1260 } 1261 1262 assert(width >= 1); 1263 1264 prev_link = NULL; 1265 for (i = 1; i <= width; i++) { 1266 /* get the ring element */ 1267 temp_link = (struct ring_elt *)malloc(sizeof(struct ring_elt)); 1268 if (temp_link == NULL) { 1269 printf("malloc(%u) failed!\n", sizeof(struct ring_elt)); 1270 exit(1); 1271 } 1272 /* remember the first one so we can close the ring at the end */ 1273 if (i == 1) { 1274 first_link = temp_link; 1275 } 1276 temp_link->buffer_base = (char *)malloc(malloc_size); 1277 if (temp_link == NULL) { 1278 printf("malloc(%d) failed!\n", malloc_size); 1279 exit(1); 1280 } 1281 1282 #ifndef WIN32 1283 temp_link->buffer_ptr = (char *)(( (long)(temp_link->buffer_base) + 1284 (long)alignment - 1) & 1285 ~((long)alignment - 1)); 1286 #else 1287 temp_link->buffer_ptr = (char *)(( (ULONG_PTR)(temp_link->buffer_base) + 1288 (ULONG_PTR)alignment - 1) & 1289 ~((ULONG_PTR)alignment - 1)); 1290 #endif 1291 temp_link->buffer_ptr += offset; 1292 /* is where the buffer fill code goes. */ 1293 if (do_fill) { 1294 char *bufptr = temp_link->buffer_ptr; 1295 bytes_left = buffer_size; 1296 while (bytes_left) { 1297 if (((bytes_read = (int)fread(bufptr, 1298 1, 1299 bytes_left, 1300 fill_source)) == 0) && 1301 (feof(fill_source))){ 1302 rewind(fill_source); 1303 } 1304 bufptr += bytes_read; 1305 bytes_left -= bytes_read; 1306 } 1307 } 1308 else { 1309 /* use the default fill to ID our data traffic on the 1310 network. it ain't exactly pretty, but it should work */ 1311 int j; 1312 char *bufptr = temp_link->buffer_ptr; 1313 for (j = 0; j < buffer_size; j++) { 1314 bufptr[j] = default_fill[fill_cursor]; 1315 fill_cursor += 1; 1316 /* the Windows DDK compiler with an x86_64 target wants a cast 1317 here */ 1318 if (fill_cursor > (int)strlen(default_fill)) { 1319 fill_cursor = 0; 1320 } 1321 } 1322 1323 } 1324 temp_link->next = prev_link; 1325 prev_link = temp_link; 1326 } 1327 if (first_link) { /* SAF Prefast made me do it... */ 1328 first_link->next = temp_link; 1329 } 1330 1331 return(first_link); /* it's a circle, doesn't matter which we return */ 1332 } 1333 1334 /* this routine will dirty the first dirty_count bytes of the 1335 specified buffer and/or read clean_count bytes from the buffer. it 1336 will go N bytes at a time, the only question is how large should N 1337 be and if we should be going continguously, or based on some 1338 assumption of cache line size */ 1339 1340 void 1341 access_buffer(char *buffer_ptr,int length, int dirty_count, int clean_count) { 1342 1343 char *temp_buffer; 1344 char *limit; 1345 int i, dirty_totals; 1346 1347 temp_buffer = buffer_ptr; 1348 limit = temp_buffer + length; 1349 dirty_totals = 0; 1350 1351 for (i = 0; 1352 ((i < dirty_count) && (temp_buffer < limit)); 1353 i++) { 1354 *temp_buffer += (char)i; 1355 dirty_totals += *temp_buffer; 1356 temp_buffer++; 1357 } 1358 1359 for (i = 0; 1360 ((i < clean_count) && (temp_buffer < limit)); 1361 i++) { 1362 dirty_totals += *temp_buffer; 1363 temp_buffer++; 1364 } 1365 1366 if (debug > 100) { 1367 fprintf(where, 1368 "This was here to try to avoid dead-code elimination %d\n", 1369 dirty_totals); 1370 fflush(where); 1371 } 1372 } 1373 1374 1376 #ifdef HAVE_ICSC_EXS 1377 1378 #include <sys/mman.h> 1379 #include <sys/exs.h> 1380 1381 /* this routine will allocate a circular list of buffers for either */ 1382 /* send or receive operations. each of these buffers will be aligned */ 1383 /* and offset as per the users request. the circumference of this */ 1384 /* ring will be controlled by the setting of send_width. the buffers */ 1385 /* will be filled with data from the file specified in fill_file. if */ 1386 /* fill_file is an empty string, the buffers will not be filled with */ 1387 /* any particular data */ 1388 1389 struct ring_elt * 1390 allocate_exs_buffer_ring (int width, int buffer_size, int alignment, int offset, exs_mhandle_t *mhandlep) 1391 { 1392 1393 struct ring_elt *first_link; 1394 struct ring_elt *temp_link; 1395 struct ring_elt *prev_link; 1396 1397 int i; 1398 int malloc_size; 1399 int bytes_left; 1400 int bytes_read; 1401 int do_fill; 1402 1403 FILE *fill_source; 1404 1405 int mmap_size; 1406 char *mmap_buffer, *mmap_buffer_aligned; 1407 1408 malloc_size = buffer_size + alignment + offset; 1409 1410 /* did the user wish to have the buffers pre-filled with data from a */ 1411 /* particular source? */ 1412 if (strcmp (fill_file, "") == 0) { 1413 do_fill = 0; 1414 fill_source = NULL; 1415 } else { 1416 do_fill = 1; 1417 fill_source = (FILE *) fopen (fill_file, "r"); 1418 if (fill_source == (FILE *) NULL) { 1419 perror ("Could not open requested fill file"); 1420 exit (1); 1421 } 1422 } 1423 1424 assert (width >= 1); 1425 1426 if (debug) { 1427 fprintf (where, "allocate_exs_buffer_ring: " 1428 "width=%d buffer_size=%d alignment=%d offset=%d\n", 1429 width, buffer_size, alignment, offset); 1430 } 1431 1432 /* allocate shared memory */ 1433 mmap_size = width * malloc_size; 1434 mmap_buffer = (char *) mmap ((caddr_t)NULL, mmap_size+NBPG-1, 1435 PROT_READ|PROT_WRITE, 1436 MAP_SHARED|MAP_ANONYMOUS, -1, 0); 1437 if (mmap_buffer == NULL) { 1438 perror ("allocate_exs_buffer_ring: mmap failed"); 1439 exit (1); 1440 } 1441 mmap_buffer_aligned = (char *) ((uintptr_t)mmap_buffer & ~(NBPG-1)); 1442 if (debug) { 1443 fprintf (where, "allocate_exs_buffer_ring: " 1444 "mmap buffer size=%d address=0x%p aligned=0x%p\n", 1445 mmap_size, mmap_buffer, mmap_buffer_aligned); 1446 } 1447 1448 /* register shared memory */ 1449 *mhandlep = exs_mregister ((void *)mmap_buffer_aligned, (size_t)mmap_size, 0); 1450 if (*mhandlep == EXS_MHANDLE_INVALID) { 1451 perror ("allocate_exs_buffer_ring: exs_mregister failed"); 1452 exit (1); 1453 } 1454 if (debug) { 1455 fprintf (where, "allocate_exs_buffer_ring: mhandle=%d\n", 1456 *mhandlep); 1457 } 1458 1459 /* allocate ring elements */ 1460 first_link = (struct ring_elt *) malloc (width * sizeof (struct ring_elt)); 1461 if (first_link == NULL) { 1462 printf ("malloc(%d) failed!\n", width * sizeof (struct ring_elt)); 1463 exit (1); 1464 } 1465 1466 /* initialize buffer ring */ 1467 prev_link = first_link + width - 1; 1468 1469 for (i = 0, temp_link = first_link; i < width; i++, temp_link++) { 1470 1471 temp_link->buffer_base = (char *) mmap_buffer_aligned + (i*malloc_size); 1472 #ifndef WIN32 1473 temp_link->buffer_ptr = (char *) 1474 (((long)temp_link->buffer_base + (long)alignment - 1) & 1475 ~((long)alignment - 1)); 1476 #else 1477 temp_link->buffer_ptr = (char *) 1478 (((ULONG_PTR)temp_link->buffer_base + (ULONG_PTR)alignment - 1) & 1479 ~((ULONG_PTR)alignment - 1)); 1480 #endif 1481 temp_link->buffer_ptr += offset; 1482 1483 if (debug) { 1484 fprintf (where, "allocate_exs_buffer_ring: " 1485 "buffer: index=%d base=0x%p ptr=0x%p\n", 1486 i, temp_link->buffer_base, temp_link->buffer_ptr); 1487 } 1488 1489 /* is where the buffer fill code goes. */ 1490 if (do_fill) { 1491 bytes_left = buffer_size; 1492 while (bytes_left) { 1493 if (((bytes_read = (int) fread (temp_link->buffer_ptr, 1494 1, 1495 bytes_left, 1496 fill_source)) == 0) && 1497 (feof (fill_source))) { 1498 rewind (fill_source); 1499 } 1500 bytes_left -= bytes_read; 1501 } 1502 } 1503 1504 /* do linking */ 1505 prev_link->next = temp_link; 1506 prev_link = temp_link; 1507 } 1508 1509 return (first_link); /* it's a circle, doesn't matter which we return */ 1510 } 1511 1512 #endif /* HAVE_ICSC_EXS */ 1513 1514 1515 1517 #ifdef HAVE_SENDFILE 1518 /* this routine will construct a ring of sendfile_ring_elt structs 1519 that the routine sendfile_tcp_stream() will use to get parameters 1520 to its calls to sendfile(). It will setup the ring to point at the 1521 file specified in the global -F option that is already used to 1522 pre-fill buffers in the send() case. 08/2000 1523 1524 if there is no file specified in a global -F option, we will create 1525 a tempoarary file and fill it with random data and use that 1526 instead. raj 2007-08-09 */ 1527 1528 struct sendfile_ring_elt * 1529 alloc_sendfile_buf_ring(int width, 1530 int buffer_size, 1531 int alignment, 1532 int offset) 1533 1534 { 1535 1536 struct sendfile_ring_elt *first_link = NULL; 1537 struct sendfile_ring_elt *temp_link = NULL; 1538 struct sendfile_ring_elt *prev_link; 1539 1540 int i; 1541 int fildes; 1542 struct stat statbuf; 1543 1544 /* if the user has not specified a file with the -F option, we will 1545 fail the test. otherwise, go ahead and try to open the 1546 file. 08/2000 */ 1547 if (strcmp(fill_file,"") == 0) { 1548 /* use an temp file for the fill file */ 1549 char *temp_file; 1550 int *temp_buffer; 1551 1552 /* make sure we have at least an ints worth, even if the user is 1553 using an insane buffer size for a sendfile test. we are 1554 ass-u-me-ing that malloc will return something at least aligned 1555 on an int boundary... */ 1556 temp_buffer = (int *) malloc(buffer_size + sizeof(int)); 1557 if (temp_buffer) { 1558 /* ok, we have the buffer we are going to write, lets get a 1559 temporary filename */ 1560 temp_file = tmpnam(NULL); 1561 if (NULL != temp_file) { 1562 fildes = open(temp_file,O_RDWR | O_EXCL | O_CREAT,0600); 1563 if (-1 != fildes) { 1564 int count; 1565 int *int_ptr; 1566 1567 /* initialize the random number generator */ 1568 srand(getpid()); 1569 1570 /* unlink the file so it goes poof when we 1571 exit. unless/until shown to be a problem we will 1572 blissfully ignore the return value. raj 2007-08-09 */ 1573 unlink(temp_file); 1574 1575 /* now fill-out the file with at least buffer_size * width bytes */ 1576 for (count = 0; count < width; count++) { 1577 /* fill the buffer with random data. it doesn't have to be 1578 really random, just "random enough" :) we do this here rather 1579 than up above because we want each write to the file to be 1580 different random data */ 1581 int_ptr = temp_buffer; 1582 for (i = 0; i <= buffer_size/sizeof(int); i++) { 1583 *int_ptr = rand(); 1584 int_ptr++; 1585 } 1586 if (write(fildes,temp_buffer,buffer_size+sizeof(int)) != 1587 buffer_size + sizeof(int)) { 1588 perror("allocate_sendfile_buf_ring: incomplete write"); 1589 exit(-1); 1590 } 1591 } 1592 } 1593 else { 1594 perror("allocate_sendfile_buf_ring: could not open tempfile"); 1595 exit(-1); 1596 } 1597 } 1598 else { 1599 perror("allocate_sendfile_buf_ring: could not allocate temp name"); 1600 exit(-1); 1601 } 1602 } 1603 else { 1604 perror("alloc_sendfile_buf_ring: could not allocate buffer for file"); 1605 exit(-1); 1606 } 1607 } 1608 else { 1609 /* the user pointed us at a file, so try it */ 1610 fildes = open(fill_file , O_RDONLY); 1611 if (fildes == -1){ 1612 perror("alloc_sendfile_buf_ring: Could not open requested file"); 1613 exit(1); 1614 } 1615 /* make sure there is enough file there to allow us to make a 1616 complete ring. that way we do not need additional logic in the 1617 ring setup to deal with wrap-around issues. we might want that 1618 someday, but not just now. 08/2000 */ 1619 if (stat(fill_file,&statbuf) != 0) { 1620 perror("alloc_sendfile_buf_ring: could not stat file"); 1621 exit(1); 1622 } 1623 if (statbuf.st_size < (width * buffer_size)) { 1624 /* the file is too short */ 1625 fprintf(stderr,"alloc_sendfile_buf_ring: specified file too small.\n"); 1626 fprintf(stderr,"file must be larger than send_width * send_size\n"); 1627 fflush(stderr); 1628 exit(1); 1629 } 1630 } 1631 1632 /* so, at this point we know that fildes is a descriptor which 1633 references a file of sufficient size for our nefarious 1634 porpoises. raj 2007-08-09 */ 1635 1636 prev_link = NULL; 1637 for (i = 1; i <= width; i++) { 1638 /* get the ring element. we should probably make sure the malloc() 1639 was successful, but for now we'll just let the code bomb 1640 mysteriously. 08/2000 */ 1641 1642 temp_link = (struct sendfile_ring_elt *) 1643 malloc(sizeof(struct sendfile_ring_elt)); 1644 if (temp_link == NULL) { 1645 printf("malloc(%u) failed!\n", sizeof(struct sendfile_ring_elt)); 1646 exit(1); 1647 } 1648 1649 /* remember the first one so we can close the ring at the end */ 1650 1651 if (i == 1) { 1652 first_link = temp_link; 1653 } 1654 1655 /* now fill-in the fields of the structure with the apropriate 1656 stuff. just how should we deal with alignment and offset I 1657 wonder? until something better comes-up, I think we will just 1658 ignore them. 08/2000 */ 1659 1660 temp_link->fildes = fildes; /* from which file do we send? */ 1661 temp_link->offset = offset; /* starting at which offset? */ 1662 offset += buffer_size; /* get ready for the next elt */ 1663 temp_link->length = buffer_size; /* how many bytes to send */ 1664 temp_link->hdtrl = NULL; /* no header or trailer */ 1665 temp_link->flags = 0; /* no flags */ 1666 1667 /* is where the buffer fill code went. */ 1668 1669 temp_link->next = prev_link; 1670 prev_link = temp_link; 1671 } 1672 /* close the ring */ 1673 first_link->next = temp_link; 1674 1675 return(first_link); /* it's a dummy ring */ 1676 } 1677 1678 #endif /* HAVE_SENDFILE */ 1679 1680 1681 /***********************************************************************/ 1683 /* */ 1684 /* dump_request() */ 1685 /* */ 1686 /* display the contents of the request array to the user. it will */ 1687 /* display the contents in decimal, hex, and ascii, with four bytes */ 1688 /* per line. */ 1689 /* */ 1690 /***********************************************************************/ 1691 1692 void 1693 dump_request() 1694 { 1695 int counter = 0; 1696 fprintf(where,"request contents:\n"); 1697 for (counter = 0; counter < ((sizeof(netperf_request)/4)-3); counter += 4) { 1698 fprintf(where,"%d:\t%8x %8x %8x %8x \t|%4.4s| |%4.4s| |%4.4s| |%4.4s|\n", 1699 counter, 1700 request_array[counter], 1701 request_array[counter+1], 1702 request_array[counter+2], 1703 request_array[counter+3], 1704 (char *)&request_array[counter], 1705 (char *)&request_array[counter+1], 1706 (char *)&request_array[counter+2], 1707 (char *)&request_array[counter+3]); 1708 } 1709 fflush(where); 1710 } 1711 1712 1713 /***********************************************************************/ 1714 /* */ 1715 /* dump_response() */ 1716 /* */ 1717 /* display the content of the response array to the user. it will */ 1718 /* display the contents in decimal, hex, and ascii, with four bytes */ 1719 /* per line. */ 1720 /* */ 1721 /***********************************************************************/ 1722 1723 void 1724 dump_response() 1725 { 1726 int counter = 0; 1727 1728 fprintf(where,"response contents\n"); 1729 for (counter = 0; counter < ((sizeof(netperf_response)/4)-3); counter += 4) { 1730 fprintf(where,"%d:\t%8x %8x %8x %8x \t>%4.4s< >%4.4s< >%4.4s< >%4.4s<\n", 1731 counter, 1732 response_array[counter], 1733 response_array[counter+1], 1734 response_array[counter+2], 1735 response_array[counter+3], 1736 (char *)&response_array[counter], 1737 (char *)&response_array[counter+1], 1738 (char *)&response_array[counter+2], 1739 (char *)&response_array[counter+3]); 1740 } 1741 fflush(where); 1742 } 1743 1744 /* 1745 1746 format_number() 1747 1748 return a pointer to a formatted string containing the value passed 1749 translated into the units specified. It assumes that the base units 1750 are bytes. If the format calls for bits, it will use SI units (10^) 1751 if the format calls for bytes, it will use CS units (2^)... This 1752 routine should look familiar to uses of the latest ttcp... 1753 1754 we would like to use "t" or "T" for transactions, but probably 1755 should leave those for terabits and terabytes respectively, so for 1756 transactions, we will use "x" which will, by default, do absolutely 1757 nothing to the result. why? so we don't have to special case code 1758 elsewhere such as in the TCP_RR-as-bidirectional test case. 1759 1760 */ 1761 1762 1763 char * 1764 format_number(double number) 1765 { 1766 static char fmtbuf[64]; 1767 1768 switch (libfmt) { 1769 case 'K': 1770 snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f" , number / 1024.0); 1771 break; 1772 case 'M': 1773 snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number / 1024.0 / 1024.0); 1774 break; 1775 case 'G': 1776 snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number / 1024.0 / 1024.0 / 1024.0); 1777 break; 1778 case 'k': 1779 snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number * 8 / 1000.0); 1780 break; 1781 case 'm': 1782 snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number * 8 / 1000.0 / 1000.0); 1783 break; 1784 case 'g': 1785 snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number * 8 / 1000.0 / 1000.0 / 1000.0); 1786 break; 1787 case 'x': 1788 snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number); 1789 break; 1790 default: 1791 snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number / 1024.0); 1792 } 1793 1794 return fmtbuf; 1795 } 1796 1797 char 1798 format_cpu_method(int method) 1799 { 1800 1801 char method_char; 1802 1803 switch (method) { 1804 case CPU_UNKNOWN: 1805 method_char = 'U'; 1806 break; 1807 case HP_IDLE_COUNTER: 1808 method_char = 'I'; 1809 break; 1810 case PSTAT: 1811 method_char = 'P'; 1812 break; 1813 case KSTAT: 1814 method_char = 'K'; 1815 break; 1816 case KSTAT_10: 1817 method_char = 'M'; 1818 break; 1819 case PERFSTAT: 1820 method_char = 'E'; 1821 break; 1822 case TIMES: /* historical only, completely unsuitable 1823 for netperf's purposes */ 1824 method_char = 'T'; 1825 break; 1826 case GETRUSAGE: /* historical only, completely unsuitable 1827 for netperf;s purposes */ 1828 method_char = 'R'; 1829 break; 1830 case LOOPER: 1831 method_char = 'L'; 1832 break; 1833 case NT_METHOD: 1834 method_char = 'N'; 1835 break; 1836 case PROC_STAT: 1837 method_char = 'S'; 1838 break; 1839 case SYSCTL: 1840 method_char = 'C'; 1841 break; 1842 case OSX: 1843 method_char = 'O'; 1844 break; 1845 default: 1846 method_char = '?'; 1847 } 1848 1849 return method_char; 1850 1851 } 1852 1853 char * 1854 format_units() 1855 { 1856 static char unitbuf[64]; 1857 1858 switch (libfmt) { 1859 case 'K': 1860 strcpy(unitbuf, "KBytes"); 1861 break; 1862 case 'M': 1863 strcpy(unitbuf, "MBytes"); 1864 break; 1865 case 'G': 1866 strcpy(unitbuf, "GBytes"); 1867 break; 1868 case 'k': 1869 strcpy(unitbuf, "10^3bits"); 1870 break; 1871 case 'm': 1872 strcpy(unitbuf, "10^6bits"); 1873 break; 1874 case 'g': 1875 strcpy(unitbuf, "10^9bits"); 1876 break; 1877 case 'x': 1878 strcpy(unitbuf, "Trans"); 1879 break; 1880 1881 default: 1882 strcpy(unitbuf, "KBytes"); 1883 } 1884 1885 return unitbuf; 1886 } 1887 1888 1890 /****************************************************************/ 1891 /* */ 1892 /* shutdown_control() */ 1893 /* */ 1894 /* tear-down the control connection between me and the server. */ 1895 /****************************************************************/ 1896 1897 void 1898 shutdown_control() 1899 { 1900 1901 char *buf = (char *)&netperf_response; 1902 int buflen = sizeof(netperf_response); 1903 1904 /* stuff for select, use fd_set for better compliance */ 1905 fd_set readfds; 1906 struct timeval timeout; 1907 1908 if (debug) { 1909 fprintf(where, 1910 "shutdown_control: shutdown of control connection requested.\n"); 1911 fflush(where); 1912 } 1913 1914 /* first, we say that we will be sending no more data on the */ 1915 /* connection */ 1916 if (shutdown(netlib_control,1) == SOCKET_ERROR) { 1917 Print_errno(where, 1918 "shutdown_control: error in shutdown"); 1919 fflush(where); 1920 exit(1); 1921 } 1922 1923 /* Now, we hang on a select waiting for the socket to become */ 1924 /* readable to receive the shutdown indication from the remote. this */ 1925 /* will be "just" like the recv_response() code */ 1926 1927 /* we only select once. it is assumed that if the response is split */ 1928 /* (which should not be happening, that we will receive the whole */ 1929 /* thing and not have a problem ;-) */ 1930 1931 FD_ZERO(&readfds); 1932 FD_SET(netlib_control,&readfds); 1933 timeout.tv_sec = 60; /* wait one minute then punt */ 1934 timeout.tv_usec = 0; 1935 1936 /* select had better return one, or there was either a problem or a */ 1937 /* timeout... */ 1938 if (select(FD_SETSIZE, 1939 &readfds, 1940 0, 1941 0, 1942 &timeout) != 1) { 1943 Print_errno(where, 1944 "shutdown_control: no response received"); 1945 fflush(where); 1946 exit(1); 1947 } 1948 1949 /* we now assume that the socket has come ready for reading */ 1950 recv(netlib_control, buf, buflen,0); 1951 1952 } 1953 1954 /* 1955 bind_to_specific_processor will bind the calling process to the 1956 processor in "processor" It has lots of ugly ifdefs to deal with 1957 all the different ways systems do processor affinity. this is a 1958 generalization of work initially done by stephen burger. raj 1959 2004/12/13 */ 1960 1961 void 1962 bind_to_specific_processor(int processor_affinity, int use_cpu_map) 1963 { 1964 1965 int mapped_affinity; 1966 1967 /* this is in place because the netcpu_looper processor affinity 1968 ass-u-me-s a contiguous CPU id space starting with 0. for the 1969 regular netperf/netserver affinity, we ass-u-me the user has used 1970 a suitable CPU id even when the space is not contiguous and 1971 starting from zero */ 1972 if (use_cpu_map) { 1973 mapped_affinity = lib_cpu_map[processor_affinity]; 1974 } 1975 else { 1976 mapped_affinity = processor_affinity; 1977 } 1978 1979 #ifdef HAVE_MPCTL 1980 /* indeed, at some point it would be a good idea to check the return 1981 status and pass-along notification of error... raj 2004/12/13 */ 1982 mpctl(MPC_SETPROCESS_FORCE, mapped_affinity, getpid()); 1983 #elif HAVE_PROCESSOR_BIND 1984 #include <sys/types.h> 1985 #include <sys/processor.h> 1986 #include <sys/procset.h> 1987 processor_bind(P_PID,P_MYID,mapped_affinity,NULL); 1988 #elif HAVE_BINDPROCESSOR 1989 #include <sys/processor.h> 1990 /* this is the call on AIX. It takes a "what" of BINDPROCESS or 1991 BINDTHRAD, then "who" and finally "where" which is a CPU number 1992 or it seems PROCESSOR_CLASS_ANY there also seems to be a mycpu() 1993 call to return the current CPU assignment. this is all based on 1994 the sys/processor.h include file. from empirical testing, it 1995 would seem that the my_cpu() call returns the current CPU on 1996 which we are running rather than the CPU binding, so it's return 1997 value will not tell you if you are bound vs unbound. */ 1998 bindprocessor(BINDPROCESS,getpid(),(cpu_t)mapped_affinity); 1999 #elif HAVE_SCHED_SETAFFINITY 2000 #include <sched.h> 2001 /* in theory this should cover systems with more CPUs than bits in a 2002 long, without having to specify __USE_GNU. we "cheat" by taking 2003 defines from /usr/include/bits/sched.h, which we ass-u-me is 2004 included by <sched.h>. If they are not there we will just 2005 fall-back on what we had before, which is to use just the size of 2006 an unsigned long. raj 2006-09-14 */ 2007 2008 #if defined(__CPU_SETSIZE) 2009 #define NETPERF_CPU_SETSIZE __CPU_SETSIZE 2010 #define NETPERF_CPU_SET(cpu, cpusetp) __CPU_SET(cpu, cpusetp) 2011 #define NETPERF_CPU_ZERO(cpusetp) __CPU_ZERO (cpusetp) 2012 typedef cpu_set_t netperf_cpu_set_t; 2013 #else 2014 #define NETPERF_CPU_SETSIZE sizeof(unsigned long) 2015 #define NETPERF_CPU_SET(cpu, cpusetp) *cpusetp = 1 << cpu 2016 #define NETPERF_CPU_ZERO(cpusetp) *cpusetp = (unsigned long)0 2017 typedef unsigned long netperf_cpu_set_t; 2018 #endif 2019 2020 netperf_cpu_set_t netperf_cpu_set; 2021 unsigned int len = sizeof(netperf_cpu_set); 2022 2023 if (mapped_affinity < 8*sizeof(netperf_cpu_set)) { 2024 NETPERF_CPU_ZERO(&netperf_cpu_set); 2025 NETPERF_CPU_SET(mapped_affinity,&netperf_cpu_set); 2026 2027 if (sched_setaffinity(getpid(), len, &netperf_cpu_set)) { 2028 if (debug) { 2029 fprintf(stderr, "failed to set PID %d's CPU affinity errno %d\n", 2030 getpid(),errno); 2031 fflush(stderr); 2032 } 2033 } 2034 } 2035 else { 2036 if (debug) { 2037 fprintf(stderr, 2038 "CPU number larger than pre-compiled limits. Consider a recompile.\n"); 2039 fflush(stderr); 2040 } 2041 } 2042 2043 #elif HAVE_BIND_TO_CPU_ID 2044 /* this is the one for Tru64 */ 2045 #include <sys/types.h> 2046 #include <sys/resource.h> 2047 #include <sys/processor.h> 2048 2049 /* really should be checking a return code one of these days. raj 2050 2005/08/31 */ 2051 2052 bind_to_cpu_id(getpid(), mapped_affinity,0); 2053 2054 #elif WIN32 2055 2056 { 2057 ULONG_PTR AffinityMask; 2058 ULONG_PTR ProcessAffinityMask; 2059 ULONG_PTR SystemAffinityMask; 2060 2061 if ((mapped_affinity < 0) || 2062 (mapped_affinity > MAXIMUM_PROCESSORS)) { 2063 fprintf(where, 2064 "Invalid processor_affinity specified: %d\n", mapped_affinity); fflush(where); 2065 return; 2066 } 2067 2068 if (!GetProcessAffinityMask( 2069 GetCurrentProcess(), 2070 &ProcessAffinityMask, 2071 &SystemAffinityMask)) 2072 { 2073 perror("GetProcessAffinityMask failed"); 2074 fflush(stderr); 2075 exit(1); 2076 } 2077 2078 AffinityMask = (ULONG_PTR)1 << mapped_affinity; 2079 2080 if (AffinityMask & ProcessAffinityMask) { 2081 if (!SetThreadAffinityMask( GetCurrentThread(), AffinityMask)) { 2082 perror("SetThreadAffinityMask failed"); 2083 fflush(stderr); 2084 } 2085 } else if (debug) { 2086 fprintf(where, 2087 "Processor affinity set to CPU# %d\n", mapped_affinity); 2088 fflush(where); 2089 } 2090 } 2091 2092 #else 2093 if (debug) { 2094 fprintf(where, 2095 "Processor affinity not available for this platform!\n"); 2096 fflush(where); 2097 } 2098 #endif 2099 } 2100 2101 2102 /* 2104 * Sets a socket to non-blocking operation. 2105 */ 2106 int 2107 set_nonblock (SOCKET sock) 2108 { 2109 #ifdef WIN32 2110 unsigned long flags = 1; 2111 return (ioctlsocket(sock, FIONBIO, &flags) != SOCKET_ERROR); 2112 #else 2113 return (fcntl(sock, F_SETFL, O_NONBLOCK) != -1); 2114 #endif 2115 } 2116 2117 2118 2120 /***********************************************************************/ 2121 /* */ 2122 /* send_request() */ 2123 /* */ 2124 /* send a netperf request on the control socket to the remote half of */ 2125 /* the connection. to get us closer to intervendor interoperability, */ 2126 /* we will call htonl on each of the int that compose the message to */ 2127 /* be sent. the server-half of the connection will call the ntohl */ 2128 /* routine to undo any changes that may have been made... */ 2129 /* */ 2130 /***********************************************************************/ 2131 2132 void 2133 send_request() 2134 { 2135 int counter=0; 2136 2137 /* display the contents of the request if the debug level is high */ 2138 /* enough. otherwise, just send the darned thing ;-) */ 2139 2140 if (debug > 1) { 2141 fprintf(where,"entered send_request...contents before htonl:\n"); 2142 dump_request(); 2143 } 2144 2145 /* pass the processor affinity request value to netserver */ 2146 /* this is a kludge and I know it. sgb 8/11/04 */ 2147 2148 netperf_request.content.dummy = remote_proc_affinity; 2149 2150 /* put the entire request array into network order. We do this */ 2151 /* arbitrarily rather than trying to figure-out just how much */ 2152 /* of the request array contains real information. this should */ 2153 /* be simpler, and at any rate, the performance of sending */ 2154 /* control messages for this benchmark is not of any real */ 2155 /* concern. */ 2156 2157 for (counter=0;counter < sizeof(netperf_request)/4; counter++) { 2158 request_array[counter] = htonl(request_array[counter]); 2159 } 2160 2161 if (debug > 1) { 2162 fprintf(where,"send_request...contents after htonl:\n"); 2163 dump_request(); 2164 2165 fprintf(where, 2166 "\nsend_request: about to send %u bytes from %p\n", 2167 sizeof(netperf_request), 2168 &netperf_request); 2169 fflush(where); 2170 } 2171 2172 if (send(netlib_control, 2173 (char *)&netperf_request, 2174 sizeof(netperf_request), 2175 0) != sizeof(netperf_request)) { 2176 perror("send_request: send call failure"); 2177 2178 exit(1); 2179 } 2180 } 2181 2182 /***********************************************************************/ 2183 /* */ 2184 /* send_response() */ 2185 /* */ 2186 /* send a netperf response on the control socket to the remote half of */ 2187 /* the connection. to get us closer to intervendor interoperability, */ 2188 /* we will call htonl on each of the int that compose the message to */ 2189 /* be sent. the other half of the connection will call the ntohl */ 2190 /* routine to undo any changes that may have been made... */ 2191 /* */ 2192 /***********************************************************************/ 2193 2194 void 2195 send_response() 2196 { 2197 int counter=0; 2198 int bytes_sent; 2199 2200 /* display the contents of the request if the debug level is high */ 2201 /* enough. otherwise, just send the darned thing ;-) */ 2202 2203 if (debug > 1) { 2204 fprintf(where, 2205 "send_response: contents of %u ints before htonl\n", 2206 sizeof(netperf_response)/4); 2207 dump_response(); 2208 } 2209 2210 /* put the entire response_array into network order. We do this */ 2211 /* arbitrarily rather than trying to figure-out just how much of the */ 2212 /* request array contains real information. this should be simpler, */ 2213 /* and at any rate, the performance of sending control messages for */ 2214 /* this benchmark is not of any real concern. */ 2215 2216 for (counter=0;counter < sizeof(netperf_response)/4; counter++) { 2217 response_array[counter] = htonl(response_array[counter]); 2218 } 2219 2220 if (debug > 1) { 2221 fprintf(where, 2222 "send_response: contents after htonl\n"); 2223 dump_response(); 2224 fprintf(where, 2225 "about to send %u bytes from %p\n", 2226 sizeof(netperf_response), 2227 &netperf_response); 2228 fflush(where); 2229 } 2230 2231 /*KC*/ 2232 if ((bytes_sent = send(server_sock, 2233 (char *)&netperf_response, 2234 sizeof(netperf_response), 2235 0)) != sizeof(netperf_response)) { 2236 perror("send_response: send call failure"); 2237 fprintf(where, "BytesSent: %d\n", bytes_sent); 2238 exit(1); 2239 } 2240 2241 } 2242 2243 /***********************************************************************/ 2244 /* */ 2245 /* recv_request() */ 2246 /* */ 2247 /* receive the remote's request on the control socket. we will put */ 2248 /* the entire response into host order before giving it to the */ 2249 /* calling routine. hopefully, this will go most of the way to */ 2250 /* insuring intervendor interoperability. if there are any problems, */ 2251 /* we will just punt the entire situation. */ 2252 /* */ 2253 /***********************************************************************/ 2254 2255 void 2256 recv_request() 2257 { 2258 int tot_bytes_recvd, 2259 bytes_recvd, 2260 bytes_left; 2261 char *buf = (char *)&netperf_request; 2262 int buflen = sizeof(netperf_request); 2263 int counter; 2264 2265 tot_bytes_recvd = 0; 2266 bytes_recvd = 0; /* nt_lint; bytes_recvd uninitialized if buflen == 0 */ 2267 bytes_left = buflen; 2268 while ((tot_bytes_recvd != buflen) && 2269 ((bytes_recvd = recv(server_sock, buf, bytes_left,0)) > 0 )) { 2270 tot_bytes_recvd += bytes_recvd; 2271 buf += bytes_recvd; 2272 bytes_left -= bytes_recvd; 2273 } 2274 2275 /* put the request into host order */ 2276 2277 for (counter = 0; counter < sizeof(netperf_request)/sizeof(int); counter++) { 2278 request_array[counter] = ntohl(request_array[counter]); 2279 } 2280 2281 if (debug) { 2282 fprintf(where, 2283 "recv_request: received %d bytes of request.\n", 2284 tot_bytes_recvd); 2285 fflush(where); 2286 } 2287 2288 if (bytes_recvd == SOCKET_ERROR) { 2289 Print_errno(where, 2290 "recv_request: error on recv"); 2291 fflush(where); 2292 exit(1); 2293 } 2294 2295 if (bytes_recvd == 0) { 2296 /* the remote has shutdown the control connection, we should shut it */ 2297 /* down as well and exit */ 2298 2299 if (debug) { 2300 fprintf(where, 2301 "recv_request: remote requested shutdown of control\n"); 2302 fflush(where); 2303 } 2304 2305 if (netlib_control != INVALID_SOCKET) { 2306 shutdown_control(); 2307 } 2308 exit(0); 2309 } 2310 2311 if (tot_bytes_recvd < buflen) { 2312 if (debug > 1) 2313 dump_request(); 2314 2315 fprintf(where, 2316 "recv_request: partial request received of %d bytes\n", 2317 tot_bytes_recvd); 2318 fflush(where); 2319 exit(1); 2320 } 2321 2322 if (debug > 1) { 2323 dump_request(); 2324 } 2325 2326 /* get the processor affinity request value from netperf */ 2327 /* this is a kludge and I know it. sgb 8/11/04 */ 2328 2329 local_proc_affinity = netperf_request.content.dummy; 2330 2331 if (local_proc_affinity != -1) { 2332 bind_to_specific_processor(local_proc_affinity,0); 2333 } 2334 2335 } 2336 2337 /* 2338 2339 recv_response_timed() 2340 2341 receive the remote's response on the control socket. we will put the 2342 entire response into host order before giving it to the calling 2343 routine. hopefully, this will go most of the way to insuring 2344 intervendor interoperability. if there are any problems, we will just 2345 punt the entire situation. 2346 2347 The call to select at the beginning is to get us out of hang 2348 situations where the remote gives-up but we don't find-out about 2349 it. This seems to happen only rarely, but it would be nice to be 2350 somewhat robust ;-) 2351 2352 The "_timed" part is to allow the caller to add (or I suppose 2353 subtract) from the length of timeout on the select call. this was 2354 added since not all the CPU utilization mechanisms require a 40 2355 second calibration, and we used to have an aribtrary 40 second sleep 2356 in "calibrate_remote_cpu" - since we don't _always_ need that, we 2357 want to simply add 40 seconds to the select() timeout from that call, 2358 but don't want to change all the "recv_response" calls in the code 2359 right away. sooo, we push the functionality of the old 2360 recv_response() into a new recv_response_timed(addl_timout) call, and 2361 have recv_response() call recv_response_timed(0). raj 2005-05-16 2362 2363 */ 2364 2365 2366 void 2367 recv_response_timed(int addl_time) 2368 { 2369 int tot_bytes_recvd, 2370 bytes_recvd = 0, 2371 bytes_left; 2372 char *buf = (char *)&netperf_response; 2373 int buflen = sizeof(netperf_response); 2374 int counter; 2375 2376 /* stuff for select, use fd_set for better compliance */ 2377 fd_set readfds; 2378 struct timeval timeout; 2379 2380 tot_bytes_recvd = 0; 2381 bytes_left = buflen; 2382 2383 /* zero out the response structure */ 2384 2385 /* BUG FIX SJB 2/4/93 - should be < not <= */ 2386 for (counter = 0; counter < sizeof(netperf_response)/sizeof(int); counter++) { 2387 response_array[counter] = 0; 2388 } 2389 2390 /* we only select once. it is assumed that if the response is split */ 2391 /* (which should not be happening, that we will receive the whole */ 2392 /* thing and not have a problem ;-) */ 2393 2394 FD_ZERO(&readfds); 2395 FD_SET(netlib_control,&readfds); 2396 timeout.tv_sec = 120 + addl_time; /* wait at least two minutes 2397 before punting - the USE_LOOPER 2398 CPU stuff may cause remote's to 2399 have a bit longer time of it 2400 than 60 seconds would allow. 2401 triggered by fix from Jeff 2402 Dwork. */ 2403 timeout.tv_usec = 0; 2404 2405 /* select had better return one, or there was either a problem or a */ 2406 /* timeout... */ 2407 2408 if ((counter = select(FD_SETSIZE, 2409 &readfds, 2410 0, 2411 0, 2412 &timeout)) != 1) { 2413 fprintf(where, 2414 "netperf: receive_response: no response received. errno %d counter %d\n", 2415 errno, 2416 counter); 2417 exit(1); 2418 } 2419 2420 while ((tot_bytes_recvd != buflen) && 2421 ((bytes_recvd = recv(netlib_control, buf, bytes_left,0)) > 0 )) { 2422 tot_bytes_recvd += bytes_recvd; 2423 buf += bytes_recvd; 2424 bytes_left -= bytes_recvd; 2425 } 2426 2427 if (debug) { 2428 fprintf(where,"recv_response: received a %d byte response\n", 2429 tot_bytes_recvd); 2430 fflush(where); 2431 } 2432 2433 /* put the response into host order */ 2434 2435 for (counter = 0; counter < sizeof(netperf_response)/sizeof(int); counter++) { 2436 response_array[counter] = ntohl(response_array[counter]); 2437 } 2438 2439 if (bytes_recvd == SOCKET_ERROR) { 2440 perror("recv_response"); 2441 exit(1); 2442 } 2443 if (tot_bytes_recvd < buflen) { 2444 fprintf(stderr, 2445 "recv_response: partial response received: %d bytes\n", 2446 tot_bytes_recvd); 2447 fflush(stderr); 2448 if (debug > 1) 2449 dump_response(); 2450 exit(1); 2451 } 2452 if (debug > 1) { 2453 dump_response(); 2454 } 2455 } 2456 2457 void 2458 recv_response() 2459 { 2460 recv_response_timed(0); 2461 } 2462 2463 2464 2466 #if defined(USE_PSTAT) || defined (USE_SYSCTL) 2467 int 2468 hi_32(big_int) 2469 long long *big_int; 2470 { 2471 union overlay_u { 2472 long long dword; 2473 long words[2]; 2474 } *overlay; 2475 2476 overlay = (union overlay_u *)big_int; 2477 /* on those systems which are byte swapped, we really wish to */ 2478 /* return words[1] - at least I think so - raj 4/95 */ 2479 if (htonl(1L) == 1L) { 2480 /* we are a "normal" :) machine */ 2481 return(overlay->words[0]); 2482 } 2483 else { 2484 return(overlay->words[1]); 2485 } 2486 } 2487 2488 int 2489 lo_32(big_int) 2490 long long *big_int; 2491 { 2492 union overlay_u { 2493 long long dword; 2494 long words[2]; 2495 } *overlay; 2496 2497 overlay = (union overlay_u *)big_int; 2498 /* on those systems which are byte swapped, we really wish to */ 2499 /* return words[0] - at least I think so - raj 4/95 */ 2500 if (htonl(1L) == 1L) { 2501 /* we are a "normal" :) machine */ 2502 return(overlay->words[1]); 2503 } 2504 else { 2505 return(overlay->words[0]); 2506 } 2507 } 2508 2509 #endif /* USE_PSTAT || USE_SYSCTL */ 2510 2511 2513 void libmain() 2514 { 2515 fprintf(where,"hello world\n"); 2516 fprintf(where,"debug: %d\n",debug); 2517 } 2518 2519 2520 void 2522 set_sock_buffer (SOCKET sd, enum sock_buffer which, int requested_size, int *effective_sizep) 2523 { 2524 #ifdef SO_SNDBUF 2525 int optname = (which == SEND_BUFFER) ? SO_SNDBUF : SO_RCVBUF; 2526 netperf_socklen_t sock_opt_len; 2527 2528 /* seems that under Windows, setting a value of zero is how one 2529 tells the stack you wish to enable copy-avoidance. Knuth only 2530 knows what it will do on other stacks, but it might be 2531 interesting to find-out, so we won't bother #ifdef'ing the change 2532 to allow asking for 0 bytes. Courtesy of SAF, 2007-05 raj 2533 2007-05-31 */ 2534 if (requested_size >= 0) { 2535 if (setsockopt(sd, SOL_SOCKET, optname, 2536 (char *)&requested_size, sizeof(int)) < 0) { 2537 fprintf(where, "netperf: set_sock_buffer: %s option: errno %d\n", 2538 (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF", 2539 errno); 2540 fflush(where); 2541 exit(1); 2542 } 2543 if (debug > 1) { 2544 fprintf(where, "netperf: set_sock_buffer: %s of %d requested.\n", 2545 (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF", 2546 requested_size); 2547 fflush(where); 2548 } 2549 } 2550 2551 /* Now, we will find-out what the size actually became, and report */ 2552 /* that back to the user. If the call fails, we will just report a -1 */ 2553 /* back to the initiator for the recv buffer size. */ 2554 2555 sock_opt_len = sizeof(netperf_socklen_t); 2556 if (getsockopt(sd, SOL_SOCKET, optname, (char *)effective_sizep, 2557 &sock_opt_len) < 0) { 2558 fprintf(where, "netperf: set_sock_buffer: getsockopt %s: errno %d\n", 2559 (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF", errno); 2560 fflush(where); 2561 *effective_sizep = -1; 2562 } 2563 2564 if (debug) { 2565 fprintf(where, "netperf: set_sock_buffer: " 2566 "%s socket size determined to be %d\n", 2567 (which == SEND_BUFFER) ? "send" : "receive", *effective_sizep); 2568 fflush(where); 2569 } 2570 #else /* SO_SNDBUF */ 2571 *effective_size = -1; 2572 #endif /* SO_SNDBUF */ 2573 } 2574 2575 void 2576 dump_addrinfo(FILE *dumploc, struct addrinfo *info, 2577 char *host, char *port, int family) 2578 { 2579 struct sockaddr *ai_addr; 2580 struct addrinfo *temp; 2581 temp=info; 2582 2583 fprintf(dumploc, "getaddrinfo returned the following for host '%s' ", host); 2584 fprintf(dumploc, "port '%s' ", port); 2585 fprintf(dumploc, "family %s\n", inet_ftos(family)); 2586 while (temp) { 2587 /* seems that Solaris 10 GA bits will not give a canonical name 2588 for ::0 or 0.0.0.0, and their fprintf() cannot deal with a null 2589 pointer, so we have to check for a null pointer. probably a 2590 safe thing to do anyway, eventhough it was not necessary on 2591 linux or hp-ux. raj 2005-02-09 */ 2592 if (temp->ai_canonname) { 2593 fprintf(dumploc, 2594 "\tcannonical name: '%s'\n",temp->ai_canonname); 2595 } 2596 else { 2597 fprintf(dumploc, 2598 "\tcannonical name: '%s'\n","(nil)"); 2599 } 2600 fprintf(dumploc, 2601 "\tflags: %x family: %s: socktype: %s protocol %s addrlen %d\n", 2602 temp->ai_flags, 2603 inet_ftos(temp->ai_family), 2604 inet_ttos(temp->ai_socktype), 2605 inet_ptos(temp->ai_protocol), 2606 temp->ai_addrlen); 2607 ai_addr = temp->ai_addr; 2608 if (ai_addr != NULL) { 2609 fprintf(dumploc, 2610 "\tsa_family: %s sadata: %d %d %d %d %d %d\n", 2611 inet_ftos(ai_addr->sa_family), 2612 (u_char)ai_addr->sa_data[0], 2613 (u_char)ai_addr->sa_data[1], 2614 (u_char)ai_addr->sa_data[2], 2615 (u_char)ai_addr->sa_data[3], 2616 (u_char)ai_addr->sa_data[4], 2617 (u_char)ai_addr->sa_data[5]); 2618 } 2619 temp = temp->ai_next; 2620 } 2621 fflush(dumploc); 2622 } 2623 2624 /* 2625 establish_control() 2626 2627 set-up the control connection between netperf and the netserver so we 2628 can actually run some tests. if we cannot establish the control 2629 connection, that may or may not be a good thing, so we will let the 2630 caller decide what to do. 2631 2632 to assist with pesky end-to-end-unfriendly things like firewalls, we 2633 allow the caller to specify both the remote hostname and port, and the 2634 local addressing info. i believe that in theory it is possible to 2635 have an IPv4 endpoint and an IPv6 endpoint communicate with one 2636 another, but for the time being, we are only going to take-in one 2637 requested address family parameter. this means that the only way 2638 (iirc) that we might get a mixed-mode connection would be if the 2639 address family is specified as AF_UNSPEC, and getaddrinfo() returns 2640 different families for the local and server names. 2641 2642 the "names" can also be IP addresses in ASCII string form. 2643 2644 raj 2003-02-27 */ 2645 2646 SOCKET 2647 establish_control_internal(char *hostname, 2648 char *port, 2649 int remfam, 2650 char *localhost, 2651 char *localport, 2652 int locfam) 2653 { 2654 int not_connected; 2655 SOCKET control_sock; 2656 int count; 2657 int error; 2658 2659 struct addrinfo hints; 2660 struct addrinfo *local_res; 2661 struct addrinfo *remote_res; 2662 struct addrinfo *local_res_temp; 2663 struct addrinfo *remote_res_temp; 2664 2665 if (debug) { 2666 fprintf(where, 2667 "establish_control called with host '%s' port '%s' remfam %s\n", 2668 hostname, 2669 port, 2670 inet_ftos(remfam)); 2671 fprintf(where, 2672 "\t\tlocal '%s' port '%s' locfam %s\n", 2673 localhost, 2674 localport, 2675 inet_ftos(locfam)); 2676 fflush(where); 2677 } 2678 2679 /* first, we do the remote */ 2680 memset(&hints, 0, sizeof(hints)); 2681 hints.ai_family = remfam; 2682 hints.ai_socktype = SOCK_STREAM; 2683 hints.ai_protocol = IPPROTO_TCP; 2684 hints.ai_flags = 0|AI_CANONNAME; 2685 count = 0; 2686 do { 2687 error = getaddrinfo((char *)hostname, 2688 (char *)port, 2689 &hints, 2690 &remote_res); 2691 count += 1; 2692 if (error == EAI_AGAIN) { 2693 if (debug) { 2694 fprintf(where,"Sleeping on getaddrinfo EAI_AGAIN\n"); 2695 fflush(where); 2696 } 2697 sleep(1); 2698 } 2699 } while ((error == EAI_AGAIN) && (count <= 5)); 2700 2701 if (error) { 2702 printf("establish control: could not resolve remote '%s' port '%s' af %s", 2703 hostname, 2704 port, 2705 inet_ftos(remfam)); 2706 printf("\n\tgetaddrinfo returned %d %s\n", 2707 error, 2708 gai_strerror(error)); 2709 return(INVALID_SOCKET); 2710 } 2711 2712 if (debug) { 2713 dump_addrinfo(where, remote_res, hostname, port, remfam); 2714 } 2715 2716 /* now we do the local */ 2717 memset(&hints, 0, sizeof(hints)); 2718 hints.ai_family = locfam; 2719 hints.ai_socktype = SOCK_STREAM; 2720 hints.ai_protocol = IPPROTO_TCP; 2721 hints.ai_flags = AI_PASSIVE|AI_CANONNAME; 2722 count = 0; 2723 do { 2724 count += 1; 2725 error = getaddrinfo((char *)localhost, 2726 (char *)localport, 2727 &hints, 2728 &local_res); 2729 if (error == EAI_AGAIN) { 2730 if (debug) { 2731 fprintf(where, 2732 "Sleeping on getaddrinfo(%s,%s) EAI_AGAIN count %d \n", 2733 localhost, 2734 localport, 2735 count); 2736 fflush(where); 2737 } 2738 sleep(1); 2739 } 2740 } while ((error == EAI_AGAIN) && (count <= 5)); 2741 2742 if (error) { 2743 printf("establish control: could not resolve local '%s' port '%s' af %s", 2744 localhost, 2745 localport, 2746 inet_ftos(locfam)); 2747 printf("\n\tgetaddrinfo returned %d %s\n", 2748 error, 2749 gai_strerror(error)); 2750 return(INVALID_SOCKET); 2751 } 2752 2753 if (debug) { 2754 dump_addrinfo(where, local_res, localhost, localport, locfam); 2755 } 2756 2757 not_connected = 1; 2758 local_res_temp = local_res; 2759 remote_res_temp = remote_res; 2760 /* we want to loop through all the possibilities. looping on the 2761 local addresses will be handled within the while loop. I suppose 2762 these is some more "C-expert" way to code this, but it has not 2763 lept to mind just yet :) raj 2003-02024 */ 2764 2765 while (remote_res_temp != NULL) { 2766 2767 /* I am guessing that we should use the address family of the 2768 local endpoint, and we will not worry about mixed family types 2769 - presumeably the stack or other transition mechanisms will be 2770 able to deal with that for us. famous last words :) raj 2003-02-26 */ 2771 control_sock = socket(local_res_temp->ai_family, 2772 SOCK_STREAM, 2773 0); 2774 if (control_sock == INVALID_SOCKET) { 2775 /* at some point we'll need a more generic "display error" 2776 message for when/if we use GUIs and the like. unlike a bind 2777 or connect failure, failure to allocate a socket is 2778 "immediately fatal" and so we return to the caller. raj 2003-02-24 */ 2779 if (debug) { 2780 perror("establish_control: unable to allocate control socket"); 2781 } 2782 return(INVALID_SOCKET); 2783 } 2784 2785 /* if we are going to control the local enpoint addressing, we 2786 need to call bind. of course, we should probably be setting one 2787 of the SO_REUSEmumble socket options? raj 2005-02-04 */ 2788 if (bind(control_sock, 2789 local_res_temp->ai_addr, 2790 local_res_temp->ai_addrlen) == 0) { 2791 if (debug) { 2792 fprintf(where, 2793 "bound control socket to %s and %s\n", 2794 localhost, 2795 localport); 2796 } 2797 2798 if (connect(control_sock, 2799 remote_res_temp->ai_addr, 2800 remote_res_temp->ai_addrlen) == 0) { 2801 /* we have successfully connected to the remote netserver */ 2802 if (debug) { 2803 fprintf(where, 2804 "successful connection to remote netserver at %s and %s\n", 2805 hostname, 2806 port); 2807 } 2808 not_connected = 0; 2809 /* this should get us out of the while loop */ 2810 break; 2811 } else { 2812 /* the connect call failed */ 2813 if (debug) { 2814 fprintf(where, 2815 "establish_control: connect failed, errno %d %s\n", 2816 errno, 2817 strerror(errno)); 2818 fprintf(where, " trying next address combination\n"); 2819 fflush(where); 2820 } 2821 } 2822 } 2823 else { 2824 /* the bind failed */ 2825 if (debug) { 2826 fprintf(where, 2827 "establish_control: bind failed, errno %d %s\n", 2828 errno, 2829 strerror(errno)); 2830 fprintf(where, " trying next address combination\n"); 2831 fflush(where); 2832 } 2833 } 2834 2835 if ((local_res_temp = local_res_temp->ai_next) == NULL) { 2836 /* wrap the local and move to the next server, don't forget to 2837 close the current control socket. raj 2003-02-24 */ 2838 local_res_temp = local_res; 2839 /* the outer while conditions will deal with the case when we 2840 get to the end of all the possible remote addresses. */ 2841 remote_res_temp = remote_res_temp->ai_next; 2842 /* it is simplest here to just close the control sock. since 2843 this is not a performance critical section of code, we 2844 don't worry about overheads for socket allocation or 2845 close. raj 2003-02-24 */ 2846 } 2847 close(control_sock); 2848 } 2849 2850 /* we no longer need the addrinfo stuff */ 2851 freeaddrinfo(local_res); 2852 freeaddrinfo(remote_res); 2853 2854 /* so, we are either connected or not */ 2855 if (not_connected) { 2856 fprintf(where, "establish control: are you sure there is a netserver listening on %s at port %s?\n",hostname,port); 2857 fflush(where); 2858 return(INVALID_SOCKET); 2859 } 2860 /* at this point, we are connected. we probably want some sort of 2861 version check with the remote at some point. raj 2003-02-24 */ 2862 return(control_sock); 2863 } 2864 2865 void 2866 establish_control(char *hostname, 2867 char *port, 2868 int remfam, 2869 char *localhost, 2870 char *localport, 2871 int locfam) 2872 2873 { 2874 2875 netlib_control = establish_control_internal(hostname, 2876 port, 2877 remfam, 2878 localhost, 2879 localport, 2880 locfam); 2881 if (netlib_control == INVALID_SOCKET) { 2882 fprintf(where, 2883 "establish_control could not establish the control connection from %s port %s address family %s to %s port %s address family %s\n", 2884 localhost,localport,inet_ftos(locfam), 2885 hostname,port,inet_ftos(remfam)); 2886 fflush(where); 2887 exit(INVALID_SOCKET); 2888 } 2889 } 2890 2891 2892 2894 2895 /***********************************************************************/ 2896 /* */ 2897 /* get_id() */ 2898 /* */ 2899 /* Return a string to the calling routine that contains the */ 2900 /* identifying information for the host we are running on. This */ 2901 /* information will then either be displayed locally, or returned to */ 2902 /* a remote caller for display there. */ 2903 /* */ 2904 /***********************************************************************/ 2905 2906 char * 2907 get_id() 2908 { 2909 static char id_string[80]; 2910 #ifdef WIN32 2911 char system_name[MAX_COMPUTERNAME_LENGTH+1] ; 2912 DWORD name_len = MAX_COMPUTERNAME_LENGTH + 1 ; 2913 #else 2914 struct utsname system_name; 2915 #endif /* WIN32 */ 2916 2917 #ifdef WIN32 2918 SYSTEM_INFO SystemInfo; 2919 GetSystemInfo( &SystemInfo ) ; 2920 if ( !GetComputerName(system_name , &name_len) ) 2921 strcpy(system_name , "no_name") ; 2922 #else 2923 if (uname(&system_name) <0) { 2924 perror("identify_local: uname"); 2925 exit(1); 2926 } 2927 #endif /* WIN32 */ 2928 2929 snprintf(id_string, sizeof(id_string), 2930 #ifdef WIN32 2931 "%-15s%-15s%d.%d%d", 2932 "Windows NT", 2933 system_name , 2934 GetVersion() & 0xFF , 2935 GetVersion() & 0xFF00 , 2936 SystemInfo.dwProcessorType 2937 2938 #else 2939 "%-15s%-15s%-15s%-15s%-15s", 2940 system_name.sysname, 2941 system_name.nodename, 2942 system_name.release, 2943 system_name.version, 2944 system_name.machine 2945 #endif /* WIN32 */ 2946 ); 2947 return (id_string); 2948 } 2949 2950 2951 /***********************************************************************/ 2952 /* */ 2953 /* identify_local() */ 2954 /* */ 2955 /* Display identifying information about the local host to the user. */ 2956 /* At first release, this information will be the same as that which */ 2957 /* is returned by the uname -a command, with the exception of the */ 2958 /* idnumber field, which seems to be a non-POSIX item, and hence */ 2959 /* non-portable. */ 2960 /* */ 2961 /***********************************************************************/ 2962 2963 void 2964 identify_local() 2965 { 2966 2967 char *local_id; 2968 2969 local_id = get_id(); 2970 2971 fprintf(where,"Local Information \n\ 2972 Sysname Nodename Release Version Machine\n"); 2973 2974 fprintf(where,"%s\n", 2975 local_id); 2976 2977 } 2978 2979 2980 /***********************************************************************/ 2981 /* */ 2982 /* identify_remote() */ 2983 /* */ 2984 /* Display identifying information about the remote host to the user. */ 2985 /* At first release, this information will be the same as that which */ 2986 /* is returned by the uname -a command, with the exception of the */ 2987 /* idnumber field, which seems to be a non-POSIX item, and hence */ 2988 /* non-portable. A request is sent to the remote side, which will */ 2989 /* return a string containing the utsname information in a */ 2990 /* pre-formatted form, which is then displayed after the header. */ 2991 /* */ 2992 /***********************************************************************/ 2993 2994 void 2995 identify_remote() 2996 { 2997 2998 char *remote_id=""; 2999 3000 /* send a request for node info to the remote */ 3001 netperf_request.content.request_type = NODE_IDENTIFY; 3002 3003 send_request(); 3004 3005 /* and now wait for the reply to come back */ 3006 3007 recv_response(); 3008 3009 if (netperf_response.content.serv_errno) { 3010 Set_errno(netperf_response.content.serv_errno); 3011 perror("identify_remote: on remote"); 3012 exit(1); 3013 } 3014 3015 fprintf(where,"Remote Information \n\ 3016 Sysname Nodename Release Version Machine\n"); 3017 3018 fprintf(where,"%s", 3019 remote_id); 3020 } 3021 3022 void 3023 cpu_start(int measure_cpu) 3024 { 3025 3026 gettimeofday(&time1, 3027 &tz); 3028 3029 if (measure_cpu) { 3030 cpu_util_init(); 3031 measuring_cpu = 1; 3032 cpu_method = get_cpu_method(); 3033 cpu_start_internal(); 3034 } 3035 } 3036 3037 3038 void 3040 cpu_stop(int measure_cpu, float *elapsed) 3041 3042 { 3043 3044 int sec, 3045 usec; 3046 3047 if (measure_cpu) { 3048 cpu_stop_internal(); 3049 cpu_util_terminate(); 3050 } 3051 3052 gettimeofday(&time2, 3053 &tz); 3054 3055 if (time2.tv_usec < time1.tv_usec) { 3056 time2.tv_usec += 1000000; 3057 time2.tv_sec -= 1; 3058 } 3059 3060 sec = time2.tv_sec - time1.tv_sec; 3061 usec = time2.tv_usec - time1.tv_usec; 3062 lib_elapsed = (float)sec + ((float)usec/(float)1000000.0); 3063 3064 *elapsed = lib_elapsed; 3065 3066 } 3067 3068 3069 double 3070 calc_thruput_interval(double units_received,double elapsed) 3071 3072 { 3073 double divisor; 3074 3075 /* We will calculate the thruput in libfmt units/second */ 3076 switch (libfmt) { 3077 case 'K': 3078 divisor = 1024.0; 3079 break; 3080 case 'M': 3081 divisor = 1024.0 * 1024.0; 3082 break; 3083 case 'G': 3084 divisor = 1024.0 * 1024.0 * 1024.0; 3085 break; 3086 case 'k': 3087 divisor = 1000.0 / 8.0; 3088 break; 3089 case 'm': 3090 divisor = 1000.0 * 1000.0 / 8.0; 3091 break; 3092 case 'g': 3093 divisor = 1000.0 * 1000.0 * 1000.0 / 8.0; 3094 break; 3095 3096 default: 3097 divisor = 1024.0; 3098 } 3099 3100 return (units_received / divisor / elapsed); 3101 3102 } 3103 3104 double 3105 calc_thruput(double units_received) 3106 3107 { 3108 return(calc_thruput_interval(units_received,lib_elapsed)); 3109 } 3110 3111 /* these "_omni" versions are ones which understand 'x' as a unit, 3112 meaning transactions/s. we have a separate routine rather than 3113 convert the existing routine so we don't have to go and change 3114 _all_ the nettest_foo.c files at one time. raj 2007-06-08 */ 3115 3116 double 3117 calc_thruput_interval_omni(double units_received,double elapsed) 3118 3119 { 3120 double divisor; 3121 3122 /* We will calculate the thruput in libfmt units/second */ 3123 switch (libfmt) { 3124 case 'K': 3125 divisor = 1024.0; 3126 break; 3127 case 'M': 3128 divisor = 1024.0 * 1024.0; 3129 break; 3130 case 'G': 3131 divisor = 1024.0 * 1024.0 * 1024.0; 3132 break; 3133 case 'k': 3134 divisor = 1000.0 / 8.0; 3135 break; 3136 case 'm': 3137 divisor = 1000.0 * 1000.0 / 8.0; 3138 break; 3139 case 'g': 3140 divisor = 1000.0 * 1000.0 * 1000.0 / 8.0; 3141 break; 3142 case 'x': 3143 divisor = 1.0; 3144 break; 3145 3146 default: 3147 fprintf(where, 3148 "WARNING calc_throughput_internal_omni: unknown units %c\n", 3149 libfmt); 3150 fflush(where); 3151 divisor = 1024.0; 3152 } 3153 3154 return (units_received / divisor / elapsed); 3155 3156 } 3157 3158 double 3159 calc_thruput_omni(double units_received) 3160 3161 { 3162 return(calc_thruput_interval_omni(units_received,lib_elapsed)); 3163 } 3164 3165 3166 3168 3169 3170 float 3171 calc_cpu_util(float elapsed_time) 3172 { 3173 return(calc_cpu_util_internal(elapsed_time)); 3174 } 3175 3176 float 3177 calc_service_demand_internal(double unit_divisor, 3178 double units_sent, 3179 float elapsed_time, 3180 float cpu_utilization, 3181 int num_cpus) 3182 3183 { 3184 3185 double service_demand; 3186 double thruput; 3187 3188 if (debug) { 3189 fprintf(where,"calc_service_demand called: units_sent = %f\n", 3190 units_sent); 3191 fprintf(where," elapsed_time = %f\n", 3192 elapsed_time); 3193 fprintf(where," cpu_util = %f\n", 3194 cpu_utilization); 3195 fprintf(where," num cpu = %d\n", 3196 num_cpus); 3197 fflush(where); 3198 } 3199 3200 if (num_cpus == 0) num_cpus = lib_num_loc_cpus; 3201 3202 if (elapsed_time == 0.0) { 3203 elapsed_time = lib_elapsed; 3204 } 3205 if (cpu_utilization == 0.0) { 3206 cpu_utilization = lib_local_cpu_util; 3207 } 3208 3209 thruput = (units_sent / 3210 (double) unit_divisor / 3211 (double) elapsed_time); 3212 3213 /* on MP systems, it is necessary to multiply the service demand by */ 3214 /* the number of CPU's. at least, I believe that to be the case:) */ 3215 /* raj 10/95 */ 3216 3217 /* thruput has a "per second" component. if we were using 100% ( */ 3218 /* 100.0) of the CPU in a second, that would be 1 second, or 1 */ 3219 /* millisecond, so we multiply cpu_utilization by 10 to go to */ 3220 /* milliseconds, or 10,000 to go to micro seconds. With revision */ 3221 /* 2.1, the service demand measure goes to microseconds per unit. */ 3222 /* raj 12/95 */ 3223 service_demand = (cpu_utilization*10000.0/thruput) * 3224 (float) num_cpus; 3225 3226 if (debug) { 3227 fprintf(where,"calc_service_demand using: units_sent = %f\n", 3228 units_sent); 3229 fprintf(where," elapsed_time = %f\n", 3230 elapsed_time); 3231 fprintf(where," cpu_util = %f\n", 3232 cpu_utilization); 3233 fprintf(where," num cpu = %d\n", 3234 num_cpus); 3235 fprintf(where,"calc_service_demand got: thruput = %f\n", 3236 thruput); 3237 fprintf(where," servdem = %f\n", 3238 service_demand); 3239 fflush(where); 3240 } 3241 return (float)service_demand; 3242 } 3243 3244 float calc_service_demand(double units_sent, 3245 float elapsed_time, 3246 float cpu_utilization, 3247 int num_cpus) 3248 3249 { 3250 3251 double unit_divisor = (double)1024.0; 3252 3253 return(calc_service_demand_internal(unit_divisor, 3254 units_sent, 3255 elapsed_time, 3256 cpu_utilization, 3257 num_cpus)); 3258 } 3259 3260 float calc_service_demand_trans(double units_sent, 3261 float elapsed_time, 3262 float cpu_utilization, 3263 int num_cpus) 3264 3265 { 3266 3267 double unit_divisor = (double)1.0; 3268 3269 return(calc_service_demand_internal(unit_divisor, 3270 units_sent, 3271 elapsed_time, 3272 cpu_utilization, 3273 num_cpus)); 3274 } 3275 3276 3277 3279 float 3280 calibrate_local_cpu(float local_cpu_rate) 3281 { 3282 3283 lib_num_loc_cpus = get_num_cpus(); 3284 3285 lib_use_idle = 0; 3286 #ifdef USE_LOOPER 3287 cpu_util_init(); 3288 lib_use_idle = 1; 3289 #endif /* USE_LOOPER */ 3290 3291 if (local_cpu_rate > 0) { 3292 /* The user think that he knows what the cpu rate is. We assume */ 3293 /* that all the processors of an MP system are essentially the */ 3294 /* same - for this reason we do not have a per processor maxrate. */ 3295 /* if the machine has processors which are different in */ 3296 /* performance, the CPU utilization will be skewed. raj 4/95 */ 3297 lib_local_maxrate = local_cpu_rate; 3298 } 3299 else { 3300 /* if neither USE_LOOPER nor USE_PSTAT are defined, we return a */ 3301 /* 0.0 to indicate that times or getrusage should be used. raj */ 3302 /* 4/95 */ 3303 lib_local_maxrate = (float)0.0; 3304 #if defined(USE_PROC_STAT) || defined(USE_LOOPER) || defined(USE_PSTAT) || defined(USE_KSTAT) || defined(USE_PERFSTAT) || defined(USE_SYSCTL) 3305 lib_local_maxrate = calibrate_idle_rate(4,10); 3306 #endif 3307 } 3308 return lib_local_maxrate; 3309 } 3310 3311 3312 float 3313 calibrate_remote_cpu() 3314 { 3315 float remrate; 3316 3317 netperf_request.content.request_type = CPU_CALIBRATE; 3318 send_request(); 3319 /* we know that calibration will last at least 40 seconds, so go to */ 3320 /* sleep for that long so the 60 second select in recv_response will */ 3321 /* not pop. raj 7/95 */ 3322 3323 /* we know that CPU calibration may last as long as 40 seconds, so 3324 make sure we "select" for at least that long while looking for 3325 the response. raj 2005-05-16 */ 3326 recv_response_timed(40); 3327 3328 if (netperf_response.content.serv_errno) { 3329 /* initially, silently ignore remote errors and pass */ 3330 /* back a zero to the caller this should allow us to */ 3331 /* mix rev 1.0 and rev 1.1 netperfs... */ 3332 return((float)0.0); 3333 } 3334 else { 3335 /* the rate is the first word of the test_specific data */ 3336 bcopy((char *)netperf_response.content.test_specific_data, 3337 (char *)&remrate, 3338 sizeof(remrate)); 3339 bcopy((char *)netperf_response.content.test_specific_data + sizeof(remrate), 3340 (char *)&lib_num_rem_cpus, 3341 sizeof(lib_num_rem_cpus)); 3342 /* remrate = (float) netperf_response.content.test_specific_data[0]; */ 3343 return(remrate); 3344 } 3345 } 3346 3347 #ifndef WIN32 3349 /* WIN32 requires that at least one of the file sets to select be non-null. */ 3350 /* Since msec_sleep routine is only called by nettest_dlpi & nettest_unix, */ 3351 /* let's duck this issue. */ 3352 3353 int 3354 msec_sleep( int msecs ) 3355 { 3356 int rval ; 3357 3358 struct timeval timeout; 3359 3360 timeout.tv_sec = msecs / 1000; 3361 timeout.tv_usec = (msecs - (msecs/1000) *1000) * 1000; 3362 if ((rval = select(0, 3363 0, 3364 0, 3365 0, 3366 &timeout))) { 3367 if ( SOCKET_EINTR(rval) ) { 3368 return(1); 3369 } 3370 perror("msec_sleep: select"); 3371 exit(1); 3372 } 3373 return(0); 3374 } 3375 #endif /* WIN32 */ 3376 3377 #ifdef WANT_HISTOGRAM 3378 /* hist.c 3379 3380 Given a time difference in microseconds, increment one of 61 3381 different buckets: 3382 3383 0 - 9 in increments of 1 usec 3384 0 - 9 in increments of 10 usecs 3385 0 - 9 in increments of 100 usecs 3386 1 - 9 in increments of 1 msec 3387 1 - 9 in increments of 10 msecs 3388 1 - 9 in increments of 100 msecs 3389 1 - 9 in increments of 1 sec 3390 1 - 9 in increments of 10 sec 3391 > 100 secs 3392 3393 This will allow any time to be recorded to within an accuracy of 3394 10%, and provides a compact representation for capturing the 3395 distribution of a large number of time differences (e.g. 3396 request-response latencies). 3397 3398 Colin Low 10/6/93 3399 Rick Jones 2004-06-15 extend to unit and ten usecs 3400 */ 3401 3402 /* #include "sys.h" */ 3403 3404 /*#define HIST_TEST*/ 3405 3406 HIST 3407 HIST_new(void){ 3408 HIST h; 3409 if((h = (HIST) malloc(sizeof(struct histogram_struct))) == NULL) { 3410 perror("HIST_new - malloc failed"); 3411 exit(1); 3412 } 3413 HIST_clear(h); 3414 return h; 3415 } 3416 3417 void 3418 HIST_clear(HIST h){ 3419 int i; 3420 for(i = 0; i < 10; i++){ 3421 h->unit_usec[i] = 0; 3422 h->ten_usec[i] = 0; 3423 h->hundred_usec[i] = 0; 3424 h->unit_msec[i] = 0; 3425 h->ten_msec[i] = 0; 3426 h->hundred_msec[i] = 0; 3427 h->unit_sec[i] = 0; 3428 h->ten_sec[i] = 0; 3429 } 3430 h->ridiculous = 0; 3431 h->total = 0; 3432 } 3433 3434 void 3435 HIST_add(register HIST h, int time_delta){ 3436 register int val; 3437 h->total++; 3438 val = time_delta; 3439 if(val <= 9) h->unit_usec[val]++; 3440 else { 3441 val = val/10; 3442 if(val <= 9) h->ten_usec[val]++; 3443 else { 3444 val = val/10; 3445 if(val <= 9) h->hundred_usec[val]++; 3446 else { 3447 val = val/10; 3448 if(val <= 9) h->unit_msec[val]++; 3449 else { 3450 val = val/10; 3451 if(val <= 9) h->ten_msec[val]++; 3452 else { 3453 val = val/10; 3454 if(val <= 9) h->hundred_msec[val]++; 3455 else { 3456 val = val/10; 3457 if(val <= 9) h->unit_sec[val]++; 3458 else { 3459 val = val/10; 3460 if(val <= 9) h->ten_sec[val]++; 3461 else h->ridiculous++; 3462 } 3463 } 3464 } 3465 } 3466 } 3467 } 3468 } 3469 } 3470 3471 #define RB_printf printf 3472 3473 void 3474 output_row(FILE *fd, char *title, int *row){ 3475 register int i; 3476 RB_printf("%s", title); 3477 for(i = 0; i < 10; i++) RB_printf(": %4d", row[i]); 3478 RB_printf("\n"); 3479 } 3480 3481 int 3482 sum_row(int *row) { 3483 int sum = 0; 3484 int i; 3485 for (i = 0; i < 10; i++) sum += row[i]; 3486 return(sum); 3487 } 3488 3489 void 3490 HIST_report(HIST h){ 3491 #ifndef OLD_HISTOGRAM 3492 output_row(stdout, "UNIT_USEC ", h->unit_usec); 3493 output_row(stdout, "TEN_USEC ", h->ten_usec); 3494 output_row(stdout, "HUNDRED_USEC ", h->hundred_usec); 3495 #else 3496 h->hundred_usec[0] += sum_row(h->unit_usec); 3497 h->hundred_usec[0] += sum_row(h->ten_usec); 3498 output_row(stdout, "TENTH_MSEC ", h->hundred_usec); 3499 #endif 3500 output_row(stdout, "UNIT_MSEC ", h->unit_msec); 3501 output_row(stdout, "TEN_MSEC ", h->ten_msec); 3502 output_row(stdout, "HUNDRED_MSEC ", h->hundred_msec); 3503 output_row(stdout, "UNIT_SEC ", h->unit_sec); 3504 output_row(stdout, "TEN_SEC ", h->ten_sec); 3505 RB_printf(">100_SECS: %d\n", h->ridiculous); 3506 RB_printf("HIST_TOTAL: %d\n", h->total); 3507 } 3508 3509 #endif 3510 3511 /* with the advent of sit-and-spin intervals support, we might as well 3512 make these things available all the time, not just for demo or 3513 histogram modes. raj 2006-02-06 */ 3514 #ifdef HAVE_GETHRTIME 3515 3516 void 3517 HIST_timestamp(hrtime_t *timestamp) 3518 { 3519 *timestamp = gethrtime(); 3520 } 3521 3522 int 3523 delta_micro(hrtime_t *begin, hrtime_t *end) 3524 { 3525 long nsecs; 3526 nsecs = (*end) - (*begin); 3527 return(nsecs/1000); 3528 } 3529 3530 #elif defined(HAVE_GET_HRT) 3531 #include "hrt.h" 3532 3533 void 3534 HIST_timestamp(hrt_t *timestamp) 3535 { 3536 *timestamp = get_hrt(); 3537 } 3538 3539 int 3540 delta_micro(hrt_t *begin, hrt_t *end) 3541 { 3542 3543 return((int)get_hrt_delta(*end,*begin)); 3544 3545 } 3546 #elif defined(WIN32) 3547 void HIST_timestamp(LARGE_INTEGER *timestamp) 3548 { 3549 QueryPerformanceCounter(timestamp); 3550 } 3551 3552 int delta_micro(LARGE_INTEGER *begin, LARGE_INTEGER *end) 3553 { 3554 LARGE_INTEGER DeltaTimestamp; 3555 static LARGE_INTEGER TickHz = {0,0}; 3556 3557 if (TickHz.QuadPart == 0) 3558 { 3559 QueryPerformanceFrequency(&TickHz); 3560 } 3561 3562 /*+*+ Rick; this will overflow after ~2000 seconds, is that 3563 good enough? Spencer: Yes, that should be more than good 3564 enough for histogram support */ 3565 3566 DeltaTimestamp.QuadPart = (end->QuadPart - begin->QuadPart) * 3567 1000000/TickHz.QuadPart; 3568 assert((DeltaTimestamp.HighPart == 0) && 3569 ((int)DeltaTimestamp.LowPart >= 0)); 3570 3571 return (int)DeltaTimestamp.LowPart; 3572 } 3573 3574 #else 3575 3576 void 3577 HIST_timestamp(struct timeval *timestamp) 3578 { 3579 gettimeofday(timestamp,NULL); 3580 } 3581 3582 /* return the difference (in micro seconds) between two timeval */ 3583 /* timestamps */ 3584 int 3585 delta_micro(struct timeval *begin,struct timeval *end) 3586 3587 { 3588 3589 int usecs, secs; 3590 3591 if (end->tv_usec < begin->tv_usec) { 3592 /* borrow a second from the tv_sec */ 3593 end->tv_usec += 1000000; 3594 end->tv_sec--; 3595 } 3596 usecs = end->tv_usec - begin->tv_usec; 3597 secs = end->tv_sec - begin->tv_sec; 3598 3599 usecs += (secs * 1000000); 3600 3601 return(usecs); 3602 3603 } 3604 #endif /* HAVE_GETHRTIME */ 3605 3606 3607 #ifdef WANT_DLPI 3609 3610 int 3611 put_control(fd, len, pri, ack) 3612 int fd, len, pri, ack; 3613 { 3614 int error; 3615 int flags = 0; 3616 dl_error_ack_t *err_ack = (dl_error_ack_t *)control_data; 3617 3618 control_message.len = len; 3619 3620 if ((error = putmsg(fd, &control_message, 0, pri)) < 0 ) { 3621 fprintf(where,"put_control: putmsg error %d\n",error); 3622 fflush(where); 3623 return(-1); 3624 } 3625 if ((error = getmsg(fd, &control_message, 0, &flags)) < 0) { 3626 fprintf(where,"put_control: getsmg error %d\n",error); 3627 fflush(where); 3628 return(-1); 3629 } 3630 if (err_ack->dl_primitive != ack) { 3631 fprintf(where,"put_control: acknowledgement error wanted %u got %u \n", 3632 ack,err_ack->dl_primitive); 3633 if (err_ack->dl_primitive == DL_ERROR_ACK) { 3634 fprintf(where," dl_error_primitive: %u\n", 3635 err_ack->dl_error_primitive); 3636 fprintf(where," dl_errno: %u\n", 3637 err_ack->dl_errno); 3638 fprintf(where," dl_unix_errno %u\n", 3639 err_ack->dl_unix_errno); 3640 } 3641 fflush(where); 3642 return(-1); 3643 } 3644 3645 return(0); 3646 } 3647 3648 int 3649 dl_open(char devfile[], int ppa) 3650 { 3651 int fd; 3652 dl_attach_req_t *attach_req = (dl_attach_req_t *)control_data; 3653 3654 if ((fd = open(devfile, O_RDWR)) == -1) { 3655 fprintf(where,"netperf: dl_open: open of %s failed, errno = %d\n", 3656 devfile, 3657 errno); 3658 return(-1); 3659 } 3660 3661 attach_req->dl_primitive = DL_ATTACH_REQ; 3662 attach_req->dl_ppa = ppa; 3663 3664 if (put_control(fd, sizeof(dl_attach_req_t), 0, DL_OK_ACK) < 0) { 3665 fprintf(where, 3666 "netperf: dl_open: could not send control message, errno = %d\n", 3667 errno); 3668 return(-1); 3669 } 3670 return(fd); 3671 } 3672 3673 int 3674 dl_bind(int fd, int sap, int mode, char *dlsap_ptr, int *dlsap_len) 3675 { 3676 dl_bind_req_t *bind_req = (dl_bind_req_t *)control_data; 3677 dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)control_data; 3678 3679 bind_req->dl_primitive = DL_BIND_REQ; 3680 bind_req->dl_sap = sap; 3681 bind_req->dl_max_conind = 1; 3682 bind_req->dl_service_mode = mode; 3683 bind_req->dl_conn_mgmt = 0; 3684 bind_req->dl_xidtest_flg = 0; 3685 3686 if (put_control(fd, sizeof(dl_bind_req_t), 0, DL_BIND_ACK) < 0) { 3687 fprintf(where, 3688 "netperf: dl_bind: could not send control message, errno = %d\n", 3689 errno); 3690 return(-1); 3691 } 3692 3693 /* at this point, the control_data portion of the control message */ 3694 /* structure should contain a DL_BIND_ACK, which will have a full */ 3695 /* DLSAP in it. we want to extract this and pass it up so that */ 3696 /* it can be passed around. */ 3697 if (*dlsap_len >= bind_ack->dl_addr_length) { 3698 bcopy((char *)bind_ack+bind_ack->dl_addr_offset, 3699 dlsap_ptr, 3700 bind_ack->dl_addr_length); 3701 *dlsap_len = bind_ack->dl_addr_length; 3702 return(0); 3703 } 3704 else { 3705 return (-1); 3706 } 3707 } 3708 3709 int 3710 dl_connect(int fd, unsigned char *remote_addr, int remote_addr_len) 3711 { 3712 dl_connect_req_t *connection_req = (dl_connect_req_t *)control_data; 3713 dl_connect_con_t *connection_con = (dl_connect_con_t *)control_data; 3714 struct pollfd pinfo; 3715 3716 int flags = 0; 3717 3718 /* this is here on the off chance that we really want some data */ 3719 u_long data_area[512]; 3720 struct strbuf data_message; 3721 3722 int error; 3723 3724 data_message.maxlen = 2048; 3725 data_message.len = 0; 3726 data_message.buf = (char *)data_area; 3727 3728 connection_req->dl_primitive = DL_CONNECT_REQ; 3729 connection_req->dl_dest_addr_length = remote_addr_len; 3730 connection_req->dl_dest_addr_offset = sizeof(dl_connect_req_t); 3731 connection_req->dl_qos_length = 0; 3732 connection_req->dl_qos_offset = 0; 3733 bcopy (remote_addr, 3734 (unsigned char *)control_data + sizeof(dl_connect_req_t), 3735 remote_addr_len); 3736 3737 /* well, I would call the put_control routine here, but the sequence */ 3738 /* of connection stuff with DLPI is a bit screwey with all this */ 3739 /* message passing - Toto, I don't think were in Berkeley anymore. */ 3740 3741 control_message.len = sizeof(dl_connect_req_t) + remote_addr_len; 3742 if ((error = putmsg(fd,&control_message,0,0)) !=0) { 3743 fprintf(where,"dl_connect: putmsg failure, errno = %d, error 0x%x \n", 3744 errno,error); 3745 fflush(where); 3746 return(-1); 3747 }; 3748 3749 pinfo.fd = fd; 3750 pinfo.events = POLLIN | POLLPRI; 3751 pinfo.revents = 0; 3752 3753 if ((error = getmsg(fd,&control_message,&data_message,&flags)) != 0) { 3754 fprintf(where,"dl_connect: getmsg failure, errno = %d, error 0x%x \n", 3755 errno,error); 3756 fflush(where); 3757 return(-1); 3758 } 3759 while (control_data[0] == DL_TEST_CON) { 3760 /* i suppose we spin until we get an error, or a connection */ 3761 /* indication */ 3762 if((error = getmsg(fd,&control_message,&data_message,&flags)) !=0) { 3763 fprintf(where,"dl_connect: getmsg failure, errno = %d, error = 0x%x\n", 3764 errno,error); 3765 fflush(where); 3766 return(-1); 3767 } 3768 } 3769 3770 /* we are out - it either worked or it didn't - which was it? */ 3771 if (control_data[0] == DL_CONNECT_CON) { 3772 return(0); 3773 } 3774 else { 3775 return(-1); 3776 } 3777 } 3778 3779 int 3780 dl_accept(fd, remote_addr, remote_addr_len) 3781 int fd; 3782 unsigned char *remote_addr; 3783 int remote_addr_len; 3784 { 3785 dl_connect_ind_t *connect_ind = (dl_connect_ind_t *)control_data; 3786 dl_connect_res_t *connect_res = (dl_connect_res_t *)control_data; 3787 int tmp_cor; 3788 int flags = 0; 3789 3790 /* hang around and wait for a connection request */ 3791 getmsg(fd,&control_message,0,&flags); 3792 while (control_data[0] != DL_CONNECT_IND) { 3793 getmsg(fd,&control_message,0,&flags); 3794 } 3795 3796 /* now respond to the request. at some point, we may want to be sure */ 3797 /* that the connection came from the correct station address, but */ 3798 /* will assume that we do not have to worry about it just now. */ 3799 3800 tmp_cor = connect_ind->dl_correlation; 3801 3802 connect_res->dl_primitive = DL_CONNECT_RES; 3803 connect_res->dl_correlation = tmp_cor; 3804 connect_res->dl_resp_token = 0; 3805 connect_res->dl_qos_length = 0; 3806 connect_res->dl_qos_offset = 0; 3807 connect_res->dl_growth = 0; 3808 3809 return(put_control(fd, sizeof(dl_connect_res_t), 0, DL_OK_ACK)); 3810 3811 } 3812 3813 int 3814 dl_set_window(fd, window) 3815 int fd, window; 3816 { 3817 return(0); 3818 } 3819 3820 void 3821 dl_stats(fd) 3822 int fd; 3823 { 3824 } 3825 3826 int 3827 dl_send_disc(fd) 3828 int fd; 3829 { 3830 } 3831 3832 int 3833 dl_recv_disc(fd) 3834 int fd; 3835 { 3836 } 3837 #endif /* WANT_DLPI*/ 3838 3839 /* these routines for confidence intervals are courtesy of IBM. They */ 3840 /* have been modified slightly for more general usage beyond TCP/UDP */ 3841 /* tests. raj 11/94 I would suspect that this code carries an IBM */ 3842 /* copyright that is much the same as that for the original HP */ 3843 /* netperf code */ 3844 int confidence_iterations; /* for iterations */ 3845 3846 double 3847 result_confid=-10.0, 3848 loc_cpu_confid=-10.0, 3849 rem_cpu_confid=-10.0, 3850 3851 measured_sum_result=0.0, 3852 measured_square_sum_result=0.0, 3853 measured_mean_result=0.0, 3854 measured_var_result=0.0, 3855 3856 measured_sum_local_cpu=0.0, 3857 measured_square_sum_local_cpu=0.0, 3858 measured_mean_local_cpu=0.0, 3859 measured_var_local_cpu=0.0, 3860 3861 measured_sum_remote_cpu=0.0, 3862 measured_square_sum_remote_cpu=0.0, 3863 measured_mean_remote_cpu=0.0, 3864 measured_var_remote_cpu=0.0, 3865 3866 measured_sum_local_service_demand=0.0, 3867 measured_square_sum_local_service_demand=0.0, 3868 measured_mean_local_service_demand=0.0, 3869 measured_var_local_service_demand=0.0, 3870 3871 measured_sum_remote_service_demand=0.0, 3872 measured_square_sum_remote_service_demand=0.0, 3873 measured_mean_remote_service_demand=0.0, 3874 measured_var_remote_service_demand=0.0, 3875 3876 measured_sum_local_time=0.0, 3877 measured_square_sum_local_time=0.0, 3878 measured_mean_local_time=0.0, 3879 measured_var_local_time=0.0, 3880 3881 measured_mean_remote_time=0.0, 3882 3883 measured_fails, 3884 measured_local_results, 3885 confidence=-10.0; 3886 /* interval=0.1; */ 3887 3888 /************************************************************************/ 3889 /* */ 3890 /* Constants for Confidence Intervals */ 3891 /* */ 3892 /************************************************************************/ 3893 void 3894 init_stat() 3895 { 3896 measured_sum_result=0.0; 3897 measured_square_sum_result=0.0; 3898 measured_mean_result=0.0; 3899 measured_var_result=0.0; 3900 3901 measured_sum_local_cpu=0.0; 3902 measured_square_sum_local_cpu=0.0; 3903 measured_mean_local_cpu=0.0; 3904 measured_var_local_cpu=0.0; 3905 3906 measured_sum_remote_cpu=0.0; 3907 measured_square_sum_remote_cpu=0.0; 3908 measured_mean_remote_cpu=0.0; 3909 measured_var_remote_cpu=0.0; 3910 3911 measured_sum_local_service_demand=0.0; 3912 measured_square_sum_local_service_demand=0.0; 3913 measured_mean_local_service_demand=0.0; 3914 measured_var_local_service_demand=0.0; 3915 3916 measured_sum_remote_service_demand=0.0; 3917 measured_square_sum_remote_service_demand=0.0; 3918 measured_mean_remote_service_demand=0.0; 3919 measured_var_remote_service_demand=0.0; 3920 3921 measured_sum_local_time=0.0; 3922 measured_square_sum_local_time=0.0; 3923 measured_mean_local_time=0.0; 3924 measured_var_local_time=0.0; 3925 3926 measured_mean_remote_time=0.0; 3927 3928 measured_fails = 0.0; 3929 measured_local_results=0.0, 3930 confidence=-10.0; 3931 } 3932 3933 /* this routine does a simple table lookup for some statistical */ 3934 /* function that I would remember if I stayed awake in my probstats */ 3935 /* class... raj 11/94 */ 3936 double 3937 confid(int level, int freedom) 3938 { 3939 double t99[35],t95[35]; 3940 3941 t95[1]=12.706; 3942 t95[2]= 4.303; 3943 t95[3]= 3.182; 3944 t95[4]= 2.776; 3945 t95[5]= 2.571; 3946 t95[6]= 2.447; 3947 t95[7]= 2.365; 3948 t95[8]= 2.306; 3949 t95[9]= 2.262; 3950 t95[10]= 2.228; 3951 t95[11]= 2.201; 3952 t95[12]= 2.179; 3953 t95[13]= 2.160; 3954 t95[14]= 2.145; 3955 t95[15]= 2.131; 3956 t95[16]= 2.120; 3957 t95[17]= 2.110; 3958 t95[18]= 2.101; 3959 t95[19]= 2.093; 3960 t95[20]= 2.086; 3961 t95[21]= 2.080; 3962 t95[22]= 2.074; 3963 t95[23]= 2.069; 3964 t95[24]= 2.064; 3965 t95[25]= 2.060; 3966 t95[26]= 2.056; 3967 t95[27]= 2.052; 3968 t95[28]= 2.048; 3969 t95[29]= 2.045; 3970 t95[30]= 2.042; 3971 3972 t99[1]=63.657; 3973 t99[2]= 9.925; 3974 t99[3]= 5.841; 3975 t99[4]= 4.604; 3976 t99[5]= 4.032; 3977 t99[6]= 3.707; 3978 t99[7]= 3.499; 3979 t99[8]= 3.355; 3980 t99[9]= 3.250; 3981 t99[10]= 3.169; 3982 t99[11]= 3.106; 3983 t99[12]= 3.055; 3984 t99[13]= 3.012; 3985 t99[14]= 2.977; 3986 t99[15]= 2.947; 3987 t99[16]= 2.921; 3988 t99[17]= 2.898; 3989 t99[18]= 2.878; 3990 t99[19]= 2.861; 3991 t99[20]= 2.845; 3992 t99[21]= 2.831; 3993 t99[22]= 2.819; 3994 t99[23]= 2.807; 3995 t99[24]= 2.797; 3996 t99[25]= 2.787; 3997 t99[26]= 2.779; 3998 t99[27]= 2.771; 3999 t99[28]= 2.763; 4000 t99[29]= 2.756; 4001 t99[30]= 2.750; 4002 4003 if(level==95){ 4004 return(t95[freedom]); 4005 } else if(level==99){ 4006 return(t99[freedom]); 4007 } else{ 4008 return(0); 4009 } 4010 } 4011 4012 void 4013 calculate_confidence(int confidence_iterations, 4014 float time, 4015 double result, 4016 float loc_cpu, 4017 float rem_cpu, 4018 float loc_sd, 4019 float rem_sd) 4020 { 4021 4022 if (debug) { 4023 fprintf(where, 4024 "calculate_confidence: itr %d; time %f; res %f\n", 4025 confidence_iterations, 4026 time, 4027 result); 4028 fprintf(where, 4029 " lcpu %f; rcpu %f\n", 4030 loc_cpu, 4031 rem_cpu); 4032 fprintf(where, 4033 " lsdm %f; rsdm %f\n", 4034 loc_sd, 4035 rem_sd); 4036 fflush(where); 4037 } 4038 4039 /* the test time */ 4040 measured_sum_local_time += 4041 (double) time; 4042 measured_square_sum_local_time += 4043 (double) time*time; 4044 measured_mean_local_time = 4045 (double) measured_sum_local_time/confidence_iterations; 4046 measured_var_local_time = 4047 (double) measured_square_sum_local_time/confidence_iterations 4048 -measured_mean_local_time*measured_mean_local_time; 4049 4050 /* the test result */ 4051 measured_sum_result += 4052 (double) result; 4053 measured_square_sum_result += 4054 (double) result*result; 4055 measured_mean_result = 4056 (double) measured_sum_result/confidence_iterations; 4057 measured_var_result = 4058 (double) measured_square_sum_result/confidence_iterations 4059 -measured_mean_result*measured_mean_result; 4060 4061 /* local cpu utilization */ 4062 measured_sum_local_cpu += 4063 (double) loc_cpu; 4064 measured_square_sum_local_cpu += 4065 (double) loc_cpu*loc_cpu; 4066 measured_mean_local_cpu = 4067 (double) measured_sum_local_cpu/confidence_iterations; 4068 measured_var_local_cpu = 4069 (double) measured_square_sum_local_cpu/confidence_iterations 4070 -measured_mean_local_cpu*measured_mean_local_cpu; 4071 4072 /* remote cpu util */ 4073 measured_sum_remote_cpu += 4074 (double) rem_cpu; 4075 measured_square_sum_remote_cpu+= 4076 (double) rem_cpu*rem_cpu; 4077 measured_mean_remote_cpu = 4078 (double) measured_sum_remote_cpu/confidence_iterations; 4079 measured_var_remote_cpu = 4080 (double) measured_square_sum_remote_cpu/confidence_iterations 4081 -measured_mean_remote_cpu*measured_mean_remote_cpu; 4082 4083 /* local service demand */ 4084 measured_sum_local_service_demand += 4085 (double) loc_sd; 4086 measured_square_sum_local_service_demand+= 4087 (double) loc_sd*loc_sd; 4088 measured_mean_local_service_demand = 4089 (double) measured_sum_local_service_demand/confidence_iterations; 4090 measured_var_local_service_demand = 4091 (double) measured_square_sum_local_service_demand/confidence_iterations 4092 -measured_mean_local_service_demand*measured_mean_local_service_demand; 4093 4094 /* remote service demand */ 4095 measured_sum_remote_service_demand += 4096 (double) rem_sd; 4097 measured_square_sum_remote_service_demand+= 4098 (double) rem_sd*rem_sd; 4099 measured_mean_remote_service_demand = 4100 (double) measured_sum_remote_service_demand/confidence_iterations; 4101 measured_var_remote_service_demand = 4102 (double) measured_square_sum_remote_service_demand/confidence_iterations 4103 -measured_mean_remote_service_demand*measured_mean_remote_service_demand; 4104 4105 if(confidence_iterations>1){ 4106 result_confid= (double) interval - 4107 2.0 * confid(confidence_level,confidence_iterations-1)* 4108 sqrt(measured_var_result/(confidence_iterations-1.0)) / 4109 measured_mean_result; 4110 4111 loc_cpu_confid= (double) interval - 4112 2.0 * confid(confidence_level,confidence_iterations-1)* 4113 sqrt(measured_var_local_cpu/(confidence_iterations-1.0)) / 4114 measured_mean_local_cpu; 4115 4116 rem_cpu_confid= (double) interval - 4117 2.0 * confid(confidence_level,confidence_iterations-1)* 4118 sqrt(measured_var_remote_cpu/(confidence_iterations-1.0)) / 4119 measured_mean_remote_cpu; 4120 4121 if(debug){ 4122 printf("Conf_itvl %2d: results:%4.1f%% loc_cpu:%4.1f%% rem_cpu:%4.1f%%\n", 4123 confidence_iterations, 4124 (interval-result_confid)*100.0, 4125 (interval-loc_cpu_confid)*100.0, 4126 (interval-rem_cpu_confid)*100.0); 4127 } 4128 4129 /* if the user has requested that we only wait for the result to 4130 be confident rather than the result and CPU util(s) then do 4131 so. raj 2007-08-08 */ 4132 if (!result_confidence_only) { 4133 confidence = min(min(result_confid,loc_cpu_confid),rem_cpu_confid); 4134 } 4135 else { 4136 confidence = result_confid; 4137 } 4138 } 4139 } 4140 4141 /* here ends the IBM code */ 4142 4143 void 4144 retrieve_confident_values(float *elapsed_time, 4145 double *thruput, 4146 float *local_cpu_utilization, 4147 float *remote_cpu_utilization, 4148 float *local_service_demand, 4149 float *remote_service_demand) 4150 4151 { 4152 *elapsed_time = (float)measured_mean_local_time; 4153 *thruput = measured_mean_result; 4154 *local_cpu_utilization = (float)measured_mean_local_cpu; 4155 *remote_cpu_utilization = (float)measured_mean_remote_cpu; 4156 *local_service_demand = (float)measured_mean_local_service_demand; 4157 *remote_service_demand = (float)measured_mean_remote_service_demand; 4158 } 4159 4160 /* display_confidence() is called when we could not achieve the */ 4161 /* desirec confidence in the results. it will print the achieved */ 4162 /* confidence to "where" raj 11/94 */ 4163 void 4164 display_confidence() 4165 4166 { 4167 fprintf(where, 4168 "!!! WARNING\n"); 4169 fprintf(where, 4170 "!!! Desired confidence was not achieved within "); 4171 fprintf(where, 4172 "the specified iterations.\n"); 4173 fprintf(where, 4174 "!!! This implies that there was variability in "); 4175 fprintf(where, 4176 "the test environment that\n"); 4177 fprintf(where, 4178 "!!! must be investigated before going further.\n"); 4179 fprintf(where, 4180 "!!! Confidence intervals: Throughput : %4.1f%%\n", 4181 100.0 * (interval - result_confid)); 4182 fprintf(where, 4183 "!!! Local CPU util : %4.1f%%\n", 4184 100.0 * (interval - loc_cpu_confid)); 4185 fprintf(where, 4186 "!!! Remote CPU util : %4.1f%%\n\n", 4187 100.0 * (interval - rem_cpu_confid)); 4188 } 4189 4190