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