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(%u) failed!\n", sizeof(struct ring_elt));
1257 exit(1);
1258 }
1259 /* remember the first one so we can close the ring at the end */
1260 if (i == 1) {
1261 first_link = temp_link;
1262 }
1263 temp_link->buffer_base = (char *)malloc(malloc_size);
1264 if (temp_link == NULL) {
1265 printf("malloc(%d) failed!\n", malloc_size);
1266 exit(1);
1267 }
1268
1269 #ifndef WIN32
1270 temp_link->buffer_ptr = (char *)(( (long)(temp_link->buffer_base) +
1271 (long)alignment - 1) &
1272 ~((long)alignment - 1));
1273 #else
1274 temp_link->buffer_ptr = (char *)(( (ULONG_PTR)(temp_link->buffer_base) +
1275 (ULONG_PTR)alignment - 1) &
1276 ~((ULONG_PTR)alignment - 1));
1277 #endif
1278 temp_link->buffer_ptr += offset;
1279 /* is where the buffer fill code goes. */
1280 if (do_fill) {
1281 char *bufptr = temp_link->buffer_ptr;
1282 bytes_left = buffer_size;
1283 while (bytes_left) {
1284 if (((bytes_read = (int)fread(bufptr,
1285 1,
1286 bytes_left,
1287 fill_source)) == 0) &&
1288 (feof(fill_source))){
1289 rewind(fill_source);
1290 }
1291 bufptr += bytes_read;
1292 bytes_left -= bytes_read;
1293 }
1294 }
1295 else {
1296 /* use the default fill to ID our data traffic on the
1297 network. it ain't exactly pretty, but it should work */
1298 int j;
1299 char *bufptr = temp_link->buffer_ptr;
1300 for (j = 0; j < buffer_size; j++) {
1301 bufptr[j] = default_fill[fill_cursor];
1302 fill_cursor += 1;
1303 /* the Windows DDK compiler with an x86_64 target wants a cast
1304 here */
1305 if (fill_cursor > (int)strlen(default_fill)) {
1306 fill_cursor = 0;
1307 }
1308 }
1309
1310 }
1311 temp_link->next = prev_link;
1312 prev_link = temp_link;
1313 }
1314 if (first_link) { /* SAF Prefast made me do it... */
1315 first_link->next = temp_link;
1316 }
1317
1318 return(first_link); /* it's a circle, doesn't matter which we return */
1319 }
1320
1321 /* this routine will dirty the first dirty_count bytes of the
1322 specified buffer and/or read clean_count bytes from the buffer. it
1323 will go N bytes at a time, the only question is how large should N
1324 be and if we should be going continguously, or based on some
1325 assumption of cache line size */
1326
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 int counter = 0;
1680 fprintf(where,"request contents:\n");
1681 for (counter = 0; counter < ((sizeof(netperf_request)/4)-3); counter += 4) {
1682 fprintf(where,"%d:\t%8x %8x %8x %8x \t|%4.4s| |%4.4s| |%4.4s| |%4.4s|\n",
1683 counter,
1684 request_array[counter],
1685 request_array[counter+1],
1686 request_array[counter+2],
1687 request_array[counter+3],
1688 (char *)&request_array[counter],
1689 (char *)&request_array[counter+1],
1690 (char *)&request_array[counter+2],
1691 (char *)&request_array[counter+3]);
1692 }
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 int counter = 0;
1711
1712 fprintf(where,"response contents\n");
1713 for (counter = 0; counter < ((sizeof(netperf_response)/4)-3); counter += 4) {
1714 fprintf(where,"%d:\t%8x %8x %8x %8x \t>%4.4s< >%4.4s< >%4.4s< >%4.4s<\n",
1715 counter,
1716 response_array[counter],
1717 response_array[counter+1],
1718 response_array[counter+2],
1719 response_array[counter+3],
1720 (char *)&response_array[counter],
1721 (char *)&response_array[counter+1],
1722 (char *)&response_array[counter+2],
1723 (char *)&response_array[counter+3]);
1724 }
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 int counter=0;
2117
2118 /* display the contents of the request if the debug level is high */
2119 /* enough. otherwise, just send the darned thing ;-) */
2120
2121 if (debug > 1) {
2122 fprintf(where,"entered send_request...contents before htonl:\n");
2123 dump_request();
2124 }
2125
2126 /* pass the processor affinity request value to netserver */
2127 /* this is a kludge and I know it. sgb 8/11/04 */
2128
2129 netperf_request.content.dummy = remote_proc_affinity;
2130
2131 /* put the entire request array into network order. We do this */
2132 /* arbitrarily rather than trying to figure-out just how much */
2133 /* of the request array contains real information. this should */
2134 /* be simpler, and at any rate, the performance of sending */
2135 /* control messages for this benchmark is not of any real */
2136 /* concern. */
2137
2138 for (counter=0;counter < sizeof(netperf_request)/4; counter++) {
2139 request_array[counter] = htonl(request_array[counter]);
2140 }
2141
2142 if (debug > 1) {
2143 fprintf(where,"send_request...contents after htonl:\n");
2144 dump_request();
2145
2146 fprintf(where,
2147 "\nsend_request: about to send %u bytes from %p\n",
2148 sizeof(netperf_request),
2149 &netperf_request);
2150 fflush(where);
2151 }
2152
2153 if (send(netlib_control,
2154 (char *)&netperf_request,
2155 sizeof(netperf_request),
2156 0) != sizeof(netperf_request)) {
2157 perror("send_request: send call failure");
2158
2159 exit(1);
2160 }
2161 }
2162
2163 /***********************************************************************/
2164 /* */
2165 /* send_response() */
2166 /* */
2167 /* send a netperf response on the control socket to the remote half of */
2168 /* the connection. to get us closer to intervendor interoperability, */
2169 /* we will call htonl on each of the int that compose the message to */
2170 /* be sent. the other half of the connection will call the ntohl */
2171 /* routine to undo any changes that may have been made... */
2172 /* */
2173 /***********************************************************************/
2174
2175 void
send_response()2176 send_response()
2177 {
2178 int counter=0;
2179 int bytes_sent;
2180
2181 /* display the contents of the request if the debug level is high */
2182 /* enough. otherwise, just send the darned thing ;-) */
2183
2184 if (debug > 1) {
2185 fprintf(where,
2186 "send_response: contents of %u ints before htonl\n",
2187 sizeof(netperf_response)/4);
2188 dump_response();
2189 }
2190
2191 /* put the entire response_array into network order. We do this */
2192 /* arbitrarily rather than trying to figure-out just how much of the */
2193 /* request array contains real information. this should be simpler, */
2194 /* and at any rate, the performance of sending control messages for */
2195 /* this benchmark is not of any real concern. */
2196
2197 for (counter=0;counter < sizeof(netperf_response)/4; counter++) {
2198 response_array[counter] = htonl(response_array[counter]);
2199 }
2200
2201 if (debug > 1) {
2202 fprintf(where,
2203 "send_response: contents after htonl\n");
2204 dump_response();
2205 fprintf(where,
2206 "about to send %u bytes from %p\n",
2207 sizeof(netperf_response),
2208 &netperf_response);
2209 fflush(where);
2210 }
2211
2212 /*KC*/
2213 if ((bytes_sent = send(server_sock,
2214 (char *)&netperf_response,
2215 sizeof(netperf_response),
2216 0)) != sizeof(netperf_response)) {
2217 perror("send_response: send call failure");
2218 fprintf(where, "BytesSent: %d\n", bytes_sent);
2219 exit(1);
2220 }
2221
2222 }
2223
2224 /***********************************************************************/
2225 /* */
2226 /* recv_request() */
2227 /* */
2228 /* receive the remote's request on the control socket. we will put */
2229 /* the entire response into host order before giving it to the */
2230 /* calling routine. hopefully, this will go most of the way to */
2231 /* insuring intervendor interoperability. if there are any problems, */
2232 /* we will just punt the entire situation. */
2233 /* */
2234 /***********************************************************************/
2235
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 int 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 int 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 %d\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