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