home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / netper21.zip / netlib.c < prev    next >
C/C++ Source or Header  |  1997-03-20  |  108KB  |  3,830 lines

  1. char    netlib_id[]="\
  2. @(#)netlib.c (c) Copyright 1993, 1994 Hewlett-Packard Company. Version 2.1";
  3.  
  4. /****************************************************************/
  5. /*                                */
  6. /*    netlib.c                        */
  7. /*                                */
  8. /*    the common utility routines available to all...        */
  9. /*                                */
  10. /*    establish_control()    establish the control socket    */
  11. /*    calibrate_local_cpu()    do local cpu calibration    */
  12. /*    calibrate_remote_cpu()    do remote cpu calibration    */
  13. /*    send_request()        send a request to the remote    */
  14. /*    recv_response()        receive a response from remote    */
  15. /*    send_response()        send a response to the remote    */
  16. /*    recv_request()        recv a request from the remote    */
  17. /*    dump_request()        dump request contents        */
  18. /*    dump_response()        dump response contents        */
  19. /*    cpu_start()        start measuring cpu        */
  20. /*    cpu_stop()        stop measuring cpu        */
  21. /*    calc_cpu_util()        calculate the cpu utilization    */
  22. /*    calc_service_demand()    calculate the service demand    */
  23. /*    calc_thruput()        calulate the tput in units    */
  24. /*    calibrate()        really calibrate local cpu    */
  25. /*    identify_local()    print local host information    */
  26. /*    identify_remote()    print remote host information    */
  27. /*    format_number()        format the number (KB, MB,etc)    */
  28. /*    format_units()        return the format in english    */
  29. /*    msec_sleep()        sleep for some msecs        */
  30. /*      start_timer()           start a timer                   */
  31. /*                                */
  32. /*      the routines you get when DO_DLPI is defined...         */
  33. /*                                                              */
  34. /*      dl_open()               open a file descriptor and      */
  35. /*                              attach to the card              */
  36. /*      dl_mtu()                find the MTU of the card        */
  37. /*      dl_bind()               bind the sap do the card        */
  38. /*      dl_connect()            sender's have of connect        */
  39. /*      dl_accpet()             receiver's half of connect      */
  40. /*      dl_set_window()         set the window size             */
  41. /*      dl_stats()              retrieve statistics             */
  42. /*      dl_send_disc()          initiate disconnect (sender)    */
  43. /*      dl_recv_disc()          accept disconnect (receiver)    */
  44. /****************************************************************/
  45.  
  46. /****************************************************************/
  47. /*                                */
  48. /*    Global include files                          */
  49. /*                                       */
  50. /****************************************************************/
  51.  
  52.  /* It would seem that most of the includes being done here from */
  53.  /* "sys/" actually have higher-level wrappers at just /usr/include. */
  54.  /* This is based on a spot-check of a couple systems at my disposal. */
  55.  /* If you have trouble compiling you may want to add "sys/" raj 10/95 */
  56. #include <limits.h>
  57. #include <signal.h>
  58. #include <sys/types.h>
  59. #include <fcntl.h>
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. #include <math.h>
  63. #include <string.h>
  64.  
  65.  
  66. #ifndef WIN32
  67.  /* at some point, I would like to get rid of all these "sys/" */
  68.  /* includes where appropriate. if you have a system that requires */
  69.  /* them, speak now, or your system may not comile later revisions of */
  70.  /* netperf. raj 1/96 */
  71. #include <unistd.h>
  72. #include <sys/stat.h>
  73. #include <sys/times.h>
  74. #include <sys/time.h>
  75. #include <sys/socket.h>
  76. #include <netinet/in.h>
  77. #include <arpa/inet.h>
  78. #include <netdb.h>
  79. #include <errno.h>
  80. #include <sys/utsname.h>
  81. #include <sys/param.h>
  82.  
  83. #ifdef USE_LOOPER
  84. #include <sys/mman.h>
  85. #endif /* USE_LOOPER */
  86.  
  87. #else /* WIN32 */
  88.  
  89. #ifdef NT_SDK
  90.  /* this is an alternative for CPU util that is being worked-on, but I */
  91.  /* don't have an SDK for it. raj 1/96 */
  92. #include <nt.h>                                            /* robin */
  93. #include <ntrtl.h>                                         /* robin */
  94. #include <nturtl.h>                                        /* robin */
  95. #endif /* NT_SDK */
  96.  
  97. #include <process.h>
  98. #include <time.h>
  99. #include <windows.h>
  100. #include <winsock.h>
  101. #define SIGALRM (14)
  102. #define sleep(x) Sleep((x)*1000)
  103.  
  104. #endif /* WIN32 */
  105.  
  106. #ifdef _AIX
  107. #include <sys/select.h>
  108. #include <sys/sched.h>
  109. #include <sys/pri.h>
  110. #define PRIORITY PRI_LOW
  111. #else/* _AIX */
  112. #ifdef __sgi 
  113. #include <sys/prctl.h>
  114. #include <sys/schedctl.h>
  115. #define PRIORITY NDPLOMIN
  116. #endif /* __sgi */
  117. #endif /* _AIX */
  118.  
  119. #ifdef USE_PSTAT
  120. #include <sys/dk.h>
  121. #include <sys/pstat.h>
  122. #endif /* USE_PSTAT */
  123.  
  124.  /* not all systems seem to have the sysconf for page size. for those */
  125.  /* which do not, we will assume that the page size is 8192 bytes. */
  126.  /* this should be more than enough to be sure that there is no page */
  127.  /* or cache thrashing by looper processes on MP systems. otherwise */
  128.  /* that's really just too bad - such systems should define */
  129.  /* _SC_PAGE_SIZE - raj 4/95 */
  130. #ifndef _SC_PAGE_SIZE
  131. #define NETPERF_PAGE_SIZE 8192
  132. #else
  133. #define NETPERF_PAGE_SIZE sysconf(_SC_PAGE_SIZE)
  134. #endif /* _SC_PAGE_SIZE */
  135.  
  136. #ifdef DO_DLPI
  137. #include <sys/stream.h>
  138. #include <sys/stropts.h>
  139. #include <sys/poll.h>
  140. #ifdef __osf__
  141. #include <sys/dlpihdr.h>
  142. #else /* __osf__ */
  143. #include <sys/dlpi.h>
  144. #ifdef __hpux
  145. #include <sys/dlpi_ext.h>
  146. #endif /* __hpux */
  147. #endif /* __osf__ */
  148. #endif /* DO_DLPI */
  149.  
  150. #ifdef HISTOGRAM
  151. #include "hist.h"
  152. #endif /* HISTOGRAM */
  153. /****************************************************************/
  154. /*                                                              */
  155. /*    Local Include Files                    */
  156. /*                                                              */
  157. /****************************************************************/
  158. #define NETLIB
  159. #include "netlib.h"
  160. #include "netsh.h"
  161.  
  162.  
  163. /****************************************************************/
  164. /*                                       */
  165. /*    Global constants, macros and variables            */
  166. /*                                       */
  167. /****************************************************************/
  168.  
  169. #ifdef WIN32
  170. struct    timezone {
  171.     int     dummy ;
  172.     } ;
  173.  
  174. int     win_kludge_socket = 0;
  175. #endif /* WIN32 */
  176.  
  177. #ifndef LONG_LONG_MAX
  178. #define LONG_LONG_MAX 9223372036854775807LL
  179. #endif /* LONG_LONG_MAX */
  180.  
  181.  /* older versions of netperf knew about the HP kernel IDLE counter. */
  182.  /* this is now obsolete - in favor of either pstat(), times, or a */
  183.  /* process-level looper process. we also now require support for the */
  184.  /* "long" integer type. raj 4/95.  */
  185.  
  186. int 
  187.   lib_num_loc_cpus;    /* the number of cpus in the system */
  188.  
  189. #define PAGES_PER_CHILD 2
  190.  
  191. #ifdef USE_PSTAT
  192. long long
  193.   *lib_idle_address[MAXCPUS], /* addresses of the per-cpu idle counters    */
  194.   lib_start_count[MAXCPUS],  /* idle counter initial value per-cpu      */
  195.   lib_end_count[MAXCPUS];    /* idle counter final value per-cpu    */
  196.  
  197. long long
  198.   *lib_base_pointer;
  199.  
  200. #else 
  201. #ifdef USE_LOOPER
  202.  
  203. long
  204.   *lib_idle_address[MAXCPUS], /* addresses of the per-cpu idle counters    */
  205.   lib_start_count[MAXCPUS],  /* idle counter initial value per-cpu      */
  206.   lib_end_count[MAXCPUS];    /* idle counter final value per-cpu    */
  207.  
  208. long
  209.   *lib_base_pointer;
  210.  
  211. #ifdef WIN32
  212. HANDLE
  213.   lib_idle_pids[MAXCPUS];    /* the pids (ok, handles) of the per-cpu */
  214.                  /* idle loopers */ 
  215. #else
  216. int
  217.   lib_idle_pids[MAXCPUS];    /* the pids of the per-cpu idle loopers */
  218. #endif /* WIN32 */
  219.  
  220. int
  221.   lib_idle_fd;
  222.   
  223. #endif /* USE_LOOPER */
  224. #endif /* USE_PSTAT */  
  225.  
  226. int    lib_use_idle;
  227. int     cpu_method;
  228.  
  229.  /* if there is no IDLE counter in the kernel */
  230. #ifdef USE_PSTAT
  231. struct    pst_dynamic    pst_dynamic_info;
  232. long            cp_time1[PST_MAX_CPUSTATES];
  233. long                    cp_time2[PST_MAX_CPUSTATES];
  234. #else
  235. #ifdef WIN32
  236. #ifdef NT_SDK
  237. LARGE_INTEGER       systime_start;                         /* robin */
  238. LARGE_INTEGER       systime_end;                           /* robin */ 
  239. KERNEL_USER_TIMES   perf_start;                            /* robin */
  240. KERNEL_USER_TIMES   perf_end;                              /* robin */
  241. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION sysperf_start;    /* robin */
  242. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION sysperf_end;      /* robin */
  243. #endif /* NT_SDK */
  244. #else
  245. struct    tms        times_data1, 
  246.                         times_data2;
  247. #endif /* WIN32 */
  248. #endif
  249.  
  250. struct    timeval        time1, time2;
  251. struct    timezone    tz;
  252. float    lib_elapsed,
  253.     lib_local_maxrate,
  254.     lib_remote_maxrate,
  255.     lib_local_cpu_util,
  256.     lib_remote_cpu_util;
  257.  
  258. int    *request_array;
  259. int    *response_array;
  260.  
  261. int    netlib_control;
  262.  
  263. int    server_sock;
  264.  
  265. int    tcp_proto_num;
  266.  
  267.  /* in the past, I was overlaying a structure on an array of ints. now */
  268.  /* I am going to have a "real" structure, and point an array of ints */
  269.  /* at it. the real structure will be forced to the same alignment as */
  270.  /* the type "double." this change will mean that pre-2.1 netperfs */
  271.  /* cannot be mixed with 2.1 and later. raj 11/95 */
  272.  
  273. union    netperf_request_struct    netperf_request;
  274. union    netperf_response_struct    netperf_response;
  275.  
  276. FILE    *where;
  277.  
  278. char    libfmt = 'm';
  279.     
  280. #ifdef DO_DLPI
  281. /* some stuff for DLPI control messages */
  282. #define DLPI_DATA_SIZE 2048
  283.  
  284. unsigned long control_data[DLPI_DATA_SIZE];
  285. struct strbuf control_message = {DLPI_DATA_SIZE, 0, (char *)control_data};
  286.  
  287. #endif /* DO_DLPI */
  288.  
  289. int    times_up;
  290.  
  291. #ifdef WIN32
  292.  /* we use a getopt implementation from net.sources */
  293. /*
  294.  * get option letter from argument vector
  295.  */
  296. int
  297.     opterr = 1,        /* should error messages be printed? */
  298.     optind = 1,        /* index into parent argv vector */
  299.     optopt;            /* character checked for validity */
  300. char
  301.     *optarg;        /* argument associated with option */
  302.  
  303. #define EMSG    ""
  304.  
  305. char *progname;            /* may also be defined elsewhere */
  306.  
  307. #endif /* WIN32 */
  308.  
  309. static int measuring_cpu;
  310.  
  311. #ifdef INTERVALS
  312. static unsigned int usec_per_itvl;
  313.  
  314. void
  315. stop_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("clusterperf: cluster_root: setitimer");
  329.     exit(1);
  330.   }
  331.   return;
  332. }
  333. #endif /* INTERVALS */
  334.  
  335.  
  336.  
  337. #ifdef WIN32
  338. static void
  339. error(char *pch)
  340. {
  341.   if (!opterr) {
  342.     return;        /* without printing */
  343.     }
  344.   fprintf(stderr, "%s: %s: %c\n",
  345.       (NULL != progname) ? progname : "getopt", pch, optopt);
  346. }
  347.  
  348. int
  349. getopt(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.  
  402.  
  403. double
  404. ntohd(net_double)
  405.      double net_double;
  406.  
  407. {
  408.   /* we rely on things being nicely packed */
  409.   union {
  410.     double whole_thing;
  411.     unsigned int words[2];
  412.     unsigned char bytes[8];
  413.   } conv_rec;
  414.  
  415.   unsigned char scratch;
  416.   int i;
  417.  
  418.   /* on those systems where ntohl is a no-op, we want to return the */
  419.   /* original value, unchanged */
  420.  
  421.   if (ntohl(1L) == 1L) {
  422.     return(net_double);
  423.   }
  424.  
  425.   conv_rec.whole_thing = net_double;
  426.  
  427.   /* we know that in the message passing routines that ntohl will have */
  428.   /* been called on the 32 bit quantities. we need to put those back */
  429.   /* the way they belong before we swap */
  430.   conv_rec.words[0] = htonl(conv_rec.words[0]);
  431.   conv_rec.words[1] = htonl(conv_rec.words[1]);
  432.   
  433.   /* now swap */
  434.   for (i=0; i<= 3; i++) {
  435.     scratch = conv_rec.bytes[i];
  436.     conv_rec.bytes[i] = conv_rec.bytes[7-i];
  437.     conv_rec.bytes[7-i] = scratch;
  438.   }
  439.   
  440.   return(conv_rec.whole_thing);
  441.   
  442. }
  443. double
  444. htond(host_double)
  445.      double host_double;
  446.  
  447. {
  448.   /* we rely on things being nicely packed */
  449.   union {
  450.     double whole_thing;
  451.     unsigned int words[2];
  452.     unsigned char bytes[8];
  453.   } conv_rec;
  454.  
  455.   unsigned char scratch;
  456.   int i;
  457.  
  458.   /* on those systems where ntohl is a no-op, we want to return the */
  459.   /* original value, unchanged */
  460.  
  461.   if (ntohl(1L) == 1L) {
  462.     return(host_double);
  463.   }
  464.  
  465.   conv_rec.whole_thing = host_double;
  466.  
  467.   /* now swap */
  468.   for (i=0; i<= 3; i++) {
  469.     scratch = conv_rec.bytes[i];
  470.     conv_rec.bytes[i] = conv_rec.bytes[7-i];
  471.     conv_rec.bytes[7-i] = scratch;
  472.   }
  473.   
  474.   /* we know that in the message passing routines htonl will */
  475.   /* be called on the 32 bit quantities. we need to set things up so */
  476.   /* that when this happens, the proper order will go out on the */
  477.   /* network */
  478.   conv_rec.words[0] = htonl(conv_rec.words[0]);
  479.   conv_rec.words[1] = htonl(conv_rec.words[1]);
  480.   
  481.   return(conv_rec.whole_thing);
  482.   
  483. }
  484.  
  485.  
  486. int
  487. get_num_cpus()
  488.  
  489. {
  490.  
  491.   /* on HP-UX, even when we use the looper procs we need the pstat */
  492.   /* call */ 
  493.  
  494.   int temp_cpus;
  495.  
  496. #ifdef __hpux
  497. #include <sys/pstat.h>
  498.  
  499.   struct pst_dynamic psd;
  500.  
  501.   if (pstat_getdynamic((struct pst_dynamic *)&psd, 
  502.                (size_t)sizeof(psd), (size_t)1, 0) != -1) {
  503.     temp_cpus = psd.psd_proc_cnt;
  504.   }
  505.   else {
  506.     temp_cpus = 1;
  507.   }
  508.  
  509. #else
  510.  
  511.   /* we need to know some other ways to do this, or just fall-back on */
  512.   /* a global command line option - raj 4/95 */
  513.   temp_cpus = shell_num_cpus;
  514.  
  515. #endif /*  __hpux */
  516.  
  517.   if (temp_cpus > MAXCPUS) {
  518.     fprintf(where,
  519.         "Sorry, this system has more CPUs (%d) than I can handle (%d).\n",
  520.         temp_cpus,
  521.         MAXCPUS);
  522.     fprintf(where,
  523.         "Please alter MAXCPUS in netlib.h and recompile.\n");
  524.     fflush(where);
  525.     exit(1);
  526.   }
  527.  
  528.   return(temp_cpus);
  529.   
  530. }  
  531.  
  532. #ifdef WIN32
  533. void
  534. gettimeofday( struct timeval *tv , struct timezone *not_used )
  535. {
  536.     SYSTEMTIME    sys_time ;
  537.     GetSystemTime( &sys_time ) ;
  538.  
  539.     tv->tv_sec = (long)time(NULL) ;
  540.     tv->tv_usec = sys_time.wMilliseconds ;
  541. }
  542. #endif /* WIN32 */
  543.  
  544.      
  545.  
  546. /************************************************************************/
  547. /*                                    */
  548. /*    signal catcher                                            */
  549. /*                                    */
  550. /************************************************************************/
  551.  
  552. void
  553. #ifdef __hpux
  554. catcher(sig, code, scp)
  555.      int sig;
  556.      int code;
  557.      struct sigcontext *scp;
  558. #else /* __hpux */
  559. catcher(sig)
  560.      int sig;
  561. #endif /* __hpux */
  562. {
  563.  
  564. #ifdef __hpux
  565.   if (debug > 2) {
  566.     fprintf(where,"caught signal %d ",sig);
  567.     if (scp) {
  568.       fprintf(where,"while in syscall %d\n",
  569.           scp->sc_syscall);
  570.     }
  571.     else {
  572.       fprintf(where,"null scp\n");
  573.     }
  574.     fflush(where);
  575.   }
  576. #endif /* RAJ_DEBUG */
  577.  
  578.   switch(sig) {
  579.     
  580.   case SIGINT:
  581.     fprintf(where,"netperf: caught SIGINT\n");
  582.     fflush(where);
  583.     exit(1);
  584.     break;
  585.   case SIGALRM: 
  586.    if (--test_len_ticks == 0) {
  587.       /* the test is over */
  588.       if (times_up != 0) {
  589.     fprintf(where,"catcher: timer popped with times_up != 0\n");
  590.     fflush(where);
  591.       }
  592.       times_up = 1;
  593. #ifdef INTERVALS
  594.       stop_itimer();
  595. #endif /* INTERVALS */
  596.       break;
  597.     }
  598.     else {
  599. #ifdef INTERVALS
  600. #ifdef __hpux
  601.       /* the test is not over yet and we must have been using the */
  602.       /* interval timer. if we were in SYS_SIGSUSPEND we want to */
  603.       /* re-start the system call. Otherwise, we want to get out of */
  604.       /* the sigsuspend call. I NEED TO KNOW HOW TO DO THIS FOR OTHER */
  605.       /* OPERATING SYSTEMS. If you know how, please let me know. rick */
  606.       /* jones <raj@cup.hp.com> */
  607.       if (scp->sc_syscall != SYS_SIGSUSPEND) {
  608.     if (debug > 2) {
  609.       fprintf(where,
  610.           "catcher: Time to send burst > interval!\n");
  611.       fflush(where);
  612.     }
  613.     scp->sc_syscall_action = SIG_RESTART;
  614.       }
  615. #endif /* __hpux */
  616.       if (demo_mode) {
  617.     /* spit-out what the performance was in units/s. based on our */
  618.     /* knowledge of the interval length we do not need to call */
  619.     /* gettimeofday() raj 2/95 */
  620.     fprintf(where,"%g\n",(units_this_tick * 
  621.                   (double) 1000000 / 
  622.                   (double) usec_per_itvl));
  623.     fflush(where);
  624.     units_this_tick = (double) 0.0;
  625.       }
  626. #else /* INTERVALS */
  627.       fprintf(where,
  628.           "catcher: interval timer running unexpectedly!\n");
  629.       fflush(where);
  630.       times_up = 1;
  631. #endif /* INTERVALS */      
  632.       break;
  633.     }
  634.   }
  635.   return;
  636. }
  637.  
  638.  
  639. void
  640. install_signal_catchers()
  641.  
  642. {
  643.   /* just a simple little routine to catch a bunch of signals */
  644.  
  645. #ifndef WIN32
  646.   struct sigaction action;
  647.   int i;
  648.  
  649.   fprintf(where,"installing catcher for all signals\n");
  650.   fflush(where);
  651.  
  652.   sigemptyset(&(action.sa_mask));
  653.   action.sa_handler = catcher;
  654.  
  655. #ifdef SA_INTERRUPT
  656.   action.sa_flags = SA_INTERRUPT;
  657. #else /* SA_INTERRUPT */
  658.   action.sa_flags = 0;
  659. #endif /* SA_INTERRUPT */
  660.  
  661.  
  662.   for (i = 1; i <= NSIG; i++) {
  663.     if (i != SIGALRM) {
  664.       if (sigaction(SIGALRM,&action,NULL) != 0) {
  665.     fprintf(where,
  666.         "Could not install signal catcher for sig %d, errno %d\n",
  667.         i,
  668.         errno);
  669.     fflush(where);
  670.  
  671.       }
  672.     }
  673.   }
  674. #else
  675.   return;
  676. #endif /* WIN32 */ 
  677. }
  678.  
  679.  
  680. #ifdef WIN32
  681. #define SIGALRM    (14)
  682. void
  683. emulate_alarm( int seconds )
  684. {
  685.  
  686.     Sleep( seconds * 1000 ) ;
  687.  
  688.     times_up = 1;
  689.  
  690.     /* We have yet to find a good way to fully emulate the effects */
  691.     /* of signals and getting EINTR from system calls under */
  692.     /* winsock, so what we do here is close the socket out from */
  693.     /* under the other thread. it is rather kludgy, but should be */
  694.     /* sufficient to get this puppy shipped. the concept can be */
  695.     /* attributed/blamed :) on Robin raj 1/96 */
  696.  
  697.     if (win_kludge_socket != 0) {
  698.       closesocket(win_kludge_socket);
  699.     }
  700. }
  701.  
  702. #endif /* WIN32 */
  703.  
  704. void
  705. start_timer(time)
  706.      int time;
  707. {
  708.  
  709. #ifdef WIN32
  710. struct    sigaction {
  711.     int dummy ;
  712.     } ;
  713. void    emulate_alarm(int) ;
  714.  
  715. long    thread_id ;
  716.  
  717. CreateThread(0,
  718.          0,
  719.          (LPTHREAD_START_ROUTINE)emulate_alarm,
  720.          (LPVOID)time,
  721.          0,
  722.          &thread_id ) ;
  723.  
  724. #else /* not WIN32 */
  725.  
  726. struct sigaction action;
  727.  
  728. if (debug) {
  729.   fprintf(where,"About to start a timer for %d seconds.\n",time);
  730.   fflush(where);
  731. }
  732.  
  733.   action.sa_handler = catcher;
  734.   sigemptyset(&(action.sa_mask));
  735.   sigaddset(&(action.sa_mask),SIGALRM);
  736.  
  737. #ifdef SA_INTERRUPT
  738.   /* on some systems (SunOS 4.blah), system calls are restarted. we do */
  739.   /* not want that */
  740.   action.sa_flags = SA_INTERRUPT;
  741. #else /* SA_INTERRUPT */
  742.   action.sa_flags = 0;
  743. #endif /* SA_INTERRUPT */
  744.  
  745.   if (sigaction(SIGALRM, &action, NULL) < 0) {
  746.     fprintf(where,"start_timer: error installing alarm handler ");
  747.     fprintf(where,"errno %d\n",errno);
  748.     fflush(where);
  749.     exit(1);
  750.   }
  751.  
  752.   /* this is the easy case - just set the timer for so many seconds */ 
  753.   if (alarm(time) != 0) {
  754.     fprintf(where,
  755.         "error starting alarm timer, errno %d\n",
  756.         errno);
  757.     fflush(where);
  758.   }
  759. #endif /* WIN32 */
  760.  
  761.   test_len_ticks = 1;
  762.  
  763.  
  764.  
  765.  /* this routine will disable any running timer */
  766. void
  767. stop_timer()
  768. {
  769. #ifndef WIN32
  770.   alarm(0);
  771. #else
  772.   /* at some point we may need some win32 equivalent */
  773. #endif /* WIN32 */
  774.  
  775. }
  776.  
  777.  
  778. #ifdef INTERVALS
  779.  /* this routine will enable the interval timer and set things up so */
  780.  /* that for a timed test the test will end at the proper time. it */
  781.  /* should detect the presence of POSIX.4 timer_* routines one of */
  782.  /* these days */
  783. void
  784. start_itimer( interval_len_msec )
  785.      unsigned int interval_len_msec;
  786. {
  787.  
  788.   unsigned int ticks_per_itvl;
  789.  
  790.   struct itimerval new_interval;
  791.   struct itimerval old_interval;
  792.  
  793.   /* if -DINTERVALS was used, we will use the ticking of the itimer to */
  794.   /* tell us when the test is over. while the user will be specifying */
  795.   /* some number of milliseconds, we know that the interval timer is */
  796.   /* really in units of 1/HZ. so, to prevent the test from running */
  797.   /* "long" it would be necessary to keep this in mind when calculating */
  798.   /* the number of itimer events */
  799.  
  800.   ticks_per_itvl = ((interval_wate * sysconf(_SC_CLK_TCK) * 1000) / 
  801.             1000000);
  802.  
  803.   if (ticks_per_itvl == 0) ticks_per_itvl = 1;
  804.  
  805.   /* how many usecs in each interval? */
  806.   usec_per_itvl = ticks_per_itvl * (1000000 / sysconf(_SC_CLK_TCK));
  807.  
  808.   /* how many times will the timer pop before the test is over? */
  809.   if (test_time > 0) {
  810.     /* this was a timed test */
  811.     test_len_ticks = (test_time * 1000000) / usec_per_itvl;
  812.   }
  813.   else {
  814.     /* this was not a timed test, use MAXINT */
  815.     test_len_ticks = INT_MAX;
  816.   }
  817.  
  818.   if (debug) {
  819.     fprintf(where,"setting the interval timer to %d sec %d usec ",
  820.         usec_per_itvl / 1000000,
  821.         usec_per_itvl % 1000000);
  822.     fprintf(where,"test len %d ticks\n",
  823.         test_len_ticks);
  824.     fflush(where);
  825.   }
  826.  
  827.   /* if this was not a timed test, then we really aught to enable the */
  828.   /* signal catcher raj 2/95 */
  829.  
  830.   new_interval.it_interval.tv_sec = usec_per_itvl / 1000000;
  831.   new_interval.it_interval.tv_usec = usec_per_itvl % 1000000;  
  832.   new_interval.it_value.tv_sec = usec_per_itvl / 1000000;
  833.   new_interval.it_value.tv_usec = usec_per_itvl % 1000000;  
  834.   if (setitimer(ITIMER_REAL,&new_interval,&old_interval) != 0) {
  835.     /* there was a problem arming the interval timer */ 
  836.     perror("clusterperf: cluster_root: setitimer");
  837.     exit(1);
  838.   }
  839. }
  840. #endif /* INTERVALS */
  841.  
  842. /****************************************************************/
  843. /*                                */
  844. /*    netlib_init()                        */
  845. /*                                */
  846. /*    initialize the performance library...            */
  847. /*                                */
  848. /****************************************************************/
  849.  
  850. void
  851. netlib_init()
  852. {
  853.   where           = stdout;
  854.  
  855.   request_array = (int *)(&netperf_request);
  856.   response_array = (int *)(&netperf_response);
  857.  
  858.   if (debug) {
  859.     fprintf(where,
  860.         "netlib_init: request_array at 0x%x\n",
  861.         request_array);
  862.     fprintf(where,
  863.         "netlib_init: response_array at 0x%x\n",
  864.         response_array);
  865.  
  866.     fflush(where);
  867.   }
  868.  
  869. }
  870.  
  871.  /* this routine will conver the string into an unsigned integer. it */
  872.  /* is used primarily for the command-line options taking a number */
  873.  /* (such as the socket size) which could be rather large. If someone */
  874.  /* enters 32M, then the number will be converted to 32 * 1024 * 1024. */
  875.  /* If they inter 32m, the number will be converted to 32 * 1000 * */
  876.  /* 1000 */
  877. unsigned int
  878. convert(string)
  879.      char *string;
  880.  
  881. {
  882.   unsigned int base;
  883.   base = atoi(string);
  884.   if (strstr(string,"K")) {
  885.     base *= 1024;
  886.   }
  887.   if (strstr(string,"M")) {
  888.     base *= (1024 * 1024);
  889.   }
  890.   if (strstr(string,"G")) {
  891.     base *= (1024 * 1024 * 1024);
  892.   }
  893.   if (strstr(string,"k")) {
  894.     base *= (1000);
  895.   }
  896.   if (strstr(string,"m")) {
  897.     base *= (1000 * 1000);
  898.   }
  899.   if (strstr(string,"g")) {
  900.     base *= (1000 * 1000 * 1000);
  901.   }
  902.   return(base);
  903. }
  904.  
  905.  
  906.  /* this routine will allocate a circular list of buffers for either */
  907.  /* send or receive operations. each of these buffers will be aligned */
  908.  /* and offset as per the users request. the circumference of this */
  909.  /* ring will be controlled by the setting of send_width. the buffers */
  910.  /* will be filled with data from the file specified in fill_file. if */
  911.  /* fill_file is an empty string, the buffers will not be filled with */
  912.  /* any particular data */
  913.  
  914. struct ring_elt *
  915. allocate_buffer_ring(width, buffer_size, alignment, offset)
  916.      int width;
  917.      int buffer_size;
  918.      int alignment;
  919.      int offset;
  920. {
  921.  
  922.   struct ring_elt *first_link = NULL;
  923.   struct ring_elt *temp_link  = NULL;
  924.   struct ring_elt *prev_link;
  925.  
  926.   int i;
  927.   int malloc_size;
  928.   int bytes_left;
  929.   int bytes_read;
  930.   int do_fill;
  931.  
  932.   FILE *fill_source;
  933.  
  934.   malloc_size = buffer_size + alignment + offset;
  935.  
  936.   /* did the user wish to have the buffers pre-filled with data from a */
  937.   /* particular source? */
  938.   if (strcmp(fill_file,"") == 0) {
  939.     do_fill = 0;
  940.     fill_source = NULL;
  941.   }
  942.   else {
  943.     do_fill = 1;
  944.     fill_source = (FILE *)fopen(fill_file,"r");
  945.     if (fill_source == (FILE *)NULL) {
  946.       perror("Could not open requested fill file");
  947.       exit(1);
  948.     }
  949.   }
  950.  
  951.   prev_link = NULL;
  952.   for (i = 1; i <= width; i++) {
  953.     /* get the ring element */
  954.     temp_link = (struct ring_elt *)malloc(sizeof(struct ring_elt));
  955.     /* remember the first one so we can close the ring at the end */
  956.     if (i == 1) {
  957.       first_link = temp_link;
  958.     }
  959.     temp_link->buffer_base = (char *)malloc(malloc_size);
  960.     temp_link->buffer_ptr = (char *)(( (long)(temp_link->buffer_base) + 
  961.               (long)alignment - 1) &    
  962.              ~((long)alignment - 1));
  963.     temp_link->buffer_ptr += offset;
  964.     /* is where the buffer fill code goes. */
  965.     if (do_fill) {
  966.       bytes_left = buffer_size;
  967.       while (bytes_left) {
  968.     if (((bytes_read = fread(temp_link->buffer_ptr,
  969.                  1,
  970.                  bytes_left,
  971.                  fill_source)) == 0) &&
  972.         (feof(fill_source))){
  973.       rewind(fill_source);
  974.     }
  975.     bytes_left -= bytes_read;
  976.       }
  977.     }
  978.     temp_link->next = prev_link;
  979.     prev_link = temp_link;
  980.   }
  981.   first_link->next = temp_link;
  982.  
  983.   return(first_link); /* it's a circle, doesn't matter which we return */
  984. }
  985.  
  986.  /***********************************************************************/
  987.  /*                                    */
  988.  /*    dump_request()                            */
  989.  /*                                    */
  990.  /* display the contents of the request array to the user. it will    */
  991.  /* display the contents in decimal, hex, and ascii, with four bytes    */
  992.  /* per line.                                */
  993.  /*                                    */
  994.  /***********************************************************************/
  995.  
  996. void
  997. dump_request()
  998. {
  999. int counter = 0;
  1000. fprintf(where,"request contents:\n");
  1001. for (counter = 0; counter < ((sizeof(netperf_request)/4)-3); counter += 4) {
  1002.   fprintf(where,"%d:\t%8x %8x %8x %8x \t|%4.4s| |%4.4s| |%4.4s| |%4.4s|\n",
  1003.       counter,
  1004.       request_array[counter],
  1005.       request_array[counter+1],
  1006.       request_array[counter+2],
  1007.       request_array[counter+3],
  1008.       (char *)&request_array[counter],
  1009.       (char *)&request_array[counter+1],
  1010.       (char *)&request_array[counter+2],
  1011.       (char *)&request_array[counter+3]);
  1012. }
  1013. fflush(where);
  1014. }
  1015.  
  1016.  
  1017.  /***********************************************************************/
  1018.  /*                                    */
  1019.  /*    dump_response()                            */
  1020.  /*                                    */
  1021.  /* display the content of the response array to the user. it will    */
  1022.  /* display the contents in decimal, hex, and ascii, with four bytes    */
  1023.  /* per line.                                */
  1024.  /*                                    */
  1025.  /***********************************************************************/
  1026.  
  1027. void
  1028. dump_response()
  1029. {
  1030. int counter = 0;
  1031.  
  1032. fprintf(where,"response contents\n");
  1033. for (counter = 0; counter < ((sizeof(netperf_response)/4)-3); counter += 4) {
  1034.   fprintf(where,"%d:\t%8x %8x %8x %8x \t>%4.4s< >%4.4s< >%4.4s< >%4.4s<\n",
  1035.       counter,
  1036.       response_array[counter],
  1037.       response_array[counter+1],
  1038.       response_array[counter+2],
  1039.       response_array[counter+3],
  1040.       (char *)&response_array[counter],
  1041.       (char *)&response_array[counter+1],
  1042.       (char *)&response_array[counter+2],
  1043.       (char *)&response_array[counter+3]);
  1044. }
  1045. fflush(where);
  1046. }
  1047.  
  1048.  /***********************************************************************/
  1049.  /*                                    */
  1050.  /*    format_number()                            */
  1051.  /*                                    */
  1052.  /* return a pointer to a formatted string containing the value passed  */
  1053.  /* translated into the units specified. It assumes that the base units */
  1054.  /* are bytes. If the format calls for bits, it will use SI units (10^) */
  1055.  /* if the format calls for bytes, it will use CS units (2^)...        */
  1056.  /* This routine should look familiar to uses of the latest ttcp...    */
  1057.  /*                                    */
  1058.  /***********************************************************************/
  1059.  
  1060. char *
  1061. format_number(number)
  1062. double    number;
  1063. {
  1064.     static    char    fmtbuf[64];
  1065.     
  1066.     switch (libfmt) {
  1067.     case 'K':
  1068.         sprintf(fmtbuf, "%-7.2f" , number / 1024.0);
  1069.         break;
  1070.     case 'M':
  1071.         sprintf(fmtbuf, "%-7.2f", number / 1024.0 / 1024.0);
  1072.         break;
  1073.     case 'G':
  1074.         sprintf(fmtbuf, "%-7.2f", number / 1024.0 / 1024.0 / 1024.0);
  1075.         break;
  1076.     case 'k':
  1077.         sprintf(fmtbuf, "%-7.2f", number * 8 / 1000.0);
  1078.         break;
  1079.     case 'm':
  1080.         sprintf(fmtbuf, "%-7.2f", number * 8 / 1000.0 / 1000.0);
  1081.         break;
  1082.     case 'g':
  1083.         sprintf(fmtbuf, "%-7.2f", number * 8 / 1000.0 / 1000.0 / 1000.0);
  1084.         break;
  1085.  
  1086.         default:
  1087.         sprintf(fmtbuf, "%-7.2f", number / 1024.0);
  1088.     }
  1089.  
  1090.     return fmtbuf;
  1091. }
  1092.  
  1093. char
  1094. format_cpu_method(method)
  1095.      int method;
  1096. {
  1097.  
  1098.   char method_char;
  1099.  
  1100.   switch (method) {
  1101.   case CPU_UNKNOWN:
  1102.     method_char = 'U';
  1103.     break;
  1104.   case HP_IDLE_COUNTER:
  1105.     method_char = 'I';
  1106.     break;
  1107.   case PSTAT:
  1108.     method_char = 'P';
  1109.     break;
  1110.   case TIMES:
  1111.     method_char = 'T';
  1112.     break;
  1113.   case GETRUSAGE:
  1114.     method_char = 'R';
  1115.     break;
  1116.   case LOOPER:
  1117.     method_char = 'L';
  1118.     break;
  1119.   case NT_METHOD:
  1120.     method_char = 'N';
  1121.     break;
  1122.   default:
  1123.     method_char = '?';
  1124.   }
  1125.   
  1126.   return method_char;
  1127.  
  1128. }
  1129.  
  1130. char *
  1131. format_units()
  1132. {
  1133.   static    char    unitbuf[64];
  1134.   
  1135.   switch (libfmt) {
  1136.   case 'K':
  1137.     sprintf(unitbuf, "%s", "KBytes");
  1138.     break;
  1139.   case 'M':
  1140.     sprintf(unitbuf, "%s", "MBytes");
  1141.     break;
  1142.   case 'G':
  1143.     sprintf(unitbuf, "%s", "GBytes");
  1144.     break;
  1145.   case 'k':
  1146.     sprintf(unitbuf, "%s", "10^3bits");
  1147.     break;
  1148.   case 'm':
  1149.     sprintf(unitbuf, "%s", "10^6bits");
  1150.     break;
  1151.   case 'g':
  1152.     sprintf(unitbuf, "%s", "10^9bits");
  1153.     break;
  1154.     
  1155.   default:
  1156.     sprintf(unitbuf, "%s", "KBytes");
  1157.   }
  1158.   
  1159.   return unitbuf;
  1160. }
  1161.  
  1162.  
  1163. /****************************************************************/
  1164. /*                                */
  1165. /*    shutdown_control()                    */
  1166. /*                                */
  1167. /* tear-down the control connection between me and the server.  */
  1168. /****************************************************************/
  1169.  
  1170. void 
  1171. shutdown_control()
  1172. {
  1173.  
  1174.   char     *buf = (char *)&netperf_response;
  1175.   int     buflen = sizeof(netperf_response);
  1176.  
  1177.   /* stuff for select, use fd_set for better compliance */
  1178.   fd_set    readfds;
  1179.   struct    timeval    timeout;
  1180.  
  1181.   if (debug) {
  1182.     fprintf(where,
  1183.         "shutdown_control: shutdown of control connection requested.\n");
  1184.     fflush(where);
  1185.   }
  1186.  
  1187.   /* first, we say that we will be sending no more data on the */
  1188.   /* connection */
  1189.   if (shutdown(netlib_control,1) == -1) {
  1190.     fprintf(where,
  1191.         "shutdown_control: error in shutdown. errno %d\n",
  1192.         errno);
  1193.     fflush(where);
  1194.     exit(1);
  1195.   }
  1196.  
  1197.   /* Now, we hang on a select waiting for the socket to become */
  1198.   /* readable to receive the shutdown indication from the remote. this */
  1199.   /* will be "just" like the recv_response() code */
  1200.  
  1201.   /* we only select once. it is assumed that if the response is split */
  1202.   /* (which should not be happening, that we will receive the whole */
  1203.   /* thing and not have a problem ;-) */
  1204.  
  1205.   FD_ZERO(&readfds);
  1206.   FD_SET(netlib_control,&readfds);
  1207.   timeout.tv_sec  = 60; /* wait two minutes then punt */
  1208.   timeout.tv_usec = 0;
  1209.  
  1210.   /* select had better return one, or there was either a problem or a */
  1211.   /* timeout... */
  1212.   if (select(FD_SETSIZE,
  1213.          &readfds,
  1214.          0,
  1215.          0,
  1216.          &timeout) != 1) {
  1217.     fprintf(where,
  1218.         "shutdown_control: no response received. errno %d\n",
  1219.         errno);
  1220.     fflush(where);
  1221.     exit(1);
  1222.   }
  1223.  
  1224.   /* we now assume that the socket has come ready for reading */
  1225.   recv(netlib_control, buf, buflen,0);
  1226.  
  1227. }
  1228.  
  1229.  
  1230.  /***********************************************************************/
  1231.  /*                                    */
  1232.  /*    send_request()                            */
  1233.  /*                                    */
  1234.  /* send a netperf request on the control socket to the remote half of     */
  1235.  /* the connection. to get us closer to intervendor interoperability,     */
  1236.  /* we will call htonl on each of the int that compose the message to     */
  1237.  /* be sent. the server-half of the connection will call the ntohl     */
  1238.  /* routine to undo any changes that may have been made...         */
  1239.  /*                                     */
  1240.  /***********************************************************************/
  1241.  
  1242. void
  1243. send_request()
  1244. {
  1245.   int    counter=0;
  1246.   
  1247.   /* display the contents of the request if the debug level is high */
  1248.   /* enough. otherwise, just send the darned thing ;-) */
  1249.   
  1250.   if (debug > 1) {
  1251.     fprintf(where,"entered send_request...contents before htonl:\n");
  1252.     dump_request();
  1253.   }
  1254.   
  1255.   /* put the entire request array into network order. We do this */
  1256.   /* arbitrarily rather than trying to figure-out just how much */
  1257.   /* of the request array contains real information. this should */
  1258.   /* be simpler, and at any rate, the performance of sending */
  1259.   /* control messages for this benchmark is not of any real */
  1260.   /* concern. */ 
  1261.   
  1262.   for (counter=0;counter < sizeof(netperf_request)/4; counter++) {
  1263.     request_array[counter] = htonl(request_array[counter]);
  1264.   }
  1265.   
  1266.   if (debug > 1) {
  1267.     fprintf(where,"send_request...contents after htonl:\n");
  1268.     dump_request();
  1269.  
  1270.     fprintf(where,
  1271.         "\nsend_request: about to send %d bytes from %x\n",
  1272.         sizeof(netperf_request),
  1273.         &netperf_request);
  1274.     fflush(where);
  1275.   }
  1276.  
  1277.   if (send(netlib_control,
  1278.        (char *)&netperf_request,
  1279.        sizeof(netperf_request),
  1280.        0) != sizeof(netperf_request)) {
  1281.     perror("send_request: send call failure");
  1282.     
  1283.     exit(1);
  1284.   }
  1285. }
  1286.  
  1287. /***********************************************************************/
  1288.  /*                                    */
  1289.  /*    send_response()                            */
  1290.  /*                                    */
  1291.  /* send a netperf response on the control socket to the remote half of */
  1292.  /* the connection. to get us closer to intervendor interoperability,     */
  1293.  /* we will call htonl on each of the int that compose the message to     */
  1294.  /* be sent. the other half of the connection will call the ntohl     */
  1295.  /* routine to undo any changes that may have been made...         */
  1296.  /*                                     */
  1297.  /***********************************************************************/
  1298.  
  1299. void
  1300. send_response()
  1301. {
  1302.   int    counter=0;
  1303.  
  1304.   /* display the contents of the request if the debug level is high */
  1305.   /* enough. otherwise, just send the darned thing ;-) */
  1306.  
  1307.   if (debug > 1) {
  1308.     fprintf(where,
  1309.         "send_response: contents of %d ints before htonl\n",
  1310.         sizeof(netperf_response)/4);
  1311.     dump_response();
  1312.   }
  1313.  
  1314.   /* put the entire response_array into network order. We do this */
  1315.   /* arbitrarily rather than trying to figure-out just how much of the */
  1316.   /* request array contains real information. this should be simpler, */
  1317.   /* and at any rate, the performance of sending control messages for */
  1318.   /* this benchmark is not of any real concern. */
  1319.   
  1320.   for (counter=0;counter < sizeof(netperf_response)/4; counter++) {
  1321.     response_array[counter] = htonl(response_array[counter]);
  1322.   }
  1323.   
  1324.   if (debug > 1) {
  1325.     fprintf(where,
  1326.         "send_response: contents after htonl\n");
  1327.     dump_response();
  1328.     fprintf(where,
  1329.         "about to send %d bytes from %x\n",
  1330.         sizeof(netperf_response),
  1331.         &netperf_response);
  1332.     fflush(where);
  1333.   }
  1334.  
  1335.   /*KC*/
  1336.   if (send(server_sock,
  1337.        (char *)&netperf_response,
  1338.        sizeof(netperf_response),
  1339.        0) != sizeof(netperf_response)) {
  1340.     perror("send_response: send call failure");
  1341.     exit(1);
  1342.   }
  1343.   
  1344. }
  1345.  
  1346.  /***********************************************************************/
  1347.  /*                                     */
  1348.  /*    recv_request()                            */
  1349.  /*                                    */
  1350.  /* receive the remote's request on the control socket. we will put    */
  1351.  /* the entire response into host order before giving it to the        */
  1352.  /* calling routine. hopefully, this will go most of the way to        */
  1353.  /* insuring intervendor interoperability. if there are any problems,    */
  1354.  /* we will just punt the entire situation.                */
  1355.  /*                                    */
  1356.  /***********************************************************************/
  1357.  
  1358. void
  1359. recv_request()
  1360. {
  1361. int     tot_bytes_recvd,
  1362.         bytes_recvd, 
  1363.         bytes_left;
  1364. char     *buf = (char *)&netperf_request;
  1365. int    buflen = sizeof(netperf_request);
  1366. int    counter;
  1367.  
  1368. tot_bytes_recvd = 0;    
  1369. bytes_left      = buflen;
  1370. while ((tot_bytes_recvd != buflen) &&
  1371.        ((bytes_recvd = recv(server_sock, buf, bytes_left,0)) > 0 )) {
  1372.   tot_bytes_recvd += bytes_recvd;
  1373.   buf             += bytes_recvd;
  1374.   bytes_left      -= bytes_recvd;
  1375. }
  1376.  
  1377. /* put the request into host order */
  1378.  
  1379. for (counter = 0; counter < sizeof(netperf_request)/sizeof(int); counter++) {
  1380.   request_array[counter] = ntohl(request_array[counter]);
  1381. }
  1382.  
  1383. if (debug) {
  1384.   fprintf(where,
  1385.       "recv_request: received %d bytes of request.\n",
  1386.       tot_bytes_recvd);
  1387.   fflush(where);
  1388. }
  1389.  
  1390. #ifdef WIN32
  1391. if (bytes_recvd == SOCKET_ERROR ) {
  1392. #else
  1393. if (bytes_recvd == -1) {
  1394. #endif /* WIN32 */
  1395.   fprintf(where,
  1396.       "recv_request: error on recv, errno %d\n",
  1397.       errno);
  1398.   fflush(where);
  1399.   exit(1);
  1400. }
  1401.  
  1402. if (bytes_recvd == 0) {
  1403.   /* the remote has shutdown the control connection, we should shut it */
  1404.   /* down as well and exit */
  1405.  
  1406.   if (debug) {
  1407.     fprintf(where,
  1408.         "recv_request: remote reqeusted shutdown of control\n");
  1409.     fflush(where);
  1410.   }
  1411.  
  1412.   shutdown_control();
  1413.   exit(0);
  1414. }
  1415.  
  1416. if (tot_bytes_recvd < buflen) {
  1417.   if (debug > 1)
  1418.     dump_request();
  1419.  
  1420.   fprintf(where,
  1421.       "recv_request: partial request received of %d bytes\n",
  1422.       tot_bytes_recvd);
  1423.   fflush(where);
  1424.   exit(1);
  1425. }
  1426.  
  1427. if (debug > 1) {
  1428.   dump_request();
  1429. }
  1430. }
  1431.  
  1432.  /***********************************************************************/
  1433.  /*                                     */
  1434.  /*    recv_response()                            */
  1435.  /*                                    */
  1436.  /* receive the remote's response on the control socket. we will put    */
  1437.  /* the entire response into host order before giving it to the        */
  1438.  /* calling routine. hopefully, this will go most of the way to        */
  1439.  /* insuring intervendor interoperability. if there are any problems,    */
  1440.  /* we will just punt the entire situation.                */
  1441.  /*                                    */
  1442.  /* The call to select at the beginning is to get us out of hang    */
  1443.  /* situations where the remote gives-up but we don't find-out about    */
  1444.  /* it. This seems to happen only rarely, but it would be nice to be    */
  1445.  /* somewhat robust ;-)                            */
  1446.  /***********************************************************************/
  1447.  
  1448. void
  1449. recv_response()
  1450. {
  1451. int     tot_bytes_recvd,
  1452.         bytes_recvd = 0, 
  1453.         bytes_left;
  1454. char     *buf = (char *)&netperf_response;
  1455. int     buflen = sizeof(netperf_response);
  1456. int    counter;
  1457.  
  1458.  /* stuff for select, use fd_set for better compliance */
  1459. fd_set    readfds;
  1460. struct    timeval    timeout;
  1461.  
  1462. tot_bytes_recvd = 0;    
  1463. bytes_left      = buflen;
  1464.  
  1465. /* zero out the response structure */
  1466.  
  1467. /* BUG FIX SJB 2/4/93 - should be < not <= */
  1468. for (counter = 0; counter < sizeof(netperf_response)/sizeof(int); counter++) {
  1469.         response_array[counter] = 0;
  1470. }
  1471.  
  1472.  /* we only select once. it is assumed that if the response is split */
  1473.  /* (which should not be happening, that we will receive the whole */
  1474.  /* thing and not have a problem ;-) */
  1475.  
  1476. FD_ZERO(&readfds);
  1477. FD_SET(netlib_control,&readfds);
  1478. timeout.tv_sec  = 60; /* wait one minute then punt */
  1479. timeout.tv_usec = 0;
  1480.  
  1481.  /* select had better return one, or there was either a problem or a */
  1482.  /* timeout... */
  1483.  
  1484. if ((counter = select(FD_SETSIZE,
  1485.               &readfds,
  1486.               0,
  1487.               0,
  1488.               &timeout)) != 1) {
  1489.   fprintf(where,
  1490.       "netperf: receive_response: no response received. errno %d counter %d\n",
  1491.       errno,
  1492.       counter);
  1493.   exit(1);
  1494. }
  1495.  
  1496. while ((tot_bytes_recvd != buflen) &&
  1497.        ((bytes_recvd = recv(netlib_control, buf, bytes_left,0)) > 0 )) {
  1498.   tot_bytes_recvd += bytes_recvd;
  1499.   buf             += bytes_recvd;
  1500.   bytes_left      -= bytes_recvd;
  1501. }
  1502.  
  1503. if (debug) {
  1504.   fprintf(where,"recv_response: received a %d byte response\n",
  1505.       tot_bytes_recvd);
  1506.   fflush(where);
  1507. }
  1508.  
  1509. /* put the response into host order */
  1510.  
  1511. for (counter = 0; counter < sizeof(netperf_response)/sizeof(int); counter++) {
  1512.   response_array[counter] = ntohl(response_array[counter]);
  1513. }
  1514.  
  1515. if (bytes_recvd == -1) {
  1516.     perror("recv_response");
  1517.     exit(1);
  1518. }
  1519. if (tot_bytes_recvd < buflen) {
  1520.   fprintf(stderr,
  1521.       "recv_response: partial response received: %d bytes\n",
  1522.       tot_bytes_recvd);
  1523.   fflush(stderr);
  1524.   if (debug > 1)
  1525.     dump_response();
  1526.   exit(1);
  1527. }
  1528. if (debug > 1) {
  1529.   dump_response();
  1530. }
  1531. }
  1532.  
  1533.  
  1534.  
  1535. #ifdef USE_PSTAT
  1536. int
  1537. hi_32(big_int)
  1538.      long long *big_int;
  1539. {
  1540.   union overlay_u {
  1541.     long long  dword;
  1542.     long       words[2];
  1543.   } *overlay;
  1544.  
  1545.   overlay = (union overlay_u *)big_int;
  1546.   /* on those systems which are byte swapped, we really wish to */
  1547.   /* return words[1] - at least I think so - raj 4/95 */
  1548.   if (htonl(1L) == 1L) {
  1549.     /* we are a "normal" :) machine */
  1550.     return(overlay->words[0]);
  1551.   }
  1552.   else {
  1553.     return(overlay->words[1]);
  1554.   }
  1555. }
  1556.  
  1557. int
  1558. lo_32(big_int)
  1559.      long long *big_int;
  1560. {
  1561.   union overlay_u {
  1562.     long long  dword;
  1563.     long       words[2];
  1564.   } *overlay;
  1565.  
  1566.   overlay = (union overlay_u *)big_int;
  1567.   /* on those systems which are byte swapped, we really wish to */
  1568.   /* return words[0] - at least I think so - raj 4/95 */
  1569.   if (htonl(1L) == 1L) {
  1570.     /* we are a "normal" :) machine */
  1571.     return(overlay->words[1]);
  1572.   }
  1573.   else {
  1574.     return(overlay->words[0]);
  1575.   }
  1576. }
  1577.  
  1578. #endif /* USE_PSTAT */
  1579.  
  1580.  
  1581.  
  1582. #ifdef USE_LOOPER
  1583.  
  1584.  /* calibrate_looper */
  1585.  
  1586.  /* Loop a number of times, sleeping wait_time seconds each and */
  1587.  /* count how high the idle counter gets each time. Return  the */
  1588.  /* measured cpu rate to the calling routine. raj 4/95 */
  1589.  
  1590. float
  1591. calibrate_looper(times,wait_time)
  1592.      int times;
  1593.      int wait_time;
  1594.  
  1595. {
  1596.  
  1597.   long    
  1598.     firstcnt[MAXCPUS],
  1599.     secondcnt[MAXCPUS];
  1600.  
  1601.   float    
  1602.     elapsed,
  1603.     temp_rate,
  1604.     rate[MAXTIMES],
  1605.     local_maxrate;
  1606.  
  1607.   long    
  1608.     sec,
  1609.     usec;
  1610.  
  1611.   int    
  1612.     i,
  1613.     j;
  1614.   
  1615.   struct  timeval time1, time2 ;
  1616.   struct  timezone tz;
  1617.   
  1618.   if (times > MAXTIMES) {
  1619.     times = MAXTIMES;
  1620.   }
  1621.  
  1622.   local_maxrate = (float)-1.0;
  1623.   
  1624.   for(i = 0; i < times; i++) {
  1625.     rate[i] = (float)0.0;
  1626.     for (j = 0; j < lib_num_loc_cpus; j++) {
  1627.       firstcnt[j] = *(lib_idle_address[j]);
  1628.     }
  1629.     gettimeofday (&time1, &tz);
  1630.     sleep(wait_time);
  1631.     gettimeofday (&time2, &tz);
  1632.  
  1633.     if (time2.tv_usec < time1.tv_usec)
  1634.       {
  1635.     time2.tv_usec += 1000000;
  1636.     time2.tv_sec -=1;
  1637.       }
  1638.     sec = time2.tv_sec - time1.tv_sec;
  1639.     usec = time2.tv_usec - time1.tv_usec;
  1640.     elapsed = (float)sec + ((float)usec/(float)1000000.0);
  1641.     
  1642.     if(debug) {
  1643.       fprintf(where, "Calibration for counter run: %d\n",i);
  1644.       fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec);
  1645.       fprintf(where,"\telapsed time = %g\n",elapsed);
  1646.     }
  1647.  
  1648.     for (j = 0; j < lib_num_loc_cpus; j++) {
  1649.       secondcnt[j] = *(lib_idle_address[j]);
  1650.       if(debug) {
  1651.     /* I know that there are situations where compilers know about */
  1652.     /* long long, but the library fucntions do not... raj 4/95 */
  1653.     fprintf(where,
  1654.         "\tfirstcnt[%d] = 0x%8.8x%8.8x secondcnt[%d] = 0x%8.8x%8.8x\n",
  1655.         j,
  1656.         firstcnt[j],
  1657.         firstcnt[j],
  1658.         j,
  1659.         secondcnt[j],
  1660.         secondcnt[j]);
  1661.       }
  1662.       /* we assume that it would wrap no more than once. we also */
  1663.       /* assume that the result of subtracting will "fit" raj 4/95 */
  1664.       temp_rate = (secondcnt[j] >= firstcnt[j]) ?
  1665.     (float)(secondcnt[j] - firstcnt[j])/elapsed : 
  1666.       (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed;
  1667.       if (temp_rate > rate[i]) rate[i] = temp_rate;
  1668.       if(debug) {
  1669.     fprintf(where,"\trate[%d] = %g\n",i,rate[i]);
  1670.     fflush(where);
  1671.       }
  1672.       if (local_maxrate < rate[i]) local_maxrate = rate[i];
  1673.     }
  1674.   }
  1675.   if(debug) {
  1676.     fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate);
  1677.     fflush(where);
  1678.   }
  1679.   return local_maxrate;
  1680. }
  1681. #endif /* USE_LOOPER */
  1682.  
  1683.  
  1684. #ifdef USE_PSTAT
  1685. #ifdef PSTAT_IPCINFO
  1686. /****************************************************************/
  1687. /*                                */
  1688. /*    calibrate_pstat                                         */
  1689. /*                                */
  1690. /*    Loop a number of times, sleeping wait_time seconds each */
  1691. /* and count how high the idle counter gets each time. Return    */
  1692. /* the measured cpu rate to the calling routine.        */
  1693. /*                                */
  1694. /****************************************************************/
  1695.  
  1696. float
  1697. calibrate_pstat(times,wait_time)
  1698.      int times;
  1699.      int wait_time;
  1700.  
  1701. {
  1702.   long long
  1703.     firstcnt[MAXCPUS],
  1704.     secondcnt[MAXCPUS];
  1705.  
  1706.   float    
  1707.     elapsed, 
  1708.     temp_rate,
  1709.     rate[MAXTIMES],
  1710.     local_maxrate;
  1711.  
  1712.   long    
  1713.     sec,
  1714.     usec;
  1715.  
  1716.   int    
  1717.     i,
  1718.     j;
  1719.   
  1720.   long    count;
  1721.  
  1722.   struct  timeval time1, time2;
  1723.   struct  timezone tz;
  1724.  
  1725.   struct pst_processor *psp;
  1726.   
  1727.   if (times > MAXTIMES) {
  1728.     times = MAXTIMES;
  1729.   }
  1730.   
  1731.   local_maxrate = -1.0;
  1732.  
  1733.   psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
  1734.  
  1735.   for(i = 0; i < times; i++) {
  1736.     rate[i] = 0.0;
  1737.     /* get the idle sycle counter for each processor */
  1738.     if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
  1739.       for (j = 0; j < lib_num_loc_cpus; j++) {
  1740.     union overlay_u {
  1741.       long long full;
  1742.       long      word[2];
  1743.     } *overlay;
  1744.     overlay = (union overlay_u *)&(firstcnt[j]);
  1745.     overlay->word[0] = psp[j].psp_idlecycles.psc_hi;
  1746.     overlay->word[1] = psp[j].psp_idlecycles.psc_lo;
  1747.       }
  1748.     }
  1749.     else {
  1750.       fprintf(where,"pstat_setprocessor failure errno %d\n");
  1751.       fflush(where);
  1752.       exit(1);
  1753.     }
  1754.  
  1755.     gettimeofday (&time1, &tz);
  1756.     sleep(wait_time);
  1757.     gettimeofday (&time2, &tz);
  1758.     
  1759.     if (time2.tv_usec < time1.tv_usec)
  1760.       {
  1761.     time2.tv_usec += 1000000;
  1762.     time2.tv_sec -=1;
  1763.       }
  1764.     sec = time2.tv_sec - time1.tv_sec;
  1765.     usec = time2.tv_usec - time1.tv_usec;
  1766.     elapsed = (float)sec + ((float)usec/(float)1000000.0);
  1767.  
  1768.     if(debug) {
  1769.       fprintf(where, "Calibration for counter run: %d\n",i);
  1770.       fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec);
  1771.       fprintf(where,"\telapsed time = %g\n",elapsed);
  1772.     }
  1773.  
  1774.     if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
  1775.       for (j = 0; j < lib_num_loc_cpus; j++) {
  1776.     union overlay_u {
  1777.       long long full;
  1778.       long      word[2];
  1779.     } *overlay;
  1780.     overlay = (union overlay_u *)&(secondcnt[j]);
  1781.     overlay->word[0] = psp[j].psp_idlecycles.psc_hi;
  1782.     overlay->word[1] = psp[j].psp_idlecycles.psc_lo;
  1783.     if(debug) {
  1784.       /* I know that there are situations where compilers know about */
  1785.       /* long long, but the library fucntions do not... raj 4/95 */
  1786.       fprintf(where,
  1787.           "\tfirstcnt[%d] = 0x%8.8x%8.8x secondcnt[%d] = 0x%8.8x%8.8x\n",
  1788.           j,
  1789.           hi_32(&firstcnt[j]),
  1790.           lo_32(&firstcnt[j]),
  1791.           j,
  1792.           hi_32(&secondcnt[j]),
  1793.           lo_32(&secondcnt[j]));
  1794.     }
  1795.     temp_rate = (secondcnt[j] >= firstcnt[j]) ? 
  1796.       (float)(secondcnt[j] - firstcnt[j] )/elapsed : 
  1797.         (float)(secondcnt[j] - firstcnt[j] + LONG_LONG_MAX)/elapsed;
  1798.     if (temp_rate > rate[i]) rate[i] = temp_rate;
  1799.     if(debug) {
  1800.       fprintf(where,"\trate[%d] = %g\n",i,rate[i]);
  1801.       fflush(where);
  1802.     }
  1803.     if (local_maxrate < rate[i]) local_maxrate = rate[i];
  1804.       }
  1805.     }
  1806.     else {
  1807.       fprintf(where,"pstat failure; errno %d\n",errno);
  1808.       fflush(where);
  1809.       exit(1);
  1810.     }
  1811.   }
  1812.   if(debug) {
  1813.     fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate);
  1814.     fflush(where);
  1815.   }
  1816.   return local_maxrate;
  1817. }
  1818. #endif /* PSTAT_IPCINFO */
  1819. #endif /* USE_PSTAT */
  1820.  
  1821.  
  1822. void libmain()
  1823. {
  1824. fprintf(where,"hello world\n");
  1825. fprintf(where,"debug: %d\n",debug);
  1826. }
  1827.  
  1828. /****************************************************************/
  1829. /*                                */
  1830. /*    establish_control()                    */
  1831. /*                                */
  1832. /* set-up the control connection between me and the server so    */
  1833. /* we can actually run some tests. if we cannot establish the   */
  1834. /* control connection, we might as well punt...            */
  1835. /* the variables for the control socket are kept in this lib    */
  1836. /* so as to 'hide' them from the upper routines as much as    */
  1837. /* possible so we can change them without affecting anyone...    */
  1838. /****************************************************************/
  1839.  
  1840. struct    sockaddr_in    server;         /* remote host address          */
  1841. struct    servent        *sp;            /* server entity                */
  1842. struct    hostent        *hp;            /* host entity                  */
  1843.  
  1844. void 
  1845. establish_control(hostname,port)
  1846. char         hostname[];
  1847. short int    port;
  1848. {
  1849.  
  1850.   unsigned int addr;
  1851.  
  1852.   if (debug > 1) {
  1853.     fprintf(where,"establish_control: entered with %s and %d\n",
  1854.         hostname,
  1855.         port);
  1856.   }
  1857.  
  1858.   /********************************************************/
  1859.   /* Set up the control socket netlib_control first    */
  1860.   /* for the time being we will assume that all set-ups    */
  1861.   /* are for tcp/ip and sockets...            */
  1862.   /********************************************************/
  1863.   
  1864.   bzero((char *)&server,
  1865.     sizeof(server));
  1866.   server.sin_port = htons(port);
  1867.  
  1868.   /* it would seem that while HP-UX will allow an IP address (as a */
  1869.   /* string) in a call to gethostbyname, other, less enlightened */
  1870.   /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
  1871.   if ((hp = gethostbyname(hostname)) == NULL) {
  1872.     if ((addr = inet_addr(hostname)) == -1) {
  1873.       fprintf(where,
  1874.           "establish_control: could not resolve the name %s\n",
  1875.           hostname);
  1876.       fflush(where);
  1877.       exit(1);
  1878.     }
  1879.     server.sin_addr.s_addr = addr;
  1880.     server.sin_family = AF_INET;
  1881.   }
  1882.   else {
  1883.     bcopy(hp->h_addr,
  1884.       (char *)&server.sin_addr,
  1885.       hp->h_length);
  1886.     server.sin_family = hp->h_addrtype;
  1887.   }
  1888.   
  1889.   
  1890.   if (debug > 1) {
  1891.     fprintf(where,"got the host info... \n");
  1892.     fflush(where);
  1893.   }
  1894.   
  1895.   
  1896.   if (debug > 1) {
  1897.     fprintf(where,"creating a socket\n");
  1898.     fflush(stdout);
  1899.   }
  1900.  
  1901. #ifdef __EMX__
  1902.   if(hp == NULL)
  1903.   {
  1904.     netlib_control = socket(PF_INET,
  1905.             SOCK_STREAM,
  1906.             tcp_proto_num);
  1907.   }
  1908.   else
  1909.     netlib_control = socket(hp->h_addrtype,
  1910.           SOCK_STREAM,
  1911.           tcp_proto_num);
  1912. #else
  1913.   
  1914.   netlib_control = socket(hp->h_addrtype,
  1915.               SOCK_STREAM,
  1916.               tcp_proto_num);
  1917. #endif
  1918.   
  1919.   if (netlib_control < 0){
  1920.     perror("establish_control: control socket");
  1921.     exit(1);
  1922.   }
  1923.   
  1924.   if (debug > 1) {
  1925.     fprintf(where,"about to connect\n");
  1926.     fflush(stdout);
  1927.   }
  1928.   
  1929.   if (connect(netlib_control, 
  1930.           (struct sockaddr *)&server, 
  1931.           sizeof(server)) <0){
  1932.     perror("establish_control: control socket connect failed");
  1933.     exit(1);
  1934.   }
  1935.   if (debug) {
  1936.     fprintf(where,"establish_control: connect completes\n");
  1937.   }
  1938.   
  1939.   /********************************************************/
  1940.   /* The Control Socket set-up is done, so now we want    */
  1941.   /* to test for connectivity on the connection        */
  1942.   /********************************************************/
  1943.  
  1944.   if (debug) 
  1945.     netperf_request.content.request_type = DEBUG_ON;
  1946.   else
  1947.     netperf_request.content.request_type = DEBUG_OFF;
  1948.   
  1949.   send_request();
  1950.   recv_response();
  1951.   
  1952.   if (netperf_response.content.response_type != DEBUG_OK) {
  1953.     fprintf(stderr,"establish_control: Unknown response to debug check\n");
  1954.     exit(1);
  1955.   }
  1956.   else if(debug)
  1957.     fprintf(where,"establish_control: check for connectivity ok\n");
  1958.   
  1959. }
  1960.  
  1961.  
  1962.  
  1963.  /***********************************************************************/
  1964.  /*                                    */
  1965.  /*    get_id()                            */
  1966.  /*                                    */
  1967.  /* Return a string to the calling routine that contains the        */
  1968.  /* identifying information for the host we are running on. This    */
  1969.  /* information will then either be displayed locally, or returned to    */
  1970.  /* a remote caller for display there.                    */
  1971.  /*                                    */
  1972.  /***********************************************************************/
  1973.  
  1974. void
  1975. get_id(id_string)
  1976. char *id_string;
  1977. {
  1978. #ifdef WIN32
  1979. SYSTEM_INFO        system_info ;
  1980. char            system_name[MAX_COMPUTERNAME_LENGTH+1] ;
  1981. int            name_len = MAX_COMPUTERNAME_LENGTH + 1 ;
  1982. #else
  1983. struct    utsname        system_name;
  1984. #endif /* WIN32 */
  1985.  
  1986. #ifdef WIN32
  1987. GetSystemInfo( &system_info ) ;
  1988. if ( !GetComputerName(system_name , &name_len) )
  1989.     strcpy(system_name , "no_name") ;
  1990. #else
  1991. if (uname(&system_name) <0) {
  1992.     perror("identify_local: uname");
  1993.     exit(1);
  1994. }
  1995. #endif /* WIN32 */
  1996.  
  1997. sprintf(id_string,
  1998. #ifdef WIN32
  1999.     "%-15s%-15s%d.%d%-15s",
  2000.     "Windows NT",
  2001.     system_name ,
  2002.     GetVersion() & 0xFF ,
  2003.     GetVersion() & 0xFF00 ,
  2004.     system_info.dwProcessorType ) ;
  2005.     
  2006. #else
  2007.     "%-15s%-15s%-15s%-15s%-15s",
  2008.     system_name.sysname,
  2009.     system_name.nodename,
  2010.     system_name.release,
  2011.     system_name.version,
  2012.     system_name.machine);
  2013. #endif /* WIN32 */
  2014. }
  2015.  
  2016.  
  2017.  /***********************************************************************/
  2018.  /*                                    */
  2019.  /*    identify_local()                        */
  2020.  /*                                    */
  2021.  /* Display identifying information about the local host to the user.    */
  2022.  /* At first release, this information will be the same as that which    */
  2023.  /* is returned by the uname -a command, with the exception of the    */
  2024.  /* idnumber field, which seems to be a non-POSIX item, and hence    */
  2025.  /* non-portable.                            */
  2026.  /*                                    */
  2027.  /***********************************************************************/
  2028.  
  2029. void
  2030. identify_local()
  2031. {
  2032.  
  2033. char    local_id[80];
  2034.  
  2035. get_id(local_id);
  2036.  
  2037. fprintf(where,"Local Information \n\
  2038. Sysname       Nodename       Release        Version        Machine\n");
  2039.  
  2040. fprintf(where,"%s\n",
  2041.        local_id);
  2042.  
  2043. }
  2044.  
  2045.  
  2046.  /***********************************************************************/
  2047.  /*                                    */
  2048.  /*    identify_remote()                        */
  2049.  /*                                    */
  2050.  /* Display identifying information about the remote host to the user.    */
  2051.  /* At first release, this information will be the same as that which    */
  2052.  /* is returned by the uname -a command, with the exception of the    */
  2053.  /* idnumber field, which seems to be a non-POSIX item, and hence    */
  2054.  /* non-portable. A request is sent to the remote side, which will    */
  2055.  /* return a string containing the utsname information in a        */
  2056.  /* pre-formatted form, which is then displayed after the header.    */
  2057.  /*                                    */
  2058.  /***********************************************************************/
  2059.  
  2060. void
  2061. identify_remote()
  2062. {
  2063.  
  2064. char    *remote_id="";
  2065.  
  2066. /* send a request for node info to the remote */
  2067. netperf_request.content.request_type = NODE_IDENTIFY;
  2068.  
  2069. send_request();
  2070.  
  2071. /* and now wait for the reply to come back */
  2072.  
  2073. recv_response();
  2074.  
  2075. if (netperf_response.content.serv_errno) {
  2076.     errno = netperf_response.content.serv_errno;
  2077.     perror("identify_remote: on remote");
  2078.     exit(1);
  2079. }
  2080.  
  2081. fprintf(where,"Remote Information \n\
  2082. Sysname       Nodename       Release        Version        Machine\n");
  2083.  
  2084. fprintf(where,"%s",
  2085.        remote_id);
  2086. }
  2087.  
  2088. void
  2089. cpu_start(measure_cpu)
  2090.      int measure_cpu;
  2091. {
  2092.  
  2093.   int    i;
  2094.  
  2095.   gettimeofday(&time1,
  2096.            &tz);
  2097.   
  2098.   if (measure_cpu) {
  2099.     measuring_cpu = 1;
  2100. #ifdef USE_LOOPER
  2101.     cpu_method = LOOPER;
  2102.     for (i = 0; i < lib_num_loc_cpus; i++){
  2103.       lib_start_count[i] = *lib_idle_address[i];
  2104.     }
  2105. #else
  2106. #ifdef    USE_PSTAT
  2107.     cpu_method = PSTAT;
  2108. #ifdef PSTAT_IPCINFO
  2109.     /* we need to know if we have the 10.0 pstat interface */
  2110.     /* available. I know that at 10.0, the define for PSTAT_IPCINFO */
  2111.     /* was added, but that it is not there prior. so, this should */
  2112.     /* act as the automagic compile trigger that I need. raj 4/95 */
  2113.     cpu_method = HP_IDLE_COUNTER;
  2114.     {
  2115.       /* get the idle sycle counter for each processor */
  2116.       struct pst_processor *psp;
  2117.       union overlay_u {
  2118.     long long full;
  2119.     long      word[2];
  2120.       } *overlay;
  2121.       
  2122.       psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
  2123.       if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
  2124.     int i;
  2125.     for (i = 0; i < lib_num_loc_cpus; i++) {
  2126.       overlay = (union overlay_u *)&(lib_start_count[i]);
  2127.       overlay->word[0] = psp[i].psp_idlecycles.psc_hi;
  2128.       overlay->word[1] = psp[i].psp_idlecycles.psc_lo;
  2129.       if(debug) {
  2130.         fprintf(where,
  2131.             "\tlib_start_count[%d] = 0x%8.8x%8.8x\n",
  2132.             i,
  2133.             hi_32(&lib_start_count[i]),
  2134.             lo_32(&lib_start_count[i]));
  2135.         fflush(where);
  2136.       }
  2137.     }
  2138.     free(psp);
  2139.       }
  2140.     }
  2141. #else
  2142.     /* this is what we should get when compiling on an HP-UX 9.X */
  2143.     /* system. raj 4/95 */
  2144.     pstat_getdynamic((struct pst_dynamic *)&pst_dynamic_info,
  2145.              sizeof(pst_dynamic_info),1,0);
  2146.     for (i = 0; i < PST_MAX_CPUSTATES; i++) {
  2147.       cp_time1[i] = pst_dynamic_info.psd_cpu_time[i];
  2148.     }
  2149. #endif /* PSTAT_IPCINFO */
  2150. #else
  2151. #ifdef WIN32
  2152. #ifdef NT_SDK
  2153.     /*--------------------------------------------------*/      /* robin */
  2154.     /* Use Win/NT internal counters to measure CPU%     */      /* robin */
  2155.     /*--------------------------------------------------*/      /* robin */
  2156.     NTSTATUS status;                                            /* robin */
  2157.                                                                 /* robin */
  2158.     status = NtQuerySystemTime( &systime_start );               /* robin */
  2159.     if (debug) {                                                /* robin */
  2160.        if (!NT_SUCCESS(status)) {                               /* robin */
  2161.           fprintf(where,"NtQuerySystemTime "                    /* robin */
  2162.                         "failed: 0x%08X\n",                     /* robin */
  2163.                         status);                                /* robin */
  2164.        }                                                        /* robin */
  2165.     }                                                           /* robin */
  2166.                                                                 /* robin */
  2167.     status = NtQuerySystemInformation (                         /* robin */
  2168.                 SystemProcessorPerformanceInformation,          /* robin */
  2169.                 &sysperf_start,                                 /* robin */
  2170.                 sizeof(sysperf_start),                          /* robin */
  2171.                 NULL );                                         /* robin */
  2172.                                                                 /* robin */
  2173.     if (debug) {                                                /* robin */
  2174.        if (!NT_SUCCESS(status)) {                               /* robin */
  2175.           fprintf(where,"NtQuerySystemInformation "             /* robin */
  2176.                         "failed: 0x%08X\n",                     /* robin */
  2177.                         status);                                /* robin */
  2178.        }                                                        /* robin */
  2179.     }                                                           /* robin */
  2180.                                                                 /* robin */
  2181. #endif /* NT_SDK */
  2182. #else
  2183.     cpu_method = TIMES;
  2184.     times(×_data1);
  2185. #endif /* WIN32 */
  2186. #endif /* USE_PSTAT */
  2187. #endif /* USE_LOOPER */
  2188.   }
  2189. }
  2190.  
  2191.  
  2192. void
  2193. cpu_stop(measure_cpu,elapsed)
  2194. int    measure_cpu;
  2195. float    *elapsed;
  2196. {
  2197. #ifndef WIN32
  2198. #include <sys/wait.h>
  2199. #endif /* WIN32 */
  2200.  
  2201. int    sec,
  2202.         usec;
  2203.  
  2204. int    i;
  2205.  
  2206. if (measure_cpu) {
  2207. #ifdef USE_LOOPER
  2208.   for (i = 0; i < lib_num_loc_cpus; i++){
  2209.     lib_end_count[i] = *lib_idle_address[i];
  2210.   }
  2211. #ifdef WIN32
  2212.   /* it would seem that if/when the process exits, all the threads */
  2213.   /* will go away too, so I don't think I need any explicit thread */
  2214.   /* killing calls here. raj 1/96 */
  2215. #else
  2216.   /* now go through and kill-off all the child processes */
  2217.   for (i = 0; i < lib_num_loc_cpus; i++){
  2218.     kill(lib_idle_pids[i],SIGQUIT);
  2219.   }
  2220.   /* reap the children */
  2221.   while(waitpid(-1, NULL, WNOHANG) > 0) { }
  2222.   
  2223.   /* finally, unlink the mmaped file */
  2224.   munmap((caddr_t)lib_base_pointer,
  2225.      ((NETPERF_PAGE_SIZE * PAGES_PER_CHILD) * 
  2226.       lib_num_loc_cpus));
  2227.   unlink("/tmp/netperf_cpu");
  2228. #endif /* WIN32 */
  2229. #else
  2230. #ifdef    USE_PSTAT
  2231. #ifdef PSTAT_IPCINFO
  2232.   {
  2233.     struct pst_processor *psp;
  2234.     union overlay_u {
  2235.       long long full;
  2236.       long      word[2];
  2237.     } *overlay;
  2238.     psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
  2239.     if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
  2240.       for (i = 0; i < lib_num_loc_cpus; i++) {
  2241.     overlay = (union overlay_u *)&(lib_end_count[i]);
  2242.     overlay->word[0] = psp[i].psp_idlecycles.psc_hi;
  2243.     overlay->word[1] = psp[i].psp_idlecycles.psc_lo;
  2244.     if(debug) {
  2245.       fprintf(where,
  2246.           "\tlib_end_count[%d]   = 0x%8.8x%8.8x\n",
  2247.           i,
  2248.           hi_32(&lib_end_count[i]),
  2249.           lo_32(&lib_end_count[i]));
  2250.       fflush(where);
  2251.     }
  2252.       }
  2253.       free(psp);
  2254.     }
  2255.     else {
  2256.       fprintf(where,"pstat_getprocessor failure: errno %d\n",errno);
  2257.       fflush(where);
  2258.       exit(1);
  2259.     }
  2260.   }
  2261. #else /* not HP-UX 10.0 or later */
  2262.   {
  2263.     pstat_getdynamic(&pst_dynamic_info, sizeof(pst_dynamic_info),1,0);
  2264.     for (i = 0; i < PST_MAX_CPUSTATES; i++) {
  2265.       cp_time2[i] = pst_dynamic_info.psd_cpu_time[i];
  2266.     }
  2267.   }    
  2268. #endif /* PSTAT_IPC_INFO */
  2269. #else
  2270. #ifdef WIN32
  2271. #ifdef NT_SDK
  2272.        NTSTATUS status;                                         /* robin */
  2273.                                                                 /* robin */
  2274.        status = NtQuerySystemTime( &systime_end );              /* robin */
  2275.        if (debug) {                                             /* robin */
  2276.           if (!NT_SUCCESS(status)) {                            /* robin */
  2277.              fprintf(where,"NtQuerySystemTime "                 /* robin */
  2278.                            "failed: 0x%08X\n",                  /* robin */
  2279.                            status);                             /* robin */
  2280.           }                                                     /* robin */
  2281.        }                                                        /* robin */
  2282.        status = NtQuerySystemInformation (                      /* robin */
  2283.                    SystemProcessorPerformanceInformation,       /* robin */
  2284.                    &sysperf_end,                                /* robin */
  2285.                    sizeof(sysperf_end),                         /* robin */
  2286.                    NULL );                                      /* robin */
  2287.                                                                 /* robin */
  2288.        if (debug) {                                             /* robin */
  2289.           if (!NT_SUCCESS(status)) {                            /* robin */
  2290.              fprintf(where,"NtQuerySystemInformation "          /* robin */
  2291.                            "failed: 0x%08X\n",                  /* robin */
  2292.                            status);                             /* robin */
  2293.           }                                                     /* robin */
  2294.        }                                                        /* robin */
  2295.                                                                 /* robin */
  2296. #endif /* NT_SDK */
  2297. #else
  2298.   times(×_data2);
  2299. #endif /* WIN32 */
  2300. #endif /* USE_PSTAT */
  2301. #endif /* USE_LOOPER */
  2302. }
  2303.  
  2304. gettimeofday(&time2,
  2305.          &tz);
  2306.  
  2307. if (time2.tv_usec < time1.tv_usec) {
  2308.   time2.tv_usec    += 1000000;
  2309.   time2.tv_sec    -= 1;
  2310. }
  2311.  
  2312. sec    = time2.tv_sec - time1.tv_sec;
  2313. usec    = time2.tv_usec - time1.tv_usec;
  2314. lib_elapsed    = (float)sec + ((float)usec/(float)1000000.0);
  2315.  
  2316. *elapsed = lib_elapsed;
  2317.     
  2318. }
  2319.  
  2320. double
  2321. calc_thruput(units_received)
  2322. double units_received;
  2323.  
  2324. {
  2325.   double    divisor;
  2326.  
  2327.   /* We will calculate the thruput in libfmt units/second */
  2328.   switch (libfmt) {
  2329.   case 'K':
  2330.     divisor = 1024.0;
  2331.     break;
  2332.   case 'M':
  2333.     divisor = 1024.0 * 1024.0;
  2334.     break;
  2335.   case 'G':
  2336.     divisor = 1024.0 * 1024.0 * 1024.0;
  2337.     break;
  2338.   case 'k':
  2339.     divisor = 1000.0 / 8.0;
  2340.     break;
  2341.   case 'm':
  2342.     divisor = 1000.0 * 1000.0 / 8.0;
  2343.     break;
  2344.   case 'g':
  2345.     divisor = 1000.0 * 1000.0 * 1000.0 / 8.0;
  2346.     break;
  2347.     
  2348.   default:
  2349.     divisor = 1024.0;
  2350.   }
  2351.   
  2352.   return (units_received / divisor / lib_elapsed);
  2353.  
  2354. }
  2355.  
  2356.  
  2357.  
  2358.  
  2359. float 
  2360. calc_cpu_util(elapsed_time)
  2361.      float elapsed_time;
  2362. {
  2363.   
  2364.   float    actual_rate;
  2365.   float correction_factor;
  2366. #ifdef USE_PSTAT
  2367. #ifdef PSTAT_IPCINFO
  2368.   float temp_util;
  2369. #else
  2370.   long diff;
  2371. #endif
  2372. #endif
  2373.   int    cpu_time_ticks;
  2374.   long    ticks_sec;
  2375.   int    i;
  2376.   
  2377.  
  2378.   lib_local_cpu_util = (float)0.0;
  2379.   /* It is possible that the library measured a time other than */
  2380.   /* the one that the user want for the cpu utilization */
  2381.   /* calculations - for example, tests that were ended by */
  2382.   /* watchdog timers such as the udp stream test. We let these */
  2383.   /* tests tell up what the elapsed time should be. */
  2384.   
  2385.   if (elapsed_time != 0.0) {
  2386.     correction_factor = (float) 1.0 + 
  2387.       ((lib_elapsed - elapsed_time) / elapsed_time);
  2388.   }
  2389.   else {
  2390.     correction_factor = (float) 1.0;
  2391.   }
  2392.   
  2393. #ifdef USE_LOOPER
  2394.   for (i = 0; i < lib_num_loc_cpus; i++) {
  2395.  
  2396.     /* it would appear that on some systems, in loopback, nice */
  2397.     /* is *very* effective, causing the looper process to stop */
  2398.     /* dead in its tracks. if this happens, we need to ensure  */
  2399.     /* that the calculation does not go south. raj 6/95        */
  2400.     if (lib_end_count[i] == lib_start_count[i]) {
  2401.       lib_end_count[i]++;
  2402.     }
  2403.     
  2404.     actual_rate = (lib_end_count[i] > lib_start_count[i]) ?
  2405.       (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed :
  2406.     (float)(lib_end_count[i] - lib_start_count[i] +
  2407.         MAXLONG)/ lib_elapsed;
  2408.     if (debug) {
  2409.       fprintf(where,
  2410.           "calc_cpu_util: actual_rate on processor %d is %f\n",
  2411.           i,
  2412.           actual_rate);
  2413.     }
  2414.     lib_local_cpu_util += (lib_local_maxrate - actual_rate) /
  2415.       lib_local_maxrate * 100;
  2416.   }
  2417.   /* we want the average across all n processors */
  2418.   lib_local_cpu_util /= (float)lib_num_loc_cpus;
  2419.  
  2420. #else
  2421. #ifdef USE_PSTAT
  2422. #ifdef PSTAT_IPCINFO
  2423.   {
  2424.     /* this looks just like the looper case. at least I think it */
  2425.     /* should :) raj 4/95 */
  2426.     for (i = 0; i < lib_num_loc_cpus; i++) {
  2427.       /* we assume that the two are not more than a long apart. I */
  2428.       /* know that this is bad, but trying to go from long longs to */
  2429.       /* a float (perhaps a double) is boggling my mind right now. */
  2430.       /* raj 4/95 */
  2431.  
  2432.       long long 
  2433.     diff;
  2434.       
  2435.       if (lib_end_count[i] >= lib_start_count[i]) {
  2436.     diff = lib_end_count[i] - lib_start_count[i];
  2437.       }
  2438.       else {
  2439.     diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX;
  2440.       }
  2441.       actual_rate = (float) diff / lib_elapsed;
  2442.       temp_util = (lib_local_maxrate - actual_rate) /
  2443.     lib_local_maxrate * 100;
  2444.       lib_local_cpu_util += temp_util;
  2445.       if (debug) {
  2446.     fprintf(where,
  2447.         "calc_cpu_util: actual_rate on cpu %d is %f cpu %6.2f\n",
  2448.         i,
  2449.         actual_rate,
  2450.         temp_util);
  2451.       }
  2452.     }
  2453.     /* we want the average across all n processors */
  2454.     lib_local_cpu_util /= (float)lib_num_loc_cpus;
  2455.   }
  2456. #else
  2457.   {
  2458.     /* we had no idle counter, but there was a pstat. we */
  2459.     /* will use the cpu_time_ticks variable for the total */
  2460.     /* ticks calculation */
  2461.     cpu_time_ticks = 0;
  2462.     /* how many ticks were there in our interval? */
  2463.     for (i = 0; i < PST_MAX_CPUSTATES; i++) {
  2464.       diff = cp_time2[i] - cp_time1[i];
  2465.       cpu_time_ticks += diff;
  2466.       if (debug) {
  2467.     fprintf(where,
  2468.         "%d cp_time1 %d cp_time2 %d diff %d cpu_time_ticks is %d \n",
  2469.         i,
  2470.         cp_time1[i],
  2471.         cp_time2[i],
  2472.         diff,
  2473.         cpu_time_ticks);
  2474.     fflush(where);
  2475.       }
  2476.     }
  2477.     if (!cpu_time_ticks)
  2478.       cpu_time_ticks = 1;
  2479.     /* cpu used is 100% minus the idle time - right ?-) */
  2480.     lib_local_cpu_util = 1.0 - ( ((float)(cp_time2[CP_IDLE] - 
  2481.                       cp_time1[CP_IDLE]))
  2482.                 / (float)cpu_time_ticks);
  2483.     lib_local_cpu_util *= 100.0;
  2484.     if (debug) {
  2485.       fprintf(where,
  2486.           "calc_cpu_util has cpu_time_ticks at %d\n",cpu_time_ticks);
  2487.       fprintf(where,"sysconf ticks is %g\n",
  2488.           sysconf(_SC_CLK_TCK) * lib_elapsed);
  2489.       fprintf(where,"calc_cpu_util has idle_ticks at %d\n",
  2490.           (cp_time2[CP_IDLE] - cp_time1[CP_IDLE]));
  2491.       fflush(where);
  2492.     }
  2493.   }
  2494. #endif /* PSTAT_IPCINFO */
  2495. #else
  2496. #ifdef WIN32
  2497. #ifdef NT_SDK
  2498.   LARGE_INTEGER delta_t,    /* scratch */                       /* robin */
  2499.                 elapsed,    /* elapsed total system time */     /* robin */
  2500.                 kernel,     /* elapsed kernel mode time  */     /* robin */
  2501.                 idle,       /* elapsed kernel idle time  */     /* robin */
  2502.                 user;       /* elapsed user mode time    */     /* robin */
  2503.   ULONG         remainder;  /* never used, discarded value */   /* robin */
  2504.   ULONG         cpu;        /* cpu utilization (as ULONG)  */   /* robin */
  2505.                                                                 /* robin */
  2506.   /* The magic number 10*1000 will convert the  */              /* robin */
  2507.   /* 100ns time units (returned by NT kernel)   */              /* robin */
  2508.   /* into millisecond units.                    */              /* robin */
  2509.   delta_t = RtlLargeIntegerSubtract(                            /* robin */
  2510.                        systime_end,                             /* robin */
  2511.                        systime_start);                          /* robin */
  2512.   elapsed = RtlExtendedLargeIntegerDivide(                      /* robin */
  2513.                        delta_t,                                 /* robin */
  2514.                        10*1000,                                 /* robin */
  2515.                        &remainder);                             /* robin */
  2516.   if (debug) {
  2517.     fprintf(where,
  2518.         "NT's elapsed time %d\n",
  2519.         remainder);
  2520.     fflush(where);
  2521.   }
  2522.  
  2523.   delta_t = RtlLargeIntegerSubtract(                            /* robin */
  2524.                        sysperf_end.KernelTime,                  /* robin */
  2525.                        sysperf_start.KernelTime);               /* robin */
  2526.   kernel  = RtlExtendedLargeIntegerDivide(                      /* robin */
  2527.                        delta_t,                                 /* robin */
  2528.                        10*1000,                                 /* robin */
  2529.                        &remainder);                             /* robin */
  2530.   if (debug) {
  2531.     fprintf(where,
  2532.         " kernel time %d ",
  2533.         kernel);
  2534.     fflush(where);
  2535.   }
  2536.  
  2537.   delta_t = RtlLargeIntegerSubtract(                            /* robin */
  2538.                        sysperf_end.IdleTime,                    /* robin */
  2539.                        sysperf_start.IdleTime);                 /* robin */
  2540.   idle    = RtlExtendedLargeIntegerDivide(                      /* robin */
  2541.                        delta_t,                                 /* robin */
  2542.                        10*1000,                                 /* robin */
  2543.                        &remainder);                             /* robin */
  2544.   if (debug) {
  2545.     fprintf(where,
  2546.         " idle time %d ",
  2547.         idle);
  2548.     fflush(where);
  2549.   }
  2550.  
  2551.   delta_t = RtlLargeIntegerSubtract(                            /* robin */
  2552.                        sysperf_end.UserTime,                    /* robin */
  2553.                        sysperf_start.UserTime);                 /* robin */
  2554.   user    = RtlExtendedLargeIntegerDivide(                      /* robin */
  2555.                        delta_t,                                 /* robin */
  2556.                        10*1000,                                 /* robin */
  2557.                        &remainder);                             /* robin */
  2558.  
  2559.   if (debug) {
  2560.     fprintf(where,
  2561.         " user time %d\n",
  2562.         user);
  2563.     fflush(where);
  2564.   }
  2565.  
  2566.                                                                 /* robin */
  2567.   cpu = ((kernel.LowPart+user.LowPart-idle.LowPart)*100 + 50)   /* robin */
  2568.                       /elapsed.LowPart;                         /* robin */
  2569.   lib_local_cpu_util = (float)cpu;                              /* robin */
  2570.                                                                 /* robin */
  2571.                                                                 /* robin */
  2572.   if (debug) {                                                  /* robin */
  2573.      fprintf(where,"calc_cpu_util: local_cpu_util = %ld%%\n",   /* robin */
  2574.                    cpu);                                        /* robin */
  2575.   }                                                             /* robin */
  2576.                                                                 /* robin */
  2577. #endif /* NT_SDK */
  2578. #else
  2579.   /* we had no kernel idle counter, so use what we can */
  2580.   ticks_sec = sysconf(_SC_CLK_TCK);
  2581.   cpu_time_ticks = ((times_data2.tms_utime - times_data1.tms_utime) +
  2582.             (times_data2.tms_stime -
  2583.              times_data1.tms_stime));
  2584.   
  2585.   if (debug) {
  2586.     fprintf(where,"calc_cpu_util has cpu_time_ticks at %d\n",cpu_time_ticks);
  2587.     fprintf(where,"calc_cpu_util has tick_sec at %ld\n",ticks_sec);
  2588.     fprintf(where,"calc_cpu_util has lib_elapsed at %f\n",lib_elapsed);
  2589.     fflush(where);
  2590.   }
  2591.   
  2592.   lib_local_cpu_util = (float) (((double) (cpu_time_ticks) /
  2593.                  (double) ticks_sec /
  2594.                  (double) lib_elapsed) *
  2595.                 (double) 100.0);
  2596. #endif /* WIN32 */
  2597. #endif /* USE_PSTAT */
  2598. #endif /* USE_LOOPER */
  2599.   lib_local_cpu_util *= correction_factor;
  2600.   return lib_local_cpu_util;
  2601. }
  2602.  
  2603. float calc_service_demand(units_sent,
  2604.               elapsed_time,
  2605.               cpu_utilization,
  2606.               num_cpus)
  2607. double    units_sent;
  2608. float    elapsed_time;
  2609. float    cpu_utilization;
  2610. int     num_cpus;
  2611.  
  2612. {
  2613.  
  2614.   double unit_divisor = (float)1024.0;
  2615.   double service_demand;
  2616.   double thruput;
  2617.  
  2618.   if (debug) {
  2619.     fprintf(where,"calc_service_demand called:  units_sent = %f\n",
  2620.         units_sent);
  2621.     fprintf(where,"                             elapsed_time = %f\n",
  2622.         elapsed_time);
  2623.     fprintf(where,"                             cpu_util = %f\n",
  2624.         cpu_utilization);
  2625.     fprintf(where,"                             num cpu = %d\n",
  2626.         num_cpus);
  2627.     fflush(where);
  2628.   }
  2629.  
  2630.   if (num_cpus == 0) num_cpus = lib_num_loc_cpus;
  2631.   
  2632.   if (elapsed_time == 0.0) {
  2633.     elapsed_time = lib_elapsed;
  2634.   }
  2635.   if (cpu_utilization == 0.0) {
  2636.     cpu_utilization = lib_local_cpu_util;
  2637.   }
  2638.   
  2639.   thruput = (units_sent / 
  2640.          (double) unit_divisor / 
  2641.          (double) elapsed_time);
  2642.  
  2643.   /* on MP systems, it is necessary to multiply the service demand by */
  2644.   /* the number of CPU's. at least, I believe that to be the case:) */
  2645.   /* raj 10/95 */
  2646.  
  2647.   /* thruput has a "per second" component. if we were using 100% ( */
  2648.   /* 100.0) of the CPU in a second, that would be 1 second, or 1 */
  2649.   /* millisecond, so we multiply cpu_utilization by 10 to go to */
  2650.   /* milliseconds, or 10,000 to go to micro seconds. With revision */
  2651.   /* 2.1, the service demand measure goes to microseconds per unit. */
  2652.   /* raj 12/95 */ 
  2653.   service_demand = (cpu_utilization*10000.0/thruput) * 
  2654.     (float) num_cpus;
  2655.   
  2656.   if (debug) {
  2657.     fprintf(where,"calc_service_demand using:   units_sent = %f\n",
  2658.         units_sent);
  2659.     fprintf(where,"                             elapsed_time = %f\n",
  2660.         elapsed_time);
  2661.     fprintf(where,"                             cpu_util = %f\n",
  2662.         cpu_utilization);
  2663.     fprintf(where,"                             num cpu = %d\n",
  2664.         num_cpus);
  2665.     fprintf(where,"calc_service_demand got:     thruput = %f\n",
  2666.         thruput);
  2667.     fprintf(where,"                             servdem = %f\n",
  2668.         service_demand);
  2669.     fflush(where);
  2670.   }
  2671.   return service_demand;
  2672. }
  2673.  
  2674.  
  2675. #ifdef USE_LOOPER
  2676. void
  2677. bind_to_processor(child_num)
  2678.      int child_num;
  2679. {
  2680.   /* This routine will bind the calling process to a particular */
  2681.   /* processor. We are not choosy as to which processor, so it will be */
  2682.   /* the process id mod the number of processors - shifted by one for */
  2683.   /* those systems which name processor starting from one instead of */
  2684.   /* zero. on those systems where I do not yet know how to bind a */
  2685.   /* process to a processor, this routine will be a no-op raj 10/95 */
  2686.  
  2687.   /* just as a reminder, this is *only* for the looper processes, not */
  2688.   /* the actual measurement processes. those will, should, MUST float */
  2689.   /* or not float from CPU to CPU as controlled by the operating */
  2690.   /* system defaults. raj 12/95 */
  2691.  
  2692. #ifdef __hpux
  2693. #include <sys/syscall.h>
  2694. #include <sys/mp.h>
  2695.  
  2696.   int old_cpu = -2;
  2697.  
  2698.   if (debug) {
  2699.     fprintf(where,
  2700.         "child %d asking for CPU %d as pid %d with %d CPUs\n",
  2701.         child_num,
  2702.         (child_num % lib_num_loc_cpus),
  2703.         getpid(),
  2704.         lib_num_loc_cpus);
  2705.     fflush(where);
  2706.   }
  2707.  
  2708.   SETPROCESS((child_num % lib_num_loc_cpus), getpid());
  2709.   return;
  2710.  
  2711. #else
  2712. #ifdef __sun
  2713.  /* this may also get SunOS, which may not have this stuff? */
  2714. #include <sys/processor.h>
  2715. #include <sys/procset.h>
  2716.  
  2717.   int old_binding;
  2718.  
  2719.   if (debug) {
  2720.     fprintf(where,
  2721.         "bind_to_processor: child %d asking for CPU %d as pid %d with %d CPUs\n",
  2722.         child_num,
  2723.         (child_num % lib_num_loc_cpus),
  2724.         getpid(),
  2725.         lib_num_loc_cpus);
  2726.     fflush(where);
  2727.   }
  2728.  
  2729.   if (processor_bind(P_PID,
  2730.              getpid(),
  2731.              (child_num % lib_num_loc_cpus), 
  2732.               &old_binding) != 0) {
  2733.     fprintf(where,"bind_to_processor: unable to perform processor binding\n");
  2734.     fprintf(where,"                   errno %d\n",errno);
  2735.     fflush(where);
  2736.   }
  2737.   return;
  2738. #else
  2739.   return;
  2740. #endif /* __sun */
  2741. #endif /* __hpux */
  2742. }
  2743.  
  2744.  
  2745.  
  2746.  /* sit_and_spin will just spin about incrementing a value */
  2747.  /* this value will either be in a memory mapped region on Unix shared */
  2748.  /* by each looper process, or something appropriate on Windows/NT */
  2749.  /* (malloc'd or such). This routine is reasonably ugly in that it has */
  2750.  /* priority manipulating code for lots of different operating */
  2751.  /* systems. This routine never returns. raj 1/96 */ 
  2752.  
  2753. void
  2754. sit_and_spin(child_index)
  2755.      int child_index;
  2756.  
  2757. {
  2758.   long *my_counter_ptr;
  2759.  
  2760.  /* only use C stuff if we are not WIN32 unless and until we */
  2761.  /* switch from CreateThread to _beginthread. raj 1/96 */
  2762. #ifndef WIN32
  2763.   /* we are the child. we could decide to exec some separate */
  2764.   /* program, but that doesn't really seem worthwhile - raj 4/95 */
  2765.   if (debug > 1) {
  2766.     fprintf(where,
  2767.         "Looper child %d is born, pid %d\n",
  2768.         child_index,
  2769.         getpid());
  2770.     fflush(where);
  2771.   }
  2772.   
  2773. #endif /* WIN32 */
  2774.  
  2775.   /* reset our base pointer to be at the appropriate offset */
  2776.   my_counter_ptr = (long *) ((char *)lib_base_pointer + 
  2777.                  (NETPERF_PAGE_SIZE * 
  2778.                   PAGES_PER_CHILD * child_index));
  2779.   
  2780.   /* in the event we are running on an MP system, it would */
  2781.   /* probably be good to bind the soaker processes to specific */
  2782.   /* processors. I *think* this is the most reasonable thing to */
  2783.   /* do, and would be closes to simulating the information we get */
  2784.   /* on HP-UX with pstat. I could put all the system-specific code */
  2785.   /* here, but will "abstract it into another routine to keep this */
  2786.   /* area more readable. I'll probably do the same thine with the */
  2787.   /* "low pri code" raj 10/95 */
  2788.   
  2789.   /* NOTE. I do *NOT* think it would be appropriate for the actual */
  2790.   /* test processes to be bound to a  particular processor - that */
  2791.   /* is something that should be left up to the operating system. */
  2792.   
  2793.   bind_to_processor(child_index);
  2794.   
  2795.   for (*my_counter_ptr = 0L;
  2796.        ;
  2797.        (*my_counter_ptr)++) {
  2798.     if (!(*lib_base_pointer % 1)) {
  2799.       /* every once and again, make sure that our process priority is */
  2800.       /* nice and low. also, by making system calls, it may be easier */
  2801.       /* for us to be pre-empted by something that needs to do useful */
  2802.       /* work - like the thread of execution actually sending and */
  2803.       /* receiveing data across the network :) */
  2804. #ifdef _AIX
  2805.       int pid,prio;
  2806.  
  2807.       prio = PRIORITY;
  2808.       pid = getpid();
  2809.       /* if you are not root, this call will return EPERM - why one */
  2810.       /* cannot change one's own priority to  lower value is beyond */
  2811.       /* me. raj 2/26/96 */  
  2812.       setpri(pid, prio);
  2813. #else /* _AIX */
  2814. #ifdef __sgi
  2815.       int pid,prio;
  2816.  
  2817.       prio = PRIORITY;
  2818.       pid = getpid();
  2819.       schedctl(NDPRI, pid, prio);
  2820.       sginap(0);
  2821. #else /* __sgi */
  2822. #ifdef WIN32
  2823.       SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_IDLE);
  2824. #else /* WIN32 */
  2825. #ifdef __sun
  2826. #include <sys/types.h>
  2827. #include <sys/priocntl.h>
  2828. #include <sys/rtpriocntl.h>
  2829. #include <sys/tspriocntl.h>
  2830.       /* I would *really* like to know how to use priocntl to make the */
  2831.       /* priority low for this looper process. however, either my mind */
  2832.       /* is addled, or the manpage in section two for priocntl is not */
  2833.       /* terribly helpful - for one, it has no examples :( so, if you */
  2834.       /* can help, I'd love to hear from you. in the meantime, we will */
  2835.       /* rely on nice(39). raj 2/26/96 */
  2836.       nice(39);
  2837. #else /* __sun */
  2838.       nice(39);
  2839. #endif /* __sun */
  2840. #endif /* WIN32 */
  2841. #endif /* __sgi */
  2842. #endif /* _AIX */
  2843.     }
  2844.   }
  2845. }
  2846.  
  2847.  
  2848.  
  2849.  /* this routine will start all the looper processes or threads for */
  2850.  /* measuring CPU utilization. */
  2851.  
  2852. void
  2853. start_looper_processes()
  2854. {
  2855.  
  2856.   unsigned int  
  2857.     i,
  2858.     file_size;
  2859.   
  2860.   /* we want at least two pages for each processor. the */
  2861.   /* child for any one processor will write to the first of his two */
  2862.   /* pages, and the second page will be a buffer in case there is page */
  2863.   /* prefetching. if your system pre-fetches more than a single page, */
  2864.   /* well, you'll have to modify this or live with it :( raj 4/95 */
  2865.  
  2866.   file_size = ((NETPERF_PAGE_SIZE * PAGES_PER_CHILD) * 
  2867.            lib_num_loc_cpus);
  2868.   
  2869. #ifndef WIN32
  2870.  
  2871.   /* we we are not using WINDOWS NT (or 95 actually :), then we want */
  2872.   /* to create a memory mapped region so we can see all the counting */
  2873.   /* rates of the loopers */
  2874.  
  2875.   lib_idle_fd = open("/tmp/netperf_cpu",O_RDWR | O_CREAT | O_EXCL);
  2876.   
  2877.   if (lib_idle_fd == -1) {
  2878.     fprintf(where,"create_looper: file creation; errno %d\n",errno);
  2879.     fflush(where);
  2880.     exit(1);
  2881.   }
  2882.   
  2883.   if (chmod("/tmp/netperf_cpu",0644) == -1) {
  2884.     fprintf(where,"create_looper: chmod; errno %d\n",errno);
  2885.     fflush(where);
  2886.     exit(1);
  2887.   }
  2888.   
  2889.   /* with the file descriptor in place, lets be sure that the file is */
  2890.   /* large enough. */
  2891.   
  2892.   if (truncate("/tmp/netperf_cpu",file_size) == -1) {
  2893.     fprintf(where,"create_looper: truncate: errno %d\n",errno);
  2894.     fflush(where);
  2895.     exit(1);
  2896.   }
  2897.   
  2898.   /* the file should be large enough now, so we can mmap it */
  2899.   
  2900.   /* if the system does not have MAP_VARIABLE, just define it to */
  2901.   /* be zero. it is only used/needed on HP-UX (?) raj 4/95 */
  2902. #ifndef MAP_VARIABLE
  2903. #define MAP_VARIABLE 0x0000
  2904. #endif /* MAP_VARIABLE */
  2905. #ifndef MAP_FILE
  2906. #define MAP_FILE 0x0000
  2907. #endif /* MAP_FILE */
  2908.   if ((lib_base_pointer = (long *)mmap(NULL,
  2909.                        file_size,
  2910.                        PROT_READ | PROT_WRITE,
  2911.                        MAP_FILE | MAP_SHARED | MAP_VARIABLE,
  2912.                        lib_idle_fd,
  2913.                        0)) == (long *)-1) {
  2914.     fprintf(where,"create_looper: mmap: errno %d\n",errno);
  2915.     fflush(where);
  2916.     exit(1);
  2917.   }
  2918.   
  2919.  
  2920.   if (debug > 1) {
  2921.     fprintf(where,"num CPUs %d, file_size %d, lib_base_pointer 0x%8.0lx\n",
  2922.         lib_num_loc_cpus,
  2923.         file_size,
  2924.         (unsigned long)lib_base_pointer);
  2925.     fflush(where);
  2926.   }
  2927.  
  2928.   /* we should have a valid base pointer. lets fork */
  2929.   
  2930.   for (i = 0; i < lib_num_loc_cpus; i++) {
  2931.     switch (lib_idle_pids[i] = fork()) {
  2932.     case -1:
  2933.       perror("netperf: fork");
  2934.       exit(1);
  2935.     case 0:
  2936.       /* we are the child. we could decide to exec some separate */
  2937.       /* program, but that doesn't really seem worthwhile - raj 4/95 */
  2938.  
  2939.       sit_and_spin(i);
  2940.  
  2941.       /* we should never really get here, but if we do, just exit(0) */
  2942.       exit(0);
  2943.       break;
  2944.     default:
  2945.       /* we must be the parent */
  2946.       lib_idle_address[i] = (long *) ((char *)lib_base_pointer + 
  2947.                       (NETPERF_PAGE_SIZE * 
  2948.                        PAGES_PER_CHILD * i));
  2949.       if (debug) {
  2950.     fprintf(where,"lib_idle_address[%d] is %8.8lx\n",
  2951.         i,
  2952.         (unsigned long)lib_idle_address[i]);
  2953.     fflush(where);
  2954.       }
  2955.     }
  2956.   }
  2957. #else
  2958.   /* we are compiled -DWIN32 */
  2959.   if ((lib_base_pointer = malloc(file_size)) == NULL) {
  2960.     fprintf(where,
  2961.         "create_looper_process could not malloc %d bytes\n",
  2962.         file_size);
  2963.     fflush(where);
  2964.     exit(1);
  2965.   }
  2966.  
  2967.   /* now, create all the threads */
  2968.   for(i = 0; i < lib_num_loc_cpus; i++) {
  2969.     long place_holder;
  2970.     if ((lib_idle_pids[i] = CreateThread(0,
  2971.                      0,
  2972.                      (LPTHREAD_START_ROUTINE)sit_and_spin,
  2973.                      (LPVOID)i,
  2974.                      0,
  2975.                      &place_holder)) == NULL ) {
  2976.       fprintf(where,
  2977.           "create_looper_process: CreateThread failled\n");
  2978.       fflush(where);
  2979.       /* I wonder if I need to look for other threads to kill? */
  2980.       exit(1);
  2981.     }
  2982.     lib_idle_address[i] = (long *) ((char *)lib_base_pointer + 
  2983.                     (NETPERF_PAGE_SIZE * 
  2984.                      PAGES_PER_CHILD * i));
  2985.     if (debug) {
  2986.       fprintf(where,"lib_idle_address[%d] is %8.8lx\n",
  2987.           i,
  2988.           (unsigned long)lib_idle_address[i]);
  2989.       fflush(where);
  2990.     }
  2991.   }
  2992. #endif /* WIN32 */
  2993.  
  2994.   /* we need to have the looper processes settled-in before we do */
  2995.   /* anything with them, so lets sleep for say 30 seconds. raj 4/95 */
  2996.  
  2997.   sleep(30);
  2998. }
  2999.  
  3000. #endif /* USE_LOOPER */
  3001.  
  3002.  
  3003. float
  3004. calibrate_local_cpu(local_cpu_rate)
  3005.      float    local_cpu_rate;
  3006. {
  3007.   
  3008.   lib_num_loc_cpus = get_num_cpus();
  3009.  
  3010.   lib_use_idle = 0;
  3011. #ifdef USE_LOOPER
  3012.   /* we want to get the looper processes going */
  3013.   start_looper_processes();
  3014.   lib_use_idle = 1;
  3015. #endif /* USE_LOOPER */
  3016.  
  3017.   if (local_cpu_rate > 0) {
  3018.     /* The user think that he knows what the cpu rate is. We assume */
  3019.     /* that all the processors of an MP system are essentially the */
  3020.     /* same - for this reason we do not have a per processor maxrate. */
  3021.     /* if the machine has processors which are different in */
  3022.     /* performance, the CPU utilization will be skewed. raj 4/95 */
  3023.     lib_local_maxrate = local_cpu_rate;
  3024.   }
  3025.   else {
  3026.     /* if neither USE_LOOPER nor USE_PSTAT are defined, we return a */
  3027.     /* 0.0 to indicate that times or getrusage should be used. raj */
  3028.     /* 4/95 */
  3029.     lib_local_maxrate = (float)0.0;
  3030. #ifdef USE_LOOPER    
  3031.     lib_local_maxrate = calibrate_looper(4,10);
  3032. #endif
  3033. #ifdef USE_PSTAT
  3034. #ifdef PSTAT_IPCINFO
  3035.     /* one version of pstat needs calibration */
  3036.     lib_local_maxrate = calibrate_pstat(4,10);
  3037. #endif /* PSTAT_IPCINFO */
  3038. #endif /* USE_PSTAT */
  3039.   }
  3040.   return lib_local_maxrate;
  3041. }
  3042.  
  3043.  
  3044. float
  3045. calibrate_remote_cpu()
  3046. {
  3047.   float    remrate;
  3048.  
  3049.   netperf_request.content.request_type = CPU_CALIBRATE;
  3050.   send_request();
  3051.   /* we know that calibration will last at least 40 seconds, so go to */
  3052.   /* sleep for that long so the 60 second select in recv_response will */
  3053.   /* not pop. raj 7/95 */
  3054.   sleep(40);
  3055.   recv_response();
  3056.   if (netperf_response.content.serv_errno) {
  3057.     /* initially, silently ignore remote errors and pass */
  3058.     /* back a zero to the caller this should allow us to */
  3059.     /* mix rev 1.0 and rev 1.1 netperfs... */
  3060.     return((float)0.0);
  3061.   }
  3062.   else {
  3063.     /* the rate is the first word of the test_specific data */
  3064.     bcopy((char *)netperf_response.content.test_specific_data,
  3065.       (char *)&remrate,
  3066.       sizeof(remrate));
  3067. /*    remrate = (float) netperf_response.content.test_specific_data[0]; */
  3068.     return(remrate);
  3069.   }    
  3070. }
  3071.  
  3072. int
  3073. msec_sleep( msecs )
  3074.      int msecs;
  3075. {
  3076.  
  3077. #ifdef WIN32
  3078.   int        rval ;
  3079. #endif /* WIN32 */
  3080.  
  3081.   struct timeval interval;
  3082.  
  3083.   interval.tv_sec = msecs / 1000;
  3084.   interval.tv_usec = (msecs - (msecs/1000) *1000) * 1000;
  3085. #ifdef WIN32
  3086.   if (rval = select(0,
  3087. #else
  3088.   if (select(0,
  3089. #endif /* WIN32 */
  3090.          0,
  3091.          0,
  3092.          0,
  3093.          &interval)) {
  3094. #ifdef WIN32
  3095.     if ( rval == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ) {
  3096. #else
  3097.     if (errno == EINTR) {
  3098. #endif /* WIN32 */
  3099.       return(1);
  3100.     }
  3101.     perror("msec_sleep: select");
  3102.     exit(1);
  3103.   }
  3104.   return(0);
  3105. }
  3106.  
  3107. #ifdef HISTOGRAM
  3108. /* hist.c
  3109.  
  3110.    Given a time difference in microseconds, increment one of 61
  3111.    different buckets: 
  3112.    
  3113.    0 - 9 in increments of 100 usecs
  3114.    1 - 9 in increments of 1 msec
  3115.    1 - 9 in increments of 10 msecs
  3116.    1 - 9 in increments of 100 msecs
  3117.    1 - 9 in increments of 1 sec
  3118.    1 - 9 in increments of 10 sec
  3119.    > 100 secs
  3120.    
  3121.    This will allow any time to be recorded to within an accuracy of
  3122.    10%, and provides a compact  representation for capturing the
  3123.    distribution of a large number of time differences (e.g.
  3124.    request-response latencies).
  3125.    
  3126.    Colin Low  10/6/93
  3127. */
  3128.  
  3129. /* #include "sys.h" */
  3130.  
  3131. /*#define HIST_TEST*/
  3132.  
  3133. HIST HIST_new(void){
  3134.    HIST h;
  3135.    if((h = (HIST) malloc(sizeof(struct histogram_struct))) == NULL) {
  3136.      perror("HIST_new - malloc failed");
  3137.      exit(1);
  3138.    }
  3139.    HIST_clear(h);
  3140.    return h;
  3141. }
  3142.  
  3143. void HIST_clear(HIST h){
  3144.    int i;
  3145.    for(i = 0; i < 10; i++){
  3146.       h->tenth_msec[i] = 0;
  3147.       h->unit_msec[i] = 0;
  3148.       h->ten_msec[i] = 0;
  3149.       h->hundred_msec[i] = 0;
  3150.       h->unit_sec[i] = 0;
  3151.       h->ten_sec[i] = 0;
  3152.    }
  3153.    h->ridiculous = 0;
  3154.    h->total = 0;
  3155. }
  3156.  
  3157. void HIST_add(register HIST h, int time_delta){
  3158.    register int val;
  3159.    h->total++;
  3160.    val = time_delta/100;
  3161.    if(val <= 9) h->tenth_msec[val]++;
  3162.    else {
  3163.       val = val/10;
  3164.       if(val <= 9) h->unit_msec[val]++;
  3165.       else {
  3166.          val = val/10;
  3167.          if(val <= 9) h->ten_msec[val]++;
  3168.          else {
  3169.             val = val/10;
  3170.             if(val <= 9) h->hundred_msec[val]++;
  3171.             else {
  3172.                val = val/10;
  3173.                if(val <= 9) h->unit_sec[val]++;
  3174.                else {
  3175.                    val = val/10;
  3176.                    if(val <= 9) h->ten_sec[val]++;
  3177.                    else h->ridiculous++;
  3178.                }
  3179.             }
  3180.          }
  3181.       }
  3182.    }
  3183. }
  3184.  
  3185. #define RB_printf printf
  3186.  
  3187. void output_row(FILE *fd, char *title, int *row){
  3188.    register int i;
  3189.    RB_printf("%s", title);
  3190.    for(i = 0; i < 10; i++) RB_printf(": %4d", row[i]);
  3191.    RB_printf("\n");
  3192. }
  3193.  
  3194.  
  3195. void HIST_report(HIST h){
  3196.    output_row(stdout, "TENTH_MSEC    ", h->tenth_msec);
  3197.    output_row(stdout, "UNIT_MSEC     ", h->unit_msec);
  3198.    output_row(stdout, "TEN_MSEC      ", h->ten_msec);
  3199.    output_row(stdout, "HUNDRED_MSEC  ", h->hundred_msec);
  3200.    output_row(stdout, "UNIT_SEC      ", h->unit_sec);
  3201.    output_row(stdout, "TEN_SEC       ", h->ten_sec);
  3202.    RB_printf(">100_SECS: %d\n", h->ridiculous);
  3203.    RB_printf("HIST_TOTAL:      %d\n", h->total);
  3204. }
  3205.  
  3206.  /* return the difference (in micro seconds) between two timeval */
  3207.  /* timestamps */
  3208. int
  3209. delta_micro(struct timeval *begin,struct timeval *end)
  3210.  
  3211. {
  3212.  
  3213.   int usecs, secs;
  3214.  
  3215.   if (end->tv_usec < begin->tv_usec) {
  3216.     /* borrow a second from the tv_sec */
  3217.     end->tv_usec += 1000000;
  3218.     end->tv_sec--;
  3219.   }
  3220.   usecs = end->tv_usec - begin->tv_usec;
  3221.   secs  = end->tv_sec - begin->tv_sec;
  3222.  
  3223.   usecs += (secs * 1000000);
  3224.  
  3225.   return(usecs);
  3226.  
  3227. }
  3228.  
  3229. #endif /* HISTOGRAM */
  3230.  
  3231. #ifdef DO_DLPI
  3232.  
  3233. int
  3234. put_control(fd, len, pri, ack)
  3235.      int fd, len, pri, ack;
  3236. {
  3237.   int error;
  3238.   int flags = 0;
  3239.   dl_error_ack_t *err_ack = (dl_error_ack_t *)control_data;
  3240.  
  3241.   control_message.len = len;
  3242.  
  3243.   if ((error = putmsg(fd, &control_message, 0, pri)) < 0 ) {
  3244.     fprintf(where,"put_control: putmsg error %d\n",error);
  3245.     fflush(where);
  3246.     return(-1);
  3247.   }
  3248.   if ((error = getmsg(fd, &control_message, 0, &flags)) < 0) {
  3249.     fprintf(where,"put_control: getsmg error %d\n",error);
  3250.     fflush(where);
  3251.     return(-1);
  3252.   }
  3253.   if (err_ack->dl_primitive != ack) {
  3254.     fprintf(where,"put_control: acknowledgement error wanted %u got %u \n",
  3255.         ack,err_ack->dl_primitive);
  3256.     if (err_ack->dl_primitive == DL_ERROR_ACK) {
  3257.       fprintf(where,"             dl_error_primitive: %u\n",
  3258.           err_ack->dl_error_primitive);
  3259.       fprintf(where,"             dl_errno:           %u\n",
  3260.           err_ack->dl_errno);
  3261.       fprintf(where,"             dl_unix_errno       %u\n",
  3262.           err_ack->dl_unix_errno);
  3263.     }
  3264.     fflush(where);
  3265.     return(-1);
  3266.   }
  3267.  
  3268.   return(0);
  3269. }
  3270.     
  3271. int
  3272. dl_open(devfile,ppa)
  3273.      char devfile[];
  3274.      int ppa;
  3275.      
  3276. {
  3277.   int fd;
  3278.   dl_attach_req_t *attach_req = (dl_attach_req_t *)control_data;
  3279.  
  3280.   if ((fd = open(devfile, O_RDWR)) == -1) {
  3281.     fprintf(where,"netperf: dl_open: open of %s failed, errno = %d\n",
  3282.         devfile,
  3283.         errno);
  3284.     return(-1);
  3285.   }
  3286.  
  3287.   attach_req->dl_primitive = DL_ATTACH_REQ;
  3288.   attach_req->dl_ppa = ppa;
  3289.  
  3290.   if (put_control(fd, sizeof(dl_attach_req_t), 0, DL_OK_ACK) < 0) {
  3291.     fprintf(where,
  3292.         "netperf: dl_open: could not send control message, errno = %d\n",
  3293.         errno);
  3294.     return(-1);
  3295.   }
  3296.   return(fd);
  3297. }
  3298.  
  3299. int
  3300. dl_bind(fd, sap, mode, dlsap_ptr, dlsap_len)
  3301.      int fd, sap, mode;
  3302.      char *dlsap_ptr;
  3303.      int *dlsap_len;
  3304. {
  3305.   dl_bind_req_t *bind_req = (dl_bind_req_t *)control_data;
  3306.   dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)control_data;
  3307.  
  3308.   bind_req->dl_primitive = DL_BIND_REQ;
  3309.   bind_req->dl_sap = sap;
  3310.   bind_req->dl_max_conind = 1;
  3311.   bind_req->dl_service_mode = mode;
  3312.   bind_req->dl_conn_mgmt = 0;
  3313.   bind_req->dl_xidtest_flg = 0;
  3314.  
  3315.   if (put_control(fd, sizeof(dl_bind_req_t), 0, DL_BIND_ACK) < 0) {
  3316.     fprintf(where,
  3317.         "netperf: dl_bind: could not send control message, errno = %d\n",
  3318.         errno);
  3319.     return(-1);
  3320.   }
  3321.  
  3322.   /* at this point, the control_data portion of the control message */
  3323.   /* structure should contain a DL_BIND_ACK, which will have a full */
  3324.   /* DLSAP in it. we want to extract this and pass it up so that    */
  3325.   /* it can be passed around. */
  3326.   if (*dlsap_len >= bind_ack->dl_addr_length) {
  3327.     bcopy((char *)bind_ack+bind_ack->dl_addr_offset,
  3328.           dlsap_ptr,
  3329.           bind_ack->dl_addr_length);
  3330.     *dlsap_len = bind_ack->dl_addr_length;
  3331.     return(0);
  3332.   }
  3333.   else { 
  3334.     return (-1); 
  3335.   }
  3336. }
  3337.  
  3338. int
  3339. dl_connect(fd, rem_addr, rem_addr_len)
  3340.      int fd;
  3341.      unsigned char *rem_addr;
  3342.      int rem_addr_len;
  3343. {
  3344.   dl_connect_req_t *connection_req = (dl_connect_req_t *)control_data;
  3345.   dl_connect_con_t *connection_con = (dl_connect_con_t *)control_data;
  3346.   struct pollfd pinfo;
  3347.  
  3348.   int flags = 0;
  3349.  
  3350.   /* this is here on the off chance that we really want some data */
  3351.   u_long data_area[512];
  3352.   struct strbuf data_message;
  3353.  
  3354.   int error;
  3355.  
  3356.   data_message.maxlen = 2048;
  3357.   data_message.len = 0;
  3358.   data_message.buf = (char *)data_area;
  3359.  
  3360.   connection_req->dl_primitive = DL_CONNECT_REQ;
  3361.   connection_req->dl_dest_addr_length = rem_addr_len;
  3362.   connection_req->dl_dest_addr_offset = sizeof(dl_connect_req_t);
  3363.   connection_req->dl_qos_length = 0;
  3364.   connection_req->dl_qos_offset = 0;
  3365.   bcopy (rem_addr, 
  3366.      (unsigned char *)control_data + sizeof(dl_connect_req_t),
  3367.      rem_addr_len);
  3368.  
  3369.   /* well, I would call the put_control routine here, but the sequence */
  3370.   /* of connection stuff with DLPI is a bit screwey with all this */
  3371.   /* message passing - Toto, I don't think were in Berkeley anymore. */
  3372.  
  3373.   control_message.len = sizeof(dl_connect_req_t) + rem_addr_len;
  3374.   if ((error = putmsg(fd,&control_message,0,0)) !=0) {
  3375.     fprintf(where,"dl_connect: putmsg failure, errno = %d, error 0x%x \n",
  3376.             errno,error);
  3377.     fflush(where);
  3378.     return(-1);
  3379.   };
  3380.  
  3381.   pinfo.fd = fd;
  3382.   pinfo.events = POLLIN | POLLPRI;
  3383.   pinfo.revents = 0;
  3384.  
  3385.   if ((error = getmsg(fd,&control_message,&data_message,&flags)) != 0) {
  3386.     fprintf(where,"dl_connect: getmsg failure, errno = %d, error 0x%x \n",
  3387.             errno,error);
  3388.     fflush(where);
  3389.     return(-1);
  3390.   }
  3391.   while (control_data[0] == DL_TEST_CON) {
  3392.     /* i suppose we spin until we get an error, or a connection */
  3393.     /* indication */
  3394.     if((error = getmsg(fd,&control_message,&data_message,&flags)) !=0) {
  3395.        fprintf(where,"dl_connect: getmsg failure, errno = %d, error = 0x%x\n",
  3396.                errno,error);
  3397.        fflush(where);
  3398.        return(-1);
  3399.     }
  3400.   }
  3401.  
  3402.   /* we are out - it either worked or it didn't - which was it? */
  3403.   if (control_data[0] == DL_CONNECT_CON) {
  3404.     return(0);
  3405.   }
  3406.   else {
  3407.     return(-1);
  3408.   }
  3409. }
  3410.  
  3411. int
  3412. dl_accept(fd, rem_addr, rem_addr_len)
  3413.      int fd;
  3414.      unsigned char *rem_addr;
  3415.      int rem_addr_len;
  3416. {
  3417.   dl_connect_ind_t *connect_ind = (dl_connect_ind_t *)control_data;
  3418.   dl_connect_res_t *connect_res = (dl_connect_res_t *)control_data;
  3419.   int tmp_cor;
  3420.   int flags = 0;
  3421.  
  3422.   /* hang around and wait for a connection request */
  3423.   getmsg(fd,&control_message,0,&flags);
  3424.   while (control_data[0] != DL_CONNECT_IND) {
  3425.     getmsg(fd,&control_message,0,&flags);
  3426.   }
  3427.  
  3428.   /* now respond to the request. at some point, we may want to be sure */
  3429.   /* that the connection came from the correct station address, but */
  3430.   /* will assume that we do not have to worry about it just now. */
  3431.  
  3432.   tmp_cor = connect_ind->dl_correlation;
  3433.  
  3434.   connect_res->dl_primitive = DL_CONNECT_RES;
  3435.   connect_res->dl_correlation = tmp_cor;
  3436.   connect_res->dl_resp_token = 0;
  3437.   connect_res->dl_qos_length = 0;
  3438.   connect_res->dl_qos_offset = 0;
  3439.   connect_res->dl_growth = 0;
  3440.  
  3441.   return(put_control(fd, sizeof(dl_connect_res_t), 0, DL_OK_ACK));
  3442.  
  3443. }
  3444.  
  3445. int
  3446. dl_set_window(fd, window)
  3447.      int fd, window;
  3448. {
  3449.   return(0);
  3450. }
  3451.  
  3452. void
  3453. dl_stats(fd)
  3454.      int fd;
  3455. {
  3456. }
  3457.  
  3458. int
  3459. dl_send_disc(fd)
  3460.      int fd;
  3461. {
  3462. }
  3463.  
  3464. int
  3465. dl_recv_disc(fd)
  3466.      int fd;
  3467. {
  3468. }
  3469. #endif /* DO_DLPI*/
  3470.  
  3471.  /* these routines for confidence intervals are courtesy of IBM. They */
  3472.  /* have been modified slightly for more general usage beyond TCP/UDP */
  3473.  /* tests. raj 11/94 I would suspect that this code carries an IBM */
  3474.  /* copyright that is much the same as that for the original HP */
  3475.  /* netperf code */
  3476. int    confidence_iterations; /* for iterations */
  3477.  
  3478. double  
  3479.   result_confid=-10.0,
  3480.   loc_cpu_confid=-10.0,
  3481.   rem_cpu_confid=-10.0,
  3482.  
  3483.   measured_sum_result=0.0, 
  3484.   measured_square_sum_result=0.0,
  3485.   measured_mean_result=0.0, 
  3486.   measured_var_result=0.0, 
  3487.  
  3488.   measured_sum_local_cpu=0.0,
  3489.   measured_square_sum_local_cpu=0.0,
  3490.   measured_mean_local_cpu=0.0,
  3491.   measured_var_local_cpu=0.0, 
  3492.  
  3493.   measured_sum_remote_cpu=0.0,
  3494.   measured_square_sum_remote_cpu=0.0,
  3495.   measured_mean_remote_cpu=0.0,
  3496.   measured_var_remote_cpu=0.0, 
  3497.   
  3498.   measured_sum_local_service_demand=0.0,
  3499.   measured_square_sum_local_service_demand=0.0,
  3500.   measured_mean_local_service_demand=0.0,
  3501.   measured_var_local_service_demand=0.0,
  3502.  
  3503.   measured_sum_remote_service_demand=0.0,
  3504.   measured_square_sum_remote_service_demand=0.0,
  3505.   measured_mean_remote_service_demand=0.0,
  3506.   measured_var_remote_service_demand=0.0,
  3507.  
  3508.   measured_sum_local_time=0.0,
  3509.   measured_square_sum_local_time=0.0,
  3510.   measured_mean_local_time=0.0,
  3511.   measured_var_local_time=0.0,
  3512.  
  3513.   measured_mean_remote_time=0.0, 
  3514.   
  3515.   measured_fails,
  3516.   measured_local_results,
  3517.   confidence=-10.0;
  3518. /*  interval=0.1; */
  3519.  
  3520. /************************************************************************/
  3521. /*                                         */
  3522. /*         Constants for Confidence Intervals                          */
  3523. /*                                         */
  3524. /************************************************************************/
  3525. void 
  3526. init_stat()
  3527. {
  3528.     measured_sum_result=0.0;
  3529.     measured_square_sum_result=0.0;
  3530.     measured_mean_result=0.0;
  3531.     measured_var_result=0.0;
  3532.  
  3533.     measured_sum_local_cpu=0.0;
  3534.     measured_square_sum_local_cpu=0.0;
  3535.     measured_mean_local_cpu=0.0;
  3536.     measured_var_local_cpu=0.0;
  3537.  
  3538.     measured_sum_remote_cpu=0.0;
  3539.     measured_square_sum_remote_cpu=0.0;
  3540.     measured_mean_remote_cpu=0.0;
  3541.     measured_var_remote_cpu=0.0;
  3542.  
  3543.     measured_sum_local_service_demand=0.0;
  3544.     measured_square_sum_local_service_demand=0.0;
  3545.     measured_mean_local_service_demand=0.0;
  3546.     measured_var_local_service_demand=0.0;
  3547.  
  3548.     measured_sum_remote_service_demand=0.0;
  3549.     measured_square_sum_remote_service_demand=0.0;
  3550.     measured_mean_remote_service_demand=0.0;
  3551.     measured_var_remote_service_demand=0.0;
  3552.  
  3553.     measured_sum_local_time=0.0;
  3554.     measured_square_sum_local_time=0.0;
  3555.     measured_mean_local_time=0.0;
  3556.     measured_var_local_time=0.0;
  3557.  
  3558.     measured_mean_remote_time=0.0;
  3559.  
  3560.     measured_fails = 0.0;
  3561.     measured_local_results=0.0,
  3562.     confidence=-10.0;
  3563. }
  3564.  
  3565.  /* this routine does a simple table lookup for some statistical */
  3566.  /* function that I would remember if I stayed awake in my probstats */
  3567.  /* class... raj 11/94 */
  3568. double 
  3569. confid(level,freedom)
  3570. int    level;
  3571. int    freedom;
  3572. {
  3573. double  t99[35],t95[35];
  3574.  
  3575.    t95[1]=12.706;
  3576.    t95[2]= 4.303;
  3577.    t95[3]= 3.182;
  3578.    t95[4]= 2.776;
  3579.    t95[5]= 2.571;
  3580.    t95[6]= 2.447;
  3581.    t95[7]= 2.365;
  3582.    t95[8]= 2.306;
  3583.    t95[9]= 2.262;
  3584.    t95[10]= 2.228;
  3585.    t95[11]= 2.201;
  3586.    t95[12]= 2.179;
  3587.    t95[13]= 2.160;
  3588.    t95[14]= 2.145;
  3589.    t95[15]= 2.131;
  3590.    t95[16]= 2.120;
  3591.    t95[17]= 2.110;
  3592.    t95[18]= 2.101;
  3593.    t95[19]= 2.093;
  3594.    t95[20]= 2.086;
  3595.    t95[21]= 2.080;
  3596.    t95[22]= 2.074;
  3597.    t95[23]= 2.069;
  3598.    t95[24]= 2.064;
  3599.    t95[25]= 2.060;
  3600.    t95[26]= 2.056;
  3601.    t95[27]= 2.052;
  3602.    t95[28]= 2.048;
  3603.    t95[29]= 2.045;
  3604.    t95[30]= 2.042;
  3605.    
  3606.    t99[1]=63.657;
  3607.    t99[2]= 9.925;
  3608.    t99[3]= 5.841;
  3609.    t99[4]= 4.604;
  3610.    t99[5]= 4.032;
  3611.    t99[6]= 3.707;
  3612.    t99[7]= 3.499;
  3613.    t99[8]= 3.355;
  3614.    t99[9]= 3.250;
  3615.    t99[10]= 3.169;
  3616.    t99[11]= 3.106;
  3617.    t99[12]= 3.055;
  3618.    t99[13]= 3.012;
  3619.    t99[14]= 2.977;
  3620.    t99[15]= 2.947;
  3621.    t99[16]= 2.921;
  3622.    t99[17]= 2.898;
  3623.    t99[18]= 2.878;
  3624.    t99[19]= 2.861;
  3625.    t99[20]= 2.845;
  3626.    t99[21]= 2.831;
  3627.    t99[22]= 2.819;
  3628.    t99[23]= 2.807;
  3629.    t99[24]= 2.797;
  3630.    t99[25]= 2.787;
  3631.    t99[26]= 2.779;
  3632.    t99[27]= 2.771;
  3633.    t99[28]= 2.763;
  3634.    t99[29]= 2.756;
  3635.    t99[30]= 2.750;
  3636.    
  3637.    if(level==95){
  3638.        return(t95[freedom]);
  3639.    } else if(level==99){
  3640.         return(t99[freedom]);
  3641.    } else{
  3642.         return(0);
  3643.    }
  3644. }
  3645.  
  3646. void
  3647. calculate_confidence(confidence_iterations,
  3648.              time,
  3649.              result,
  3650.              loc_cpu,
  3651.              rem_cpu,
  3652.              loc_sd,
  3653.              rem_sd)
  3654. int    confidence_iterations;
  3655. float   time;
  3656. double    result;
  3657. float    loc_cpu;
  3658. float    rem_cpu;
  3659. float   loc_sd;
  3660. float   rem_sd;
  3661. {
  3662.  
  3663.   if (debug) {
  3664.     fprintf(where,
  3665.         "calculate_confidence: itr  %d; time %f; res  %f\n",
  3666.         confidence_iterations,
  3667.         time,
  3668.         result);
  3669.     fprintf(where,
  3670.         "                               lcpu %f; rcpu %f\n",
  3671.         loc_cpu,
  3672.         rem_cpu);
  3673.     fprintf(where,
  3674.         "                               lsdm %f; rsdm %f\n",
  3675.         loc_sd,
  3676.         rem_sd);
  3677.     fflush(where);
  3678.   }
  3679.  
  3680.   /* the test time */
  3681.   measured_sum_local_time        += 
  3682.     (double) time;
  3683.   measured_square_sum_local_time    += 
  3684.     (double) time*time;
  3685.   measured_mean_local_time        =  
  3686.     (double) measured_sum_local_time/confidence_iterations;
  3687.   measured_var_local_time        =  
  3688.     (double) measured_square_sum_local_time/confidence_iterations
  3689.       -measured_mean_local_time*measured_mean_local_time;
  3690.   
  3691.   /* the test result */
  3692.   measured_sum_result        += 
  3693.     (double) result;
  3694.   measured_square_sum_result    += 
  3695.     (double) result*result;
  3696.   measured_mean_result        =  
  3697.     (double) measured_sum_result/confidence_iterations;
  3698.   measured_var_result        =  
  3699.     (double) measured_square_sum_result/confidence_iterations
  3700.       -measured_mean_result*measured_mean_result;
  3701.  
  3702.   /* local cpu utilization */
  3703.   measured_sum_local_cpu    += 
  3704.     (double) loc_cpu;
  3705.   measured_square_sum_local_cpu    += 
  3706.     (double) loc_cpu*loc_cpu;
  3707.   measured_mean_local_cpu    = 
  3708.     (double) measured_sum_local_cpu/confidence_iterations;
  3709.   measured_var_local_cpu    = 
  3710.     (double) measured_square_sum_local_cpu/confidence_iterations
  3711.       -measured_mean_local_cpu*measured_mean_local_cpu;
  3712.  
  3713.   /* remote cpu util */
  3714.   measured_sum_remote_cpu    +=
  3715.     (double) rem_cpu;
  3716.   measured_square_sum_remote_cpu+=
  3717.     (double) rem_cpu*rem_cpu;
  3718.   measured_mean_remote_cpu    = 
  3719.     (double) measured_sum_remote_cpu/confidence_iterations;
  3720.   measured_var_remote_cpu    = 
  3721.     (double) measured_square_sum_remote_cpu/confidence_iterations
  3722.       -measured_mean_remote_cpu*measured_mean_remote_cpu;
  3723.  
  3724.   /* local service demand */
  3725.   measured_sum_local_service_demand    +=
  3726.     (double) loc_sd;
  3727.   measured_square_sum_local_service_demand+=
  3728.     (double) loc_sd*loc_sd;
  3729.   measured_mean_local_service_demand    = 
  3730.     (double) measured_sum_local_service_demand/confidence_iterations;
  3731.   measured_var_local_service_demand    = 
  3732.     (double) measured_square_sum_local_service_demand/confidence_iterations
  3733.       -measured_mean_local_service_demand*measured_mean_local_service_demand;
  3734.  
  3735.   /* remote service demand */
  3736.   measured_sum_remote_service_demand    +=
  3737.     (double) rem_sd;
  3738.   measured_square_sum_remote_service_demand+=
  3739.     (double) rem_sd*rem_sd;
  3740.   measured_mean_remote_service_demand    = 
  3741.     (double) measured_sum_remote_service_demand/confidence_iterations;
  3742.   measured_var_remote_service_demand    = 
  3743.     (double) measured_square_sum_remote_service_demand/confidence_iterations
  3744.       -measured_mean_remote_service_demand*measured_mean_remote_service_demand;
  3745.  
  3746.   if(confidence_iterations>1){ 
  3747.      result_confid= (double) interval - 
  3748.        2.0 * confid(confidence_level,confidence_iterations-1)* 
  3749.      sqrt(measured_var_result/(confidence_iterations-1.0)) / 
  3750.        measured_mean_result;
  3751.  
  3752.      loc_cpu_confid= (double) interval - 
  3753.        2.0 * confid(confidence_level,confidence_iterations-1)* 
  3754.      sqrt(measured_var_local_cpu/(confidence_iterations-1.0)) / 
  3755.        measured_mean_local_cpu;
  3756.  
  3757.      rem_cpu_confid= (double) interval - 
  3758.        2.0 * confid(confidence_level,confidence_iterations-1)*
  3759.      sqrt(measured_var_remote_cpu/(confidence_iterations-1.0)) / 
  3760.        measured_mean_remote_cpu;
  3761.  
  3762.      if(debug){
  3763.        printf("Conf_itvl %2d: results:%4.1f%% loc_cpu:%4.1f%% rem_cpu:%4.1f%%\n",
  3764.           confidence_iterations,
  3765.           (interval-result_confid)*100.0,
  3766.           (interval-loc_cpu_confid)*100.0,
  3767.           (interval-rem_cpu_confid)*100.0);
  3768.      }
  3769.  
  3770.      confidence = min(min(result_confid,loc_cpu_confid),rem_cpu_confid);
  3771.  
  3772.   }
  3773. }
  3774.  
  3775.  /* here ends the IBM code */
  3776.  
  3777. void
  3778. retrieve_confident_values(elapsed_time,
  3779.               thruput,
  3780.               local_cpu_utilization,
  3781.               remote_cpu_utilization,
  3782.               local_service_demand,
  3783.               remote_service_demand)
  3784.      float  *elapsed_time;
  3785.      double *thruput;
  3786.      float  *local_cpu_utilization;
  3787.      float  *remote_cpu_utilization;
  3788.      float  *local_service_demand;
  3789.      float  *remote_service_demand;
  3790.  
  3791. {
  3792.   *elapsed_time            = measured_mean_local_time;
  3793.   *thruput                 = measured_mean_result;
  3794.   *local_cpu_utilization   = measured_mean_local_cpu;
  3795.   *remote_cpu_utilization  = measured_mean_remote_cpu;
  3796.   *local_service_demand    = measured_mean_local_service_demand;
  3797.   *remote_service_demand   = measured_mean_remote_service_demand;
  3798. }
  3799.  
  3800.  /* display_confidence() is called when we could not achieve the */
  3801.  /* desirec confidence in the results. it will print the achieved */
  3802.  /* confidence to "where" raj 11/94 */
  3803. void
  3804. display_confidence()
  3805.  
  3806. {
  3807.   fprintf(where,
  3808.       "!!! WARNING\n");
  3809.   fprintf(where,
  3810.       "!!! Desired confidence was not achieved within ");
  3811.   fprintf(where,
  3812.       "the specified iterations.\n");
  3813.   fprintf(where,
  3814.       "!!! This implies that there was variability in ");
  3815.   fprintf(where,
  3816.       "the test environment that\n");
  3817.   fprintf(where,
  3818.       "!!! must be investigated before going further.\n");
  3819.   fprintf(where,
  3820.       "!!! Confidence intervals: Throughput      : %4.1f%%\n",
  3821.       100.0 * (interval - result_confid));
  3822.   fprintf(where,
  3823.       "!!!                       Local CPU util  : %4.1f%%\n",
  3824.       100.0 * (interval - loc_cpu_confid));
  3825.   fprintf(where,
  3826.       "!!!                       Remote CPU util : %4.1f%%\n\n",
  3827.       100.0 * (interval - rem_cpu_confid));
  3828. }
  3829.