diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:31 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:31 -0800 |
commit | 8eb453f761a608a321986303fd8fefecb463fd6a (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 | |
parent | acbeb739a2260972afbd58233fc8939fe5014e3c (diff) | |
download | netperf-8eb453f761a608a321986303fd8fefecb463fd6a.tar.gz |
auto import from //depot/cupcake/@135843
-rw-r--r-- | Android.mk | 42 | ||||
-rw-r--r-- | MODULE_LICENSE_HP | 43 | ||||
-rw-r--r-- | config.h | 351 | ||||
-rw-r--r-- | hist.h | 116 | ||||
-rw-r--r-- | netcpu.h | 19 | ||||
-rw-r--r-- | netcpu_kstat.c | 415 | ||||
-rw-r--r-- | netcpu_kstat10.c | 559 | ||||
-rw-r--r-- | netcpu_looper.c | 656 | ||||
-rw-r--r-- | netcpu_none.c | 67 | ||||
-rw-r--r-- | netcpu_ntperf.c | 497 | ||||
-rw-r--r-- | netcpu_osx.c | 149 | ||||
-rw-r--r-- | netcpu_perfstat.c | 351 | ||||
-rw-r--r-- | netcpu_procstat.c | 265 | ||||
-rw-r--r-- | netcpu_pstat.c | 307 | ||||
-rw-r--r-- | netcpu_pstatnew.c | 398 | ||||
-rw-r--r-- | netcpu_sysctl.c | 127 | ||||
-rw-r--r-- | netlib.c | 4161 | ||||
-rw-r--r-- | netlib.h | 621 | ||||
-rw-r--r-- | netperf.c | 284 | ||||
-rw-r--r-- | netperf_version.h | 1 | ||||
-rw-r--r-- | netserver.c | 1022 | ||||
-rw-r--r-- | netsh.c | 1002 | ||||
-rw-r--r-- | netsh.h | 149 | ||||
-rw-r--r-- | nettest_bsd.c | 12333 | ||||
-rw-r--r-- | nettest_bsd.h | 471 | ||||
-rw-r--r-- | nettest_dlpi.c | 3798 | ||||
-rw-r--r-- | nettest_dlpi.h | 215 | ||||
-rw-r--r-- | nettest_sctp.c | 4869 | ||||
-rw-r--r-- | nettest_sctp.h | 128 | ||||
-rw-r--r-- | nettest_sdp.c | 3553 | ||||
-rw-r--r-- | nettest_sdp.h | 170 | ||||
-rw-r--r-- | nettest_unix.c | 3431 | ||||
-rw-r--r-- | nettest_unix.h | 198 | ||||
-rw-r--r-- | nettest_xti.c | 6026 | ||||
-rw-r--r-- | nettest_xti.h | 264 |
35 files changed, 0 insertions, 47058 deletions
diff --git a/Android.mk b/Android.mk deleted file mode 100644 index a0d5b80..0000000 --- a/Android.mk +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2008 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH := $(call my-dir) - -L_DEFS := -DHAVE_CONFIG_H -UAF_INET6 -L_CFLAGS := $(L_DEFS) -L_USE_CPU_SOURCE := netcpu_none.c - -L_COMMON_SRC := hist.h netlib.c netsh.c nettest_bsd.c nettest_dlpi.c \ - nettest_unix.c nettest_xti.c nettest_sctp.c nettest_sdp.c - -netperf_SOURCES := netperf.c $(L_COMMON_SRC) $(L_USE_CPU_SOURCE) -netserver_SOURCES := netserver.c $(L_COMMON_SRC) $(L_USE_CPU_SOURCE) - -include $(CLEAR_VARS) -LOCAL_MODULE := netperf -LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) -LOCAL_MODULE_TAGS := tests eng -LOCAL_CFLAGS := $(L_CFLAGS) -LOCAL_SRC_FILES := $(netperf_SOURCES) -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) -LOCAL_MODULE := netserver -LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) -LOCAL_MODULE_TAGS := tests eng -LOCAL_CFLAGS := $(L_CFLAGS) -LOCAL_SRC_FILES := $(netserver_SOURCES) -include $(BUILD_EXECUTABLE) - diff --git a/MODULE_LICENSE_HP b/MODULE_LICENSE_HP deleted file mode 100644 index 3f3ceb2..0000000 --- a/MODULE_LICENSE_HP +++ /dev/null @@ -1,43 +0,0 @@ - - - Copyright (C) 1993 Hewlett-Packard Company - ALL RIGHTS RESERVED. - - The enclosed software and documentation includes copyrighted works - of Hewlett-Packard Co. For as long as you comply with the following - limitations, you are hereby authorized to (i) use, reproduce, and - modify the software and documentation, and to (ii) distribute the - software and documentation, including modifications, for - non-commercial purposes only. - - 1. The enclosed software and documentation is made available at no - charge in order to advance the general development of - high-performance networking products. - - 2. You may not delete any copyright notices contained in the - software or documentation. All hard copies, and copies in - source code or object code form, of the software or - documentation (including modifications) must contain at least - one of the copyright notices. - - 3. The enclosed software and documentation has not been subjected - to testing and quality control and is not a Hewlett-Packard Co. - product. At a future time, Hewlett-Packard Co. may or may not - offer a version of the software and documentation as a product. - - 4. THE SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS". - HEWLETT-PACKARD COMPANY DOES NOT WARRANT THAT THE USE, - REPRODUCTION, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR - DOCUMENTATION WILL NOT INFRINGE A THIRD PARTY'S INTELLECTUAL - PROPERTY RIGHTS. HP DOES NOT WARRANT THAT THE SOFTWARE OR - DOCUMENTATION IS ERROR FREE. HP DISCLAIMS ALL WARRANTIES, - EXPRESS AND IMPLIED, WITH REGARD TO THE SOFTWARE AND THE - DOCUMENTATION. HP SPECIFICALLY DISCLAIMS ALL WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - - 5. HEWLETT-PACKARD COMPANY WILL NOT IN ANY EVENT BE LIABLE FOR ANY - DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES - (INCLUDING LOST PROFITS) RELATED TO ANY USE, REPRODUCTION, - MODIFICATION, OR DISTRIBUTION OF THE SOFTWARE OR DOCUMENTATION. - - diff --git a/config.h b/config.h deleted file mode 100644 index 5c89615..0000000 --- a/config.h +++ /dev/null @@ -1,351 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to one to enable dirty buffer support. May affect results. */ -/* #undef DIRTY */ - -#undef AF_INET6 - -/* Define to 1 if you have the `alarm' function. */ -#define HAVE_ALARM 1 - -/* Define to 1 if you have the <arpa/inet.h> header file. */ -#define HAVE_ARPA_INET_H 1 - -/* Define to 1 if you have the `bindprocessor' function. */ -/* #undef HAVE_BINDPROCESSOR */ - -/* Define to 1 if you have the `bind_to_cpu_id' function. */ -/* #undef HAVE_BIND_TO_CPU_ID */ - -/* Define to 1 if you have the `bzero' function. */ -#define HAVE_BZERO 1 - -/* Define to 1 if you have the <endian.h> header file. */ -/* #define HAVE_ENDIAN_H 1 */ - -/* Define to 1 if you have the <errno.h> header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the <fcntl.h> header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the `fork' function. */ -#define HAVE_FORK 1 - -/* Define to 1 if you have the `getaddrinfo' function. */ -#define HAVE_GETADDRINFO 1 - -/* Define to 1 if you have the `gethostbyname' function. */ -#define HAVE_GETHOSTBYNAME 1 - -/* Define to 1 if you have the `gethrtime' function. */ -/* #undef HAVE_GETHRTIME */ - -/* Define to 1 if you have the `getnameinfo' function. */ -#define HAVE_GETNAMEINFO 1 - -/* Define to 1 if you have the `getpagesize' function. */ -#define HAVE_GETPAGESIZE 1 - -/* Define to 1 if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY 1 - -/* Define to one to include ICSC-EXS tests. */ -/* #undef HAVE_ICSC_EXS */ - -/* Define to 1 if you have the `inet_ntoa' function. */ -#define HAVE_INET_NTOA 1 - -/* Define to 1 if you have the `inet_ntop' function. */ -#define HAVE_INET_NTOP 1 - -/* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `exs' library (-lexs). */ -/* #undef HAVE_LIBEXS */ - -/* Define to 1 if you have the `kstat' library (-lkstat). */ -/* #undef HAVE_LIBKSTAT */ - -/* Define to 1 if you have the `m' library (-lm). */ -#define HAVE_LIBM 1 - -/* Define to 1 if you have the `mach' library (-lmach). */ -/* #undef HAVE_LIBMACH */ - -/* Define to 1 if you have the `nsl' library (-lnsl). */ -/* #undef HAVE_LIBNSL */ - -/* Define to 1 if you have the `perfstat' library (-lperfstat). */ -/* #undef HAVE_LIBPERFSTAT */ - -/* Define to 1 if you have the `sctp' library (-lsctp). */ -/* #undef HAVE_LIBSCTP */ - -/* Define to 1 if you have the `sdp' library (-lsdp). */ -/* #undef HAVE_LIBSDP */ - -/* Define to 1 if you have the `sendfile' library (-lsendfile). */ -/* #undef HAVE_LIBSENDFILE */ - -/* Define to 1 if you have the `socket' library (-lsocket). */ -/* #undef HAVE_LIBSOCKET */ - -/* Define to 1 if you have the <limits.h> header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if you have the <malloc.h> header file. */ -/* #define HAVE_MALLOC_H 1 */ - -/* Define to 1 if you have the `memcpy' function. */ -#define HAVE_MEMCPY 1 - -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `memset' function. */ -#define HAVE_MEMSET 1 - -/* Define to 1 if you have a working `mmap' system call. */ -#define HAVE_MMAP 1 - -/* Define to 1 if you have the `mpctl' function. */ -/* #undef HAVE_MPCTL */ - -/* Define to 1 if you have the `munmap' function. */ -#define HAVE_MUNMAP 1 - -/* Define to 1 if you have the <netdb.h> header file. */ -#define HAVE_NETDB_H 1 - -/* Define to 1 if you have the <netinet/in.h> header file. */ -#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if you have the <netinet/sctp.h> header file. */ -/* #undef HAVE_NETINET_SCTP_H */ - -/* Define to 1 if you have the `processor_bind' function. */ -/* #undef HAVE_PROCESSOR_BIND */ - -/* Define to 1 if you have the `sched_setaffinity' function. */ -/* #define HAVE_SCHED_SETAFFINITY 1 */ - -/* Define to 1 if `struct sctp_event_subscribe' has a - `sctp_adaptation_layer_event' member */ -/* #undef HAVE_SCTP_ADAPTATION_LAYER_EVENT */ - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the `sendfile' function. */ -/* #undef HAVE_SENDFILE */ - -/* Define to 1 if you have the <signal.h> header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define to 1 if you have the `socket' function. */ -#define HAVE_SOCKET 1 - -/* Define to 1 if you have the `sqrt' function. */ -#define HAVE_SQRT 1 - -/* Define to 1 if stdbool.h conforms to C99. */ -#define HAVE_STDBOOL_H 1 - -/* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strcasecmp' function. */ -#define HAVE_STRCASECMP 1 - -/* Define to 1 if you have the `strchr' function. */ -#define HAVE_STRCHR 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strstr' function. */ -#define HAVE_STRSTR 1 - -/* Define to 1 if you have the `strtoul' function. */ -#define HAVE_STRTOUL 1 - -/* Define to 1 if <netinet/in.h> defines `struct sockaddr_storage' */ -#define HAVE_STRUCT_SOCKADDR_STORAGE 1 - -/* Define to 1 if you have the <sys/ioctl.h> header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the <sys/mman.h> header file. */ -#define HAVE_SYS_MMAN_H 1 - -/* Define to 1 if you have the <sys/param.h> header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the <sys/select.h> header file. */ -#define HAVE_SYS_SELECT_H 1 - -/* Define to 1 if you have the <sys/socket.h> header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the <sys/time.h> header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ -#define HAVE_SYS_WAIT_H 1 - -/* Define to 1 if you have the `uname' function. */ -#define HAVE_UNAME 1 - -/* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the `vfork' function. */ -#define HAVE_VFORK 1 - -/* Define to 1 if you have the <vfork.h> header file. */ -/* #undef HAVE_VFORK_H */ - -/* Define to 1 if `fork' works. */ -#define HAVE_WORKING_FORK 1 - -/* Define to 1 if `vfork' works. */ -#define HAVE_WORKING_VFORK 1 - -/* Define to 1 if the system has the type `_Bool'. */ -#define HAVE__BOOL 1 - -/* Define to 1 if `h_errno' is declared by <netdb.h> */ -#define H_ERRNO_DECLARED 1 - -/* Name of package */ -#define PACKAGE "netperf" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "netperf" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "netperf 2.4.4" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "netperf" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "2.4.4" - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* Define to the type of arg 1 for `select'. */ -#define SELECT_TYPE_ARG1 int - -/* Define to the type of args 2, 3 and 4 for `select'. */ -#define SELECT_TYPE_ARG234 (fd_set *) - -/* Define to the type of arg 5 for `select'. */ -#define SELECT_TYPE_ARG5 (struct timeval *) - -/* Define to 1 if the `setpgrp' function takes no argument. */ -#define SETPGRP_VOID 1 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ -#define TIME_WITH_SYS_TIME 1 - -/* Use Solaris's kstat interface to measure CPU util. */ -/* #undef USE_KSTAT */ - -/* Use looper/soaker processes to measure CPU util. */ -/* #undef USE_LOOPER */ - -/* Use MacOS X's host_info interface to measure CPU util. */ -/* #undef USE_OSX */ - -/* Use AIX's perfstat interface to measure CPU util. */ -/* #undef USE_PERFSTAT */ - -/* Use Linux's procstat interface to measure CPU util. */ -#define USE_PROC_STAT 1 - -/* Use HP-UX's pstat interface to measure CPU util. */ -/* #undef USE_PSTAT */ - -/* Use FreeBSD's sysctl interface to measure CPU util. */ -/* #undef USE_SYSCTL */ - -/* Version number of package */ -#define VERSION "2.4.4" - -/* Define to one to enable demo support. May affect results. */ -/* #undef WANT_DEMO */ - -/* Define to one to include DLPI tests. */ -/* #undef WANT_DLPI */ - -/* Define to one to enable initial _RR burst support. May affect results. */ -/* #undef WANT_FIRST_BURST */ - -/* Define to one to enable histogram support. May affect results. */ -/* #undef WANT_HISTOGRAM */ - -/* Define to one to enable paced operation support. May affect results. */ -/* #undef WANT_INTERVALS */ - -/* Define to one to include SCTP tests. */ -/* #define WANT_SCTP 1 */ - -/* Define to one to include SDP tests. */ -/* #undef WANT_SDP */ - -/* Define to one to spin waiting on paced operation. WILL AFFEFCT CPU - UTILIZATION */ -/* #undef WANT_SPIN */ - -/* Define to one to include Unix Domain socket tests. */ -/* #undef WANT_UNIX */ - -/* Define to one to include XTI tests. */ -/* #undef WANT_XTI */ - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* type to use in place of socklen_t if not defined */ -#define netperf_socklen_t size_t - -/* Define to `long int' if <sys/types.h> does not define. */ -/* #undef off_t */ - -/* Define to `int' if <sys/types.h> does not define. */ -/* #undef pid_t */ - -/* Define to `unsigned int' if <sys/types.h> does not define. */ -/* #undef size_t */ - -/* Define as `fork' if `vfork' does not work. */ -/* #undef vfork */ @@ -1,116 +0,0 @@ -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif - -/* hist.h - - Given a time difference in microseconds, increment one of 61 - different buckets: - - 0 - 9 in increments of 1 usec - 0 - 9 in increments of 10 usecs - 0 - 9 in increments of 100 usecs - 0 - 9 in increments of 1 msec - 0 - 9 in increments of 10 msecs - 0 - 9 in increments of 100 msecs - 0 - 9 in increments of 1 sec - 0 - 9 in increments of 10 sec - > 100 secs - - This will allow any time to be recorded to within an accuracy of - 10%, and provides a compact representation for capturing the - distribution of a large number of time differences (e.g. - request-response latencies). - - Colin Low 10/6/93 - Rick Jones 2004-06-15 - extend to 1 and 10 usec -*/ -#ifndef _HIST_INCLUDED -#define _HIST_INCLUDED - -#ifdef IRIX -#include <sys/time.h> -#endif /* IRIX */ - -#if defined(HAVE_GET_HRT) -#include "hrt.h" -#endif - -struct histogram_struct { - int unit_usec[10]; - int ten_usec[10]; - int hundred_usec[10]; - int unit_msec[10]; - int ten_msec[10]; - int hundred_msec[10]; - int unit_sec[10]; - int ten_sec[10]; - int ridiculous; - int total; -}; - -typedef struct histogram_struct *HIST; - -/* - HIST_new - return a new, cleared histogram data type -*/ - -HIST HIST_new(void); - -/* - HIST_clear - reset a histogram by clearing all totals to zero -*/ - -void HIST_clear(HIST h); - -/* - HIST_add - add a time difference to a histogram. Time should be in - microseconds. -*/ - -void HIST_add(register HIST h, int time_delta); - -/* - HIST_report - create an ASCII report on the contents of a histogram. - Currently printsto standard out -*/ - -void HIST_report(HIST h); - -/* - HIST_timestamp - take a timestamp suitable for use in a histogram. -*/ - -#ifdef HAVE_GETHRTIME -void HIST_timestamp(hrtime_t *timestamp); -#elif defined(HAVE_GET_HRT) -void HIST_timestamp(hrt_t *timestamp); -#elif defined(WIN32) -void HIST_timestamp(LARGE_INTEGER *timestamp); -#else -void HIST_timestamp(struct timeval *timestamp); -#endif - -/* - delta_micro - calculate the difference in microseconds between two - timestamps -*/ -#ifdef HAVE_GETHRTIME -int delta_micro(hrtime_t *begin, hrtime_t *end); -#elif defined(HAVE_GET_HRT) -int delta_micro(hrt_t *begin, hrt_t *end); -#elif defined(WIN32) -int delta_micro(LARGE_INTEGER *begin, LARGE_INTEGER *end); -#else -int delta_micro(struct timeval *begin, struct timeval *end); -#endif - -#endif - diff --git a/netcpu.h b/netcpu.h deleted file mode 100644 index 58d1e1c..0000000 --- a/netcpu.h +++ /dev/null @@ -1,19 +0,0 @@ -/* This should define all the common routines etc exported by the - various netcpu_mumble.c files raj 2005-01-26 */ - -extern void cpu_util_init(void); -extern void cpu_util_terminate(void); -extern int get_cpu_method(); - -#ifdef WIN32 -/* +*+ temp until I figure out what header this is in; I know it's - there someplace... */ -typedef unsigned __int64 uint64_t; -#endif - -extern void get_cpu_idle(uint64_t *res); -extern float calibrate_idle_rate(int iterations, int interval); -extern float calc_cpu_util_internal(float elapsed); -extern void cpu_start_internal(void); -extern void cpu_stop_internal(void); - diff --git a/netcpu_kstat.c b/netcpu_kstat.c deleted file mode 100644 index 6320658..0000000 --- a/netcpu_kstat.c +++ /dev/null @@ -1,415 +0,0 @@ -char netcpu_kstat_id[]="\ -@(#)netcpu_kstat.c Version 2.4.0"; - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdio.h> - -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif - -#if HAVE_UNISTD_H -# include <unistd.h> -#endif -#if HAVE_STRINGS_H -# include <strings.h> -#endif -#if STDC_HEADERS -# include <stdlib.h> -# include <stddef.h> -#else -# if HAVE_STDLIB_H -# include <stdlib.h> -# endif -#endif - -#include <kstat.h> -#include <sys/sysinfo.h> - -#include "netsh.h" -#include "netlib.h" - -/* the lib_start_count and lib_end_count arrays hold the starting - and ending values of whatever is counting when the system is - idle. The rate at which this increments during a test is compared - with a previous calibrarion to arrive at a CPU utilization - percentage. raj 2005-01-26 */ -static uint64_t lib_start_count[MAXCPUS]; -static uint64_t lib_end_count[MAXCPUS]; - -static kstat_t *cpu_ks[MAXCPUS]; /* the addresses that kstat will - need to pull the cpu info from - the kstat interface. at least I - think that is what this is :) raj - 8/2000 */ - -#define UPDKCID(nk,ok) \ -if (nk == -1) { \ - perror("kstat_read "); \ - exit(1); \ -} \ -if (nk != ok)\ - goto kcid_changed; - -static kstat_ctl_t *kc = NULL; -static kid_t kcid = 0; - -/* do the initial open of the kstat interface, get the chain id's all - straightened-out and set-up the addresses for get_kstat_idle to do - its thing. liberally borrowed from the sources to TOP. raj 8/2000 */ - -static int -open_kstat() -{ - kstat_t *ks; - kid_t nkcid; - int i; - int changed = 0; - static int ncpu = 0; - - kstat_named_t *kn; - - if (debug) { - fprintf(where,"open_kstat: enter\n"); - fflush(where); - } - - /* - * 0. kstat_open - */ - - if (!kc) - { - kc = kstat_open(); - if (!kc) - { - perror("kstat_open "); - exit(1); - } - changed = 1; - kcid = kc->kc_chain_id; - } -#ifdef rickwasstupid - else { - fprintf(where,"open_kstat double open!\n"); - fflush(where); - exit(1); - } -#endif - - /* keep doing it until no more changes */ - kcid_changed: - - if (debug) { - fprintf(where,"passing kcid_changed\n"); - fflush(where); - } - - /* - * 1. kstat_chain_update - */ - nkcid = kstat_chain_update(kc); - if (nkcid) - { - /* UPDKCID will abort if nkcid is -1, so no need to check */ - changed = 1; - kcid = nkcid; - } - UPDKCID(nkcid,0); - - if (debug) { - fprintf(where,"kstat_lookup for unix/system_misc\n"); - fflush(where); - } - - ks = kstat_lookup(kc, "unix", 0, "system_misc"); - if (kstat_read(kc, ks, 0) == -1) { - perror("kstat_read"); - exit(1); - } - - - if (changed) { - - /* - * 2. get data addresses - */ - - ncpu = 0; - - kn = kstat_data_lookup(ks, "ncpus"); - if (kn && kn->value.ui32 > lib_num_loc_cpus) { - fprintf(stderr,"number of CPU's mismatch!"); - exit(1); - } - - for (ks = kc->kc_chain; ks; - ks = ks->ks_next) - { - if (strncmp(ks->ks_name, "cpu_stat", 8) == 0) - { - nkcid = kstat_read(kc, ks, NULL); - /* if kcid changed, pointer might be invalid. we'll deal - wtih changes at this stage, but will not accept them - when we are actually in the middle of reading - values. hopefully this is not going to be a big - issue. raj 8/2000 */ - UPDKCID(nkcid, kcid); - - if (debug) { - fprintf(where,"cpu_ks[%d] getting %p\n",ncpu,ks); - fflush(where); - } - - cpu_ks[ncpu] = ks; - ncpu++; - if (ncpu > lib_num_loc_cpus) - { - /* with the check above, would we ever hit this? */ - fprintf(stderr, - "kstat finds too many cpus %d: should be %d\n", - ncpu,lib_num_loc_cpus); - exit(1); - } - } - } - /* note that ncpu could be less than ncpus, but that's okay */ - changed = 0; - } -} - -/* return the value of the idle tick counter for the specified CPU */ -static long -get_kstat_idle(cpu) - int cpu; -{ - cpu_stat_t cpu_stat; - kid_t nkcid; - - if (debug) { - fprintf(where, - "get_kstat_idle reading with kc %x and ks %p\n", - kc, - cpu_ks[cpu]); - } - - nkcid = kstat_read(kc, cpu_ks[cpu], &cpu_stat); - /* if kcid changed, pointer might be invalid, fail the test */ - UPDKCID(nkcid, kcid); - - return(cpu_stat.cpu_sysinfo.cpu[CPU_IDLE]); - - kcid_changed: - perror("kcid changed midstream and I cannot deal with that!"); - exit(1); -} - -void -cpu_util_init(void) -{ - open_kstat(); - return; -} - -void -cpu_util_terminate(void) -{ - return; -} - -int -get_cpu_method(void) -{ - return KSTAT; -} - -void -get_cpu_idle(uint64_t *res) -{ - - int i; - - /* this open may be redundant */ - open_kstat(); - - for (i = 0; i < lib_num_loc_cpus; i++){ - res[i] = get_kstat_idle(i); - } - return; -} - -float -calibrate_idle_rate(int iterations, int interval) -{ - - long - firstcnt[MAXCPUS], - secondcnt[MAXCPUS]; - - float - elapsed, - temp_rate, - rate[MAXTIMES], - local_maxrate; - - long - sec, - usec; - - int - i, - j; - - struct timeval time1, time2 ; - struct timezone tz; - - if (debug) { - fprintf(where,"calling open_kstat from calibrate_kstat\n"); - fflush(where); - } - - open_kstat(); - - if (iterations > MAXTIMES) { - iterations = MAXTIMES; - } - - local_maxrate = (float)-1.0; - - for(i = 0; i < iterations; i++) { - rate[i] = (float)0.0; - for (j = 0; j < lib_num_loc_cpus; j++) { - firstcnt[j] = get_kstat_idle(j); - } - gettimeofday (&time1, &tz); - sleep(interval); - gettimeofday (&time2, &tz); - - if (time2.tv_usec < time1.tv_usec) - { - time2.tv_usec += 1000000; - time2.tv_sec -=1; - } - sec = time2.tv_sec - time1.tv_sec; - usec = time2.tv_usec - time1.tv_usec; - elapsed = (float)sec + ((float)usec/(float)1000000.0); - - if(debug) { - fprintf(where, "Calibration for kstat counter run: %d\n",i); - fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec); - fprintf(where,"\telapsed time = %g\n",elapsed); - } - - for (j = 0; j < lib_num_loc_cpus; j++) { - secondcnt[j] = get_kstat_idle(j); - if(debug) { - /* I know that there are situations where compilers know about */ - /* long long, but the library functions do not... raj 4/95 */ - fprintf(where, - "\tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lx\n", - j, - firstcnt[j], - firstcnt[j], - j, - secondcnt[j], - secondcnt[j]); - } - /* we assume that it would wrap no more than once. we also */ - /* assume that the result of subtracting will "fit" raj 4/95 */ - temp_rate = (secondcnt[j] >= firstcnt[j]) ? - (float)(secondcnt[j] - firstcnt[j])/elapsed : - (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed; - if (temp_rate > rate[i]) rate[i] = temp_rate; - if(debug) { - fprintf(where,"\trate[%d] = %g\n",i,rate[i]); - fflush(where); - } - if (local_maxrate < rate[i]) local_maxrate = rate[i]; - } - } - if(debug) { - fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate); - fflush(where); - } - return local_maxrate; -} - -float -calc_cpu_util_internal(float elapsed_time) -{ - int i; - float correction_factor; - float actual_rate; - - lib_local_cpu_util = (float)0.0; - /* It is possible that the library measured a time other than */ - /* the one that the user want for the cpu utilization */ - /* calculations - for example, tests that were ended by */ - /* watchdog timers such as the udp stream test. We let these */ - /* tests tell up what the elapsed time should be. */ - - if (elapsed_time != 0.0) { - correction_factor = (float) 1.0 + - ((lib_elapsed - elapsed_time) / elapsed_time); - } - else { - correction_factor = (float) 1.0; - } - - for (i = 0; i < lib_num_loc_cpus; i++) { - - /* it would appear that on some systems, in loopback, nice is - *very* effective, causing the looper process to stop dead in its - tracks. if this happens, we need to ensure that the calculation - does not go south. raj 6/95 and if we run completely out of idle, - the same thing could in theory happen to the USE_KSTAT path. raj - 8/2000 */ - - if (lib_end_count[i] == lib_start_count[i]) { - lib_end_count[i]++; - } - - actual_rate = (lib_end_count[i] > lib_start_count[i]) ? - (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed : - (float)(lib_end_count[i] - lib_start_count[i] + - MAXLONG)/ lib_elapsed; - if (debug) { - fprintf(where, - "calc_cpu_util: actual_rate on processor %d is %f start %lx end %lx\n", - i, - actual_rate, - lib_start_count[i], - lib_end_count[i]); - } - lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) / - lib_local_maxrate * 100; - lib_local_cpu_util += lib_local_per_cpu_util[i]; - } - /* we want the average across all n processors */ - lib_local_cpu_util /= (float)lib_num_loc_cpus; - - lib_local_cpu_util *= correction_factor; - return lib_local_cpu_util; - - -} - -void -cpu_start_internal(void) -{ - get_cpu_idle(lib_start_count); - return; -} - -void -cpu_stop_internal(void) -{ - get_cpu_idle(lib_end_count); -} diff --git a/netcpu_kstat10.c b/netcpu_kstat10.c deleted file mode 100644 index 299e66d..0000000 --- a/netcpu_kstat10.c +++ /dev/null @@ -1,559 +0,0 @@ -char netcpu_kstat10_id[]="\ -@(#)netcpu_kstat10.c (c) Copyright 2005-2007, Hewlett-Packard Company Version 2.4.3"; - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdio.h> - -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif - -#if HAVE_UNISTD_H -# include <unistd.h> -#endif -#if HAVE_STRINGS_H -# include <strings.h> -#endif -#if STDC_HEADERS -# include <stdlib.h> -# include <stddef.h> -#else -# if HAVE_STDLIB_H -# include <stdlib.h> -# endif -#endif - -#include <errno.h> - -#include <kstat.h> -#include <sys/sysinfo.h> - -#include "netsh.h" -#include "netlib.h" - -static kstat_ctl_t *kc = NULL; -static kid_t kcid = 0; - -typedef struct cpu_time_counters { - uint64_t idle; - uint64_t user; - uint64_t kernel; - uint64_t interrupt; -} cpu_time_counters_t; - -static cpu_time_counters_t starting_cpu_counters[MAXCPUS]; -static cpu_time_counters_t ending_cpu_counters[MAXCPUS]; -static cpu_time_counters_t delta_cpu_counters[MAXCPUS]; -static cpu_time_counters_t corrected_cpu_counters[MAXCPUS]; - -static void -print_cpu_time_counters(char *name, int instance, cpu_time_counters_t *counters) -{ - fprintf(where,"%s[%d]:\n",name,instance); - fprintf(where, - "\t idle %llu\n",counters[instance].idle); - fprintf(where, - "\t user %llu\n",counters[instance].user); - fprintf(where, - "\t kernel %llu\n",counters[instance].kernel); - fprintf(where, - "\t interrupt %llu\n",counters[instance].interrupt); -} - -void -cpu_util_init(void) -{ - kc = kstat_open(); - - if (kc == NULL) { - fprintf(where, - "cpu_util_init: kstat_open: errno %d %s\n", - errno, - strerror(errno)); - fflush(where); - exit(-1); - } - return; -} - -void -cpu_util_terminate(void) -{ - kstat_close(kc); - return; -} - -int -get_cpu_method(void) -{ - return KSTAT_10; -} - -static void -print_unexpected_statistic_warning(char *who, char *what, char *why) -{ - if (why) { - fprintf(where, - "WARNING! WARNING! WARNING! WARNING!\n"); - fprintf(where, - "%s found an unexpected %s statistic %.16s\n", - who, - why, - what); - } - else { - fprintf(where, - "%s is ignoring statistic %.16s\n", - who, - what); - } -} - -static void -get_cpu_counters(int cpu_num, cpu_time_counters_t *counters) -{ - - kstat_t *ksp; - int found=0; - kid_t nkcid; - kstat_named_t *knp; - int i; - - ksp = kstat_lookup(kc, "cpu", cpu_num, "sys"); - if ((ksp) && (ksp->ks_type == KSTAT_TYPE_NAMED)) { - /* happiness and joy, keep going */ - nkcid = kstat_read(kc, ksp, NULL); - if (nkcid != -1) { - /* happiness and joy, keep going. we could consider adding a - "found < 3" to the end conditions, but then we wouldn't - search to the end and find that Sun added some nsec. we - probably want to see if they add an nsec. raj 2005-01-28 */ - for (i = ksp->ks_ndata, knp = ksp->ks_data; - i > 0; - knp++,i--) { - /* we would be hosed if the same name could appear twice */ - if (!strcmp("cpu_nsec_idle",knp->name)) { - found++; - counters[cpu_num].idle = knp->value.ui64; - } - else if (!strcmp("cpu_nsec_user",knp->name)) { - found++; - counters[cpu_num].user = knp->value.ui64; - } - else if (!strcmp("cpu_nsec_kernel",knp->name)) { - found++; - counters[cpu_num].kernel = knp->value.ui64; - } - else if (strstr(knp->name,"nsec")) { - /* finding another nsec here means Sun have changed - something and we need to warn the user. raj 2005-01-28 */ - print_unexpected_statistic_warning("get_cpu_counters", - knp->name, - "nsec"); - } - else if (debug >=2) { - - /* might want to tell people about what we are skipping. - however, only display other names debug >=2. raj - 2005-01-28 - */ - - print_unexpected_statistic_warning("get_cpu_counters", - knp->name, - NULL); - } - } - if (3 == found) { - /* happiness and joy */ - return; - } - else { - fprintf(where, - "get_cpu_counters could not find one or more of the expected counters!\n"); - fflush(where); - exit(-1); - } - } - else { - /* the kstat_read returned an error or the chain changed */ - fprintf(where, - "get_cpu_counters: kstat_read failed or chain id changed %d %s\n", - errno, - strerror(errno)); - fflush(where); - exit(-1); - } - } - else { - /* the lookup failed or found the wrong type */ - fprintf(where, - "get_cpu_counters: kstat_lookup failed for module 'cpu' instance %d name 'sys' and KSTAT_TYPE_NAMED: errno %d %s\n", - cpu_num, - errno, - strerror(errno)); - fflush(where); - exit(-1); - } -} - -static void -get_interrupt_counters(int cpu_num, cpu_time_counters_t *counters) -{ - kstat_t *ksp; - int found=0; - kid_t nkcid; - kstat_named_t *knp; - int i; - - ksp = kstat_lookup(kc, "cpu", cpu_num, "intrstat"); - - counters[cpu_num].interrupt = 0; - if ((ksp) && (ksp->ks_type == KSTAT_TYPE_NAMED)) { - /* happiness and joy, keep going */ - nkcid = kstat_read(kc, ksp, NULL); - if (nkcid != -1) { - /* happiness and joy, keep going. we could consider adding a - "found < 15" to the end conditions, but then we wouldn't - search to the end and find that Sun added some "time." we - probably want to see if they add a "nsec." raj 2005-01-28 */ - for (i = ksp->ks_ndata, knp = ksp->ks_data; - i > 0; - knp++,i--) { - if (strstr(knp->name,"time")) { - found++; - counters[cpu_num].interrupt += knp->value.ui64; - } - else if (debug >=2) { - - /* might want to tell people about what we are skipping. - however, only display other names debug >=2. raj - 2005-01-28 - */ - - print_unexpected_statistic_warning("get_cpu_counters", - knp->name, - NULL); - } - } - if (15 == found) { - /* happiness and joy */ - return; - } - else { - fprintf(where, - "get_cpu_counters could not find one or more of the expected counters!\n"); - fflush(where); - exit(-1); - } - } - else { - /* the kstat_read returned an error or the chain changed */ - fprintf(where, - "get_cpu_counters: kstat_read failed or chain id changed %d %s\n", - errno, - strerror(errno)); - fflush(where); - exit(-1); - } - } - else { - /* the lookup failed or found the wrong type */ - fprintf(where, - "get_cpu_counters: kstat_lookup failed for module 'cpu' instance %d class 'intrstat' and KSTAT_TYPE_NAMED: errno %d %s\n", - cpu_num, - errno, - strerror(errno)); - fflush(where); - exit(-1); - } - -} - -static void -get_cpu_time_counters(cpu_time_counters_t *counters) -{ - - int i; - - for (i = 0; i < lib_num_loc_cpus; i++){ - get_cpu_counters(i, counters); - get_interrupt_counters(i, counters); - } - - return; -} - -/* the kstat10 mechanism, since it is based on actual nanosecond - counters is not going to use a comparison to an idle rate. so, the - calibrate_idle_rate routine will be rather simple :) raj 2005-01-28 - */ - -float -calibrate_idle_rate(int iterations, int interval) -{ - return 0.0; -} - -float -calc_cpu_util_internal(float elapsed_time) -{ - int i; - float correction_factor; - float actual_rate; - - uint64_t total_cpu_nsec; - - /* multiply by 100 and divide by total and you get whole - percentages. multiply by 1000 and divide by total and you get - tenths of percentages. multiply by 10000 and divide by total and - you get hundredths of percentages. etc etc etc raj 2005-01-28 */ - -#define CALC_PERCENT 100 -#define CALC_TENTH_PERCENT 1000 -#define CALC_HUNDREDTH_PERCENT 10000 -#define CALC_THOUSANDTH_PERCENT 100000 -#define CALC_ACCURACY CALC_THOUSANDTH_PERCENT - - uint64_t fraction_idle; - uint64_t fraction_user; - uint64_t fraction_kernel; - uint64_t fraction_interrupt; - - uint64_t interrupt_idle; - uint64_t interrupt_user; - uint64_t interrupt_kernel; - - lib_local_cpu_util = (float)0.0; - - /* It is possible that the library measured a time other than */ - /* the one that the user want for the cpu utilization */ - /* calculations - for example, tests that were ended by */ - /* watchdog timers such as the udp stream test. We let these */ - /* tests tell up what the elapsed time should be. */ - - if (elapsed_time != 0.0) { - correction_factor = (float) 1.0 + - ((lib_elapsed - elapsed_time) / elapsed_time); - } - else { - correction_factor = (float) 1.0; - } - - for (i = 0; i < lib_num_loc_cpus; i++) { - - /* this is now the fun part. we have the nanoseconds _allegedly_ - spent in user, idle and kernel. We also have nanoseconds spent - servicing interrupts. Sadly, in the developer's finite wisdom, - the interrupt time accounting is in parallel with the other - accounting. this means that time accounted in user, kernel or - idle will also include time spent in interrupt. for netperf's - porpoises we do not really care about that for user and kernel, - but we certainly do care for idle. the $64B question becomes - - how to "correct" for this? - - we could just subtract interrupt time from idle. that has the - virtue of simplicity and also "punishes" Sun for doing - something that seems to be so stupid. however, we probably - have to be "fair" even to the allegedly stupid so the other - mechanism, suggested by a Sun engineer is to subtract interrupt - time from each of user, kernel and idle in proportion to their - numbers. then we sum the corrected user, kernel and idle along - with the interrupt time and use that to calculate a new idle - percentage and thus a CPU util percentage. - - that is what we will attempt to do here. raj 2005-01-28 - - of course, we also have to wonder what we should do if there is - more interrupt time than the sum of user, kernel and idle. - that is a theoretical possibility I suppose, but for the - time-being, one that we will blythly ignore, except perhaps for - a quick check. raj 2005-01-31 - */ - - /* we ass-u-me that these counters will never wrap during a - netperf run. this may not be a particularly safe thing to - do. raj 2005-01-28 */ - delta_cpu_counters[i].idle = ending_cpu_counters[i].idle - - starting_cpu_counters[i].idle; - delta_cpu_counters[i].user = ending_cpu_counters[i].user - - starting_cpu_counters[i].user; - delta_cpu_counters[i].kernel = ending_cpu_counters[i].kernel - - starting_cpu_counters[i].kernel; - delta_cpu_counters[i].interrupt = ending_cpu_counters[i].interrupt - - starting_cpu_counters[i].interrupt; - - if (debug) { - print_cpu_time_counters("delta_cpu_counters",i,delta_cpu_counters); - } - - /* for this summation, we do not include interrupt time */ - total_cpu_nsec = - delta_cpu_counters[i].idle + - delta_cpu_counters[i].user + - delta_cpu_counters[i].kernel; - - if (debug) { - fprintf(where,"total_cpu_nsec %llu\n",total_cpu_nsec); - } - - if (delta_cpu_counters[i].interrupt > total_cpu_nsec) { - /* we are not in Kansas any more Toto, and I am not quite sure - the best way to get our tails out of here so let us just - punt. raj 2005-01-31 */ - fprintf(where, - "WARNING! WARNING! WARNING! WARNING! WARNING! \n"); - fprintf(where, - "calc_cpu_util_internal: more interrupt time than others combined!\n"); - fprintf(where, - "\tso CPU util cannot be estimated\n"); - fprintf(where, - "\t delta[%d].interrupt %llu\n",i,delta_cpu_counters[i].interrupt); - fprintf(where, - "\t delta[%d].idle %llu\n",i,delta_cpu_counters[i].idle); - fprintf(where, - "\t delta[%d].user %llu\n",i,delta_cpu_counters[i].user); - fprintf(where, - "\t delta[%d].kernel %llu\n",i,delta_cpu_counters[i].kernel); - fflush(where); - - lib_local_cpu_util = -1.0; - lib_local_per_cpu_util[i] = -1.0; - return -1.0; - } - - /* and now some fun with integer math. i initially tried to - promote things to long doubled but that didn't seem to result - in happiness and joy. raj 2005-01-28 */ - - fraction_idle = - (delta_cpu_counters[i].idle * CALC_ACCURACY) / total_cpu_nsec; - - fraction_user = - (delta_cpu_counters[i].user * CALC_ACCURACY) / total_cpu_nsec; - - fraction_kernel = - (delta_cpu_counters[i].kernel * CALC_ACCURACY) / total_cpu_nsec; - - /* ok, we have our fractions, now we want to take that fraction of - the interrupt time and subtract that from the bucket. */ - - interrupt_idle = ((delta_cpu_counters[i].interrupt * fraction_idle) / - CALC_ACCURACY); - - interrupt_user = ((delta_cpu_counters[i].interrupt * fraction_user) / - CALC_ACCURACY); - - interrupt_kernel = ((delta_cpu_counters[i].interrupt * fraction_kernel) / - CALC_ACCURACY); - - if (debug) { - fprintf(where, - "\tfraction_idle %llu interrupt_idle %llu\n", - fraction_idle, - interrupt_idle); - fprintf(where, - "\tfraction_user %llu interrupt_user %llu\n", - fraction_user, - interrupt_user); - fprintf(where,"\tfraction_kernel %llu interrupt_kernel %llu\n", - fraction_kernel, - interrupt_kernel); - } - - corrected_cpu_counters[i].idle = delta_cpu_counters[i].idle - - interrupt_idle; - - corrected_cpu_counters[i].user = delta_cpu_counters[i].user - - interrupt_user; - - corrected_cpu_counters[i].kernel = delta_cpu_counters[i].kernel - - interrupt_kernel; - - corrected_cpu_counters[i].interrupt = delta_cpu_counters[i].interrupt; - - if (debug) { - print_cpu_time_counters("corrected_cpu_counters", - i, - corrected_cpu_counters); - } - - /* I was going to checkfor going less than zero, but since all the - calculations are in unsigned quantities that would seem to be a - triffle silly... raj 2005-01-28 */ - - /* ok, now we sum the numbers again, this time including interrupt - */ - - total_cpu_nsec = - corrected_cpu_counters[i].idle + - corrected_cpu_counters[i].user + - corrected_cpu_counters[i].kernel + - corrected_cpu_counters[i].interrupt; - - /* and recalculate our fractions we are really only going to use - fraction_idle, but lets calculate the rest just for the heck of - it. one day we may want to display them. raj 2005-01-28 */ - - /* multiply by 100 and divide by total and you get whole - percentages. multiply by 1000 and divide by total and you get - tenths of percentages. multiply by 10000 and divide by total - and you get hundredths of percentages. etc etc etc raj - 2005-01-28 */ - fraction_idle = - (corrected_cpu_counters[i].idle * CALC_ACCURACY) / total_cpu_nsec; - - fraction_user = - (corrected_cpu_counters[i].user * CALC_ACCURACY) / total_cpu_nsec; - - fraction_kernel = - (corrected_cpu_counters[i].kernel * CALC_ACCURACY) / total_cpu_nsec; - - fraction_interrupt = - (corrected_cpu_counters[i].interrupt * CALC_ACCURACY) / total_cpu_nsec; - - if (debug) { - fprintf(where,"\tfraction_idle %lu\n",fraction_idle); - fprintf(where,"\tfraction_user %lu\n",fraction_user); - fprintf(where,"\tfraction_kernel %lu\n",fraction_kernel); - fprintf(where,"\tfraction_interrupt %lu\n",fraction_interrupt); - } - - /* and finally, what is our CPU utilization? */ - lib_local_per_cpu_util[i] = 100.0 - (((float)fraction_idle / - (float)CALC_ACCURACY) * 100.0); - if (debug) { - fprintf(where, - "lib_local_per_cpu_util[%d] %g\n", - i, - lib_local_per_cpu_util[i]); - } - lib_local_cpu_util += lib_local_per_cpu_util[i]; - } - /* we want the average across all n processors */ - lib_local_cpu_util /= (float)lib_num_loc_cpus; - - lib_local_cpu_util *= correction_factor; - return lib_local_cpu_util; - - -} - -void -cpu_start_internal(void) -{ - get_cpu_time_counters(starting_cpu_counters); - return; -} - -void -cpu_stop_internal(void) -{ - get_cpu_time_counters(ending_cpu_counters); -} diff --git a/netcpu_looper.c b/netcpu_looper.c deleted file mode 100644 index b76c7c9..0000000 --- a/netcpu_looper.c +++ /dev/null @@ -1,656 +0,0 @@ -char netcpu_looper_id[]="\ -@(#)netcpu_looper.c (c) Copyright 2005-2007. Version 2.4.3"; - -/* netcpu_looper.c - - Implement the soaker process specific portions of netperf CPU - utilization measurements. These are broken-out into a separate file - to make life much nicer over in netlib.c which had become a maze of - twisty, CPU-util-related, #ifdefs, all different. raj 2005-01-26 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> - -#ifdef HAVE_FCNTL_H -# include <fcntl.h> -#endif -#if HAVE_UNISTD_H -# include <unistd.h> -#endif -#if defined(HAVE_MMAP) || defined(HAVE_SYS_MMAN_H) -# include <sys/mman.h> -#else -# error netcpu_looper requires mmap -#endif - -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif - -#if HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif - -#if HAVE_SYS_WAIT_H -# include <sys/wait.h> -#endif - -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif - -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif - -#include "netsh.h" -#include "netlib.h" - -#define PAGES_PER_CHILD 2 - -/* the lib_start_count and lib_end_count arrays hold the starting - and ending values of whatever is counting when the system is - idle. The rate at which this increments during a test is compared - with a previous calibrarion to arrive at a CPU utilization - percentage. raj 2005-01-26 */ -static uint64_t lib_start_count[MAXCPUS]; -static uint64_t lib_end_count[MAXCPUS]; - -static int *cpu_mappings; - -static int lib_idle_fd; -static uint64_t *lib_idle_address[MAXCPUS]; -static long *lib_base_pointer; -static pid_t lib_idle_pids[MAXCPUS]; -static int lib_loopers_running=0; - -/* we used to use this code to bind the loopers, but since we have - decided to enable processor affinity for the actual - netperf/netserver processes we will use that affinity routine, - which happens to know about more systems than this */ - -#ifdef NOTDEF -static void -bind_to_processor(int child_num) -{ - /* This routine will bind the calling process to a particular */ - /* processor. We are not choosy as to which processor, so it will be */ - /* the process id mod the number of processors - shifted by one for */ - /* those systems which name processor starting from one instead of */ - /* zero. on those systems where I do not yet know how to bind a */ - /* process to a processor, this routine will be a no-op raj 10/95 */ - - /* just as a reminder, this is *only* for the looper processes, not */ - /* the actual measurement processes. those will, should, MUST float */ - /* or not float from CPU to CPU as controlled by the operating */ - /* system defaults. raj 12/95 */ - -#ifdef __hpux -#include <sys/syscall.h> -#include <sys/mp.h> - - int old_cpu = -2; - - if (debug) { - fprintf(where, - "child %d asking for CPU %d as pid %d with %d CPUs\n", - child_num, - (child_num % lib_num_loc_cpus), - getpid(), - lib_num_loc_cpus); - fflush(where); - } - - SETPROCESS((child_num % lib_num_loc_cpus), getpid()); - return; - -#else -#if defined(__sun) && defined(__SVR4) - /* should only be Solaris */ -#include <sys/processor.h> -#include <sys/procset.h> - - int old_binding; - - if (debug) { - fprintf(where, - "bind_to_processor: child %d asking for CPU %d as pid %d with %d CPUs\n", - child_num, - (child_num % lib_num_loc_cpus), - getpid(), - lib_num_loc_cpus); - fflush(where); - } - - if (processor_bind(P_PID, - getpid(), - (child_num % lib_num_loc_cpus), - &old_binding) != 0) { - fprintf(where,"bind_to_processor: unable to perform processor binding\n"); - fprintf(where," errno %d\n",errno); - fflush(where); - } - return; -#else -#ifdef WIN32 - - if (!SetThreadAffinityMask(GetCurrentThread(), (ULONG_PTR)1 << (child_num % lib_num_loc_cpus))) { - perror("SetThreadAffinityMask failed"); - fflush(stderr); - } - - if (debug) { - fprintf(where, - "bind_to_processor: child %d asking for CPU %d of %d CPUs\n", - child_num, - (child_num % lib_num_loc_cpus), - lib_num_loc_cpus); - fflush(where); - } - -#endif - return; -#endif /* __sun && _SVR4 */ -#endif /* __hpux */ -} -#endif - - /* sit_and_spin will just spin about incrementing a value */ - /* this value will either be in a memory mapped region on Unix shared */ - /* by each looper process, or something appropriate on Windows/NT */ - /* (malloc'd or such). This routine is reasonably ugly in that it has */ - /* priority manipulating code for lots of different operating */ - /* systems. This routine never returns. raj 1/96 */ - -static void -sit_and_spin(int child_index) - -{ - uint64_t *my_counter_ptr; - - /* only use C stuff if we are not WIN32 unless and until we */ - /* switch from CreateThread to _beginthread. raj 1/96 */ -#ifndef WIN32 - /* we are the child. we could decide to exec some separate */ - /* program, but that doesn't really seem worthwhile - raj 4/95 */ - if (debug > 1) { - fprintf(where, - "Looper child %d is born, pid %d\n", - child_index, - getpid()); - fflush(where); - } - -#endif /* WIN32 */ - - /* reset our base pointer to be at the appropriate offset */ - my_counter_ptr = (uint64_t *) ((char *)lib_base_pointer + - (netlib_get_page_size() * - PAGES_PER_CHILD * child_index)); - - /* in the event we are running on an MP system, it would */ - /* probably be good to bind the soaker processes to specific */ - /* processors. I *think* this is the most reasonable thing to */ - /* do, and would be closes to simulating the information we get */ - /* on HP-UX with pstat. I could put all the system-specific code */ - /* here, but will "abstract it into another routine to keep this */ - /* area more readable. I'll probably do the same thine with the */ - /* "low pri code" raj 10/95 */ - - /* since we are "flying blind" wrt where we should bind the looper - processes, we want to use the cpu_map that was prepared by netlib - rather than assume that the CPU ids on the system start at zero - and are contiguous. raj 2006-04-03 */ - bind_to_specific_processor(child_index % lib_num_loc_cpus,1); - - for (*my_counter_ptr = 0L; - ; - (*my_counter_ptr)++) { - if (!(*lib_base_pointer % 1)) { - /* every once and again, make sure that our process priority is */ - /* nice and low. also, by making system calls, it may be easier */ - /* for us to be pre-empted by something that needs to do useful */ - /* work - like the thread of execution actually sending and */ - /* receiving data across the network :) */ -#ifdef _AIX - int pid,prio; - - prio = PRIORITY; - pid = getpid(); - /* if you are not root, this call will return EPERM - why one */ - /* cannot change one's own priority to lower value is beyond */ - /* me. raj 2/26/96 */ - setpri(pid, prio); -#else /* _AIX */ -#ifdef __sgi - int pid,prio; - - prio = PRIORITY; - pid = getpid(); - schedctl(NDPRI, pid, prio); - sginap(0); -#else /* __sgi */ -#ifdef WIN32 - SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_IDLE); -#else /* WIN32 */ -#if defined(__sun) && defined(__SVR4) -#include <sys/types.h> -#include <sys/priocntl.h> -#include <sys/rtpriocntl.h> -#include <sys/tspriocntl.h> - /* I would *really* like to know how to use priocntl to make the */ - /* priority low for this looper process. however, either my mind */ - /* is addled, or the manpage in section two for priocntl is not */ - /* terribly helpful - for one, it has no examples :( so, if you */ - /* can help, I'd love to hear from you. in the meantime, we will */ - /* rely on nice(39). raj 2/26/96 */ - nice(39); -#else /* __sun && __SVR4 */ - nice(39); -#endif /* __sun && _SVR4 */ -#endif /* WIN32 */ -#endif /* __sgi */ -#endif /* _AIX */ - } - } -} - - - - /* this routine will start all the looper processes or threads for */ - /* measuring CPU utilization. */ - -static void -start_looper_processes() -{ - - unsigned int i, file_size; - - /* we want at least two pages for each processor. the */ - /* child for any one processor will write to the first of his two */ - /* pages, and the second page will be a buffer in case there is page */ - /* prefetching. if your system pre-fetches more than a single page, */ - /* well, you'll have to modify this or live with it :( raj 4/95 */ - - file_size = ((netlib_get_page_size() * PAGES_PER_CHILD) * - lib_num_loc_cpus); - -#ifndef WIN32 - - /* we we are not using WINDOWS NT (or 95 actually :), then we want */ - /* to create a memory mapped region so we can see all the counting */ - /* rates of the loopers */ - - /* could we just use an anonymous memory region for this? it is */ - /* possible that using a mmap()'ed "real" file, while convenient for */ - /* debugging, could result in some filesystem activity - like */ - /* metadata updates? raj 4/96 */ - lib_idle_fd = open("/tmp/netperf_cpu",O_RDWR | O_CREAT | O_EXCL); - - if (lib_idle_fd == -1) { - fprintf(where,"create_looper: file creation; errno %d\n",errno); - fflush(where); - exit(1); - } - - if (chmod("/tmp/netperf_cpu",0644) == -1) { - fprintf(where,"create_looper: chmod; errno %d\n",errno); - fflush(where); - exit(1); - } - - /* with the file descriptor in place, lets be sure that the file is */ - /* large enough. */ - - if (truncate("/tmp/netperf_cpu",file_size) == -1) { - fprintf(where,"create_looper: truncate: errno %d\n",errno); - fflush(where); - exit(1); - } - - /* the file should be large enough now, so we can mmap it */ - - /* if the system does not have MAP_VARIABLE, just define it to */ - /* be zero. it is only used/needed on HP-UX (?) raj 4/95 */ -#ifndef MAP_VARIABLE -#define MAP_VARIABLE 0x0000 -#endif /* MAP_VARIABLE */ -#ifndef MAP_FILE -#define MAP_FILE 0x0000 -#endif /* MAP_FILE */ - if ((lib_base_pointer = (long *)mmap(NULL, - file_size, - PROT_READ | PROT_WRITE, - MAP_FILE | MAP_SHARED | MAP_VARIABLE, - lib_idle_fd, - 0)) == (long *)-1) { - fprintf(where,"create_looper: mmap: errno %d\n",errno); - fflush(where); - exit(1); - } - - - if (debug > 1) { - fprintf(where,"num CPUs %d, file_size %d, lib_base_pointer %p\n", - lib_num_loc_cpus, - file_size, - lib_base_pointer); - fflush(where); - } - - /* we should have a valid base pointer. lets fork */ - - for (i = 0; i < (unsigned int)lib_num_loc_cpus; i++) { - switch (lib_idle_pids[i] = fork()) { - case -1: - perror("netperf: fork"); - exit(1); - case 0: - /* we are the child. we could decide to exec some separate */ - /* program, but that doesn't really seem worthwhile - raj 4/95 */ - - signal(SIGTERM, SIG_DFL); - sit_and_spin(i); - - /* we should never really get here, but if we do, just exit(0) */ - exit(0); - break; - default: - /* we must be the parent */ - lib_idle_address[i] = (uint64_t *) ((char *)lib_base_pointer + - (netlib_get_page_size() * - PAGES_PER_CHILD * i)); - if (debug) { - fprintf(where,"lib_idle_address[%d] is %p\n", - i, - lib_idle_address[i]); - fflush(where); - } - } - } -#else - /* we are compiled -DWIN32 */ - if ((lib_base_pointer = malloc(file_size)) == NULL) { - fprintf(where, - "create_looper_process could not malloc %d bytes\n", - file_size); - fflush(where); - exit(1); - } - - /* now, create all the threads */ - for(i = 0; i < (unsigned int)lib_num_loc_cpus; i++) { - long place_holder; - if ((lib_idle_pids[i] = CreateThread(0, - 0, - (LPTHREAD_START_ROUTINE)sit_and_spin, - (LPVOID)(ULONG_PTR)i, - 0, - &place_holder)) == NULL ) { - fprintf(where, - "create_looper_process: CreateThread failed\n"); - fflush(where); - /* I wonder if I need to look for other threads to kill? */ - exit(1); - } - lib_idle_address[i] = (long *) ((char *)lib_base_pointer + - (netlib_get_page_size() * - PAGES_PER_CHILD * i)); - if (debug) { - fprintf(where,"lib_idle_address[%d] is %p\n", - i, - lib_idle_address[i]); - fflush(where); - } - } -#endif /* WIN32 */ - - /* we need to have the looper processes settled-in before we do */ - /* anything with them, so lets sleep for say 30 seconds. raj 4/95 */ - - sleep(30); -} - -void -cpu_util_init(void) -{ - cpu_method = LOOPER; - - /* we want to get the looper processes going */ - if (!lib_loopers_running) { - start_looper_processes(); - lib_loopers_running = 1; - } - - return; -} - -/* clean-up any left-over CPU util resources - looper processes, - files, whatever. raj 2005-01-26 */ -void -cpu_util_terminate() { - -#ifdef WIN32 - /* it would seem that if/when the process exits, all the threads */ - /* will go away too, so I don't think I need any explicit thread */ - /* killing calls here. raj 1/96 */ -#else - - int i; - - /* now go through and kill-off all the child processes */ - for (i = 0; i < lib_num_loc_cpus; i++){ - /* SIGKILL can leave core files behind - thanks to Steinar Haug */ - /* for pointing that out. */ - kill(lib_idle_pids[i],SIGTERM); - } - lib_loopers_running = 0; - /* reap the children */ - while(waitpid(-1, NULL, WNOHANG) > 0) { } - - /* finally, unlink the mmaped file */ - munmap((caddr_t)lib_base_pointer, - ((netlib_get_page_size() * PAGES_PER_CHILD) * - lib_num_loc_cpus)); - unlink("/tmp/netperf_cpu"); -#endif - return; -} - -int -get_cpu_method(void) -{ - return LOOPER; -} - - /* calibrate_looper */ - - /* Loop a number of iterations, sleeping interval seconds each and */ - /* count how high the idle counter gets each time. Return the */ - /* measured cpu rate to the calling routine. raj 4/95 */ - -float -calibrate_idle_rate (int iterations, int interval) -{ - - uint64_t - firstcnt[MAXCPUS], - secondcnt[MAXCPUS]; - - float - elapsed, - temp_rate, - rate[MAXTIMES], - local_maxrate; - - long - sec, - usec; - - int - i, - j; - - struct timeval time1, time2 ; - struct timezone tz; - - if (iterations > MAXTIMES) { - iterations = MAXTIMES; - } - - local_maxrate = (float)-1.0; - - for(i = 0; i < iterations; i++) { - rate[i] = (float)0.0; - for (j = 0; j < lib_num_loc_cpus; j++) { - firstcnt[j] = *(lib_idle_address[j]); - } - gettimeofday (&time1, &tz); - sleep(interval); - gettimeofday (&time2, &tz); - - if (time2.tv_usec < time1.tv_usec) - { - time2.tv_usec += 1000000; - time2.tv_sec -=1; - } - sec = time2.tv_sec - time1.tv_sec; - usec = time2.tv_usec - time1.tv_usec; - elapsed = (float)sec + ((float)usec/(float)1000000.0); - - if(debug) { - fprintf(where, "Calibration for counter run: %d\n",i); - fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec); - fprintf(where,"\telapsed time = %g\n",elapsed); - } - - for (j = 0; j < lib_num_loc_cpus; j++) { - secondcnt[j] = *(lib_idle_address[j]); - if(debug) { - /* I know that there are situations where compilers know about */ - /* long long, but the library fucntions do not... raj 4/95 */ - fprintf(where, - "\tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lx\n", - j, - (uint32_t)(firstcnt[j]>>32), - (uint32_t)(firstcnt[j]&0xffffffff), - j, - (uint32_t)(secondcnt[j]>>32), - (uint32_t)(secondcnt[j]&0xffffffff)); - } - /* we assume that it would wrap no more than once. we also */ - /* assume that the result of subtracting will "fit" raj 4/95 */ - temp_rate = (secondcnt[j] >= firstcnt[j]) ? - (float)(secondcnt[j] - firstcnt[j])/elapsed : - (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed; - if (temp_rate > rate[i]) rate[i] = temp_rate; - if(debug) { - fprintf(where,"\trate[%d] = %g\n",i,rate[i]); - fflush(where); - } - if (local_maxrate < rate[i]) local_maxrate = rate[i]; - } - } - if(debug) { - fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate); - fflush(where); - } - return local_maxrate; -} - - -void -get_cpu_idle (uint64_t *res) -{ - int i; - - for (i = 0; i < lib_num_loc_cpus; i++){ - res[i] = *lib_idle_address[i]; - } - -} - -float -calc_cpu_util_internal(float elapsed_time) -{ - int i; - float correction_factor; - float actual_rate; - - lib_local_cpu_util = (float)0.0; - /* It is possible that the library measured a time other than */ - /* the one that the user want for the cpu utilization */ - /* calculations - for example, tests that were ended by */ - /* watchdog timers such as the udp stream test. We let these */ - /* tests tell up what the elapsed time should be. */ - - if (elapsed_time != 0.0) { - correction_factor = (float) 1.0 + - ((lib_elapsed - elapsed_time) / elapsed_time); - } - else { - correction_factor = (float) 1.0; - } - - for (i = 0; i < lib_num_loc_cpus; i++) { - - /* it would appear that on some systems, in loopback, nice is - *very* effective, causing the looper process to stop dead in its - tracks. if this happens, we need to ensure that the calculation - does not go south. raj 6/95 and if we run completely out of idle, - the same thing could in theory happen to the USE_KSTAT path. raj - 8/2000 */ - - if (lib_end_count[i] == lib_start_count[i]) { - lib_end_count[i]++; - } - - actual_rate = (lib_end_count[i] > lib_start_count[i]) ? - (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed : - (float)(lib_end_count[i] - lib_start_count[i] + - MAXLONG)/ lib_elapsed; - if (debug) { - fprintf(where, - "calc_cpu_util: actual_rate on processor %d is %f start 0x%8.8lx%8.8lx end 0x%8.8lx%8.8lx\n", - i, - actual_rate, - (uint32_t)(lib_start_count[i]>>32), - (uint32_t)(lib_start_count[i]&0xffffffff), - (uint32_t)(lib_end_count[i]>>32), - (uint32_t)(lib_end_count[i]&0xffffffff)); - } - lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) / - lib_local_maxrate * 100; - lib_local_cpu_util += lib_local_per_cpu_util[i]; - } - /* we want the average across all n processors */ - lib_local_cpu_util /= (float)lib_num_loc_cpus; - - lib_local_cpu_util *= correction_factor; - return lib_local_cpu_util; - - -} -void -cpu_start_internal(void) -{ - get_cpu_idle(lib_start_count); - return; -} - -void -cpu_stop_internal(void) -{ - get_cpu_idle(lib_end_count); -} diff --git a/netcpu_none.c b/netcpu_none.c deleted file mode 100644 index f71b240..0000000 --- a/netcpu_none.c +++ /dev/null @@ -1,67 +0,0 @@ -char netcpu_none_id[]="\ -@(#)netcpu_none.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.0"; - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdio.h> - -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif - -#include "netsh.h" -#include "netlib.h" - -void -cpu_util_init(void) -{ - return; -} - -void -cpu_util_terminate(void) -{ - return; -} - -int -get_cpu_method(void) -{ - return CPU_UNKNOWN; -} - -void -get_cpu_idle(uint64_t *res) -{ - return; -} - -float -calibrate_idle_rate(int iterations, int interval) -{ - return 0.0; -} - -float -calc_cpu_util_internal(float elapsed_time) -{ - return -1.0; -} - -void -cpu_start_internal(void) -{ - return; -} - -void -cpu_stop_internal(void) -{ - return; -} diff --git a/netcpu_ntperf.c b/netcpu_ntperf.c deleted file mode 100644 index e8d8f76..0000000 --- a/netcpu_ntperf.c +++ /dev/null @@ -1,497 +0,0 @@ -char netcpu_ntperf_id[]="\ -@(#)netcpu_ntperf.c (c) Copyright 2005-2007, Hewlett-Packard Company, Version 2.4.3"; - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdio.h> - -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif - -#if 0 -#include <limits.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <string.h> -#endif - -#include <assert.h> - -#include <process.h> -#include <time.h> - -#include <windows.h> -#include <assert.h> - -#include <winsock2.h> -// If you are trying to compile on Windows 2000 or NT 4.0 you may -// need to define DONT_IPV6 in the "sources" files. -#ifndef DONT_IPV6 -#include <ws2tcpip.h> -#endif - -#include "netsh.h" -#include "netlib.h" - -// -// System CPU time information class. -// Used to get CPU time information. -// -// SDK\inc\ntexapi.h -// Function x8: SystemProcessorPerformanceInformation -// DataStructure: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION -// - -#define SystemProcessorPerformanceInformation 0x08 - -typedef struct -{ - LARGE_INTEGER IdleTime; - LARGE_INTEGER KernelTime; - LARGE_INTEGER UserTime; - LARGE_INTEGER DpcTime; - LARGE_INTEGER InterruptTime; - LONG InterruptCount; -} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; - -// -// Calls to get the information -// -typedef ULONG (__stdcall *NT_QUERY_SYSTEM_INFORMATION)( - ULONG SystemInformationClass, - PVOID SystemInformation, - ULONG SystemInformationLength, - PULONG ReturnLength - ); - -NT_QUERY_SYSTEM_INFORMATION NtQuerySystemInformation = NULL; - - -static LARGE_INTEGER TickHz = {0,0}; - -_inline LARGE_INTEGER ReadPerformanceCounter(VOID) -{ - LARGE_INTEGER Counter; - QueryPerformanceCounter(&Counter); - - return(Counter); -} // ReadperformanceCounter - - -/* The NT performance data is accessed through the NtQuerySystemInformation - call. References to the PDH.DLL have been deleted. This structure - is the root for these data structures. */ - -typedef struct sPerfObj -{ - LARGE_INTEGER StartTime; - LARGE_INTEGER EndTime; - SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION StartInfo[MAXCPUS +1]; - SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION EndInfo[MAXCPUS +1]; -} PerfObj, *PPerfObj; - -static PerfObj *PerfCntrs; - -// Forward declarations - -PerfObj *InitPerfCntrs(); -void RestartPerfCntrs(PerfObj *PerfCntrs); -double ReportPerfCntrs(PerfObj *PerfCntrs); /* returns CPU utilization */ -void ClosePerfCntrs(PerfObj *PerfCntrs); - - -void -cpu_util_init(void) -{ - if (NtQuerySystemInformation == NULL) { - // Open the performance counter interface - PerfCntrs = InitPerfCntrs(); - } - return; -} - -void -cpu_util_terminate(void) -{ - return; -} - -int -get_cpu_method(void) -{ - return NT_METHOD; -} - -typedef unsigned __int64 uint64_t; - -void -get_cpu_idle(uint64_t *res) -{ - RestartPerfCntrs(PerfCntrs); - return; -} - -float -calibrate_idle_rate(int iterations, int interval) -{ - return (float)0.0; -} - - -/* - InitPerfCntrs() - - - Changed to no longer access the NT performance registry interfaces. - A direct call to NtQuerySystemInformation (an undocumented NT API) - is made instead. Parameters determined by decompilation of ntkrnlmp - and ntdll. -*/ - - -PerfObj *InitPerfCntrs() -{ - PerfObj *NewPerfCntrs; - DWORD NTVersion; - DWORD status; - SYSTEM_INFO SystemInfo; - - GetSystemInfo(&SystemInfo); - - NewPerfCntrs = (PerfObj *)GlobalAlloc(GPTR, sizeof(PerfObj)); - assert(NewPerfCntrs != NULL); - - ZeroMemory((PCHAR)NewPerfCntrs, sizeof(PerfObj)); - - // get NT version - NTVersion = GetVersion(); - if (NTVersion >= 0x80000000) - { - fprintf(stderr, "Not running on Windows NT\n"); - exit(1); - } - - // locate the calls we need in NTDLL - //Lint - NtQuerySystemInformation = - (NT_QUERY_SYSTEM_INFORMATION)GetProcAddress( GetModuleHandle("ntdll.dll"), - "NtQuerySystemInformation" ); - - if ( !(NtQuerySystemInformation) ) - { - //Lint - status = GetLastError(); - fprintf(stderr, "GetProcAddressFailed, status: %X\n", status); - exit(1); - } - - // setup to measure timestamps with the high resolution timers. - if (QueryPerformanceFrequency(&TickHz) == FALSE) - { - fprintf(stderr,"MAIN - QueryPerformanceFrequency Failed!\n"); - exit(2); - } - - RestartPerfCntrs(NewPerfCntrs); - - return(NewPerfCntrs); -} /* InitPerfCntrs */ - -/* - RestartPerfCntrs() - - - The Performance counters must be read twice to produce rate and - percentage results. This routine is called before the start of a - benchmark to establish the initial counters. It must be called a - second time after the benchmark completes to collect the final state - of the performance counters. ReportPerfCntrs is called to print the - results after the benchmark completes. -*/ - -void RestartPerfCntrs(PerfObj *PerfCntrs) -{ - DWORD returnLength = 0; //Lint - DWORD returnNumCPUs; //Lint - DWORD i; - - DWORD status; - SYSTEM_INFO SystemInfo; - - GetSystemInfo(&SystemInfo); - - // Move previous data from EndInfo to StartInfo. - CopyMemory((PCHAR)&PerfCntrs->StartInfo[0], - (PCHAR)&PerfCntrs->EndInfo[0], - sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*(MAXCPUS +1)); - - PerfCntrs->StartTime = PerfCntrs->EndTime; - - // get the current CPUTIME information - if ( (status = NtQuerySystemInformation( SystemProcessorPerformanceInformation, - (PCHAR)&PerfCntrs->EndInfo[0], sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*MAXCPUS, - &returnLength )) != 0) - { - fprintf(stderr, "NtQuery failed, status: %X\n", status); - exit(1); - } - - PerfCntrs->EndTime = ReadPerformanceCounter(); - - // Validate that NtQuery returned a reasonable amount of data - if ((returnLength % sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)) != 0) - { - fprintf(stderr, "NtQuery didn't return expected amount of data\n"); - fprintf(stderr, "Expected a multiple of %i, returned %i\n", - sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), returnLength); - exit(1); - } - returnNumCPUs = returnLength / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); - - if (returnNumCPUs != (int)SystemInfo.dwNumberOfProcessors) - { - fprintf(stderr, "NtQuery didn't return expected amount of data\n"); - fprintf(stderr, "Expected data for %i CPUs, returned %i\n", - (int)SystemInfo.dwNumberOfProcessors, returnNumCPUs); - exit(1); - } - - // Zero entries not returned by NtQuery - ZeroMemory((PCHAR)&PerfCntrs->EndInfo[returnNumCPUs], - sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)* - (MAXCPUS +1 - returnNumCPUs)); - - // Total all of the CPUs - // KernelTime needs to be fixed-up; it includes both idle & - // true kernel time - // Note that kernel time also includes DpcTime & InterruptTime, but - // I like this. - for (i=0; i < returnNumCPUs; i++) - { - PerfCntrs->EndInfo[i].KernelTime.QuadPart -= PerfCntrs->EndInfo[i].IdleTime.QuadPart; - PerfCntrs->EndInfo[MAXCPUS].IdleTime.QuadPart += PerfCntrs->EndInfo[i].IdleTime.QuadPart; - PerfCntrs->EndInfo[MAXCPUS].KernelTime.QuadPart += PerfCntrs->EndInfo[i].KernelTime.QuadPart; - PerfCntrs->EndInfo[MAXCPUS].UserTime.QuadPart += PerfCntrs->EndInfo[i].UserTime.QuadPart; - PerfCntrs->EndInfo[MAXCPUS].DpcTime.QuadPart += PerfCntrs->EndInfo[i].DpcTime.QuadPart; - PerfCntrs->EndInfo[MAXCPUS].InterruptTime.QuadPart += PerfCntrs->EndInfo[i].InterruptTime.QuadPart; - PerfCntrs->EndInfo[MAXCPUS].InterruptCount += PerfCntrs->EndInfo[i].InterruptCount; - } - -} /* RestartPerfCntrs */ - -/* - ReportPerfCntrs() - - This routine reports the results of the various performance - counters. -*/ - -double ReportPerfCntrs(PerfObj *PerfCntrs) -{ - double tot_CPU_Util; - int i; - int duration; // in 100 usecs - - LARGE_INTEGER ActualDuration; - - SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION DeltaInfo[MAXCPUS +1]; - - LARGE_INTEGER TotalCPUTime[MAXCPUS +1]; - - SYSTEM_INFO SystemInfo; - - GetSystemInfo(&SystemInfo); - - for (i=0; i <= MAXCPUS; i++) - { - DeltaInfo[i].IdleTime.QuadPart = PerfCntrs->EndInfo[i].IdleTime.QuadPart - - PerfCntrs->StartInfo[i].IdleTime.QuadPart; - DeltaInfo[i].KernelTime.QuadPart = PerfCntrs->EndInfo[i].KernelTime.QuadPart - - PerfCntrs->StartInfo[i].KernelTime.QuadPart; - DeltaInfo[i].UserTime.QuadPart = PerfCntrs->EndInfo[i].UserTime.QuadPart - - PerfCntrs->StartInfo[i].UserTime.QuadPart; - DeltaInfo[i].DpcTime.QuadPart = PerfCntrs->EndInfo[i].DpcTime.QuadPart - - PerfCntrs->StartInfo[i].DpcTime.QuadPart; - DeltaInfo[i].InterruptTime.QuadPart = PerfCntrs->EndInfo[i].InterruptTime.QuadPart - - PerfCntrs->StartInfo[i].InterruptTime.QuadPart; - DeltaInfo[i].InterruptCount = PerfCntrs->EndInfo[i].InterruptCount - - PerfCntrs->StartInfo[i].InterruptCount; - - TotalCPUTime[i].QuadPart = - DeltaInfo[i].IdleTime.QuadPart + - DeltaInfo[i].KernelTime.QuadPart + - DeltaInfo[i].UserTime.QuadPart; - // KernelTime already includes DpcTime & InterruptTime! - // + DeltaInfo[i].DpcTime.QuadPart + - // DeltaInfo[i].InterruptTime.QuadPart; - } - - tot_CPU_Util = 100.0*(1.0 - (double)DeltaInfo[MAXCPUS].IdleTime.QuadPart/(double)TotalCPUTime[MAXCPUS].QuadPart); //Lint - - // Re-calculate duration, since we may have stoped early due to cntr-C. - ActualDuration.QuadPart = PerfCntrs->EndTime.QuadPart - - PerfCntrs->StartTime.QuadPart; - - // convert to 1/10 milliseconds (100 usec) - ActualDuration.QuadPart = (ActualDuration.QuadPart*10000)/TickHz.QuadPart; - duration = ActualDuration.LowPart; - - if (verbosity > 1) - { - fprintf(where,"ActualDuration (ms): %d\n", duration/10); - } - - if (verbosity > 1) - { - fprintf(where, "%% CPU _Total"); - if ((int)SystemInfo.dwNumberOfProcessors > 1) - { - for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++) - { - fprintf(where, "\t CPU %i", i); - } - } - fprintf(where, "\n"); - - fprintf(where, "Busy %5.2f", tot_CPU_Util); - if ((int)SystemInfo.dwNumberOfProcessors > 1) - { - for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++) - { - fprintf(where, "\t %5.2f", - 100.0*(1.0 - (double)DeltaInfo[i].IdleTime.QuadPart/(double)TotalCPUTime[i].QuadPart)); //Lint - } - } - fprintf(where, "\n"); - - fprintf(where, "Kernel %5.2f", - 100.0*(double)DeltaInfo[MAXCPUS].KernelTime.QuadPart/(double)TotalCPUTime[MAXCPUS].QuadPart); //Lint - - if ((int)SystemInfo.dwNumberOfProcessors > 1) - { - for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++) - { - fprintf(where, "\t %5.2f", - 100.0*(double)DeltaInfo[i].KernelTime.QuadPart/(double)TotalCPUTime[i].QuadPart); //Lint - } - } - fprintf(where, "\n"); - - fprintf(where, "User %5.2f", - 100.0*(double)DeltaInfo[MAXCPUS].UserTime.QuadPart/(double)TotalCPUTime[MAXCPUS].QuadPart); - - if ((int)SystemInfo.dwNumberOfProcessors > 1) - { - for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++) - { - fprintf(where, "\t %5.2f", - 100.0*(double)DeltaInfo[i].UserTime.QuadPart/TotalCPUTime[i].QuadPart); //Lint - } - } - fprintf(where, "\n"); - - fprintf(where, "Dpc %5.2f", - 100.0*(double)DeltaInfo[MAXCPUS].DpcTime.QuadPart/(double)TotalCPUTime[MAXCPUS].QuadPart); //Lint - - if ((int)SystemInfo.dwNumberOfProcessors > 1) - { - for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++) - { - fprintf(where, "\t %5.2f", - 100.0*(double)DeltaInfo[i].DpcTime.QuadPart/(double)TotalCPUTime[i].QuadPart); //Lint - } - } - fprintf(where, "\n"); - - fprintf(where, "Interrupt %5.2f", - 100.0*(double)DeltaInfo[MAXCPUS].InterruptTime.QuadPart/(double)TotalCPUTime[MAXCPUS].QuadPart); //Lint - - if ((int)SystemInfo.dwNumberOfProcessors > 1) - { - for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++) - { - fprintf(where, "\t %5.2f", - 100.0*(double)DeltaInfo[i].InterruptTime.QuadPart/TotalCPUTime[i].QuadPart); //Lint - } - } - fprintf(where, "\n\n"); - - fprintf(where, "Interrupt/Sec. %5.1f", - (double)DeltaInfo[MAXCPUS].InterruptCount*10000.0/(double)duration); - - if ((int)SystemInfo.dwNumberOfProcessors > 1) - { - for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++) - { - fprintf(where, "\t %5.1f", - (double)DeltaInfo[i].InterruptCount*10000.0/(double)duration); - } - } - fprintf(where, "\n\n"); - fflush(where); - } - - return (tot_CPU_Util); - -} /* ReportPerfCntrs */ - -/* - ClosePerfCntrs() - - - This routine cleans up the performance counter APIs. -*/ - -void ClosePerfCntrs(PerfObj *PerfCntrs) -{ - GlobalFree(PerfCntrs); - - NtQuerySystemInformation = NULL; -} /* ClosePerfCntrs */ - -void -cpu_start_internal(void) -{ - RestartPerfCntrs(PerfCntrs);
-} - -void -cpu_stop_internal(void) -{ - RestartPerfCntrs(PerfCntrs);
-} - -float -calc_cpu_util_internal(float elapsed_time) -{ - float correction_factor; - lib_local_cpu_util = (float)0.0; - /* It is possible that the library measured a time other than */ - /* the one that the user want for the cpu utilization */ - /* calculations - for example, tests that were ended by */ - /* watchdog timers such as the udp stream test. We let these */ - /* tests tell up what the elapsed time should be. */ - - if (elapsed_time != 0.0) { - correction_factor = (float) 1.0 + - ((lib_elapsed - elapsed_time) / elapsed_time); - } - else { - correction_factor = (float) 1.0; - } - - if (debug) { - fprintf(where, "correction factor: %f\n", correction_factor); - } - - lib_local_cpu_util = (float)ReportPerfCntrs(PerfCntrs); - lib_local_cpu_util *= correction_factor; - return lib_local_cpu_util; - -} diff --git a/netcpu_osx.c b/netcpu_osx.c deleted file mode 100644 index 2132be1..0000000 --- a/netcpu_osx.c +++ /dev/null @@ -1,149 +0,0 @@ -char netcpu_sysctl_id[]="\ -@(#)netcpu_osx.c Version 2.4.3"; - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdio.h> - -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif - -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif -#if HAVE_LIMITS_H -# include <limits.h> -# ifndef LONG_LONG_MAX -# define LONG_LONG_MAX LLONG_MAX -# endif /* LONG_LONG_MAX */ -#endif - - -#include <errno.h> - -#include <mach/host_info.h> -#include <mach/mach_types.h> -/* it would seem that on 10.3.9 mach_msg_type_number_t is in - <mach/message.h> so we'll see about including that one too. - hopefully it still exists in 10.4. if not, we will need to add some - .h file checks in configure so we can use "HAVE_mumble" ifdefs - here */ -#include <mach/message.h> - -#include "netsh.h" -#include "netlib.h" - -#define UNSIGNED_DIFFERENCE(x,y) (x >= y ? x - y : (0 - y) + x ) - -static host_cpu_load_info_data_t lib_start_ticks; -static host_cpu_load_info_data_t lib_end_ticks; - -static mach_port_t lib_host_port; - -void -cpu_util_init(void) -{ - lib_host_port = mach_host_self(); - return; -} - -void -cpu_util_terminate(void) -{ - mach_port_deallocate(lib_host_port); - return; -} - -int -get_cpu_method(void) -{ - return OSX; -} - -void -get_cpu_idle(uint64_t *res) -{ - return; -} - -void -get_host_ticks(host_cpu_load_info_t info) -{ - mach_msg_type_number_t count; - - count = HOST_CPU_LOAD_INFO_COUNT; - host_statistics(lib_host_port, HOST_CPU_LOAD_INFO, (host_info_t)info, &count); - return; -} - -/* calibrate_sysctl - perform the idle rate calculation using the - sysctl call - typically on BSD */ - -float -calibrate_idle_rate(int iterations, int interval) -{ - return (float)0.0; -} - -float -calc_cpu_util_internal(float elapsed_time) -{ - float correction_factor; - natural_t userticks, systicks, idleticks, totalticks; - - lib_local_cpu_util = (float)0.0; - /* It is possible that the library measured a time other than */ - /* the one that the user want for the cpu utilization */ - /* calculations - for example, tests that were ended by */ - /* watchdog timers such as the udp stream test. We let these */ - /* tests tell up what the elapsed time should be. */ - - if (elapsed_time != 0.0) { - correction_factor = (float) 1.0 + - ((lib_elapsed - elapsed_time) / elapsed_time); - } - else { - correction_factor = (float) 1.0; - } - - if (debug) { - fprintf(where, "correction factor: %f\n", correction_factor); - } - - userticks = UNSIGNED_DIFFERENCE((lib_end_ticks.cpu_ticks[CPU_STATE_USER] + lib_end_ticks.cpu_ticks[CPU_STATE_NICE]), - (lib_start_ticks.cpu_ticks[CPU_STATE_USER] + lib_start_ticks.cpu_ticks[CPU_STATE_NICE])); - systicks = UNSIGNED_DIFFERENCE(lib_end_ticks.cpu_ticks[CPU_STATE_SYSTEM], lib_start_ticks.cpu_ticks[CPU_STATE_SYSTEM]); - idleticks = UNSIGNED_DIFFERENCE(lib_end_ticks.cpu_ticks[CPU_STATE_IDLE], lib_start_ticks.cpu_ticks[CPU_STATE_IDLE]); - totalticks = userticks + systicks + idleticks; - - lib_local_cpu_util = ((float)userticks + (float)systicks)/(float)totalticks * 100.0f; - lib_local_cpu_util *= correction_factor; - - return lib_local_cpu_util; - -} -void -cpu_start_internal(void) -{ - get_host_ticks(&lib_start_ticks); -} - -void -cpu_stop_internal(void) -{ - get_host_ticks(&lib_end_ticks); -} diff --git a/netcpu_perfstat.c b/netcpu_perfstat.c deleted file mode 100644 index f928a25..0000000 --- a/netcpu_perfstat.c +++ /dev/null @@ -1,351 +0,0 @@ -char netcpu_perfstat_id[]="\ -@(#)netcpu_perfstat.c Version 2.4.0"; - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdio.h> - -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif - -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif - -#if HAVE_LIMITS_H -# include <limits.h> -# ifndef LONG_LONG_MAX -# define LONG_LONG_MAX LLONG_MAX -# endif /* LONG_LONG_MAX */ -#endif - -#include <errno.h> - -#include "netsh.h" -#include "netlib.h" - -/* the lib_start_count and lib_end_count arrays hold the starting - and ending values of whatever is counting when the system is - idle. The rate at which this increments during a test is compared - with a previous calibration to arrive at a CPU utilization - percentage. raj 2005-01-26 */ -static uint64_t lib_start_count[MAXCPUS]; -static uint64_t lib_end_count[MAXCPUS]; - - -void -cpu_util_init(void) -{ - return; -} - -void -cpu_util_terminate(void) -{ - return; -} - -int -get_cpu_method(void) -{ - return PERFSTAT; -} - -void -get_cpu_idle(uint64_t *res) -{ - perfstat_cpu_t *perfstat_buffer; - perfstat_cpu_t *per_cpu_pointer; - perfstat_id_t name; - int i,ret; - - /* a name of "" will cause us to start from the beginning */ - strcpy(name.name,""); - perfstat_buffer = (perfstat_cpu_t *)malloc(lib_num_loc_cpus * - sizeof(perfstat_cpu_t)); - if (perfstat_buffer == NULL) { - fprintf(where, - "cpu_start: malloc failed errno %d\n", - errno); - fflush(where); - exit(-1); - } - - /* happiness and joy, keep going */ - ret = perfstat_cpu(&name, - perfstat_buffer, - sizeof(perfstat_cpu_t), - lib_num_loc_cpus); - - if ((ret == -1) || - (ret != lib_num_loc_cpus)) { - fprintf(where, - "cpu_start: perfstat_cpu failed/count off; errno %d cpus %d count %d\n", - errno, - lib_num_loc_cpus, - ret); - fflush(where); - exit(-1); - } - - per_cpu_pointer = perfstat_buffer; - for (i = 0; i < lib_num_loc_cpus; i++){ - res[i] = per_cpu_pointer->idle; - per_cpu_pointer++; - } - free(perfstat_buffer); - - return; -} - -float -calibrate_idle_rate(int iterations, int interval) -{ - unsigned long long - firstcnt[MAXCPUS], - secondcnt[MAXCPUS]; - - float - elapsed, - temp_rate, - rate[MAXTIMES], - local_maxrate; - - long - sec, - usec; - - int - i, - j; - - struct timeval time1, time2 ; - struct timezone tz; - - perfstat_cpu_t *perfstat_buffer; - perfstat_cpu_t *per_cpu_pointer; - perfstat_id_t name; - int ret; - - if (debug) { - fprintf(where,"enter calibrate_perfstat\n"); - fflush(where); - } - - if (iterations > MAXTIMES) { - iterations = MAXTIMES; - } - - local_maxrate = (float)-1.0; - - perfstat_buffer = (perfstat_cpu_t *)malloc(lib_num_loc_cpus * - sizeof(perfstat_cpu_t)); - if (perfstat_buffer == NULL) { - fprintf(where, - "calibrate_perfstat: malloc failed errno %d\n", - errno); - fflush(where); - exit(-1); - } - - for(i = 0; i < iterations; i++) { - rate[i] = (float)0.0; - /* a name of "" will cause us to start from the beginning */ - strcpy(name.name,""); - - /* happiness and joy, keep going */ - ret = perfstat_cpu(&name, - perfstat_buffer, - sizeof(perfstat_cpu_t), - lib_num_loc_cpus); - - if ((ret == -1) || - (ret != lib_num_loc_cpus)) { - fprintf(where, - "calibrate_perfstat: perfstat_cpu failed/count off; errno %d cpus %d count %d\n", - errno, - lib_num_loc_cpus, - ret); - fflush(where); - exit(-1); - } - - per_cpu_pointer = perfstat_buffer; - for (j = 0; j < lib_num_loc_cpus; j++) { - firstcnt[j] = per_cpu_pointer->idle; - per_cpu_pointer++; - } - gettimeofday (&time1, &tz); - sleep(interval); - gettimeofday (&time2, &tz); - - if (time2.tv_usec < time1.tv_usec) - { - time2.tv_usec += 1000000; - time2.tv_sec -=1; - } - sec = time2.tv_sec - time1.tv_sec; - usec = time2.tv_usec - time1.tv_usec; - elapsed = (float)sec + ((float)usec/(float)1000000.0); - - /* happiness and joy, keep going */ - ret = perfstat_cpu(&name, - perfstat_buffer, - sizeof(perfstat_cpu_t), - lib_num_loc_cpus); - - if ((ret == -1) || - (ret != lib_num_loc_cpus)) { - fprintf(where, - "calibrate_perfstat: perfstat_cpu failed/count off; errno %d cpus %d count %d\n", - errno, - lib_num_loc_cpus, - ret); - fflush(where); - exit(-1); - } - - per_cpu_pointer = perfstat_buffer; - - if(debug) { - fprintf(where, "Calibration for perfstat counter run: %d\n",i); - fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec); - fprintf(where,"\telapsed time = %g\n",elapsed); - } - - for (j = 0; j < lib_num_loc_cpus; j++) { - secondcnt[j] = per_cpu_pointer->idle; - per_cpu_pointer++; - if(debug) { - /* I know that there are situations where compilers know about */ - /* long long, but the library functions do not... raj 4/95 */ - fprintf(where, - "\tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lx\n", - j, - firstcnt[j], - firstcnt[j], - j, - secondcnt[j], - secondcnt[j]); - } - /* we assume that it would wrap no more than once. we also */ - /* assume that the result of subtracting will "fit" raj 4/95 */ - temp_rate = (secondcnt[j] >= firstcnt[j]) ? - (float)(secondcnt[j] - firstcnt[j])/elapsed : - (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed; - if (temp_rate > rate[i]) rate[i] = temp_rate; - if(debug) { - fprintf(where,"\trate[%d] = %g\n",i,rate[i]); - fflush(where); - } - if (local_maxrate < rate[i]) local_maxrate = rate[i]; - } - } - if(debug) { - fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate); - fflush(where); - } - free(perfstat_buffer); - return local_maxrate; -} - -float -calc_cpu_util_internal(float elapsed_time) -{ - int i; - - float actual_rate; - float correction_factor; - - lib_local_cpu_util = (float)0.0; - /* It is possible that the library measured a time other than */ - /* the one that the user want for the cpu utilization */ - /* calculations - for example, tests that were ended by */ - /* watchdog timers such as the udp stream test. We let these */ - /* tests tell up what the elapsed time should be. */ - - if (elapsed_time != 0.0) { - correction_factor = (float) 1.0 + - ((lib_elapsed - elapsed_time) / elapsed_time); - } - else { - correction_factor = (float) 1.0; - } - - /* this looks just like the looper case. at least I think it */ - /* should :) raj 4/95 */ - for (i = 0; i < lib_num_loc_cpus; i++) { - - /* we assume that the two are not more than a long apart. I */ - /* know that this is bad, but trying to go from long longs to */ - /* a float (perhaps a double) is boggling my mind right now. */ - /* raj 4/95 */ - - long long - diff; - - if (lib_end_count[i] >= lib_start_count[i]) { - diff = lib_end_count[i] - lib_start_count[i]; - } - else { - diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX; - } - actual_rate = (float) diff / lib_elapsed; - lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) / - lib_local_maxrate * 100; - lib_local_cpu_util += lib_local_per_cpu_util[i]; - if (debug) { - fprintf(where, - "calc_cpu_util: actual_rate on cpu %d is %g max_rate %g cpu %6.2f\n", - i, - actual_rate, - lib_local_maxrate, - lib_local_per_cpu_util[i]); - } - } - - /* we want the average across all n processors */ - lib_local_cpu_util /= (float)lib_num_loc_cpus; - - if (debug) { - fprintf(where, - "calc_cpu_util: average across CPUs is %g\n",lib_local_cpu_util); - } - - lib_local_cpu_util *= correction_factor; - - if (debug) { - fprintf(where, - "calc_cpu_util: returning %g\n",lib_local_cpu_util); - } - - return lib_local_cpu_util; - -} -void -cpu_start_internal(void) -{ - get_cpu_idle(lib_start_count); - return; -} - -void -cpu_stop_internal(void) -{ - get_cpu_idle(lib_end_count); -} - diff --git a/netcpu_procstat.c b/netcpu_procstat.c deleted file mode 100644 index 5bdadea..0000000 --- a/netcpu_procstat.c +++ /dev/null @@ -1,265 +0,0 @@ -char netcpu_procstat_id[]="\ -@(#)netcpu_procstat.c (c) Copyright 2005-2007 Version 2.4.3"; - -/* netcpu_procstat.c - - Implement the /proc/stat specific portions of netperf CPU - utilization measurements. These are broken-out into a separate file - to make life much nicer over in netlib.c which had become a maze of - twisty, CPU-util-related, #ifdefs, all different. raj 2005-01-26 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> - -#ifdef HAVE_FCNTL_H -# include <fcntl.h> -#endif -#if HAVE_UNISTD_H -# include <unistd.h> -#endif -#if STDC_HEADERS -# include <stdlib.h> -# include <stddef.h> -#else -# if HAVE_STDLIB_H -# include <stdlib.h> -# endif -#endif - -#include <string.h> - -#include "netsh.h" -#include "netlib.h" - -/* the lib_start_count and lib_end_count arrays hold the starting - and ending values of whatever is counting when the system is - idle. The rate at which this increments during a test is compared - with a previous calibrarion to arrive at a CPU utilization - percentage. raj 2005-01-26 */ -static uint64_t lib_start_count[MAXCPUS]; -static uint64_t lib_end_count[MAXCPUS]; - - -/* The max. length of one line of /proc/stat cpu output */ -#define CPU_LINE_LENGTH ((8 * sizeof (long) / 3 + 1) * 4 + 8) -#define PROC_STAT_FILE_NAME "/proc/stat" -#define N_CPU_LINES(nr) (nr == 1 ? 1 : 1 + nr) - -static int proc_stat_fd = -1; -static char *proc_stat_buf = NULL; -static int proc_stat_buflen = 0; - -void -cpu_util_init(void) -{ - - if (debug) { - fprintf(where, - "cpu_util_init enter, proc_stat_fd %d proc_stat_buf %p\n", - proc_stat_fd, - proc_stat_buf); - fflush(where); - } - if (proc_stat_fd < 0) { - proc_stat_fd = open (PROC_STAT_FILE_NAME, O_RDONLY, NULL); - if (proc_stat_fd < 0) { - fprintf (stderr, "Cannot open %s!\n", PROC_STAT_FILE_NAME); - exit (1); - }; - }; - - if (!proc_stat_buf) { - proc_stat_buflen = N_CPU_LINES (lib_num_loc_cpus) * CPU_LINE_LENGTH; - if (debug) { - fprintf(where, - "lib_num_loc_cpus %d lines %d CPU_LINE_LENGTH %d proc_stat_buflen %d\n", - lib_num_loc_cpus, - N_CPU_LINES(lib_num_loc_cpus), - CPU_LINE_LENGTH, - proc_stat_buflen); - fflush(where); - } - proc_stat_buf = (char *)malloc (proc_stat_buflen); - if (!proc_stat_buf) { - fprintf (stderr, "Cannot allocate buffer memory!\n"); - exit (1); - } - } - return; -} - -void -cpu_util_terminate(void) -{ - close(proc_stat_fd); - proc_stat_fd = -1; - free(proc_stat_buf); - proc_stat_buf = NULL; - return; -} - -int -get_cpu_method() -{ - return PROC_STAT; -} - -float -calibrate_idle_rate (int iterations, int interval) -{ - if (proc_stat_fd < 0) { - proc_stat_fd = open (PROC_STAT_FILE_NAME, O_RDONLY, NULL); - if (proc_stat_fd < 0) { - fprintf (stderr, "Cannot open %s!\n", PROC_STAT_FILE_NAME); - exit (1); - }; - }; - - if (!proc_stat_buf) { - proc_stat_buflen = N_CPU_LINES (lib_num_loc_cpus) * CPU_LINE_LENGTH; - if (debug) { - fprintf(where, - "calibrate: lib_num_loc_cpus %d lines %d CPU_LINE_LENGTH %d proc_stat_buflen %d\n", - lib_num_loc_cpus, - N_CPU_LINES(lib_num_loc_cpus), - CPU_LINE_LENGTH, - proc_stat_buflen); - fflush(where); - } - proc_stat_buf = (char *)malloc (proc_stat_buflen); - if (!proc_stat_buf) { - fprintf (stderr, "Cannot allocate buffer memory!\n"); - exit (1); - }; - }; - - return sysconf (_SC_CLK_TCK); -} - -void -get_cpu_idle (uint64_t *res) -{ - int space; - int i; - int n = lib_num_loc_cpus; - char *p = proc_stat_buf; - - lseek (proc_stat_fd, 0, SEEK_SET); - read (proc_stat_fd, p, proc_stat_buflen); - - if (debug) { - fprintf(where,"proc_stat_buf '%.*s'\n",proc_stat_buflen,p); - fflush(where); - } - /* Skip first line (total) on SMP */ - if (n > 1) p = strchr (p, '\n'); - - /* Idle time is the 4th space-separated token */ - for (i = 0; i < n; i++) { - for (space = 0; space < 4; space ++) { - p = strchr (p, ' '); - while (*++p == ' '); - }; - res[i] = strtoul (p, &p, 10); - if (debug) { - fprintf(where,"res[%d] is %llu\n",i,res[i]); - fflush(where); - } - p = strchr (p, '\n'); - }; - -} - -/* take the initial timestamp and start collecting CPU utilization if - requested */ - -void -measure_cpu_start() -{ - cpu_method = PROC_STAT; - get_cpu_idle(lib_start_count); -} - -/* collect final CPU utilization raw data */ -void -measure_cpu_stop() -{ - get_cpu_idle(lib_end_count); -} - -float -calc_cpu_util_internal(float elapsed_time) -{ - int i; - - float actual_rate; - float correction_factor; - - lib_local_cpu_util = (float)0.0; - /* It is possible that the library measured a time other than */ - /* the one that the user want for the cpu utilization */ - /* calculations - for example, tests that were ended by */ - /* watchdog timers such as the udp stream test. We let these */ - /* tests tell up what the elapsed time should be. */ - - if (elapsed_time != 0.0) { - correction_factor = (float) 1.0 + - ((lib_elapsed - elapsed_time) / elapsed_time); - } - else { - correction_factor = (float) 1.0; - } - - for (i = 0; i < lib_num_loc_cpus; i++) { - - /* it would appear that on some systems, in loopback, nice is - *very* effective, causing the looper process to stop dead in its - tracks. if this happens, we need to ensure that the calculation - does not go south. raj 6/95 and if we run completely out of idle, - the same thing could in theory happen to the USE_KSTAT path. raj - 8/2000 */ - - if (lib_end_count[i] == lib_start_count[i]) { - lib_end_count[i]++; - } - - actual_rate = (lib_end_count[i] > lib_start_count[i]) ? - (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed : - (float)(lib_end_count[i] - lib_start_count[i] + - MAXLONG)/ lib_elapsed; - lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) / - lib_local_maxrate * 100; - if (debug) { - fprintf(where, - "calc_cpu_util: actual_rate on processor %d is %f start %llx end %llx util %f\n", - i, - actual_rate, - lib_start_count[i], - lib_end_count[i], - lib_local_per_cpu_util[i]); - } - lib_local_cpu_util += lib_local_per_cpu_util[i]; - } - /* we want the average across all n processors */ - lib_local_cpu_util /= (float)lib_num_loc_cpus; - - lib_local_cpu_util *= correction_factor; - return lib_local_cpu_util; -} - -void -cpu_start_internal(void) -{ - get_cpu_idle(lib_start_count); - return; -} - -void -cpu_stop_internal(void) -{ - get_cpu_idle(lib_end_count); -} diff --git a/netcpu_pstat.c b/netcpu_pstat.c deleted file mode 100644 index 08f27c1..0000000 --- a/netcpu_pstat.c +++ /dev/null @@ -1,307 +0,0 @@ -char netcpu_pstat_id[]="\ -@(#)netcpu_pstat.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.0"; - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdio.h> - -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif - -#if HAVE_LIMITS_H -# include <limits.h> -#endif - -#include <sys/dk.h> -#include <sys/pstat.h> - -#ifndef PSTAT_IPCINFO -# error Sorry, pstat() CPU utilization on 10.0 and later only -#endif - -#include "netsh.h" -#include "netlib.h" - -/* the lib_start_count and lib_end_count arrays hold the starting - and ending values of whatever is counting when the system is - idle. The rate at which this increments during a test is compared - with a previous calibrarion to arrive at a CPU utilization - percentage. raj 2005-01-26 */ -static uint64_t lib_start_count[MAXCPUS]; -static uint64_t lib_end_count[MAXCPUS]; - -void -cpu_util_init(void) -{ - return; -} - -void -cpu_util_terminate(void) -{ - return; -} - -int -get_cpu_method(void) -{ - return HP_IDLE_COUNTER; -} - -void -get_cpu_idle(uint64_t *res) -{ - /* get the idle sycle counter for each processor */ - struct pst_processor *psp; - union overlay_u { - long long full; - long word[2]; - } *overlay; - - psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp)); - if (psp == NULL) { - printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp)); - exit(1); - } - if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) { - int i; - for (i = 0; i < lib_num_loc_cpus; i++) { - overlay = (union overlay_u *)&(res[i]); - overlay->word[0] = psp[i].psp_idlecycles.psc_hi; - overlay->word[1] = psp[i].psp_idlecycles.psc_lo; - if(debug) { - fprintf(where, - "\tres[%d] = 0x%8.8x%8.8x\n", - i, - hi_32(&res[i]), - lo_32(&res[i])); - fflush(where); - } - } - free(psp); - } -} - -/* calibrate_pstat - Loop a number of iterations, sleeping wait_time seconds each and - count how high the idle counter gets each time. Return the measured - cpu rate to the calling routine. */ - -float -calibrate_idle_rate(int iterations, int interval) -{ - - uint64_t - firstcnt[MAXCPUS], - secondcnt[MAXCPUS]; - - float - elapsed, - temp_rate, - rate[MAXTIMES], - local_maxrate; - - long - sec, - usec; - - int - i, - j; - - long count; - - struct timeval time1, time2; - struct timezone tz; - - struct pst_processor *psp; - - if (iterations > MAXTIMES) { - iterations = MAXTIMES; - } - - local_maxrate = -1.0; - - psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp)); - if (psp == NULL) { - printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp)); - exit(1); - } - - for(i = 0; i < iterations; i++) { - rate[i] = 0.0; - /* get the idle sycle counter for each processor */ - if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) { - for (j = 0; j < lib_num_loc_cpus; j++) { - union overlay_u { - long long full; - long word[2]; - } *overlay; - overlay = (union overlay_u *)&(firstcnt[j]); - overlay->word[0] = psp[j].psp_idlecycles.psc_hi; - overlay->word[1] = psp[j].psp_idlecycles.psc_lo; - } - } - else { - fprintf(where,"pstat_getprocessor failure errno %d\n",errno); - fflush(where); - exit(1); - } - - gettimeofday (&time1, &tz); - sleep(interval); - gettimeofday (&time2, &tz); - - if (time2.tv_usec < time1.tv_usec) - { - time2.tv_usec += 1000000; - time2.tv_sec -=1; - } - sec = time2.tv_sec - time1.tv_sec; - usec = time2.tv_usec - time1.tv_usec; - elapsed = (float)sec + ((float)usec/(float)1000000.0); - - if(debug) { - fprintf(where, "Calibration for counter run: %d\n",i); - fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec); - fprintf(where,"\telapsed time = %g\n",elapsed); - } - - if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) { - for (j = 0; j < lib_num_loc_cpus; j++) { - union overlay_u { - long long full; - long word[2]; - } *overlay; - overlay = (union overlay_u *)&(secondcnt[j]); - overlay->word[0] = psp[j].psp_idlecycles.psc_hi; - overlay->word[1] = psp[j].psp_idlecycles.psc_lo; - if(debug) { - /* I know that there are situations where compilers know about */ - /* long long, but the library fucntions do not... raj 4/95 */ - fprintf(where, - "\tfirstcnt[%d] = 0x%8.8x%8.8x secondcnt[%d] = 0x%8.8x%8.8x\n", - j, - hi_32(&firstcnt[j]), - lo_32(&firstcnt[j]), - j, - hi_32(&secondcnt[j]), - lo_32(&secondcnt[j])); - } - temp_rate = (secondcnt[j] >= firstcnt[j]) ? - (float)(secondcnt[j] - firstcnt[j] )/elapsed : - (float)(secondcnt[j] - firstcnt[j] + LONG_LONG_MAX)/elapsed; - if (temp_rate > rate[i]) rate[i] = temp_rate; - if(debug) { - fprintf(where,"\trate[%d] = %g\n",i,rate[i]); - fflush(where); - } - if (local_maxrate < rate[i]) local_maxrate = rate[i]; - } - } - else { - fprintf(where,"pstat failure; errno %d\n",errno); - fflush(where); - exit(1); - } - } - if(debug) { - fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate); - fflush(where); - } - return local_maxrate; - -} - -float -calc_cpu_util_internal(float elapsed_time) -{ - int i; - - float actual_rate; - float correction_factor; - - lib_local_cpu_util = (float)0.0; - /* It is possible that the library measured a time other than */ - /* the one that the user want for the cpu utilization */ - /* calculations - for example, tests that were ended by */ - /* watchdog timers such as the udp stream test. We let these */ - /* tests tell up what the elapsed time should be. */ - - if (elapsed_time != 0.0) { - correction_factor = (float) 1.0 + - ((lib_elapsed - elapsed_time) / elapsed_time); - } - else { - correction_factor = (float) 1.0; - } - - /* this looks just like the looper case. at least I think it */ - /* should :) raj 4/95 */ - for (i = 0; i < lib_num_loc_cpus; i++) { - - /* we assume that the two are not more than a long apart. I */ - /* know that this is bad, but trying to go from long longs to */ - /* a float (perhaps a double) is boggling my mind right now. */ - /* raj 4/95 */ - - long long - diff; - - if (lib_end_count[i] >= lib_start_count[i]) { - diff = lib_end_count[i] - lib_start_count[i]; - } - else { - diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX; - } - actual_rate = (float) diff / lib_elapsed; - lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) / - lib_local_maxrate * 100; - lib_local_cpu_util += lib_local_per_cpu_util[i]; - if (debug) { - fprintf(where, - "calc_cpu_util: actual_rate on cpu %d is %g max_rate %g cpu %6.2f\n", - i, - actual_rate, - lib_local_maxrate, - lib_local_per_cpu_util[i]); - } - } - - /* we want the average across all n processors */ - lib_local_cpu_util /= (float)lib_num_loc_cpus; - - if (debug) { - fprintf(where, - "calc_cpu_util: average across CPUs is %g\n",lib_local_cpu_util); - } - - lib_local_cpu_util *= correction_factor; - - if (debug) { - fprintf(where, - "calc_cpu_util: returning %g\n",lib_local_cpu_util); - } - - return lib_local_cpu_util; - -} -void -cpu_start_internal(void) -{ - get_cpu_idle(lib_start_count); - return; -} - -void -cpu_stop_internal(void) -{ - get_cpu_idle(lib_end_count); -} diff --git a/netcpu_pstatnew.c b/netcpu_pstatnew.c deleted file mode 100644 index fd2d036..0000000 --- a/netcpu_pstatnew.c +++ /dev/null @@ -1,398 +0,0 @@ -char netcpu_pstatnew_id[]="\ -@(#)netcpu_pstatnew.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.1"; - -/* since we "know" that this interface is available only on 11.23 and - later, and that 11.23 and later are strictly 64-bit kernels, we can - arbitrarily set _PSTAT64 here and not have to worry about it up in - the configure script and makefiles. raj 2005/09/06 */ - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdio.h> - -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif - -#include <unistd.h> - -#if HAVE_LIMITS_H -# include <limits.h> -#endif - -#include <sys/dk.h> -#include <sys/pstat.h> - -/* HP-UX 11.23 seems to have added three other cycle counters to the - original psp_idlecycles - one for user, one for kernel and one for - interrupt. so, we can now use those to calculate CPU utilization - without requiring any calibration phase. raj 2005-02-16 */ - -#ifndef PSTAT_IPCINFO -# error Sorry, pstat() CPU utilization on 10.0 and later only -#endif - -typedef struct cpu_time_counters { - uint64_t idle; - uint64_t user; - uint64_t kernel; - uint64_t interrupt; -} cpu_time_counters_t; - -uint64_t lib_iticksperclktick; - -#include "netsh.h" -#include "netlib.h" - -/* the lib_start_count and lib_end_count arrays hold the starting - and ending values of whatever is counting when the system is - idle. The rate at which this increments during a test is compared - with a previous calibrarion to arrive at a CPU utilization - percentage. raj 2005-01-26 */ - -static cpu_time_counters_t starting_cpu_counters[MAXCPUS]; -static cpu_time_counters_t ending_cpu_counters[MAXCPUS]; -static cpu_time_counters_t delta_cpu_counters[MAXCPUS]; - -void -cpu_util_init(void) -{ - return; -} - -void -cpu_util_terminate(void) -{ - return; -} - -int -get_cpu_method(void) -{ - return HP_IDLE_COUNTER; -} - -void -get_cpu_counters(cpu_time_counters_t *res) -{ - /* get the idle sycle counter for each processor. now while on a - 64-bit kernel the ".psc_hi" and ".psc_lo" fields are 64 bits, - only the bottom 32-bits are actually valid. don't ask me - why, that is just the way it is. soo, we shift the psc_hi - value by 32 bits and then just sum-in the psc_lo value. raj - 2005/09/06 */ - struct pst_processor *psp; - - psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp)); - if (psp == NULL) { - printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp)); - exit(1); - } - if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) { - int i; - /* we use lib_iticksperclktick in our sanity checking. we - ass-u-me it is the same value for each CPU - famous last - words no doubt. raj 2005/09/06 */ - lib_iticksperclktick = psp[0].psp_iticksperclktick; - for (i = 0; i < lib_num_loc_cpus; i++) { - res[i].idle = (((uint64_t)psp[i].psp_idlecycles.psc_hi << 32) + - psp[i].psp_idlecycles.psc_lo); - if(debug) { - fprintf(where, - "\tidle[%d] = 0x%"PRIx64" ", - i, - res[i].idle); - fflush(where); - } - res[i].user = (((uint64_t)psp[i].psp_usercycles.psc_hi << 32) + - psp[i].psp_usercycles.psc_lo); - if(debug) { - fprintf(where, - "user[%d] = 0x%"PRIx64" ", - i, - res[i].user); - fflush(where); - } - res[i].kernel = (((uint64_t)psp[i].psp_systemcycles.psc_hi << 32) + - psp[i].psp_systemcycles.psc_lo); - if(debug) { - fprintf(where, - "kern[%d] = 0x%"PRIx64" ", - i, - res[i].kernel); - fflush(where); - } - res[i].interrupt = (((uint64_t)psp[i].psp_interruptcycles.psc_hi << 32) + - psp[i].psp_interruptcycles.psc_lo); - if(debug) { - fprintf(where, - "intr[%d] = 0x%"PRIx64"\n", - i, - res[i].interrupt); - fflush(where); - } - } - free(psp); - } -} - -/* calibrate_pstatnew - there really isn't anything much to do here since we have all the - counters and use their ratios for CPU util measurement. raj - 2005-02-16 */ - -float -calibrate_idle_rate(int iterations, int interval) -{ - return 0.0; -} - -static void -print_cpu_time_counters(char *name, int instance, cpu_time_counters_t *counters) -{ - fprintf(where,"%s[%d]:\n",name,instance); - fprintf(where, - "\t idle %llu\n",counters[instance].idle); - fprintf(where, - "\t user %llu\n",counters[instance].user); - fprintf(where, - "\t kernel %llu\n",counters[instance].kernel); - fprintf(where, - "\t interrupt %llu\n",counters[instance].interrupt); -} - -float -calc_cpu_util_internal(float elapsed_time) -{ - int i; - - uint64_t total_cpu_cycles; - uint64_t sanity_cpu_cycles; - -#ifndef USE_INTEGER_MATH - double fraction_idle; - double fraction_user; - double fraction_kernel; - double fraction_interrupt; - double estimated_fraction_interrupt; -#else - uint64_t fraction_idle; - uint64_t fraction_user; - uint64_t fraction_kernel; - uint64_t fraction_interrupt; - uint64_t estimated_fraction_interrupt; - -#define CALC_PERCENT 100 -#define CALC_TENTH_PERCENT 1000 -#define CALC_HUNDREDTH_PERCENT 10000 -#define CALC_THOUSANDTH_PERCENT 100000 -#define CALC_ACCURACY CALC_THOUSANDTH_PERCENT - -#endif /* USE_INTEGER_MATH */ - float actual_rate; - float correction_factor; - - lib_local_cpu_util = (float)0.0; - - /* It is possible that the library measured a time other than */ - /* the one that the user want for the cpu utilization */ - /* calculations - for example, tests that were ended by */ - /* watchdog timers such as the udp stream test. We let these */ - /* tests tell up what the elapsed time should be. */ - - if (elapsed_time != 0.0) { - correction_factor = (float) 1.0 + - ((lib_elapsed - elapsed_time) / elapsed_time); - } - else { - correction_factor = (float) 1.0; - } - - /* calculate our sanity check on cycles */ - if (debug) { - fprintf(where, - "lib_elapsed %g _SC_CLK_TCK %d lib_iticksperclktick %"PRIu64"\n", - lib_elapsed, - sysconf(_SC_CLK_TCK), - lib_iticksperclktick); - } - - /* Ok, elsewhere I may have said that HP-UX 11.23 does the "right" - thing in measuring user, kernel, interrupt and idle all together - instead of overlapping interrupt with the others like an OS that - shall not be named. However.... it seems there is a bug in the - accounting for interrupt cycles, whereby the cycles do not get - properly accounted. The sum of user, kernel, interrupt and idle - does not equal the clock rate multiplied by the elapsed time. - Some cycles go missing. - - Since we see agreement between netperf and glance/vsar with the - old "pstat" mechanism, we can presume that the accounting for - idle cycles is sufficiently accurate. So, while we will still do - math with user, kernel and interrupt cycles, we will only - caculate CPU utilization based on the ratio of idle to _real_ - total cycles. I am told that a "future release" of HP-UX will - fix the interupt cycle accounting. raj 2005/09/14 */ - - /* calculate what the sum of CPU cycles _SHOULD_ be */ - sanity_cpu_cycles = (uint64_t) ((double)lib_elapsed * - (double) sysconf(_SC_CLK_TCK) * (double)lib_iticksperclktick); - - /* this looks just like the looper case. at least I think it */ - /* should :) raj 4/95 */ - for (i = 0; i < lib_num_loc_cpus; i++) { - - /* we ass-u-me that these counters will never wrap during a - netperf run. this may not be a particularly safe thing to - do. raj 2005-01-28 */ - delta_cpu_counters[i].idle = ending_cpu_counters[i].idle - - starting_cpu_counters[i].idle; - delta_cpu_counters[i].user = ending_cpu_counters[i].user - - starting_cpu_counters[i].user; - delta_cpu_counters[i].kernel = ending_cpu_counters[i].kernel - - starting_cpu_counters[i].kernel; - delta_cpu_counters[i].interrupt = ending_cpu_counters[i].interrupt - - starting_cpu_counters[i].interrupt; - - if (debug) { - print_cpu_time_counters("delta_cpu_counters",i,delta_cpu_counters); - } - - /* now get the sum, which we ass-u-me does not overflow a 64-bit - counter. raj 2005-02-16 */ - total_cpu_cycles = - delta_cpu_counters[i].idle + - delta_cpu_counters[i].user + - delta_cpu_counters[i].kernel + - delta_cpu_counters[i].interrupt; - - if (debug) { - fprintf(where, - "total_cpu_cycles %"PRIu64" sanity_cpu_cycles %"PRIu64" missing %"PRIu64"\n", - total_cpu_cycles, - sanity_cpu_cycles, - sanity_cpu_cycles - total_cpu_cycles); - } - - /* since HP-UX 11.23 does the _RIGHT_ thing and idle/user/kernel - does _NOT_ overlap with interrupt, we do not have to apply any - correction kludge. raj 2005-02-16 */ - -#ifndef USE_INTEGER_MATH - /* when the accounting for interrupt time gets its act together, - we can use total_cpu_cycles rather than sanity_cpu_cycles, but - until then, use sanity_cpu_ccles. raj 2005/09/14 */ - - fraction_idle = (double)delta_cpu_counters[i].idle / - (double)sanity_cpu_cycles; - - fraction_user = (double)delta_cpu_counters[i].user / - (double)sanity_cpu_cycles; - - fraction_kernel = (double) delta_cpu_counters[i].kernel / - (double)sanity_cpu_cycles; - - fraction_interrupt = (double)delta_cpu_counters[i].interrupt / - (double)sanity_cpu_cycles; - - /* ass-u-me that it is only interrupt that is bogus, and assign - all the "missing" cycles to it. raj 2005/09/14 */ - estimated_fraction_interrupt = ((double)delta_cpu_counters[i].interrupt + - (sanity_cpu_cycles - total_cpu_cycles)) / - (double)sanity_cpu_cycles; - - if (debug) { - fprintf(where,"\tfraction_idle %g\n",fraction_idle); - fprintf(where,"\tfraction_user %g\n",fraction_user); - fprintf(where,"\tfraction_kernel %g\n",fraction_kernel); - fprintf(where,"\tfraction_interrupt %g WARNING, possibly under-counted!\n",fraction_interrupt); - fprintf(where,"\testimated_fraction_interrupt %g\n", - estimated_fraction_interrupt); - } - - /* and finally, what is our CPU utilization? */ - lib_local_per_cpu_util[i] = 100.0 - (fraction_idle * 100.0); -#else - /* and now some fun with integer math. i initially tried to - promote things to long doubled but that didn't seem to result - in happiness and joy. raj 2005-01-28 */ - - /* multiply by 100 and divide by total and you get whole - percentages. multiply by 1000 and divide by total and you get - tenths of percentages. multiply by 10000 and divide by total - and you get hundredths of percentages. etc etc etc raj - 2005-01-28 */ - - /* when the accounting for interrupt time gets its act together, - we can use total_cpu_cycles rather than sanity_cpu_cycles, but - until then, use sanity_cpu_ccles. raj 2005/09/14 */ - - fraction_idle = - (delta_cpu_counters[i].idle * CALC_ACCURACY) / sanity_cpu_cycles; - - fraction_user = - (delta_cpu_counters[i].user * CALC_ACCURACY) / sanity_cpu_cycles; - - fraction_kernel = - (delta_cpu_counters[i].kernel * CALC_ACCURACY) / sanity_cpu_cycles; - - fraction_interrupt = - (delta_cpu_counters[i].interrupt * CALC_ACCURACY) / sanity_cpu_cycles; - - - estimated_fraction_interrupt = - ((delta_cpu_counters[i].interrupt + - (sanity_cpu_cycles - total_cpu_cycles)) * - CALC_ACCURACY) / sanity_cpu_cycles; - - if (debug) { - fprintf(where,"\tfraction_idle %"PRIu64"\n",fraction_idle); - fprintf(where,"\tfraction_user %"PRIu64"\n",fraction_user); - fprintf(where,"\tfraction_kernel %"PRIu64"\n",fraction_kernel); - fprintf(where,"\tfraction_interrupt %"PRIu64"WARNING, possibly under-counted!\n",fraction_interrupt); - fprintf(where,"\testimated_fraction_interrupt %"PRIu64"\n", - estimated_fraction_interrupt); - } - - /* and finally, what is our CPU utilization? */ - lib_local_per_cpu_util[i] = 100.0 - (((float)fraction_idle / - (float)CALC_ACCURACY) * 100.0); -#endif - if (debug) { - fprintf(where, - "lib_local_per_cpu_util[%d] %g\n", - i, - lib_local_per_cpu_util[i]); - } - lib_local_cpu_util += lib_local_per_cpu_util[i]; - } - /* we want the average across all n processors */ - lib_local_cpu_util /= (float)lib_num_loc_cpus; - - lib_local_cpu_util *= correction_factor; - - if (debug) { - fprintf(where, - "calc_cpu_util: returning %g\n",lib_local_cpu_util); - } - - return lib_local_cpu_util; - -} -void -cpu_start_internal(void) -{ - get_cpu_counters(starting_cpu_counters); -} - -void -cpu_stop_internal(void) -{ - get_cpu_counters(ending_cpu_counters); -} diff --git a/netcpu_sysctl.c b/netcpu_sysctl.c deleted file mode 100644 index 919f62c..0000000 --- a/netcpu_sysctl.c +++ /dev/null @@ -1,127 +0,0 @@ -char netcpu_sysctl_id[]="\ -@(#)netcpu_sysctl.c Version 2.4.3"; - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdio.h> -#include <unistd.h> - -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif - -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif -#if HAVE_LIMITS_H -# include <limits.h> -# ifndef LONG_LONG_MAX -# define LONG_LONG_MAX LLONG_MAX -# endif /* LONG_LONG_MAX */ -#endif - - -#include <errno.h> - -/* need to have some sort of check for sys/sysctl.h versus sysctl.h */ -#include <sys/sysctl.h> - - -/* this has been liberally cut and pasted from <sys/resource.h> on - FreeBSD. in general, this would be a bad idea, but I don't want to - have to do a _KERNEL define to get these and that is what - sys/resource.h seems to want. raj 2002-03-03 */ -#define CP_USER 0 -#define CP_NICE 1 -#define CP_SYS 2 -#define CP_INTR 3 -#define CP_IDLE 4 -#define CPUSTATES 5 - - -#include "netsh.h" -#include "netlib.h" - -static long lib_start_count[CPUSTATES]; -static long lib_end_count[CPUSTATES]; - -void -cpu_util_init(void) -{ - return; -} - -void -cpu_util_terminate(void) -{ - return; -} - -int -get_cpu_method(void) -{ - return SYSCTL; -} - -static void -get_cpu_time(long *cpu_time) -{ - size_t cpu_time_len = CPUSTATES * sizeof (cpu_time[0]); - - if (sysctlbyname("kern.cp_time", cpu_time, &cpu_time_len, NULL, 0) == -1) { - fprintf (stderr, "Cannot get CPU time!\n"); - exit (1); - } -} - -/* calibrate_sysctl - perform the idle rate calculation using the - sysctl call - typically on BSD */ - -float -calibrate_idle_rate(int iterations, int interval) -{ - return sysconf (_SC_CLK_TCK); -} - -float -calc_cpu_util_internal(float elapsed_time) -{ - long sum_idle, sum_busy; - int i; - - for (sum_busy = 0, i = 0; i < CPUSTATES; i++) { - if (i != CP_IDLE) - sum_busy += lib_end_count[i] - lib_start_count[i]; - } - - sum_idle = lib_end_count[CP_IDLE] - lib_start_count[CP_IDLE]; - lib_local_cpu_util = (float)sum_busy / (float)(sum_busy + sum_idle); - lib_local_cpu_util *= 100.0; - - return lib_local_cpu_util; - -} -void -cpu_start_internal(void) -{ - get_cpu_time(lib_start_count); -} - -void -cpu_stop_internal(void) -{ - get_cpu_time(lib_end_count); -} diff --git a/netlib.c b/netlib.c deleted file mode 100644 index bee93c8..0000000 --- a/netlib.c +++ /dev/null @@ -1,4161 +0,0 @@ -char netlib_id[]="\ -@(#)netlib.c (c) Copyright 1993-2007 Hewlett-Packard Company. Version 2.4.3"; - - -/****************************************************************/ -/* */ -/* netlib.c */ -/* */ -/* the common utility routines available to all... */ -/* */ -/* establish_control() establish the control socket */ -/* calibrate_local_cpu() do local cpu calibration */ -/* calibrate_remote_cpu() do remote cpu calibration */ -/* send_request() send a request to the remote */ -/* recv_response() receive a response from remote */ -/* send_response() send a response to the remote */ -/* recv_request() recv a request from the remote */ -/* dump_request() dump request contents */ -/* dump_response() dump response contents */ -/* cpu_start() start measuring cpu */ -/* cpu_stop() stop measuring cpu */ -/* calc_cpu_util() calculate the cpu utilization */ -/* calc_service_demand() calculate the service demand */ -/* calc_thruput() calulate the tput in units */ -/* calibrate() really calibrate local cpu */ -/* identify_local() print local host information */ -/* identify_remote() print remote host information */ -/* format_number() format the number (KB, MB,etc) */ -/* format_units() return the format in english */ -/* msec_sleep() sleep for some msecs */ -/* start_timer() start a timer */ -/* */ -/* the routines you get when WANT_DLPI is defined... */ -/* */ -/* dl_open() open a file descriptor and */ -/* attach to the card */ -/* dl_mtu() find the MTU of the card */ -/* dl_bind() bind the sap do the card */ -/* dl_connect() sender's have of connect */ -/* dl_accpet() receiver's half of connect */ -/* dl_set_window() set the window size */ -/* dl_stats() retrieve statistics */ -/* dl_send_disc() initiate disconnect (sender) */ -/* dl_recv_disc() accept disconnect (receiver) */ -/****************************************************************/ - -/****************************************************************/ -/* */ -/* Global include files */ -/* */ -/****************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - - /* It would seem that most of the includes being done here from */ - /* "sys/" actually have higher-level wrappers at just /usr/include. */ - /* This is based on a spot-check of a couple systems at my disposal. */ - /* If you have trouble compiling you may want to add "sys/" raj 10/95 */ -#include <limits.h> -#include <signal.h> -#ifdef MPE -# define NSIG _NSIG -#endif /* MPE */ -#include <sys/types.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <string.h> -#include <assert.h> -#ifdef HAVE_ENDIAN_H -#include <endian.h> -#endif - - -#ifndef WIN32 - /* at some point, I would like to get rid of all these "sys/" */ - /* includes where appropriate. if you have a system that requires */ - /* them, speak now, or your system may not comile later revisions of */ - /* netperf. raj 1/96 */ -#include <unistd.h> -#include <sys/stat.h> -#include <sys/times.h> -#ifndef MPE -#include <time.h> -#include <sys/time.h> -#endif /* MPE */ -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <errno.h> -#include <sys/utsname.h> -#if !defined(MPE) && !defined(__VMS) -#include <sys/param.h> -#endif /* MPE */ - -#else /* WIN32 */ - -#include <process.h> -#include <time.h> -#include <winsock2.h> -#define netperf_socklen_t socklen_t -#include <windows.h> - -/* the only time someone should need to define DONT_IPV6 in the - "sources" file is if they are trying to compile on Windows 2000 or - NT4 and I suspect this may not be their only problem :) */ -#ifndef DONT_IPV6 -#include <ws2tcpip.h> -#endif - -#include <windows.h> - -#define SIGALRM (14) -#define sleep(x) Sleep((x)*1000) - -#endif /* WIN32 */ - -#ifdef _AIX -#include <sys/select.h> -#include <sys/sched.h> -#include <sys/pri.h> -#define PRIORITY PRI_LOW -#else/* _AIX */ -#ifdef __sgi -#include <sys/prctl.h> -#include <sys/schedctl.h> -#define PRIORITY NDPLOMIN -#endif /* __sgi */ -#endif /* _AIX */ - -#ifdef WANT_DLPI -#include <sys/stream.h> -#include <sys/stropts.h> -#include <sys/poll.h> -#ifdef __osf__ -#include <sys/dlpihdr.h> -#else /* __osf__ */ -#include <sys/dlpi.h> -#ifdef __hpux -#include <sys/dlpi_ext.h> -#endif /* __hpux */ -#endif /* __osf__ */ -#endif /* WANT_DLPI */ - -#ifdef HAVE_MPCTL -#include <sys/mpctl.h> -#endif - -#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO) -# include "missing/getaddrinfo.h" -#endif - - -#ifdef WANT_HISTOGRAM -#include "hist.h" -#endif /* WANT_HISTOGRAM */ -/****************************************************************/ -/* */ -/* Local Include Files */ -/* */ -/****************************************************************/ -#define NETLIB -#include "netlib.h" -#include "netsh.h" -#include "netcpu.h" - -/****************************************************************/ -/* */ -/* Global constants, macros and variables */ -/* */ -/****************************************************************/ - -#if defined(WIN32) || defined(__VMS) -struct timezone { - int dummy ; - } ; -#ifndef __VMS -SOCKET win_kludge_socket = INVALID_SOCKET; -SOCKET win_kludge_socket2 = INVALID_SOCKET; -#endif /* __VMS */ -#endif /* WIN32 || __VMS */ - -#ifndef LONG_LONG_MAX -#define LONG_LONG_MAX 9223372036854775807LL -#endif /* LONG_LONG_MAX */ - - /* older versions of netperf knew about the HP kernel IDLE counter. */ - /* this is now obsolete - in favor of either pstat(), times, or a */ - /* process-level looper process. we also now require support for the */ - /* "long" integer type. raj 4/95. */ - -int - lib_num_loc_cpus, /* the number of cpus in the system */ - lib_num_rem_cpus; /* how many we think are in the remote */ - -#define PAGES_PER_CHILD 2 - -int lib_use_idle; -int cpu_method; - -struct timeval time1, time2; -struct timezone tz; -float lib_elapsed, - lib_local_maxrate, - lib_remote_maxrate, - lib_local_cpu_util, - lib_remote_cpu_util; - -float lib_local_per_cpu_util[MAXCPUS]; -int lib_cpu_map[MAXCPUS]; - -int *request_array; -int *response_array; - -/* INVALID_SOCKET == INVALID_HANDLE_VALUE == (unsigned int)(~0) == -1 */ -SOCKET netlib_control = INVALID_SOCKET; -SOCKET server_sock = INVALID_SOCKET; - -/* global variables to hold the value for processor affinity */ -int local_proc_affinity,remote_proc_affinity = -1; - -/* these are to allow netperf to be run easily through those evil, - end-to-end breaking things known as firewalls */ -char local_data_port[10]; -char remote_data_port[10]; - -char *local_data_address=NULL; -char *remote_data_address=NULL; - -int local_data_family=AF_UNSPEC; -int remote_data_family=AF_UNSPEC; - - /* in the past, I was overlaying a structure on an array of ints. now */ - /* I am going to have a "real" structure, and point an array of ints */ - /* at it. the real structure will be forced to the same alignment as */ - /* the type "double." this change will mean that pre-2.1 netperfs */ - /* cannot be mixed with 2.1 and later. raj 11/95 */ - -union netperf_request_struct netperf_request; -union netperf_response_struct netperf_response; - -FILE *where; - -char libfmt = '?'; - -#ifdef WANT_DLPI -/* some stuff for DLPI control messages */ -#define DLPI_DATA_SIZE 2048 - -unsigned long control_data[DLPI_DATA_SIZE]; -struct strbuf control_message = {DLPI_DATA_SIZE, 0, (char *)control_data}; - -#endif /* WANT_DLPI */ - -#ifdef WIN32 -HANDLE hAlarm = INVALID_HANDLE_VALUE; -#endif - -int times_up; - -#ifdef WIN32 - /* we use a getopt implementation from net.sources */ -/* - * get option letter from argument vector - */ -int - opterr = 1, /* should error messages be printed? */ - optind = 1, /* index into parent argv vector */ - optopt; /* character checked for validity */ -char - *optarg; /* argument associated with option */ - -#define EMSG "" - -#endif /* WIN32 */ - -static int measuring_cpu; -int -netlib_get_page_size(void) { - - /* not all systems seem to have the sysconf for page size. for - those which do not, we will assume that the page size is 8192 - bytes. this should be more than enough to be sure that there is - no page or cache thrashing by looper processes on MP - systems. otherwise that's really just too bad - such systems - should define _SC_PAGE_SIZE - raj 4/95 */ - -#ifndef _SC_PAGE_SIZE -#ifdef WIN32 - -SYSTEM_INFO SystemInfo; - - GetSystemInfo(&SystemInfo); - - return SystemInfo.dwPageSize; -#else - return(8192L); -#endif /* WIN32 */ -#else - return(sysconf(_SC_PAGE_SIZE)); -#endif /* _SC_PAGE_SIZE */ - -} - - -#ifdef WANT_INTERVALS -static unsigned int usec_per_itvl; - - -void -stop_itimer() - -{ - - struct itimerval new_interval; - struct itimerval old_interval; - - new_interval.it_interval.tv_sec = 0; - new_interval.it_interval.tv_usec = 0; - new_interval.it_value.tv_sec = 0; - new_interval.it_value.tv_usec = 0; - if (setitimer(ITIMER_REAL,&new_interval,&old_interval) != 0) { - /* there was a problem arming the interval timer */ - perror("netperf: setitimer"); - exit(1); - } - return; -} -#endif /* WANT_INTERVALS */ - - - -#ifdef WIN32 -static void -error(char *pch) -{ - if (!opterr) { - return; /* without printing */ - } - fprintf(stderr, "%s: %s: %c\n", - (NULL != program) ? program : "getopt", pch, optopt); -} - -int -getopt(int argc, char **argv, char *ostr) -{ - static char *place = EMSG; /* option letter processing */ - register char *oli; /* option letter list index */ - - if (!*place) { - /* update scanning pointer */ - if (optind >= argc || *(place = argv[optind]) != '-' || !*++place) { - return EOF; - } - if (*place == '-') { - /* found "--" */ - ++optind; - place = EMSG ; /* Added by shiva for Netperf */ - return EOF; - } - } - - /* option letter okay? */ - if ((optopt = (int)*place++) == (int)':' - || !(oli = strchr(ostr, optopt))) { - if (!*place) { - ++optind; - } - error("illegal option"); - return BADCH; - } - if (*++oli != ':') { - /* don't need argument */ - optarg = NULL; - if (!*place) - ++optind; - } else { - /* need an argument */ - if (*place) { - optarg = place; /* no white space */ - } else if (argc <= ++optind) { - /* no arg */ - place = EMSG; - error("option requires an argument"); - return BADCH; - } else { - optarg = argv[optind]; /* white space */ - } - place = EMSG; - ++optind; - } - return optopt; /* return option letter */ -} -#endif /* WIN32 */ - -/*---------------------------------------------------------------------------- - * WIN32 implementation of perror, does not deal very well with WSA errors - * The stdlib.h version of perror only deals with the ancient XENIX error codes. - * - * +*+SAF Why can't all WSA errors go through GetLastError? Most seem to... - *--------------------------------------------------------------------------*/ - -#ifdef WIN32 -void PrintWin32Error(FILE *stream, LPSTR text) -{ - LPSTR szTemp; - DWORD dwResult; - DWORD dwError; - - dwError = GetLastError(); - dwResult = FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY, - NULL, - dwError, - LANG_NEUTRAL, - (LPTSTR)&szTemp, - 0, - NULL ); - - if (dwResult) - fprintf(stream, "%s: %s\n", text, szTemp); - else - fprintf(stream, "%s: error 0x%x\n", text, dwError); - fflush(stream); - - if (szTemp) - LocalFree((HLOCAL)szTemp); -} -#endif /* WIN32 */ - - -char * -inet_ttos(int type) -{ - switch (type) { - case SOCK_DGRAM: - return("SOCK_DGRAM"); - break; - case SOCK_STREAM: - return("SOCK_STREAM"); - break; - default: - return("SOCK_UNKNOWN"); - } -} - - - -char unknown[32]; - -char * -inet_ptos(int protocol) { - switch (protocol) { - case IPPROTO_TCP: - return("IPPROTO_TCP"); - break; - case IPPROTO_UDP: - return("IPPROTO_UDP"); - break; -#if defined(IPPROTO_SCTP) - case IPPROTO_SCTP: - return("IPPROTO_SCTP"); - break; -#endif - default: - snprintf(unknown,sizeof(unknown),"IPPROTO_UNKNOWN(%d)",protocol); - return(unknown); - } -} - -/* one of these days, this should not be required */ -#ifndef AF_INET_SDP -#define AF_INET_SDP 27 -#define PF_INET_SDP AF_INET_SDP -#endif - -char * -inet_ftos(int family) -{ - switch(family) { - case AF_INET: - return("AF_INET"); - break; -#if defined(AF_INET6) - case AF_INET6: - return("AF_INET6"); - break; -#endif -#if defined(AF_INET_SDP) - case AF_INET_SDP: - return("AF_INET_SDP"); - break; -#endif - default: - return("AF_UNSPEC"); - } -} - -int -inet_nton(int af, const void *src, char *dst, int cnt) - -{ - - switch (af) { - case AF_INET: - /* magic constants again... :) */ - if (cnt >= 4) { - memcpy(dst,src,4); - return 4; - } - else { - Set_errno(ENOSPC); - return(-1); - } - break; -#if defined(AF_INET6) - case AF_INET6: - if (cnt >= 16) { - memcpy(dst,src,16); - return(16); - } - else { - Set_errno(ENOSPC); - return(-1); - } - break; -#endif - default: - Set_errno(EAFNOSUPPORT); - return(-1); - } -} - -double -ntohd(double net_double) - -{ - /* we rely on things being nicely packed */ - union { - double whole_thing; - unsigned int words[2]; - unsigned char bytes[8]; - } conv_rec; - - unsigned char scratch; - int i; - - /* on those systems where ntohl is a no-op, we want to return the */ - /* original value, unchanged */ - - if (ntohl(1L) == 1L) { - return(net_double); - } - - conv_rec.whole_thing = net_double; - - /* we know that in the message passing routines that ntohl will have */ - /* been called on the 32 bit quantities. we need to put those back */ - /* the way they belong before we swap */ - conv_rec.words[0] = htonl(conv_rec.words[0]); - conv_rec.words[1] = htonl(conv_rec.words[1]); - - /* now swap */ - for (i=0; i<= 3; i++) { - scratch = conv_rec.bytes[i]; - conv_rec.bytes[i] = conv_rec.bytes[7-i]; - conv_rec.bytes[7-i] = scratch; - } - -#if defined(__FLOAT_WORD_ORDER) && defined(__BYTE_ORDER) - if (__FLOAT_WORD_ORDER != __BYTE_ORDER) { - /* Fixup mixed endian floating point machines */ - unsigned int scratch = conv_rec.words[0]; - conv_rec.words[0] = conv_rec.words[1]; - conv_rec.words[1] = scratch; - } -#endif - - return(conv_rec.whole_thing); - -} - -double -htond(double host_double) - -{ - /* we rely on things being nicely packed */ - union { - double whole_thing; - unsigned int words[2]; - unsigned char bytes[8]; - } conv_rec; - - unsigned char scratch; - int i; - - /* on those systems where ntohl is a no-op, we want to return the */ - /* original value, unchanged */ - - if (ntohl(1L) == 1L) { - return(host_double); - } - - conv_rec.whole_thing = host_double; - - /* now swap */ - for (i=0; i<= 3; i++) { - scratch = conv_rec.bytes[i]; - conv_rec.bytes[i] = conv_rec.bytes[7-i]; - conv_rec.bytes[7-i] = scratch; - } - -#if defined(__FLOAT_WORD_ORDER) && defined(__BYTE_ORDER) - if (__FLOAT_WORD_ORDER != __BYTE_ORDER) { - /* Fixup mixed endian floating point machines */ - unsigned int scratch = conv_rec.words[0]; - conv_rec.words[0] = conv_rec.words[1]; - conv_rec.words[1] = scratch; - } -#endif - - /* we know that in the message passing routines htonl will */ - /* be called on the 32 bit quantities. we need to set things up so */ - /* that when this happens, the proper order will go out on the */ - /* network */ - conv_rec.words[0] = htonl(conv_rec.words[0]); - conv_rec.words[1] = htonl(conv_rec.words[1]); - - return(conv_rec.whole_thing); - -} - - -/* one of these days, this should be abstracted-out just like the CPU - util stuff. raj 2005-01-27 */ -int -get_num_cpus() - -{ - - /* on HP-UX, even when we use the looper procs we need the pstat */ - /* call */ - - int temp_cpus; - -#ifdef __hpux -#include <sys/pstat.h> - - struct pst_dynamic psd; - - if (pstat_getdynamic((struct pst_dynamic *)&psd, - (size_t)sizeof(psd), (size_t)1, 0) != -1) { - temp_cpus = psd.psd_proc_cnt; - } - else { - temp_cpus = 1; - } - -#else - /* MW: <unistd.h> was included for non-Windows systems above. */ - /* Thus if _SC_NPROC_ONLN is defined, we should be able to use sysconf. */ -#ifdef _SC_NPROCESSORS_ONLN - temp_cpus = sysconf(_SC_NPROCESSORS_ONLN); - -#ifdef USE_PERFSTAT - temp_cpus = perfstat_cpu(NULL,NULL, sizeof(perfstat_cpu_t), 0); -#endif /* USE_PERFSTAT */ - -#else /* no _SC_NPROCESSORS_ONLN */ - -#ifdef WIN32 - SYSTEM_INFO SystemInfo; - GetSystemInfo(&SystemInfo); - - temp_cpus = SystemInfo.dwNumberOfProcessors; -#else - /* we need to know some other ways to do this, or just fall-back on */ - /* a global command line option - raj 4/95 */ - temp_cpus = shell_num_cpus; -#endif /* WIN32 */ -#endif /* _SC_NPROCESSORS_ONLN */ -#endif /* __hpux */ - - if (temp_cpus > MAXCPUS) { - fprintf(where, - "Sorry, this system has more CPUs (%d) than I can handle (%d).\n", - temp_cpus, - MAXCPUS); - fprintf(where, - "Please alter MAXCPUS in netlib.h and recompile.\n"); - fflush(where); - exit(1); - } - - return(temp_cpus); - -} - -#ifdef WIN32 -#ifdef __GNUC__ - #define S64_SUFFIX(x) x##LL -#else - #define S64_SUFFIX(x) x##i64 -#endif - -/* - * Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 - */ -#define EPOCH_BIAS S64_SUFFIX(116444736000000000) - -/* - * Union to facilitate converting from FILETIME to unsigned __int64 - */ -typedef union { - unsigned __int64 ft_scalar; - FILETIME ft_struct; -} FT; - -void -gettimeofday( struct timeval *tv , struct timezone *not_used ) -{ - FT nt_time; - __int64 UnixTime; /* microseconds since 1/1/1970 */ - - GetSystemTimeAsFileTime( &(nt_time.ft_struct) ); - - UnixTime = ((nt_time.ft_scalar - EPOCH_BIAS) / S64_SUFFIX(10)); - tv->tv_sec = (long)(time_t)(UnixTime / S64_SUFFIX(1000000)); - tv->tv_usec = (unsigned long)(UnixTime % S64_SUFFIX(1000000)); -} -#endif /* WIN32 */ - - - -/************************************************************************/ -/* */ -/* signal catcher */ -/* */ -/************************************************************************/ - -void -#if defined(__hpux) -catcher(sig, code, scp) - int sig; - int code; - struct sigcontext *scp; -#else -catcher(int sig) -#endif /* __hpux || __VMS */ -{ - -#ifdef __hpux - if (debug > 2) { - fprintf(where,"caught signal %d ",sig); - if (scp) { - fprintf(where,"while in syscall %d\n", - scp->sc_syscall); - } - else { - fprintf(where,"null scp\n"); - } - fflush(where); - } -#endif /* RAJ_DEBUG */ - - switch(sig) { - - case SIGINT: - fprintf(where,"netperf: caught SIGINT\n"); - fflush(where); - exit(1); - break; - case SIGALRM: - if (--test_len_ticks == 0) { - /* the test is over */ - if (times_up != 0) { - fprintf(where,"catcher: timer popped with times_up != 0\n"); - fflush(where); - } - times_up = 1; -#if defined(WANT_INTERVALS) && !defined(WANT_SPIN) - stop_itimer(); -#endif /* WANT_INTERVALS */ - break; - } - else { -#ifdef WANT_INTERVALS -#ifdef __hpux - /* the test is not over yet and we must have been using the */ - /* interval timer. if we were in SYS_SIGSUSPEND we want to */ - /* re-start the system call. Otherwise, we want to get out of */ - /* the sigsuspend call. I NEED TO KNOW HOW TO DO THIS FOR OTHER */ - /* OPERATING SYSTEMS. If you know how, please let me know. rick */ - /* jones <raj@cup.hp.com> */ - if (scp->sc_syscall != SYS_SIGSUSPEND) { - if (debug > 2) { - fprintf(where, - "catcher: Time to send burst > interval!\n"); - fflush(where); - } - scp->sc_syscall_action = SIG_RESTART; - } -#endif /* __hpux */ -#else /* WANT_INTERVALS */ - fprintf(where, - "catcher: interval timer running unexpectedly!\n"); - fflush(where); - times_up = 1; -#endif /* WANT_INTERVALS */ - break; - } - } - return; -} - - -void -install_signal_catchers() - -{ - /* just a simple little routine to catch a bunch of signals */ - -#ifndef WIN32 - struct sigaction action; - int i; - - fprintf(where,"installing catcher for all signals\n"); - fflush(where); - - sigemptyset(&(action.sa_mask)); - action.sa_handler = catcher; - -#ifdef SA_INTERRUPT - action.sa_flags = SA_INTERRUPT; -#else /* SA_INTERRUPT */ - action.sa_flags = 0; -#endif /* SA_INTERRUPT */ - - - for (i = 1; i <= NSIG; i++) { - if (i != SIGALRM) { - if (sigaction(i,&action,NULL) != 0) { - fprintf(where, - "Could not install signal catcher for sig %d, errno %d\n", - i, - errno); - fflush(where); - - } - } - } -#else - return; -#endif /* WIN32 */ -} - - -#ifdef WIN32 -#define SIGALRM (14) -void -emulate_alarm( int seconds ) -{ - DWORD ErrorCode; - - /* Wait on this event for parm seconds. */ - - ErrorCode = WaitForSingleObject(hAlarm, seconds*1000); - if (ErrorCode == WAIT_FAILED) - { - perror("WaitForSingleObject failed"); - exit(1); - } - - if (ErrorCode == WAIT_TIMEOUT) - { - /* WaitForSingleObject timed out; this means the timer - wasn't canceled. */ - - times_up = 1; - - /* We have yet to find a good way to fully emulate the effects */ - /* of signals and getting EINTR from system calls under */ - /* winsock, so what we do here is close the socket out from */ - /* under the other thread. It is rather kludgy, but should be */ - /* sufficient to get this puppy shipped. The concept can be */ - /* attributed/blamed :) on Robin raj 1/96 */ - - if (win_kludge_socket != INVALID_SOCKET) { - closesocket(win_kludge_socket); - } - if (win_kludge_socket2 != INVALID_SOCKET) { - closesocket(win_kludge_socket2); - } - } -} - -#endif /* WIN32 */ - -void -start_timer(int time) -{ - -#ifdef WIN32 - /*+*+SAF What if StartTimer is called twice without the first timer */ - /*+*+SAF expiring? */ - - DWORD thread_id ; - HANDLE tHandle; - - if (hAlarm == (HANDLE) INVALID_HANDLE_VALUE) - { - /* Create the Alarm event object */ - hAlarm = CreateEvent( - (LPSECURITY_ATTRIBUTES) NULL, /* no security */ - FALSE, /* auto reset event */ - FALSE, /* init. state = reset */ - (void *)NULL); /* unnamed event object */ - if (hAlarm == (HANDLE) INVALID_HANDLE_VALUE) - { - perror("CreateEvent failure"); - exit(1); - } - } - else - { - ResetEvent(hAlarm); - } - - - tHandle = CreateThread(0, - 0, - (LPTHREAD_START_ROUTINE)emulate_alarm, - (LPVOID)(ULONG_PTR)time, - 0, - &thread_id ) ; - CloseHandle(tHandle); - -#else /* not WIN32 */ - -struct sigaction action; - -if (debug) { - fprintf(where,"About to start a timer for %d seconds.\n",time); - fflush(where); -} - - action.sa_handler = catcher; - sigemptyset(&(action.sa_mask)); - sigaddset(&(action.sa_mask),SIGALRM); - -#ifdef SA_INTERRUPT - /* on some systems (SunOS 4.blah), system calls are restarted. we do */ - /* not want that */ - action.sa_flags = SA_INTERRUPT; -#else /* SA_INTERRUPT */ - action.sa_flags = 0; -#endif /* SA_INTERRUPT */ - - if (sigaction(SIGALRM, &action, NULL) < 0) { - fprintf(where,"start_timer: error installing alarm handler "); - fprintf(where,"errno %d\n",errno); - fflush(where); - exit(1); - } - - /* this is the easy case - just set the timer for so many seconds */ - if (alarm(time) != 0) { - fprintf(where, - "error starting alarm timer, errno %d\n", - errno); - fflush(where); - } -#endif /* WIN32 */ - - test_len_ticks = 1; - -} - - - /* this routine will disable any running timer */ -void -stop_timer() -{ -#ifndef WIN32 - alarm(0); -#else - /* at some point we may need some win32 equivalent */ - if (hAlarm != (HANDLE) INVALID_HANDLE_VALUE) - { - SetEvent(hAlarm); - } -#endif /* WIN32 */ - -} - - -#ifdef WANT_INTERVALS - /* this routine will enable the interval timer and set things up so */ - /* that for a timed test the test will end at the proper time. it */ - /* should detect the presence of POSIX.4 timer_* routines one of */ - /* these days */ -void -start_itimer(unsigned int interval_len_msec ) -{ - - unsigned int ticks_per_itvl; - - struct itimerval new_interval; - struct itimerval old_interval; - - /* if -DWANT_INTERVALS was used, we will use the ticking of the itimer to */ - /* tell us when the test is over. while the user will be specifying */ - /* some number of milliseconds, we know that the interval timer is */ - /* really in units of 1/HZ. so, to prevent the test from running */ - /* "long" it would be necessary to keep this in mind when calculating */ - /* the number of itimer events */ - - ticks_per_itvl = ((interval_wate * sysconf(_SC_CLK_TCK) * 1000) / - 1000000); - - if (ticks_per_itvl == 0) ticks_per_itvl = 1; - - /* how many usecs in each interval? */ - usec_per_itvl = ticks_per_itvl * (1000000 / sysconf(_SC_CLK_TCK)); - - /* how many times will the timer pop before the test is over? */ - if (test_time > 0) { - /* this was a timed test */ - test_len_ticks = (test_time * 1000000) / usec_per_itvl; - } - else { - /* this was not a timed test, use MAXINT */ - test_len_ticks = INT_MAX; - } - - if (debug) { - fprintf(where,"setting the interval timer to %d sec %d usec ", - usec_per_itvl / 1000000, - usec_per_itvl % 1000000); - fprintf(where,"test len %d ticks\n", - test_len_ticks); - fflush(where); - } - - /* if this was not a timed test, then we really aught to enable the */ - /* signal catcher raj 2/95 */ - - new_interval.it_interval.tv_sec = usec_per_itvl / 1000000; - new_interval.it_interval.tv_usec = usec_per_itvl % 1000000; - new_interval.it_value.tv_sec = usec_per_itvl / 1000000; - new_interval.it_value.tv_usec = usec_per_itvl % 1000000; - if (setitimer(ITIMER_REAL,&new_interval,&old_interval) != 0) { - /* there was a problem arming the interval timer */ - perror("netperf: setitimer"); - exit(1); - } -} -#endif /* WANT_INTERVALS */ - -void -netlib_init_cpu_map() { - - int i; -#ifdef HAVE_MPCTL - int num; - i = 0; - /* I go back and forth on whether this should be the system-wide set - of calls, or if the processor set versions (sans the _SYS) should - be used. at the moment I believe that the system-wide version - should be used. raj 2006-04-03 */ - num = mpctl(MPC_GETNUMSPUS_SYS,0,0); - lib_cpu_map[i] = mpctl(MPC_GETFIRSTSPU_SYS,0,0); - for (i = 1;((i < num) && (i < MAXCPUS)); i++) { - lib_cpu_map[i] = mpctl(MPC_GETNEXTSPU_SYS,lib_cpu_map[i-1],0); - } - /* from here, we set them all to -1 because if we launch more - loopers than actual CPUs, well, I'm not sure why :) */ - for (; i < MAXCPUS; i++) { - lib_cpu_map[i] = -1; - } - -#else - /* we assume that there is indeed a contiguous mapping */ - for (i = 0; i < MAXCPUS; i++) { - lib_cpu_map[i] = i; - } -#endif -} - - -/****************************************************************/ -/* */ -/* netlib_init() */ -/* */ -/* initialize the performance library... */ -/* */ -/****************************************************************/ - -void -netlib_init() -{ - int i; - - where = stdout; - - request_array = (int *)(&netperf_request); - response_array = (int *)(&netperf_response); - - for (i = 0; i < MAXCPUS; i++) { - lib_local_per_cpu_util[i] = 0.0; - } - - /* on those systems where we know that CPU numbers may not start at - zero and be contiguous, we provide a way to map from a - contiguous, starting from 0 CPU id space to the actual CPU ids. - at present this is only used for the netcpu_looper stuff because - we ass-u-me that someone setting processor affinity from the - netperf commandline will provide a "proper" CPU identifier. raj - 2006-04-03 */ - - netlib_init_cpu_map(); - - if (debug) { - fprintf(where, - "netlib_init: request_array at %p\n", - request_array); - fprintf(where, - "netlib_init: response_array at %p\n", - response_array); - - fflush(where); - } - -} - - /* this routine will conver the string into an unsigned integer. it */ - /* is used primarily for the command-line options taking a number */ - /* (such as the socket size) which could be rather large. If someone */ - /* enters 32M, then the number will be converted to 32 * 1024 * 1024. */ - /* If they inter 32m, the number will be converted to 32 * 1000 * */ - /* 1000 */ -unsigned int -convert(char *string) - -{ - unsigned int base; - base = atoi(string); - if (strstr(string,"K")) { - base *= 1024; - } - if (strstr(string,"M")) { - base *= (1024 * 1024); - } - if (strstr(string,"G")) { - base *= (1024 * 1024 * 1024); - } - if (strstr(string,"k")) { - base *= (1000); - } - if (strstr(string,"m")) { - base *= (1000 * 1000); - } - if (strstr(string,"g")) { - base *= (1000 * 1000 * 1000); - } - return(base); -} - -/* this routine is like convert, but it is used for an interval time - specification instead of stuff like socket buffer or send sizes. - it converts everything to microseconds for internal use. if there - is an 'm' at the end it assumes the user provided milliseconds, s - will imply seconds, u will imply microseconds. in the future n - will imply nanoseconds but for now it will be ignored. if there is - no suffix or an unrecognized suffix, it will be assumed the user - provided milliseconds, which was the long-time netperf default. one - of these days, we should probably revisit that nanosecond business - wrt the return value being just an int rather than a uint64_t or - something. raj 2006-02-06 */ - -unsigned int -convert_timespec(char *string) { - - unsigned int base; - base = atoi(string); - if (strstr(string,"m")) { - base *= 1000; - } - else if (strstr(string,"u")) { - base *= (1); - } - else if (strstr(string,"s")) { - base *= (1000 * 1000); - } - else { - base *= (1000); - } - return(base); -} - - - /* this routine will allocate a circular list of buffers for either */ - /* send or receive operations. each of these buffers will be aligned */ - /* and offset as per the users request. the circumference of this */ - /* ring will be controlled by the setting of send_width. the buffers */ - /* will be filled with data from the file specified in fill_file. if */ - /* fill_file is an empty string, the buffers will not be filled with */ - /* any particular data */ - -struct ring_elt * -allocate_buffer_ring(int width, int buffer_size, int alignment, int offset) -{ - - struct ring_elt *first_link = NULL; - struct ring_elt *temp_link = NULL; - struct ring_elt *prev_link; - - int i; - int malloc_size; - int bytes_left; - int bytes_read; - int do_fill; - - FILE *fill_source; - char default_fill[] = "netperf"; - int fill_cursor = 0; - - malloc_size = buffer_size + alignment + offset; - - /* did the user wish to have the buffers pre-filled with data from a */ - /* particular source? */ - if (strcmp(fill_file,"") == 0) { - do_fill = 0; - fill_source = NULL; - } - else { - do_fill = 1; - fill_source = (FILE *)fopen(fill_file,"r"); - if (fill_source == (FILE *)NULL) { - perror("Could not open requested fill file"); - exit(1); - } - } - - assert(width >= 1); - - prev_link = NULL; - for (i = 1; i <= width; i++) { - /* get the ring element */ - temp_link = (struct ring_elt *)malloc(sizeof(struct ring_elt)); - if (temp_link == NULL) { - printf("malloc(%u) failed!\n", sizeof(struct ring_elt)); - exit(1); - } - /* remember the first one so we can close the ring at the end */ - if (i == 1) { - first_link = temp_link; - } - temp_link->buffer_base = (char *)malloc(malloc_size); - if (temp_link == NULL) { - printf("malloc(%d) failed!\n", malloc_size); - exit(1); - } - -#ifndef WIN32 - temp_link->buffer_ptr = (char *)(( (long)(temp_link->buffer_base) + - (long)alignment - 1) & - ~((long)alignment - 1)); -#else - temp_link->buffer_ptr = (char *)(( (ULONG_PTR)(temp_link->buffer_base) + - (ULONG_PTR)alignment - 1) & - ~((ULONG_PTR)alignment - 1)); -#endif - temp_link->buffer_ptr += offset; - /* is where the buffer fill code goes. */ - if (do_fill) { - char *bufptr = temp_link->buffer_ptr; - bytes_left = buffer_size; - while (bytes_left) { - if (((bytes_read = (int)fread(bufptr, - 1, - bytes_left, - fill_source)) == 0) && - (feof(fill_source))){ - rewind(fill_source); - } - bufptr += bytes_read; - bytes_left -= bytes_read; - } - } - else { - /* use the default fill to ID our data traffic on the - network. it ain't exactly pretty, but it should work */ - int j; - char *bufptr = temp_link->buffer_ptr; - for (j = 0; j < buffer_size; j++) { - bufptr[j] = default_fill[fill_cursor]; - fill_cursor += 1; - /* the Windows DDK compiler with an x86_64 target wants a cast - here */ - if (fill_cursor > (int)strlen(default_fill)) { - fill_cursor = 0; - } - } - - } - temp_link->next = prev_link; - prev_link = temp_link; - } - if (first_link) { /* SAF Prefast made me do it... */ - first_link->next = temp_link; - } - - return(first_link); /* it's a circle, doesn't matter which we return */ -} - -/* this routine will dirty the first dirty_count bytes of the - specified buffer and/or read clean_count bytes from the buffer. it - will go N bytes at a time, the only question is how large should N - be and if we should be going continguously, or based on some - assumption of cache line size */ - -void -access_buffer(char *buffer_ptr,int length, int dirty_count, int clean_count) { - - char *temp_buffer; - char *limit; - int i, dirty_totals; - - temp_buffer = buffer_ptr; - limit = temp_buffer + length; - dirty_totals = 0; - - for (i = 0; - ((i < dirty_count) && (temp_buffer < limit)); - i++) { - *temp_buffer += (char)i; - dirty_totals += *temp_buffer; - temp_buffer++; - } - - for (i = 0; - ((i < clean_count) && (temp_buffer < limit)); - i++) { - dirty_totals += *temp_buffer; - temp_buffer++; - } - - if (debug > 100) { - fprintf(where, - "This was here to try to avoid dead-code elimination %d\n", - dirty_totals); - fflush(where); - } -} - - -#ifdef HAVE_ICSC_EXS - -#include <sys/mman.h> -#include <sys/exs.h> - - /* this routine will allocate a circular list of buffers for either */ - /* send or receive operations. each of these buffers will be aligned */ - /* and offset as per the users request. the circumference of this */ - /* ring will be controlled by the setting of send_width. the buffers */ - /* will be filled with data from the file specified in fill_file. if */ - /* fill_file is an empty string, the buffers will not be filled with */ - /* any particular data */ - -struct ring_elt * -allocate_exs_buffer_ring (int width, int buffer_size, int alignment, int offset, exs_mhandle_t *mhandlep) -{ - - struct ring_elt *first_link; - struct ring_elt *temp_link; - struct ring_elt *prev_link; - - int i; - int malloc_size; - int bytes_left; - int bytes_read; - int do_fill; - - FILE *fill_source; - - int mmap_size; - char *mmap_buffer, *mmap_buffer_aligned; - - malloc_size = buffer_size + alignment + offset; - - /* did the user wish to have the buffers pre-filled with data from a */ - /* particular source? */ - if (strcmp (fill_file, "") == 0) { - do_fill = 0; - fill_source = NULL; - } else { - do_fill = 1; - fill_source = (FILE *) fopen (fill_file, "r"); - if (fill_source == (FILE *) NULL) { - perror ("Could not open requested fill file"); - exit (1); - } - } - - assert (width >= 1); - - if (debug) { - fprintf (where, "allocate_exs_buffer_ring: " - "width=%d buffer_size=%d alignment=%d offset=%d\n", - width, buffer_size, alignment, offset); - } - - /* allocate shared memory */ - mmap_size = width * malloc_size; - mmap_buffer = (char *) mmap ((caddr_t)NULL, mmap_size+NBPG-1, - PROT_READ|PROT_WRITE, - MAP_SHARED|MAP_ANONYMOUS, -1, 0); - if (mmap_buffer == NULL) { - perror ("allocate_exs_buffer_ring: mmap failed"); - exit (1); - } - mmap_buffer_aligned = (char *) ((uintptr_t)mmap_buffer & ~(NBPG-1)); - if (debug) { - fprintf (where, "allocate_exs_buffer_ring: " - "mmap buffer size=%d address=0x%p aligned=0x%p\n", - mmap_size, mmap_buffer, mmap_buffer_aligned); - } - - /* register shared memory */ - *mhandlep = exs_mregister ((void *)mmap_buffer_aligned, (size_t)mmap_size, 0); - if (*mhandlep == EXS_MHANDLE_INVALID) { - perror ("allocate_exs_buffer_ring: exs_mregister failed"); - exit (1); - } - if (debug) { - fprintf (where, "allocate_exs_buffer_ring: mhandle=%d\n", - *mhandlep); - } - - /* allocate ring elements */ - first_link = (struct ring_elt *) malloc (width * sizeof (struct ring_elt)); - if (first_link == NULL) { - printf ("malloc(%d) failed!\n", width * sizeof (struct ring_elt)); - exit (1); - } - - /* initialize buffer ring */ - prev_link = first_link + width - 1; - - for (i = 0, temp_link = first_link; i < width; i++, temp_link++) { - - temp_link->buffer_base = (char *) mmap_buffer_aligned + (i*malloc_size); -#ifndef WIN32 - temp_link->buffer_ptr = (char *) - (((long)temp_link->buffer_base + (long)alignment - 1) & - ~((long)alignment - 1)); -#else - temp_link->buffer_ptr = (char *) - (((ULONG_PTR)temp_link->buffer_base + (ULONG_PTR)alignment - 1) & - ~((ULONG_PTR)alignment - 1)); -#endif - temp_link->buffer_ptr += offset; - - if (debug) { - fprintf (where, "allocate_exs_buffer_ring: " - "buffer: index=%d base=0x%p ptr=0x%p\n", - i, temp_link->buffer_base, temp_link->buffer_ptr); - } - - /* is where the buffer fill code goes. */ - if (do_fill) { - bytes_left = buffer_size; - while (bytes_left) { - if (((bytes_read = (int) fread (temp_link->buffer_ptr, - 1, - bytes_left, - fill_source)) == 0) && - (feof (fill_source))) { - rewind (fill_source); - } - bytes_left -= bytes_read; - } - } - - /* do linking */ - prev_link->next = temp_link; - prev_link = temp_link; - } - - return (first_link); /* it's a circle, doesn't matter which we return */ -} - -#endif /* HAVE_ICSC_EXS */ - - - -#ifdef HAVE_SENDFILE -/* this routine will construct a ring of sendfile_ring_elt structs - that the routine sendfile_tcp_stream() will use to get parameters - to its calls to sendfile(). It will setup the ring to point at the - file specified in the global -F option that is already used to - pre-fill buffers in the send() case. 08/2000 - - if there is no file specified in a global -F option, we will create - a tempoarary file and fill it with random data and use that - instead. raj 2007-08-09 */ - -struct sendfile_ring_elt * -alloc_sendfile_buf_ring(int width, - int buffer_size, - int alignment, - int offset) - -{ - - struct sendfile_ring_elt *first_link = NULL; - struct sendfile_ring_elt *temp_link = NULL; - struct sendfile_ring_elt *prev_link; - - int i; - int fildes; - struct stat statbuf; - - /* if the user has not specified a file with the -F option, we will - fail the test. otherwise, go ahead and try to open the - file. 08/2000 */ - if (strcmp(fill_file,"") == 0) { - /* use an temp file for the fill file */ - char *temp_file; - int *temp_buffer; - - /* make sure we have at least an ints worth, even if the user is - using an insane buffer size for a sendfile test. we are - ass-u-me-ing that malloc will return something at least aligned - on an int boundary... */ - temp_buffer = (int *) malloc(buffer_size + sizeof(int)); - if (temp_buffer) { - /* ok, we have the buffer we are going to write, lets get a - temporary filename */ - temp_file = tmpnam(NULL); - if (NULL != temp_file) { - fildes = open(temp_file,O_RDWR | O_EXCL | O_CREAT,0600); - if (-1 != fildes) { - int count; - int *int_ptr; - - /* initialize the random number generator */ - srand(getpid()); - - /* unlink the file so it goes poof when we - exit. unless/until shown to be a problem we will - blissfully ignore the return value. raj 2007-08-09 */ - unlink(temp_file); - - /* now fill-out the file with at least buffer_size * width bytes */ - for (count = 0; count < width; count++) { - /* fill the buffer with random data. it doesn't have to be - really random, just "random enough" :) we do this here rather - than up above because we want each write to the file to be - different random data */ - int_ptr = temp_buffer; - for (i = 0; i <= buffer_size/sizeof(int); i++) { - *int_ptr = rand(); - int_ptr++; - } - if (write(fildes,temp_buffer,buffer_size+sizeof(int)) != - buffer_size + sizeof(int)) { - perror("allocate_sendfile_buf_ring: incomplete write"); - exit(-1); - } - } - } - else { - perror("allocate_sendfile_buf_ring: could not open tempfile"); - exit(-1); - } - } - else { - perror("allocate_sendfile_buf_ring: could not allocate temp name"); - exit(-1); - } - } - else { - perror("alloc_sendfile_buf_ring: could not allocate buffer for file"); - exit(-1); - } - } - else { - /* the user pointed us at a file, so try it */ - fildes = open(fill_file , O_RDONLY); - if (fildes == -1){ - perror("alloc_sendfile_buf_ring: Could not open requested file"); - exit(1); - } - /* make sure there is enough file there to allow us to make a - complete ring. that way we do not need additional logic in the - ring setup to deal with wrap-around issues. we might want that - someday, but not just now. 08/2000 */ - if (stat(fill_file,&statbuf) != 0) { - perror("alloc_sendfile_buf_ring: could not stat file"); - exit(1); - } - if (statbuf.st_size < (width * buffer_size)) { - /* the file is too short */ - fprintf(stderr,"alloc_sendfile_buf_ring: specified file too small.\n"); - fprintf(stderr,"file must be larger than send_width * send_size\n"); - fflush(stderr); - exit(1); - } - } - - /* so, at this point we know that fildes is a descriptor which - references a file of sufficient size for our nefarious - porpoises. raj 2007-08-09 */ - - prev_link = NULL; - for (i = 1; i <= width; i++) { - /* get the ring element. we should probably make sure the malloc() - was successful, but for now we'll just let the code bomb - mysteriously. 08/2000 */ - - temp_link = (struct sendfile_ring_elt *) - malloc(sizeof(struct sendfile_ring_elt)); - if (temp_link == NULL) { - printf("malloc(%u) failed!\n", sizeof(struct sendfile_ring_elt)); - exit(1); - } - - /* remember the first one so we can close the ring at the end */ - - if (i == 1) { - first_link = temp_link; - } - - /* now fill-in the fields of the structure with the apropriate - stuff. just how should we deal with alignment and offset I - wonder? until something better comes-up, I think we will just - ignore them. 08/2000 */ - - temp_link->fildes = fildes; /* from which file do we send? */ - temp_link->offset = offset; /* starting at which offset? */ - offset += buffer_size; /* get ready for the next elt */ - temp_link->length = buffer_size; /* how many bytes to send */ - temp_link->hdtrl = NULL; /* no header or trailer */ - temp_link->flags = 0; /* no flags */ - - /* is where the buffer fill code went. */ - - temp_link->next = prev_link; - prev_link = temp_link; - } - /* close the ring */ - first_link->next = temp_link; - - return(first_link); /* it's a dummy ring */ -} - -#endif /* HAVE_SENDFILE */ - - - /***********************************************************************/ - /* */ - /* dump_request() */ - /* */ - /* display the contents of the request array to the user. it will */ - /* display the contents in decimal, hex, and ascii, with four bytes */ - /* per line. */ - /* */ - /***********************************************************************/ - -void -dump_request() -{ -int counter = 0; -fprintf(where,"request contents:\n"); -for (counter = 0; counter < ((sizeof(netperf_request)/4)-3); counter += 4) { - fprintf(where,"%d:\t%8x %8x %8x %8x \t|%4.4s| |%4.4s| |%4.4s| |%4.4s|\n", - counter, - request_array[counter], - request_array[counter+1], - request_array[counter+2], - request_array[counter+3], - (char *)&request_array[counter], - (char *)&request_array[counter+1], - (char *)&request_array[counter+2], - (char *)&request_array[counter+3]); -} -fflush(where); -} - - - /***********************************************************************/ - /* */ - /* dump_response() */ - /* */ - /* display the content of the response array to the user. it will */ - /* display the contents in decimal, hex, and ascii, with four bytes */ - /* per line. */ - /* */ - /***********************************************************************/ - -void -dump_response() -{ -int counter = 0; - -fprintf(where,"response contents\n"); -for (counter = 0; counter < ((sizeof(netperf_response)/4)-3); counter += 4) { - fprintf(where,"%d:\t%8x %8x %8x %8x \t>%4.4s< >%4.4s< >%4.4s< >%4.4s<\n", - counter, - response_array[counter], - response_array[counter+1], - response_array[counter+2], - response_array[counter+3], - (char *)&response_array[counter], - (char *)&response_array[counter+1], - (char *)&response_array[counter+2], - (char *)&response_array[counter+3]); -} -fflush(where); -} - - /* - - format_number() - - return a pointer to a formatted string containing the value passed - translated into the units specified. It assumes that the base units - are bytes. If the format calls for bits, it will use SI units (10^) - if the format calls for bytes, it will use CS units (2^)... This - routine should look familiar to uses of the latest ttcp... - - we would like to use "t" or "T" for transactions, but probably - should leave those for terabits and terabytes respectively, so for - transactions, we will use "x" which will, by default, do absolutely - nothing to the result. why? so we don't have to special case code - elsewhere such as in the TCP_RR-as-bidirectional test case. - - */ - - -char * -format_number(double number) -{ - static char fmtbuf[64]; - - switch (libfmt) { - case 'K': - snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f" , number / 1024.0); - break; - case 'M': - snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number / 1024.0 / 1024.0); - break; - case 'G': - snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number / 1024.0 / 1024.0 / 1024.0); - break; - case 'k': - snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number * 8 / 1000.0); - break; - case 'm': - snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number * 8 / 1000.0 / 1000.0); - break; - case 'g': - snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number * 8 / 1000.0 / 1000.0 / 1000.0); - break; - case 'x': - snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number); - break; - default: - snprintf(fmtbuf, sizeof(fmtbuf), "%-7.2f", number / 1024.0); - } - - return fmtbuf; -} - -char -format_cpu_method(int method) -{ - - char method_char; - - switch (method) { - case CPU_UNKNOWN: - method_char = 'U'; - break; - case HP_IDLE_COUNTER: - method_char = 'I'; - break; - case PSTAT: - method_char = 'P'; - break; - case KSTAT: - method_char = 'K'; - break; - case KSTAT_10: - method_char = 'M'; - break; - case PERFSTAT: - method_char = 'E'; - break; - case TIMES: /* historical only, completely unsuitable - for netperf's purposes */ - method_char = 'T'; - break; - case GETRUSAGE: /* historical only, completely unsuitable - for netperf;s purposes */ - method_char = 'R'; - break; - case LOOPER: - method_char = 'L'; - break; - case NT_METHOD: - method_char = 'N'; - break; - case PROC_STAT: - method_char = 'S'; - break; - case SYSCTL: - method_char = 'C'; - break; - case OSX: - method_char = 'O'; - break; - default: - method_char = '?'; - } - - return method_char; - -} - -char * -format_units() -{ - static char unitbuf[64]; - - switch (libfmt) { - case 'K': - strcpy(unitbuf, "KBytes"); - break; - case 'M': - strcpy(unitbuf, "MBytes"); - break; - case 'G': - strcpy(unitbuf, "GBytes"); - break; - case 'k': - strcpy(unitbuf, "10^3bits"); - break; - case 'm': - strcpy(unitbuf, "10^6bits"); - break; - case 'g': - strcpy(unitbuf, "10^9bits"); - break; - case 'x': - strcpy(unitbuf, "Trans"); - break; - - default: - strcpy(unitbuf, "KBytes"); - } - - return unitbuf; -} - - -/****************************************************************/ -/* */ -/* shutdown_control() */ -/* */ -/* tear-down the control connection between me and the server. */ -/****************************************************************/ - -void -shutdown_control() -{ - - char *buf = (char *)&netperf_response; - int buflen = sizeof(netperf_response); - - /* stuff for select, use fd_set for better compliance */ - fd_set readfds; - struct timeval timeout; - - if (debug) { - fprintf(where, - "shutdown_control: shutdown of control connection requested.\n"); - fflush(where); - } - - /* first, we say that we will be sending no more data on the */ - /* connection */ - if (shutdown(netlib_control,1) == SOCKET_ERROR) { - Print_errno(where, - "shutdown_control: error in shutdown"); - fflush(where); - exit(1); - } - - /* Now, we hang on a select waiting for the socket to become */ - /* readable to receive the shutdown indication from the remote. this */ - /* will be "just" like the recv_response() code */ - - /* we only select once. it is assumed that if the response is split */ - /* (which should not be happening, that we will receive the whole */ - /* thing and not have a problem ;-) */ - - FD_ZERO(&readfds); - FD_SET(netlib_control,&readfds); - timeout.tv_sec = 60; /* wait one minute then punt */ - timeout.tv_usec = 0; - - /* select had better return one, or there was either a problem or a */ - /* timeout... */ - if (select(FD_SETSIZE, - &readfds, - 0, - 0, - &timeout) != 1) { - Print_errno(where, - "shutdown_control: no response received"); - fflush(where); - exit(1); - } - - /* we now assume that the socket has come ready for reading */ - recv(netlib_control, buf, buflen,0); - -} - -/* - bind_to_specific_processor will bind the calling process to the - processor in "processor" It has lots of ugly ifdefs to deal with - all the different ways systems do processor affinity. this is a - generalization of work initially done by stephen burger. raj - 2004/12/13 */ - -void -bind_to_specific_processor(int processor_affinity, int use_cpu_map) -{ - - int mapped_affinity; - - /* this is in place because the netcpu_looper processor affinity - ass-u-me-s a contiguous CPU id space starting with 0. for the - regular netperf/netserver affinity, we ass-u-me the user has used - a suitable CPU id even when the space is not contiguous and - starting from zero */ - if (use_cpu_map) { - mapped_affinity = lib_cpu_map[processor_affinity]; - } - else { - mapped_affinity = processor_affinity; - } - -#ifdef HAVE_MPCTL - /* indeed, at some point it would be a good idea to check the return - status and pass-along notification of error... raj 2004/12/13 */ - mpctl(MPC_SETPROCESS_FORCE, mapped_affinity, getpid()); -#elif HAVE_PROCESSOR_BIND -#include <sys/types.h> -#include <sys/processor.h> -#include <sys/procset.h> - processor_bind(P_PID,P_MYID,mapped_affinity,NULL); -#elif HAVE_BINDPROCESSOR -#include <sys/processor.h> - /* this is the call on AIX. It takes a "what" of BINDPROCESS or - BINDTHRAD, then "who" and finally "where" which is a CPU number - or it seems PROCESSOR_CLASS_ANY there also seems to be a mycpu() - call to return the current CPU assignment. this is all based on - the sys/processor.h include file. from empirical testing, it - would seem that the my_cpu() call returns the current CPU on - which we are running rather than the CPU binding, so it's return - value will not tell you if you are bound vs unbound. */ - bindprocessor(BINDPROCESS,getpid(),(cpu_t)mapped_affinity); -#elif HAVE_SCHED_SETAFFINITY -#include <sched.h> - /* in theory this should cover systems with more CPUs than bits in a - long, without having to specify __USE_GNU. we "cheat" by taking - defines from /usr/include/bits/sched.h, which we ass-u-me is - included by <sched.h>. If they are not there we will just - fall-back on what we had before, which is to use just the size of - an unsigned long. raj 2006-09-14 */ - -#if defined(__CPU_SETSIZE) -#define NETPERF_CPU_SETSIZE __CPU_SETSIZE -#define NETPERF_CPU_SET(cpu, cpusetp) __CPU_SET(cpu, cpusetp) -#define NETPERF_CPU_ZERO(cpusetp) __CPU_ZERO (cpusetp) - typedef cpu_set_t netperf_cpu_set_t; -#else -#define NETPERF_CPU_SETSIZE sizeof(unsigned long) -#define NETPERF_CPU_SET(cpu, cpusetp) *cpusetp = 1 << cpu -#define NETPERF_CPU_ZERO(cpusetp) *cpusetp = (unsigned long)0 - typedef unsigned long netperf_cpu_set_t; -#endif - - netperf_cpu_set_t netperf_cpu_set; - unsigned int len = sizeof(netperf_cpu_set); - - if (mapped_affinity < 8*sizeof(netperf_cpu_set)) { - NETPERF_CPU_ZERO(&netperf_cpu_set); - NETPERF_CPU_SET(mapped_affinity,&netperf_cpu_set); - - if (sched_setaffinity(getpid(), len, &netperf_cpu_set)) { - if (debug) { - fprintf(stderr, "failed to set PID %d's CPU affinity errno %d\n", - getpid(),errno); - fflush(stderr); - } - } - } - else { - if (debug) { - fprintf(stderr, - "CPU number larger than pre-compiled limits. Consider a recompile.\n"); - fflush(stderr); - } - } - -#elif HAVE_BIND_TO_CPU_ID - /* this is the one for Tru64 */ -#include <sys/types.h> -#include <sys/resource.h> -#include <sys/processor.h> - - /* really should be checking a return code one of these days. raj - 2005/08/31 */ - - bind_to_cpu_id(getpid(), mapped_affinity,0); - -#elif WIN32 - - { - ULONG_PTR AffinityMask; - ULONG_PTR ProcessAffinityMask; - ULONG_PTR SystemAffinityMask; - - if ((mapped_affinity < 0) || - (mapped_affinity > MAXIMUM_PROCESSORS)) { - fprintf(where, - "Invalid processor_affinity specified: %d\n", mapped_affinity); fflush(where); - return; - } - - if (!GetProcessAffinityMask( - GetCurrentProcess(), - &ProcessAffinityMask, - &SystemAffinityMask)) - { - perror("GetProcessAffinityMask failed"); - fflush(stderr); - exit(1); - } - - AffinityMask = (ULONG_PTR)1 << mapped_affinity; - - if (AffinityMask & ProcessAffinityMask) { - if (!SetThreadAffinityMask( GetCurrentThread(), AffinityMask)) { - perror("SetThreadAffinityMask failed"); - fflush(stderr); - } - } else if (debug) { - fprintf(where, - "Processor affinity set to CPU# %d\n", mapped_affinity); - fflush(where); - } - } - -#else - if (debug) { - fprintf(where, - "Processor affinity not available for this platform!\n"); - fflush(where); - } -#endif -} - - -/* - * Sets a socket to non-blocking operation. - */ -int -set_nonblock (SOCKET sock) -{ -#ifdef WIN32 - unsigned long flags = 1; - return (ioctlsocket(sock, FIONBIO, &flags) != SOCKET_ERROR); -#else - return (fcntl(sock, F_SETFL, O_NONBLOCK) != -1); -#endif -} - - - - /***********************************************************************/ - /* */ - /* send_request() */ - /* */ - /* send a netperf request on the control socket to the remote half of */ - /* the connection. to get us closer to intervendor interoperability, */ - /* we will call htonl on each of the int that compose the message to */ - /* be sent. the server-half of the connection will call the ntohl */ - /* routine to undo any changes that may have been made... */ - /* */ - /***********************************************************************/ - -void -send_request() -{ - int counter=0; - - /* display the contents of the request if the debug level is high */ - /* enough. otherwise, just send the darned thing ;-) */ - - if (debug > 1) { - fprintf(where,"entered send_request...contents before htonl:\n"); - dump_request(); - } - - /* pass the processor affinity request value to netserver */ - /* this is a kludge and I know it. sgb 8/11/04 */ - - netperf_request.content.dummy = remote_proc_affinity; - - /* put the entire request array into network order. We do this */ - /* arbitrarily rather than trying to figure-out just how much */ - /* of the request array contains real information. this should */ - /* be simpler, and at any rate, the performance of sending */ - /* control messages for this benchmark is not of any real */ - /* concern. */ - - for (counter=0;counter < sizeof(netperf_request)/4; counter++) { - request_array[counter] = htonl(request_array[counter]); - } - - if (debug > 1) { - fprintf(where,"send_request...contents after htonl:\n"); - dump_request(); - - fprintf(where, - "\nsend_request: about to send %u bytes from %p\n", - sizeof(netperf_request), - &netperf_request); - fflush(where); - } - - if (send(netlib_control, - (char *)&netperf_request, - sizeof(netperf_request), - 0) != sizeof(netperf_request)) { - perror("send_request: send call failure"); - - exit(1); - } -} - -/***********************************************************************/ - /* */ - /* send_response() */ - /* */ - /* send a netperf response on the control socket to the remote half of */ - /* the connection. to get us closer to intervendor interoperability, */ - /* we will call htonl on each of the int that compose the message to */ - /* be sent. the other half of the connection will call the ntohl */ - /* routine to undo any changes that may have been made... */ - /* */ - /***********************************************************************/ - -void -send_response() -{ - int counter=0; - int bytes_sent; - - /* display the contents of the request if the debug level is high */ - /* enough. otherwise, just send the darned thing ;-) */ - - if (debug > 1) { - fprintf(where, - "send_response: contents of %u ints before htonl\n", - sizeof(netperf_response)/4); - dump_response(); - } - - /* put the entire response_array into network order. We do this */ - /* arbitrarily rather than trying to figure-out just how much of the */ - /* request array contains real information. this should be simpler, */ - /* and at any rate, the performance of sending control messages for */ - /* this benchmark is not of any real concern. */ - - for (counter=0;counter < sizeof(netperf_response)/4; counter++) { - response_array[counter] = htonl(response_array[counter]); - } - - if (debug > 1) { - fprintf(where, - "send_response: contents after htonl\n"); - dump_response(); - fprintf(where, - "about to send %u bytes from %p\n", - sizeof(netperf_response), - &netperf_response); - fflush(where); - } - - /*KC*/ - if ((bytes_sent = send(server_sock, - (char *)&netperf_response, - sizeof(netperf_response), - 0)) != sizeof(netperf_response)) { - perror("send_response: send call failure"); - fprintf(where, "BytesSent: %d\n", bytes_sent); - exit(1); - } - -} - - /***********************************************************************/ - /* */ - /* recv_request() */ - /* */ - /* receive the remote's request on the control socket. we will put */ - /* the entire response into host order before giving it to the */ - /* calling routine. hopefully, this will go most of the way to */ - /* insuring intervendor interoperability. if there are any problems, */ - /* we will just punt the entire situation. */ - /* */ - /***********************************************************************/ - -void -recv_request() -{ -int tot_bytes_recvd, - bytes_recvd, - bytes_left; -char *buf = (char *)&netperf_request; -int buflen = sizeof(netperf_request); -int counter; - -tot_bytes_recvd = 0; - bytes_recvd = 0; /* nt_lint; bytes_recvd uninitialized if buflen == 0 */ -bytes_left = buflen; -while ((tot_bytes_recvd != buflen) && - ((bytes_recvd = recv(server_sock, buf, bytes_left,0)) > 0 )) { - tot_bytes_recvd += bytes_recvd; - buf += bytes_recvd; - bytes_left -= bytes_recvd; -} - -/* put the request into host order */ - -for (counter = 0; counter < sizeof(netperf_request)/sizeof(int); counter++) { - request_array[counter] = ntohl(request_array[counter]); -} - -if (debug) { - fprintf(where, - "recv_request: received %d bytes of request.\n", - tot_bytes_recvd); - fflush(where); -} - -if (bytes_recvd == SOCKET_ERROR) { - Print_errno(where, - "recv_request: error on recv"); - fflush(where); - exit(1); -} - -if (bytes_recvd == 0) { - /* the remote has shutdown the control connection, we should shut it */ - /* down as well and exit */ - - if (debug) { - fprintf(where, - "recv_request: remote requested shutdown of control\n"); - fflush(where); - } - - if (netlib_control != INVALID_SOCKET) { - shutdown_control(); - } - exit(0); -} - -if (tot_bytes_recvd < buflen) { - if (debug > 1) - dump_request(); - - fprintf(where, - "recv_request: partial request received of %d bytes\n", - tot_bytes_recvd); - fflush(where); - exit(1); -} - - if (debug > 1) { - dump_request(); - } - - /* get the processor affinity request value from netperf */ - /* this is a kludge and I know it. sgb 8/11/04 */ - - local_proc_affinity = netperf_request.content.dummy; - - if (local_proc_affinity != -1) { - bind_to_specific_processor(local_proc_affinity,0); - } - -} - - /* - - recv_response_timed() - - receive the remote's response on the control socket. we will put the - entire response into host order before giving it to the calling - routine. hopefully, this will go most of the way to insuring - intervendor interoperability. if there are any problems, we will just - punt the entire situation. - - The call to select at the beginning is to get us out of hang - situations where the remote gives-up but we don't find-out about - it. This seems to happen only rarely, but it would be nice to be - somewhat robust ;-) - - The "_timed" part is to allow the caller to add (or I suppose - subtract) from the length of timeout on the select call. this was - added since not all the CPU utilization mechanisms require a 40 - second calibration, and we used to have an aribtrary 40 second sleep - in "calibrate_remote_cpu" - since we don't _always_ need that, we - want to simply add 40 seconds to the select() timeout from that call, - but don't want to change all the "recv_response" calls in the code - right away. sooo, we push the functionality of the old - recv_response() into a new recv_response_timed(addl_timout) call, and - have recv_response() call recv_response_timed(0). raj 2005-05-16 - - */ - - -void -recv_response_timed(int addl_time) -{ -int tot_bytes_recvd, - bytes_recvd = 0, - bytes_left; -char *buf = (char *)&netperf_response; -int buflen = sizeof(netperf_response); -int counter; - - /* stuff for select, use fd_set for better compliance */ -fd_set readfds; -struct timeval timeout; - -tot_bytes_recvd = 0; -bytes_left = buflen; - -/* zero out the response structure */ - -/* BUG FIX SJB 2/4/93 - should be < not <= */ -for (counter = 0; counter < sizeof(netperf_response)/sizeof(int); counter++) { - response_array[counter] = 0; -} - - /* we only select once. it is assumed that if the response is split */ - /* (which should not be happening, that we will receive the whole */ - /* thing and not have a problem ;-) */ - -FD_ZERO(&readfds); -FD_SET(netlib_control,&readfds); -timeout.tv_sec = 120 + addl_time; /* wait at least two minutes - before punting - the USE_LOOPER - CPU stuff may cause remote's to - have a bit longer time of it - than 60 seconds would allow. - triggered by fix from Jeff - Dwork. */ -timeout.tv_usec = 0; - - /* select had better return one, or there was either a problem or a */ - /* timeout... */ - -if ((counter = select(FD_SETSIZE, - &readfds, - 0, - 0, - &timeout)) != 1) { - fprintf(where, - "netperf: receive_response: no response received. errno %d counter %d\n", - errno, - counter); - exit(1); -} - -while ((tot_bytes_recvd != buflen) && - ((bytes_recvd = recv(netlib_control, buf, bytes_left,0)) > 0 )) { - tot_bytes_recvd += bytes_recvd; - buf += bytes_recvd; - bytes_left -= bytes_recvd; -} - -if (debug) { - fprintf(where,"recv_response: received a %d byte response\n", - tot_bytes_recvd); - fflush(where); -} - -/* put the response into host order */ - -for (counter = 0; counter < sizeof(netperf_response)/sizeof(int); counter++) { - response_array[counter] = ntohl(response_array[counter]); -} - -if (bytes_recvd == SOCKET_ERROR) { - perror("recv_response"); - exit(1); -} -if (tot_bytes_recvd < buflen) { - fprintf(stderr, - "recv_response: partial response received: %d bytes\n", - tot_bytes_recvd); - fflush(stderr); - if (debug > 1) - dump_response(); - exit(1); -} -if (debug > 1) { - dump_response(); -} -} - -void -recv_response() -{ - recv_response_timed(0); -} - - - -#if defined(USE_PSTAT) || defined (USE_SYSCTL) -int -hi_32(big_int) - long long *big_int; -{ - union overlay_u { - long long dword; - long words[2]; - } *overlay; - - overlay = (union overlay_u *)big_int; - /* on those systems which are byte swapped, we really wish to */ - /* return words[1] - at least I think so - raj 4/95 */ - if (htonl(1L) == 1L) { - /* we are a "normal" :) machine */ - return(overlay->words[0]); - } - else { - return(overlay->words[1]); - } -} - -int -lo_32(big_int) - long long *big_int; -{ - union overlay_u { - long long dword; - long words[2]; - } *overlay; - - overlay = (union overlay_u *)big_int; - /* on those systems which are byte swapped, we really wish to */ - /* return words[0] - at least I think so - raj 4/95 */ - if (htonl(1L) == 1L) { - /* we are a "normal" :) machine */ - return(overlay->words[1]); - } - else { - return(overlay->words[0]); - } -} - -#endif /* USE_PSTAT || USE_SYSCTL */ - - -void libmain() -{ -fprintf(where,"hello world\n"); -fprintf(where,"debug: %d\n",debug); -} - - -void -set_sock_buffer (SOCKET sd, enum sock_buffer which, int requested_size, int *effective_sizep) -{ -#ifdef SO_SNDBUF - int optname = (which == SEND_BUFFER) ? SO_SNDBUF : SO_RCVBUF; - netperf_socklen_t sock_opt_len; - - /* seems that under Windows, setting a value of zero is how one - tells the stack you wish to enable copy-avoidance. Knuth only - knows what it will do on other stacks, but it might be - interesting to find-out, so we won't bother #ifdef'ing the change - to allow asking for 0 bytes. Courtesy of SAF, 2007-05 raj - 2007-05-31 */ - if (requested_size >= 0) { - if (setsockopt(sd, SOL_SOCKET, optname, - (char *)&requested_size, sizeof(int)) < 0) { - fprintf(where, "netperf: set_sock_buffer: %s option: errno %d\n", - (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF", - errno); - fflush(where); - exit(1); - } - if (debug > 1) { - fprintf(where, "netperf: set_sock_buffer: %s of %d requested.\n", - (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF", - requested_size); - fflush(where); - } - } - - /* Now, we will find-out what the size actually became, and report */ - /* that back to the user. If the call fails, we will just report a -1 */ - /* back to the initiator for the recv buffer size. */ - - sock_opt_len = sizeof(netperf_socklen_t); - if (getsockopt(sd, SOL_SOCKET, optname, (char *)effective_sizep, - &sock_opt_len) < 0) { - fprintf(where, "netperf: set_sock_buffer: getsockopt %s: errno %d\n", - (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF", errno); - fflush(where); - *effective_sizep = -1; - } - - if (debug) { - fprintf(where, "netperf: set_sock_buffer: " - "%s socket size determined to be %d\n", - (which == SEND_BUFFER) ? "send" : "receive", *effective_sizep); - fflush(where); - } -#else /* SO_SNDBUF */ - *effective_size = -1; -#endif /* SO_SNDBUF */ -} - -void -dump_addrinfo(FILE *dumploc, struct addrinfo *info, - char *host, char *port, int family) -{ - struct sockaddr *ai_addr; - struct addrinfo *temp; - temp=info; - - fprintf(dumploc, "getaddrinfo returned the following for host '%s' ", host); - fprintf(dumploc, "port '%s' ", port); - fprintf(dumploc, "family %s\n", inet_ftos(family)); - while (temp) { - /* seems that Solaris 10 GA bits will not give a canonical name - for ::0 or 0.0.0.0, and their fprintf() cannot deal with a null - pointer, so we have to check for a null pointer. probably a - safe thing to do anyway, eventhough it was not necessary on - linux or hp-ux. raj 2005-02-09 */ - if (temp->ai_canonname) { - fprintf(dumploc, - "\tcannonical name: '%s'\n",temp->ai_canonname); - } - else { - fprintf(dumploc, - "\tcannonical name: '%s'\n","(nil)"); - } - fprintf(dumploc, - "\tflags: %x family: %s: socktype: %s protocol %s addrlen %d\n", - temp->ai_flags, - inet_ftos(temp->ai_family), - inet_ttos(temp->ai_socktype), - inet_ptos(temp->ai_protocol), - temp->ai_addrlen); - ai_addr = temp->ai_addr; - if (ai_addr != NULL) { - fprintf(dumploc, - "\tsa_family: %s sadata: %d %d %d %d %d %d\n", - inet_ftos(ai_addr->sa_family), - (u_char)ai_addr->sa_data[0], - (u_char)ai_addr->sa_data[1], - (u_char)ai_addr->sa_data[2], - (u_char)ai_addr->sa_data[3], - (u_char)ai_addr->sa_data[4], - (u_char)ai_addr->sa_data[5]); - } - temp = temp->ai_next; - } - fflush(dumploc); -} - -/* - establish_control() - -set-up the control connection between netperf and the netserver so we -can actually run some tests. if we cannot establish the control -connection, that may or may not be a good thing, so we will let the -caller decide what to do. - -to assist with pesky end-to-end-unfriendly things like firewalls, we -allow the caller to specify both the remote hostname and port, and the -local addressing info. i believe that in theory it is possible to -have an IPv4 endpoint and an IPv6 endpoint communicate with one -another, but for the time being, we are only going to take-in one -requested address family parameter. this means that the only way -(iirc) that we might get a mixed-mode connection would be if the -address family is specified as AF_UNSPEC, and getaddrinfo() returns -different families for the local and server names. - -the "names" can also be IP addresses in ASCII string form. - -raj 2003-02-27 */ - -SOCKET -establish_control_internal(char *hostname, - char *port, - int remfam, - char *localhost, - char *localport, - int locfam) -{ - int not_connected; - SOCKET control_sock; - int count; - int error; - - struct addrinfo hints; - struct addrinfo *local_res; - struct addrinfo *remote_res; - struct addrinfo *local_res_temp; - struct addrinfo *remote_res_temp; - - if (debug) { - fprintf(where, - "establish_control called with host '%s' port '%s' remfam %s\n", - hostname, - port, - inet_ftos(remfam)); - fprintf(where, - "\t\tlocal '%s' port '%s' locfam %s\n", - localhost, - localport, - inet_ftos(locfam)); - fflush(where); - } - - /* first, we do the remote */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = remfam; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = 0|AI_CANONNAME; - count = 0; - do { - error = getaddrinfo((char *)hostname, - (char *)port, - &hints, - &remote_res); - count += 1; - if (error == EAI_AGAIN) { - if (debug) { - fprintf(where,"Sleeping on getaddrinfo EAI_AGAIN\n"); - fflush(where); - } - sleep(1); - } - } while ((error == EAI_AGAIN) && (count <= 5)); - - if (error) { - printf("establish control: could not resolve remote '%s' port '%s' af %s", - hostname, - port, - inet_ftos(remfam)); - printf("\n\tgetaddrinfo returned %d %s\n", - error, - gai_strerror(error)); - return(INVALID_SOCKET); - } - - if (debug) { - dump_addrinfo(where, remote_res, hostname, port, remfam); - } - - /* now we do the local */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = locfam; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_PASSIVE|AI_CANONNAME; - count = 0; - do { - count += 1; - error = getaddrinfo((char *)localhost, - (char *)localport, - &hints, - &local_res); - if (error == EAI_AGAIN) { - if (debug) { - fprintf(where, - "Sleeping on getaddrinfo(%s,%s) EAI_AGAIN count %d \n", - localhost, - localport, - count); - fflush(where); - } - sleep(1); - } - } while ((error == EAI_AGAIN) && (count <= 5)); - - if (error) { - printf("establish control: could not resolve local '%s' port '%s' af %s", - localhost, - localport, - inet_ftos(locfam)); - printf("\n\tgetaddrinfo returned %d %s\n", - error, - gai_strerror(error)); - return(INVALID_SOCKET); - } - - if (debug) { - dump_addrinfo(where, local_res, localhost, localport, locfam); - } - - not_connected = 1; - local_res_temp = local_res; - remote_res_temp = remote_res; - /* we want to loop through all the possibilities. looping on the - local addresses will be handled within the while loop. I suppose - these is some more "C-expert" way to code this, but it has not - lept to mind just yet :) raj 2003-02024 */ - - while (remote_res_temp != NULL) { - - /* I am guessing that we should use the address family of the - local endpoint, and we will not worry about mixed family types - - presumeably the stack or other transition mechanisms will be - able to deal with that for us. famous last words :) raj 2003-02-26 */ - control_sock = socket(local_res_temp->ai_family, - SOCK_STREAM, - 0); - if (control_sock == INVALID_SOCKET) { - /* at some point we'll need a more generic "display error" - message for when/if we use GUIs and the like. unlike a bind - or connect failure, failure to allocate a socket is - "immediately fatal" and so we return to the caller. raj 2003-02-24 */ - if (debug) { - perror("establish_control: unable to allocate control socket"); - } - return(INVALID_SOCKET); - } - - /* if we are going to control the local enpoint addressing, we - need to call bind. of course, we should probably be setting one - of the SO_REUSEmumble socket options? raj 2005-02-04 */ - if (bind(control_sock, - local_res_temp->ai_addr, - local_res_temp->ai_addrlen) == 0) { - if (debug) { - fprintf(where, - "bound control socket to %s and %s\n", - localhost, - localport); - } - - if (connect(control_sock, - remote_res_temp->ai_addr, - remote_res_temp->ai_addrlen) == 0) { - /* we have successfully connected to the remote netserver */ - if (debug) { - fprintf(where, - "successful connection to remote netserver at %s and %s\n", - hostname, - port); - } - not_connected = 0; - /* this should get us out of the while loop */ - break; - } else { - /* the connect call failed */ - if (debug) { - fprintf(where, - "establish_control: connect failed, errno %d %s\n", - errno, - strerror(errno)); - fprintf(where, " trying next address combination\n"); - fflush(where); - } - } - } - else { - /* the bind failed */ - if (debug) { - fprintf(where, - "establish_control: bind failed, errno %d %s\n", - errno, - strerror(errno)); - fprintf(where, " trying next address combination\n"); - fflush(where); - } - } - - if ((local_res_temp = local_res_temp->ai_next) == NULL) { - /* wrap the local and move to the next server, don't forget to - close the current control socket. raj 2003-02-24 */ - local_res_temp = local_res; - /* the outer while conditions will deal with the case when we - get to the end of all the possible remote addresses. */ - remote_res_temp = remote_res_temp->ai_next; - /* it is simplest here to just close the control sock. since - this is not a performance critical section of code, we - don't worry about overheads for socket allocation or - close. raj 2003-02-24 */ - } - close(control_sock); - } - - /* we no longer need the addrinfo stuff */ - freeaddrinfo(local_res); - freeaddrinfo(remote_res); - - /* so, we are either connected or not */ - if (not_connected) { - fprintf(where, "establish control: are you sure there is a netserver listening on %s at port %s?\n",hostname,port); - fflush(where); - return(INVALID_SOCKET); - } - /* at this point, we are connected. we probably want some sort of - version check with the remote at some point. raj 2003-02-24 */ - return(control_sock); -} - -void -establish_control(char *hostname, - char *port, - int remfam, - char *localhost, - char *localport, - int locfam) - -{ - - netlib_control = establish_control_internal(hostname, - port, - remfam, - localhost, - localport, - locfam); - if (netlib_control == INVALID_SOCKET) { - fprintf(where, - "establish_control could not establish the control connection from %s port %s address family %s to %s port %s address family %s\n", - localhost,localport,inet_ftos(locfam), - hostname,port,inet_ftos(remfam)); - fflush(where); - exit(INVALID_SOCKET); - } -} - - - - - /***********************************************************************/ - /* */ - /* get_id() */ - /* */ - /* Return a string to the calling routine that contains the */ - /* identifying information for the host we are running on. This */ - /* information will then either be displayed locally, or returned to */ - /* a remote caller for display there. */ - /* */ - /***********************************************************************/ - -char * -get_id() -{ - static char id_string[80]; -#ifdef WIN32 -char system_name[MAX_COMPUTERNAME_LENGTH+1] ; -DWORD name_len = MAX_COMPUTERNAME_LENGTH + 1 ; -#else -struct utsname system_name; -#endif /* WIN32 */ - -#ifdef WIN32 - SYSTEM_INFO SystemInfo; - GetSystemInfo( &SystemInfo ) ; - if ( !GetComputerName(system_name , &name_len) ) - strcpy(system_name , "no_name") ; -#else - if (uname(&system_name) <0) { - perror("identify_local: uname"); - exit(1); - } -#endif /* WIN32 */ - - snprintf(id_string, sizeof(id_string), -#ifdef WIN32 - "%-15s%-15s%d.%d%d", - "Windows NT", - system_name , - GetVersion() & 0xFF , - GetVersion() & 0xFF00 , - SystemInfo.dwProcessorType - -#else - "%-15s%-15s%-15s%-15s%-15s", - system_name.sysname, - system_name.nodename, - system_name.release, - system_name.version, - system_name.machine -#endif /* WIN32 */ - ); - return (id_string); -} - - - /***********************************************************************/ - /* */ - /* identify_local() */ - /* */ - /* Display identifying information about the local host to the user. */ - /* At first release, this information will be the same as that which */ - /* is returned by the uname -a command, with the exception of the */ - /* idnumber field, which seems to be a non-POSIX item, and hence */ - /* non-portable. */ - /* */ - /***********************************************************************/ - -void -identify_local() -{ - -char *local_id; - -local_id = get_id(); - -fprintf(where,"Local Information \n\ -Sysname Nodename Release Version Machine\n"); - -fprintf(where,"%s\n", - local_id); - -} - - - /***********************************************************************/ - /* */ - /* identify_remote() */ - /* */ - /* Display identifying information about the remote host to the user. */ - /* At first release, this information will be the same as that which */ - /* is returned by the uname -a command, with the exception of the */ - /* idnumber field, which seems to be a non-POSIX item, and hence */ - /* non-portable. A request is sent to the remote side, which will */ - /* return a string containing the utsname information in a */ - /* pre-formatted form, which is then displayed after the header. */ - /* */ - /***********************************************************************/ - -void -identify_remote() -{ - -char *remote_id=""; - -/* send a request for node info to the remote */ -netperf_request.content.request_type = NODE_IDENTIFY; - -send_request(); - -/* and now wait for the reply to come back */ - -recv_response(); - -if (netperf_response.content.serv_errno) { - Set_errno(netperf_response.content.serv_errno); - perror("identify_remote: on remote"); - exit(1); -} - -fprintf(where,"Remote Information \n\ -Sysname Nodename Release Version Machine\n"); - -fprintf(where,"%s", - remote_id); -} - -void -cpu_start(int measure_cpu) -{ - - gettimeofday(&time1, - &tz); - - if (measure_cpu) { - cpu_util_init(); - measuring_cpu = 1; - cpu_method = get_cpu_method(); - cpu_start_internal(); - } -} - - -void -cpu_stop(int measure_cpu, float *elapsed) - -{ - - int sec, - usec; - - if (measure_cpu) { - cpu_stop_internal(); - cpu_util_terminate(); - } - - gettimeofday(&time2, - &tz); - - if (time2.tv_usec < time1.tv_usec) { - time2.tv_usec += 1000000; - time2.tv_sec -= 1; - } - - sec = time2.tv_sec - time1.tv_sec; - usec = time2.tv_usec - time1.tv_usec; - lib_elapsed = (float)sec + ((float)usec/(float)1000000.0); - - *elapsed = lib_elapsed; - -} - - -double -calc_thruput_interval(double units_received,double elapsed) - -{ - double divisor; - - /* We will calculate the thruput in libfmt units/second */ - switch (libfmt) { - case 'K': - divisor = 1024.0; - break; - case 'M': - divisor = 1024.0 * 1024.0; - break; - case 'G': - divisor = 1024.0 * 1024.0 * 1024.0; - break; - case 'k': - divisor = 1000.0 / 8.0; - break; - case 'm': - divisor = 1000.0 * 1000.0 / 8.0; - break; - case 'g': - divisor = 1000.0 * 1000.0 * 1000.0 / 8.0; - break; - - default: - divisor = 1024.0; - } - - return (units_received / divisor / elapsed); - -} - -double -calc_thruput(double units_received) - -{ - return(calc_thruput_interval(units_received,lib_elapsed)); -} - -/* these "_omni" versions are ones which understand 'x' as a unit, - meaning transactions/s. we have a separate routine rather than - convert the existing routine so we don't have to go and change - _all_ the nettest_foo.c files at one time. raj 2007-06-08 */ - -double -calc_thruput_interval_omni(double units_received,double elapsed) - -{ - double divisor; - - /* We will calculate the thruput in libfmt units/second */ - switch (libfmt) { - case 'K': - divisor = 1024.0; - break; - case 'M': - divisor = 1024.0 * 1024.0; - break; - case 'G': - divisor = 1024.0 * 1024.0 * 1024.0; - break; - case 'k': - divisor = 1000.0 / 8.0; - break; - case 'm': - divisor = 1000.0 * 1000.0 / 8.0; - break; - case 'g': - divisor = 1000.0 * 1000.0 * 1000.0 / 8.0; - break; - case 'x': - divisor = 1.0; - break; - - default: - fprintf(where, - "WARNING calc_throughput_internal_omni: unknown units %c\n", - libfmt); - fflush(where); - divisor = 1024.0; - } - - return (units_received / divisor / elapsed); - -} - -double -calc_thruput_omni(double units_received) - -{ - return(calc_thruput_interval_omni(units_received,lib_elapsed)); -} - - - - - -float -calc_cpu_util(float elapsed_time) -{ - return(calc_cpu_util_internal(elapsed_time)); -} - -float -calc_service_demand_internal(double unit_divisor, - double units_sent, - float elapsed_time, - float cpu_utilization, - int num_cpus) - -{ - - double service_demand; - double thruput; - - if (debug) { - fprintf(where,"calc_service_demand called: units_sent = %f\n", - units_sent); - fprintf(where," elapsed_time = %f\n", - elapsed_time); - fprintf(where," cpu_util = %f\n", - cpu_utilization); - fprintf(where," num cpu = %d\n", - num_cpus); - fflush(where); - } - - if (num_cpus == 0) num_cpus = lib_num_loc_cpus; - - if (elapsed_time == 0.0) { - elapsed_time = lib_elapsed; - } - if (cpu_utilization == 0.0) { - cpu_utilization = lib_local_cpu_util; - } - - thruput = (units_sent / - (double) unit_divisor / - (double) elapsed_time); - - /* on MP systems, it is necessary to multiply the service demand by */ - /* the number of CPU's. at least, I believe that to be the case:) */ - /* raj 10/95 */ - - /* thruput has a "per second" component. if we were using 100% ( */ - /* 100.0) of the CPU in a second, that would be 1 second, or 1 */ - /* millisecond, so we multiply cpu_utilization by 10 to go to */ - /* milliseconds, or 10,000 to go to micro seconds. With revision */ - /* 2.1, the service demand measure goes to microseconds per unit. */ - /* raj 12/95 */ - service_demand = (cpu_utilization*10000.0/thruput) * - (float) num_cpus; - - if (debug) { - fprintf(where,"calc_service_demand using: units_sent = %f\n", - units_sent); - fprintf(where," elapsed_time = %f\n", - elapsed_time); - fprintf(where," cpu_util = %f\n", - cpu_utilization); - fprintf(where," num cpu = %d\n", - num_cpus); - fprintf(where,"calc_service_demand got: thruput = %f\n", - thruput); - fprintf(where," servdem = %f\n", - service_demand); - fflush(where); - } - return (float)service_demand; -} - -float calc_service_demand(double units_sent, - float elapsed_time, - float cpu_utilization, - int num_cpus) - -{ - - double unit_divisor = (double)1024.0; - - return(calc_service_demand_internal(unit_divisor, - units_sent, - elapsed_time, - cpu_utilization, - num_cpus)); -} - -float calc_service_demand_trans(double units_sent, - float elapsed_time, - float cpu_utilization, - int num_cpus) - -{ - - double unit_divisor = (double)1.0; - - return(calc_service_demand_internal(unit_divisor, - units_sent, - elapsed_time, - cpu_utilization, - num_cpus)); -} - - - -float -calibrate_local_cpu(float local_cpu_rate) -{ - - lib_num_loc_cpus = get_num_cpus(); - - lib_use_idle = 0; -#ifdef USE_LOOPER - cpu_util_init(); - lib_use_idle = 1; -#endif /* USE_LOOPER */ - - if (local_cpu_rate > 0) { - /* The user think that he knows what the cpu rate is. We assume */ - /* that all the processors of an MP system are essentially the */ - /* same - for this reason we do not have a per processor maxrate. */ - /* if the machine has processors which are different in */ - /* performance, the CPU utilization will be skewed. raj 4/95 */ - lib_local_maxrate = local_cpu_rate; - } - else { - /* if neither USE_LOOPER nor USE_PSTAT are defined, we return a */ - /* 0.0 to indicate that times or getrusage should be used. raj */ - /* 4/95 */ - lib_local_maxrate = (float)0.0; -#if defined(USE_PROC_STAT) || defined(USE_LOOPER) || defined(USE_PSTAT) || defined(USE_KSTAT) || defined(USE_PERFSTAT) || defined(USE_SYSCTL) - lib_local_maxrate = calibrate_idle_rate(4,10); -#endif - } - return lib_local_maxrate; -} - - -float -calibrate_remote_cpu() -{ - float remrate; - - netperf_request.content.request_type = CPU_CALIBRATE; - send_request(); - /* we know that calibration will last at least 40 seconds, so go to */ - /* sleep for that long so the 60 second select in recv_response will */ - /* not pop. raj 7/95 */ - - /* we know that CPU calibration may last as long as 40 seconds, so - make sure we "select" for at least that long while looking for - the response. raj 2005-05-16 */ - recv_response_timed(40); - - if (netperf_response.content.serv_errno) { - /* initially, silently ignore remote errors and pass */ - /* back a zero to the caller this should allow us to */ - /* mix rev 1.0 and rev 1.1 netperfs... */ - return((float)0.0); - } - else { - /* the rate is the first word of the test_specific data */ - bcopy((char *)netperf_response.content.test_specific_data, - (char *)&remrate, - sizeof(remrate)); - bcopy((char *)netperf_response.content.test_specific_data + sizeof(remrate), - (char *)&lib_num_rem_cpus, - sizeof(lib_num_rem_cpus)); -/* remrate = (float) netperf_response.content.test_specific_data[0]; */ - return(remrate); - } -} - -#ifndef WIN32 -/* WIN32 requires that at least one of the file sets to select be non-null. */ -/* Since msec_sleep routine is only called by nettest_dlpi & nettest_unix, */ -/* let's duck this issue. */ - -int -msec_sleep( int msecs ) -{ - int rval ; - - struct timeval timeout; - - timeout.tv_sec = msecs / 1000; - timeout.tv_usec = (msecs - (msecs/1000) *1000) * 1000; - if ((rval = select(0, - 0, - 0, - 0, - &timeout))) { - if ( SOCKET_EINTR(rval) ) { - return(1); - } - perror("msec_sleep: select"); - exit(1); - } - return(0); -} -#endif /* WIN32 */ - -#ifdef WANT_HISTOGRAM -/* hist.c - - Given a time difference in microseconds, increment one of 61 - different buckets: - - 0 - 9 in increments of 1 usec - 0 - 9 in increments of 10 usecs - 0 - 9 in increments of 100 usecs - 1 - 9 in increments of 1 msec - 1 - 9 in increments of 10 msecs - 1 - 9 in increments of 100 msecs - 1 - 9 in increments of 1 sec - 1 - 9 in increments of 10 sec - > 100 secs - - This will allow any time to be recorded to within an accuracy of - 10%, and provides a compact representation for capturing the - distribution of a large number of time differences (e.g. - request-response latencies). - - Colin Low 10/6/93 - Rick Jones 2004-06-15 extend to unit and ten usecs -*/ - -/* #include "sys.h" */ - -/*#define HIST_TEST*/ - -HIST -HIST_new(void){ - HIST h; - if((h = (HIST) malloc(sizeof(struct histogram_struct))) == NULL) { - perror("HIST_new - malloc failed"); - exit(1); - } - HIST_clear(h); - return h; -} - -void -HIST_clear(HIST h){ - int i; - for(i = 0; i < 10; i++){ - h->unit_usec[i] = 0; - h->ten_usec[i] = 0; - h->hundred_usec[i] = 0; - h->unit_msec[i] = 0; - h->ten_msec[i] = 0; - h->hundred_msec[i] = 0; - h->unit_sec[i] = 0; - h->ten_sec[i] = 0; - } - h->ridiculous = 0; - h->total = 0; -} - -void -HIST_add(register HIST h, int time_delta){ - register int val; - h->total++; - val = time_delta; - if(val <= 9) h->unit_usec[val]++; - else { - val = val/10; - if(val <= 9) h->ten_usec[val]++; - else { - val = val/10; - if(val <= 9) h->hundred_usec[val]++; - else { - val = val/10; - if(val <= 9) h->unit_msec[val]++; - else { - val = val/10; - if(val <= 9) h->ten_msec[val]++; - else { - val = val/10; - if(val <= 9) h->hundred_msec[val]++; - else { - val = val/10; - if(val <= 9) h->unit_sec[val]++; - else { - val = val/10; - if(val <= 9) h->ten_sec[val]++; - else h->ridiculous++; - } - } - } - } - } - } - } -} - -#define RB_printf printf - -void -output_row(FILE *fd, char *title, int *row){ - register int i; - RB_printf("%s", title); - for(i = 0; i < 10; i++) RB_printf(": %4d", row[i]); - RB_printf("\n"); -} - -int -sum_row(int *row) { - int sum = 0; - int i; - for (i = 0; i < 10; i++) sum += row[i]; - return(sum); -} - -void -HIST_report(HIST h){ -#ifndef OLD_HISTOGRAM - output_row(stdout, "UNIT_USEC ", h->unit_usec); - output_row(stdout, "TEN_USEC ", h->ten_usec); - output_row(stdout, "HUNDRED_USEC ", h->hundred_usec); -#else - h->hundred_usec[0] += sum_row(h->unit_usec); - h->hundred_usec[0] += sum_row(h->ten_usec); - output_row(stdout, "TENTH_MSEC ", h->hundred_usec); -#endif - output_row(stdout, "UNIT_MSEC ", h->unit_msec); - output_row(stdout, "TEN_MSEC ", h->ten_msec); - output_row(stdout, "HUNDRED_MSEC ", h->hundred_msec); - output_row(stdout, "UNIT_SEC ", h->unit_sec); - output_row(stdout, "TEN_SEC ", h->ten_sec); - RB_printf(">100_SECS: %d\n", h->ridiculous); - RB_printf("HIST_TOTAL: %d\n", h->total); -} - -#endif - -/* with the advent of sit-and-spin intervals support, we might as well - make these things available all the time, not just for demo or - histogram modes. raj 2006-02-06 */ -#ifdef HAVE_GETHRTIME - -void -HIST_timestamp(hrtime_t *timestamp) -{ - *timestamp = gethrtime(); -} - -int -delta_micro(hrtime_t *begin, hrtime_t *end) -{ - long nsecs; - nsecs = (*end) - (*begin); - return(nsecs/1000); -} - -#elif defined(HAVE_GET_HRT) -#include "hrt.h" - -void -HIST_timestamp(hrt_t *timestamp) -{ - *timestamp = get_hrt(); -} - -int -delta_micro(hrt_t *begin, hrt_t *end) -{ - - return((int)get_hrt_delta(*end,*begin)); - -} -#elif defined(WIN32) -void HIST_timestamp(LARGE_INTEGER *timestamp) -{ - QueryPerformanceCounter(timestamp); -} - -int delta_micro(LARGE_INTEGER *begin, LARGE_INTEGER *end) -{ - LARGE_INTEGER DeltaTimestamp; - static LARGE_INTEGER TickHz = {0,0}; - - if (TickHz.QuadPart == 0) - { - QueryPerformanceFrequency(&TickHz); - } - - /*+*+ Rick; this will overflow after ~2000 seconds, is that - good enough? Spencer: Yes, that should be more than good - enough for histogram support */ - - DeltaTimestamp.QuadPart = (end->QuadPart - begin->QuadPart) * - 1000000/TickHz.QuadPart; - assert((DeltaTimestamp.HighPart == 0) && - ((int)DeltaTimestamp.LowPart >= 0)); - - return (int)DeltaTimestamp.LowPart; -} - -#else - -void -HIST_timestamp(struct timeval *timestamp) -{ - gettimeofday(timestamp,NULL); -} - - /* return the difference (in micro seconds) between two timeval */ - /* timestamps */ -int -delta_micro(struct timeval *begin,struct timeval *end) - -{ - - int usecs, secs; - - if (end->tv_usec < begin->tv_usec) { - /* borrow a second from the tv_sec */ - end->tv_usec += 1000000; - end->tv_sec--; - } - usecs = end->tv_usec - begin->tv_usec; - secs = end->tv_sec - begin->tv_sec; - - usecs += (secs * 1000000); - - return(usecs); - -} -#endif /* HAVE_GETHRTIME */ - - -#ifdef WANT_DLPI - -int -put_control(fd, len, pri, ack) - int fd, len, pri, ack; -{ - int error; - int flags = 0; - dl_error_ack_t *err_ack = (dl_error_ack_t *)control_data; - - control_message.len = len; - - if ((error = putmsg(fd, &control_message, 0, pri)) < 0 ) { - fprintf(where,"put_control: putmsg error %d\n",error); - fflush(where); - return(-1); - } - if ((error = getmsg(fd, &control_message, 0, &flags)) < 0) { - fprintf(where,"put_control: getsmg error %d\n",error); - fflush(where); - return(-1); - } - if (err_ack->dl_primitive != ack) { - fprintf(where,"put_control: acknowledgement error wanted %u got %u \n", - ack,err_ack->dl_primitive); - if (err_ack->dl_primitive == DL_ERROR_ACK) { - fprintf(where," dl_error_primitive: %u\n", - err_ack->dl_error_primitive); - fprintf(where," dl_errno: %u\n", - err_ack->dl_errno); - fprintf(where," dl_unix_errno %u\n", - err_ack->dl_unix_errno); - } - fflush(where); - return(-1); - } - - return(0); -} - -int -dl_open(char devfile[], int ppa) -{ - int fd; - dl_attach_req_t *attach_req = (dl_attach_req_t *)control_data; - - if ((fd = open(devfile, O_RDWR)) == -1) { - fprintf(where,"netperf: dl_open: open of %s failed, errno = %d\n", - devfile, - errno); - return(-1); - } - - attach_req->dl_primitive = DL_ATTACH_REQ; - attach_req->dl_ppa = ppa; - - if (put_control(fd, sizeof(dl_attach_req_t), 0, DL_OK_ACK) < 0) { - fprintf(where, - "netperf: dl_open: could not send control message, errno = %d\n", - errno); - return(-1); - } - return(fd); -} - -int -dl_bind(int fd, int sap, int mode, char *dlsap_ptr, int *dlsap_len) -{ - dl_bind_req_t *bind_req = (dl_bind_req_t *)control_data; - dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)control_data; - - bind_req->dl_primitive = DL_BIND_REQ; - bind_req->dl_sap = sap; - bind_req->dl_max_conind = 1; - bind_req->dl_service_mode = mode; - bind_req->dl_conn_mgmt = 0; - bind_req->dl_xidtest_flg = 0; - - if (put_control(fd, sizeof(dl_bind_req_t), 0, DL_BIND_ACK) < 0) { - fprintf(where, - "netperf: dl_bind: could not send control message, errno = %d\n", - errno); - return(-1); - } - - /* at this point, the control_data portion of the control message */ - /* structure should contain a DL_BIND_ACK, which will have a full */ - /* DLSAP in it. we want to extract this and pass it up so that */ - /* it can be passed around. */ - if (*dlsap_len >= bind_ack->dl_addr_length) { - bcopy((char *)bind_ack+bind_ack->dl_addr_offset, - dlsap_ptr, - bind_ack->dl_addr_length); - *dlsap_len = bind_ack->dl_addr_length; - return(0); - } - else { - return (-1); - } -} - -int -dl_connect(int fd, unsigned char *remote_addr, int remote_addr_len) -{ - dl_connect_req_t *connection_req = (dl_connect_req_t *)control_data; - dl_connect_con_t *connection_con = (dl_connect_con_t *)control_data; - struct pollfd pinfo; - - int flags = 0; - - /* this is here on the off chance that we really want some data */ - u_long data_area[512]; - struct strbuf data_message; - - int error; - - data_message.maxlen = 2048; - data_message.len = 0; - data_message.buf = (char *)data_area; - - connection_req->dl_primitive = DL_CONNECT_REQ; - connection_req->dl_dest_addr_length = remote_addr_len; - connection_req->dl_dest_addr_offset = sizeof(dl_connect_req_t); - connection_req->dl_qos_length = 0; - connection_req->dl_qos_offset = 0; - bcopy (remote_addr, - (unsigned char *)control_data + sizeof(dl_connect_req_t), - remote_addr_len); - - /* well, I would call the put_control routine here, but the sequence */ - /* of connection stuff with DLPI is a bit screwey with all this */ - /* message passing - Toto, I don't think were in Berkeley anymore. */ - - control_message.len = sizeof(dl_connect_req_t) + remote_addr_len; - if ((error = putmsg(fd,&control_message,0,0)) !=0) { - fprintf(where,"dl_connect: putmsg failure, errno = %d, error 0x%x \n", - errno,error); - fflush(where); - return(-1); - }; - - pinfo.fd = fd; - pinfo.events = POLLIN | POLLPRI; - pinfo.revents = 0; - - if ((error = getmsg(fd,&control_message,&data_message,&flags)) != 0) { - fprintf(where,"dl_connect: getmsg failure, errno = %d, error 0x%x \n", - errno,error); - fflush(where); - return(-1); - } - while (control_data[0] == DL_TEST_CON) { - /* i suppose we spin until we get an error, or a connection */ - /* indication */ - if((error = getmsg(fd,&control_message,&data_message,&flags)) !=0) { - fprintf(where,"dl_connect: getmsg failure, errno = %d, error = 0x%x\n", - errno,error); - fflush(where); - return(-1); - } - } - - /* we are out - it either worked or it didn't - which was it? */ - if (control_data[0] == DL_CONNECT_CON) { - return(0); - } - else { - return(-1); - } -} - -int -dl_accept(fd, remote_addr, remote_addr_len) - int fd; - unsigned char *remote_addr; - int remote_addr_len; -{ - dl_connect_ind_t *connect_ind = (dl_connect_ind_t *)control_data; - dl_connect_res_t *connect_res = (dl_connect_res_t *)control_data; - int tmp_cor; - int flags = 0; - - /* hang around and wait for a connection request */ - getmsg(fd,&control_message,0,&flags); - while (control_data[0] != DL_CONNECT_IND) { - getmsg(fd,&control_message,0,&flags); - } - - /* now respond to the request. at some point, we may want to be sure */ - /* that the connection came from the correct station address, but */ - /* will assume that we do not have to worry about it just now. */ - - tmp_cor = connect_ind->dl_correlation; - - connect_res->dl_primitive = DL_CONNECT_RES; - connect_res->dl_correlation = tmp_cor; - connect_res->dl_resp_token = 0; - connect_res->dl_qos_length = 0; - connect_res->dl_qos_offset = 0; - connect_res->dl_growth = 0; - - return(put_control(fd, sizeof(dl_connect_res_t), 0, DL_OK_ACK)); - -} - -int -dl_set_window(fd, window) - int fd, window; -{ - return(0); -} - -void -dl_stats(fd) - int fd; -{ -} - -int -dl_send_disc(fd) - int fd; -{ -} - -int -dl_recv_disc(fd) - int fd; -{ -} -#endif /* WANT_DLPI*/ - - /* these routines for confidence intervals are courtesy of IBM. They */ - /* have been modified slightly for more general usage beyond TCP/UDP */ - /* tests. raj 11/94 I would suspect that this code carries an IBM */ - /* copyright that is much the same as that for the original HP */ - /* netperf code */ -int confidence_iterations; /* for iterations */ - -double - result_confid=-10.0, - loc_cpu_confid=-10.0, - rem_cpu_confid=-10.0, - - measured_sum_result=0.0, - measured_square_sum_result=0.0, - measured_mean_result=0.0, - measured_var_result=0.0, - - measured_sum_local_cpu=0.0, - measured_square_sum_local_cpu=0.0, - measured_mean_local_cpu=0.0, - measured_var_local_cpu=0.0, - - measured_sum_remote_cpu=0.0, - measured_square_sum_remote_cpu=0.0, - measured_mean_remote_cpu=0.0, - measured_var_remote_cpu=0.0, - - measured_sum_local_service_demand=0.0, - measured_square_sum_local_service_demand=0.0, - measured_mean_local_service_demand=0.0, - measured_var_local_service_demand=0.0, - - measured_sum_remote_service_demand=0.0, - measured_square_sum_remote_service_demand=0.0, - measured_mean_remote_service_demand=0.0, - measured_var_remote_service_demand=0.0, - - measured_sum_local_time=0.0, - measured_square_sum_local_time=0.0, - measured_mean_local_time=0.0, - measured_var_local_time=0.0, - - measured_mean_remote_time=0.0, - - measured_fails, - measured_local_results, - confidence=-10.0; -/* interval=0.1; */ - -/************************************************************************/ -/* */ -/* Constants for Confidence Intervals */ -/* */ -/************************************************************************/ -void -init_stat() -{ - measured_sum_result=0.0; - measured_square_sum_result=0.0; - measured_mean_result=0.0; - measured_var_result=0.0; - - measured_sum_local_cpu=0.0; - measured_square_sum_local_cpu=0.0; - measured_mean_local_cpu=0.0; - measured_var_local_cpu=0.0; - - measured_sum_remote_cpu=0.0; - measured_square_sum_remote_cpu=0.0; - measured_mean_remote_cpu=0.0; - measured_var_remote_cpu=0.0; - - measured_sum_local_service_demand=0.0; - measured_square_sum_local_service_demand=0.0; - measured_mean_local_service_demand=0.0; - measured_var_local_service_demand=0.0; - - measured_sum_remote_service_demand=0.0; - measured_square_sum_remote_service_demand=0.0; - measured_mean_remote_service_demand=0.0; - measured_var_remote_service_demand=0.0; - - measured_sum_local_time=0.0; - measured_square_sum_local_time=0.0; - measured_mean_local_time=0.0; - measured_var_local_time=0.0; - - measured_mean_remote_time=0.0; - - measured_fails = 0.0; - measured_local_results=0.0, - confidence=-10.0; -} - - /* this routine does a simple table lookup for some statistical */ - /* function that I would remember if I stayed awake in my probstats */ - /* class... raj 11/94 */ -double -confid(int level, int freedom) -{ -double t99[35],t95[35]; - - t95[1]=12.706; - t95[2]= 4.303; - t95[3]= 3.182; - t95[4]= 2.776; - t95[5]= 2.571; - t95[6]= 2.447; - t95[7]= 2.365; - t95[8]= 2.306; - t95[9]= 2.262; - t95[10]= 2.228; - t95[11]= 2.201; - t95[12]= 2.179; - t95[13]= 2.160; - t95[14]= 2.145; - t95[15]= 2.131; - t95[16]= 2.120; - t95[17]= 2.110; - t95[18]= 2.101; - t95[19]= 2.093; - t95[20]= 2.086; - t95[21]= 2.080; - t95[22]= 2.074; - t95[23]= 2.069; - t95[24]= 2.064; - t95[25]= 2.060; - t95[26]= 2.056; - t95[27]= 2.052; - t95[28]= 2.048; - t95[29]= 2.045; - t95[30]= 2.042; - - t99[1]=63.657; - t99[2]= 9.925; - t99[3]= 5.841; - t99[4]= 4.604; - t99[5]= 4.032; - t99[6]= 3.707; - t99[7]= 3.499; - t99[8]= 3.355; - t99[9]= 3.250; - t99[10]= 3.169; - t99[11]= 3.106; - t99[12]= 3.055; - t99[13]= 3.012; - t99[14]= 2.977; - t99[15]= 2.947; - t99[16]= 2.921; - t99[17]= 2.898; - t99[18]= 2.878; - t99[19]= 2.861; - t99[20]= 2.845; - t99[21]= 2.831; - t99[22]= 2.819; - t99[23]= 2.807; - t99[24]= 2.797; - t99[25]= 2.787; - t99[26]= 2.779; - t99[27]= 2.771; - t99[28]= 2.763; - t99[29]= 2.756; - t99[30]= 2.750; - - if(level==95){ - return(t95[freedom]); - } else if(level==99){ - return(t99[freedom]); - } else{ - return(0); - } -} - -void -calculate_confidence(int confidence_iterations, - float time, - double result, - float loc_cpu, - float rem_cpu, - float loc_sd, - float rem_sd) -{ - - if (debug) { - fprintf(where, - "calculate_confidence: itr %d; time %f; res %f\n", - confidence_iterations, - time, - result); - fprintf(where, - " lcpu %f; rcpu %f\n", - loc_cpu, - rem_cpu); - fprintf(where, - " lsdm %f; rsdm %f\n", - loc_sd, - rem_sd); - fflush(where); - } - - /* the test time */ - measured_sum_local_time += - (double) time; - measured_square_sum_local_time += - (double) time*time; - measured_mean_local_time = - (double) measured_sum_local_time/confidence_iterations; - measured_var_local_time = - (double) measured_square_sum_local_time/confidence_iterations - -measured_mean_local_time*measured_mean_local_time; - - /* the test result */ - measured_sum_result += - (double) result; - measured_square_sum_result += - (double) result*result; - measured_mean_result = - (double) measured_sum_result/confidence_iterations; - measured_var_result = - (double) measured_square_sum_result/confidence_iterations - -measured_mean_result*measured_mean_result; - - /* local cpu utilization */ - measured_sum_local_cpu += - (double) loc_cpu; - measured_square_sum_local_cpu += - (double) loc_cpu*loc_cpu; - measured_mean_local_cpu = - (double) measured_sum_local_cpu/confidence_iterations; - measured_var_local_cpu = - (double) measured_square_sum_local_cpu/confidence_iterations - -measured_mean_local_cpu*measured_mean_local_cpu; - - /* remote cpu util */ - measured_sum_remote_cpu += - (double) rem_cpu; - measured_square_sum_remote_cpu+= - (double) rem_cpu*rem_cpu; - measured_mean_remote_cpu = - (double) measured_sum_remote_cpu/confidence_iterations; - measured_var_remote_cpu = - (double) measured_square_sum_remote_cpu/confidence_iterations - -measured_mean_remote_cpu*measured_mean_remote_cpu; - - /* local service demand */ - measured_sum_local_service_demand += - (double) loc_sd; - measured_square_sum_local_service_demand+= - (double) loc_sd*loc_sd; - measured_mean_local_service_demand = - (double) measured_sum_local_service_demand/confidence_iterations; - measured_var_local_service_demand = - (double) measured_square_sum_local_service_demand/confidence_iterations - -measured_mean_local_service_demand*measured_mean_local_service_demand; - - /* remote service demand */ - measured_sum_remote_service_demand += - (double) rem_sd; - measured_square_sum_remote_service_demand+= - (double) rem_sd*rem_sd; - measured_mean_remote_service_demand = - (double) measured_sum_remote_service_demand/confidence_iterations; - measured_var_remote_service_demand = - (double) measured_square_sum_remote_service_demand/confidence_iterations - -measured_mean_remote_service_demand*measured_mean_remote_service_demand; - - if(confidence_iterations>1){ - result_confid= (double) interval - - 2.0 * confid(confidence_level,confidence_iterations-1)* - sqrt(measured_var_result/(confidence_iterations-1.0)) / - measured_mean_result; - - loc_cpu_confid= (double) interval - - 2.0 * confid(confidence_level,confidence_iterations-1)* - sqrt(measured_var_local_cpu/(confidence_iterations-1.0)) / - measured_mean_local_cpu; - - rem_cpu_confid= (double) interval - - 2.0 * confid(confidence_level,confidence_iterations-1)* - sqrt(measured_var_remote_cpu/(confidence_iterations-1.0)) / - measured_mean_remote_cpu; - - if(debug){ - printf("Conf_itvl %2d: results:%4.1f%% loc_cpu:%4.1f%% rem_cpu:%4.1f%%\n", - confidence_iterations, - (interval-result_confid)*100.0, - (interval-loc_cpu_confid)*100.0, - (interval-rem_cpu_confid)*100.0); - } - - /* if the user has requested that we only wait for the result to - be confident rather than the result and CPU util(s) then do - so. raj 2007-08-08 */ - if (!result_confidence_only) { - confidence = min(min(result_confid,loc_cpu_confid),rem_cpu_confid); - } - else { - confidence = result_confid; - } - } -} - - /* here ends the IBM code */ - -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) - -{ - *elapsed_time = (float)measured_mean_local_time; - *thruput = measured_mean_result; - *local_cpu_utilization = (float)measured_mean_local_cpu; - *remote_cpu_utilization = (float)measured_mean_remote_cpu; - *local_service_demand = (float)measured_mean_local_service_demand; - *remote_service_demand = (float)measured_mean_remote_service_demand; -} - - /* display_confidence() is called when we could not achieve the */ - /* desirec confidence in the results. it will print the achieved */ - /* confidence to "where" raj 11/94 */ -void -display_confidence() - -{ - fprintf(where, - "!!! WARNING\n"); - fprintf(where, - "!!! Desired confidence was not achieved within "); - fprintf(where, - "the specified iterations.\n"); - fprintf(where, - "!!! This implies that there was variability in "); - fprintf(where, - "the test environment that\n"); - fprintf(where, - "!!! must be investigated before going further.\n"); - fprintf(where, - "!!! Confidence intervals: Throughput : %4.1f%%\n", - 100.0 * (interval - result_confid)); - fprintf(where, - "!!! Local CPU util : %4.1f%%\n", - 100.0 * (interval - loc_cpu_confid)); - fprintf(where, - "!!! Remote CPU util : %4.1f%%\n\n", - 100.0 * (interval - rem_cpu_confid)); -} - diff --git a/netlib.h b/netlib.h deleted file mode 100644 index 5b6900e..0000000 --- a/netlib.h +++ /dev/null @@ -1,621 +0,0 @@ -/* - Copyright (C) 1993-2005 Hewlett-Packard Company -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#if defined(HAVE_SYS_SOCKET_H) -# include <sys/socket.h> -#endif -#if defined(HAVE_NETDB_H) -# include <netdb.h> -#endif -#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO) -# include "missing/getaddrinfo.h" -#endif - -#define PAD_TIME 4 -/* library routine specifc defines */ -#define MAXSPECDATA 62 /* how many ints worth of data */ - /* can tests send... */ -#define MAXTIMES 4 /* how many times may we loop */ - /* to calibrate */ -#define MAXCPUS 256 /* how many CPU's can we track */ -#define MAXMESSAGESIZE 65536 -#define MAXALIGNMENT 16384 -#define MAXOFFSET 4096 -#define DATABUFFERLEN MAXMESSAGESIZE+MAXALIGNMENT+MAXOFFSET - -#define DEBUG_ON 1 -#define DEBUG_OFF 2 -#define DEBUG_OK 3 -#define NODE_IDENTIFY 4 -#define CPU_CALIBRATE 5 - -#define DO_TCP_STREAM 10 -#define TCP_STREAM_RESPONSE 11 -#define TCP_STREAM_RESULTS 12 - -#define DO_TCP_RR 13 -#define TCP_RR_RESPONSE 14 -#define TCP_RR_RESULTS 15 - -#define DO_UDP_STREAM 16 -#define UDP_STREAM_RESPONSE 17 -#define UDP_STREAM_RESULTS 18 - -#define DO_UDP_RR 19 -#define UDP_RR_RESPONSE 20 -#define UDP_RR_RESULTS 21 - -#define DO_DLPI_CO_STREAM 22 -#define DLPI_CO_STREAM_RESPONSE 23 -#define DLPI_CO_STREAM_RESULTS 24 - -#define DO_DLPI_CO_RR 25 -#define DLPI_CO_RR_RESPONSE 26 -#define DLPI_CO_RR_RESULTS 27 - -#define DO_DLPI_CL_STREAM 28 -#define DLPI_CL_STREAM_RESPONSE 29 -#define DLPI_CL_STREAM_RESULTS 30 - -#define DO_DLPI_CL_RR 31 -#define DLPI_CL_RR_RESPONSE 32 -#define DLPI_CL_RR_RESULTS 33 - -#define DO_TCP_CRR 34 -#define TCP_CRR_RESPONSE 35 -#define TCP_CRR_RESULTS 36 - -#define DO_STREAM_STREAM 37 -#define STREAM_STREAM_RESPONSE 38 -#define STREAM_STREAM_RESULTS 39 - -#define DO_STREAM_RR 40 -#define STREAM_RR_RESPONSE 41 -#define STREAM_RR_RESULTS 42 - -#define DO_DG_STREAM 43 -#define DG_STREAM_RESPONSE 44 -#define DG_STREAM_RESULTS 45 - -#define DO_DG_RR 46 -#define DG_RR_RESPONSE 47 -#define DG_RR_RESULTS 48 - -#define DO_FORE_STREAM 49 -#define FORE_STREAM_RESPONSE 50 -#define FORE_STREAM_RESULTS 51 - -#define DO_FORE_RR 52 -#define FORE_RR_RESPONSE 53 -#define FORE_RR_RESULTS 54 - -#define DO_HIPPI_STREAM 55 -#define HIPPI_STREAM_RESPONSE 56 -#define HIPPI_STREAM_RESULTS 57 - -#define DO_HIPPI_RR 52 -#define HIPPI_RR_RESPONSE 53 -#define HIPPI_RR_RESULTS 54 - -#define DO_XTI_TCP_STREAM 55 -#define XTI_TCP_STREAM_RESPONSE 56 -#define XTI_TCP_STREAM_RESULTS 57 - -#define DO_XTI_TCP_RR 58 -#define XTI_TCP_RR_RESPONSE 59 -#define XTI_TCP_RR_RESULTS 60 - -#define DO_XTI_UDP_STREAM 61 -#define XTI_UDP_STREAM_RESPONSE 62 -#define XTI_UDP_STREAM_RESULTS 63 - -#define DO_XTI_UDP_RR 64 -#define XTI_UDP_RR_RESPONSE 65 -#define XTI_UDP_RR_RESULTS 66 - -#define DO_XTI_TCP_CRR 67 -#define XTI_TCP_CRR_RESPONSE 68 -#define XTI_TCP_CRR_RESULTS 69 - -#define DO_TCP_TRR 70 -#define TCP_TRR_RESPONSE 71 -#define TCP_TRR_RESULTS 72 - -#define DO_TCP_NBRR 73 -#define TCP_NBRR_RESPONSE 74 -#define TCP_NBRR_RESULTS 75 - -#define DO_TCPIPV6_STREAM 76 -#define TCPIPV6_STREAM_RESPONSE 77 -#define TCPIPV6_STREAM_RESULTS 78 - -#define DO_TCPIPV6_RR 79 -#define TCPIPV6_RR_RESPONSE 80 -#define TCPIPV6_RR_RESULTS 81 - -#define DO_UDPIPV6_STREAM 82 -#define UDPIPV6_STREAM_RESPONSE 83 -#define UDPIPV6_STREAM_RESULTS 84 - -#define DO_UDPIPV6_RR 85 -#define UDPIPV6_RR_RESPONSE 86 -#define UDPIPV6_RR_RESULTS 87 - -#define DO_TCPIPV6_CRR 88 -#define TCPIPV6_CRR_RESPONSE 89 -#define TCPIPV6_CRR_RESULTS 90 - -#define DO_TCPIPV6_TRR 91 -#define TCPIPV6_TRR_RESPONSE 92 -#define TCPIPV6_TRR_RESULTS 93 - -#define DO_TCP_MAERTS 94 -#define TCP_MAERTS_RESPONSE 95 -#define TCP_MAERTS_RESULTS 96 - -#define DO_LWPSTR_STREAM 100 -#define LWPSTR_STREAM_RESPONSE 110 -#define LWPSTR_STREAM_RESULTS 120 - -#define DO_LWPSTR_RR 130 -#define LWPSTR_RR_RESPONSE 140 -#define LWPSTR_RR_RESULTS 150 - -#define DO_LWPDG_STREAM 160 -#define LWPDG_STREAM_RESPONSE 170 -#define LWPDG_STREAM_RESULTS 180 - -#define DO_LWPDG_RR 190 -#define LWPDG_RR_RESPONSE 200 -#define LWPDG_RR_RESULTS 210 - -#define DO_TCP_CC 300 -#define TCP_CC_RESPONSE 301 -#define TCP_CC_RESULTS 302 - -/* The DNS_RR test has been removed from netperf but we leave these - here for historical purposes. Those wanting to do DNS_RR tests - should use netperf4 instead. */ -#define DO_DNS_RR 400 -#define DNS_RR_RESPONSE 401 -#define DNS_RR_RESULTS 402 - -#define DO_SCTP_STREAM 500 -#define SCTP_STREAM_RESPONSE 501 -#define SCTP_STREAM_RESULT 502 - -#define DO_SCTP_STREAM_MANY 510 -#define SCTP_STREAM_MANY_RESPONSE 511 -#define SCTP_STREAM_MANY_RESULT 512 - -#define DO_SCTP_RR 520 -#define SCTP_RR_RESPONSE 521 -#define SCTP_RR_RESULT 502 - -#define DO_SCTP_RR_MANY 530 -#define SCTP_RR_MANY_RESPONSE 531 -#define SCTP_RR_MANY_RESULT 532 - -#define DO_SDP_STREAM 540 -#define SDP_STREAM_RESPONSE 541 -#define SDP_STREAM_RESULTS 542 - -#define DO_SDP_RR 543 -#define SDP_RR_RESPONSE 544 -#define SDP_RR_RESULTS 545 - -#define DO_SDP_MAERTS 546 -#define SDP_MAERTS_RESPONSE 547 -#define SDP_MAERTS_RESULTS 548 - -#define DO_SDP_CRR 549 -#define SDP_CRR_RESPONSE 550 -#define SDP_CRR_RESULTS 551 - -#define DO_SDP_CC 552 -#define SDP_CC_RESPONSE 553 -#define SDP_CC_RESULTS 554 - -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif - -enum sock_buffer{ - SEND_BUFFER, - RECV_BUFFER -}; - - /* some of the fields in these structures are going to be doubles and */ - /* such. so, we probably want to ensure that they will start on */ - /* "double" boundaries. this will break compatability to pre-2.1 */ - /* releases, but then, backwards compatability has never been a */ - /* stated goal of netperf. raj 11/95 */ - -union netperf_request_struct { - struct { - int request_type; - int dummy; - int test_specific_data[MAXSPECDATA]; - } content; - double dummy; -}; - -union netperf_response_struct { - struct { - int response_type; - int serv_errno; - int test_specific_data[MAXSPECDATA]; - } content; - double dummy; -}; - -struct ring_elt { - struct ring_elt *next; /* next element in the ring */ - char *buffer_base; /* in case we have to free it at somepoint */ - char *buffer_ptr; /* the aligned and offset pointer */ -}; - -/* +*+ SAF Sorry about the hacks with errno; NT made me do it :( - - WinNT does define an errno. - It is mostly a legacy from the XENIX days. - - Depending upon the version of the C run time that is linked in, it is - either a simple variable (like UNIX code expects), but more likely it - is the address of a procedure to return the error number. So any - code that sets errno is likely to be overwriting the address of this - procedure. Worse, only a tiny fraction of NT's errors get set - through errno. - - So I have changed the netperf code to use a define Set_errno when - that is it's intent. On non-windows platforms this is just an - assignment to errno. But on NT this calls SetLastError. - - I also define errno (now only used on right side of assignments) - on NT to be GetLastError. - - Similarly, perror is defined on NT, but it only accesses the same - XENIX errors that errno covers. So on NT this is redefined to be - Perror and it expands all GetLastError texts. */ - - -#ifdef WIN32 -/* INVALID_SOCKET == INVALID_HANDLE_VALUE == (unsigned int)(~0) */ -/* SOCKET_ERROR == -1 */ -#define ENOTSOCK WSAENOTSOCK -#define EINTR WSAEINTR -#define ENOBUFS WSAENOBUFS -#define EWOULDBLOCK WSAEWOULDBLOCK -#define EAFNOSUPPORT WSAEAFNOSUPPORT -/* I don't use a C++ style of comment because it upsets some C - compilers, possibly even when it is inside an ifdef WIN32... */ -/* from public\sdk\inc\crt\errno.h */ -#define ENOSPC 28 - -#ifdef errno -/* delete the one from stdlib.h */ -/*#define errno (*_errno()) */ -#undef errno -#endif -#define errno GetLastError() -#define Set_errno(num) SetLastError((num)) - -#define perror(text) PrintWin32Error(stderr, (text)) -#define Print_errno(stream, text) PrintWin32Error((stream), (text)) - -extern void PrintWin32Error(FILE *stream, LPSTR text); - -#if !defined(NT_PERF) && !defined(USE_LOOPER) -#define NT_PERF -#endif -#else -/* Really shouldn't use manifest constants! */ -/*+*+SAF There are other examples of "== -1" and "<0" that probably */ -/*+*+SAF should be cleaned up as well. */ -#define INVALID_SOCKET -1 -#define SOCKET_ERROR -1 - -#define SOCKET int -#define Set_errno(num) errno = (num) - -#define Print_errno(stream, text) fprintf((stream), "%s errno %d\n", (text), errno) -#endif - -/* Robin & Rick's kludge to try to have a timer signal EINTR by closing */ -/* the socket from another thread can also return several other errors. */ -/* Let's define a macro to hide all of this. */ - -#ifndef WIN32 -#define SOCKET_EINTR(return_value) (errno == EINTR) -#define SOCKET_EADDRINUSE(return_value) (errno == EADDRINUSE) -#define SOCKET_EADDRNOTAVAIL(return_value) (errno == EADDRNOTAVAIL) - -#else - -/* not quite sure I like the extra cases for WIN32 but that is what my - WIN32 expert sugested. I'm not sure what WSA's to put for - EADDRINUSE */ - -#define SOCKET_EINTR(return_value) \ - (((return_value) == SOCKET_ERROR) && \ - ((errno == EINTR) || \ - (errno == WSAECONNABORTED) || \ - (errno == WSAECONNRESET) )) -#define SOCKET_EADDRINUSE(return_value) \ - (((return_value) == SOCKET_ERROR) && \ - ((errno == WSAEADDRINUSE) )) -#define SOCKET_EADDRNOTAVAIL(return_value) \ - (((return_value) == SOCKET_ERROR) && \ - ((errno == WSAEADDRNOTAVAIL) )) -#endif - -#ifdef HAVE_SENDFILE - -struct sendfile_ring_elt { - struct sendfile_ring_elt *next; /* next element in the ring */ - int fildes; /* the file descriptor of the source - file */ - off_t offset; /* the offset from the beginning of - the file for this send */ - size_t length; /* the number of bytes to send - - this is redundant with the - send_size variable but I decided - to include it anyway */ - struct iovec *hdtrl; /* a pointer to a header/trailer - that we do not initially use and - so should be set to NULL when the - ring is setup. */ - int flags; /* the flags to pass to sendfile() - - presently unused and should be - set to zero when the ring is - setup. */ -}; - -#endif /* HAVE_SENDFILE */ - - /* the diferent codes to denote the type of CPU utilization */ - /* methods used */ -#define CPU_UNKNOWN 0 -#define HP_IDLE_COUNTER 1 -#define PSTAT 2 -#define TIMES 3 -#define LOOPER 4 -#define GETRUSAGE 5 -#define NT_METHOD 6 -#define KSTAT 7 -#define PROC_STAT 8 -#define SYSCTL 9 -#define PERFSTAT 10 -#define KSTAT_10 11 -#define OSX 12 - -#define BADCH ('?') - -#ifndef NETLIB -#ifdef WIN32 -#ifndef _GETOPT_ -#define _GETOPT_ - -int getopt(int argc, char **argv, char *optstring); - -extern char *optarg; /* returned arg to go with this option */ -extern int optind; /* index to next argv element to process */ -extern int opterr; /* should error messages be printed? */ -extern int optopt; /* */ - -#endif /* _GETOPT_ */ - -extern SOCKET win_kludge_socket, win_kludge_socket2; -#endif /* WIN32 */ - -extern int local_proc_affinity, remote_proc_affinity; - -/* these are to allow netperf to be run easily through those evil, - end-to-end breaking things known as firewalls */ -extern char local_data_port[10]; -extern char remote_data_port[10]; - -extern char *local_data_address; -extern char *remote_data_address; - -extern int local_data_family; -extern int remote_data_family; - -extern union netperf_request_struct netperf_request; -extern union netperf_response_struct netperf_response; - -extern float lib_local_cpu_util; -extern float lib_elapsed; -extern float lib_local_maxrate; - -extern char libfmt; - -extern int cpu_method; -extern int lib_num_loc_cpus; -extern int lib_num_rem_cpus; -extern SOCKET server_sock; -extern int times_up; -extern FILE *where; -extern int loops_per_msec; -extern float lib_local_per_cpu_util[]; - -extern void netlib_init(); -extern int netlib_get_page_size(); -extern void install_signal_catchers(); -extern void establish_control(char hostname[], - char port[], - int af, - char local_hostname[], - char local_port[], - int local_af); -extern void shutdown_control(); -extern void init_stat(); -extern void send_request(); -extern void recv_response(); -extern void send_response(); -extern void recv_request(); -extern void dump_request(); -extern void dump_addrinfo(FILE *dumploc, struct addrinfo *info, - char *host, char *port, int family); -extern void start_timer(int time); -extern void stop_timer(); -extern void cpu_start(int measure_cpu); -extern void cpu_stop(int measure_cpu, float *elapsed); -extern void calculate_confidence(int confidence_iterations, - float time, - double result, - float loc_cpu, - float rem_cpu, - float loc_sd, - float rem_sd); -extern 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); -extern void display_confidence(); -extern void set_sock_buffer(SOCKET sd, - enum sock_buffer which, - int requested_size, - int *effective_sizep); -extern char *format_units(); - -extern char *inet_ftos(int family); -extern char *inet_ttos(int type); -extern char *inet_ptos(int protocol); -extern double ntohd(double net_double); -extern double htond(double host_double); -extern int inet_nton(int af, const void *src, char *dst, int cnt); -extern void libmain(); -extern double calc_thruput(double units_received); -extern double calc_thruput_interval(double units_received,double elapsed); -extern double calc_thruput_omni(double units_received); -extern double calc_thruput_interval_omni(double units_received,double elapsed); -extern float calibrate_local_cpu(float local_cpu_rate); -extern float calibrate_remote_cpu(); -extern void bind_to_specific_processor(int processor_affinity,int use_cpu_map); -extern int set_nonblock (SOCKET sock); - -#ifndef WIN32 - -/* WIN32 requires that at least one of the file sets to select be - non-null. Since msec_sleep routine is only called by nettest_dlpi & - nettest_unix, let's duck this issue. */ - -extern int msec_sleep( int msecs ); -#endif /* WIN32 */ -extern float calc_cpu_util(float elapsed_time); -extern float calc_service_demand(double units_sent, - float elapsed_time, - float cpu_utilization, - int num_cpus); -extern float calc_service_demand_trans(double units_sent, - float elapsed_time, - float cpu_utilization, - int num_cpus); -#if defined(__hpux) -extern void catcher(int, siginfo_t *,void *); -#else -extern void catcher(int); -#endif /* __hpux */ -extern struct ring_elt *allocate_buffer_ring(); -extern void access_buffer(char *buffer_ptr, - int length, - int dirty_count, - int clean_count); - -#ifdef HAVE_ICSC_EXS -extern struct ring_elt *allocate_exs_buffer_ring(); -#endif /* HAVE_ICSC_EXS */ -#ifdef HAVE_SENDFILE -extern struct sendfile_ring_elt *alloc_sendfile_buf_ring(); -#endif /* HAVE_SENDFILE */ -#ifdef WANT_DLPI -/* it seems that AIX in its finite wisdom has some bogus define in an - include file which defines "rem_addr" which then screws-up this extern - unless we change the names to protect the guilty. reported by Eric - Jones */ -extern int dl_connect(int fd, unsigned char *remote_addr, int remote_addr_len); -extern int dl_bind(int fd, int sap, int mode, char *dlsap_ptr, int *dlsap_len); -extern int dl_open(char devfile[], int ppa); -#endif /* WANT_DLPI */ -extern char format_cpu_method(int method); -extern unsigned int convert(char *string); -extern unsigned int convert_timespec(char *string); - -#ifdef WANT_INTERVALS -extern void start_itimer(unsigned int interval_len_msec); -#endif - /* these are all for the confidence interval stuff */ -extern double confidence; - -#endif - -#ifdef WIN32 -#define close(x) closesocket(x) -#define strcasecmp(a,b) _stricmp(a,b) -#define getpid() ((int)GetCurrentProcessId()) -#endif - -#ifdef WIN32 -#if 0 -/* Should really use safe string functions; but not for now... */ -#include <strsafe.h> -/* Microsoft has deprecated _snprintf; it isn't guarenteed to null terminate the result buffer. */ -/* They want us to call StringCbPrintf instead; it always null terminates the string. */ -#endif - -#define snprintf _snprintf -#endif - -/* Define a macro to align a buffer with an offset from a power of 2 - boundary. */ - -#ifndef WIN32 -#define ULONG_PTR unsigned long -#endif - -#define ALIGN_BUFFER(BufPtr, Align, Offset) \ - (char *)(( (ULONG_PTR)(BufPtr) + \ - (ULONG_PTR) (Align) -1) & \ - ~((ULONG_PTR) (Align) - 1)) + (ULONG_PTR)(Offset) - - /* if your system has bcopy and bzero, include it here, otherwise, we */ - /* will try to use memcpy aand memset. fix from Bruce Barnett @ GE. */ -#if defined(hpux) || defined (__VMS) -#define HAVE_BCOPY -#define HAVE_BZERO -#endif - -#ifdef WIN32 -#define HAVE_MIN -#else -#define _stdcall -#define _cdecl -#endif - -#ifndef HAVE_BCOPY -#define bcopy(s,d,h) memcpy((d),(s),(h)) -#endif /* HAVE_BCOPY */ - -#ifndef HAVE_BZERO -#define bzero(p,h) memset((p),0,(h)) -#endif /* HAVE_BZERO */ - -#ifndef HAVE_MIN -#define min(a,b) ((a < b) ? a : b) -#endif /* HAVE_MIN */ - -#ifdef USE_PERFSTAT -# include <libperfstat.h> -#endif diff --git a/netperf.c b/netperf.c deleted file mode 100644 index 84717ac..0000000 --- a/netperf.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - - Copyright (C) 1993-2007 Hewlett-Packard Company - ALL RIGHTS RESERVED. - - The enclosed software and documentation includes copyrighted works - of Hewlett-Packard Co. For as long as you comply with the following - limitations, you are hereby authorized to (i) use, reproduce, and - modify the software and documentation, and to (ii) distribute the - software and documentation, including modifications, for - non-commercial purposes only. - - 1. The enclosed software and documentation is made available at no - charge in order to advance the general development of - high-performance networking products. - - 2. You may not delete any copyright notices contained in the - software or documentation. All hard copies, and copies in - source code or object code form, of the software or - documentation (including modifications) must contain at least - one of the copyright notices. - - 3. The enclosed software and documentation has not been subjected - to testing and quality control and is not a Hewlett-Packard Co. - product. At a future time, Hewlett-Packard Co. may or may not - offer a version of the software and documentation as a product. - - 4. THE SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS". - HEWLETT-PACKARD COMPANY DOES NOT WARRANT THAT THE USE, - REPRODUCTION, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR - DOCUMENTATION WILL NOT INFRINGE A THIRD PARTY'S INTELLECTUAL - PROPERTY RIGHTS. HP DOES NOT WARRANT THAT THE SOFTWARE OR - DOCUMENTATION IS ERROR FREE. HP DISCLAIMS ALL WARRANTIES, - EXPRESS AND IMPLIED, WITH REGARD TO THE SOFTWARE AND THE - DOCUMENTATION. HP SPECIFICALLY DISCLAIMS ALL WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - - 5. HEWLETT-PACKARD COMPANY WILL NOT IN ANY EVENT BE LIABLE FOR ANY - DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES - (INCLUDING LOST PROFITS) RELATED TO ANY USE, REPRODUCTION, - MODIFICATION, OR DISTRIBUTION OF THE SOFTWARE OR DOCUMENTATION. - -*/ -char netperf_id[]="\ -@(#)netperf.c (c) Copyright 1993-2007 Hewlett-Packard Company. Version 2.4.3"; - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdio.h> -#include <stdlib.h> -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif - -/* FreeBSD doesn't like socket.h before types are set. */ -#if __FreeBSD__ -# include <sys/types.h> -#endif - -#ifndef WIN32 -/* this should only be temporary */ -#include <sys/socket.h> -#endif - -#ifdef WIN32 -#include <winsock2.h> -#include <windows.h> -#endif /* WIN32 */ - -#include "netsh.h" -#include "netlib.h" -#include "nettest_bsd.h" - -#ifdef WANT_UNIX -#include "nettest_unix.h" -#endif /* WANT_UNIX */ - -#ifdef WANT_XTI -#include "nettest_xti.h" -#endif /* WANT_XTI */ - -#ifdef WANT_DLPI -#include "nettest_dlpi.h" -#endif /* WANT_DLPI */ - -#ifdef WANT_SDP -#include "nettest_sdp.h" -#endif - -/* The DNS tests have been removed from netperf2. Those wanting to do - DNS_RR tests should use netperf4 instead. */ - -#ifdef DO_DNS -#error DNS tests have been removed from netperf. Use netperf4 instead -#endif /* DO_DNS */ - -#ifdef WANT_SCTP -#include "nettest_sctp.h" -#endif - - /* this file contains the main for the netperf program. all the other */ - /* routines can be found in the file netsh.c */ - - -int _cdecl -main(int argc, char *argv[]) -{ - -#ifdef WIN32 - WSADATA wsa_data ; - - /* Initialize the winsock lib ( version 2.2 ) */ - if ( WSAStartup(MAKEWORD(2,2), &wsa_data) == SOCKET_ERROR ){ - printf("WSAStartup() failed : %d\n", GetLastError()) ; - return 1 ; - } -#endif /* WIN32 */ - - netlib_init(); - set_defaults(); - scan_cmd_line(argc,argv); - - if (debug) { - dump_globals(); - install_signal_catchers(); - } - - if (debug) { - printf("remotehost is %s and port %s\n",host_name,test_port); - fflush(stdout); - } - - - if (!no_control) { - establish_control(host_name,test_port,address_family, - local_host_name,local_test_port,local_address_family); - } - - if (strcasecmp(test_name,"TCP_STREAM") == 0) { - send_tcp_stream(host_name); - } - else if (strcasecmp(test_name,"TCP_MAERTS") == 0) { - send_tcp_maerts(host_name); - } -#ifdef HAVE_ICSC_EXS - else if (strcasecmp(test_name,"EXS_TCP_STREAM") == 0) { - send_exs_tcp_stream(host_name); - } -#endif /* HAVE_ICSC_EXS */ -#ifdef HAVE_SENDFILE - else if (strcasecmp(test_name,"TCP_SENDFILE") == 0) { - sendfile_tcp_stream(host_name); - } -#endif /* HAVE_SENDFILE */ - else if (strcasecmp(test_name,"TCP_RR") == 0) { - send_tcp_rr(host_name); - } - else if (strcasecmp(test_name,"TCP_CRR") == 0) { - send_tcp_conn_rr(host_name); - } - else if (strcasecmp(test_name,"TCP_CC") == 0) { - send_tcp_cc(host_name); - } -#ifdef DO_1644 - else if (strcasecmp(test_name,"TCP_TRR") == 0) { - send_tcp_tran_rr(host_name); - } -#endif /* DO_1644 */ -#ifdef DO_NBRR - else if (strcasecmp(test_name,"TCP_NBRR") == 0) { - send_tcp_nbrr(host_name); - } -#endif /* DO_NBRR */ - else if (strcasecmp(test_name,"UDP_STREAM") == 0) { - send_udp_stream(host_name); - } - else if (strcasecmp(test_name,"UDP_RR") == 0) { - send_udp_rr(host_name); - } - else if (strcasecmp(test_name,"LOC_CPU") == 0) { - loc_cpu_rate(); - } - else if (strcasecmp(test_name,"REM_CPU") == 0) { - rem_cpu_rate(); - } -#ifdef WANT_DLPI - else if (strcasecmp(test_name,"DLCO_RR") == 0) { - send_dlpi_co_rr(host_name); - } - else if (strcasecmp(test_name,"DLCL_RR") == 0) { - send_dlpi_cl_rr(host_name); - } - else if (strcasecmp(test_name,"DLCO_STREAM") == 0) { - send_dlpi_co_stream(host_name); - } - else if (strcasecmp(test_name,"DLCL_STREAM") == 0) { - send_dlpi_cl_stream(host_name); - } -#endif /* WANT_DLPI */ -#ifdef WANT_UNIX - else if (strcasecmp(test_name,"STREAM_RR") == 0) { - send_stream_rr(host_name); - } - else if (strcasecmp(test_name,"DG_RR") == 0) { - send_dg_rr(host_name); - } - else if (strcasecmp(test_name,"STREAM_STREAM") == 0) { - send_stream_stream(host_name); - } - else if (strcasecmp(test_name,"DG_STREAM") == 0) { - send_dg_stream(host_name); - } -#endif /* WANT_UNIX */ -#ifdef WANT_XTI - else if (strcasecmp(test_name,"XTI_TCP_STREAM") == 0) { - send_xti_tcp_stream(host_name); - } - else if (strcasecmp(test_name,"XTI_TCP_RR") == 0) { - send_xti_tcp_rr(host_name); - } - else if (strcasecmp(test_name,"XTI_UDP_STREAM") == 0) { - send_xti_udp_stream(host_name); - } - else if (strcasecmp(test_name,"XTI_UDP_RR") == 0) { - send_xti_udp_rr(host_name); - } -#endif /* WANT_XTI */ - -#ifdef WANT_SCTP - else if (strcasecmp(test_name, "SCTP_STREAM") == 0) { - send_sctp_stream(host_name); - } - else if (strcasecmp(test_name, "SCTP_RR") == 0) { - send_sctp_rr(host_name); - } - else if (strcasecmp(test_name, "SCTP_STREAM_MANY") == 0) { - send_sctp_stream_1toMany(host_name); - } - else if (strcasecmp(test_name, "SCTP_RR_MANY") == 0) { - send_sctp_stream_1toMany(host_name); - } -#endif - -#ifdef DO_DNS - else if (strcasecmp(test_name,"DNS_RR") == 0) { - fprintf(stderr, - "DNS tests can now be found in netperf4.\n"); - fflush(stderr); - exit(-1); - } -#endif /* DO_DNS */ -#ifdef WANT_SDP - else if (strcasecmp(test_name,"SDP_STREAM") == 0) { - send_sdp_stream(host_name); - } - else if (strcasecmp(test_name,"SDP_MAERTS") == 0) { - send_sdp_maerts(host_name); - } - else if (strcasecmp(test_name,"SDP_RR") == 0) { - send_sdp_rr(host_name); - } -#endif /* WANT_SDP */ - else { - printf("The test you requested is unknown to this netperf.\n"); - printf("Please verify that you have the correct test name, \n"); - printf("and that test family has been compiled into this netperf.\n"); - exit(1); - } - - if (!no_control) { - shutdown_control(); - } - -#ifdef WIN32 - /* Cleanup the winsock lib */ - WSACleanup(); -#endif - - return(0); -} - - diff --git a/netperf_version.h b/netperf_version.h deleted file mode 100644 index b2b9fdc..0000000 --- a/netperf_version.h +++ /dev/null @@ -1 +0,0 @@ -#define NETPERF_VERSION "2.4.4" diff --git a/netserver.c b/netserver.c deleted file mode 100644 index 02be3ce..0000000 --- a/netserver.c +++ /dev/null @@ -1,1022 +0,0 @@ -/* - - Copyright (C) 1993-2007 Hewlett-Packard Company - ALL RIGHTS RESERVED. - - The enclosed software and documentation includes copyrighted works - of Hewlett-Packard Co. For as long as you comply with the following - limitations, you are hereby authorized to (i) use, reproduce, and - modify the software and documentation, and to (ii) distribute the - software and documentation, including modifications, for - non-commercial purposes only. - - 1. The enclosed software and documentation is made available at no - charge in order to advance the general development of - high-performance networking products. - - 2. You may not delete any copyright notices contained in the - software or documentation. All hard copies, and copies in - source code or object code form, of the software or - documentation (including modifications) must contain at least - one of the copyright notices. - - 3. The enclosed software and documentation has not been subjected - to testing and quality control and is not a Hewlett-Packard Co. - product. At a future time, Hewlett-Packard Co. may or may not - offer a version of the software and documentation as a product. - - 4. THE SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS". - HEWLETT-PACKARD COMPANY DOES NOT WARRANT THAT THE USE, - REPRODUCTION, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR - DOCUMENTATION WILL NOT INFRINGE A THIRD PARTY'S INTELLECTUAL - PROPERTY RIGHTS. HP DOES NOT WARRANT THAT THE SOFTWARE OR - DOCUMENTATION IS ERROR FREE. HP DISCLAIMS ALL WARRANTIES, - EXPRESS AND IMPLIED, WITH REGARD TO THE SOFTWARE AND THE - DOCUMENTATION. HP SPECIFICALLY DISCLAIMS ALL WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - - 5. HEWLETT-PACKARD COMPANY WILL NOT IN ANY EVENT BE LIABLE FOR ANY - DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES - (INCLUDING LOST PROFITS) RELATED TO ANY USE, REPRODUCTION, - MODIFICATION, OR DISTRIBUTION OF THE SOFTWARE OR DOCUMENTATION. - -*/ - -#include "netperf_version.h" - -char netserver_id[]="\ -@(#)netserver.c (c) Copyright 1993-2007 Hewlett-Packard Co. Version 2.4.3"; - - /***********************************************************************/ - /* */ - /* netserver.c */ - /* */ - /* This is the server side code for the netperf test package. It */ - /* will operate either stand-alone, or as a child of inetd. In this */ - /* way, we insure that it can be installed on systems with or without */ - /* root permissions (editing inetd.conf). Essentially, this code is */ - /* the analog to the netsh.c code. */ - /* */ - /***********************************************************************/ - - -/************************************************************************/ -/* */ -/* Global include files */ -/* */ -/************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#if HAVE_STRING_H -# if !STDC_HEADERS && HAVE_MEMORY_H -# include <memory.h> -# endif -# include <string.h> -#endif -#if HAVE_STRINGS_H -# include <strings.h> -#endif -#if HAVE_LIMITS_H -# include <limits.h> -#endif -#include <sys/types.h> -#include <stdio.h> -#ifndef WIN32 -#include <errno.h> -#include <signal.h> -#endif -#if !defined(WIN32) && !defined(__VMS) -#include <sys/ipc.h> -#endif /* !defined(WIN32) && !defined(__VMS) */ -#include <fcntl.h> -#ifdef WIN32 -#include <time.h> -#include <winsock2.h> -#define netperf_socklen_t socklen_t -/* we need to find some other way to decide to include ws2 */ -/* if you are trying to compile on Windows 2000 or NT 4 you will */ -/* probably have to define DONT_IPV6 */ -#ifndef DONT_IPV6 -#include <ws2tcpip.h> -#endif /* DONT_IPV6 */ -#include <windows.h> -#define sleep(x) Sleep((x)*1000) -#else -#ifndef MPE -#include <sys/time.h> -#endif /* MPE */ -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <netinet/in.h> -#include <netdb.h> -#include <unistd.h> -#ifndef DONT_WAIT -#include <sys/wait.h> -#endif /* DONT_WAIT */ -#endif /* WIN32 */ -#include <stdlib.h> -#ifdef __VMS -#include <tcpip$inetdef.h> -#include <unixio.h> -#endif /* __VMS */ -#include "netlib.h" -#include "nettest_bsd.h" - -#ifdef WANT_UNIX -#include "nettest_unix.h" -#endif /* WANT_UNIX */ - -#ifdef WANT_DLPI -#include "nettest_dlpi.h" -#endif /* WANT_DLPI */ - -#ifdef WANT_SCTP -#include "nettest_sctp.h" -#endif - -#include "netsh.h" - -#ifndef DEBUG_LOG_FILE -#ifndef WIN32 -#define DEBUG_LOG_FILE "/tmp/netperf.debug" -#else -#define DEBUG_LOG_FILE "c:\\temp\\netperf.debug" -#endif /* WIN32 */ -#endif /* DEBUG_LOG_FILE */ - - /* some global variables */ - -FILE *afp; -char listen_port[10]; -extern char *optarg; -extern int optind, opterr; - -#ifndef WIN32 -#define SERVER_ARGS "dL:n:p:v:V46" -#else -#define SERVER_ARGS "dL:n:p:v:V46I:i:" -#endif - -/* perhaps one day we will use this as part of only opening a debug - log file if debug is set, of course we have to be wary of the base - use of "where" and so probably always need "where" pointing - "somewhere" or other. */ -void -open_debug_file() -{ -#ifndef WIN32 -#ifndef PATH_MAX -#define PATH_MAX MAX_PATH -#endif - char FileName[PATH_MAX]; /* for opening the debug log file */ - strcpy(FileName, DEBUG_LOG_FILE); - - if (where != NULL) fflush(where); - - snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%d", getpid()); - if ((where = fopen(FileName, "w")) == NULL) { - perror("netserver: debug file"); - exit(1); - } - - chmod(FileName,0644); -#endif - -} - /* This routine implements the "main event loop" of the netperf */ - /* server code. Code above it will have set-up the control connection */ - /* so it can just merrily go about its business, which is to */ - /* "schedule" performance tests on the server. */ - -void -process_requests() -{ - - float temp_rate; - - if (debug) open_debug_file(); - - - while (1) { - recv_request(); - - switch (netperf_request.content.request_type) { - - case DEBUG_ON: - netperf_response.content.response_type = DEBUG_OK; - /* dump_request already present in recv_request; redundant? */ - if (!debug) { - debug++; - open_debug_file(); - dump_request(); - } - send_response(); - break; - - case DEBUG_OFF: - if (debug) - debug--; - netperf_response.content.response_type = DEBUG_OK; - send_response(); - /* +SAF why??? */ - if (!debug) - { - fclose(where); -#if !defined(WIN32) && !defined(MPE) && !defined(__VMS) - /* For Unix: reopen the debug write file descriptor to "/dev/null" */ - /* and redirect stdout to it. */ - fflush (stdout); - where = fopen ("/dev/null", "w"); - if (where == NULL) - { - perror ("netserver: reopening debug fp for writing: /dev/null"); - exit (1); - } - if (close (STDOUT_FILENO) == -1) - { - perror ("netserver: closing stdout file descriptor"); - exit (1); - } - if (dup (fileno (where)) == -1) - { - perror ("netserver: duplicate /dev/null write file descr. to stdout"); - exit (1); - } -#endif /* !WIN32 !MPE !__VMS */ - } - break; - - case CPU_CALIBRATE: - netperf_response.content.response_type = CPU_CALIBRATE; - temp_rate = calibrate_local_cpu(0.0); - bcopy((char *)&temp_rate, - (char *)netperf_response.content.test_specific_data, - sizeof(temp_rate)); - bcopy((char *)&lib_num_loc_cpus, - (char *)netperf_response.content.test_specific_data + sizeof(temp_rate), - sizeof(lib_num_loc_cpus)); - if (debug) { - fprintf(where,"netserver: sending CPU information:"); - fprintf(where,"rate is %g num cpu %d\n",temp_rate,lib_num_loc_cpus); - fflush(where); - } - - /* we need the cpu_start, cpu_stop in the looper case to kill the */ - /* child proceses raj 7/95 */ - -#ifdef USE_LOOPER - cpu_start(1); - cpu_stop(1,&temp_rate); -#endif /* USE_LOOPER */ - - send_response(); - break; - - case DO_TCP_STREAM: - recv_tcp_stream(); - break; - - case DO_TCP_MAERTS: - recv_tcp_maerts(); - break; - - case DO_TCP_RR: - recv_tcp_rr(); - break; - - case DO_TCP_CRR: - recv_tcp_conn_rr(); - break; - - case DO_TCP_CC: - recv_tcp_cc(); - break; - -#ifdef DO_1644 - case DO_TCP_TRR: - recv_tcp_tran_rr(); - break; -#endif /* DO_1644 */ - -#ifdef DO_NBRR - case DO_TCP_NBRR: - recv_tcp_nbrr(); - break; -#endif /* DO_NBRR */ - - case DO_UDP_STREAM: - recv_udp_stream(); - break; - - case DO_UDP_RR: - recv_udp_rr(); - break; - -#ifdef WANT_DLPI - - case DO_DLPI_CO_RR: - recv_dlpi_co_rr(); - break; - - case DO_DLPI_CL_RR: - recv_dlpi_cl_rr(); - break; - - case DO_DLPI_CO_STREAM: - recv_dlpi_co_stream(); - break; - - case DO_DLPI_CL_STREAM: - recv_dlpi_cl_stream(); - break; - -#endif /* WANT_DLPI */ - -#ifdef WANT_UNIX - - case DO_STREAM_STREAM: - recv_stream_stream(); - break; - - case DO_STREAM_RR: - recv_stream_rr(); - break; - - case DO_DG_STREAM: - recv_dg_stream(); - break; - - case DO_DG_RR: - recv_dg_rr(); - break; - -#endif /* WANT_UNIX */ - -#ifdef WANT_XTI - case DO_XTI_TCP_STREAM: - recv_xti_tcp_stream(); - break; - - case DO_XTI_TCP_RR: - recv_xti_tcp_rr(); - break; - - case DO_XTI_UDP_STREAM: - recv_xti_udp_stream(); - break; - - case DO_XTI_UDP_RR: - recv_xti_udp_rr(); - break; - -#endif /* WANT_XTI */ - -#ifdef WANT_SCTP - case DO_SCTP_STREAM: - recv_sctp_stream(); - break; - - case DO_SCTP_STREAM_MANY: - recv_sctp_stream_1toMany(); - break; - - case DO_SCTP_RR: - recv_sctp_rr(); - break; - - case DO_SCTP_RR_MANY: - recv_sctp_rr_1toMany(); - break; -#endif - -#ifdef WANT_SDP - case DO_SDP_STREAM: - recv_sdp_stream(); - break; - - case DO_SDP_MAERTS: - recv_sdp_maerts(); - break; - - case DO_SDP_RR: - recv_sdp_rr(); - break; -#endif - - default: - fprintf(where,"unknown test number %d\n", - netperf_request.content.request_type); - fflush(where); - netperf_response.content.serv_errno=998; - send_response(); - break; - - } - } -} - -/* - set_up_server() - - set-up the server listen socket. we only call this routine if the - user has specified a port number on the command line or we believe we - are not a child of inetd or its platform-specific equivalent */ - -/*KC*/ - -void -set_up_server(char hostname[], char port[], int af) -{ - - struct addrinfo hints; - struct addrinfo *local_res; - struct addrinfo *local_res_temp; - - struct sockaddr_storage peeraddr; - netperf_socklen_t peeraddr_len = sizeof(peeraddr); - - SOCKET server_control; - int on=1; - int count; - int error; - int not_listening; - -#if !defined(WIN32) && !defined(MPE) && !defined(__VMS) - FILE *rd_null_fp; /* Used to redirect from "/dev/null". */ - FILE *wr_null_fp; /* Used to redirect to "/dev/null". */ -#endif /* !WIN32 !MPE !__VMS */ - - if (debug) { - fprintf(stderr, - "set_up_server called with host '%s' port '%s' remfam %d\n", - hostname, - port, - af); - fflush(stderr); - } - - memset(&hints,0,sizeof(hints)); - hints.ai_family = af; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_PASSIVE; - - count = 0; - do { - error = getaddrinfo((char *)hostname, - (char *)port, - &hints, - &local_res); - count += 1; - if (error == EAI_AGAIN) { - if (debug) { - fprintf(stderr,"Sleeping on getaddrinfo EAI_AGAIN\n"); - fflush(stderr); - } - sleep(1); - } - } while ((error == EAI_AGAIN) && (count <= 5)); - - if (error) { - fprintf(stderr, - "set_up_server: could not resolve remote '%s' port '%s' af %d", - hostname, - port, - af); - fprintf(stderr,"\n\tgetaddrinfo returned %d %s\n", - error, - gai_strerror(error)); - exit(-1); - } - - if (debug) { - dump_addrinfo(stderr, local_res, hostname, port, af); - } - - not_listening = 1; - local_res_temp = local_res; - - while((local_res_temp != NULL) && (not_listening)) { - - fprintf(stderr, - "Starting netserver at port %s\n", - port); - - server_control = socket(local_res_temp->ai_family,SOCK_STREAM,0); - - if (server_control == INVALID_SOCKET) { - perror("set_up_server could not allocate a socket"); - exit(-1); - } - - /* happiness and joy, keep going */ - if (setsockopt(server_control, - SOL_SOCKET, - SO_REUSEADDR, - (char *)&on , - sizeof(on)) == SOCKET_ERROR) { - if (debug) { - perror("warning: set_up_server could not set SO_REUSEADDR"); - } - } - /* still happy and joyful */ - - if ((bind (server_control, - local_res_temp->ai_addr, - local_res_temp->ai_addrlen) != SOCKET_ERROR) && - (listen (server_control,5) != SOCKET_ERROR)) { - not_listening = 0; - break; - } - else { - /* we consider a bind() or listen() failure a transient and try - the next address */ - if (debug) { - perror("warning: set_up_server failed a bind or listen call\n"); - } - local_res_temp = local_res_temp->ai_next; - continue; - } - } - - if (not_listening) { - fprintf(stderr, - "set_up_server could not establish a listen endpoint for %s port %s with family %s\n", - host_name, - port, - inet_ftos(af)); - fflush(stderr); - exit(-1); - } - else { - printf("Starting netserver at hostname %s port %s and family %s\n", - hostname, - port, - inet_ftos(af)); - } - - /* - setpgrp(); - */ - -#if !defined(WIN32) && !defined(MPE) && !defined(__VMS) - /* Flush the standard I/O file descriptors before forking. */ - fflush (stdin); - fflush (stdout); - fflush (stderr); - switch (fork()) - { - case -1: - perror("netperf server error"); - exit(1); - - case 0: - /* Redirect stdin from "/dev/null". */ - rd_null_fp = fopen ("/dev/null", "r"); - if (rd_null_fp == NULL) - { - perror ("netserver: opening for reading: /dev/null"); - exit (1); - } - if (close (STDIN_FILENO) == -1) - { - perror ("netserver: closing stdin file descriptor"); - exit (1); - } - if (dup (fileno (rd_null_fp)) == -1) - { - perror ("netserver: duplicate /dev/null read file descr. to stdin"); - exit (1); - } - - /* Redirect stdout to the debug write file descriptor. */ - if (close (STDOUT_FILENO) == -1) - { - perror ("netserver: closing stdout file descriptor"); - exit (1); - } - if (dup (fileno (where)) == -1) - { - perror ("netserver: duplicate the debug write file descr. to stdout"); - exit (1); - } - - /* Redirect stderr to "/dev/null". */ - wr_null_fp = fopen ("/dev/null", "w"); - if (wr_null_fp == NULL) - { - perror ("netserver: opening for writing: /dev/null"); - exit (1); - } - if (close (STDERR_FILENO) == -1) - { - perror ("netserver: closing stderr file descriptor"); - exit (1); - } - if (dup (fileno (wr_null_fp)) == -1) - { - perror ("netserver: dupicate /dev/null write file descr. to stderr"); - exit (1); - } - -#ifndef NO_SETSID - setsid(); -#else - setpgrp(); -#endif /* NO_SETSID */ - - /* some OS's have SIGCLD defined as SIGCHLD */ -#ifndef SIGCLD -#define SIGCLD SIGCHLD -#endif /* SIGCLD */ - - signal(SIGCLD, SIG_IGN); - -#endif /* !WIN32 !MPE !__VMS */ - - for (;;) - { - if ((server_sock=accept(server_control, - (struct sockaddr *)&peeraddr, - &peeraddr_len)) == INVALID_SOCKET) - { - printf("server_control: accept failed errno %d\n",errno); - exit(1); - } -#if defined(MPE) || defined(__VMS) - /* - * Since we cannot fork this process , we cant fire any threads - * as they all share the same global data . So we better allow - * one request at at time - */ - process_requests() ; -#elif WIN32 - { - BOOL b; - char cmdline[80]; - PROCESS_INFORMATION pi; - STARTUPINFO si; - int i; - - memset(&si, 0 , sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - - /* Pass the server_sock as stdin for the new process. */ - /* Hopefully this will continue to be created with the OBJ_INHERIT attribute. */ - si.hStdInput = (HANDLE)server_sock; - si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - si.dwFlags = STARTF_USESTDHANDLES; - - /* Build cmdline for child process */ - strcpy(cmdline, program); - if (verbosity > 1) { - snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -v %d", verbosity); - } - for (i=0; i < debug; i++) { - snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -d"); - } - snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -I %x", (int)(UINT_PTR)server_sock); - snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -i %x", (int)(UINT_PTR)server_control); - snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -i %x", (int)(UINT_PTR)where); - - b = CreateProcess(NULL, /* Application Name */ - cmdline, - NULL, /* Process security attributes */ - NULL, /* Thread security attributes */ - TRUE, /* Inherit handles */ - 0, /* Creation flags PROCESS_QUERY_INFORMATION, */ - NULL, /* Enviornment */ - NULL, /* Current directory */ - &si, /* StartupInfo */ - &pi); - if (!b) - { - perror("CreateProcessfailure: "); - exit(1); - } - - /* We don't need the thread or process handles any more; let them */ - /* go away on their own timeframe. */ - - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - - /* And close the server_sock since the child will own it. */ - - close(server_sock); - } -#else - signal(SIGCLD, SIG_IGN); - - switch (fork()) - { - case -1: - /* something went wrong */ - exit(1); - case 0: - /* we are the child process */ - close(server_control); - process_requests(); - exit(0); - break; - default: - /* we are the parent process */ - close(server_sock); - /* we should try to "reap" some of our children. on some */ - /* systems they are being left as defunct processes. we */ - /* will call waitpid, looking for any child process, */ - /* with the WNOHANG feature. when waitpid return a zero, */ - /* we have reaped all the children there are to reap at */ - /* the moment, so it is time to move on. raj 12/94 */ -#ifndef DONT_WAIT -#ifdef NO_SETSID - /* Only call "waitpid()" if "setsid()" is not used. */ - while(waitpid(-1, NULL, WNOHANG) > 0) { } -#endif /* NO_SETSID */ -#endif /* DONT_WAIT */ - break; - } -#endif /* !WIN32 !MPE !__VMS */ - } /*for*/ -#if !defined(WIN32) && !defined(MPE) && !defined(__VMS) - break; /*case 0*/ - - default: - exit (0); - - } -#endif /* !WIN32 !MPE !__VMS */ -} - -#ifdef WIN32 - - /* With Win2003, WinNT's POSIX subsystem is gone and hence so is */ - /* fork. */ - - /* But hopefully the kernel support will continue to exist for some */ - /* time. */ - - /* We are not counting on the child address space copy_on_write */ - /* support, since it isn't exposed except through the NT native APIs */ - /* (which is not public). */ - - /* We will try to use the InheritHandles flag in CreateProcess. It */ - /* is in the public API, though it is documented as "must be FALSE". */ - - /* So where we would have forked, we will now create a new process. */ - /* I have added a set of command line switches to specify a list of */ - /* handles that the child should close since they shouldn't have */ - /* been inherited ("-i#"), and a single switch to specify the handle */ - /* for the server_sock ("I#"). */ - - /* A better alternative would be to re-write NetPerf to be */ - /* multi-threaded; i.e., move all of the various NetPerf global */ - /* variables in to thread specific structures. But this is a bigger */ - /* effort than I want to tackle at this time. (And I doubt that the */ - /* HP-UX author sees value in this effort). */ - -#endif - -int _cdecl -main(int argc, char *argv[]) -{ - - int c; - int not_inetd = 0; -#ifdef WIN32 - BOOL child = FALSE; -#endif - char arg1[BUFSIZ], arg2[BUFSIZ]; -#ifndef PATH_MAX -#define PATH_MAX MAX_PATH -#endif - char FileName[PATH_MAX]; /* for opening the debug log file */ - - struct sockaddr name; - netperf_socklen_t namelen = sizeof(name); - - -#ifdef WIN32 - WSADATA wsa_data ; - - /* Initialize the winsock lib ( version 2.2 ) */ - if ( WSAStartup(MAKEWORD(2,2), &wsa_data) == SOCKET_ERROR ){ - printf("WSAStartup() failed : %d\n", GetLastError()) ; - return 1 ; - } -#endif /* WIN32 */ - - /* Save away the program name */ - program = (char *)malloc(strlen(argv[0]) + 1); - if (program == NULL) { - printf("malloc(%d) failed!\n", strlen(argv[0]) + 1); - return 1 ; - } - strcpy(program, argv[0]); - - netlib_init(); - - /* Scan the command line to see if we are supposed to set-up our own */ - /* listen socket instead of relying on inetd. */ - - /* first set a copy of initial values */ - strncpy(local_host_name,"0.0.0.0",sizeof(local_host_name)); - local_address_family = AF_UNSPEC; - strncpy(listen_port,TEST_PORT,sizeof(listen_port)); - - while ((c = getopt(argc, argv, SERVER_ARGS)) != EOF) { - switch (c) { - case '?': - case 'h': - print_netserver_usage(); - exit(1); - case 'd': - /* we want to set the debug file name sometime */ - debug++; - break; - case 'L': - not_inetd = 1; - break_args_explicit(optarg,arg1,arg2); - if (arg1[0]) { - strncpy(local_host_name,arg1,sizeof(local_host_name)); - } - if (arg2[0]) { - local_address_family = parse_address_family(arg2); - /* if only the address family was set, we may need to set the - local_host_name accordingly. since our defaults are IPv4 - this should only be necessary if we have IPv6 support raj - 2005-02-07 */ -#if defined (AF_INET6) - if (!arg1[0]) { - strncpy(local_host_name,"::0",sizeof(local_host_name)); - } -#endif - } - break; - case 'n': - shell_num_cpus = atoi(optarg); - if (shell_num_cpus > MAXCPUS) { - fprintf(stderr, - "netserver: This version can only support %d CPUs. Please", - MAXCPUS); - fprintf(stderr, - " increase MAXCPUS in netlib.h and recompile.\n"); - fflush(stderr); - exit(1); - } - break; - case 'p': - /* we want to open a listen socket at a */ - /* specified port number */ - strncpy(listen_port,optarg,sizeof(listen_port)); - not_inetd = 1; - break; - case '4': - local_address_family = AF_INET; - break; - case '6': -#if defined(AF_INET6) - local_address_family = AF_INET6; - strncpy(local_host_name,"::0",sizeof(local_host_name)); -#else - local_address_family = AF_UNSPEC; -#endif - break; - case 'v': - /* say how much to say */ - verbosity = atoi(optarg); - break; - case 'V': - printf("Netperf version %s\n",NETPERF_VERSION); - exit(0); - break; -#ifdef WIN32 -/*+*+SAF */ - case 'I': - child = TRUE; - /* This is the handle we expect to inherit. */ - /*+*+SAF server_sock = (HANDLE)atoi(optarg); */ - break; - case 'i': - /* This is a handle we should NOT inherit. */ - /*+*+SAF CloseHandle((HANDLE)atoi(optarg)); */ - break; -#endif - - } - } - - /* +*+SAF I need a better way to find inherited handles I should close! */ - /* +*+SAF Use DuplicateHandle to force inheritable attribute (or reset it)? */ - -/* unlink(DEBUG_LOG_FILE); */ - - strcpy(FileName, DEBUG_LOG_FILE); - -#ifndef WIN32 - snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%d", getpid()); - if ((where = fopen(FileName, "w")) == NULL) { - perror("netserver: debug file"); - exit(1); - } -#else - { - - if (child) { - snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%x", getpid()); - } - - /* Hopefully, by closing stdout & stderr, the subsequent - fopen calls will get mapped to the correct std handles. */ - fclose(stdout); - - if ((where = fopen(FileName, "w")) == NULL) { - perror("netserver: fopen of debug file as new stdout failed!"); - exit(1); - } - - fclose(stderr); - - if ((where = fopen(FileName, "w")) == NULL) { - fprintf(stdout, "fopen of debug file as new stderr failed!\n"); - exit(1); - } - } -#endif - -#ifndef WIN32 - chmod(DEBUG_LOG_FILE,0644); -#endif - -#if WIN32 - if (child) { - server_sock = (SOCKET)GetStdHandle(STD_INPUT_HANDLE); - } -#endif - - /* if we are not a child of an inetd or the like, then we should - open a socket and hang listens off of it. otherwise, we should go - straight into processing requests. the do_listen() routine will sit - in an infinite loop accepting connections and forking child - processes. the child processes will call process_requests */ - - /* If fd 0 is not a socket then assume we're not being called */ - /* from inetd and start server socket on the default port. */ - /* this enhancement comes from vwelch@ncsa.uiuc.edu (Von Welch) */ - if (not_inetd) { - /* the user specified a port number on the command line */ - set_up_server(local_host_name,listen_port,local_address_family); - } -#ifdef WIN32 - /* OK, with Win2003 WinNT's POSIX subsystem is gone, and hence so is */ - /* fork. But hopefully the kernel support will continue to exist */ - /* for some time. We are not counting on the address space */ - /* copy_on_write support, since it isn't exposed except through the */ - /* NT native APIs (which are not public). We will try to use the */ - /* InheritHandles flag in CreateProcess though since this is public */ - /* and is used for more than just POSIX so hopefully it won't go */ - /* away. */ - else if (TRUE) { - if (child) { - process_requests(); - } else { - strncpy(listen_port,TEST_PORT,sizeof(listen_port)); - set_up_server(local_host_name,listen_port,local_address_family); - } - } -#endif -#if !defined(__VMS) - else if (getsockname(0, &name, &namelen) == SOCKET_ERROR) { - /* we may not be a child of inetd */ - if (errno == ENOTSOCK) { - strncpy(listen_port,TEST_PORT,sizeof(listen_port)); - set_up_server(local_host_name,listen_port,local_address_family); - } - } -#endif /* !defined(__VMS) */ - else { - /* we are probably a child of inetd, or are being invoked via the - VMS auxilliarly server mechanism */ -#if !defined(__VMS) - server_sock = 0; -#else - if ( (server_sock = socket(TCPIP$C_AUXS, SOCK_STREAM, 0)) == INVALID_SOCKET ) - { - perror("Failed to grab aux server socket" ); - exit(1); - } - -#endif /* !defined(__VMS) */ - process_requests(); - } -#ifdef WIN32 - /* Cleanup the winsock lib */ - WSACleanup(); -#endif - - return(0); -} diff --git a/netsh.c b/netsh.c deleted file mode 100644 index 7659679..0000000 --- a/netsh.c +++ /dev/null @@ -1,1002 +0,0 @@ -#include "netperf_version.h" - -char netsh_id[]="\ -@(#)netsh.c (c) Copyright 1993-2007 Hewlett-Packard Company. Version 2.4.3pre"; - - -/****************************************************************/ -/* */ -/* Global include files */ -/* */ -/****************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <sys/types.h> -#ifndef WIN32 -#include <unistd.h> -#ifndef __VMS -#include <sys/ipc.h> -#endif /* __VMS */ -#endif /* WIN32 */ -#include <fcntl.h> -#ifndef WIN32 -#include <errno.h> -#include <signal.h> -#endif /* !WIN32 */ -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> - /* the following four includes should not be needed ?*/ -#ifndef WIN32 -#include <sys/time.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#else -#include <time.h> -#include <winsock2.h> -#define netperf_socklen_t socklen_t -#endif - -#ifndef STRINGS -#include <string.h> -#else /* STRINGS */ -#include <strings.h> -#endif /* STRINGS */ - -#ifdef WIN32 -extern int getopt(int , char **, char *) ; -#else -double atof(const char *); -#endif /* WIN32 */ - -/**********************************************************************/ -/* */ -/* Local Include Files */ -/* */ -/**********************************************************************/ - -#define NETSH -#include "netsh.h" -#include "netlib.h" -#include "nettest_bsd.h" - -#ifdef WANT_UNIX -#include "nettest_unix.h" -#ifndef WIN32 -#include "sys/socket.h" -#endif /* !WIN32 */ -#endif /* WANT_UNIX */ - -#ifdef WANT_XTI -#include "nettest_xti.h" -#endif /* WANT_XTI */ - -#ifdef WANT_DLPI -#include "nettest_dlpi.h" -#endif /* WANT_DLPI */ - -#ifdef WANT_SCTP -#include "nettest_sctp.h" -#endif - - -/************************************************************************/ -/* */ -/* Global constants and macros */ -/* */ -/************************************************************************/ - - /* Some of the args take optional parameters. Since we are using */ - /* getopt to parse the command line, we will tell getopt that they do */ - /* not take parms, and then look for them ourselves */ -#define GLOBAL_CMD_LINE_ARGS "A:a:b:B:CcdDf:F:H:hi:I:k:K:l:L:n:NO:o:P:p:rt:T:v:VW:w:46" - -/************************************************************************/ -/* */ -/* Extern variables */ -/* */ -/************************************************************************/ - -/* -extern int errno; -extern char *sys_errlist[ ]; -extern int sys_nerr; -*/ - -/************************************************************************/ -/* */ -/* Global variables */ -/* */ -/************************************************************************/ - -/* some names and such */ -char *program; /* program invocation name */ -char username[BUFSIZ]; /* login name of user */ -char cmd_file[BUFSIZ]; /* name of the commands file */ - -/* stuff to say where this test is going */ -char host_name[HOSTNAMESIZE]; /* remote host name or ip addr */ -char local_host_name[HOSTNAMESIZE]; /* local hostname or ip */ -char test_name[BUFSIZ]; /* which test to run */ -char test_port[PORTBUFSIZE]; /* where is the test waiting */ -char local_test_port[PORTBUFSIZE]; /* from whence we should start */ -int address_family; /* which address family remote */ -int local_address_family; /* which address family local */ - -/* the source of data for filling the buffers */ -char fill_file[BUFSIZ]; - -/* output controlling variables */ -int - debug, /* debugging level */ - print_headers, /* do/don't display headers */ - verbosity; /* verbosity level */ - -/* When specified with -B, this will be displayed at the end of the line - for output that does not include the test header. mostly this is - to help identify a specific netperf result when concurrent netperfs - are run. raj 2006-02-01 */ -char *result_brand = NULL; - -/* cpu variables */ -int - local_cpu_usage, /* you guessed it */ - remote_cpu_usage; /* still right ! */ - -float - local_cpu_rate, - remote_cpu_rate; - -int - shell_num_cpus=1; - -/* the end-test conditions for the tests - either transactions, bytes, */ -/* or time. different vars used for clarity - space is cheap ;-) */ -int - test_time, /* test ends by time */ - test_len_ticks, /* how many times will the timer go off before */ - /* the test is over? */ - test_bytes, /* test ends on byte count */ - test_trans; /* test ends on tran count */ - -/* the alignment conditions for the tests */ -int - local_recv_align, /* alignment for local receives */ - local_send_align, /* alignment for local sends */ - local_send_offset = 0, - local_recv_offset = 0, - remote_recv_align, /* alignment for remote receives */ - remote_send_align, /* alignment for remote sends */ - remote_send_offset = 0, - remote_recv_offset = 0; - -#if defined(WANT_INTERVALS) || defined(WANT_DEMO) -int - interval_usecs, - interval_wate, - interval_burst; - -int demo_mode; /* are we actually in demo mode? */ -double demo_interval = 1000000.0; /* what is the desired interval to - display interval results. default - is one second in units of - microseconds */ -double demo_units = 0.0; /* what is our current best guess as - to how many work units must be - done to be near the desired - reporting interval? */ - -double units_this_tick; -#endif - -#ifdef DIRTY -int loc_dirty_count; -int loc_clean_count; -int rem_dirty_count; -int rem_clean_count; -#endif /* DIRTY */ - - /* some of the vairables for confidence intervals... */ - -int confidence_level; -int iteration_min; -int iteration_max; -int result_confidence_only = 0; - -double interval; - - /* stuff to control the "width" of the buffer rings for sending and */ - /* receiving data */ -int send_width; -int recv_width; - -/* address family */ -int af = AF_INET; - -/* did someone request processor affinity? */ -int cpu_binding_requested = 0; - -/* are we not establishing a control connection? */ -int no_control = 0; - -char netserver_usage[] = "\n\ -Usage: netserver [options] \n\ -\n\ -Options:\n\ - -h Display this text\n\ - -d Increase debugging output\n\ - -L name,family Use name to pick listen address and family for family\n\ - -p portnum Listen for connect requests on portnum.\n\ - -4 Do IPv4\n\ - -6 Do IPv6\n\ - -v verbosity Specify the verbosity level\n\ - -V Display version information and exit\n\ -\n"; - -/* netperf_usage done as two concatenated strings to make the MS - compiler happy when compiling for x86_32. fix from Spencer - Frink. */ - -char netperf_usage1[] = "\n\ -Usage: netperf [global options] -- [test options] \n\ -\n\ -Global options:\n\ - -a send,recv Set the local send,recv buffer alignment\n\ - -A send,recv Set the remote send,recv buffer alignment\n\ - -B brandstr Specify a string to be emitted with brief output\n\ - -c [cpu_rate] Report local CPU usage\n\ - -C [cpu_rate] Report remote CPU usage\n\ - -d Increase debugging output\n\ - -D [secs,units] * Display interim results at least every secs seconds\n\ - using units as the initial guess for units per second\n\ - -f G|M|K|g|m|k Set the output units\n\ - -F fill_file Pre-fill buffers with data from fill_file\n\ - -h Display this text\n\ - -H name|ip,fam * Specify the target machine and/or local ip and family\n\ - -i max,min Specify the max and min number of iterations (15,1)\n\ - -I lvl[,intvl] Specify confidence level (95 or 99) (99) \n\ - and confidence interval in percentage (10)\n\ - -l testlen Specify test duration (>0 secs) (<0 bytes|trans)\n\ - -L name|ip,fam * Specify the local ip|name and address family\n\ - -o send,recv Set the local send,recv buffer offsets\n\ - -O send,recv Set the remote send,recv buffer offset\n\ - -n numcpu Set the number of processors for CPU util\n\ - -N Establish no control connection, do 'send' side only\n\ - -p port,lport* Specify netserver port number and/or local port\n\ - -P 0|1 Don't/Do display test headers\n\ - -r Allow confidence to be hit on result only\n\ - -t testname Specify test to perform\n\ - -T lcpu,rcpu Request netperf/netserver be bound to local/remote cpu\n\ - -v verbosity Specify the verbosity level\n\ - -W send,recv Set the number of send,recv buffers\n\ - -v level Set the verbosity level (default 1, min 0)\n\ - -V Display the netperf version and exit\n"; - -char netperf_usage2[] = "\n\ -For those options taking two parms, at least one must be specified;\n\ -specifying one value without a comma will set both parms to that\n\ -value, specifying a value with a leading comma will set just the second\n\ -parm, a value with a trailing comma will set just the first. To set\n\ -each parm to unique values, specify both and separate them with a\n\ -comma.\n\ -\n" -"* For these options taking two parms, specifying one value with no comma\n\ -will only set the first parms and will leave the second at the default\n\ -value. To set the second value it must be preceded with a comma or be a\n\ -comma-separated pair. This is to retain previous netperf behaviour.\n"; - - -/* This routine will return the two arguments to the calling routine. */ -/* If the second argument is not specified, and there is no comma, */ -/* then the value of the second argument will be the same as the */ -/* value of the first. If there is a comma, then the value of the */ -/* second argument will be the value of the second argument ;-) */ -void -break_args(char *s, char *arg1, char *arg2) - -{ - char *ns; - ns = strchr(s,','); - if (ns) { - /* there was a comma arg2 should be the second arg*/ - *ns++ = '\0'; - while ((*arg2++ = *ns++) != '\0'); - } - else { - /* there was not a comma, we can use ns as a temp s */ - /* and arg2 should be the same value as arg1 */ - ns = s; - while ((*arg2++ = *ns++) != '\0'); - }; - while ((*arg1++ = *s++) != '\0'); -} - -/* break_args_explicit - - this routine is somewhat like break_args in that it will separate a - pair of comma-separated values. however, if there is no comma, - this version will not ass-u-me that arg2 should be the same as - arg1. raj 2005-02-04 */ -void -break_args_explicit(char *s, char *arg1, char *arg2) - -{ - char *ns; - ns = strchr(s,','); - if (ns) { - /* there was a comma arg2 should be the second arg*/ - *ns++ = '\0'; - while ((*arg2++ = *ns++) != '\0'); - } - else { - /* there was not a comma, so we should make sure that arg2 is \0 - lest something become confused. raj 2005-02-04 */ - *arg2 = '\0'; - }; - while ((*arg1++ = *s++) != '\0'); - -} - -/* given a string with possible values for setting an address family, - convert that into one of the AF_mumble values - AF_INET, AF_INET6, - AF_UNSPEC as apropriate. the family_string is compared in a - case-insensitive manner */ - -int -parse_address_family(char family_string[]) -{ - - char temp[10]; /* gotta love magic constants :) */ - - strncpy(temp,family_string,10); - - if (debug) { - fprintf(where, - "Attempting to parse address family from %s derived from %s\n", - temp, - family_string); - } -#if defined(AF_INET6) - if (strstr(temp,"6")) { - return(AF_INET6); - } -#endif - if (strstr(temp,"inet") || - strstr(temp,"4")) { - return(AF_INET); - } - if (strstr(temp,"unspec") || - strstr(temp,"0")) { - return(AF_UNSPEC); - } - fprintf(where, - "WARNING! %s not recognized as an address family, using AF_UNPSEC\n", - family_string); - fprintf(where, - "Are you sure netperf was configured for that address family?\n"); - fflush(where); - return(AF_UNSPEC); -} - - -void -set_defaults() -{ - - /* stuff to say where this test is going */ - strcpy(host_name,""); /* remote host name or ip addr */ - strcpy(local_host_name,""); /* we want it to be INADDR_ANY */ - strcpy(test_name,"TCP_STREAM"); /* which test to run */ - strncpy(test_port,"12865",PORTBUFSIZE); /* where is the test waiting */ - strncpy(local_test_port,"0",PORTBUFSIZE);/* INPORT_ANY as it were */ - address_family = AF_UNSPEC; - local_address_family = AF_UNSPEC; - - /* output controlling variables */ - debug = 0;/* debugging level */ - print_headers = 1;/* do print test headers */ - verbosity = 1;/* verbosity level */ - /* cpu variables */ - local_cpu_usage = 0;/* measure local cpu */ - remote_cpu_usage = 0;/* what do you think ;-) */ - - local_cpu_rate = (float)0.0; - remote_cpu_rate = (float)0.0; - - /* the end-test conditions for the tests - either transactions, bytes, */ - /* or time. different vars used for clarity - space is cheap ;-) */ - test_time = 10; /* test ends by time */ - test_bytes = 0; /* test ends on byte count */ - test_trans = 0; /* test ends on tran count */ - - /* the alignment conditions for the tests */ - local_recv_align = 8; /* alignment for local receives */ - local_send_align = 8; /* alignment for local sends */ - remote_recv_align = 8; /* alignment for remote receives*/ - remote_send_align = 8; /* alignment for remote sends */ - -#ifdef WANT_INTERVALS - /* rate controlling stuff */ - interval_usecs = 0; - interval_wate = 1; - interval_burst = 0; -#endif /* WANT_INTERVALS */ - -#ifdef DIRTY - /* dirty and clean cache stuff */ - loc_dirty_count = 0; - loc_clean_count = 0; - rem_dirty_count = 0; - rem_clean_count = 0; -#endif /* DIRTY */ - - /* some of the vairables for confidence intervals... */ - - confidence_level = 99; - iteration_min = 1; - iteration_max = 1; - interval = 0.05; /* five percent? */ - - no_control = 0; - strcpy(fill_file,""); -} - - -void -print_netserver_usage() -{ - fwrite(netserver_usage, sizeof(char), strlen(netserver_usage), stderr); -} - - -void -print_netperf_usage() -{ - fwrite(netperf_usage1, sizeof(char), strlen(netperf_usage1), stderr); - fwrite(netperf_usage2, sizeof(char), strlen(netperf_usage2), stderr); -} - -void -scan_cmd_line(int argc, char *argv[]) -{ - extern int optind; /* index of first unused arg */ - extern char *optarg; /* pointer to option string */ - - int c; - - char arg1[BUFSIZ], /* argument holders */ - arg2[BUFSIZ]; - - program = (char *)malloc(strlen(argv[0]) + 1); - if (program == NULL) { - printf("malloc(%d) failed!\n", strlen(argv[0]) + 1); - exit(1); - } - strcpy(program, argv[0]); - - /* Go through all the command line arguments and break them */ - /* out. For those options that take two parms, specifying only */ - /* the first will set both to that value. Specifying only the */ - /* second will leave the first untouched. To change only the */ - /* first, use the form first, (see the routine break_args.. */ - - while ((c= getopt(argc, argv, GLOBAL_CMD_LINE_ARGS)) != EOF) { - switch (c) { - case '?': - case 'h': - print_netperf_usage(); - exit(1); - case 'a': - /* set local alignments */ - break_args(optarg,arg1,arg2); - if (arg1[0]) { - local_send_align = convert(arg1); - } - if (arg2[0]) - local_recv_align = convert(arg2); - break; - case 'A': - /* set remote alignments */ - break_args(optarg,arg1,arg2); - if (arg1[0]) { - remote_send_align = convert(arg1); - } - if (arg2[0]) - remote_recv_align = convert(arg2); - break; - case 'c': - /* measure local cpu usage please. the user */ - /* may have specified the cpu rate as an */ - /* optional parm */ - if (argv[optind] && isdigit((unsigned char)argv[optind][0])){ - /* there was an optional parm */ - local_cpu_rate = (float)atof(argv[optind]); - optind++; - } - local_cpu_usage++; - break; - case 'C': - /* measure remote cpu usage please */ - if (argv[optind] && isdigit((unsigned char)argv[optind][0])){ - /* there was an optional parm */ - remote_cpu_rate = (float)atof(argv[optind]); - optind++; - } - remote_cpu_usage++; - break; - case 'd': - debug++; - break; - case 'D': -#if (defined WANT_DEMO) - demo_mode++; - if (argv[optind] && isdigit((unsigned char)argv[optind][0])){ - /* there was an optional parm */ - break_args_explicit(argv[optind],arg1,arg2); - optind++; - if (arg1[0]) { - demo_interval = atof(arg1) * 1000000.0; - } - if (arg2[0]) { - demo_units = convert(arg2); - } - } -#else - printf("Sorry, Demo Mode not configured into this netperf.\n"); - printf("please consider reconfiguring netperf with\n"); - printf("--enable-demo=yes and recompiling\n"); -#endif - break; - case 'f': - /* set the thruput formatting */ - libfmt = *optarg; - break; - case 'F': - /* set the fill_file variable for pre-filling buffers */ - strcpy(fill_file,optarg); - break; - case 'i': - /* set the iterations min and max for confidence intervals */ - break_args(optarg,arg1,arg2); - if (arg1[0]) { - iteration_max = convert(arg1); - } - if (arg2[0] ) { - iteration_min = convert(arg2); - } - /* if the iteration_max is < iteration_min make iteration_max - equal iteration_min */ - if (iteration_max < iteration_min) iteration_max = iteration_min; - /* limit minimum to 3 iterations */ - if (iteration_max < 3) iteration_max = 3; - if (iteration_min < 3) iteration_min = 3; - /* limit maximum to 30 iterations */ - if (iteration_max > 30) iteration_max = 30; - if (iteration_min > 30) iteration_min = 30; - break; - case 'I': - /* set the confidence level (95 or 99) and width */ - break_args(optarg,arg1,arg2); - if (arg1[0]) { - confidence_level = convert(arg1); - } - if((confidence_level != 95) && (confidence_level != 99)){ - printf("Only 95%% and 99%% confidence level is supported\n"); - exit(1); - } - if (arg2[0] ) { - interval = (double) convert(arg2)/100; - } - /* make sure that iteration_min and iteration_max are at least - at a reasonable default value. if a -i option has previously - been parsed, these will no longer be 1, so we can check - against 1 */ - if (iteration_min == 1) iteration_min = 3; - if (iteration_max == 1) iteration_max = 10; - - break; - case 'k': - /* local dirty and clean counts */ -#ifdef DIRTY - break_args(optarg,arg1,arg2); - if (arg1[0]) { - loc_dirty_count = convert(arg1); - } - if (arg2[0] ) { - loc_clean_count = convert(arg2); - } -#else - printf("I don't know how to get dirty.\n"); -#endif /* DIRTY */ - break; - case 'K': - /* remote dirty and clean counts */ -#ifdef DIRTY - break_args(optarg,arg1,arg2); - if (arg1[0]) { - rem_dirty_count = convert(arg1); - } - if (arg2[0] ) { - rem_clean_count = convert(arg2); - } -#else - printf("I don't know how to get dirty.\n"); -#endif /* DIRTY */ - break; - case 'n': - shell_num_cpus = atoi(optarg); - break; - case 'N': - no_control = 1; - break; - case 'o': - /* set the local offsets */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - local_send_offset = convert(arg1); - if (arg2[0]) - local_recv_offset = convert(arg2); - break; - case 'O': - /* set the remote offsets */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - remote_send_offset = convert(arg1); - if (arg2[0]) - remote_recv_offset = convert(arg2); - break; - case 'P': - /* to print or not to print, that is */ - /* the header question */ - print_headers = convert(optarg); - break; - case 'r': - /* the user wishes that we declare confidence when hit on the - result even if not yet reached on CPU utilization. only - meaningful if cpu util is enabled */ - result_confidence_only = 1; - break; - case 't': - /* set the test name */ - strcpy(test_name,optarg); - break; - case 'T': - /* We want to set the processor on which netserver or netperf */ - /* will run */ - break_args(optarg,arg1,arg2); - if (arg1[0]) { - local_proc_affinity = convert(arg1); - bind_to_specific_processor(local_proc_affinity,0); - } - if (arg2[0]) { - remote_proc_affinity = convert(arg2); - } - cpu_binding_requested = 1; - break; - case 'W': - /* set the "width" of the user space data buffer ring. This will */ - /* be the number of send_size buffers malloc'd in the tests */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - send_width = convert(arg1); - if (arg2[0]) - recv_width = convert(arg2); - break; - case 'l': - /* determine test end conditions */ - /* assume a timed test */ - test_time = convert(optarg); - test_bytes = test_trans = 0; - if (test_time < 0) { - test_bytes = -1 * test_time; - test_trans = test_bytes; - test_time = 0; - } - break; - case 'v': - /* say how much to say */ - verbosity = convert(optarg); - break; - case 'p': - /* specify an alternate port number we use break_args_explicit - here to maintain backwards compatibility with previous - generations of netperf where having a single value did not - set both remote _and_ local port number. raj 2005-02-04 */ - break_args_explicit(optarg,arg1,arg2); - if (arg1[0]) - strncpy(test_port,arg1,PORTBUFSIZE); - if (arg2[0]) - strncpy(local_test_port,arg2,PORTBUFSIZE); - break; - case 'H': - /* save-off the host identifying information, use - break_args_explicit since passing just one value should not - set both */ - break_args_explicit(optarg,arg1,arg2); - if (arg1[0]) - strncpy(host_name,arg1,sizeof(host_name)); - if (arg2[0]) - address_family = parse_address_family(arg2); - break; - case 'L': - /* save-off the local control socket addressing information. use - break_args_explicit since passing just one value should not - set both */ - break_args_explicit(optarg,arg1,arg2); - if (arg1[0]) - strncpy(local_host_name,arg1,sizeof(local_host_name)); - if (arg2[0]) - local_address_family = parse_address_family(arg2); - break; - case 'w': - /* We want to send requests at a certain wate. */ - /* Remember that there are 1000000 usecs in a */ - /* second, and that the packet rate is */ - /* expressed in packets per millisecond. */ -#ifdef WANT_INTERVALS - interval_usecs = convert_timespec(optarg); - interval_wate = interval_usecs / 1000; -#else - fprintf(where, - "Packet rate control is not compiled in.\n"); -#endif - break; - case 'b': - /* we want to have a burst so many packets per */ - /* interval. */ -#ifdef WANT_INTERVALS - interval_burst = convert(optarg); -#else - fprintf(where, - "Packet burst size is not compiled in. \n"); -#endif /* WANT_INTERVALS */ - break; - case 'B': - result_brand = malloc(strlen(optarg)+1); - if (NULL != result_brand) { - strcpy(result_brand,optarg); - } - else { - fprintf(where, - "Unable to malloc space for result brand\n"); - } - break; - case '4': - address_family = AF_INET; - local_address_family = AF_INET; - break; - case '6': -#if defined(AF_INET6) - address_family = AF_INET6; - local_address_family = AF_INET6; -#else - printf("This netperf was not compiled on an IPv6 capable system!\n"); - exit(-1); -#endif - break; - case 'V': - printf("Netperf version %s\n",NETPERF_VERSION); - exit(0); - break; - }; - } - /* ok, what should our default hostname and local binding info be? - */ - if ('\0' == host_name[0]) { - /* host_name was not set */ - switch (address_family) { - case AF_INET: - strcpy(host_name,"localhost"); - break; - case AF_UNSPEC: - /* what to do here? case it off the local_address_family I - suppose */ - switch (local_address_family) { - case AF_INET: - case AF_UNSPEC: - strcpy(host_name,"localhost"); - break; -#if defined(AF_INET6) - case AF_INET6: - strcpy(host_name,"::1"); - break; -#endif - default: - printf("Netperf does not understand %d as an address family\n", - address_family); - exit(-1); - } - break; -#if defined(AF_INET6) - case AF_INET6: - strcpy(host_name,"::1"); - break; -#endif - default: - printf("Netperf does not understand %d as an address family\n", - address_family); - exit(-1); - } - } - - /* now, having established the name to which the control will - connect, from what should it come? */ - if ('\0' == local_host_name[0]) { - switch (local_address_family) { - case AF_INET: - strcpy(local_host_name,"0.0.0.0"); - break; - case AF_UNSPEC: - switch (address_family) { - case AF_INET: - case AF_UNSPEC: - strcpy(local_host_name,"0.0.0.0"); - break; -#if defined(AF_INET6) - case AF_INET6: - strcpy(local_host_name,"::0"); - break; -#endif - default: - printf("Netperf does not understand %d as an address family\n", - address_family); - exit(-1); - } - break; -#if defined(AF_INET6) - case AF_INET6: - strcpy(local_host_name,"::0"); - break; -#endif - default: - printf("Netperf does not understand %d as an address family\n", - address_family); - exit(-1); - } - } - - /* so, if we aren't even going to establish a control connection we - should set certain "remote" settings to reflect this, regardless - of what else may have been set on the command line */ - if (no_control) { - remote_recv_align = -1; - remote_send_align = -1; - remote_send_offset = -1; - remote_recv_offset = -1; - remote_cpu_rate = (float)-1.0; - remote_cpu_usage = 0; - } - - /* parsing test-specific options used to be conditional on there - being a "--" in the option stream. however, some of the tests - have other initialization happening in their "scan" routines so we - want to call them regardless. raj 2005-02-08 */ - if ((strcasecmp(test_name,"TCP_STREAM") == 0) || -#ifdef HAVE_ICSC_EXS - (strcasecmp(test_name,"EXS_TCP_STREAM") == 0) || -#endif /* HAVE_ICSC_EXS */ -#ifdef HAVE_SENDFILE - (strcasecmp(test_name,"TCP_SENDFILE") == 0) || -#endif /* HAVE_SENDFILE */ - (strcasecmp(test_name,"TCP_MAERTS") == 0) || - (strcasecmp(test_name,"TCP_RR") == 0) || - (strcasecmp(test_name,"TCP_CRR") == 0) || - (strcasecmp(test_name,"TCP_CC") == 0) || -#ifdef DO_1644 - (strcasecmp(test_name,"TCP_TRR") == 0) || -#endif /* DO_1644 */ -#ifdef DO_NBRR - (strcasecmp(test_name,"TCP_TRR") == 0) || -#endif /* DO_NBRR */ - (strcasecmp(test_name,"UDP_STREAM") == 0) || - (strcasecmp(test_name,"UDP_RR") == 0)) - { - scan_sockets_args(argc, argv); - } - -#ifdef WANT_DLPI - else if ((strcasecmp(test_name,"DLCO_RR") == 0) || - (strcasecmp(test_name,"DLCL_RR") == 0) || - (strcasecmp(test_name,"DLCO_STREAM") == 0) || - (strcasecmp(test_name,"DLCL_STREAM") == 0)) - { - scan_dlpi_args(argc, argv); - } -#endif /* WANT_DLPI */ - -#ifdef WANT_UNIX - else if ((strcasecmp(test_name,"STREAM_RR") == 0) || - (strcasecmp(test_name,"DG_RR") == 0) || - (strcasecmp(test_name,"STREAM_STREAM") == 0) || - (strcasecmp(test_name,"DG_STREAM") == 0)) - { - scan_unix_args(argc, argv); - } -#endif /* WANT_UNIX */ - -#ifdef WANT_XTI - else if ((strcasecmp(test_name,"XTI_TCP_RR") == 0) || - (strcasecmp(test_name,"XTI_TCP_STREAM") == 0) || - (strcasecmp(test_name,"XTI_UDP_RR") == 0) || - (strcasecmp(test_name,"XTI_UDP_STREAM") == 0)) - { - scan_xti_args(argc, argv); - } -#endif /* WANT_XTI */ - -#ifdef WANT_SCTP - else if ((strcasecmp(test_name,"SCTP_STREAM") == 0) || - (strcasecmp(test_name,"SCTP_RR") == 0) || - (strcasecmp(test_name,"SCTP_STREAM_MANY") == 0) || - (strcasecmp(test_name,"SCTP_RR_MANY") == 0)) - { - scan_sctp_args(argc, argv); - } -#endif - -#ifdef WANT_SDP - else if((strcasecmp(test_name,"SDP_STREAM") == 0) || - (strcasecmp(test_name,"SDP_MAERTS") == 0) || - (strcasecmp(test_name,"SDP_RR") == 0)) - { - scan_sdp_args(argc, argv); - } -#endif - - /* what is our default value for the output units? if the test - name contains "RR" or "rr" or "Rr" or "rR" then the default is - 'x' for transactions. otherwise it is 'm' for megabits - (10^6) */ - - if ('?' == libfmt) { - /* we use a series of strstr's here because not everyone has - strcasestr and I don't feel like up or downshifting text */ - if ((strstr(test_name,"RR")) || - (strstr(test_name,"rr")) || - (strstr(test_name,"Rr")) || - (strstr(test_name,"rR"))) { - libfmt = 'x'; - } - else { - libfmt = 'm'; - } - } - else if ('x' == libfmt) { - /* now, a format of 'x' makes no sense for anything other than - an RR test. if someone has been silly enough to try to set - that, we will reset it silently to default - namely 'm' */ - if ((strstr(test_name,"RR") == NULL) && - (strstr(test_name,"rr") == NULL) && - (strstr(test_name,"Rr") == NULL) && - (strstr(test_name,"rR") == NULL)) { - libfmt = 'm'; - } - } -} - - -void -dump_globals() -{ - printf("Program name: %s\n", program); - printf("Local send alignment: %d\n",local_send_align); - printf("Local recv alignment: %d\n",local_recv_align); - printf("Remote send alignment: %d\n",remote_send_align); - printf("Remote recv alignment: %d\n",remote_recv_align); - printf("Report local CPU %d\n",local_cpu_usage); - printf("Report remote CPU %d\n",remote_cpu_usage); - printf("Verbosity: %d\n",verbosity); - printf("Debug: %d\n",debug); - printf("Port: %s\n",test_port); - printf("Test name: %s\n",test_name); - printf("Test bytes: %d Test time: %d Test trans: %d\n", - test_bytes, - test_time, - test_trans); - printf("Host name: %s\n",host_name); - printf("\n"); -} diff --git a/netsh.h b/netsh.h deleted file mode 100644 index e99883b..0000000 --- a/netsh.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - Copyright (C) 1993,1995 Hewlett-Packard Company -*/ - -/* libraried performance include file */ -/* the define NOPERFEXTERN tels us not to re-define all the */ - -/* defines and defaults */ -#define HOSTNAMESIZE 255 -#define PORTBUFSIZE 10 -#define DEFAULT_SIZE 32768 -#define HOST_NAME "127.0.0.1" -#define TEST_PORT "12865" - -/* output controlling variables */ -#define DEBUG 0 /* debugging level */ -#define VERBOSITY 0 /* verbosity level */ - -/* the end-test conditions for the tests - either transactions, bytes, */ -/* or time. different vars used for clarity - space is cheap ;-) */ -#define TEST_TIME 10 /* test ends by time */ -#define TEST_BYTES 0 /* test ends on byte count */ -#define TEST_TRANS 0 /* test ends on tran count */ - -/* the alignment conditions for the tests */ -#define LOC_RECV_ALIGN 4 /* alignment for local receives */ -#define LOC_SEND_ALIGN 4 /* alignment for local sends */ -#define REM_RECV_ALIGN 4 /* alignment for remote receive */ -#define REM_SEND_ALIGN 4 /* alignment for remote sends */ - -/* misc defines for the hell of it */ -#ifndef MAXLONG -#define MAXLONG 4294967295UL -#endif /* MAXLONG */ - -#ifndef NETSH -extern char *program; /* program invocation name */ - -/* stuff to say where this test is going */ -extern char host_name[HOSTNAMESIZE];/* remote host name or ip addr */ -extern char local_host_name[HOSTNAMESIZE]; -extern char test_port[PORTBUFSIZE]; /* where is the test waiting */ -extern char local_test_port[PORTBUFSIZE]; -extern int address_family; -extern int local_address_family; -extern int parse_address_family(char family_string[]); -extern void set_defaults(); -extern void scan_cmd_line(int argc, char *argv[]); -extern void dump_globals(); -extern void break_args(char *s, char *arg1, char *arg2); -extern void break_args_explicit(char *s, char *arg1, char *arg2); -extern void print_netserver_usage(); - -/* output controlling variables */ -extern int - debug, /* debugging level */ - print_headers, /* do/don't print test headers */ - verbosity; /* verbosity level */ - -/* the end-test conditions for the tests - either transactions, bytes, */ -/* or time. different vars used for clarity - space is cheap ;-) */ -extern int - test_time, /* test ends by time */ - test_len_ticks, - test_bytes, /* test ends on byte count */ - test_trans; /* test ends on tran count */ - -/* the alignment conditions for the tests */ -extern int - local_recv_align, /* alignment for local receives */ - local_send_align, /* alignment for local sends */ - remote_recv_align, /* alignment for remote receives */ - remote_send_align, /* alignment for remote sends */ - local_send_offset, - local_recv_offset, - remote_send_offset, - remote_recv_offset; - -#if defined(WANT_INTERVALS) || defined(WANT_DEMO) -extern int interval_usecs; -extern int interval_wate; -extern int interval_burst; - -extern int demo_mode; -extern double demo_interval; -extern double demo_units; -extern double units_this_tick; -#endif - -#ifdef DIRTY -extern int rem_dirty_count; -extern int rem_clean_count; -extern int loc_dirty_count; -extern int loc_clean_count; -#endif /* DIRTY */ - -/* stuff for confidence intervals */ - -extern int confidence_level; -extern int iteration_min; -extern int iteration_max; -extern int result_confidence_only; -extern double interval; - -extern int cpu_binding_requested; - -/* stuff to controll the bufferspace "width" */ -extern int send_width; -extern int recv_width; - -/* address family */ -extern int af; - -/* different options for other things */ -extern int - local_cpu_usage, - remote_cpu_usage; - -extern float - local_cpu_rate, - remote_cpu_rate; - -extern int - shell_num_cpus; - -extern char - test_name[BUFSIZ]; - -extern char - fill_file[BUFSIZ]; - -extern char * - result_brand; - -extern int - no_control; - -#ifdef WANT_DLPI - -extern int - loc_ppa, - rem_ppa; - -extern int - dlpi_sap; - -#endif /* WANT_DLPI */ - -#endif diff --git a/nettest_bsd.c b/nettest_bsd.c deleted file mode 100644 index 27092f3..0000000 --- a/nettest_bsd.c +++ /dev/null @@ -1,12333 +0,0 @@ -#ifndef lint -char nettest_id[]="\ -@(#)nettest_bsd.c (c) Copyright 1993-2004 Hewlett-Packard Co. Version 2.4.3"; -#endif /* lint */ - - -/****************************************************************/ -/* */ -/* nettest_bsd.c */ -/* */ -/* the BSD sockets parsing routine... */ -/* ...with the addition of Windows NT, this is now also */ -/* a Winsock test... sigh :) */ -/* */ -/* scan_sockets_args() */ -/* */ -/* the actual test routines... */ -/* */ -/* send_tcp_stream() perform a tcp stream test */ -/* recv_tcp_stream() */ -/* send_tcp_maerts() perform a tcp stream test */ -/* recv_tcp_maerts() in the other direction */ -/* send_tcp_rr() perform a tcp request/response */ -/* recv_tcp_rr() */ -/* send_tcp_conn_rr() an RR test including connect */ -/* recv_tcp_conn_rr() */ -/* send_tcp_cc() a connect/disconnect test with */ -/* recv_tcp_cc() no RR */ -/* send_udp_stream() perform a udp stream test */ -/* recv_udp_stream() */ -/* send_udp_rr() perform a udp request/response */ -/* recv_udp_rr() */ -/* loc_cpu_rate() determine the local cpu maxrate */ -/* rem_cpu_rate() find the remote cpu maxrate */ -/* */ -/****************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#if HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif -#if HAVE_SYS_STAT_H -# include <sys/stat.h> -#endif -#if STDC_HEADERS -# include <stdlib.h> -# include <stddef.h> -#else -# if HAVE_STDLIB_H -# include <stdlib.h> -# endif -#endif -#if HAVE_STRING_H -# if !STDC_HEADERS && HAVE_MEMORY_H -# include <memory.h> -# endif -# include <string.h> -#endif -#if HAVE_STRINGS_H -# include <strings.h> -#endif -#if HAVE_INTTYPES_H -# include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# endif -#endif -#if HAVE_UNISTD_H -# include <unistd.h> -#endif - -#include <fcntl.h> -#ifndef WIN32 -#include <errno.h> -#include <signal.h> -#endif - -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif - -#ifdef NOSTDLIBH -#include <malloc.h> -#endif /* NOSTDLIBH */ - -#ifndef WIN32 -#if !defined(__VMS) -#include <sys/ipc.h> -#endif /* !defined(__VMS) */ -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <netdb.h> -#else /* WIN32 */ -#include <process.h> -#define netperf_socklen_t socklen_t -#include <winsock2.h> - -/* while it is unlikely that anyone running Windows 2000 or NT 4 is - going to be trying to compile this, if they are they will want to - define DONT_IPV6 in the sources file */ -#ifndef DONT_IPV6 -#include <ws2tcpip.h> -#endif -#include <windows.h> - -#define sleep(x) Sleep((x)*1000) - -#define __func__ __FUNCTION__ -#endif /* WIN32 */ - -/* We don't want to use bare constants in the shutdown() call. In the - extremely unlikely event that SHUT_WR isn't defined, we will define - it to the value we used to be passing to shutdown() anyway. raj - 2007-02-08 */ -#if !defined(SHUT_WR) -#define SHUT_WR 1 -#endif - -#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO) -# include "missing/getaddrinfo.h" -#endif - -#include "netlib.h" -#include "netsh.h" -#include "nettest_bsd.h" - -#if defined(WANT_HISTOGRAM) || defined(WANT_DEMO) -#include "hist.h" -#endif /* WANT_HISTOGRAM */ - -/* make first_burst_size unconditional so we can use it easily enough - when calculating transaction latency for the TCP_RR test. raj - 2007-06-08 */ -int first_burst_size=0; - -#if defined(HAVE_SENDFILE) && (defined(__linux) || defined(__sun__)) -#include <sys/sendfile.h> -#endif /* HAVE_SENDFILE && (__linux || __sun__) */ - - - -/* these variables are specific to the BSD sockets tests, but can - * be used elsewhere if needed. They are externed through nettest_bsd.h - */ - -int - rss_size_req = -1, /* requested remote socket send buffer size */ - rsr_size_req = -1, /* requested remote socket recv buffer size */ - rss_size, /* remote socket send buffer size */ - rsr_size, /* remote socket recv buffer size */ - lss_size_req = -1, /* requested local socket send buffer size */ - lsr_size_req = -1, /* requested local socket recv buffer size */ - lss_size, /* local socket send buffer size */ - lsr_size, /* local socket recv buffer size */ - req_size = 1, /* request size */ - rsp_size = 1, /* response size */ - send_size, /* how big are individual sends */ - recv_size; /* how big are individual receives */ - -static int confidence_iteration; -static char local_cpu_method; -static char remote_cpu_method; - -/* these will control the width of port numbers we try to use in the */ -/* TCP_CRR and/or TCP_TRR tests. raj 3/95 */ -static int client_port_min = 5000; -static int client_port_max = 65535; - - /* different options for the sockets */ - -int - loc_nodelay, /* don't/do use NODELAY locally */ - rem_nodelay, /* don't/do use NODELAY remotely */ -#ifdef TCP_CORK - loc_tcpcork=0, /* don't/do use TCP_CORK locally */ - rem_tcpcork=0, /* don't/do use TCP_CORK remotely */ -#endif /* TCP_CORK */ - loc_sndavoid, /* avoid send copies locally */ - loc_rcvavoid, /* avoid recv copies locally */ - rem_sndavoid, /* avoid send copies remotely */ - rem_rcvavoid, /* avoid recv_copies remotely */ - local_connected = 0, /* local socket type, connected/non-connected */ - remote_connected = 0; /* remote socket type, connected/non-connected */ - -#ifdef WANT_HISTOGRAM -#ifdef HAVE_GETHRTIME -static hrtime_t time_one; -static hrtime_t time_two; -#elif HAVE_GET_HRT -#include "hrt.h" -static hrt_t time_one; -static hrt_t time_two; -#elif defined(WIN32) -static LARGE_INTEGER time_one; -static LARGE_INTEGER time_two; -#else -static struct timeval time_one; -static struct timeval time_two; -#endif /* HAVE_GETHRTIME */ -static HIST time_hist; -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_INTERVALS -int interval_count; -#ifndef WANT_SPIN -sigset_t signal_set; -#define INTERVALS_INIT() \ - if (interval_burst) { \ - /* zero means that we never pause, so we never should need the \ - interval timer. we used to use it for demo mode, but we deal \ - with that with a variant on watching the clock rather than \ - waiting for a timer. raj 2006-02-06 */ \ - start_itimer(interval_wate); \ - } \ - interval_count = interval_burst; \ - /* get the signal set for the call to sigsuspend */ \ - if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { \ - fprintf(where, \ - "%s: unable to get sigmask errno %d\n", \ - __func__, \ - errno); \ - fflush(where); \ - exit(1); \ - } - -#define INTERVALS_WAIT() \ - /* in this case, the interval count is the count-down couter \ - to decide to sleep for a little bit */ \ - if ((interval_burst) && (--interval_count == 0)) { \ - /* call sigsuspend and wait for the interval timer to get us \ - out */ \ - if (debug > 1) { \ - fprintf(where,"about to suspend\n"); \ - fflush(where); \ - } \ - if (sigsuspend(&signal_set) == EFAULT) { \ - fprintf(where, \ - "%s: fault with sigsuspend.\n", \ - __func__); \ - fflush(where); \ - exit(1); \ - } \ - interval_count = interval_burst; \ - } -#else -/* first out timestamp */ -#ifdef HAVE_GETHRTIME -static hrtime_t intvl_one; -static hrtime_t intvl_two; -static hrtime_t *intvl_one_ptr = &intvl_one; -static hrtime_t *intvl_two_ptr = &intvl_two; -static hrtime_t *temp_intvl_ptr = &intvl_one; -#elif defined(WIN32) -static LARGE_INTEGER intvl_one; -static LARGE_INTEGER intvl_two; -static LARGE_INTEGER *intvl_one_ptr = &intvl_one; -static LARGE_INTEGER *intvl_two_ptr = &intvl_two; -static LARGE_INTEGER *temp_intvl_ptr = &intvl_one; -#else -static struct timeval intvl_one; -static struct timeval intvl_two; -static struct timeval *intvl_one_ptr = &intvl_one; -static struct timeval *intvl_two_ptr = &intvl_two; -static struct timeval *temp_intvl_ptr = &intvl_one; -#endif - -#define INTERVALS_INIT() \ - if (interval_burst) { \ - HIST_timestamp(intvl_one_ptr); \ - } \ - interval_count = interval_burst; \ - -#define INTERVALS_WAIT() \ - /* in this case, the interval count is the count-down couter \ - to decide to sleep for a little bit */ \ - if ((interval_burst) && (--interval_count == 0)) { \ - /* call sigsuspend and wait for the interval timer to get us \ - out */ \ - if (debug > 1) { \ - fprintf(where,"about to spin suspend\n"); \ - fflush(where); \ - } \ - HIST_timestamp(intvl_two_ptr); \ - while(delta_micro(intvl_one_ptr,intvl_two_ptr) < interval_usecs) { \ - HIST_timestamp(intvl_two_ptr); \ - } \ - temp_intvl_ptr = intvl_one_ptr; \ - intvl_one_ptr = intvl_two_ptr; \ - intvl_two_ptr = temp_intvl_ptr; \ - interval_count = interval_burst; \ - } -#endif -#endif - -#ifdef WANT_DEMO -#ifdef HAVE_GETHRTIME -static hrtime_t demo_one; -static hrtime_t demo_two; -static hrtime_t *demo_one_ptr = &demo_one; -static hrtime_t *demo_two_ptr = &demo_two; -static hrtime_t *temp_demo_ptr = &demo_one; -#elif defined(WIN32) -static LARGE_INTEGER demo_one; -static LARGE_INTEGER demo_two; -static LARGE_INTEGER *demo_one_ptr = &demo_one; -static LARGE_INTEGER *demo_two_ptr = &demo_two; -static LARGE_INTEGER *temp_demo_ptr = &demo_one; -#else -static struct timeval demo_one; -static struct timeval demo_two; -static struct timeval *demo_one_ptr = &demo_one; -static struct timeval *demo_two_ptr = &demo_two; -static struct timeval *temp_demo_ptr = &demo_one; -#endif - -/* for a _STREAM test, "a" should be lss_size and "b" should be - rsr_size. for a _MAERTS test, "a" should be lsr_size and "b" should - be rss_size. raj 2005-04-06 */ -#define DEMO_STREAM_SETUP(a,b) \ - if ((demo_mode) && (demo_units == 0)) { \ - /* take our default value of demo_units to be the larger of \ - twice the remote's SO_RCVBUF or twice our SO_SNDBUF */ \ - if (a > b) { \ - demo_units = 2*a; \ - } \ - else { \ - demo_units = 2*b; \ - } \ - } - -#define DEMO_STREAM_INTERVAL(units) \ - if (demo_mode) { \ - double actual_interval; \ - units_this_tick += units; \ - if (units_this_tick >= demo_units) { \ - /* time to possibly update demo_units and maybe output an \ - interim result */ \ - HIST_timestamp(demo_two_ptr); \ - actual_interval = delta_micro(demo_one_ptr,demo_two_ptr); \ - /* we always want to fine-tune demo_units here whether we \ - emit an interim result or not. if we are short, this \ - will lengthen demo_units. if we are long, this will \ - shorten it */ \ - demo_units = demo_units * (demo_interval / actual_interval); \ - if (actual_interval >= demo_interval) { \ - /* time to emit an interim result */ \ - fprintf(where, \ - "Interim result: %7.2f %s/s over %.2f seconds\n", \ - calc_thruput_interval(units_this_tick, \ - actual_interval/1000000.0), \ - format_units(), \ - actual_interval/1000000.0); \ - fflush(where); \ - units_this_tick = 0.0; \ - /* now get a new starting timestamp. we could be clever \ - and swap pointers - the math we do probably does not \ - take all that long, but for now this will suffice */ \ - temp_demo_ptr = demo_one_ptr; \ - demo_one_ptr = demo_two_ptr; \ - demo_two_ptr = temp_demo_ptr; \ - } \ - } \ - } - -#define DEMO_RR_SETUP(a) \ - if ((demo_mode) && (demo_units == 0)) { \ - /* take whatever we are given */ \ - demo_units = a; \ - } - -#define DEMO_RR_INTERVAL(units) \ - if (demo_mode) { \ - double actual_interval; \ - units_this_tick += units; \ - if (units_this_tick >= demo_units) { \ - /* time to possibly update demo_units and maybe output an \ - interim result */ \ - HIST_timestamp(demo_two_ptr); \ - actual_interval = delta_micro(demo_one_ptr,demo_two_ptr); \ - /* we always want to fine-tune demo_units here whether we \ - emit an interim result or not. if we are short, this \ - will lengthen demo_units. if we are long, this will \ - shorten it */ \ - demo_units = demo_units * (demo_interval / actual_interval); \ - if (actual_interval >= demo_interval) { \ - /* time to emit an interim result */ \ - fprintf(where, \ - "Interim result: %.2f %s/s over %.2f seconds\n", \ - units_this_tick / (actual_interval/1000000.0), \ - "Trans", \ - actual_interval/1000000.0); \ - units_this_tick = 0.0; \ - /* now get a new starting timestamp. we could be clever \ - and swap pointers - the math we do probably does not \ - take all that long, but for now this will suffice */ \ - temp_demo_ptr = demo_one_ptr; \ - demo_one_ptr = demo_two_ptr; \ - demo_two_ptr = temp_demo_ptr; \ - } \ - } \ - } -#endif - -char sockets_usage[] = "\n\ -Usage: netperf [global options] -- [test options] \n\ -\n\ -TCP/UDP BSD Sockets Test Options:\n\ - -b number Send number requests at start of _RR tests\n\ - -C Set TCP_CORK when available\n\ - -D [L][,R] Set TCP_NODELAY locally and/or remotely (TCP_*)\n\ - -h Display this text\n\ - -H name,fam Use name (or IP) and family as target of data connection\n\ - -L name,fam Use name (or IP) and family as source of data connection\n\ - -m bytes Set the send size (TCP_STREAM, UDP_STREAM)\n\ - -M bytes Set the recv size (TCP_STREAM, UDP_STREAM)\n\ - -n Use the connected socket for UDP locally\n\ - -N Use the connected socket for UDP remotely\n\ - -p min[,max] Set the min/max port numbers for TCP_CRR, TCP_TRR\n\ - -P local[,remote] Set the local/remote port for the data socket\n\ - -r req,[rsp] Set request/response sizes (TCP_RR, UDP_RR)\n\ - -s send[,recv] Set local socket send/recv buffer sizes\n\ - -S send[,recv] Set remote socket send/recv buffer sizes\n\ - -4 Use AF_INET (eg IPv4) on both ends of the data conn\n\ - -6 Use AF_INET6 (eg IPv6) on both ends of the data conn\n\ -\n\ -For those options taking two parms, at least one must be specified;\n\ -specifying one value without a comma will set both parms to that\n\ -value, specifying a value with a leading comma will set just the second\n\ -parm, a value with a trailing comma will set just the first. To set\n\ -each parm to unique values, specify both and separate them with a\n\ -comma.\n"; - - - -/* these routines convert between the AF address space and the NF - address space since the numeric values of AF_mumble are not the - same across the platforms. raj 2005-02-08 */ - -int -nf_to_af(int nf) { - switch(nf) { - case NF_INET: - return AF_INET; - break; - case NF_UNSPEC: - return AF_UNSPEC; - break; - case NF_INET6: -#if defined(AF_INET6) - return AF_INET6; -#else - return AF_UNSPEC; -#endif - break; - default: - return AF_UNSPEC; - break; - } -} - -int -af_to_nf(int af) { - - switch(af) { - case AF_INET: - return NF_INET; - break; - case AF_UNSPEC: - return NF_UNSPEC; - break; -#if defined(AF_INET6) - case AF_INET6: - return NF_INET6; - break; -#endif - default: - return NF_UNSPEC; - break; - } -} - - - /* This routine is intended to retrieve interesting aspects of tcp */ - /* for the data connection. at first, it attempts to retrieve the */ - /* maximum segment size. later, it might be modified to retrieve */ - /* other information, but it must be information that can be */ - /* retrieved quickly as it is called during the timing of the test. */ - /* for that reason, a second routine may be created that can be */ - /* called outside of the timing loop */ -static -void -get_tcp_info(SOCKET socket, int *mss) -{ - -#ifdef TCP_MAXSEG - netperf_socklen_t sock_opt_len; - - sock_opt_len = sizeof(netperf_socklen_t); - if (getsockopt(socket, - getprotobyname("tcp")->p_proto, - TCP_MAXSEG, - (char *)mss, - &sock_opt_len) == SOCKET_ERROR) { - fprintf(where, - "netperf: get_tcp_info: getsockopt TCP_MAXSEG: errno %d\n", - errno); - fflush(where); - *mss = -1; - } -#else - *mss = -1; -#endif /* TCP_MAXSEG */ -} - - -/* return a pointer to a completed addrinfo chain - prefer - data_address to controlhost and utilize the specified address - family */ - -struct addrinfo * -complete_addrinfo(char *controlhost, char *data_address, char *port, int family, int type, int protocol, int flags) -{ - struct addrinfo hints; - struct addrinfo *res; - struct addrinfo *temp_res; - -#define CHANGED_SOCK_TYPE 0x1 -#define CHANGED_PROTOCOL 0x2 -#define CHANGED_SCTP 0x4 - int change_info = 0; - static int change_warning_displayed = 0; - - int count = 0; - int error = 0; - - char *hostname; - - /* take data-address over controlhost */ - if (data_address) - hostname = data_address; - else - hostname = controlhost; - - if (debug) { - fprintf(where, - "complete_addrinfo using hostname %s port %s family %s type %s prot %s flags 0x%x\n", - hostname, - port, - inet_ftos(family), - inet_ttos(type), - inet_ptos(protocol), - flags); - fflush(where); - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = family; - hints.ai_socktype = type; - hints.ai_protocol = protocol; - hints.ai_flags = flags|AI_CANONNAME; - - count = 0; - do { - error = getaddrinfo((char *)hostname, - (char *)port, - &hints, - &res); - count += 1; - if (error == EAI_AGAIN) { - if (debug) { - fprintf(where,"Sleeping on getaddrinfo EAI_AGAIN\n"); - fflush(where); - } - sleep(1); - } - /* while you see this kludge first, it is actually the second, the - first being the one for Solaris below. The need for this kludge - came after implementing the Solaris broken getaddrinfo kludge - - now we see a kludge in Linux getaddrinfo where if it is given - SOCK_STREAM and IPPROTO_SCTP it barfs with a -7 - EAI_SOCKTYPE. so, we check if the error was EAI_SOCKTYPE and if - we were asking for IPPROTO_SCTP and if so, kludge, again... raj - 2008-10-13 */ -#ifdef WANT_SCTP - if (EAI_SOCKTYPE == error -#ifdef EAI_BADHINTS - || EAI_BADHINTS == error -#endif - ) { - /* we ass-u-me this is the Linux getaddrinfo bug, clear the - hints.ai_protocol field, and set some state "remembering" - that we did this so the code for the Solaris kludge can do - the fix-up for us. also flip error over to EAI_AGAIN and - make sure we don't "count" this time around the loop. */ - hints.ai_protocol = 0; - error = EAI_AGAIN; - count -= 1; - change_info |= CHANGED_SCTP; - } -#endif - } while ((error == EAI_AGAIN) && (count <= 5)); - - if (error) { - fprintf(where, - "complete_addrinfo: could not resolve '%s' port '%s' af %d", - hostname, - port, - family); - fprintf(where, - "\n\tgetaddrinfo returned %d %s\n", - error, - gai_strerror(error)); - fflush(where); - exit(-1); - } - - /* there exists at least one platform - Solaris 10 - that does not - seem to completely honor the ai_protocol and/or ai_socktype one - sets in the hints parm to the getaddrinfo call. so, we need to - walk the list of entries returned and if either of those do not - match what we asked for, we need to go ahead and set them - "correctly" this is based in part on some earlier SCTP-only code - from previous revisions. raj 2006-10-09 */ - - temp_res = res; - - while (temp_res) { - - if ((type) && - (temp_res->ai_socktype != type)) { - change_info |= CHANGED_SOCK_TYPE; - if (debug) { - fprintf(where, - "WARNING! Changed bogus getaddrinfo socket type %d to %d\n", - temp_res->ai_socktype, - type); - fflush(where); - } - temp_res->ai_socktype = type; - } - - if ((protocol) && - (temp_res->ai_protocol != protocol)) { - change_info |= CHANGED_PROTOCOL; - if (debug) { - fprintf(where, - "WARNING! Changed bogus getaddrinfo protocol %d to %d\n", - temp_res->ai_protocol, - protocol); - fflush(where); - } - temp_res->ai_protocol = protocol; - } - temp_res = temp_res->ai_next; - } - - if ((change_info & CHANGED_SOCK_TYPE) && - !(change_warning_displayed & CHANGED_SOCK_TYPE)) { - change_warning_displayed |= CHANGED_SOCK_TYPE; - fprintf(where, - "WARNING! getaddrinfo returned a socket type which did not\n"); - fprintf(where, - "match the requested type. Please contact your vendor for\n"); - fprintf(where, - "a fix to this bug in getaddrinfo()\n"); - fflush(where); - } - - /* if we dropped the protocol hint, it would be for a protocol that - getaddrinfo() wasn't supporting yet, not for the bug that it took - our hint and still returned zero. raj 2006-10-16 */ - if ((change_info & CHANGED_PROTOCOL) && - !(change_warning_displayed & CHANGED_PROTOCOL) && - (hints.ai_protocol != 0)) { - change_warning_displayed |= CHANGED_PROTOCOL; - fprintf(where, - "WARNING! getaddrinfo returned a protocol other than the\n"); - fprintf(where, - "requested protocol. Please contact your vendor for\n"); - fprintf(where, - "a fix to this bug in getaddrinfo()\n"); - fflush(where); - } - - if ((change_info & CHANGED_SCTP) && - !(change_warning_displayed & CHANGED_SCTP)) { - change_warning_displayed |= CHANGED_SCTP; - fprintf(where, - "WARNING! getaddrinfo on this platform does not accept IPPROTO_SCTP!\n"); - fprintf(where, - "Please contact your vendor for a fix to this bug in getaddrinfo().\n"); - fflush(where); - } - - - if (debug) { - dump_addrinfo(where, res, hostname, port, family); - } - - return(res); -} - -void -complete_addrinfos(struct addrinfo **remote,struct addrinfo **local, char remote_host[], int type, int protocol, int flags) { - - *remote = complete_addrinfo(remote_host, - remote_data_address, - remote_data_port, - remote_data_family, - type, - protocol, - flags); - - /* OK, if the user has not specified a local data endpoint address - (test-specific -L), pick the local data endpoint address based on - the remote data family info (test-specific -H or -4 or -6 - option). if the user has not specified remote data addressing - info (test-specific -H, -4 -6) pick something based on the local - control connection address (ie the global -L option). */ - - if (NULL == local_data_address) { - local_data_address = malloc(HOSTNAMESIZE); - if (NULL == remote_data_address) { - if (debug) { - fprintf(where, - "local_data_address not set, using local_host_name of '%s'\n", - local_host_name); - fflush(where); - } - strcpy(local_data_address,local_host_name); - } - else { - if (debug) { - fprintf(where, - "local_data_address not set, using address family info\n"); - fflush(where); - } - /* by default, use 0.0.0.0 - assume IPv4 */ - strcpy(local_data_address,"0.0.0.0"); -#if defined(AF_INET6) - if ((AF_INET6 == local_data_family) || - ((AF_UNSPEC == local_data_family) && - (AF_INET6 == remote_data_family)) || - ((AF_UNSPEC == local_data_family) && - (AF_INET6 == (*remote)->ai_family))) { - strcpy(local_data_address,"::0"); - } -#endif - } - } - - *local = complete_addrinfo("what to put here?", - local_data_address, - local_data_port, - local_data_family, - type, - protocol, - flags|AI_PASSIVE); - -} - -void -set_hostname_and_port(char *hostname, char *portstr, int family, int port) -{ - strcpy(hostname,"0.0.0.0"); -#if defined AF_INET6 - if (AF_INET6 == family) { - strcpy(hostname,"::0"); - } -#endif - - sprintf(portstr, "%u", port); - -} - -static unsigned short -get_port_number(struct addrinfo *res) -{ - switch(res->ai_family) { - case AF_INET: { - struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr; - return(ntohs(foo->sin_port)); - break; - } -#if defined(AF_INET6) - case AF_INET6: { - struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr; - return(ntohs(foo->sin6_port)); - break; - } -#endif - default: - fprintf(where, - "Unexpected Address Family of %u\n",res->ai_family); - fflush(where); - exit(-1); - } -} - -/* this routine will set the port number of the sockaddr in the - addrinfo to the specified value, based on the address family */ -void -set_port_number(struct addrinfo *res, unsigned short port) -{ - switch(res->ai_family) { - case AF_INET: { - struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr; - foo->sin_port = htons(port); - break; - } -#if defined(AF_INET6) - case AF_INET6: { - struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr; - foo->sin6_port = htons(port); - break; - } -#endif - default: - fprintf(where, - "Unexpected Address Family of %u\n",res->ai_family); - fflush(where); - exit(-1); - } -} - - - - /* This routine will create a data (listen) socket with the - apropriate options set and return it to the caller. this replaces - all the duplicate code in each of the test routines and should help - make things a little easier to understand. since this routine can be - called by either the netperf or netserver programs, all output - should be directed towards "where." family is generally AF_INET and - type will be either SOCK_STREAM or SOCK_DGRAM. This routine will - also be used by the "SCTP" tests, hence the slightly strange-looking - SCTP stuff in the classic bsd sockets test file... vlad/raj - 2005-03-15 */ - -SOCKET -create_data_socket(struct addrinfo *res) -{ - - SOCKET temp_socket; - int one; - int on = 1; - - - /*set up the data socket */ - temp_socket = socket(res->ai_family, - res->ai_socktype, - res->ai_protocol); - - if (temp_socket == INVALID_SOCKET){ - fprintf(where, - "netperf: create_data_socket: socket: errno %d fam %s type %s prot %s errmsg %s\n", - errno, - inet_ftos(res->ai_family), - inet_ttos(res->ai_socktype), - inet_ptos(res->ai_protocol), - strerror(errno)); - fflush(where); - exit(1); - } - - if (debug) { - fprintf(where,"create_data_socket: socket %d obtained...\n",temp_socket); - fflush(where); - } - - /* Modify the local socket size. The reason we alter the send buffer - size here rather than when the connection is made is to take care - of decreases in buffer size. Decreasing the window size after - connection establishment is a TCP no-no. Also, by setting the - buffer (window) size before the connection is established, we can - control the TCP MSS (segment size). The MSS is never (well, should - never be) more that 1/2 the minimum receive buffer size at each - half of the connection. This is why we are altering the receive - buffer size on the sending size of a unidirectional transfer. If - the user has not requested that the socket buffers be altered, we - will try to find-out what their values are. If we cannot touch the - socket buffer in any way, we will set the values to -1 to indicate - that. */ - - /* all the oogy nitty gritty stuff moved from here into the routine - being called below, per patches from davidm to workaround the bug - in Linux getsockopt(). raj 2004-06-15 */ - set_sock_buffer (temp_socket, SEND_BUFFER, lss_size_req, &lss_size); - set_sock_buffer (temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size); - - /* now, we may wish to enable the copy avoidance features on the */ - /* local system. of course, this may not be possible... */ - -#ifdef SO_RCV_COPYAVOID - if (loc_rcvavoid) { - if (setsockopt(temp_socket, - SOL_SOCKET, - SO_RCV_COPYAVOID, - (const char *)&loc_rcvavoid, - sizeof(int)) == SOCKET_ERROR) { - fprintf(where, - "netperf: create_data_socket: Could not enable receive copy avoidance"); - fflush(where); - loc_rcvavoid = 0; - } - } -#else - /* it wasn't compiled in... */ - loc_rcvavoid = 0; -#endif /* SO_RCV_COPYAVOID */ - -#ifdef SO_SND_COPYAVOID - if (loc_sndavoid) { - if (setsockopt(temp_socket, - SOL_SOCKET, - SO_SND_COPYAVOID, - (const char *)&loc_sndavoid, - sizeof(int)) == SOCKET_ERROR) { - fprintf(where, - "netperf: create_data_socket: Could not enable send copy avoidance"); - fflush(where); - loc_sndavoid = 0; - } - } -#else - /* it was not compiled in... */ - loc_sndavoid = 0; -#endif - - /* Now, we will see about setting the TCP_NODELAY flag on the local */ - /* socket. We will only do this for those systems that actually */ - /* support the option. If it fails, note the fact, but keep going. */ - /* If the user tries to enable TCP_NODELAY on a UDP socket, this */ - /* will cause an error to be displayed */ - - /* well..... long ago and far away that would have happened, in - particular because we would always use IPPROTO_TCP here. - however, now we are using res->ai_protocol, which will be - IPPROT_UDP, and while HP-UX, and I suspect no-one else on the - planet has a UDP_mumble option that overlaps with TCP_NODELAY, - sure as knuth made little green programs, linux has a UDP_CORK - option that is defined as a value of 1, which is the same a - TCP_NODELAY under Linux. So, when asking for -D and - "TCP_NODELAY" under Linux, we are actually setting UDP_CORK - instead of getting an error like every other OS on the - planet. joy and rupture. this stops a UDP_RR test cold sooo we - have to make sure that res->ai_protocol actually makes sense for - a _NODELAY setsockopt() or a UDP_RR test on Linux where someone - mistakenly sets -D will hang. raj 2005-04-21 */ - -#if defined(TCP_NODELAY) || defined(SCTP_NODELAY) - if ((loc_nodelay) && (res->ai_protocol != IPPROTO_UDP)) { - - /* strictly speaking, since the if defined above is an OR, we - should probably check against TCP_NODELAY being defined here. - however, the likelihood of SCTP_NODELAY being defined and - TCP_NODELAY _NOT_ being defined is, probably :), epsilon. raj - 2005-03-15 */ - - int option = TCP_NODELAY; - - /* I suspect that WANT_SCTP would suffice here since that is the - only time we would have called getaddrinfo with a hints asking - for SCTP, but just in case there is an SCTP implementation out - there _without_ SCTP_NODELAY... raj 2005-03-15 */ - -#if defined(WANT_SCTP) && defined(SCTP_NODELAY) - if (IPPROTO_SCTP == res->ai_protocol) { - option = SCTP_NODELAY; - } -#endif - - one = 1; - if(setsockopt(temp_socket, - res->ai_protocol, - option, - (char *)&one, - sizeof(one)) == SOCKET_ERROR) { - fprintf(where, - "netperf: create_data_socket: nodelay: errno %d\n", - errno); - fflush(where); - } - - if (debug > 1) { - fprintf(where, - "netperf: create_data_socket: [TCP|SCTP]_NODELAY requested...\n"); - fflush(where); - } - } -#else /* TCP_NODELAY */ - - loc_nodelay = 0; - -#endif /* TCP_NODELAY */ - -#if defined(TCP_CORK) - - if (loc_tcpcork != 0) { - /* the user wishes for us to set TCP_CORK on the socket */ - int one = 1; - if (setsockopt(temp_socket, - getprotobyname("tcp")->p_proto, - TCP_CORK, - (char *)&one, - sizeof(one)) == SOCKET_ERROR) { - perror("netperf: sendfile_tcp_stream: tcp_cork"); - exit(1); - } - if (debug) { - fprintf(where,"sendfile_tcp_stream: tcp_cork...\n"); - } - } - -#endif /* TCP_CORK */ - - /* since some of the UDP tests do not do anything to cause an - implicit bind() call, we need to be rather explicit about our - bind() call here. even if the address and/or the port are zero - (INADDR_ANY etc). raj 2004-07-20 */ - - if (setsockopt(temp_socket, - SOL_SOCKET, - SO_REUSEADDR, - (const char *)&on, - sizeof(on)) < 0) { - fprintf(where, - "netperf: create_data_socket: SO_REUSEADDR failed %d\n", - errno); - fflush(where); - } - - if (bind(temp_socket, - res->ai_addr, - res->ai_addrlen) < 0) { - if (debug) { - fprintf(where, - "netperf: create_data_socket: data socket bind failed errno %d\n", - errno); - fprintf(where," port: %d\n",get_port_number(res)); - fflush(where); - } - } - - - return(temp_socket); - -} - -#ifdef KLUDGE_SOCKET_OPTIONS - - - /* This routine is for those BROKEN systems which do not correctly */ - /* pass socket attributes through calls such as accept(). It should */ - /* only be called for those broken systems. I *really* don't want to */ - /* have this, but even broken systems must be measured. raj 11/95 */ -void -kludge_socket_options(int temp_socket) -{ - - set_sock_buffer(temp_socket, SEND_BUFFER, lss_size_req, &lss_size); - set_sock_buffer(temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size); - - /* now, we may wish to enable the copy avoidance features on the */ - /* local system. of course, this may not be possible... */ - /* those calls were only valid for HP-UX, and I know that HP-UX is */ - /* written correctly, and so we do not need to include those calls */ - /* in this kludgy routine. raj 11/95 */ - - - /* Now, we will see about setting the TCP_NODELAY flag on the local */ - /* socket. We will only do this for those systems that actually */ - /* support the option. If it fails, note the fact, but keep going. */ - /* If the user tries to enable TCP_NODELAY on a UDP socket, this */ - /* will cause an error to be displayed */ - -#ifdef TCP_NODELAY - if (loc_nodelay) { - one = 1; - if(setsockopt(temp_socket, - getprotobyname("tcp")->p_proto, - TCP_NODELAY, - (char *)&one, - sizeof(one)) == SOCKET_ERROR) { - fprintf(where,"netperf: kludge_socket_options: nodelay: errno %d\n", - errno); - fflush(where); - } - - if (debug > 1) { - fprintf(where, - "netperf: kludge_socket_options: TCP_NODELAY requested...\n"); - fflush(where); - } - } -#else /* TCP_NODELAY */ - - loc_nodelay = 0; - -#endif /* TCP_NODELAY */ - - } - -#endif /* KLUDGE_SOCKET_OPTIONS */ - - -static void * -get_address_address(struct addrinfo *info) -{ - struct sockaddr_in *sin; -#if defined(AF_INET6) - struct sockaddr_in6 *sin6; -#endif - - switch(info->ai_family) { - case AF_INET: - sin = (struct sockaddr_in *)info->ai_addr; - return(&(sin->sin_addr)); - break; -#if defined(AF_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *)info->ai_addr; - return(&(sin6->sin6_addr)); - break; -#endif - default: - fprintf(stderr,"we never expected to get here in get_address_address\n"); - fflush(stderr); - exit(-1); - } -} - -#if defined(WIN32) -/* +*+ Why isn't this in the winsock headers yet? */ -const char * -inet_ntop(int af, const void *src, char *dst, size_t size); -#endif - -/* This routine is a generic test header printer for the topmost header */ -void -print_top_test_header(char test_name[], struct addrinfo *source, struct addrinfo *destination) -{ - -#if defined(AF_INET6) - char address_buf[INET6_ADDRSTRLEN]; -#else - char address_buf[16]; /* magic constant */ -#endif - - /* we want to have some additional, interesting information in */ - /* the headers. we know some of it here, but not all, so we will */ - /* only print the test title here and will print the results */ - /* titles after the test is finished */ - fprintf(where,test_name); - address_buf[0] = '\0'; - inet_ntop(source->ai_family,get_address_address(source),address_buf,sizeof(address_buf)); - fprintf(where, - " from %s (%s) port %u %s", - source->ai_canonname, - address_buf, - get_port_number(source), - inet_ftos(source->ai_family)); - address_buf[0] = '\0'; - inet_ntop(destination->ai_family,get_address_address(destination),address_buf,sizeof(address_buf)); - fprintf(where, - " to %s (%s) port %u %s", - destination->ai_canonname, - address_buf, - get_port_number(destination), - inet_ftos(destination->ai_family)); - - if (iteration_max > 1) { - fprintf(where, - " : +/-%3.1f%% @ %2d%% conf. %s", - interval/0.02, - confidence_level, - result_confidence_only ? " on result only" : ""); - } - if ((loc_nodelay > 0) || (rem_nodelay > 0)) { - fprintf(where," : nodelay"); - } - if ((loc_sndavoid > 0) || - (loc_rcvavoid > 0) || - (rem_sndavoid > 0) || - (rem_rcvavoid > 0)) { - fprintf(where," : copy avoidance"); - } - - if (no_control) { - fprintf(where," : no control"); - } - -#ifdef WANT_HISTOGRAM - fprintf(where," : histogram"); -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_INTERVALS -#ifndef WANT_SPIN - fprintf(where," : interval"); -#else - fprintf(where," : spin interval"); -#endif -#endif /* WANT_INTERVALS */ - -#ifdef DIRTY - fprintf(where," : dirty data"); -#endif /* DIRTY */ -#ifdef WANT_DEMO - fprintf(where," : demo"); -#endif -#ifdef WANT_FIRST_BURST - /* a little hokey perhaps, but we really only want this to be - emitted for tests where it actually is used, which means a - "REQUEST/RESPONSE" test. raj 2005-11-10 */ - if (strstr(test_name,"REQUEST/RESPONSE")) { - fprintf(where," : first burst %d",first_burst_size); - } -#endif - if (cpu_binding_requested) { - fprintf(where," : cpu bind"); - } - fprintf(where,"\n"); - -} - - -/* This routine implements the TCP unidirectional data transfer test */ -/* (a.k.a. stream) for the sockets interface. It receives its */ -/* parameters via global variables from the shell and writes its */ -/* output to the standard output. */ - - -void -send_tcp_stream(char remote_host[]) -{ - - char *tput_title = "\ -Recv Send Send \n\ -Socket Socket Message Elapsed \n\ -Size Size Size Time Throughput \n\ -bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f %s\n"; - - char *tput_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %s\n"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Socket Socket Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c %s\n"; - - char *cpu_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ -Local Remote Local Remote Xfered Per Per\n\ -Send Recv Send Recv Send (avg) Recv (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - - char *ksink_fmt2 = "\n\ -Maximum\n\ -Segment\n\ -Size (bytes)\n\ -%6d\n"; - - - float elapsed_time; - - /* what we want is to have a buffer space that is at least one */ - /* send-size greater than our send window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - - struct ring_elt *send_ring; - - int len; - unsigned int nummessages = 0; - SOCKET send_socket; - int bytes_remaining; - int tcp_mss = -1; /* possibly uninitialized on printf far below */ - - /* with links like fddi, one can send > 32 bits worth of bytes */ - /* during a test... ;-) at some point, this should probably become a */ - /* 64bit integral type, but those are not entirely common yet */ - - unsigned long long local_bytes_sent = 0; - double bytes_sent = 0.0; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - - double thruput; - - struct addrinfo *remote_res; - struct addrinfo *local_res; - - struct tcp_stream_request_struct *tcp_stream_request; - struct tcp_stream_response_struct *tcp_stream_response; - struct tcp_stream_results_struct *tcp_stream_result; - - tcp_stream_request = - (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data; - tcp_stream_response = - (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data; - tcp_stream_result = - (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - /* complete_addrinfos will either succede or exit the process */ - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("TCP STREAM TEST",local_res,remote_res); - } - - send_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - - /*set up the data socket */ - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_tcp_stream: tcp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_tcp_stream: send_socket obtained...\n"); - } - - /* at this point, we have either retrieved the socket buffer sizes, */ - /* or have tried to set them, so now, we may want to set the send */ - /* size based on that (because the user either did not use a -m */ - /* option, or used one with an argument of 0). If the socket buffer */ - /* size is not available, we will set the send size to 4KB - no */ - /* particular reason, just arbitrary... */ - if (send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - - /* set-up the data buffer ring with the requested alignment and offset. */ - /* note also that we have allocated a quantity */ - /* of memory that is at least one send-size greater than our socket */ - /* buffer size. We want to be sure that there are at least two */ - /* buffers allocated - this can be a bit of a problem when the */ - /* send_size is bigger than the socket size, so we must check... the */ - /* user may have wanted to explicitly set the "width" of our send */ - /* buffers, we should respect that wish... */ - if (send_width == 0) { - send_width = (lss_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - if (send_ring == NULL) { - /* only allocate the send ring once. this is a networking test, */ - /* not a memory allocation test. this way, we do not need a */ - /* deallocate_buffer_ring() routine, and I don't feel like */ - /* writing one anyway :) raj 11/94 */ - send_ring = allocate_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - if (!no_control) { - /* Tell the remote end to do a listen. The server alters the - socket paramters on the other side at this point, hence the - reason for all the values being passed in the setup - message. If the user did not specify any of the parameters, - they will be passed as 0, which will indicate to the remote - that no changes beyond the system's default should be - used. Alignment is the exception, it will default to 1, which - will be no alignment alterations. */ - - netperf_request.content.request_type = DO_TCP_STREAM; - tcp_stream_request->send_buf_size = rss_size_req; - tcp_stream_request->recv_buf_size = rsr_size_req; - tcp_stream_request->receive_size = recv_size; - tcp_stream_request->no_delay = rem_nodelay; - tcp_stream_request->recv_alignment = remote_recv_align; - tcp_stream_request->recv_offset = remote_recv_offset; - tcp_stream_request->measure_cpu = remote_cpu_usage; - tcp_stream_request->cpu_rate = remote_cpu_rate; - if (test_time) { - tcp_stream_request->test_length = test_time; - } - else { - tcp_stream_request->test_length = test_bytes; - } - tcp_stream_request->so_rcvavoid = rem_rcvavoid; - tcp_stream_request->so_sndavoid = rem_sndavoid; -#ifdef DIRTY - tcp_stream_request->dirty_count = rem_dirty_count; - tcp_stream_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - tcp_stream_request->port = atoi(remote_data_port); - tcp_stream_request->ipfamily = af_to_nf(remote_res->ai_family); - if (debug > 1) { - fprintf(where, - "netperf: send_tcp_stream: requesting TCP stream test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant - socket parameters for this test type. We will put them back - into the variables here so they can be displayed if desired. - The remote will have calibrated CPU if necessary, and will - have done all the needed set-up we will have calibrated the - cpu locally before sending the request, and will grab the - counter value right after the connect returns. The remote - will grab the counter right after the accept call. This saves - the hassle of extra messages being sent for the TCP - tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = tcp_stream_response->recv_buf_size; - rss_size = tcp_stream_response->send_buf_size; - rem_nodelay = tcp_stream_response->no_delay; - remote_cpu_usage= tcp_stream_response->measure_cpu; - remote_cpu_rate = tcp_stream_response->cpu_rate; - - /* we have to make sure that the server port number is in - network order */ - set_port_number(remote_res, - (short)tcp_stream_response->data_port_number); - - rem_rcvavoid = tcp_stream_response->so_rcvavoid; - rem_sndavoid = tcp_stream_response->so_sndavoid; - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - } - -#ifdef WANT_DEMO - DEMO_STREAM_SETUP(lss_size,rsr_size) -#endif - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("netperf: send_tcp_stream: data socket connect failed"); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either */ - /* the connect would have failed, or the previous response would */ - /* have indicated a problem. I failed to see the value of the */ - /* extra message after the accept on the remote. If it failed, */ - /* we'll see it here. If it didn't, we might as well start pumping */ - /* data. */ - - /* Set-up the test end conditions. For a stream test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - /* in previous revisions, we had the same code repeated throught */ - /* all the test suites. this was unnecessary, and meant more */ - /* work for me when I wanted to switch to POSIX signals, so I */ - /* have abstracted this out into a routine in netlib.c. if you */ - /* are experiencing signal problems, you might want to look */ - /* there. raj 11/94 */ - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - bytes_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - - /* we only start the interval timer if we are using the - timer-timed intervals rather than the sit and spin ones. raj - 2006-02-06 */ -#if defined(WANT_INTERVALS) - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - - /* before we start, initialize a few variables */ - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. */ - - while ((!times_up) || (bytes_remaining > 0)) { - -#ifdef DIRTY - access_buffer(send_ring->buffer_ptr, - send_size, - loc_dirty_count, - loc_clean_count); -#endif /* DIRTY */ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before we go into send and then again just - after we come out raj 8/94 */ - /* but lets only do this if there is going to be a histogram - displayed */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - if((len=send(send_socket, - send_ring->buffer_ptr, - send_size, - 0)) != send_size) { - if ((len >=0) || SOCKET_EINTR(len)) { - /* the test was interrupted, must be the end of test */ - break; - } - perror("netperf: data send error"); - printf("len was %d\n",len); - exit(1); - } - - local_bytes_sent += send_size; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp the exit from the send call and update the histogram */ - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_DEMO - DEMO_STREAM_INTERVAL(send_size) -#endif - -#if defined(WANT_INTERVALS) - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - /* now we want to move our pointer to the next position in the */ - /* data buffer...we may also want to wrap back to the "beginning" */ - /* of the bufferspace, so we will mod the number of messages sent */ - /* by the send width, and use that to calculate the offset to add */ - /* to the base pointer. */ - nummessages++; - send_ring = send_ring->next; - if (bytes_remaining) { - bytes_remaining -= send_size; - } - } - - /* The test is over. Flush the buffers to the remote end. We do a */ - /* graceful release to insure that all data has been taken by the */ - /* remote. */ - - /* but first, if the verbosity is greater than 1, find-out what */ - /* the TCP maximum segment_size was (if possible) */ - if (verbosity > 1) { - tcp_mss = -1; - get_tcp_info(send_socket,&tcp_mss); - } - - if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) { - perror("netperf: cannot shutdown tcp stream socket"); - exit(1); - } - - /* hang a recv() off the socket to block until the remote has */ - /* brought all the data up into the application. it will do a */ - /* shutdown to cause a FIN to be sent our way. We will assume that */ - /* any exit from the recv() call is good... raj 4/93 */ - - recv(send_socket, send_ring->buffer_ptr, send_size, 0); - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured and how */ - /* long did we really */ - /* run? */ - - /* we are finished with the socket, so close it to prevent hitting */ - /* the limit on maximum open files. */ - - close(send_socket); - - if (!no_control) { - /* Get the statistics from the remote end. The remote will have - calculated service demand and all those interesting - things. If it wasn't supposed to care, it will return obvious - values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the - future, we may want to include a calculation of the thruput - measured by the remote, but it should be the case that for a - TCP stream test, that the two numbers should be *very* - close... We calculate bytes_sent regardless of the way the - test length was controlled. If it was time, we needed to, - and if it was by bytes, the user may have specified a number - of bytes that wasn't a multiple of the send_size, so we - really didn't send what he asked for ;-) */ - - bytes_sent = ntohd(tcp_stream_result->bytes_received); - } - else { - bytes_sent = (double)local_bytes_sent; - } - - thruput = calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - - remote_cpu_utilization = tcp_stream_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - tcp_stream_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - } - - /* at this point, we have finished making all the runs that we */ - /* will be making. so, we should extract what the calcuated values */ - /* are for all the confidence stuff. we could make the values */ - /* global, but that seemed a little messy, and it did not seem worth */ - /* all the mucking with header files. so, we create a routine much */ - /* like calcualte_confidence, which just returns the mean values. */ - /* raj 11/94 */ - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(tcp_stream_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand, /* remote service demand */ - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - fprintf(where, - tput_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - thruput, /* how fast did it go */ - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - /* this stuff needs to be worked-out in the presence of confidence */ - /* intervals and multiple iterations of the test... raj 11/94 */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_send_align, - remote_recv_align, - local_send_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)tcp_stream_result->recv_calls, - tcp_stream_result->recv_calls); - fprintf(where, - ksink_fmt2, - tcp_mss); - fflush(where); -#ifdef WANT_HISTOGRAM - fprintf(where,"\n\nHistogram of time spent in send() call.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } - -} - - - -/* This routine implements the netperf-side TCP unidirectional data - transfer test (a.k.a. stream) for the sockets interface where the - data flow is from the netserver to the netperf. It receives its - parameters via global variables from the shell and writes its - output to the standard output. */ - - -void -send_tcp_maerts(char remote_host[]) -{ - - char *tput_title = "\ -Recv Send Send \n\ -Socket Socket Message Elapsed \n\ -Size Size Size Time Throughput \n\ -bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f %s\n"; - - char *tput_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %s \n"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Socket Socket Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c %s\n"; - - char *cpu_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Recvs %-8.8s Sends\n\ -Local Remote Local Remote Xfered Per Per\n\ -Recv Send Recv Send Recv (avg) Send (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - - char *ksink_fmt2 = "\n\ -Maximum\n\ -Segment\n\ -Size (bytes)\n\ -%6d\n"; - - - float elapsed_time; - - /* what we want is to have a buffer space that is at least one */ - /* recv-size greater than our recv window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - - struct ring_elt *recv_ring; - - int len; - unsigned int nummessages = 0; - SOCKET recv_socket; - int bytes_remaining; - int tcp_mss = -1; /* possibly uninitialized on printf far below */ - - /* with links like fddi, one can recv > 32 bits worth of bytes */ - /* during a test... ;-) at some point, this should probably become a */ - /* 64bit integral type, but those are not entirely common yet */ - double bytes_sent = 0.0; - unsigned long long local_bytes_recvd = 0; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - - double thruput; - - struct addrinfo *remote_res; - struct addrinfo *local_res; - - struct tcp_maerts_request_struct *tcp_maerts_request; - struct tcp_maerts_response_struct *tcp_maerts_response; - struct tcp_maerts_results_struct *tcp_maerts_result; - - tcp_maerts_request = - (struct tcp_maerts_request_struct *)netperf_request.content.test_specific_data; - tcp_maerts_response = - (struct tcp_maerts_response_struct *)netperf_response.content.test_specific_data; - tcp_maerts_result = - (struct tcp_maerts_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("TCP MAERTS TEST",local_res,remote_res); - } - - recv_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - - /*set up the data socket */ - recv_socket = create_data_socket(local_res); - - if (recv_socket == INVALID_SOCKET){ - perror("netperf: send_tcp_maerts: tcp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_tcp_maerts: recv_socket obtained...\n"); - } - - /* at this point, we have either retrieved the socket buffer sizes, */ - /* or have tried to set them, so now, we may want to set the recv */ - /* size based on that (because the user either did not use a -m */ - /* option, or used one with an argument of 0). If the socket buffer */ - /* size is not available, we will set the recv size to 4KB - no */ - /* particular reason, just arbitrary... */ - if (recv_size == 0) { - if (lsr_size > 0) { - recv_size = lsr_size; - } - else { - recv_size = 4096; - } - } - - /* set-up the data buffer ring with the requested alignment and offset. */ - /* note also that we have allocated a quantity */ - /* of memory that is at least one recv-size greater than our socket */ - /* buffer size. We want to be sure that there are at least two */ - /* buffers allocated - this can be a bit of a problem when the */ - /* recv_size is bigger than the socket size, so we must check... the */ - /* user may have wanted to explicitly set the "width" of our recv */ - /* buffers, we should respect that wish... */ - if (recv_width == 0) { - recv_width = (lsr_size/recv_size) + 1; - if (recv_width == 1) recv_width++; - } - - if (recv_ring == NULL) { - /* only allocate the recv ring once. this is a networking test, */ - /* not a memory allocation test. this way, we do not need a */ - /* deallocate_buffer_ring() routine, and I don't feel like */ - /* writing one anyway :) raj 11/94 */ - recv_ring = allocate_buffer_ring(recv_width, - recv_size, - local_recv_align, - local_recv_offset); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - if (!no_control) { - /* Tell the remote end to do a listen. The server alters the - socket paramters on the other side at this point, hence the - reason for all the values being passed in the setup - message. If the user did not specify any of the parameters, - they will be passed as 0, which will indicate to the remote - that no changes beyond the system's default should be - used. Alignment is the exception, it will default to 1, which - will be no alignment alterations. */ - - netperf_request.content.request_type = DO_TCP_MAERTS; - tcp_maerts_request->send_buf_size = rss_size_req; - tcp_maerts_request->recv_buf_size = rsr_size_req; - tcp_maerts_request->send_size = send_size; - tcp_maerts_request->no_delay = rem_nodelay; - tcp_maerts_request->send_alignment = remote_send_align; - tcp_maerts_request->send_offset = remote_send_offset; - tcp_maerts_request->measure_cpu = remote_cpu_usage; - tcp_maerts_request->cpu_rate = remote_cpu_rate; - if (test_time) { - tcp_maerts_request->test_length = test_time; - } - else { - tcp_maerts_request->test_length = test_bytes; - } - tcp_maerts_request->so_rcvavoid = rem_rcvavoid; - tcp_maerts_request->so_sndavoid = rem_sndavoid; -#ifdef DIRTY - tcp_maerts_request->dirty_count = rem_dirty_count; - tcp_maerts_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - tcp_maerts_request->port = atoi(remote_data_port); - tcp_maerts_request->ipfamily = af_to_nf(remote_res->ai_family); - if (debug > 1) { - fprintf(where, - "netperf: send_tcp_maerts: requesting TCP maerts test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant - socket parameters for this test type. We will put them back - into the variables here so they can be displayed if desired. - The remote will have calibrated CPU if necessary, and will - have done all the needed set-up we will have calibrated the - cpu locally before sending the request, and will grab the - counter value right after the connect returns. The remote - will grab the counter right after the accept call. This saves - the hassle of extra messages being sent for the TCP - tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = tcp_maerts_response->recv_buf_size; - rss_size = tcp_maerts_response->send_buf_size; - rem_nodelay = tcp_maerts_response->no_delay; - remote_cpu_usage= tcp_maerts_response->measure_cpu; - remote_cpu_rate = tcp_maerts_response->cpu_rate; - send_size = tcp_maerts_response->send_size; - - /* we have to make sure that the server port number is in - network order */ - set_port_number(remote_res, - (short)tcp_maerts_response->data_port_number); - rem_rcvavoid = tcp_maerts_response->so_rcvavoid; - rem_sndavoid = tcp_maerts_response->so_sndavoid; - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - } - -#ifdef WANT_DEMO - DEMO_STREAM_SETUP(lsr_size,rss_size) -#endif - - /*Connect up to the remote port on the data socket */ - if (connect(recv_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("netperf: send_tcp_maerts: data socket connect failed"); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either */ - /* the connect would have failed, or the previous response would */ - /* have indicated a problem. I failed to see the value of the */ - /* extra message after the accept on the remote. If it failed, */ - /* we'll see it here. If it didn't, we might as well start pumping */ - /* data. */ - - /* Set-up the test end conditions. For a maerts test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - /* in previous revisions, we had the same code repeated throught */ - /* all the test suites. this was unnecessary, and meant more */ - /* work for me when I wanted to switch to POSIX signals, so I */ - /* have abstracted this out into a routine in netlib.c. if you */ - /* are experiencing signal problems, you might want to look */ - /* there. raj 11/94 */ - if (!no_control) { - /* this is a netperf to netserver test, netserver will close - to tell us the test is over, so use PAD_TIME to avoid - causing the netserver fits. */ - start_timer(test_time + PAD_TIME); - } - else { - /* this is a netperf to data source test, no PAD_TIME */ - start_timer(test_time); - } - } - else { - /* The tester wanted to recv a number of bytes. we don't do that - in a TCP_MAERTS test. sorry. raj 2002-06-21 */ - printf("netperf: send_tcp_maerts: test must be timed\n"); - exit(1); - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - - /* before we start, initialize a few variables */ - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - /* the test will continue until we either get a zero-byte recv() - on the socket or our failsafe timer expires. most of the time - we trust that we get a zero-byte recieve from the socket. raj - 2002-06-21 */ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before we go into recv and then again just - after we come out raj 8/94 */ - /* but only if we are actually going to display a histogram. raj - 2006-02-07 */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - while ((!times_up) && (len=recv(recv_socket, - recv_ring->buffer_ptr, - recv_size, - 0)) > 0 ) { - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp the exit from the recv call and update the histogram */ - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - -#ifdef DIRTY - access_buffer(recv_ring->buffer_ptr, - recv_size, - loc_dirty_count, - loc_clean_count); -#endif /* DIRTY */ - -#ifdef WANT_DEMO - DEMO_STREAM_INTERVAL(len); -#endif - -#ifdef WANT_INTERVALS - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - /* now we want to move our pointer to the next position in the */ - /* data buffer...we may also want to wrap back to the "beginning" */ - /* of the bufferspace, so we will mod the number of messages sent */ - /* by the recv width, and use that to calculate the offset to add */ - /* to the base pointer. */ - nummessages++; - recv_ring = recv_ring->next; - if (bytes_remaining) { - bytes_remaining -= len; - } - - local_bytes_recvd += len; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* make sure we timestamp just before we go into recv */ - /* raj 2004-06-15 */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - } - - /* an EINTR is to be expected when this is a no_control test */ - if (((len < 0) || SOCKET_EINTR(len)) && (!no_control)) { - perror("send_tcp_maerts: data recv error"); - printf("len was %d\n",len); - exit(1); - } - - /* if we get here, it must mean we had a recv return of 0 before - the watchdog timer expired, or the watchdog timer expired and - this was a no_control test */ - - /* The test is over. Flush the buffers to the remote end. We do a - graceful release to tell the remote we have all the data. */ - - /* but first, if the verbosity is greater than 1, find-out what */ - /* the TCP maximum segment_size was (if possible) */ - if (verbosity > 1) { - tcp_mss = -1; - get_tcp_info(recv_socket,&tcp_mss); - } - - if (shutdown(recv_socket,SHUT_WR) == SOCKET_ERROR) { - perror("netperf: cannot shutdown tcp maerts socket"); - exit(1); - } - - stop_timer(); - - /* this call will always give us the local elapsed time for the - test, and will also store-away the necessaries for cpu - utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured and how */ - /* long did we really */ - /* run? */ - - /* we are finished with the socket, so close it to prevent hitting */ - /* the limit on maximum open files. */ - - close(recv_socket); - - if (!no_control) { - /* Get the statistics from the remote end. The remote will have - calculated service demand and all those interesting - things. If it wasn't supposed to care, it will return obvious - values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the - future, we may want to include a calculation of the thruput - measured by the remote, but it should be the case that for a - TCP maerts test, that the two numbers should be *very* - close... We calculate bytes_sent regardless of the way the - test length was controlled. If it was time, we needed to, - and if it was by bytes, the user may have specified a number - of bytes that wasn't a multiple of the recv_size, so we - really didn't recv what he asked for ;-) */ - - bytes_sent = ntohd(tcp_maerts_result->bytes_sent); - } - else { - bytes_sent = (double)local_bytes_recvd; - } - - - thruput = calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - - remote_cpu_utilization = tcp_maerts_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - tcp_maerts_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - } - - /* at this point, we have finished making all the runs that we */ - /* will be making. so, we should extract what the calcuated values */ - /* are for all the confidence stuff. we could make the values */ - /* global, but that seemed a little messy, and it did not seem worth */ - /* all the mucking with header files. so, we create a routine much */ - /* like calcualte_confidence, which just returns the mean values. */ - /* raj 11/94 */ - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(tcp_maerts_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the recvs */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand, /* remote service demand */ - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - fprintf(where, - tput_fmt_1, /* the format string */ - lsr_size, /* local recvbuf size */ - rss_size, /* remot sendbuf size */ - send_size, /* how large were the recvs */ - elapsed_time, /* how long did it take */ - thruput, /* how fast did it go */ - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - /* this stuff needs to be worked-out in the presence of confidence */ - /* intervals and multiple iterations of the test... raj 11/94 */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_recv_align, - remote_recv_align, - local_recv_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)tcp_maerts_result->send_calls, - tcp_maerts_result->send_calls); - fprintf(where, - ksink_fmt2, - tcp_mss); - fflush(where); -#ifdef WANT_HISTOGRAM - fprintf(where,"\n\nHistogram of time spent in recv() call.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } - -} - - - -#ifdef HAVE_ICSC_EXS - -#include <sys/exs.h> - - -/* This routine implements the TCP unidirectional data transfer test */ -/* (a.k.a. stream) for the sockets interface. It receives its */ -/* parameters via global variables from the shell and writes its */ -/* output to the standard output. */ - -void -send_exs_tcp_stream(char remote_host[]) -{ - - char *tput_title = "\ -Recv Send Send \n\ -Socket Socket Message Elapsed \n\ -Size Size Size Time Throughput \n\ -bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f \n"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Socket Socket Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - - char *cpu_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ -Local Remote Local Remote Xfered Per Per\n\ -Send Recv Send Recv Send (avg) Recv (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - - char *ksink_fmt2 = "\n\ -Maximum\n\ -Segment\n\ -Size (bytes)\n\ -%6d\n"; - - - float elapsed_time; - - /* what we want is to have a buffer space that is at least one */ - /* send-size greater than our send window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - - struct ring_elt *send_ring; - - int len; - unsigned int nummessages = 0; - SOCKET send_socket; - int bytes_remaining; - int tcp_mss = -1; /* possibly uninitialized on printf far below */ - - exs_mhandle_t exs_mhandle; - exs_qhandle_t exs_qhandle; -#define NETPERF_EXS_PENDING 16 - int exs_aio_pending; - int exs_aio_eagain; - int exs_aio_dequeued; - int exs_aio_dequeuecnt; - int exs_evtcnt; -#define NETPERF_EXS_QSIZE 128 - exs_event_t exs_evtvec[NETPERF_EXS_QSIZE]; - - /* with links like fddi, one can send > 32 bits worth of bytes */ - /* during a test... ;-) at some point, this should probably become a */ - /* 64bit integral type, but those are not entirely common yet */ - - double bytes_sent = 0.0; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - - double thruput; - - struct addrinfo *remote_res; - struct addrinfo *local_res; - - struct tcp_stream_request_struct *tcp_stream_request; - struct tcp_stream_response_struct *tcp_stream_response; - struct tcp_stream_results_struct *tcp_stream_result; - - tcp_stream_request = - (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data; - tcp_stream_response = - (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data; - tcp_stream_result = - (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data; - -#if 0 /* def WANT_HISTOGRAM */ - time_hist = HIST_new(); -#endif /* WANT_HISTOGRAM */ - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - /* complete_addrinfos will either succede or exit the process */ - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("EXS TCP STREAM TEST",local_res,remote_res); - } - - send_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* initialize EXS API and create event queue */ - if (exs_init (EXS_VERSION) == -1) { - perror ("netperf: send_exs_tcp_stream: exs_init failed"); - exit (1); - } - - if ((exs_qhandle = exs_qcreate (NETPERF_EXS_QSIZE)) == EXS_QHANDLE_INVALID) { - perror ("netperf: send_exs_tcp_stream: exs_qcreate failed"); - exit (1); - } - if (debug) { - fprintf (where, "send_exs_tcp_stream: qhandle=%d\n", exs_qhandle); - } - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - - /*set up the data socket */ - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_tcp_stream: tcp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_tcp_stream: send_socket obtained...\n"); - } - - /* at this point, we have either retrieved the socket buffer sizes, */ - /* or have tried to set them, so now, we may want to set the send */ - /* size based on that (because the user either did not use a -m */ - /* option, or used one with an argument of 0). If the socket buffer */ - /* size is not available, we will set the send size to 4KB - no */ - /* particular reason, just arbitrary... */ - if (send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - - /* set-up the data buffer ring with the requested alignment and offset. */ - /* note also that we have allocated a quantity */ - /* of memory that is at least one send-size greater than our socket */ - /* buffer size. We want to be sure that there are at least two */ - /* buffers allocated - this can be a bit of a problem when the */ - /* send_size is bigger than the socket size, so we must check... the */ - /* user may have wanted to explicitly set the "width" of our send */ - /* buffers, we should respect that wish... */ - if (send_width == 0) { - send_width = (lss_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - if (send_ring == NULL) { - /* only allocate the send ring once. this is a networking test, */ - /* not a memory allocation test. this way, we do not need a */ - /* deallocate_buffer_ring() routine, and I don't feel like */ - /* writing one anyway :) raj 11/94 */ - send_ring = allocate_exs_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset, - &exs_mhandle); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 1, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_TCP_STREAM; - tcp_stream_request->send_buf_size = rss_size_req; - tcp_stream_request->recv_buf_size = rsr_size_req; - tcp_stream_request->receive_size = recv_size; - tcp_stream_request->no_delay = rem_nodelay; - tcp_stream_request->recv_alignment = remote_recv_align; - tcp_stream_request->recv_offset = remote_recv_offset; - tcp_stream_request->measure_cpu = remote_cpu_usage; - tcp_stream_request->cpu_rate = remote_cpu_rate; - if (test_time) { - tcp_stream_request->test_length = test_time; - } - else { - tcp_stream_request->test_length = test_bytes; - } - tcp_stream_request->so_rcvavoid = rem_rcvavoid; - tcp_stream_request->so_sndavoid = rem_sndavoid; -#ifdef DIRTY - tcp_stream_request->dirty_count = rem_dirty_count; - tcp_stream_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - tcp_stream_request->port = atoi(remote_data_port); - tcp_stream_request->ipfamily = af_to_nf(remote_res->ai_family); - if (debug > 1) { - fprintf(where, - "netperf: send_tcp_stream: requesting TCP stream test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right*/ - /* after the connect returns. The remote will grab the counter right*/ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = tcp_stream_response->recv_buf_size; - rss_size = tcp_stream_response->send_buf_size; - rem_nodelay = tcp_stream_response->no_delay; - remote_cpu_usage= tcp_stream_response->measure_cpu; - remote_cpu_rate = tcp_stream_response->cpu_rate; - - /* we have to make sure that the server port number is in */ - /* network order */ - set_port_number(remote_res,(short)tcp_stream_response->data_port_number); - - rem_rcvavoid = tcp_stream_response->so_rcvavoid; - rem_sndavoid = tcp_stream_response->so_sndavoid; - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - -#if 0 /* def WANT_DEMO */ - DEMO_STREAM_SETUP(lss_size,rsr_size) -#endif - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("netperf: send_tcp_stream: data socket connect failed"); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either */ - /* the connect would have failed, or the previous response would */ - /* have indicated a problem. I failed to see the value of the */ - /* extra message after the accept on the remote. If it failed, */ - /* we'll see it here. If it didn't, we might as well start pumping */ - /* data. */ - - /* Set-up the test end conditions. For a stream test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - /* in previous revisions, we had the same code repeated throught */ - /* all the test suites. this was unnecessary, and meant more */ - /* work for me when I wanted to switch to POSIX signals, so I */ - /* have abstracted this out into a routine in netlib.c. if you */ - /* are experiencing signal problems, you might want to look */ - /* there. raj 11/94 */ - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - bytes_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#if 0 /* def WANT_INTERVALS */ - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - - /* before we start, initialize a few variables */ - -#if 0 /* def WANT_DEMO */ - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. */ - - exs_aio_pending = 0; - exs_aio_eagain = 0; - exs_aio_dequeuecnt = 0; - - while ((!times_up) || (bytes_remaining > 0)) { - -#ifdef DIRTY - access_buffer(send_ring->buffer_ptr, - send_size, - loc_dirty_count, - loc_clean_count); -#endif /* DIRTY */ - -#if 0 /* def WANT_HISTOGRAM */ - /* timestamp just before we go into send and then again just after */ - /* we come out raj 8/94 */ - HIST_timestamp(&time_one); -#endif /* WANT_HISTOGRAM */ - - - /* post up to NETPERF_EXS_PENDING I/Os */ - while ((exs_aio_pending < NETPERF_EXS_PENDING) && - (exs_send (send_socket, send_ring->buffer_ptr, send_size, - 0, exs_qhandle, (exs_ahandle_t)-1, exs_mhandle) == 0)) { - exs_aio_pending++; - - /* now we want to move our pointer to the next - position in the data buffer...we may also want to - wrap back to the "beginning" of the bufferspace, so - we will mod the number of messages sent by the send - width, and use that to calculate the offset to add - to the base pointer. */ - - nummessages++; - send_ring = send_ring->next; - if (bytes_remaining) { - bytes_remaining -= send_size; - } - } - - /* check exs_send result */ - if (exs_aio_pending < NETPERF_EXS_PENDING) { - /* standard flow control case */ - if (errno == EAGAIN) - exs_aio_eagain++; - /* case of times_up */ - else if (errno == EINTR) - break; - /* strange, let's stop */ - else { - perror ("netperf: exs_send error"); - exit (1); - } - } - - /* dequeue events with "threshold" on 1/2 posted */ - exs_aio_dequeued = - exs_qdequeue (exs_qhandle, exs_evtvec, - -(exs_aio_pending>>1), NULL); - exs_aio_dequeuecnt++; - - /* check exs_dequeue result */ - if (exs_aio_dequeued < 0) { - /* case of times_up */ - if (errno == EINTR) - break; - /* strange, let's stop */ - else { - perror ("netperf: exs_send error"); - exit (1); - } - } - /* update number of pending I/Os */ - else { - exs_aio_pending -= exs_aio_dequeued; - } - - -#if 0 /* def WANT_HISTOGRAM */ - /* timestamp the exit from the send call and update the histogram */ - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); -#endif /* WANT_HISTOGRAM */ - -#if 0 /* def WANT_DEMO */ - DEMO_STREAM_INTERVAL(send_size); -#endif - -#if 0 /* def WANT_INTERVALS */ - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - } - - /* Collect the last completion events */ - exs_aio_dequeued = - exs_qdequeue (exs_qhandle, exs_evtvec, -exs_aio_pending, NULL); - exs_aio_dequeuecnt++; - /* check exs_dequeue result and update number of pending I/Os */ - if (exs_aio_dequeued < 0) { - perror ("netperf: exs_send error"); - exit (1); - } - exs_aio_pending -= exs_aio_dequeued; - - /* Display some async I/O debug info */ - if (debug) { - fprintf (where, "send_exs_tcp_stream: " - "aio sent=%d eagain=%d dequeue=%d pending=%d\n", - nummessages, exs_aio_eagain, exs_aio_dequeuecnt, exs_aio_pending); - } - - /* The test is over. Flush the buffers to the remote end. We do a */ - /* graceful release to insure that all data has been taken by the */ - /* remote. */ - - /* but first, if the verbosity is greater than 1, find-out what */ - /* the TCP maximum segment_size was (if possible) */ - if (verbosity > 1) { - tcp_mss = -1; - get_tcp_info(send_socket,&tcp_mss); - } - - if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) { - perror("netperf: cannot shutdown tcp stream socket"); - exit(1); - } - - /* hang a recv() off the socket to block until the remote has */ - /* brought all the data up into the application. it will do a */ - /* shutdown to cause a FIN to be sent our way. We will assume that */ - /* any exit from the recv() call is good... raj 4/93 */ - - recv(send_socket, send_ring->buffer_ptr, send_size, 0); - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured and how */ - /* long did we really */ - /* run? */ - - /* we are finished with the socket, so close it to prevent hitting */ - /* the limit on maximum open files. */ - - close(send_socket); - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a TCP stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) */ - - bytes_sent = ntohd(tcp_stream_result->bytes_received); - - thruput = calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - - remote_cpu_utilization = tcp_stream_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - tcp_stream_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - } - - /* at this point, we have finished making all the runs that we */ - /* will be making. so, we should extract what the calcuated values */ - /* are for all the confidence stuff. we could make the values */ - /* global, but that seemed a little messy, and it did not seem worth */ - /* all the mucking with header files. so, we create a routine much */ - /* like calcualte_confidence, which just returns the mean values. */ - /* raj 11/94 */ - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(tcp_stream_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - fprintf(where, - tput_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - thruput);/* how fast did it go */ - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - /* this stuff needs to be worked-out in the presence of confidence */ - /* intervals and multiple iterations of the test... raj 11/94 */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_send_align, - remote_recv_align, - local_send_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)tcp_stream_result->recv_calls, - tcp_stream_result->recv_calls); - fprintf(where, - ksink_fmt2, - tcp_mss); - fflush(where); -#if 0 /* def WANT_HISTOGRAM */ - fprintf(where,"\n\nHistogram of time spent in send() call.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } - -} - -#endif /* HAVE_ICSC_EXS */ - - - -#if defined(HAVE_SENDFILE) - -#if defined(QUICK_SENDPATH) - -/* - * a temporary stub for the sendpath() system call - * which is defined & implemented in the kernel - * but which has no libc stub. - */ -#include <sys/types.h> -#include <sys/scall_define.h> -#include <sys/uio.h> - -ssize_t -sendpath(int s, char *path, off_t offset, size_t nbytes, - const struct iovec *hdtrl, int flags) - { - return syscall(SYS_sendpath, s, path, offset, nbytes, hdtrl, flags); - } -#endif /* QUICK_SENDPATH */ - -/* This routine implements the TCP unidirectional data transfer test - (a.k.a. stream) for the sockets interface using the sendfile() - system call - TCP_SENDFILE. It receives its parameters via global - variables from the shell and writes its output to the standard - output. Basically, this is the same test as the send_tcp_stream() - logic and we even tell the remote to do a TCP_STREAM test since for - all it knows, nothig is different. */ - -void -sendfile_tcp_stream(remote_host) - char remote_host[]; -{ - - char *tput_title = "\ -Recv Send Send \n\ -Socket Socket Message Elapsed \n\ -Size Size Size Time Throughput \n\ -bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f \n"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Socket Socket Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - char *cpu_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ -Local Remote Local Remote Xfered Per Per\n\ -Send Recv Send Recv Send (avg) Recv (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - -char *ksink_fmt2 = "\n\ -Maximum\n\ -Segment\n\ -Size (bytes)\n\ -%6d\n"; - - float elapsed_time; - - /* what we want is to have a buffer space that is at least one */ - /* send-size greater than our send window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - - struct sendfile_ring_elt *send_ring; - - int len; - unsigned int nummessages = 0; - SOCKET send_socket; - int bytes_remaining; - int tcp_mss = -1; /* possibly uninitialized on printf far below */ - - /* with links like fddi, one can send > 32 bits worth of bytes */ - /* during a test... ;-) at some point, this should probably become a */ - /* 64bit integral type, but those are not entirely common yet */ - double bytes_sent = 0.0; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - - double thruput; - - struct addrinfo *remote_res; - struct addrinfo *local_res; - struct sockaddr_in server; - -#if defined(__linux) || defined(__sun__) - off_t scratch_offset; /* the linux sendfile() call will update - the offset variable, which is - something we do _not_ want to happen - to the value in the send_ring! so, we - have to use a scratch variable. */ -#endif /* __linux || defined(__sun__) */ -#if defined (USE_OSX) - off_t scratch_len; /* Darwin 9.x need a value-result parameter */ -#endif -#if defined (__sun__) - size_t scratch_len; /* the sun sendfilev() needs a place to - tell us how many bytes were written, - even though it also returns the value */ - sendfilevec_t sv; -#endif /* __sun__ */ - - struct tcp_stream_request_struct *tcp_stream_request; - struct tcp_stream_response_struct *tcp_stream_response; - struct tcp_stream_results_struct *tcp_stream_result; - - tcp_stream_request = - (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data; - tcp_stream_response = - (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data; - tcp_stream_result = - (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - bzero((char *)&server, - sizeof(server)); - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - /* we want to have some additional, interesting information in */ - /* the headers. we know some of it here, but not all, so we will */ - /* only print the test title here and will print the results */ - /* titles after the test is finished */ -#ifdef QUICK_SENDPATH - print_top_test_header("TCP SENDPATH TEST",local_res,remote_res); -#else - print_top_test_header("TCP SENDFILE TEST",local_res,remote_res); -#endif /* QUICK_SENDPATH */ - } - send_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - - /* set up the data socket */ - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: sendfile_tcp_stream: tcp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"sendfile_tcp_stream: send_socket obtained...\n"); - } - -#if defined(TCP_CORK) - /* should this even be here?!? */ - if (loc_tcpcork != 0) { - /* the user wishes for us to set TCP_CORK on the socket */ - int one = 1; - if (setsockopt(send_socket, - getprotobyname("tcp")->p_proto, - TCP_CORK, - (char *)&one, - sizeof(one)) == SOCKET_ERROR) { - perror("netperf: sendfile_tcp_stream: tcp_cork"); - exit(1); - } - if (debug) { - fprintf(where,"sendfile_tcp_stream: tcp_cork...\n"); - } - } - -#endif /* TCP_CORK */ - - /* at this point, we have either retrieved the socket buffer sizes, */ - /* or have tried to set them, so now, we may want to set the send */ - /* size based on that (because the user either did not use a -m */ - /* option, or used one with an argument of 0). If the socket buffer */ - /* size is not available, we will set the send size to 4KB - no */ - /* particular reason, just arbitrary... */ - - /*check for file size/ min file size here? create file here/ back out???*/ - - if (send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - - /* set-up the data buffer ring with the requested alignment and - offset. note also that we have allocated a quantity of memory - that is at least one send-size greater than our socket buffer - size. We want to be sure that there are at least two buffers - allocated - this can be a bit of a problem when the send_size - is bigger than the socket size, so we must check... the user - may have wanted to explicitly set the "width" of our send - buffers, we should respect that wish... */ - - /*sendring -> an offset index that will shift the starting point of the*/ - /*section of the file sent throughout the file*/ - - if (send_width == 0) { - send_width = (lss_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - if (send_ring == NULL) { - - /* only allocate the send ring once. this is a networking test, - not a memory allocation test. this way, we do not need a - deallocate_buffer_ring() routine, and I don't feel like - writing one anyway :) raj 11/94 */ - - send_ring = alloc_sendfile_buf_ring(send_width, - send_size, - local_send_align, - local_send_offset); - } - - /* If the user has requested cpu utilization measurements, we must - calibrate the cpu(s). We will perform this task within the - tests themselves. If the user has specified the cpu rate, then - calibrate_local_cpu will return rather quickly as it will have - nothing to do. If local_cpu_rate is zero, then we will go - through all the "normal" calibration stuff and return the rate - back. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the - socket paramters on the other side at this point, hence the - reason for all the values being passed in the setup - message. If the user did not specify any of the parameters, - they will be passed as 0, which will indicate to the remote - that no changes beyond the system's default should be - used. Alignment is the exception, it will default to 1, which - will be no alignment alterations. */ - - netperf_request.content.request_type = DO_TCP_STREAM; - tcp_stream_request->send_buf_size = rss_size_req; - tcp_stream_request->recv_buf_size = rsr_size_req; - tcp_stream_request->receive_size = recv_size; - tcp_stream_request->no_delay = rem_nodelay; - tcp_stream_request->recv_alignment = remote_recv_align; - tcp_stream_request->recv_offset = remote_recv_offset; - tcp_stream_request->measure_cpu = remote_cpu_usage; - tcp_stream_request->cpu_rate = remote_cpu_rate; - - if (test_time) { - tcp_stream_request->test_length = test_time; - } - else { - tcp_stream_request->test_length = test_bytes; - } - - tcp_stream_request->so_rcvavoid = rem_rcvavoid; - tcp_stream_request->so_sndavoid = rem_sndavoid; - -#ifdef DIRTY - tcp_stream_request->dirty_count = rem_dirty_count; - tcp_stream_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - tcp_stream_request->port = atoi(remote_data_port); - tcp_stream_request->ipfamily = af_to_nf(remote_res->ai_family); - - if (debug > 1) { - fprintf(where, - "netperf: send_tcp_stream: requesting TCP stream test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant - socket parameters for this test type. We will put them back - into the variables here so they can be displayed if desired. - The remote will have calibrated CPU if necessary, and will have - done all the needed set-up we will have calibrated the cpu - locally before sending the request, and will grab the counter - value right after the connect returns. The remote will grab the - counter right after the accept call. This saves the hassle of - extra messages being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = tcp_stream_response->recv_buf_size; - rss_size = tcp_stream_response->send_buf_size; - rem_nodelay = tcp_stream_response->no_delay; - remote_cpu_usage= tcp_stream_response->measure_cpu; - remote_cpu_rate = tcp_stream_response->cpu_rate; - - /* we have to make sure that the server port number is in */ - /* network order */ - set_port_number(remote_res,(short)tcp_stream_response->data_port_number); - rem_rcvavoid = tcp_stream_response->so_rcvavoid; - rem_sndavoid = tcp_stream_response->so_sndavoid; - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - -#ifdef WANT_DEMO - DEMO_STREAM_SETUP(lss_size,rsr_size) -#endif - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("netperf: send_tcp_stream: data socket connect failed"); - printf(" port: %d\n",ntohs(server.sin_port)); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either - the connect would have failed, or the previous response would - have indicated a problem. I failed to see the value of the - extra message after the accept on the remote. If it failed, - we'll see it here. If it didn't, we might as well start pumping - data. */ - - /* Set-up the test end conditions. For a stream test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - - /* in previous revisions, we had the same code repeated throught - all the test suites. this was unnecessary, and meant more - work for me when I wanted to switch to POSIX signals, so I - have abstracted this out into a routine in netlib.c. if you - are experiencing signal problems, you might want to look - there. raj 11/94 */ - - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - bytes_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - - - /* before we start, initialize a few variables */ - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - /* We use an "OR" to control test execution. When the test is - controlled by time, the byte count check will always return - false. When the test is controlled by byte count, the time test - will always return false. When the test is finished, the whole - expression will go false and we will stop sending data. */ - - while ((!times_up) || (bytes_remaining > 0)) { - - /* the sendfile_tcp_stream test does not support making the buffers - dirty. 08/2000 */ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before we go into sendfile() and then again - just after we come out raj 08/2000 */ - /* but only if we are actually going to display a histogram */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - /* you can look at netlib.h for a description of the fields we - are passing to sendfile(). 08/2000 */ -#ifdef QUICK_SENDPATH - if ((len=sendpath(send_socket, - fill_file, - send_ring->offset, - send_ring->length, - send_ring->hdtrl, - send_ring->flags)) != send_size) -#elif defined(__linux) - scratch_offset = send_ring->offset; - if ((len=sendfile(send_socket, - send_ring->fildes, - &scratch_offset, /* modified after the call! */ - send_ring->length)) != send_size) -#elif defined (__sun__) - /* We must call with SFV_NOWAIT and a large file size (>= 16MB) to - get zero-copy, as well as compiling with -D_LARGEFILE_SOURCE - -D_FILE_OFFSET_BITS=64 */ - sv.sfv_fd = send_ring->fildes; - sv.sfv_flag = SFV_NOWAIT; - sv.sfv_off = send_ring->offset; - sv.sfv_len = send_ring->length; - if ((len = sendfilev(send_socket, &sv, 1, &scratch_len)) != send_size) -#elif defined(__FreeBSD__) - /* so close to HP-UX and yet so far away... :) */ - if ((sendfile(send_ring->fildes, - send_socket, - send_ring->offset, - send_ring->length, - NULL, - (off_t *)&len, - send_ring->flags) != 0) || - (len != send_size)) -#elif defined(USE_OSX) - scratch_len = send_ring->length; - if ((sendfile(send_ring->fildes, - send_socket, - send_ring->offset, - (off_t *)&scratch_len, - NULL, - send_ring->flags) != 0) || - (scratch_len != send_size)) -#else /* original sendile HP-UX */ - if ((len=sendfile(send_socket, - send_ring->fildes, - send_ring->offset, - send_ring->length, - send_ring->hdtrl, - send_ring->flags)) != send_size) -#endif /* QUICK_SENDPATH */ - { - /* the test was interrupted, must be the end of test. the - send_tcp_stream code has some WIN32 ifdefs that we do not - need here. */ - if ((len >=0) || SOCKET_EINTR(len)) { - break; - } - perror("netperf: data send error: sendfile"); - fprintf(stderr, - "len was %d send_size was %d\n", - len, - send_size); - fflush(stderr); - exit(1); - } - - /* offset += len;*/ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp the exit from the send call and update the - histogram */ - - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_DEMO - DEMO_STREAM_INTERVAL(send_size); -#endif - -#ifdef WANT_INTERVALS - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - /* now we want to move our pointer to the next position in the */ - /* data buffer...we may also want to wrap back to the "beginning" */ - /* of the bufferspace, so we will mod the number of messages sent */ - /* by the send width, and use that to calculate the offset to add */ - /* to the base pointer. */ - - nummessages++; - send_ring = send_ring->next; - if (bytes_remaining) { - bytes_remaining -= send_size; - } - } - - /* The test is over. Flush the buffers to the remote end. We do a - graceful release to insure that all data has been taken by the - remote. */ - - /* but first, if the verbosity is greater than 1, find-out what */ - /* the TCP maximum segment_size was (if possible) */ - if (verbosity > 1) { - tcp_mss = -1; - get_tcp_info(send_socket,&tcp_mss); - } - - if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) { - perror("netperf: cannot shutdown tcp stream socket"); - exit(1); - } - - /* hang a recv() off the socket to block until the remote has */ - /* brought all the data up into the application. it will do a */ - /* shutdown to cause a FIN to be sent our way. We will assume that */ - /* any exit from the recv() call is good... raj 4/93 */ - - /* since we are using sendfile() instead of send, we have no - scratch buffer from the send_ring to use for the - receive. however, since we "know" that the recv should be - returning zero bytes (not that we are making the checks we - should) we can pass the address of the flags field. raj 08/2000 - */ - - recv(send_socket, - &(send_ring->flags), - sizeof(send_ring->flags), - 0); - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured and how */ - /* long did we really */ - /* run? */ - - /* we are finished with the socket, so close it to prevent hitting */ - /* the limit on maximum open files. */ - - close(send_socket); - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a TCP stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) */ - - bytes_sent = ntohd(tcp_stream_result->bytes_received); - - thruput = calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - - remote_cpu_utilization = tcp_stream_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - tcp_stream_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - confidence_iteration++; - } - - /* at this point, we have finished making all the runs that we */ - /* will be making. so, we should extract what the calcuated values */ - /* are for all the confidence stuff. we could make the values */ - /* global, but that seemed a little messy, and it did not seem worth */ - /* all the mucking with header files. so, we create a routine much */ - /* like calcualte_confidence, which just returns the mean values. */ - /* raj 11/94 */ - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(tcp_stream_result->cpu_method); - - switch (verbosity) { - case 0: - - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - - break; - - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - break; - } - - } - - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - - case 0: - - fprintf(where, - tput_fmt_0, - thruput); - break; - - case 1: - case 2: - - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - thruput);/* how fast did it go */ - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - /* this stuff needs to be worked-out in the presence of confidence */ - /* intervals and multiple iterations of the test... raj 11/94 */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_send_align, - remote_recv_align, - local_send_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)tcp_stream_result->recv_calls, - tcp_stream_result->recv_calls); - - fprintf(where, - ksink_fmt2, - tcp_mss); - - fflush(where); - -#ifdef WANT_HISTOGRAM - - fprintf(where,"\n\nHistogram of time spent in send() call.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } -} - -#endif /* HAVE_SENDFILE */ - -/* This is the server-side routine for the tcp stream test. It is */ -/* implemented as one routine. I could break things-out somewhat, but */ -/* didn't feel it was necessary. */ - -void -recv_tcp_stream() -{ - - struct sockaddr_storage myaddr_in, peeraddr_in; - SOCKET s_listen,s_data; - netperf_socklen_t addrlen; - int len; - unsigned int receive_calls; - float elapsed_time; - double bytes_received; - - struct ring_elt *recv_ring; - - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - -#ifdef DO_SELECT - fd_set readfds; - struct timeval timeout; -#endif /* DO_SELECT */ - - struct tcp_stream_request_struct *tcp_stream_request; - struct tcp_stream_response_struct *tcp_stream_response; - struct tcp_stream_results_struct *tcp_stream_results; - -#ifdef DO_SELECT - FD_ZERO(&readfds); - timeout.tv_sec = 1; - timeout.tv_usec = 0; -#endif /* DO_SELECT */ - - tcp_stream_request = - (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data; - tcp_stream_response = - (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data; - tcp_stream_results = - (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_tcp_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_tcp_stream: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = TCP_STREAM_RESPONSE; - - if (debug) { - fprintf(where,"recv_tcp_stream: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug) { - fprintf(where,"recv_tcp_stream: requested alignment of %d\n", - tcp_stream_request->recv_alignment); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = tcp_stream_request->send_buf_size; - lsr_size_req = tcp_stream_request->recv_buf_size; - loc_nodelay = tcp_stream_request->no_delay; - loc_rcvavoid = tcp_stream_request->so_rcvavoid; - loc_sndavoid = tcp_stream_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(tcp_stream_request->ipfamily), - tcp_stream_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(tcp_stream_request->ipfamily), - SOCK_STREAM, - IPPROTO_TCP, - 0); - - s_listen = create_data_socket(local_res); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - -#ifdef WIN32 - /* The test timer can fire during operations on the listening socket, - so to make the start_timer below work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket2 = s_listen; -#endif - - /* what sort of sizes did we end-up with? */ - if (tcp_stream_request->receive_size == 0) { - if (lsr_size > 0) { - recv_size = lsr_size; - } - else { - recv_size = 4096; - } - } - else { - recv_size = tcp_stream_request->receive_size; - } - - /* we want to set-up our recv_ring in a manner analagous to what we */ - /* do on the sending side. this is more for the sake of symmetry */ - /* than for the needs of say copy avoidance, but it might also be */ - /* more realistic - this way one could conceivably go with a */ - /* double-buffering scheme when taking the data an putting it into */ - /* the filesystem or something like that. raj 7/94 */ - - if (recv_width == 0) { - recv_width = (lsr_size/recv_size) + 1; - if (recv_width == 1) recv_width++; - } - - recv_ring = allocate_buffer_ring(recv_width, - recv_size, - tcp_stream_request->recv_alignment, - tcp_stream_request->recv_offset); - - if (debug) { - fprintf(where,"recv_tcp_stream: receive alignment and offset set...\n"); - fflush(where); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - tcp_stream_response->data_port_number = - (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - tcp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */ - if (tcp_stream_request->measure_cpu) { - tcp_stream_response->measure_cpu = 1; - tcp_stream_response->cpu_rate = - calibrate_local_cpu(tcp_stream_request->cpu_rate); - } - else { - tcp_stream_response->measure_cpu = 0; - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - tcp_stream_response->send_buf_size = lss_size; - tcp_stream_response->recv_buf_size = lsr_size; - tcp_stream_response->no_delay = loc_nodelay; - tcp_stream_response->so_rcvavoid = loc_rcvavoid; - tcp_stream_response->so_sndavoid = loc_sndavoid; - tcp_stream_response->receive_size = recv_size; - - send_response(); - - addrlen = sizeof(peeraddr_in); - - if ((s_data=accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - exit(1); - } - -#ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass */ - /* attributes across an accept() call. Including this goes against */ - /* my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(tcp_stream_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - /* there used to be an #ifdef DIRTY call to access_buffer() here, - but we have switched from accessing the buffer before the recv() - call to accessing the buffer after the recv() call. The - accessing before was, IIRC, related to having dirty data when - doing page-flipping copy avoidance. */ - - bytes_received = 0; - receive_calls = 0; - - while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) { - if (len == SOCKET_ERROR ) - { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - bytes_received += len; - receive_calls++; - -#ifdef DIRTY - /* we access the buffer after the recv() call now, rather than before */ - access_buffer(recv_ring->buffer_ptr, - recv_size, - tcp_stream_request->dirty_count, - tcp_stream_request->clean_count); -#endif /* DIRTY */ - - - /* move to the next buffer in the recv_ring */ - recv_ring = recv_ring->next; - -#ifdef PAUSE - sleep(1); -#endif /* PAUSE */ - -#ifdef DO_SELECT - FD_SET(s_data,&readfds); - select(s_data+1,&readfds,NULL,NULL,&timeout); -#endif /* DO_SELECT */ - - } - - /* perform a shutdown to signal the sender that */ - /* we have received all the data sent. raj 4/93 */ - - if (shutdown(s_data,SHUT_WR) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - cpu_stop(tcp_stream_request->measure_cpu,&elapsed_time); - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_tcp_stream: got %g bytes\n", - bytes_received); - fprintf(where, - "recv_tcp_stream: got %d recvs\n", - receive_calls); - fflush(where); - } - - tcp_stream_results->bytes_received = htond(bytes_received); - tcp_stream_results->elapsed_time = elapsed_time; - tcp_stream_results->recv_calls = receive_calls; - - tcp_stream_results->cpu_method = cpu_method; - tcp_stream_results->num_cpus = lib_num_loc_cpus; - - if (tcp_stream_request->measure_cpu) { - tcp_stream_results->cpu_util = calc_cpu_util(0.0); - }; - - if (debug) { - fprintf(where, - "recv_tcp_stream: test complete, sending results.\n"); - fprintf(where, - " bytes_received %g receive_calls %d\n", - bytes_received, - receive_calls); - fprintf(where, - " len %d\n", - len); - fflush(where); - } - - send_response(); - - /* we are now done with the sockets */ - close(s_data); - close(s_listen); - - } - -/* This is the server-side routine for the tcp maerts test. It is - implemented as one routine. I could break things-out somewhat, but - didn't feel it was necessary. */ - -void -recv_tcp_maerts() -{ - - struct sockaddr_storage myaddr_in, peeraddr_in; - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - - SOCKET s_listen,s_data; - netperf_socklen_t addrlen; - int len; - unsigned int send_calls; - float elapsed_time; - double bytes_sent = 0.0 ; - - struct ring_elt *send_ring; - - struct tcp_maerts_request_struct *tcp_maerts_request; - struct tcp_maerts_response_struct *tcp_maerts_response; - struct tcp_maerts_results_struct *tcp_maerts_results; - - tcp_maerts_request = - (struct tcp_maerts_request_struct *)netperf_request.content.test_specific_data; - tcp_maerts_response = - (struct tcp_maerts_response_struct *)netperf_response.content.test_specific_data; - tcp_maerts_results = - (struct tcp_maerts_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_tcp_maerts: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired - parameters and then let the initiator know that all is ready. If - socket size defaults are to be used, then the initiator will have - sent us 0's. If the socket sizes cannot be changed, then we will - send-back what they are. If that information cannot be - determined, then we send-back -1's for the sizes. If things go - wrong for any reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It - would be best if the error that the remote reports to the user is - the actual error we encountered, rather than some bogus - unexpected response type message. */ - - if (debug) { - fprintf(where,"recv_tcp_maerts: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = TCP_MAERTS_RESPONSE; - - if (debug) { - fprintf(where,"recv_tcp_maerts: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug) { - fprintf(where,"recv_tcp_maerts: requested alignment of %d\n", - tcp_maerts_request->send_alignment); - fflush(where); - } - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_tcp_maerts: grabbing a socket...\n"); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = tcp_maerts_request->send_buf_size; - lsr_size_req = tcp_maerts_request->recv_buf_size; - loc_nodelay = tcp_maerts_request->no_delay; - loc_rcvavoid = tcp_maerts_request->so_rcvavoid; - loc_sndavoid = tcp_maerts_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(tcp_maerts_request->ipfamily), - tcp_maerts_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(tcp_maerts_request->ipfamily), - SOCK_STREAM, - IPPROTO_TCP, - 0); - - s_listen = create_data_socket(local_res); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - -#ifdef WIN32 - /* The test timer can fire during operations on the listening socket, - so to make the start_timer below work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket2 = s_listen; -#endif - - - /* what sort of sizes did we end-up with? */ - if (tcp_maerts_request->send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - else { - send_size = tcp_maerts_request->send_size; - } - - /* we want to set-up our recv_ring in a manner analagous to what we */ - /* do on the recving side. this is more for the sake of symmetry */ - /* than for the needs of say copy avoidance, but it might also be */ - /* more realistic - this way one could conceivably go with a */ - /* double-buffering scheme when taking the data an putting it into */ - /* the filesystem or something like that. raj 7/94 */ - - if (send_width == 0) { - send_width = (lsr_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - send_ring = allocate_buffer_ring(send_width, - send_size, - tcp_maerts_request->send_alignment, - tcp_maerts_request->send_offset); - - if (debug) { - fprintf(where,"recv_tcp_maerts: receive alignment and offset set...\n"); - fflush(where); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - tcp_maerts_response->data_port_number = - (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - tcp_maerts_response->cpu_rate = (float)0.0; /* assume no cpu */ - if (tcp_maerts_request->measure_cpu) { - tcp_maerts_response->measure_cpu = 1; - tcp_maerts_response->cpu_rate = - calibrate_local_cpu(tcp_maerts_request->cpu_rate); - } - else { - tcp_maerts_response->measure_cpu = 0; - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - tcp_maerts_response->send_buf_size = lss_size; - tcp_maerts_response->recv_buf_size = lsr_size; - tcp_maerts_response->no_delay = loc_nodelay; - tcp_maerts_response->so_rcvavoid = loc_rcvavoid; - tcp_maerts_response->so_sndavoid = loc_sndavoid; - tcp_maerts_response->send_size = send_size; - - send_response(); - - addrlen = sizeof(peeraddr_in); - - /* we will start the timer before the accept() to be somewhat - analagous to the starting of the timer before the connect() call - in the TCP_STREAM test. raj 2002-06-21 */ - - start_timer(tcp_maerts_request->test_length); - - /* Now it's time to start receiving data on the connection. We will - first grab the apropriate counters and then start grabbing. */ - - cpu_start(tcp_maerts_request->measure_cpu); - - - if ((s_data=accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - exit(1); - } - -#ifdef KLUDGE_SOCKET_OPTIONS - - /* this is for those systems which *INCORRECTLY* fail to pass - attributes across an accept() call. Including this goes against - my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - bytes_sent = 0.0; - send_calls = 0; - - len = 0; /* nt-lint; len is not initialized (printf far below) if - times_up initially true.*/ - times_up = 0; /* must remember to initialize this little beauty */ - while (!times_up) { - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - - access_buffer(send_ring->buffer_ptr, - send_size, - tcp_maerts_request->dirty_count, - tcp_maerts_request->clean_count); - -#endif /* DIRTY */ - - if((len=send(s_data, - send_ring->buffer_ptr, - send_size, - 0)) != send_size) { - if ((len >=0) || SOCKET_EINTR(len)) { - /* the test was interrupted, must be the end of test */ - break; - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - bytes_sent += len; - send_calls++; - - /* more to the next buffer in the send_ring */ - send_ring = send_ring->next; - - } - - /* perform a shutdown to signal the sender that */ - /* we have received all the data sent. raj 4/93 */ - - if (shutdown(s_data,SHUT_WR) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* hang a recv() off the socket to block until the remote has - brought all the data up into the application. it will do a - shutdown to cause a FIN to be sent our way. We will assume that - any exit from the recv() call is good... raj 4/93 */ - - recv(s_data, send_ring->buffer_ptr, send_size, 0); - - - cpu_stop(tcp_maerts_request->measure_cpu,&elapsed_time); - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_tcp_maerts: got %g bytes\n", - bytes_sent); - fprintf(where, - "recv_tcp_maerts: got %d sends\n", - send_calls); - fflush(where); - } - - tcp_maerts_results->bytes_sent = htond(bytes_sent); - tcp_maerts_results->elapsed_time = elapsed_time; - tcp_maerts_results->send_calls = send_calls; - - if (tcp_maerts_request->measure_cpu) { - tcp_maerts_results->cpu_util = calc_cpu_util(0.0); - }; - - if (debug) { - fprintf(where, - "recv_tcp_maerts: test complete, sending results.\n"); - fprintf(where, - " bytes_sent %g send_calls %d\n", - bytes_sent, - send_calls); - fprintf(where, - " len %d\n", - len); - fflush(where); - } - - tcp_maerts_results->cpu_method = cpu_method; - tcp_maerts_results->num_cpus = lib_num_loc_cpus; - send_response(); - - /* we are now done with the sockets */ - close(s_data); - close(s_listen); - - } - - - /* this routine implements the sending (netperf) side of the TCP_RR */ - /* test. */ - -void -send_tcp_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_title_band = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed \n\ -Send Recv Size Size Time Throughput \n\ -bytes Bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f %s\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f %s\n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; - - char *cpu_title_tput = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Tput CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time %-8.8s local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c %s\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\ -Alignment Offset RoundTrip Trans Throughput\n\ -Local Remote Local Remote Latency Rate %-8.8s/s\n\ -Send Recv Send Recv usec/Tran per sec Outbound Inbound\n\ -%5d %5d %5d %5d %-6.3f %-6.3f %-6.3f %-6.3f\n"; - - - int timed_out = 0; - float elapsed_time; - - int len; - char *temp_message_ptr; - int nummessages; - SOCKET send_socket; - int trans_remaining; - double bytes_xferd; - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - int rsp_bytes_left; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct addrinfo *local_res; - struct addrinfo *remote_res; - - struct tcp_rr_request_struct *tcp_rr_request; - struct tcp_rr_response_struct *tcp_rr_response; - struct tcp_rr_results_struct *tcp_rr_result; - -#ifdef WANT_FIRST_BURST -#define REQUEST_CWND_INITIAL 2 - /* "in the beginning..." the WANT_FIRST_BURST stuff was like both - Unix and the state of New Jersey - both were simple an unspoiled. - then it was realized that some stacks are quite picky about - initial congestion windows and a non-trivial initial burst of - requests would not be individual segments even with TCP_NODELAY - set. so, we have to start tracking a poor-man's congestion window - up here in window space because we want to try to make something - happen that frankly, we cannot guarantee with the specification - of TCP. ain't that grand?-) raj 2006-01-30 */ - int requests_outstanding = 0; - int request_cwnd = REQUEST_CWND_INITIAL; /* we ass-u-me that having - three requests - outstanding at the - beginning of the test - is ok with TCP stacks - of interest. the first - two will come from our - first_burst loop, and - the third from our - regularly scheduled - send */ -#endif - - tcp_rr_request = - (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data; - tcp_rr_response= - (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data; - tcp_rr_result = - (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("TCP REQUEST/RESPONSE TEST",local_res,remote_res); - } - - /* initialize a few counters */ - - send_ring = NULL; - recv_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - timed_out = 0; - trans_remaining = 0; - -#ifdef WANT_FIRST_BURST - /* we have to remember to reset the number of transactions - outstanding and the "congestion window for each new - iteration. raj 2006-01-31 */ - requests_outstanding = 0; - request_cwnd = REQUEST_CWND_INITIAL; -#endif - - - /* set-up the data buffers with the requested alignment and offset. */ - /* since this is a request/response test, default the send_width and */ - /* recv_width to 1 and not two raj 7/94 */ - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - if (send_ring == NULL) { - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - } - - if (recv_ring == NULL) { - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - } - - /*set up the data socket */ - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_tcp_rr: tcp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_tcp_rr: send_socket obtained...\n"); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - if (!no_control) { - /* Tell the remote end to do a listen. The server alters the - socket paramters on the other side at this point, hence the - reason for all the values being passed in the setup - message. If the user did not specify any of the parameters, - they will be passed as 0, which will indicate to the remote - that no changes beyond the system's default should be - used. Alignment is the exception, it will default to 8, which - will be no alignment alterations. */ - - netperf_request.content.request_type = DO_TCP_RR; - tcp_rr_request->recv_buf_size = rsr_size_req; - tcp_rr_request->send_buf_size = rss_size_req; - tcp_rr_request->recv_alignment = remote_recv_align; - tcp_rr_request->recv_offset = remote_recv_offset; - tcp_rr_request->send_alignment = remote_send_align; - tcp_rr_request->send_offset = remote_send_offset; - tcp_rr_request->request_size = req_size; - tcp_rr_request->response_size = rsp_size; - tcp_rr_request->no_delay = rem_nodelay; - tcp_rr_request->measure_cpu = remote_cpu_usage; - tcp_rr_request->cpu_rate = remote_cpu_rate; - tcp_rr_request->so_rcvavoid = rem_rcvavoid; - tcp_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - tcp_rr_request->test_length = test_time; - } - else { - tcp_rr_request->test_length = test_trans * -1; - } - tcp_rr_request->port = atoi(remote_data_port); - tcp_rr_request->ipfamily = af_to_nf(remote_res->ai_family); - - if (debug > 1) { - fprintf(where,"netperf: send_tcp_rr: requesting TCP rr test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant - socket parameters for this test type. We will put them back - into the variables here so they can be displayed if desired. - The remote will have calibrated CPU if necessary, and will - have done all the needed set-up we will have calibrated the - cpu locally before sending the request, and will grab the - counter value right after the connect returns. The remote - will grab the counter right after the accept call. This saves - the hassle of extra messages being sent for the TCP - tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = tcp_rr_response->recv_buf_size; - rss_size = tcp_rr_response->send_buf_size; - rem_nodelay = tcp_rr_response->no_delay; - remote_cpu_usage = tcp_rr_response->measure_cpu; - remote_cpu_rate = tcp_rr_response->cpu_rate; - /* make sure that port numbers are in network order */ - set_port_number(remote_res,(short)tcp_rr_response->data_port_number); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - } - -#ifdef WANT_DEMO - DEMO_RR_SETUP(1000) -#endif - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("netperf: data socket connect failed"); - - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - while ((!times_up) || (trans_remaining > 0)) { - /* send the request. we assume that if we use a blocking socket, */ - /* the request will be sent at one shot. */ - -#ifdef WANT_FIRST_BURST - /* we can inject no more than request_cwnd, which will grow with - time, and no more than first_burst_size. we don't use <= to - account for the "regularly scheduled" send call. of course - that makes it more a "max_outstanding_ than a - "first_burst_size" but for now we won't fix the names. also, - I suspect the extra check against < first_burst_size is - redundant since later I expect to make sure that request_cwnd - can never get larger than first_burst_size, but just at the - moment I'm feeling like a belt and suspenders kind of - programmer. raj 2006-01-30 */ - while ((first_burst_size > 0) && - (requests_outstanding < request_cwnd) && - (requests_outstanding < first_burst_size)) { - if (debug) { - fprintf(where, - "injecting, req_outstndng %d req_cwnd %d burst %d\n", - requests_outstanding, - request_cwnd, - first_burst_size); - } - if ((len = send(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - /* we should never hit the end of the test in the first burst */ - perror("send_tcp_rr: initial burst data send error"); - exit(-1); - } - requests_outstanding += 1; - } - -#endif /* WANT_FIRST_BURST */ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before our call to send, and then again just - after the receive raj 8/94 */ - /* but only if we are actually going to display one. raj - 2007-02-07 */ - - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - if ((len = send(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - if (SOCKET_EINTR(len) || (errno == 0)) { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("send_tcp_rr: data send error"); - exit(1); - } - send_ring = send_ring->next; - -#ifdef WANT_FIRST_BURST - requests_outstanding += 1; -#endif - - /* receive the response */ - rsp_bytes_left = rsp_size; - temp_message_ptr = recv_ring->buffer_ptr; - while(rsp_bytes_left > 0) { - if((rsp_bytes_recvd=recv(send_socket, - temp_message_ptr, - rsp_bytes_left, - 0)) == SOCKET_ERROR) { - if ( SOCKET_EINTR(rsp_bytes_recvd) ) { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } - perror("send_tcp_rr: data recv error"); - exit(1); - } - rsp_bytes_left -= rsp_bytes_recvd; - temp_message_ptr += rsp_bytes_recvd; - } - recv_ring = recv_ring->next; - -#ifdef WANT_FIRST_BURST - /* so, since we've gotten a response back, update the - bookkeeping accordingly. there is one less request - outstanding and we can put one more out there than before. */ - requests_outstanding -= 1; - if (request_cwnd < first_burst_size) { - request_cwnd += 1; - if (debug) { - fprintf(where, - "incr req_cwnd to %d first_burst %d reqs_outstndng %d\n", - request_cwnd, - first_burst_size, - requests_outstanding); - } - } -#endif - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_DEMO - DEMO_RR_INTERVAL(1); -#endif - -#ifdef WANT_INTERVALS - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - if ((nummessages % 100) == 0) { - fprintf(where, - "Transaction %d completed\n", - nummessages); - fflush(where); - } - } - } - - /* At this point we used to call shutdown on the data socket to be - sure all the data was delivered, but this was not germane in a - request/response test, and it was causing the tests to "hang" - when they were being controlled by time. So, I have replaced - this shutdown call with a call to close that can be found later - in the procedure. */ - - /* this call will always give us the elapsed time for the test, - and will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured? how long */ - /* did we really run? */ - - if (!no_control) { - /* Get the statistics from the remote end. The remote will have - calculated CPU utilization. If it wasn't supposed to care, it - will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where,"netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - } - - /* We now calculate what our "throughput" was for the test. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = nummessages/elapsed_time; - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu - utilization for the system(s) Of course, some of the - information might be bogus because there was no idle counter in - the kernel(s). We need to make a note of this for the user's - benefit... */ - if (local_cpu_usage) { - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will - multiply the number of transaction by 1024 to get "good" - numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - remote_cpu_utilization = tcp_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will - multiply the number of transaction by 1024 to get "good" - numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - tcp_rr_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. - if debugging is on, calculate_confidence will print-out the - parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - - /* we are now done with the socket, so close it */ - close(send_socket); - - } - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user has - specified zero-level verbosity, we will just print the local - service demand, or the remote service demand. If the user has - requested verbosity level 1, he will get the basic "streamperf" - numbers. If the user has specified a verbosity of greater than 1, - we will display a veritable plethora of background information - from outside of this block as it it not cpu_measurement - specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(tcp_rr_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - break; - case 1: - case 2: - if (print_headers) { - if ('x' == libfmt) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - else { - fprintf(where, - cpu_title_tput, - format_units(), - local_cpu_method, - remote_cpu_method); - } - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - ('x' == libfmt) ? thruput : - calc_thruput_interval_omni(thruput * (req_size+rsp_size), - 1.0), - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand, /* remote service demand */ - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - ('x' == libfmt) ? thruput : - calc_thruput_interval_omni(thruput * (req_size+rsp_size), - 1.0), - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - ('x' == libfmt) ? tput_title : tput_title_band, - format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - /* are we trans or do we need to convert to bytes then - bits? at this point, thruput is in our "confident" - transactions per second. we can convert to a - bidirectional bitrate by multiplying that by the sum - of the req_size and rsp_size. we pass that to - calc_thruput_interval_omni with an elapsed time of - 1.0 s to get it converted to [kmg]bits/s or - [KMG]Bytes/s */ - ('x' == libfmt) ? thruput : - calc_thruput_interval_omni(thruput * (req_size+rsp_size), - 1.0), - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - /* how to handle the verbose information in the presence of */ - /* confidence intervals is yet to be determined... raj 11/94 */ - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - /* normally, you might think that if we were messing about with - the value of libfmt we would need to put it back again, but - since this is basically the last thing we are going to do with - it, it does not matter. so there :) raj 2007-06-08 */ - /* if the user was asking for transactions, then we report - megabits per sedcond for the unidirectional throughput, - otherwise we use the desired units. */ - if ('x' == libfmt) { - libfmt = 'm'; - } - - fprintf(where, - ksink_fmt, - format_units(), - local_send_align, - remote_recv_offset, - local_send_offset, - remote_recv_offset, - /* if the user has enable burst mode, we have to remember - to account for that in the number of transactions - outstanding at any one time. otherwise we will - underreport the latency of individual - transactions. learned from saf by raj 2007-06-08 */ - (((double)1.0/thruput)*(double)1000000.0) * - (double) (1+first_burst_size), - thruput, - calc_thruput_interval_omni(thruput * (double)req_size,1.0), - calc_thruput_interval_omni(thruput * (double)rsp_size,1.0)); - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/response times\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - - } - -} - -void -send_udp_stream(char remote_host[]) -{ - /**********************************************************************/ - /* */ - /* UDP Unidirectional Send Test */ - /* */ - /**********************************************************************/ - -#define UDP_LENGTH_MAX 0XFFFF - 28 - - char *tput_title = "\ -Socket Message Elapsed Messages \n\ -Size Size Time Okay Errors Throughput\n\ -bytes bytes secs # # %s/sec\n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = "\ -%6d %6d %-7.2f %7d %6d %7.2f\n\ -%6d %-7.2f %7d %7.2f\n\n"; - - - char *cpu_title = "\ -Socket Message Elapsed Messages CPU Service\n\ -Size Size Time Okay Errors Throughput Util Demand\n\ -bytes bytes secs # # %s/sec %% %c%c us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.2f %c\n"; - - char *cpu_fmt_1 = "\ -%6d %6d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\ -%6d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n"; - - unsigned int messages_recvd; - unsigned int messages_sent; - unsigned int failed_sends; - - float elapsed_time, - local_cpu_utilization, - remote_cpu_utilization; - - float local_service_demand, remote_service_demand; - double local_thruput, remote_thruput; - double bytes_sent; - double bytes_recvd; - - - int len; - struct ring_elt *send_ring; - SOCKET data_socket; - - unsigned int sum_messages_sent; - unsigned int sum_messages_recvd; - unsigned int sum_failed_sends; - double sum_local_thruput; - - struct addrinfo *local_res; - struct addrinfo *remote_res; - - struct udp_stream_request_struct *udp_stream_request; - struct udp_stream_response_struct *udp_stream_response; - struct udp_stream_results_struct *udp_stream_results; - - udp_stream_request = - (struct udp_stream_request_struct *)netperf_request.content.test_specific_data; - udp_stream_response = - (struct udp_stream_response_struct *)netperf_response.content.test_specific_data; - udp_stream_results = - (struct udp_stream_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_DGRAM, - IPPROTO_UDP, - 0); - - if ( print_headers ) { - print_top_test_header("UDP UNIDIRECTIONAL SEND TEST",local_res,remote_res); - } - - send_ring = NULL; - confidence_iteration = 1; - init_stat(); - sum_messages_sent = 0; - sum_messages_recvd = 0; - sum_failed_sends = 0; - sum_local_thruput = 0.0; - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - messages_sent = 0; - messages_recvd = 0; - failed_sends = 0; - times_up = 0; - - /*set up the data socket */ - data_socket = create_data_socket(local_res); - - if (data_socket == INVALID_SOCKET){ - perror("udp_send: data socket"); - exit(1); - } - - /* now, we want to see if we need to set the send_size */ - if (send_size == 0) { - if (lss_size > 0) { - send_size = (lss_size < UDP_LENGTH_MAX ? lss_size : UDP_LENGTH_MAX); - } - else { - send_size = 4096; - } - } - - - /* set-up the data buffer with the requested alignment and offset, */ - /* most of the numbers here are just a hack to pick something nice */ - /* and big in an attempt to never try to send a buffer a second time */ - /* before it leaves the node...unless the user set the width */ - /* explicitly. */ - if (send_width == 0) send_width = 32; - - if (send_ring == NULL ) { - send_ring = allocate_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset); - } - - - /* if the user supplied a cpu rate, this call will complete rather */ - /* quickly, otherwise, the cpu rate will be retured to us for */ - /* possible display. The Library will keep it's own copy of this data */ - /* for use elsewhere. We will only display it. (Does that make it */ - /* "opaque" to us?) */ - - if (local_cpu_usage) - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - - if (!no_control) { - /* Tell the remote end to set up the data connection. The server - sends back the port number and alters the socket parameters - there. Of course this is a datagram service so no connection - is actually set up, the server just sets up the socket and - binds it. */ - - netperf_request.content.request_type = DO_UDP_STREAM; - udp_stream_request->recv_buf_size = rsr_size_req; - udp_stream_request->message_size = send_size; - udp_stream_request->recv_connected = remote_connected; - udp_stream_request->recv_alignment = remote_recv_align; - udp_stream_request->recv_offset = remote_recv_offset; - udp_stream_request->measure_cpu = remote_cpu_usage; - udp_stream_request->cpu_rate = remote_cpu_rate; - udp_stream_request->test_length = test_time; - udp_stream_request->so_rcvavoid = rem_rcvavoid; - udp_stream_request->so_sndavoid = rem_sndavoid; - udp_stream_request->port = atoi(remote_data_port); - udp_stream_request->ipfamily = af_to_nf(remote_res->ai_family); - - send_request(); - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"send_udp_stream: remote data connection done.\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("send_udp_stream: error on remote"); - exit(1); - } - - /* Place the port number returned by the remote into the sockaddr */ - /* structure so our sends can be sent to the correct place. Also get */ - /* some of the returned socket buffer information for user display. */ - - /* make sure that port numbers are in the proper order */ - set_port_number(remote_res,(short)udp_stream_response->data_port_number); - - rsr_size = udp_stream_response->recv_buf_size; - rss_size = udp_stream_response->send_buf_size; - remote_cpu_rate = udp_stream_response->cpu_rate; - } - -#ifdef WANT_DEMO - DEMO_STREAM_SETUP(lss_size,rsr_size) -#endif - - /* We "connect" up to the remote post to allow is to use the send */ - /* call instead of the sendto call. Presumeably, this is a little */ - /* simpler, and a little more efficient. I think that it also means */ - /* that we can be informed of certain things, but am not sure */ - /* yet...also, this is the way I would expect a client to behave */ - /* when talking to a server */ - if (local_connected) { - if (connect(data_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("send_udp_stream: data socket connect failed"); - exit(1); - } else if (debug) { - fprintf(where,"send_udp_stream: connected data socket.\n"); - fflush(where); - } - } - - /* set up the timer to call us after test_time. one of these days, */ - /* it might be nice to figure-out a nice reliable way to have the */ - /* test controlled by a byte count as well, but since UDP is not */ - /* reliable, that could prove difficult. so, in the meantime, we */ - /* only allow a UDP_STREAM test to be a timed test. */ - - if (test_time) { - times_up = 0; - start_timer(test_time); - } - else { - fprintf(where,"Sorry, UDP_STREAM tests must be timed.\n"); - fflush(where); - } - - /* Get the start count for the idle counter and the start time */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - /* Send datagrams like there was no tomorrow. at somepoint it might */ - /* be nice to set this up so that a quantity of bytes could be sent, */ - /* but we still need some sort of end of test trigger on the receive */ - /* side. that could be a select with a one second timeout, but then */ - /* if there is a test where none of the data arrives for awile and */ - /* then starts again, we would end the test too soon. something to */ - /* think about... */ - while (!times_up) { - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - - access_buffer(send_ring->buffer_ptr, - send_size, - loc_dirty_count, - loc_clean_count); -#endif /* DIRTY */ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - if (local_connected) { - len = send(data_socket, - send_ring->buffer_ptr, - send_size, - 0); - } else { - len = sendto(data_socket, - send_ring->buffer_ptr, - send_size, - 0, - remote_res->ai_addr, - remote_res->ai_addrlen); - } - - if (len != send_size) { - if ((len >= 0) || - SOCKET_EINTR(len)) - break; - if (errno == ENOBUFS) { - failed_sends++; - continue; - } - perror("udp_send: data send error"); - exit(1); - } - messages_sent++; - - /* now we want to move our pointer to the next position in the */ - /* data buffer... */ - - send_ring = send_ring->next; - - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* get the second timestamp */ - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_DEMO - DEMO_STREAM_INTERVAL(send_size) -#endif - -#ifdef WANT_INTERVALS - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - } - - /* This is a timed test, so the remote will be returning to us after */ - /* a time. We should not need to send any "strange" messages to tell */ - /* the remote that the test is completed, unless we decide to add a */ - /* number of messages to the test. */ - - /* the test is over, so get stats and stuff */ - cpu_stop(local_cpu_usage, - &elapsed_time); - - if (!no_control) { - /* Get the statistics from the remote end */ - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"send_udp_stream: remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("send_udp_stream: error on remote"); - exit(1); - } - messages_recvd = udp_stream_results->messages_recvd; - bytes_recvd = (double) send_size * (double) messages_recvd; - } - else { - /* since there was no control connection, we've no idea what was - actually received. raj 2007-02-08 */ - messages_recvd = -1; - bytes_recvd = -1.0; - } - - bytes_sent = (double) send_size * (double) messages_sent; - local_thruput = calc_thruput(bytes_sent); - - - /* we asume that the remote ran for as long as we did */ - - remote_thruput = calc_thruput(bytes_recvd); - - /* print the results for this socket and message size */ - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) We pass zeros for the local */ - /* cpu utilization and elapsed time to tell the routine to use */ - /* the libraries own values for those. */ - if (local_cpu_usage) { - local_cpu_utilization = calc_cpu_util(0.0); - /* shouldn't this really be based on bytes_recvd, since that is */ - /* the effective throughput of the test? I think that it should, */ - /* so will make the change raj 11/94 */ - local_service_demand = calc_service_demand(bytes_recvd, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - /* The local calculations could use variables being kept by */ - /* the local netlib routines. The remote calcuations need to */ - /* have a few things passed to them. */ - if (remote_cpu_usage) { - remote_cpu_utilization = udp_stream_results->cpu_util; - remote_service_demand = calc_service_demand(bytes_recvd, - 0.0, - remote_cpu_utilization, - udp_stream_results->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - remote_thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - /* since the routine calculate_confidence is rather generic, and */ - /* we have a few other parms of interest, we will do a little work */ - /* here to caclulate their average. */ - sum_messages_sent += messages_sent; - sum_messages_recvd += messages_recvd; - sum_failed_sends += failed_sends; - sum_local_thruput += local_thruput; - - confidence_iteration++; - - /* this datapoint is done, so we don't need the socket any longer */ - close(data_socket); - - } - - /* we should reach this point once the test is finished */ - - retrieve_confident_values(&elapsed_time, - &remote_thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* some of the interesting values aren't covered by the generic */ - /* confidence routine */ - messages_sent = sum_messages_sent / (confidence_iteration -1); - messages_recvd = sum_messages_recvd / (confidence_iteration -1); - failed_sends = sum_failed_sends / (confidence_iteration -1); - local_thruput = sum_local_thruput / (confidence_iteration -1); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(udp_stream_results->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - local_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - messages_sent, - failed_sends, - local_thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - local_service_demand, /* local service demand */ - rsr_size, - elapsed_time, - messages_recvd, - remote_thruput, - remote_cpu_utilization, /* remote cpu */ - remote_service_demand); /* remote service demand */ - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - local_thruput); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - fprintf(where, - tput_fmt_1, /* the format string */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - messages_sent, - failed_sends, - local_thruput, - rsr_size, /* remote recvbuf size */ - elapsed_time, - messages_recvd, - remote_thruput); - break; - } - } - - fflush(where); -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - fprintf(where,"\nHistogram of time spent in send() call\n"); - fflush(where); - HIST_report(time_hist); - } -#endif /* WANT_HISTOGRAM */ - -} - - - /* this routine implements the receive side (netserver) of the */ - /* UDP_STREAM performance test. */ - -void -recv_udp_stream() -{ - struct ring_elt *recv_ring; - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - - struct sockaddr_storage myaddr_in; - SOCKET s_data; - netperf_socklen_t addrlen; - struct sockaddr_storage remote_addr; - netperf_socklen_t remote_addrlen; - - int len = 0; - unsigned int bytes_received = 0; - float elapsed_time; - - int message_size; - unsigned int messages_recvd = 0; - - struct udp_stream_request_struct *udp_stream_request; - struct udp_stream_response_struct *udp_stream_response; - struct udp_stream_results_struct *udp_stream_results; - - udp_stream_request = - (struct udp_stream_request_struct *)netperf_request.content.test_specific_data; - udp_stream_response = - (struct udp_stream_response_struct *)netperf_response.content.test_specific_data; - udp_stream_results = - (struct udp_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_udp_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug > 1) { - fprintf(where,"recv_udp_stream: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = UDP_STREAM_RESPONSE; - - if (debug > 2) { - fprintf(where,"recv_udp_stream: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug > 1) { - fprintf(where,"recv_udp_stream: requested alignment of %d\n", - udp_stream_request->recv_alignment); - fflush(where); - } - - if (recv_width == 0) recv_width = 1; - - recv_ring = allocate_buffer_ring(recv_width, - udp_stream_request->message_size, - udp_stream_request->recv_alignment, - udp_stream_request->recv_offset); - - if (debug > 1) { - fprintf(where,"recv_udp_stream: receive alignment and offset set...\n"); - fflush(where); - } - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug > 1) { - fprintf(where,"recv_udp_stream: grabbing a socket...\n"); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lsr_size_req = udp_stream_request->recv_buf_size; - loc_rcvavoid = udp_stream_request->so_rcvavoid; - loc_sndavoid = udp_stream_request->so_sndavoid; - local_connected = udp_stream_request->recv_connected; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(udp_stream_request->ipfamily), - udp_stream_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(udp_stream_request->ipfamily), - SOCK_DGRAM, - IPPROTO_UDP, - 0); - - s_data = create_data_socket(local_res); - - if (s_data == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - udp_stream_response->test_length = udp_stream_request->test_length; - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_data, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_data); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - udp_stream_response->data_port_number = - (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - udp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */ - udp_stream_response->measure_cpu = 0; - if (udp_stream_request->measure_cpu) { - /* We will pass the rate into the calibration routine. If the */ - /* user did not specify one, it will be 0.0, and we will do a */ - /* "real" calibration. Otherwise, all it will really do is */ - /* store it away... */ - udp_stream_response->measure_cpu = 1; - udp_stream_response->cpu_rate = - calibrate_local_cpu(udp_stream_request->cpu_rate); - } - - message_size = udp_stream_request->message_size; - test_time = udp_stream_request->test_length; - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - udp_stream_response->send_buf_size = lss_size; - udp_stream_response->recv_buf_size = lsr_size; - udp_stream_response->so_rcvavoid = loc_rcvavoid; - udp_stream_response->so_sndavoid = loc_sndavoid; - - send_response(); - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(udp_stream_request->measure_cpu); - -#ifdef WIN32 - /* this is used so the timer thread can close the socket out from */ - /* under us, which to date is the easiest/cleanest/least */ - /* Windows-specific way I can find to force the winsock calls to */ - /* return WSAEINTR with the test is over. anything that will run on */ - /* 95 and NT and is closer to what netperf expects from Unix signals */ - /* and such would be appreciated raj 1/96 */ - win_kludge_socket = s_data; -#endif /* WIN32 */ - - /* The loop will exit when the timer pops, or if we happen to recv a */ - /* message of less than send_size bytes... */ - - times_up = 0; - - start_timer(test_time + PAD_TIME); - - if (debug) { - fprintf(where,"recv_udp_stream: about to enter inner sanctum.\n"); - fflush(where); - } - - /* We "connect" up to the remote post to allow us to use the recv */ - /* call instead of the recvfrom call. Presumeably, this is a little */ - /* simpler, and a little more efficient. */ - - if (local_connected) { - - /* Receive the first message using recvfrom to find the remote address */ - remote_addrlen = sizeof(remote_addr); - len = recvfrom(s_data, recv_ring->buffer_ptr, - message_size, 0, - (struct sockaddr*)&remote_addr, &remote_addrlen); - if (len != message_size) { - if ((len == SOCKET_ERROR) && !SOCKET_EINTR(len)) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - } - messages_recvd++; - recv_ring = recv_ring->next; - - - /* Now connect with the remote socket address */ - if (connect(s_data, - (struct sockaddr*)&remote_addr, - remote_addrlen )== INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - close(s_data); - send_response(); - exit(1); - } - - if (debug) { - fprintf(where,"recv_udp_stream: connected data socket\n"); - fflush(where); - } - } - - while (!times_up) { - if(local_connected) { - len = recv(s_data, - recv_ring->buffer_ptr, - message_size, - 0); - } else { - len = recvfrom(s_data, - recv_ring->buffer_ptr, - message_size, - 0,0,0); - } - - if (len != message_size) { - if ((len == SOCKET_ERROR) && !SOCKET_EINTR(len)) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - break; - } - messages_recvd++; - recv_ring = recv_ring->next; - } - - if (debug) { - fprintf(where,"recv_udp_stream: got %d messages.\n",messages_recvd); - fflush(where); - } - - - /* The loop now exits due timer or < send_size bytes received. in */ - /* reality, we only really support a timed UDP_STREAM test. raj */ - /* 12/95 */ - - cpu_stop(udp_stream_request->measure_cpu,&elapsed_time); - - if (times_up) { - /* we ended on a timer, subtract the PAD_TIME */ - elapsed_time -= (float)PAD_TIME; - } - else { - stop_timer(); - } - - if (debug) { - fprintf(where,"recv_udp_stream: test ended in %f seconds.\n",elapsed_time); - fflush(where); - } - - - /* We will count the "off" message that got us out of the loop */ - bytes_received = (messages_recvd * message_size) + len; - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_udp_stream: got %d bytes\n", - bytes_received); - fflush(where); - } - - netperf_response.content.response_type = UDP_STREAM_RESULTS; - udp_stream_results->bytes_received = htonl(bytes_received); - udp_stream_results->messages_recvd = messages_recvd; - udp_stream_results->elapsed_time = elapsed_time; - udp_stream_results->cpu_method = cpu_method; - udp_stream_results->num_cpus = lib_num_loc_cpus; - if (udp_stream_request->measure_cpu) { - udp_stream_results->cpu_util = calc_cpu_util(elapsed_time); - } - else { - udp_stream_results->cpu_util = (float) -1.0; - } - - if (debug > 1) { - fprintf(where, - "recv_udp_stream: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - - close(s_data); - -} - -void -send_udp_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - float elapsed_time; - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - int len; - int nummessages; - SOCKET send_socket; - int trans_remaining; - int bytes_xferd; - - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct addrinfo *local_res; - struct addrinfo *remote_res; - - struct udp_rr_request_struct *udp_rr_request; - struct udp_rr_response_struct *udp_rr_response; - struct udp_rr_results_struct *udp_rr_result; - - udp_rr_request = - (struct udp_rr_request_struct *)netperf_request.content.test_specific_data; - udp_rr_response = - (struct udp_rr_response_struct *)netperf_response.content.test_specific_data; - udp_rr_result = - (struct udp_rr_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_DGRAM, - IPPROTO_UDP, - 0); - - if ( print_headers ) { - print_top_test_header("UDP REQUEST/RESPONSE TEST",local_res,remote_res); - } - - /* initialize a few counters */ - - send_ring = NULL; - recv_ring = NULL; - nummessages = 0; - bytes_xferd = 0; - times_up = 0; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - nummessages = 0; - bytes_xferd = 0; - times_up = 0; - trans_remaining = 0; - - /* set-up the data buffers with the requested alignment and offset */ - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - if (send_ring == NULL) { - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - } - - if (recv_ring == NULL) { - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - } - - /*set up the data socket */ - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_udp_rr: udp rr data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_udp_rr: send_socket obtained...\n"); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. If */ - /* there is no idle counter in the kernel idle loop, the */ - /* local_cpu_rate will be set to -1. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - if (!no_control) { - /* Tell the remote end to do a listen. The server alters the - socket paramters on the other side at this point, hence the - reason for all the values being passed in the setup - message. If the user did not specify any of the parameters, - they will be passed as 0, which will indicate to the remote - that no changes beyond the system's default should be - used. Alignment is the exception, it will default to 8, which - will be no alignment alterations. */ - - netperf_request.content.request_type = DO_UDP_RR; - udp_rr_request->recv_buf_size = rsr_size_req; - udp_rr_request->send_buf_size = rss_size_req; - udp_rr_request->recv_alignment = remote_recv_align; - udp_rr_request->recv_offset = remote_recv_offset; - udp_rr_request->send_alignment = remote_send_align; - udp_rr_request->send_offset = remote_send_offset; - udp_rr_request->request_size = req_size; - udp_rr_request->response_size = rsp_size; - udp_rr_request->measure_cpu = remote_cpu_usage; - udp_rr_request->cpu_rate = remote_cpu_rate; - udp_rr_request->so_rcvavoid = rem_rcvavoid; - udp_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - udp_rr_request->test_length = test_time; - } - else { - udp_rr_request->test_length = test_trans * -1; - } - udp_rr_request->port = atoi(remote_data_port); - udp_rr_request->ipfamily = af_to_nf(remote_res->ai_family); - - if (debug > 1) { - fprintf(where,"netperf: send_udp_rr: requesting UDP r/r test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant - socket parameters for this test type. We will put them back - into the variables here so they can be displayed if desired. - The remote will have calibrated CPU if necessary, and will - have done all the needed set-up we will have calibrated the - cpu locally before sending the request, and will grab the - counter value right after the connect returns. The remote - will grab the counter right after the accept call. This saves - the hassle of extra messages being sent for the UDP - tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = udp_rr_response->recv_buf_size; - rss_size = udp_rr_response->send_buf_size; - remote_cpu_usage = udp_rr_response->measure_cpu; - remote_cpu_rate = udp_rr_response->cpu_rate; - /* port numbers in proper order */ - set_port_number(remote_res,(short)udp_rr_response->data_port_number); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - } - -#ifdef WANT_DEMO - DEMO_RR_SETUP(100) -#endif - - /* Connect up to the remote port on the data socket. This will set */ - /* the default destination address on this socket. With UDP, this */ - /* does make a performance difference as we may not have to do as */ - /* many routing lookups, however, I expect that a client would */ - /* behave this way. raj 1/94 */ - - if ( connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET ) { - perror("netperf: data socket connect failed"); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - -#ifdef WANT_INTERVALS - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return */ - /* false. When the test is controlled by byte count, the time test */ - /* will always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think */ - /* I just arbitrarily decrement trans_remaining for the timed */ - /* test, but will not do that just yet... One other question is */ - /* whether or not the send buffer and the receive buffer should be */ - /* the same buffer. */ - -#ifdef WANT_FIRST_BURST - { - int i; - for (i = 0; i < first_burst_size; i++) { - if((len=send(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - /* we should never hit the end of the test in the first burst */ - perror("send_udp_rr: initial burst data send error"); - exit(-1); - } - } - } -#endif /* WANT_FIRST_BURST */ - - while ((!times_up) || (trans_remaining > 0)) { - /* send the request */ -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - HIST_timestamp(&time_one); - } -#endif - if((len=send(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - if (SOCKET_EINTR(len)) { - /* We likely hit */ - /* test-end time. */ - break; - } - perror("send_udp_rr: data send error"); - exit(1); - } - send_ring = send_ring->next; - - /* receive the response. with UDP we will get it all, or nothing */ - - if((rsp_bytes_recvd=recv(send_socket, - recv_ring->buffer_ptr, - rsp_size, - 0)) != rsp_size) { - if (SOCKET_EINTR(rsp_bytes_recvd)) - { - /* Again, we have likely hit test-end time */ - break; - } - perror("send_udp_rr: data recv error"); - exit(1); - } - recv_ring = recv_ring->next; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } - -#endif - - /* at this point, we may wish to sleep for some period of */ - /* time, so we see how long that last transaction just took, */ - /* and sleep for the difference of that and the interval. We */ - /* will not sleep if the time would be less than a */ - /* millisecond. */ - -#ifdef WANT_DEMO - DEMO_RR_INTERVAL(1); -#endif - -#ifdef WANT_INTERVALS - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - if ((nummessages % 100) == 0) { - fprintf(where,"Transaction %d completed\n",nummessages); - fflush(where); - } - } - - } - - /* for some strange reason, I used to call shutdown on the UDP */ - /* data socket here. I'm not sure why, because it would not have */ - /* any effect... raj 11/94 */ - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured? how long */ - /* did we really run? */ - - if (!no_control) { - /* Get the statistics from the remote end. The remote will have - calculated service demand and all those interesting - things. If it wasn't supposed to care, it will return obvious - values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - } - - /* We now calculate what our thruput was for the test. In the */ - /* future, we may want to include a calculation of the thruput */ - /* measured by the remote, but it should be the case that for a */ - /* UDP rr test, that the two numbers should be *very* close... */ - /* We calculate bytes_sent regardless of the way the test length */ - /* was controlled. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = nummessages / elapsed_time; - - if (local_cpu_usage || remote_cpu_usage) { - - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) Of course, some of the */ - /* information might be bogus because there was no idle counter */ - /* in the kernel(s). We need to make a note of this for the */ - /* user's benefit by placing a code for the metod used in the */ - /* test banner */ - - if (local_cpu_usage) { - local_cpu_utilization = calc_cpu_util(0.0); - - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - remote_cpu_utilization = udp_rr_result->cpu_util; - - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - udp_rr_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - - /* we are done with the socket */ - close(send_socket); - } - - /* at this point, we have made all the iterations we are going to */ - /* make. */ - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(udp_rr_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - nummessages/elapsed_time, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - nummessages/elapsed_time); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - nummessages/elapsed_time); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - fflush(where); - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - /* how to handle the verbose information in the presence of */ - /* confidence intervals is yet to be determined... raj 11/94 */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* UDP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/reponse times.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } -} - - /* this routine implements the receive side (netserver) of a UDP_RR */ - /* test. */ -void -recv_udp_rr() -{ - - struct ring_elt *recv_ring; - struct ring_elt *send_ring; - - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - - struct sockaddr_storage myaddr_in; - struct sockaddr_storage peeraddr; - SOCKET s_data; - netperf_socklen_t addrlen; - int trans_received; - int trans_remaining; - int request_bytes_recvd; - int response_bytes_sent; - float elapsed_time; - - struct udp_rr_request_struct *udp_rr_request; - struct udp_rr_response_struct *udp_rr_response; - struct udp_rr_results_struct *udp_rr_results; - - udp_rr_request = - (struct udp_rr_request_struct *)netperf_request.content.test_specific_data; - udp_rr_response = - (struct udp_rr_response_struct *)netperf_response.content.test_specific_data; - udp_rr_results = - (struct udp_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_udp_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_udp_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = UDP_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_udp_rr: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variables to be at the desired */ - /* alignments with the desired offsets. */ - - if (debug) { - fprintf(where,"recv_udp_rr: requested recv alignment of %d offset %d\n", - udp_rr_request->recv_alignment, - udp_rr_request->recv_offset); - fprintf(where,"recv_udp_rr: requested send alignment of %d offset %d\n", - udp_rr_request->send_alignment, - udp_rr_request->send_offset); - fflush(where); - } - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - recv_ring = allocate_buffer_ring(recv_width, - udp_rr_request->request_size, - udp_rr_request->recv_alignment, - udp_rr_request->recv_offset); - - send_ring = allocate_buffer_ring(send_width, - udp_rr_request->response_size, - udp_rr_request->send_alignment, - udp_rr_request->send_offset); - - if (debug) { - fprintf(where,"recv_udp_rr: receive alignment and offset set...\n"); - fflush(where); - } - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_udp_rr: grabbing a socket...\n"); - fflush(where); - } - - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = udp_rr_request->send_buf_size; - lsr_size_req = udp_rr_request->recv_buf_size; - loc_rcvavoid = udp_rr_request->so_rcvavoid; - loc_sndavoid = udp_rr_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(udp_rr_request->ipfamily), - udp_rr_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(udp_rr_request->ipfamily), - SOCK_DGRAM, - IPPROTO_UDP, - 0); - - s_data = create_data_socket(local_res); - - if (s_data == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - - exit(1); - } - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_data, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_data); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - udp_rr_response->data_port_number = - (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port); - netperf_response.content.serv_errno = 0; - - if (debug) { - fprintf(where, - "recv port number %d\n", - ((struct sockaddr_in *)&myaddr_in)->sin_port); - fflush(where); - } - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - udp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */ - udp_rr_response->measure_cpu = 0; - if (udp_rr_request->measure_cpu) { - udp_rr_response->measure_cpu = 1; - udp_rr_response->cpu_rate = calibrate_local_cpu(udp_rr_request->cpu_rate); - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - udp_rr_response->send_buf_size = lss_size; - udp_rr_response->recv_buf_size = lsr_size; - udp_rr_response->so_rcvavoid = loc_rcvavoid; - udp_rr_response->so_sndavoid = loc_sndavoid; - - send_response(); - - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(udp_rr_request->measure_cpu); - -#ifdef WIN32 - /* this is used so the timer thread can close the socket out from */ - /* under us, which to date is the easiest/cleanest/least */ - /* Windows-specific way I can find to force the winsock calls to */ - /* return WSAEINTR with the test is over. anything that will run on */ - /* 95 and NT and is closer to what netperf expects from Unix signals */ - /* and such would be appreciated raj 1/96 */ - win_kludge_socket = s_data; -#endif /* WIN32 */ - - if (udp_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(udp_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = udp_rr_request->test_length * -1; - } - - addrlen = sizeof(peeraddr); - bzero((char *)&peeraddr, addrlen); - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - - /* receive the request from the other side */ - if ((request_bytes_recvd = recvfrom(s_data, - recv_ring->buffer_ptr, - udp_rr_request->request_size, - 0, - (struct sockaddr *)&peeraddr, - &addrlen)) != udp_rr_request->request_size) { - if ( SOCKET_EINTR(request_bytes_recvd) ) - { - /* we must have hit the end of test time. */ - break; - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - recv_ring = recv_ring->next; - - /* Now, send the response to the remote */ - if ((response_bytes_sent = sendto(s_data, - send_ring->buffer_ptr, - udp_rr_request->response_size, - 0, - (struct sockaddr *)&peeraddr, - addrlen)) != - udp_rr_request->response_size) { - if ( SOCKET_EINTR(response_bytes_sent) ) - { - /* we have hit end of test time. */ - break; - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - send_ring = send_ring->next; - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug) { - fprintf(where, - "recv_udp_rr: Transaction %d complete.\n", - trans_received); - fflush(where); - } - - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(udp_rr_request->measure_cpu,&elapsed_time); - - if (times_up) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_udp_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - udp_rr_results->bytes_received = (trans_received * - (udp_rr_request->request_size + - udp_rr_request->response_size)); - udp_rr_results->trans_received = trans_received; - udp_rr_results->elapsed_time = elapsed_time; - udp_rr_results->cpu_method = cpu_method; - udp_rr_results->num_cpus = lib_num_loc_cpus; - if (udp_rr_request->measure_cpu) { - udp_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_udp_rr: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - - /* we are done with the socket now */ - close(s_data); - - } - - - /* this routine implements the receive (netserver) side of a TCP_RR */ - /* test */ -void -recv_tcp_rr() -{ - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - - struct sockaddr_storage myaddr_in, - peeraddr_in; - SOCKET s_listen,s_data; - netperf_socklen_t addrlen; - char *temp_message_ptr; - int trans_received; - int trans_remaining; - int bytes_sent; - int request_bytes_recvd; - int request_bytes_remaining; - int timed_out = 0; - int sock_closed = 0; - float elapsed_time; - - struct tcp_rr_request_struct *tcp_rr_request; - struct tcp_rr_response_struct *tcp_rr_response; - struct tcp_rr_results_struct *tcp_rr_results; - - tcp_rr_request = - (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data; - tcp_rr_response = - (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data; - tcp_rr_results = - (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_tcp_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_tcp_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = TCP_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_tcp_rr: the response type is set...\n"); - fflush(where); - } - - /* allocate the recv and send rings with the requested alignments */ - /* and offsets. raj 7/94 */ - if (debug) { - fprintf(where,"recv_tcp_rr: requested recv alignment of %d offset %d\n", - tcp_rr_request->recv_alignment, - tcp_rr_request->recv_offset); - fprintf(where,"recv_tcp_rr: requested send alignment of %d offset %d\n", - tcp_rr_request->send_alignment, - tcp_rr_request->send_offset); - fflush(where); - } - - /* at some point, these need to come to us from the remote system */ - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - tcp_rr_request->response_size, - tcp_rr_request->send_alignment, - tcp_rr_request->send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - tcp_rr_request->request_size, - tcp_rr_request->recv_alignment, - tcp_rr_request->recv_offset); - - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_tcp_rr: grabbing a socket...\n"); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = tcp_rr_request->send_buf_size; - lsr_size_req = tcp_rr_request->recv_buf_size; - loc_nodelay = tcp_rr_request->no_delay; - loc_rcvavoid = tcp_rr_request->so_rcvavoid; - loc_sndavoid = tcp_rr_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(tcp_rr_request->ipfamily), - tcp_rr_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(tcp_rr_request->ipfamily), - SOCK_STREAM, - IPPROTO_TCP, - 0); - - s_listen = create_data_socket(local_res); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - - exit(1); - } - - -#ifdef WIN32 - /* The test timer can fire during operations on the listening socket, - so to make the start_timer below work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket2 = s_listen; -#endif - - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - tcp_rr_response->data_port_number = - (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - tcp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */ - tcp_rr_response->measure_cpu = 0; - - if (tcp_rr_request->measure_cpu) { - tcp_rr_response->measure_cpu = 1; - tcp_rr_response->cpu_rate = calibrate_local_cpu(tcp_rr_request->cpu_rate); - } - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - tcp_rr_response->send_buf_size = lss_size; - tcp_rr_response->recv_buf_size = lsr_size; - tcp_rr_response->no_delay = loc_nodelay; - tcp_rr_response->so_rcvavoid = loc_rcvavoid; - tcp_rr_response->so_sndavoid = loc_sndavoid; - tcp_rr_response->test_length = tcp_rr_request->test_length; - send_response(); - - addrlen = sizeof(peeraddr_in); - - if ((s_data = accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - - exit(1); - } - -#ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass */ - /* attributes across an accept() call. Including this goes against */ - /* my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - -#ifdef WIN32 - /* this is used so the timer thread can close the socket out from */ - /* under us, which to date is the easiest/cleanest/least */ - /* Windows-specific way I can find to force the winsock calls to */ - /* return WSAEINTR with the test is over. anything that will run on */ - /* 95 and NT and is closer to what netperf expects from Unix signals */ - /* and such would be appreciated raj 1/96 */ - win_kludge_socket = s_data; -#endif /* WIN32 */ - - if (debug) { - fprintf(where,"recv_tcp_rr: accept completes on the data connection.\n"); - fflush(where); - } - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(tcp_rr_request->measure_cpu); - - /* The loop will exit when we hit the end of the test time, or when */ - /* we have exchanged the requested number of transactions. */ - - if (tcp_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(tcp_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = tcp_rr_request->test_length * -1; - } - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - temp_message_ptr = recv_ring->buffer_ptr; - request_bytes_remaining = tcp_rr_request->request_size; - while(request_bytes_remaining > 0) { - if((request_bytes_recvd=recv(s_data, - temp_message_ptr, - request_bytes_remaining, - 0)) == SOCKET_ERROR) { - if (SOCKET_EINTR(request_bytes_recvd)) - { - timed_out = 1; - break; - } - - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - else if( request_bytes_recvd == 0 ) { - if (debug) { - fprintf(where,"zero is my hero\n"); - fflush(where); - } - sock_closed = 1; - break; - } - else { - request_bytes_remaining -= request_bytes_recvd; - temp_message_ptr += request_bytes_recvd; - } - } - - recv_ring = recv_ring->next; - - if ((timed_out) || (sock_closed)) { - /* we hit the end of the test based on time - or the socket - closed on us along the way. bail out of here now... */ - if (debug) { - fprintf(where,"yo5\n"); - fflush(where); - } - break; - } - - /* Now, send the response to the remote */ - if((bytes_sent=send(s_data, - send_ring->buffer_ptr, - tcp_rr_request->response_size, - 0)) == SOCKET_ERROR) { - if (SOCKET_EINTR(bytes_sent)) { - /* the test timer has popped */ - timed_out = 1; - fprintf(where,"yo6\n"); - fflush(where); - break; - } - netperf_response.content.serv_errno = 992; - send_response(); - exit(1); - } - - send_ring = send_ring->next; - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(tcp_rr_request->measure_cpu,&elapsed_time); - - stop_timer(); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_tcp_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - tcp_rr_results->bytes_received = (trans_received * - (tcp_rr_request->request_size + - tcp_rr_request->response_size)); - tcp_rr_results->trans_received = trans_received; - tcp_rr_results->elapsed_time = elapsed_time; - tcp_rr_results->cpu_method = cpu_method; - tcp_rr_results->num_cpus = lib_num_loc_cpus; - if (tcp_rr_request->measure_cpu) { - tcp_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_tcp_rr: test complete, sending results.\n"); - fflush(where); - } - - /* we are now done with the sockets */ - close(s_data); - close(s_listen); - - send_response(); - -} - - -void -loc_cpu_rate() -{ -#if defined(USE_LOOPER) - float dummy; -#endif - - /* a rather simple little test - it merely calibrates the local cpu */ - /* and prints the results. There are no headers to allow someone to */ - /* find a rate and use it in other tests automagically by setting a */ - /* variable equal to the output of this test. We ignore any rates */ - /* that may have been specified. In fact, we ignore all of the */ - /* command line args! */ - - fprintf(where, - "%g", - calibrate_local_cpu(0.0)); - - if (verbosity > 1) - fprintf(where, - "\nThere %s %d local %s\n", - (lib_num_loc_cpus > 1) ? "are" : "is", - lib_num_loc_cpus, - (lib_num_loc_cpus > 1) ? "cpus" : "cpu"); - - /* we need the cpu_start, cpu_stop in the looper case to kill the */ - /* child proceses raj 4/95 */ - -#ifdef USE_LOOPER - cpu_start(1); - cpu_stop(1,&dummy); -#endif /* USE_LOOPER */ - -} - -void -rem_cpu_rate() -{ - /* this test is much like the local variant, except that it works for */ - /* the remote system, so in this case, we do pay attention to the */ - /* value of the '-H' command line argument. */ - - fprintf(where, - "%g", - calibrate_remote_cpu()); - - if (verbosity > 1) - fprintf(where, - "\nThere %s %d remote %s\n", - (lib_num_rem_cpus > 1) ? "are" : "is", - lib_num_rem_cpus, - (lib_num_rem_cpus > 1) ? "cpus" : "cpu"); - -} - - - /* this test is intended to test the performance of establishing a - connection, exchanging a request/response pair, and repeating. it - is expected that this would be a good starting-point for - comparision of T/TCP with classic TCP for transactional workloads. - it will also look (can look) much like the communication pattern - of http for www access. */ - -void -send_tcp_conn_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\n\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - int timed_out = 0; - float elapsed_time; - - int len; - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - char *temp_message_ptr; - int nummessages; - SOCKET send_socket; - int trans_remaining; - double bytes_xferd; - int rsp_bytes_left; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct addrinfo *local_res; - struct addrinfo *remote_res; - - int myport; - int ret; - - struct tcp_conn_rr_request_struct *tcp_conn_rr_request; - struct tcp_conn_rr_response_struct *tcp_conn_rr_response; - struct tcp_conn_rr_results_struct *tcp_conn_rr_result; - - tcp_conn_rr_request = - (struct tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data; - tcp_conn_rr_response = - (struct tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data; - tcp_conn_rr_result = - (struct tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data; - - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("TCP Connect/Request/Response TEST",local_res,remote_res); - } - - /* initialize a few counters */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - - /* set-up the data buffers with the requested alignment and offset */ - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - - - if (debug) { - fprintf(where,"send_tcp_conn_rr: send_socket obtained...\n"); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - if (!no_control) { - - /* Tell the remote end to do a listen. The server alters the - socket paramters on the other side at this point, hence the - reason for all the values being passed in the setup message. If - the user did not specify any of the parameters, they will be - passed as 0, which will indicate to the remote that no changes - beyond the system's default should be used. Alignment is the - exception, it will default to 8, which will be no alignment - alterations. */ - - netperf_request.content.request_type = DO_TCP_CRR; - tcp_conn_rr_request->recv_buf_size = rsr_size_req; - tcp_conn_rr_request->send_buf_size = rss_size_req; - tcp_conn_rr_request->recv_alignment = remote_recv_align; - tcp_conn_rr_request->recv_offset = remote_recv_offset; - tcp_conn_rr_request->send_alignment = remote_send_align; - tcp_conn_rr_request->send_offset = remote_send_offset; - tcp_conn_rr_request->request_size = req_size; - tcp_conn_rr_request->response_size = rsp_size; - tcp_conn_rr_request->no_delay = rem_nodelay; - tcp_conn_rr_request->measure_cpu = remote_cpu_usage; - tcp_conn_rr_request->cpu_rate = remote_cpu_rate; - tcp_conn_rr_request->so_rcvavoid = rem_rcvavoid; - tcp_conn_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - tcp_conn_rr_request->test_length = test_time; - } - else { - tcp_conn_rr_request->test_length = test_trans * -1; - } - tcp_conn_rr_request->port = atoi(remote_data_port); - tcp_conn_rr_request->ipfamily = af_to_nf(remote_res->ai_family); - - if (debug > 1) { - fprintf(where,"netperf: send_tcp_conn_rr: requesting TCP crr test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant - socket parameters for this test type. We will put them back - into the variables here so they can be displayed if desired. - The remote will have calibrated CPU if necessary, and will have - done all the needed set-up we will have calibrated the cpu - locally before sending the request, and will grab the counter - value right after the connect returns. The remote will grab the - counter right after the accept call. This saves the hassle of - extra messages being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - rsr_size = tcp_conn_rr_response->recv_buf_size; - rss_size = tcp_conn_rr_response->send_buf_size; - rem_nodelay = tcp_conn_rr_response->no_delay; - remote_cpu_usage = tcp_conn_rr_response->measure_cpu; - remote_cpu_rate = tcp_conn_rr_response->cpu_rate; - /* make sure that port numbers are in network order */ - set_port_number(remote_res, - (unsigned short)tcp_conn_rr_response->data_port_number); - - if (debug) { - fprintf(where,"remote listen done.\n"); - fprintf(where,"remote port is %u\n",get_port_number(remote_res)); - fflush(where); - } - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - } -#ifdef WANT_DEMO - DEMO_RR_SETUP(100) -#endif - - /* pick a nice random spot between client_port_min and */ - /* client_port_max for our initial port number */ - srand(getpid()); - if (client_port_max - client_port_min) { - myport = client_port_min + - (rand() % (client_port_max - client_port_min)); - } - else { - myport = client_port_min; - } - /* there will be a ++ before the first call to bind, so subtract one */ - myport--; - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - - cpu_start(local_cpu_usage); - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - - while ((!times_up) || (trans_remaining > 0)) { - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before our call to create the socket, and then */ - /* again just after the receive raj 3/95 */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - -newport: - /* pick a new port number */ - myport++; - - /* wrap the port number when we get to client_port_max. NOTE, some */ - /* broken TCP's might treat the port number as a signed 16 bit */ - /* quantity. we aren't interested in testing such broken */ - /* implementations :) so we won't make sure that it is below 32767 */ - /* raj 8/94 */ - if (myport >= client_port_max) { - myport = client_port_min; - } - - /* we do not want to use the port number that the server is */ - /* sitting at - this would cause us to fail in a loopback test. we */ - /* could just rely on the failure of the bind to get us past this, */ - /* but I'm guessing that in this one case at least, it is much */ - /* faster, given that we *know* that port number is already in use */ - /* (or rather would be in a loopback test) */ - - if (myport == get_port_number(remote_res)) myport++; - - if (debug) { - if ((nummessages % 100) == 0) { - printf("port %d\n",myport); - } - } - - /* set up the data socket */ - set_port_number(local_res, (unsigned short)myport); - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET) { - perror("netperf: send_tcp_conn_rr: tcp stream data socket"); - exit(1); - } - - - /* we used to call bind here, but that is now taken-care-of by the - create_data_socket routine. */ - - /* Connect up to the remote port on the data socket */ - if ((ret = connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen)) == INVALID_SOCKET){ - if (SOCKET_EINTR(ret)) - { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - if ((SOCKET_EADDRINUSE(ret)) || SOCKET_EADDRNOTAVAIL(ret)) { - /* likely something our explicit bind() would have caught in - the past, so go get another port, via create_data_socket. - yes, this is a bit more overhead than before, but the - condition should be rather rare. raj 2005-02-08 */ - close(send_socket); - goto newport; - } - perror("netperf: data socket connect failed"); - printf("\tattempted to connect on socket %d to port %d", - send_socket, - get_port_number(remote_res)); - printf(" from port %d \n",get_port_number(local_res)); - exit(1); - } - - - /* send the request */ - if((len=send(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - if (SOCKET_EINTR(len)) - { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("send_tcp_conn_rr: data send error"); - exit(1); - } - send_ring = send_ring->next; - - /* receive the response */ - rsp_bytes_left = rsp_size; - temp_message_ptr = recv_ring->buffer_ptr; - - - do { - rsp_bytes_recvd = recv(send_socket, - temp_message_ptr, - rsp_bytes_left, - 0); - if (rsp_bytes_recvd > 0) { - rsp_bytes_left -= rsp_bytes_recvd; - temp_message_ptr += rsp_bytes_recvd; - } - else { - break; - } - } while (rsp_bytes_left); - - - /* OK, we are out of the loop - now what? */ - if (rsp_bytes_recvd < 0) { - /* did the timer hit, or was there an error? */ - if (SOCKET_EINTR(rsp_bytes_recvd)) - { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } - perror("send_tcp_conn_rr: data recv error"); - exit(1); - } - - /* if this is a no_control test, we initiate connection close, - otherwise the remote netserver does it to remain just like - previous behaviour. raj 2007-27-08 */ - if (!no_control) { - shutdown(send_socket,SHUT_WR); - } - - /* we are expecting to get either a return of zero indicating - connection close, or an error. */ - rsp_bytes_recvd = recv(send_socket, - temp_message_ptr, - 1, - 0); - - /* our exit from the while loop should generally be when */ - /* tmp_bytes_recvd is equal to zero, which implies the connection */ - /* has been closed by the server side. By waiting until we get the */ - /* zero return we can avoid race conditions that stick us with the */ - /* TIME_WAIT connection and not the server. raj 8/96 */ - - if (rsp_bytes_recvd == 0) { - /* connection close, call close. we assume that the requisite */ - /* number of bytes have been received */ - recv_ring = recv_ring->next; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_DEMO - DEMO_RR_INTERVAL(1) -#endif - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - fprintf(where, - "Transaction %d completed on local port %d\n", - nummessages, - get_port_number(local_res)); - fflush(where); - } - - close(send_socket); - - } - else { - /* it was less than zero - an error occured */ - if (SOCKET_EINTR(rsp_bytes_recvd)) - { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } - perror("send_tcp_conn_rr: data recv error"); - exit(1); - } - - } - - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ - /* how long did we really run? */ - - if (!no_control) { - /* Get the statistics from the remote end. The remote will have - calculated service demand and all those interesting things. If - it wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a TCP stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) We use */ - /* Kbytes/s as the units of thruput for a TCP stream test, where K = */ - /* 1024. A future enhancement *might* be to choose from a couple of */ - /* unit selections. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = calc_thruput(bytes_xferd); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where, - "WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where, - "Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where, - "DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where, - "Remote CPU usage numbers based on process information only!\n"); - fflush(where); - } - remote_cpu_utilization = tcp_conn_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - tcp_conn_rr_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - case 2: - - if (print_headers) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - nummessages/elapsed_time, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - nummessages/elapsed_time); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - nummessages/elapsed_time); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt, - local_send_align, - remote_recv_offset, - local_send_offset, - remote_recv_offset); - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/response times\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - - } - -} - - -void -recv_tcp_conn_rr() -{ - - char *message; - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - - struct sockaddr_storage myaddr_in, peeraddr_in; - SOCKET s_listen,s_data; - netperf_socklen_t addrlen; - char *recv_message_ptr; - char *send_message_ptr; - char *temp_message_ptr; - int trans_received; - int trans_remaining; - int bytes_sent; - int request_bytes_recvd; - int request_bytes_remaining; - int timed_out = 0; - float elapsed_time; - - struct tcp_conn_rr_request_struct *tcp_conn_rr_request; - struct tcp_conn_rr_response_struct *tcp_conn_rr_response; - struct tcp_conn_rr_results_struct *tcp_conn_rr_results; - - tcp_conn_rr_request = - (struct tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data; - tcp_conn_rr_response = - (struct tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data; - tcp_conn_rr_results = - (struct tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_tcp_conn_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_tcp_conn_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = TCP_CRR_RESPONSE; - - if (debug) { - fprintf(where,"recv_tcp_conn_rr: the response type is set...\n"); - fflush(where); - } - - /* set-up the data buffer with the requested alignment and offset */ - message = (char *)malloc(DATABUFFERLEN); - if (message == NULL) { - printf("malloc(%d) failed!\n", DATABUFFERLEN); - exit(1); - } - - /* We now alter the message_ptr variables to be at the desired */ - /* alignments with the desired offsets. */ - - if (debug) { - fprintf(where, - "recv_tcp_conn_rr: requested recv alignment of %d offset %d\n", - tcp_conn_rr_request->recv_alignment, - tcp_conn_rr_request->recv_offset); - fprintf(where, - "recv_tcp_conn_rr: requested send alignment of %d offset %d\n", - tcp_conn_rr_request->send_alignment, - tcp_conn_rr_request->send_offset); - fflush(where); - } - - recv_message_ptr = ALIGN_BUFFER(message, tcp_conn_rr_request->recv_alignment, tcp_conn_rr_request->recv_offset); - - send_message_ptr = ALIGN_BUFFER(message, tcp_conn_rr_request->send_alignment, tcp_conn_rr_request->send_offset); - - if (debug) { - fprintf(where,"recv_tcp_conn_rr: receive alignment and offset set...\n"); - fflush(where); - } - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_tcp_conn_rr: grabbing a socket...\n"); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = tcp_conn_rr_request->send_buf_size; - lsr_size_req = tcp_conn_rr_request->recv_buf_size; - loc_nodelay = tcp_conn_rr_request->no_delay; - loc_rcvavoid = tcp_conn_rr_request->so_rcvavoid; - loc_sndavoid = tcp_conn_rr_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(tcp_conn_rr_request->ipfamily), - tcp_conn_rr_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(tcp_conn_rr_request->ipfamily), - SOCK_STREAM, - IPPROTO_TCP, - 0); - - s_listen = create_data_socket(local_res); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - if (debug) { - fprintf(where,"could not create data socket\n"); - fflush(where); - } - exit(1); - } - -#ifdef WIN32 - /* The test timer can fire during operations on the listening socket, - so to make the start_timer below work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket2 = s_listen; -#endif - - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - if (debug) { - fprintf(where,"could not listen\n"); - fflush(where); - } - exit(1); - } - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - if (debug) { - fprintf(where,"could not getsockname\n"); - fflush(where); - } - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - tcp_conn_rr_response->data_port_number = - (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port); - if (debug) { - fprintf(where,"telling the remote to call me at %d\n", - tcp_conn_rr_response->data_port_number); - fflush(where); - } - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - tcp_conn_rr_response->cpu_rate = (float)0.0; /* assume no cpu */ - if (tcp_conn_rr_request->measure_cpu) { - tcp_conn_rr_response->measure_cpu = 1; - tcp_conn_rr_response->cpu_rate = - calibrate_local_cpu(tcp_conn_rr_request->cpu_rate); - } - - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - tcp_conn_rr_response->send_buf_size = lss_size; - tcp_conn_rr_response->recv_buf_size = lsr_size; - tcp_conn_rr_response->no_delay = loc_nodelay; - tcp_conn_rr_response->so_rcvavoid = loc_rcvavoid; - tcp_conn_rr_response->so_sndavoid = loc_sndavoid; - - send_response(); - - addrlen = sizeof(peeraddr_in); - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(tcp_conn_rr_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - if (tcp_conn_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(tcp_conn_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = tcp_conn_rr_request->test_length * -1; - } - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - - /* accept a connection from the remote */ -#ifdef WIN32 - /* The test timer will probably fire during this accept, - so to make the start_timer above work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket = s_listen; -#endif - if ((s_data=accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - if (errno == EINTR) { - /* the timer popped */ - timed_out = 1; - break; - } - fprintf(where,"recv_tcp_conn_rr: accept: errno = %d\n",errno); - fflush(where); - close(s_listen); - - exit(1); - } - - if (debug) { - fprintf(where,"recv_tcp_conn_rr: accepted data connection.\n"); - fflush(where); - } - -#ifdef WIN32 - /* this is used so the timer thread can close the socket out from */ - /* under us, which to date is the easiest/cleanest/least */ - /* Windows-specific way I can find to force the winsock calls to */ - /* return WSAEINTR with the test is over. anything that will run on */ - /* 95 and NT and is closer to what netperf expects from Unix signals */ - /* and such would be appreciated raj 1/96 */ - win_kludge_socket = s_data; -#endif /* WIN32 */ - -#ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass */ - /* attributes across an accept() call. Including this goes against */ - /* my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - - temp_message_ptr = recv_message_ptr; - request_bytes_remaining = tcp_conn_rr_request->request_size; - - /* receive the request from the other side */ - while (!times_up && (request_bytes_remaining > 0)) { - if((request_bytes_recvd=recv(s_data, - temp_message_ptr, - request_bytes_remaining, - 0)) == SOCKET_ERROR) { - if (SOCKET_EINTR(request_bytes_recvd)) - { - /* the timer popped */ - timed_out = 1; - break; - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - else { - request_bytes_remaining -= request_bytes_recvd; - temp_message_ptr += request_bytes_recvd; - } - } - - if (timed_out) { - /* we hit the end of the test based on time - lets */ - /* bail out of here now... */ - fprintf(where,"yo5\n"); - fflush(where); - break; - } - - /* Now, send the response to the remote */ - if((bytes_sent=send(s_data, - send_message_ptr, - tcp_conn_rr_request->response_size, - 0)) == SOCKET_ERROR) { - if (errno == EINTR) { - /* the test timer has popped */ - timed_out = 1; - fprintf(where,"yo6\n"); - fflush(where); - break; - } - netperf_response.content.serv_errno = 99; - send_response(); - exit(1); - } - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug) { - fprintf(where, - "recv_tcp_conn_rr: Transaction %d complete\n", - trans_received); - fflush(where); - } - - /* close the connection. the server will likely do a graceful */ - /* close of the connection, insuring that all data has arrived at */ - /* the client. for this it will call shutdown(), and then recv() and */ - /* then close(). I'm reasonably confident that this is the */ - /* appropriate sequence of calls - I would like to hear of */ - /* examples in web servers to the contrary. raj 10/95*/ -#ifdef TCP_CRR_SHUTDOWN - shutdown(s_data,SHUT_WR); - recv(s_data, - recv_message_ptr, - 1, - 0); - close(s_data); -#else - close(s_data); -#endif /* TCP_CRR_SHUTDOWN */ - - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(tcp_conn_rr_request->measure_cpu,&elapsed_time); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_tcp_conn_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - tcp_conn_rr_results->bytes_received = (trans_received * - (tcp_conn_rr_request->request_size + - tcp_conn_rr_request->response_size)); - tcp_conn_rr_results->trans_received = trans_received; - tcp_conn_rr_results->elapsed_time = elapsed_time; - if (tcp_conn_rr_request->measure_cpu) { - tcp_conn_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_tcp_conn_rr: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - -} - - -#ifdef DO_1644 - - /* this test is intended to test the performance of establishing a */ - /* connection, exchanging a request/response pair, and repeating. it */ - /* is expected that this would be a good starting-point for */ - /* comparision of T/TCP with classic TCP for transactional workloads. */ - /* it will also look (can look) much like the communication pattern */ - /* of http for www access. */ - -int -send_tcp_tran_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\n\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - int one = 1; - int timed_out = 0; - float elapsed_time; - - int len; - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - char *temp_message_ptr; - int nummessages; - SOCKET send_socket; - int trans_remaining; - double bytes_xferd; - int sock_opt_len = sizeof(int); - int rsp_bytes_left; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct hostent *hp; - struct sockaddr_in server; - struct sockaddr_in *myaddr; - unsigned int addr; - int myport; - - struct tcp_tran_rr_request_struct *tcp_tran_rr_request; - struct tcp_tran_rr_response_struct *tcp_tran_rr_response; - struct tcp_tran_rr_results_struct *tcp_tran_rr_result; - - tcp_tran_rr_request = - (struct tcp_tran_rr_request_struct *)netperf_request.content.test_specific_data; - tcp_tran_rr_response = - (struct tcp_tran_rr_response_struct *)netperf_response.content.test_specific_data; - tcp_tran_rr_result = - (struct tcp_tran_rr_results_struct *)netperf_response.content.test_specific_data; - - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - myaddr = (struct sockaddr_storage *)malloc(sizeof(struct sockaddr_storage)); - if (myaddr == NULL) { - printf("malloc(%d) failed!\n", sizeof(struct sockaddr_storage)); - exit(1); - } - - bzero((char *)&server, - sizeof(server)); - bzero((char *)myaddr, - sizeof(struct sockaddr_storage)); - myaddr->sin_family = AF_INET; - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("TCP Transactional/Request/Response TEST",local_res,remote_res); - } - - /* initialize a few counters */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - - /* set-up the data buffers with the requested alignment and offset */ - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - - - if (debug) { - fprintf(where,"send_tcp_tran_rr: send_socket obtained...\n"); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_TCP_TRR; - tcp_tran_rr_request->recv_buf_size = rsr_size_req; - tcp_tran_rr_request->send_buf_size = rss_size_req; - tcp_tran_rr_request->recv_alignment = remote_recv_align; - tcp_tran_rr_request->recv_offset = remote_recv_offset; - tcp_tran_rr_request->send_alignment = remote_send_align; - tcp_tran_rr_request->send_offset = remote_send_offset; - tcp_tran_rr_request->request_size = req_size; - tcp_tran_rr_request->response_size = rsp_size; - tcp_tran_rr_request->no_delay = rem_nodelay; - tcp_tran_rr_request->measure_cpu = remote_cpu_usage; - tcp_tran_rr_request->cpu_rate = remote_cpu_rate; - tcp_tran_rr_request->so_rcvavoid = rem_rcvavoid; - tcp_tran_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - tcp_tran_rr_request->test_length = test_time; - } - else { - tcp_tran_rr_request->test_length = test_trans * -1; - } - tcp_tran_rr_request->port = atoi(remote_data_port); - tcp_tran_rr_request->ipfamily = af_to_nf(remote_res->ai_family); - - if (debug > 1) { - fprintf(where,"netperf: send_tcp_tran_rr: requesting TCP_TRR test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right */ - /* after the connect returns. The remote will grab the counter right */ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - rsr_size = tcp_tran_rr_response->recv_buf_size; - rss_size = tcp_tran_rr_response->send_buf_size; - rem_nodelay = tcp_tran_rr_response->no_delay; - remote_cpu_usage= tcp_tran_rr_response->measure_cpu; - remote_cpu_rate = tcp_tran_rr_response->cpu_rate; - /* make sure that port numbers are in network order */ - server.sin_port = tcp_tran_rr_response->data_port_number; - server.sin_port = htons(server.sin_port); - if (debug) { - fprintf(where,"remote listen done.\n"); - fprintf(where,"remote port is %d\n",ntohs(server.sin_port)); - fflush(where); - } - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - - /* pick a nice random spot between client_port_min and */ - /* client_port_max for our initial port number. if they are the */ - /* same, then just set to _min */ - if (client_port_max - client_port_min) { - srand(getpid()); - myport = client_port_min + - (rand() % (client_port_max - client_port_min)); - } - else { - myport = client_port_min; - } - - /* there will be a ++ before the first call to bind, so subtract one */ - myport--; - myaddr->sin_port = htons((unsigned short)myport); - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - - while ((!times_up) || (trans_remaining > 0)) { - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before our call to create the socket, and then */ - /* again just after the receive raj 3/95 */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - /* set up the data socket - is this really necessary or can I just */ - /* re-use the same socket and move this cal out of the while loop. */ - /* it does introcudea *boatload* of system calls. I guess that it */ - /* all depends on "reality of programming." keeping it this way is */ - /* a bit more conservative I imagine - raj 3/95 */ - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET) { - perror("netperf: send_tcp_tran_rr: tcp stream data socket"); - exit(1); - } - - /* we set SO_REUSEADDR on the premis that no unreserved port */ - /* number on the local system is going to be already connected to */ - /* the remote netserver's port number. One thing that I might */ - /* try later is to have the remote actually allocate a couple of */ - /* port numbers and cycle through those as well. depends on if we */ - /* can get through all the unreserved port numbers in less than */ - /* the length of the TIME_WAIT state raj 8/94 */ - one = 1; - if(setsockopt(send_socket, SOL_SOCKET, SO_REUSEADDR, - (char *)&one, sock_opt_len) == SOCKET_ERROR) { - perror("netperf: send_tcp_tran_rr: so_reuseaddr"); - exit(1); - } - -newport: - /* pick a new port number */ - myport = ntohs(myaddr->sin_port); - myport++; - - /* we do not want to use the port number that the server is */ - /* sitting at - this would cause us to fail in a loopback test. we */ - /* could just rely on the failure of the bind to get us past this, */ - /* but I'm guessing that in this one case at least, it is much */ - /* faster, given that we *know* that port number is already in use */ - /* (or rather would be in a loopback test) */ - - if (myport == ntohs(server.sin_port)) myport++; - - /* wrap the port number when we get to 65535. NOTE, some broken */ - /* TCP's might treat the port number as a signed 16 bit quantity. */ - /* we aren't interested in testing such broken implementations :) */ - /* raj 8/94 */ - if (myport >= client_port_max) { - myport = client_port_min; - } - myaddr->sin_port = htons((unsigned short)myport); - - if (debug) { - if ((nummessages % 100) == 0) { - printf("port %d\n",myport); - } - } - - /* we want to bind our socket to a particular port number. */ - if (bind(send_socket, - (struct sockaddr *)myaddr, - sizeof(struct sockaddr_storage)) == SOCKET_ERROR) { - /* if the bind failed, someone else must have that port number */ - /* - perhaps in the listen state. since we can't use it, skip to */ - /* the next port number. we may have to do this again later, but */ - /* that's just too bad :) */ - if (debug > 1) { - fprintf(where, - "send_tcp_tran_rr: tried to bind to port %d errno %d\n", - ntohs(myaddr->sin_port), - errno); - fflush(where); - } - /* yes, goto's are supposed to be evil, but they do have their */ - /* uses from time to time. the real world doesn't always have */ - /* to code to ge tthe A in CS 101 :) raj 3/95 */ - goto newport; - } - - /* Connect up to the remote port on the data socket. Since this is */ - /* a test for RFC_1644-style transactional TCP, we can use the */ - /* sendto() call instead of calling connect and then send() */ - - /* send the request */ - if((len=sendto(send_socket, - send_ring->buffer_ptr, - req_size, - MSG_EOF, - (struct sockaddr *)&server, - sizeof(server))) != req_size) { - if (SOCKET_EINTR(len)) - { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("send_tcp_tran_rr: data send error"); - exit(1); - } - send_ring = send_ring->next; - - /* receive the response */ - rsp_bytes_left = rsp_size; - temp_message_ptr = recv_ring->buffer_ptr; - while(rsp_bytes_left > 0) { - if((rsp_bytes_recvd=recv(send_socket, - temp_message_ptr, - rsp_bytes_left, - 0)) == SOCKET_ERROR) { - if (SOCKET_EINTR(rsp_bytes_recvd)) - { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } - perror("send_tcp_tran_rr: data recv error"); - exit(1); - } - rsp_bytes_left -= rsp_bytes_recvd; - temp_message_ptr += rsp_bytes_recvd; - } - recv_ring = recv_ring->next; - - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - - close(send_socket); - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - fprintf(where, - "Transaction %d completed on local port %d\n", - nummessages, - ntohs(myaddr->sin_port)); - fflush(where); - } - - - } - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ - /* how long did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a TCP stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) We use */ - /* Kbytes/s as the units of thruput for a TCP stream test, where K = */ - /* 1024. A future enhancement *might* be to choose from a couple of */ - /* unit selections. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = calc_thruput(bytes_xferd); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where,"Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where,"Remote CPU usage numbers based on process information only!\n"); - fflush(where); - } - remote_cpu_utilization = tcp_tran_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - tcp_tran_rr_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - case 2: - - if (print_headers) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - nummessages/elapsed_time, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - nummessages/elapsed_time); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - nummessages/elapsed_time); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt, - local_send_align, - remote_recv_offset, - local_send_offset, - remote_recv_offset); - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/response times\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - - } - -} - - -int -recv_tcp_tran_rr() -{ - - char *message; - struct sockaddr_in myaddr_in, - peeraddr_in; - SOCKET s_listen,s_data; - netperf_socklen_t addrlen; - int NoPush = 1; - - char *recv_message_ptr; - char *send_message_ptr; - char *temp_message_ptr; - int trans_received; - int trans_remaining; - int bytes_sent; - int request_bytes_recvd; - int request_bytes_remaining; - int timed_out = 0; - float elapsed_time; - - struct tcp_tran_rr_request_struct *tcp_tran_rr_request; - struct tcp_tran_rr_response_struct *tcp_tran_rr_response; - struct tcp_tran_rr_results_struct *tcp_tran_rr_results; - - tcp_tran_rr_request = - (struct tcp_tran_rr_request_struct *)netperf_request.content.test_specific_data; - tcp_tran_rr_response = - (struct tcp_tran_rr_response_struct *)netperf_response.content.test_specific_data; - tcp_tran_rr_results = - (struct tcp_tran_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_tcp_tran_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_tcp_tran_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = TCP_TRR_RESPONSE; - - if (debug) { - fprintf(where,"recv_tcp_tran_rr: the response type is set...\n"); - fflush(where); - } - - /* set-up the data buffer with the requested alignment and offset */ - message = (char *)malloc(DATABUFFERLEN); - if (message == NULL) { - printf("malloc(%d) failed!\n", DATABUFFERLEN); - exit(1); - } - - /* We now alter the message_ptr variables to be at the desired */ - /* alignments with the desired offsets. */ - - if (debug) { - fprintf(where, - "recv_tcp_tran_rr: requested recv alignment of %d offset %d\n", - tcp_tran_rr_request->recv_alignment, - tcp_tran_rr_request->recv_offset); - fprintf(where, - "recv_tcp_tran_rr: requested send alignment of %d offset %d\n", - tcp_tran_rr_request->send_alignment, - tcp_tran_rr_request->send_offset); - fflush(where); - } - - recv_message_ptr = ALIGN_BUFFER(message, tcp_tran_rr_request->recv_alignment, tcp_tran_rr_request->recv_offset); - - send_message_ptr = ALIGN_BUFFER(message, tcp_tran_rr_request->send_alignment, tcp_tran_rr_request->send_offset); - - if (debug) { - fprintf(where,"recv_tcp_tran_rr: receive alignment and offset set...\n"); - fflush(where); - } - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - bzero((char *)&myaddr_in, - sizeof(myaddr_in)); - myaddr_in.sin_family = AF_INET; - myaddr_in.sin_addr.s_addr = INADDR_ANY; - myaddr_in.sin_port = htons((unsigned short)tcp_tran_rr_request->port); - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_tcp_tran_rr: grabbing a socket...\n"); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = tcp_tran_rr_request->send_buf_size; - lsr_size_req = tcp_tran_rr_request->recv_buf_size; - loc_nodelay = tcp_tran_rr_request->no_delay; - loc_rcvavoid = tcp_tran_rr_request->so_rcvavoid; - loc_sndavoid = tcp_tran_rr_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(tcp_tran_rr_request->ipfamily), - tcp_tran_rr_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(tcp_tran_rr_request->ipfamily), - SOCK_STREAM, - IPPROTO_TCP, - 0); - - s_listen = create_data_socket(local_res); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - if (debug) { - fprintf(where,"could not create data socket\n"); - fflush(where); - } - exit(1); - } - -#ifdef WIN32 - /* The test timer can fire during operations on the listening socket, - so to make the start_timer below work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket2 = s_listen; -#endif - - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - if (bind(s_listen, - (struct sockaddr *)&myaddr_in, - sizeof(myaddr_in)) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - if (debug) { - fprintf(where,"could not bind\n"); - fflush(where); - } - exit(1); - } - - /* we want to disable the implicit PUSH on all sends. at some point, */ - /* this might want to be a parm to the test raj 3/95 */ - if (setsockopt(s_listen, - IPPROTO_TCP, - TCP_NOPUSH, - (const char *)&NoPush, - sizeof(int)) == SOCKET_ERROR) { - fprintf(where, - "recv_tcp_tran_rr: could not set TCP_NOPUSH errno %d\n", - errno); - fflush(where); - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - if (debug) { - fprintf(where,"could not listen\n"); - fflush(where); - } - exit(1); - } - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - if (debug) { - fprintf(where,"could not geetsockname\n"); - fflush(where); - } - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - tcp_tran_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - if (debug) { - fprintf(where,"telling the remote to call me at %d\n", - tcp_tran_rr_response->data_port_number); - fflush(where); - } - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - tcp_tran_rr_response->cpu_rate = 0.0; /* assume no cpu */ - if (tcp_tran_rr_request->measure_cpu) { - tcp_tran_rr_response->measure_cpu = 1; - tcp_tran_rr_response->cpu_rate = - calibrate_local_cpu(tcp_tran_rr_request->cpu_rate); - } - - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - tcp_tran_rr_response->send_buf_size = lss_size; - tcp_tran_rr_response->recv_buf_size = lsr_size; - tcp_tran_rr_response->no_delay = loc_nodelay; - tcp_tran_rr_response->so_rcvavoid = loc_rcvavoid; - tcp_tran_rr_response->so_sndavoid = loc_sndavoid; - - send_response(); - - addrlen = sizeof(peeraddr_in); - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(tcp_tran_rr_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - if (tcp_tran_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(tcp_tran_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = tcp_tran_rr_request->test_length * -1; - } - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - - /* accept a connection from the remote */ - if ((s_data=accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - if (errno == EINTR) { - /* the timer popped */ - timed_out = 1; - break; - } - fprintf(where,"recv_tcp_tran_rr: accept: errno = %d\n",errno); - fflush(where); - close(s_listen); - - exit(1); - } - - if (debug) { - fprintf(where,"recv_tcp_tran_rr: accepted data connection.\n"); - fflush(where); - } - -#ifdef WIN32 - /* this is used so the timer thread can close the socket out from */ - /* under us, which to date is the easiest/cleanest/least */ - /* Windows-specific way I can find to force the winsock calls to */ - /* return WSAEINTR with the test is over. anything that will run on */ - /* 95 and NT and is closer to what netperf expects from Unix signals */ - /* and such would be appreciated raj 1/96 */ - win_kludge_socket = s_data; -#endif /* WIN32 */ - -#ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass */ - /* attributes across an accept() call. Including this goes against */ - /* my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - - temp_message_ptr = recv_message_ptr; - request_bytes_remaining = tcp_tran_rr_request->request_size; - - /* receive the request from the other side. we can just receive */ - /* until we get zero bytes, but that would be a slight structure */ - /* change in the code, with minimal perfomance effects. If */ - /* however, I has variable-length messages, I would want to do */ - /* this to avoid needing "double reads" - one for the message */ - /* length, and one for the rest of the message raj 3/95 */ - while(request_bytes_remaining > 0) { - if((request_bytes_recvd=recv(s_data, - temp_message_ptr, - request_bytes_remaining, - 0)) == SOCKET_ERROR) { - if ( SOCKET_EINTR(request_bytes_recvd) ) - { - /* the timer popped */ - timed_out = 1; - break; - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - else { - request_bytes_remaining -= request_bytes_recvd; - temp_message_ptr += request_bytes_recvd; - } - } - - if (timed_out) { - /* we hit the end of the test based on time - lets */ - /* bail out of here now... */ - fprintf(where,"yo5\n"); - fflush(where); - break; - } - - /* Now, send the response to the remote we can use sendto here to */ - /* help remind people that this is an rfc 1644 style of test */ - if((bytes_sent=sendto(s_data, - send_message_ptr, - tcp_tran_rr_request->response_size, - MSG_EOF, - (struct sockaddr *)&peeraddr_in, - sizeof(struct sockaddr_storage))) == SOCKET_ERROR) { - if (SOCKET_EINTR(bytes_sent)) { - /* the test timer has popped */ - timed_out = 1; - fprintf(where,"yo6\n"); - fflush(where); - break; - } - netperf_response.content.serv_errno = 99; - send_response(); - exit(1); - } - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug) { - fprintf(where, - "recv_tcp_tran_rr: Transaction %d complete\n", - trans_received); - fflush(where); - } - - /* close the connection. since we have disable PUSH on sends, the */ - /* FIN should be tacked-onto our last send instead of being */ - /* standalone */ - close(s_data); - - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(tcp_tran_rr_request->measure_cpu,&elapsed_time); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_tcp_tran_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - tcp_tran_rr_results->bytes_received = (trans_received * - (tcp_tran_rr_request->request_size + - tcp_tran_rr_request->response_size)); - tcp_tran_rr_results->trans_received = trans_received; - tcp_tran_rr_results->elapsed_time = elapsed_time; - if (tcp_tran_rr_request->measure_cpu) { - tcp_tran_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_tcp_tran_rr: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - -} -#endif /* DO_1644 */ - -#ifdef DO_NBRR - /* this routine implements the sending (netperf) side of the TCP_RR */ - /* test using POSIX-style non-blocking sockets. */ - -void -send_tcp_nbrr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - int timed_out = 0; - float elapsed_time; - - int len; - char *temp_message_ptr; - int nummessages; - SOCKET send_socket; - int trans_remaining; - double bytes_xferd; - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - int rsp_bytes_left; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct hostent *hp; - struct sockaddr_storage server; - unsigned int addr; - - struct tcp_rr_request_struct *tcp_rr_request; - struct tcp_rr_response_struct *tcp_rr_response; - struct tcp_rr_results_struct *tcp_rr_result; - - struct addrinfo *remote_res; - struct addrinfo *local_res; - - tcp_rr_request = - (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data; - tcp_rr_response= - (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data; - tcp_rr_result = - (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - bzero((char *)&server, - sizeof(server)); - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("TCP Non-Blocking REQUEST/RESPONSE TEST",local_res,remote_res); - } - - /* initialize a few counters */ - - send_ring = NULL; - recv_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - timed_out = 0; - trans_remaining = 0; - - /* set-up the data buffers with the requested alignment and offset. */ - /* since this is a request/response test, default the send_width and */ - /* recv_width to 1 and not two raj 7/94 */ - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - if (send_ring == NULL) { - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - } - - if (recv_ring == NULL) { - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - } - - /*set up the data socket */ - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_tcp_nbrr: tcp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_tcp_nbrr: send_socket obtained...\n"); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_TCP_NBRR; - tcp_rr_request->recv_buf_size = rsr_size_req; - tcp_rr_request->send_buf_size = rss_size_req; - tcp_rr_request->recv_alignment = remote_recv_align; - tcp_rr_request->recv_offset = remote_recv_offset; - tcp_rr_request->send_alignment = remote_send_align; - tcp_rr_request->send_offset = remote_send_offset; - tcp_rr_request->request_size = req_size; - tcp_rr_request->response_size = rsp_size; - tcp_rr_request->no_delay = rem_nodelay; - tcp_rr_request->measure_cpu = remote_cpu_usage; - tcp_rr_request->cpu_rate = remote_cpu_rate; - tcp_rr_request->so_rcvavoid = rem_rcvavoid; - tcp_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - tcp_rr_request->test_length = test_time; - } - else { - tcp_rr_request->test_length = test_trans * -1; - } - - if (debug > 1) { - fprintf(where,"netperf: send_tcp_nbrr: requesting TCP rr test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right*/ - /* after the connect returns. The remote will grab the counter right*/ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = tcp_rr_response->recv_buf_size; - rss_size = tcp_rr_response->send_buf_size; - rem_nodelay = tcp_rr_response->no_delay; - remote_cpu_usage = tcp_rr_response->measure_cpu; - remote_cpu_rate = tcp_rr_response->cpu_rate; - /* make sure that port numbers are in network order */ - server.sin_port = (unsigned short)tcp_rr_response->data_port_number; - server.sin_port = htons(server.sin_port); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("netperf: data socket connect failed"); - - exit(1); - } - - /* now that we are connected, mark the socket as non-blocking */ - if (!set_nonblock(send_socket)) { - perror("netperf: set_nonblock"); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - - while ((!times_up) || (trans_remaining > 0)) { - /* send the request. we assume that if we use a blocking socket, */ - /* the request will be sent at one shot. */ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before our call to send, and then again just */ - /* after the receive raj 8/94 */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - /* even though this is a non-blocking socket, we will assume for */ - /* the time being that we will be able to send an entire request */ - /* without getting an EAGAIN */ - if((len=send(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - if (SOCKET_EINTR(len)) { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("send_tcp_nbrr: data send error"); - exit(1); - } - send_ring = send_ring->next; - - /* receive the response. since we are using non-blocking I/O, we */ - /* will "spin" on the recvs */ - rsp_bytes_left = rsp_size; - temp_message_ptr = recv_ring->buffer_ptr; - while(rsp_bytes_left > 0) { - if((rsp_bytes_recvd=recv(send_socket, - temp_message_ptr, - rsp_bytes_left, - 0)) == SOCKET_ERROR) { - if (SOCKET_EINTR(rsp_bytes_recvd)) - { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } -#ifndef WIN32 // But what does WinNT indicate in this situation... - else if (errno == EAGAIN) { - Set_errno(0); - continue; - } -#endif - else { - perror("send_tcp_nbrr: data recv error"); - exit(1); - } - } - rsp_bytes_left -= rsp_bytes_recvd; - temp_message_ptr += rsp_bytes_recvd; - } - recv_ring = recv_ring->next; - - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ -#ifdef WANT_INTERVALS - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - if ((nummessages % 100) == 0) { - fprintf(where, - "Transaction %d completed\n", - nummessages); - fflush(where); - } - } - } - - /* At this point we used to call shutdown on the data socket to be */ - /* sure all the data was delivered, but this was not germane in a */ - /* request/response test, and it was causing the tests to "hang" when */ - /* they were being controlled by time. So, I have replaced this */ - /* shutdown call with a call to close that can be found later in the */ - /* procedure. */ - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured? how long */ - /* did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /* We now calculate what our thruput was for the test. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = nummessages/elapsed_time; - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - remote_cpu_utilization = tcp_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - tcp_rr_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - - /* we are now done with the socket, so close it */ - close(send_socket); - - } - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(tcp_rr_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - thruput, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - thruput); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - /* how to handle the verbose information in the presence of */ - /* confidence intervals is yet to be determined... raj 11/94 */ - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt, - local_send_align, - remote_recv_offset, - local_send_offset, - remote_recv_offset); - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/response times\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - - } - -} - - /* this routine implements the receive (netserver) side of a TCP_RR */ - /* test */ -void -recv_tcp_nbrr() -{ - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - struct sockaddr_in myaddr_in, - peeraddr_in; - SOCKET s_listen,s_data; - netperf_socklen_t addrlen; - char *temp_message_ptr; - int trans_received; - int trans_remaining; - int bytes_sent; - int request_bytes_recvd; - int request_bytes_remaining; - int timed_out = 0; - float elapsed_time; - - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - - struct tcp_rr_request_struct *tcp_rr_request; - struct tcp_rr_response_struct *tcp_rr_response; - struct tcp_rr_results_struct *tcp_rr_results; - - tcp_rr_request = - (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data; - tcp_rr_response = - (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data; - tcp_rr_results = - (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_tcp_nbrr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_tcp_nbrr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = TCP_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_tcp_nbrr: the response type is set...\n"); - fflush(where); - } - - /* allocate the recv and send rings with the requested alignments */ - /* and offsets. raj 7/94 */ - if (debug) { - fprintf(where,"recv_tcp_nbrr: requested recv alignment of %d offset %d\n", - tcp_rr_request->recv_alignment, - tcp_rr_request->recv_offset); - fprintf(where,"recv_tcp_nbrr: requested send alignment of %d offset %d\n", - tcp_rr_request->send_alignment, - tcp_rr_request->send_offset); - fflush(where); - } - - /* at some point, these need to come to us from the remote system */ - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - tcp_rr_request->response_size, - tcp_rr_request->send_alignment, - tcp_rr_request->send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - tcp_rr_request->request_size, - tcp_rr_request->recv_alignment, - tcp_rr_request->recv_offset); - - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - bzero((char *)&myaddr_in, - sizeof(myaddr_in)); - myaddr_in.sin_family = AF_INET; - myaddr_in.sin_addr.s_addr = INADDR_ANY; - myaddr_in.sin_port = htons((unsigned short)tcp_rr_request->port); - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_tcp_nbrr: grabbing a socket...\n"); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = tcp_rr_request->send_buf_size; - lsr_size_req = tcp_rr_request->recv_buf_size; - loc_nodelay = tcp_rr_request->no_delay; - loc_rcvavoid = tcp_rr_request->so_rcvavoid; - loc_sndavoid = tcp_rr_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(tcp_rr_request->ipfamily), - tcp_rr_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(tcp_rr_request->ipfamily), - SOCK_STREAM, - IPPROTO_TCP, - 0); - - s_listen = create_data_socket(local_res); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - - exit(1); - } - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - if (bind(s_listen, - (struct sockaddr *)&myaddr_in, - sizeof(myaddr_in)) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - tcp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - tcp_rr_response->cpu_rate = 0.0; /* assume no cpu */ - tcp_rr_response->measure_cpu = 0; - - if (tcp_rr_request->measure_cpu) { - tcp_rr_response->measure_cpu = 1; - tcp_rr_response->cpu_rate = calibrate_local_cpu(tcp_rr_request->cpu_rate); - } - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - tcp_rr_response->send_buf_size = lss_size; - tcp_rr_response->recv_buf_size = lsr_size; - tcp_rr_response->no_delay = loc_nodelay; - tcp_rr_response->so_rcvavoid = loc_rcvavoid; - tcp_rr_response->so_sndavoid = loc_sndavoid; - tcp_rr_response->test_length = tcp_rr_request->test_length; - send_response(); - - addrlen = sizeof(peeraddr_in); - - if ((s_data = accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - exit(1); - } - - if (debug) { - fprintf(where,"recv_tcp_nbrr: accept completes on the data connection.\n"); - fflush(where); - } - -#ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass */ - /* attributes across an accept() call. Including this goes against */ - /* my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - - /* now that we are connected, mark the socket as non-blocking */ - if (!set_nonblock(s_data)) { - close(s_data); - exit(1); - } - - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(tcp_rr_request->measure_cpu); - -#ifdef WIN32 - /* this is used so the timer thread can close the socket out from */ - /* under us, which to date is the easiest/cleanest/least */ - /* Windows-specific way I can find to force the winsock calls to */ - /* return WSAEINTR with the test is over. anything that will run on */ - /* 95 and NT and is closer to what netperf expects from Unix signals */ - /* and such would be appreciated raj 1/96 */ - win_kludge_socket = s_data; -#endif /* WIN32 */ - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - if (tcp_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(tcp_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = tcp_rr_request->test_length * -1; - } - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - temp_message_ptr = recv_ring->buffer_ptr; - request_bytes_remaining = tcp_rr_request->request_size; - while(request_bytes_remaining > 0) { - if((request_bytes_recvd=recv(s_data, - temp_message_ptr, - request_bytes_remaining, - 0)) == SOCKET_ERROR) { - if ( SOCKET_EINTR(request_bytes_recvd)) - { - /* the timer popped */ - timed_out = 1; - break; - } -#ifndef WIN32 // But what does WinNT indicate in this situation... - else if (errno == EAGAIN) { - Set_errno(0); - if (times_up) { - timed_out = 1; - break; - } - continue; - } -#endif - else { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - } - else { - request_bytes_remaining -= request_bytes_recvd; - temp_message_ptr += request_bytes_recvd; - } - } - - recv_ring = recv_ring->next; - - if (timed_out) { - /* we hit the end of the test based on time - lets */ - /* bail out of here now... */ - fprintf(where,"yo5\n"); - fflush(where); - break; - } - - /* Now, send the response to the remote */ - if((bytes_sent=send(s_data, - send_ring->buffer_ptr, - tcp_rr_request->response_size, - 0)) == SOCKET_ERROR) { - if (SOCKET_EINTR(bytes_sent)) { - /* the test timer has popped */ - timed_out = 1; - fprintf(where,"yo6\n"); - fflush(where); - break; - } - netperf_response.content.serv_errno = 992; - send_response(); - exit(1); - } - - send_ring = send_ring->next; - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(tcp_rr_request->measure_cpu,&elapsed_time); - - stop_timer(); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_tcp_nbrr: got %d transactions\n", - trans_received); - fflush(where); - } - - tcp_rr_results->bytes_received = (trans_received * - (tcp_rr_request->request_size + - tcp_rr_request->response_size)); - tcp_rr_results->trans_received = trans_received; - tcp_rr_results->elapsed_time = elapsed_time; - tcp_rr_results->cpu_method = cpu_method; - tcp_rr_results->num_cpus = lib_num_loc_cpus; - if (tcp_rr_request->measure_cpu) { - tcp_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_tcp_nbrr: test complete, sending results.\n"); - fflush(where); - } - - /* we are done with the socket, free it */ - close(s_data); - - send_response(); - -} - -#endif /* DO_NBRR */ - - - /* this test is intended to test the performance of establishing a */ - /* connection, and then closing it again. this test is of somewhat */ - /* arcane interest since no packets are exchanged between the */ - /* user-space processes, but it will show the raw overhead of */ - /* establishing a TCP connection. that service demand could then be */ - /* compared with the sum of the service demands of a TCP_CRR and */ - /* TCP_RR test - presumeably, they would all relate */ - -void -send_tcp_cc(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\n\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - int timed_out = 0; - float elapsed_time; - - char temp_message_ptr[1]; - int nummessages; - SOCKET send_socket; - int trans_remaining; - double bytes_xferd; - int rsp_bytes_left = 1; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct addrinfo *local_res; - struct addrinfo *remote_res; - - int myport; - int ret; - - struct tcp_cc_request_struct *tcp_cc_request; - struct tcp_cc_response_struct *tcp_cc_response; - struct tcp_cc_results_struct *tcp_cc_result; - - tcp_cc_request = - (struct tcp_cc_request_struct *)netperf_request.content.test_specific_data; - tcp_cc_response = - (struct tcp_cc_response_struct *)netperf_response.content.test_specific_data; - tcp_cc_result = - (struct tcp_cc_results_struct *)netperf_response.content.test_specific_data; - - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("TCP Connect/Close TEST",local_res,remote_res); - } - - /* initialize a few counters */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - - /* since there are no data buffers in this test, we need no send or */ - /* recv rings */ - - if (debug) { - fprintf(where,"send_tcp_cc: send_socket obtained...\n"); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_TCP_CC; - tcp_cc_request->recv_buf_size = rsr_size_req; - tcp_cc_request->send_buf_size = rss_size_req; - tcp_cc_request->recv_alignment = remote_recv_align; - tcp_cc_request->recv_offset = remote_recv_offset; - tcp_cc_request->send_alignment = remote_send_align; - tcp_cc_request->send_offset = remote_send_offset; - tcp_cc_request->request_size = req_size; - tcp_cc_request->response_size = rsp_size; - tcp_cc_request->no_delay = rem_nodelay; - tcp_cc_request->measure_cpu = remote_cpu_usage; - tcp_cc_request->cpu_rate = remote_cpu_rate; - tcp_cc_request->so_rcvavoid = rem_rcvavoid; - tcp_cc_request->so_sndavoid = rem_sndavoid; - if (test_time) { - tcp_cc_request->test_length = test_time; - } - else { - tcp_cc_request->test_length = test_trans * -1; - } - tcp_cc_request->port = atoi(remote_data_port); - tcp_cc_request->ipfamily = af_to_nf(remote_res->ai_family); - - if (debug > 1) { - fprintf(where,"netperf: send_tcp_cc: requesting TCP crr test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right */ - /* after the connect returns. The remote will grab the counter right */ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - rsr_size = tcp_cc_response->recv_buf_size; - rss_size = tcp_cc_response->send_buf_size; - rem_nodelay = tcp_cc_response->no_delay; - remote_cpu_usage= tcp_cc_response->measure_cpu; - remote_cpu_rate = tcp_cc_response->cpu_rate; - /* make sure that port numbers are in network order */ - set_port_number(remote_res,(unsigned short)tcp_cc_response->data_port_number); - - if (debug) { - fprintf(where,"remote listen done.\n"); - fprintf(where,"remote port is %d\n",get_port_number(remote_res)); - fflush(where); - } - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - -#ifdef WANT_DEMO - DEMO_RR_SETUP(100) -#endif - - /* pick a nice random spot between client_port_min and */ - /* client_port_max for our initial port number */ - srand(getpid()); - if (client_port_max - client_port_min) { - myport = client_port_min + - (rand() % (client_port_max - client_port_min)); - } - else { - myport = client_port_min; - } - /* there will be a ++ before the first call to bind, so subtract one */ - myport--; - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - - while ((!times_up) || (trans_remaining > 0)) { - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before our call to create the socket, and then */ - /* again just after the receive raj 3/95 */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - /* set up the data socket */ - /* newport: is this label really required any longer? */ - /* pick a new port number */ - myport++; - - /* wrap the port number when we get to client_port_max. NOTE, some */ - /* broken TCP's might treat the port number as a signed 16 bit */ - /* quantity. we aren't interested in testing such broken */ - /* implementations :) so we won't make sure that it is below 32767 */ - /* raj 8/94 */ - if (myport >= client_port_max) { - myport = client_port_min; - } - - /* we do not want to use the port number that the server is */ - /* sitting at - this would cause us to fail in a loopback test. we */ - /* could just rely on the failure of the bind to get us past this, */ - /* but I'm guessing that in this one case at least, it is much */ - /* faster, given that we *know* that port number is already in use */ - /* (or rather would be in a loopback test) */ - - if (myport == get_port_number(remote_res)) myport++; - - if (debug) { - if ((nummessages % 100) == 0) { - printf("port %d\n",myport); - } - } - set_port_number(local_res, (unsigned short)myport); - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET) { - perror("netperf: send_tcp_cc: tcp stream data socket"); - exit(1); - } - - /* we used to have a call to bind() here, but that is being - taken care of by create_data_socket(). raj 2005-02-08 */ - - /* Connect up to the remote port on the data socket */ - if ((ret = connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen)) == INVALID_SOCKET){ - if (SOCKET_EINTR(ret)) - { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("netperf: data socket connect failed"); - printf("\tattempted to connect on socket %d to port %d", - send_socket, - get_port_number(remote_res)); - printf(" from port %u \n",get_port_number(local_res)); - exit(1); - } - - /* we hang in a recv() to get the remote's close indication */ - - rsp_bytes_recvd=recv(send_socket, - temp_message_ptr, - rsp_bytes_left, - 0); - - - if (rsp_bytes_recvd == 0) { - /* connection close, call close. we assume that the requisite */ - /* number of bytes have been received */ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_DEMO - DEMO_RR_INTERVAL(1) -#endif - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - fprintf(where, - "Transaction %d completed on local port %u\n", - nummessages, - get_port_number(local_res)); - fflush(where); - } - - close(send_socket); - - } - else { - /* it was less than zero - an error occured */ - if (SOCKET_EINTR(rsp_bytes_recvd)) - { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } - perror("send_tcp_cc: data recv error"); - exit(1); - } - - } - - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ - /* how long did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a TCP stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) We use */ - /* Kbytes/s as the units of thruput for a TCP stream test, where K = */ - /* 1024. A future enhancement *might* be to choose from a couple of */ - /* unit selections. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = calc_thruput(bytes_xferd); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where,"Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where,"Remote CPU usage numbers based on process information only!\n"); - fflush(where); - } - remote_cpu_utilization = tcp_cc_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - tcp_cc_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - case 2: - - if (print_headers) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - nummessages/elapsed_time, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - nummessages/elapsed_time); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - nummessages/elapsed_time); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt, - local_send_align, - remote_recv_offset, - local_send_offset, - remote_recv_offset); - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/response times\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - - } - -} - - -void -recv_tcp_cc() -{ - - char *message; - - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - - struct sockaddr_storage myaddr_in, peeraddr_in; - SOCKET s_listen,s_data; - netperf_socklen_t addrlen; - char *recv_message_ptr; - char *send_message_ptr; - int trans_received; - int trans_remaining; - int timed_out = 0; - float elapsed_time; - - struct tcp_cc_request_struct *tcp_cc_request; - struct tcp_cc_response_struct *tcp_cc_response; - struct tcp_cc_results_struct *tcp_cc_results; - - tcp_cc_request = - (struct tcp_cc_request_struct *)netperf_request.content.test_specific_data; - tcp_cc_response = - (struct tcp_cc_response_struct *)netperf_response.content.test_specific_data; - tcp_cc_results = - (struct tcp_cc_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_tcp_cc: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_tcp_cc: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = TCP_CC_RESPONSE; - - if (debug) { - fprintf(where,"recv_tcp_cc: the response type is set...\n"); - fflush(where); - } - - /* set-up the data buffer with the requested alignment and offset */ - message = (char *)malloc(DATABUFFERLEN); - if (message == NULL) { - printf("malloc(%d) failed!\n", DATABUFFERLEN); - exit(1); - } - - /* We now alter the message_ptr variables to be at the desired */ - /* alignments with the desired offsets. */ - - if (debug) { - fprintf(where, - "recv_tcp_cc: requested recv alignment of %d offset %d\n", - tcp_cc_request->recv_alignment, - tcp_cc_request->recv_offset); - fprintf(where, - "recv_tcp_cc: requested send alignment of %d offset %d\n", - tcp_cc_request->send_alignment, - tcp_cc_request->send_offset); - fflush(where); - } - - recv_message_ptr = ALIGN_BUFFER(message, tcp_cc_request->recv_alignment, tcp_cc_request->recv_offset); - - send_message_ptr = ALIGN_BUFFER(message, tcp_cc_request->send_alignment, tcp_cc_request->send_offset); - - if (debug) { - fprintf(where,"recv_tcp_cc: receive alignment and offset set...\n"); - fflush(where); - } - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_tcp_cc: grabbing a socket...\n"); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = tcp_cc_request->send_buf_size; - lsr_size_req = tcp_cc_request->recv_buf_size; - loc_nodelay = tcp_cc_request->no_delay; - loc_rcvavoid = tcp_cc_request->so_rcvavoid; - loc_sndavoid = tcp_cc_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(tcp_cc_request->ipfamily), - tcp_cc_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(tcp_cc_request->ipfamily), - SOCK_STREAM, - IPPROTO_TCP, - 0); - - s_listen = create_data_socket(local_res); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - if (debug) { - fprintf(where,"could not create data socket\n"); - fflush(where); - } - exit(1); - } - -#ifdef WIN32 - /* The test timer can fire during operations on the listening socket, - so to make the start_timer below work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket2 = s_listen; -#endif - - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - if (debug) { - fprintf(where,"could not listen\n"); - fflush(where); - } - exit(1); - } - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - if (debug) { - fprintf(where,"could not geetsockname\n"); - fflush(where); - } - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - tcp_cc_response->data_port_number = - (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port); - if (debug) { - fprintf(where,"telling the remote to call me at %d\n", - tcp_cc_response->data_port_number); - fflush(where); - } - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - tcp_cc_response->cpu_rate = (float)0.0; /* assume no cpu */ - if (tcp_cc_request->measure_cpu) { - tcp_cc_response->measure_cpu = 1; - tcp_cc_response->cpu_rate = - calibrate_local_cpu(tcp_cc_request->cpu_rate); - } - - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - tcp_cc_response->send_buf_size = lss_size; - tcp_cc_response->recv_buf_size = lsr_size; - tcp_cc_response->no_delay = loc_nodelay; - tcp_cc_response->so_rcvavoid = loc_rcvavoid; - tcp_cc_response->so_sndavoid = loc_sndavoid; - - send_response(); - - addrlen = sizeof(peeraddr_in); - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(tcp_cc_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - if (tcp_cc_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(tcp_cc_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = tcp_cc_request->test_length * -1; - } - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { -#ifdef WIN32 - /* The test timer will probably fire during this accept, - so to make the start_timer above work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket = s_listen; -#endif - /* accept a connection from the remote */ - if ((s_data=accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - if (errno == EINTR) { - /* the timer popped */ - timed_out = 1; - break; - } - fprintf(where,"recv_tcp_cc: accept: errno = %d\n",errno); - fflush(where); - close(s_listen); - - exit(1); - } - -#ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass */ - /* attributes across an accept() call. Including this goes against */ - /* my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - -#ifdef WIN32 - /* this is used so the timer thread can close the socket out from */ - /* under us, which to date is the easiest/cleanest/least */ - /* Windows-specific way I can find to force the winsock calls to */ - /* return WSAEINTR with the test is over. anything that will run on */ - /* 95 and NT and is closer to what netperf expects from Unix signals */ - /* and such would be appreciated raj 1/96 */ - win_kludge_socket = s_data; -#endif /* WIN32 */ - - if (debug) { - fprintf(where,"recv_tcp_cc: accepted data connection.\n"); - fflush(where); - } - - - /* close the connection. the server will likely do a graceful */ - /* close of the connection, insuring that all data has arrived at */ - /* the client. for this it will call shutdown(), and then recv() and */ - /* then close(). I'm reasonably confident that this is the */ - /* appropriate sequence of calls - I would like to hear of */ - /* examples in web servers to the contrary. raj 10/95*/ - close(s_data); - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug) { - fprintf(where, - "recv_tcp_cc: Transaction %d complete\n", - trans_received); - fflush(where); - } - - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(tcp_cc_request->measure_cpu,&elapsed_time); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_tcp_cc: got %d transactions\n", - trans_received); - fflush(where); - } - - tcp_cc_results->bytes_received = (trans_received * - (tcp_cc_request->request_size + - tcp_cc_request->response_size)); - tcp_cc_results->trans_received = trans_received; - tcp_cc_results->elapsed_time = elapsed_time; - if (tcp_cc_request->measure_cpu) { - tcp_cc_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_tcp_cc: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - -} - -void -print_sockets_usage() -{ - - fwrite(sockets_usage, sizeof(char), strlen(sockets_usage), stdout); - exit(1); - -} - -void -scan_sockets_args(int argc, char *argv[]) - -{ - -#define SOCKETS_ARGS "b:CDnNhH:L:m:M:p:P:r:s:S:T:Vw:W:z46" - - extern char *optarg; /* pointer to option string */ - - int c; - - char - arg1[BUFSIZ], /* argument holders */ - arg2[BUFSIZ]; - - if (debug) { - int i; - printf("%s called with the following argument vector\n", - __func__); - for (i = 0; i< argc; i++) { - printf("%s ",argv[i]); - } - printf("\n"); - } - - strncpy(local_data_port,"0",sizeof(local_data_port)); - strncpy(remote_data_port,"0",sizeof(remote_data_port)); - - /* Go through all the command line arguments and break them */ - /* out. For those options that take two parms, specifying only */ - /* the first will set both to that value. Specifying only the */ - /* second will leave the first untouched. To change only the */ - /* first, use the form "first," (see the routine break_args.. */ - - while ((c= getopt(argc, argv, SOCKETS_ARGS)) != EOF) { - switch (c) { - case '?': - case '4': - remote_data_family = AF_INET; - local_data_family = AF_INET; - break; - case '6': -#if defined(AF_INET6) - remote_data_family = AF_INET6; - local_data_family = AF_INET6; -#else - fprintf(stderr, - "This netperf was not compiled on an IPv6 capable host!\n"); - fflush(stderr); - exit(-1); -#endif - break; - case 'h': - print_sockets_usage(); - exit(1); - case 'b': -#ifdef WANT_FIRST_BURST - first_burst_size = atoi(optarg); -#else /* WANT_FIRST_BURST */ - printf("Initial request burst functionality not compiled-in!\n"); -#endif /* WANT_FIRST_BURST */ - break; - case 'C': -#ifdef TCP_CORK - /* set TCP_CORK */ - loc_tcpcork = 1; - rem_tcpcork = 1; /* however, at first, we ony have cork affect loc */ -#else - printf("WARNING: TCP_CORK not available on this platform!\n"); -#endif /* TCP_CORK */ - break; - case 'D': - /* set the TCP nodelay flag */ - loc_nodelay = 1; - rem_nodelay = 1; - break; - case 'H': - break_args_explicit(optarg,arg1,arg2); - if (arg1[0]) { - /* make sure we leave room for the NULL termination boys and - girls. raj 2005-02-82 */ - remote_data_address = malloc(strlen(arg1)+1); - strncpy(remote_data_address,arg1,strlen(arg1)); - } - if (arg2[0]) - remote_data_family = parse_address_family(arg2); - break; - case 'L': - break_args_explicit(optarg,arg1,arg2); - if (arg1[0]) { - /* make sure we leave room for the NULL termination boys and - girls. raj 2005-02-82 */ - local_data_address = malloc(strlen(arg1)+1); - strncpy(local_data_address,arg1,strlen(arg1)); - } - if (arg2[0]) - local_data_family = parse_address_family(arg2); - break; - case 's': - /* set local socket sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - lss_size_req = convert(arg1); - if (arg2[0]) - lsr_size_req = convert(arg2); - break; - case 'S': - /* set remote socket sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - rss_size_req = convert(arg1); - if (arg2[0]) - rsr_size_req = convert(arg2); - break; - case 'r': - /* set the request/response sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - req_size = convert(arg1); - if (arg2[0]) - rsp_size = convert(arg2); - break; - case 'm': - /* set the send size */ - send_size = convert(optarg); - break; - case 'M': - /* set the recv size */ - recv_size = convert(optarg); - break; - case 'n': - /* set the local socket type*/ - local_connected = 1; - break; - case 'N': - /* set the remote socket type*/ - remote_connected = 1; - break; - case 'p': - /* set the min and max port numbers for the TCP_CRR and TCP_TRR */ - /* tests. */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - client_port_min = atoi(arg1); - if (arg2[0]) - client_port_max = atoi(arg2); - break; - case 'P': - /* set the local and remote data port numbers for the tests to - allow them to run through those blankety blank end-to-end - breaking firewalls. raj 2004-06-15 */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - strncpy(local_data_port,arg1,sizeof(local_data_port)); - if (arg2[0]) - strncpy(remote_data_port,arg2,sizeof(remote_data_port)); - break; - case 't': - /* set the test name */ - strcpy(test_name,optarg); - break; - case 'W': - /* set the "width" of the user space data */ - /* buffer. This will be the number of */ - /* send_size buffers malloc'd in the */ - /* *_STREAM test. It may be enhanced to set */ - /* both send and receive "widths" but for now */ - /* it is just the sending *_STREAM. */ - send_width = convert(optarg); - break; - case 'V' : - /* we want to do copy avoidance and will set */ - /* it for everything, everywhere, if we really */ - /* can. of course, we don't know anything */ - /* about the remote... */ -#ifdef SO_SND_COPYAVOID - loc_sndavoid = 1; -#else - loc_sndavoid = 0; - printf("Local send copy avoidance not available.\n"); -#endif -#ifdef SO_RCV_COPYAVOID - loc_rcvavoid = 1; -#else - loc_rcvavoid = 0; - printf("Local recv copy avoidance not available.\n"); -#endif - rem_sndavoid = 1; - rem_rcvavoid = 1; - break; - }; - } - -#if defined(WANT_FIRST_BURST) -#if defined(WANT_HISTOGRAM) - /* if WANT_FIRST_BURST and WANT_HISTOGRAM are defined and the user - indeed wants a non-zero first burst size, and we would emit a - histogram, then we should emit a warning that the two are not - compatible. raj 2006-01-31 */ - if ((first_burst_size > 0) && (verbosity >= 2)) { - fprintf(stderr, - "WARNING! Histograms and first bursts are incompatible!\n"); - fflush(stderr); - } -#endif -#endif - - /* we do not want to make remote_data_address non-NULL because if - the user has not specified a remote adata address, we want to - take it from the hostname in the -H global option. raj - 2005-02-08 */ - - /* so, if there is to be no control connection, we want to have some - different settings for a few things */ - - if (no_control) { - - if (strcmp(remote_data_port,"0") == 0) { - /* we need to select either the discard port, echo port or - chargen port dedepending on the test name. raj 2007-02-08 */ - if (strstr(test_name,"STREAM") || - strstr(test_name,"SENDFILE")) { - strncpy(remote_data_port,"discard",sizeof(remote_data_port)); - } - else if (strstr(test_name,"RR")) { - strncpy(remote_data_port,"echo",sizeof(remote_data_port)); - } - else if (strstr(test_name,"MAERTS")) { - strncpy(remote_data_port,"chargen",sizeof(remote_data_port)); - } - else { - printf("No default port known for the %s test, please set one yourself\n",test_name); - exit(-1); - } - } - remote_data_port[sizeof(remote_data_port) - 1] = '\0'; - - /* I go back and forth on whether these should become -1 or if - they should become 0 for a no_control test. what do you think? - raj 2006-02-08 */ - - rem_rcvavoid = -1; - rem_sndavoid = -1; - rss_size_req = -1; - rsr_size_req = -1; - rem_nodelay = -1; - - if (strstr(test_name,"STREAM") || - strstr(test_name,"SENDFILE")) { - recv_size = -1; - } - else if (strstr(test_name,"RR")) { - /* I am however _certain_ that for a no control RR test the - response size must equal the request size since 99 times out - of ten we will be speaking to the echo service somewhere */ - rsp_size = req_size; - } - else if (strstr(test_name,"MAERTS")) { - send_size = -1; - } - else { - printf("No default port known for the %s test, please set one yourself\n",test_name); - exit(-1); - } - } -} diff --git a/nettest_bsd.h b/nettest_bsd.h deleted file mode 100644 index 5491290..0000000 --- a/nettest_bsd.h +++ /dev/null @@ -1,471 +0,0 @@ -/* - Copyright (C) 1993-2004 Hewlett-Packard Company -*/ - - /* This file contains the test-specific definitions for netperf's BSD */ - /* sockets tests */ - -/* well boys and girls, seems that while AF_INET is "2" and AF_UNSPEC - is "0" the world over, AF_INET6 is different values depending on - the platform... grrr. On HP-UX 11i it is "22" and on Linux 2.6 it - is "10" sooooo... we have to define our own space for netperf to - enable us to pass values around from machine to machine. raj - 2005-02-08 */ -#define NF_UNSPEC 0 -#define NF_INET 4 -#define NF_INET6 6 - -struct tcp_stream_request_struct { - int send_buf_size; - int recv_buf_size; /* how big does the client want it - the */ - /* receive socket buffer that is */ - int receive_size; /* how many bytes do we want to receive at one */ - /* time? */ - int recv_alignment; /* what is the alignment of the receive */ - /* buffer? */ - int recv_offset; /* and at what offset from that alignment? */ - int no_delay; /* do we disable the nagle algorithm for send */ - /* coalescing? */ - int measure_cpu; /* does the client want server cpu utilization */ - /* measured? */ - float cpu_rate; /* do we know how fast the cpu is already? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid copies on */ - /* receives? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dirty_count; /* how many integers in the receive buffer */ - /* should be made dirty before calling recv? */ - int clean_count; /* how many integers should be read from the */ - /* recv buffer before calling recv? */ - int port; /* the port to which the recv side should bind - to allow netperf to run through those evil - firewall things */ - int ipfamily; /* the address family of ipaddress */ -}; - -struct tcp_stream_response_struct { - int recv_buf_size; /* how big does the client want it */ - int receive_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct tcp_stream_results_struct { - double bytes_received; - unsigned int recv_calls; - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -struct tcp_maerts_request_struct { - int send_buf_size; - int recv_buf_size; /* how big does the client want it - the */ - /* receive socket buffer that is */ - int send_size; /* how many bytes do we want netserver to send - at one time? */ - int send_alignment; /* what is the alignment of the send */ - /* buffer? */ - int send_offset; /* and at what offset from that alignment? */ - int no_delay; /* do we disable the nagle algorithm for send */ - /* coalescing? */ - int measure_cpu; /* does the client want server cpu utilization */ - /* measured? */ - float cpu_rate; /* do we know how fast the cpu is already? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid copies on */ - /* receives? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dirty_count; /* how many integers in the send buffer */ - /* should be made dirty before calling recv? */ - int clean_count; /* how many integers should be read from the */ - /* recv buffer before calling recv? */ - int port; /* the port to which the recv side should bind - to allow netperf to run through those evil - firewall things */ - int ipfamily; -}; - -struct tcp_maerts_response_struct { - int recv_buf_size; /* how big does the client want it */ - int send_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct tcp_maerts_results_struct { - double bytes_sent; - unsigned int send_calls; - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -struct tcp_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int port; /* the port to which the recv side should bind - to allow netperf to run through those evil - firewall things */ - int ipfamily; -}; - -struct tcp_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct tcp_rr_results_struct { - unsigned int bytes_received; /* ignored initially */ - unsigned int recv_calls; /* ignored initially */ - unsigned int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -struct tcp_conn_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int port; /* the port to which the recv side should bind - to allow netperf to run through those evil - firewall things */ - int ipfamily; -}; - - -struct tcp_conn_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct tcp_conn_rr_results_struct { - unsigned int bytes_received; /* ignored initially */ - unsigned int recv_calls; /* ignored initially */ - unsigned int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -struct tcp_tran_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int port; /* the port to which the recv side should bind - to allow netperf to run through those evil - firewall things */ - int ipfamily; -}; - - -struct tcp_tran_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct tcp_tran_rr_results_struct { - unsigned int bytes_received; /* ignored initially */ - unsigned int recv_calls; /* ignored initially */ - unsigned int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ - -}; - -struct udp_stream_request_struct { - int recv_buf_size; - int message_size; - int recv_connected; - int recv_alignment; - int recv_offset; - int checksum_off; - int measure_cpu; - float cpu_rate; - int test_length; - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int port; /* the port to which the recv side should bind - to allow netperf to run through those evil - firewall things */ - int ipfamily; - -}; - -struct udp_stream_response_struct { - int recv_buf_size; - int send_buf_size; - int measure_cpu; - int test_length; - int data_port_number; - float cpu_rate; - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct udp_stream_results_struct { - unsigned int messages_recvd; - unsigned int bytes_received; - float elapsed_time; - float cpu_util; - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - - -struct udp_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int port; /* the port to which the recv side should bind - to allow netperf to run through those evil - firewall things */ - int ipfamily; -}; - -struct udp_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct udp_rr_results_struct { - unsigned int bytes_received; /* ignored initially */ - unsigned int recv_calls; /* ignored initially */ - unsigned int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -struct tcp_cc_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int port; /* the port to which the recv side should bind - to allow netperf to run through those evil - firewall things */ - int ipfamily; -}; - - -struct tcp_cc_response_struct { - int recv_buf_size; /* how big does the client want it */ - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct tcp_cc_results_struct { - unsigned int bytes_received; /* ignored initially */ - unsigned int recv_calls; /* ignored initially */ - unsigned int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -extern int rss_size_req, /* requested remote socket send buffer size */ - rsr_size_req, /* requested remote socket recv buffer size */ - rss_size, /* remote socket send buffer size */ - rsr_size, /* remote socket recv buffer size */ - lss_size_req, /* requested local socket send buffer size */ - lsr_size_req, /* requested local socket recv buffer size */ - lss_size, /* local socket send buffer size */ - lsr_size, /* local socket recv buffer size */ - req_size, /* request size */ - rsp_size, /* response size */ - send_size, /* how big are individual sends */ - recv_size, /* how big are individual receives */ - loc_nodelay, /* don't/do use NODELAY locally */ - rem_nodelay, /* don't/do use NODELAY remotely */ - loc_sndavoid, /* avoid send copies locally */ - loc_rcvavoid, /* avoid recv copies locally */ - rem_sndavoid, /* avoid send copies remotely */ - rem_rcvavoid; /* avoid recv_copies remotely */ - - -extern void scan_sockets_args(int argc, char *argv[]); -extern struct addrinfo *complete_addrinfo(char *controlhost, - char *data_address, - char *port, - int family, - int type, - int protocol, - int flags); -extern void complete_addrinfos(struct addrinfo **remote, - struct addrinfo **local, - char remote_host[], - int type, - int protocol, - int flags); -extern int af_to_nf(int af); -extern int nf_to_af(int nf); -extern void print_top_test_header(char test_name[], - struct addrinfo *source, - struct addrinfo *destination); -extern void set_port_number(struct addrinfo *res, - unsigned short port); -extern void set_hostname_and_port(char *hostname, - char *portstr, - int family, - int port); -extern void send_tcp_stream(char remote_host[]); -extern void send_tcp_maerts(char remote_host[]); -extern void send_tcp_rr(char remote_host[]); -extern void send_tcp_conn_rr(char remote_host[]); -extern void send_tcp_cc(char remote_host[]); -extern void send_udp_stream(char remote_host[]); -extern void send_udp_rr(char remote_host[]); - -extern void recv_tcp_stream(); -extern void recv_tcp_maerts(); -extern void recv_tcp_rr(); -extern void recv_tcp_conn_rr(); -extern void recv_tcp_cc(); -extern void recv_udp_stream(); -extern void recv_udp_rr(); - -extern void loc_cpu_rate(); -extern void rem_cpu_rate(); - -#ifdef HAVE_ICSC_EXS -extern void send_exs_tcp_stream(char remotehost[]); -#endif /* HAVE_ICSC_EXS */ - -#ifdef HAVE_SENDFILE -extern void sendfile_tcp_stream(char remotehost[]); -#endif /* HAVE_SENDFILE */ - -#if !defined(HAVE_STRUCT_SOCKADDR_STORAGE) && !defined(sockaddr_storage) -#define sockaddr_storage sockaddr_in -#endif - -#ifdef DO_NBRR -extern void send_tcp_nbrr(char remote_host[]); - -extern void recv_tcp_nbrr(); -#endif - diff --git a/nettest_dlpi.c b/nettest_dlpi.c deleted file mode 100644 index ab3e79f..0000000 --- a/nettest_dlpi.c +++ /dev/null @@ -1,3798 +0,0 @@ - -/****************************************************************/ -/* */ -/* nettest_dlpi.c */ -/* */ -/* the actual test routines... */ -/* */ -/* send_dlpi_co_stream() perform a CO DLPI stream test */ -/* recv_dlpi_co_stream() */ -/* send_dlpi_co_rr() perform a CO DLPI req/res */ -/* recv_dlpi_co_rr() */ -/* send_dlpi_cl_stream() perform a CL DLPI stream test */ -/* recv_dlpi_cl_stream() */ -/* send_dlpi_cl_rr() perform a CL DLPI req/res */ -/* recv_dlpi_cl_rr() */ -/* */ -/****************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef WANT_DLPI -char nettest_dlpi_id[]="\ -@(#)nettest_dlpi.c (c) Copyright 1993,1995,2004 Hewlett-Packard Co. Version 2.4.3"; - -#include <sys/types.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <malloc.h> -#include <sys/stream.h> -#include <sys/stropts.h> -#include <sys/poll.h> -#ifdef __osf__ -#include <sys/dlpihdr.h> -#else /* __osf__ */ -#include <sys/dlpi.h> -#ifdef __hpux__ -#include <sys/dlpi_ext.h> -#endif /* __hpux__ */ -#endif /* __osf__ */ - -#include "netlib.h" -#include "netsh.h" -#include "nettest_dlpi.h" - -/* these are some variables global to all the DLPI tests. declare */ -/* them static to make them global only to this file */ - -static int - rsw_size, /* remote send window size */ - rrw_size, /* remote recv window size */ - lsw_size, /* local send window size */ - lrw_size, /* local recv window size */ - req_size = 100, /* request size */ - rsp_size = 200, /* response size */ - send_size, /* how big are individual sends */ - recv_size; /* how big are individual receives */ - -int - loc_ppa = 4, /* the ppa for the local interface, */ - /* as shown as the NM Id in lanscan */ - rem_ppa = 4, /* the ppa for the remote interface */ - dlpi_sap = 84; /* which 802.2 SAP should we use? */ - -char loc_dlpi_device[32] = "/dev/dlpi"; -char rem_dlpi_device[32] = "/dev/dlpi"; - -char dlpi_usage[] = "\n\ -Usage: netperf [global options] -- [test options] \n\ -\n\ -CO/CL DLPI Test Options:\n\ - -D dev[,dev] Set the local/remote DLPI device file name\n\ - -h Display this text\n\ - -M bytes Set the recv size (DLCO_STREAM, DLCL_STREAM)\n\ - -m bytes Set the send size (DLCO_STREAM, DLCL_STREAM)\n\ - -p loc[,rem] Set the local/remote PPA for the test\n\ - -R bytes Set response size (DLCO_RR, DLCL_RR)\n\ - -r bytes Set request size (DLCO_RR, DLCL_RR)\n\ - -s sap Set the 802.2 sap for the test\n\ - -W send[,recv] Set remote send/recv window sizes\n\ - -w send[,recv] Set local send/recv window sizes\n\ -\n\ -For those options taking two parms, at least one must be specified;\n\ -specifying one value without a comma will set both parms to that\n\ -value, specifying a value with a leading comma will set just the second\n\ -parm, a value with a trailing comma will set just the first. To set\n\ -each parm to unique values, specify both and separate them with a\n\ -comma.\n"; - - -/* This routine implements the CO unidirectional data transfer test */ -/* (a.k.a. stream) for the sockets interface. It receives its */ -/* parameters via global variables from the shell and writes its */ -/* output to the standard output. */ - - -void -send_dlpi_co_stream() -{ - - char *tput_title = "\ -Recv Send Send \n\ -Window Window Message Elapsed \n\ -Size Size Size Time Throughput \n\ -frames frames bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = - "%5d %5d %6d %-6.2f %7.2f \n"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Window Window Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -frames frames bytes secs. %-8.8s/s %% %% us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f\n"; - - char *cpu_fmt_1 = - "%5d %5d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ -Local Remote Local Remote Xfered Per Per\n\ -Send Recv Send Recv Send (avg) Recv (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - - - float elapsed_time; - -#ifdef WANT_INTERVALS - int interval_count; -#endif /* WANT_INTERVALS */ - - /* what we want is to have a buffer space that is at least one */ - /* send-size greater than our send window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - - struct ring_elt *send_ring; - char *message; - char *message_ptr; - struct strbuf send_message; - char dlsap[BUFSIZ]; - int dlsap_len; - int *message_int_ptr; - int message_offset; - int malloc_size; - - int len; - int nummessages; - int send_descriptor; - int bytes_remaining; - /* with links like fddi, one can send > 32 bits worth of bytes */ - /* during a test... ;-) */ - double bytes_sent; - -#ifdef DIRTY - int i; -#endif /* DIRTY */ - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct dlpi_co_stream_request_struct *dlpi_co_stream_request; - struct dlpi_co_stream_response_struct *dlpi_co_stream_response; - struct dlpi_co_stream_results_struct *dlpi_co_stream_result; - - dlpi_co_stream_request = - (struct dlpi_co_stream_request_struct *)netperf_request.content.test_specific_data; - dlpi_co_stream_response = - (struct dlpi_co_stream_response_struct *)netperf_response.content.test_specific_data; - dlpi_co_stream_result = - (struct dlpi_co_stream_results_struct *)netperf_response.content.test_specific_data; - - if ( print_headers ) { - fprintf(where,"DLPI CO STREAM TEST\n"); - if (local_cpu_usage || remote_cpu_usage) - fprintf(where,cpu_title,format_units()); - else - fprintf(where,tput_title,format_units()); - } - - /* initialize a few counters */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - - /*set up the data descriptor */ - send_descriptor = dl_open(loc_dlpi_device,loc_ppa); - if (send_descriptor < 0){ - perror("netperf: send_dlpi_co_stream: dlpi stream data descriptor"); - exit(1); - } - - /* bind the puppy and get the assigned dlsap */ - dlsap_len = BUFSIZ; - if (dl_bind(send_descriptor, - dlpi_sap, DL_CODLS, dlsap, &dlsap_len) != 0) { - fprintf(where,"send_dlpi_co_rr: bind failure\n"); - fflush(where); - exit(1); - } - - if (debug) { - fprintf(where,"send_dlpi_co_stream: send_descriptor obtained...\n"); - } - -#ifdef DL_HP_SET_LOCAL_WIN_REQ - if (lsw_size > 0) { - if (debug > 1) { - fprintf(where,"netperf: send_dlpi_co_stream: window send size altered from system default...\n"); - fprintf(where," send: %d\n",lsw_size); - } - } - if (lrw_size > 0) { - if (debug > 1) { - fprintf(where, - "netperf: send_dlpi_co_stream: window recv size altered from system default...\n"); - fprintf(where," recv: %d\n",lrw_size); - } - } - - - /* Now, we will find-out what the size actually became, and report */ - /* that back to the user. If the call fails, we will just report a -1 */ - /* back to the initiator for the recv buffer size. */ - - - if (debug) { - fprintf(where, - "netperf: send_dlpi_co_stream: window sizes determined...\n"); - fprintf(where," send: %d recv: %d\n",lsw_size,lrw_size); - ffluch(where); - } - -#else /* DL_HP_SET_LOCAL_WIN_REQ */ - - lsw_size = -1; - lrw_size = -1; - -#endif /* DL_HP_SET_LOCAL_WIN_REQ */ - - /* we should pick a default send_size, it should not be larger than */ - /* the min of the two interface MTU's, and should perhaps default to */ - /* the Interface MTU, but for now, we will default it to 1024... if */ - /* someone wants to change this, the should change the corresponding */ - /* lines in the recv_dlpi_co_stream routine */ - - if (send_size == 0) { - send_size = 1024; - } - - /* set-up the data buffer with the requested alignment and offset. */ - /* After we have calculated the proper starting address, we want to */ - /* put that back into the message variable so we go back to the */ - /* proper place. note that this means that only the first send is */ - /* guaranteed to be at the alignment specified by the -a parameter. I */ - /* think that this is a little more "real-world" than what was found */ - /* in previous versions. note also that we have allocated a quantity */ - /* of memory that is at least one send-size greater than our socket */ - /* buffer size. We want to be sure that there are at least two */ - /* buffers allocated - this can be a bit of a problem when the */ - /* send_size is bigger than the socket size, so we must check... the */ - /* user may have wanted to explicitly set the "width" of our send */ - /* buffers, we should respect that wish... */ - if (send_width == 0) { - send_width = (lsw_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - send_ring = allocate_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset); - - send_message.maxlen = send_size; - send_message.len = send_size; - send_message.buf = send_ring->buffer_ptr; - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. */ - - netperf_request.content.request_type = DO_DLPI_CO_STREAM; - dlpi_co_stream_request->send_win_size = rsw_size; - dlpi_co_stream_request->recv_win_size = rrw_size; - dlpi_co_stream_request->receive_size = recv_size; - dlpi_co_stream_request->recv_alignment= remote_recv_align; - dlpi_co_stream_request->recv_offset = remote_recv_offset; - dlpi_co_stream_request->measure_cpu = remote_cpu_usage; - dlpi_co_stream_request->cpu_rate = remote_cpu_rate; - dlpi_co_stream_request->ppa = rem_ppa; - dlpi_co_stream_request->sap = dlpi_sap; - dlpi_co_stream_request->dev_name_len = strlen(rem_dlpi_device); - strcpy(dlpi_co_stream_request->dlpi_device, - rem_dlpi_device); - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I didn't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) dlpi_co_stream_request->dlpi_device; - lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = ntohl(*charword); - } - } -#endif /* __alpha */ - - if (test_time) { - dlpi_co_stream_request->test_length = test_time; - } - else { - dlpi_co_stream_request->test_length = test_bytes; - } -#ifdef DIRTY - dlpi_co_stream_request->dirty_count = rem_dirty_count; - dlpi_co_stream_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - - - if (debug > 1) { - fprintf(where, - "netperf: send_dlpi_co_stream: requesting DLPI CO stream test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right */ - /* after the connect returns. The remote will grab the counter right */ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rrw_size = dlpi_co_stream_response->recv_win_size; - rsw_size = dlpi_co_stream_response->send_win_size; - remote_cpu_usage= dlpi_co_stream_response->measure_cpu; - remote_cpu_rate = dlpi_co_stream_response->cpu_rate; - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - exit(1); - } - - /* Connect up to the remote port on the data descriptor */ - if(dl_connect(send_descriptor, - dlpi_co_stream_response->station_addr, - dlpi_co_stream_response->station_addr_len) != 0) { - fprintf(where,"recv_dlpi_co_stream: connect failure\n"); - fflush(where); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a stream test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - bytes_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. */ - -#ifdef DIRTY - /* initialize the random number generator for putting dirty stuff */ - /* into the send buffer. raj */ - srand((int) getpid()); -#endif /* DIRTY */ - - while ((!times_up) || (bytes_remaining > 0)) { - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - message_int_ptr = (int *)message_ptr; - for (i = 0; i < loc_dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < loc_clean_count; i++) { - loc_dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - - if((putmsg(send_descriptor, - 0, - &send_message, - 0)) != 0) { - if (errno == EINTR) - break; - perror("netperf: data send error"); - exit(1); - } - send_ring = send_ring->next; - send_message.buf = send_ring->buffer_ptr; -#ifdef WANT_INTERVALS - for (interval_count = 0; - interval_count < interval_wate; - interval_count++); -#endif /* WANT_INTERVALS */ - - if (debug > 4) { - fprintf(where,"netperf: send_clpi_co_stream: putmsg called "); - fprintf(where,"len is %d\n",send_message.len); - fflush(where); - } - - nummessages++; - if (bytes_remaining) { - bytes_remaining -= send_size; - } - } - - /* The test is over. Flush the buffers to the remote end. We do a */ - /* graceful release to insure that all data has been taken by the */ - /* remote. this needs a little work - there is no three-way */ - /* handshake with type two as there is with TCP, so there really */ - /* should be a message exchange here. however, we will finesse it by */ - /* saying that the tests shoudl run for a while. */ - - if (debug) { - fprintf(where,"sending test end signal \n"); - fflush(where); - } - - send_message.len = (send_size - 1); - if (send_message.len == 0) send_message.len = 2; - - if((putmsg(send_descriptor, - 0, - &send_message, - 0)) != 0) { - perror("netperf: data send error"); - exit(1); - } - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ - /* how long did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a TCP stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) */ - - bytes_sent = ((double) send_size * (double) nummessages) + (double) len; - thruput = calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where, - "WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where, - "Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where, - "DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where, - "Remote CPU usage numbers based on process information only!\n"); - fflush(where); - } - remote_cpu_utilization = dlpi_co_stream_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - dlpi_co_stream_result->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - case 2: - fprintf(where, - cpu_fmt_1, /* the format string */ - rrw_size, /* remote recvbuf size */ - lsw_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput); - break; - case 1: - case 2: - fprintf(where, - tput_fmt_1, /* the format string */ - rrw_size, /* remote recvbuf size */ - lsw_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - thruput);/* how fast did it go */ - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_send_align, - remote_recv_align, - local_send_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)dlpi_co_stream_result->recv_calls, - dlpi_co_stream_result->recv_calls); - } - -} - - -/* This is the server-side routine for the tcp stream test. It is */ -/* implemented as one routine. I could break things-out somewhat, but */ -/* didn't feel it was necessary. */ - -int - recv_dlpi_co_stream() -{ - - int data_descriptor; - int flags = 0; - int measure_cpu; - int bytes_received; - int receive_calls; - float elapsed_time; - - struct ring_elt *recv_ring; - char *message_ptr; - char *message; - int *message_int_ptr; - struct strbuf recv_message; - int dirty_count; - int clean_count; - int i; - - struct dlpi_co_stream_request_struct *dlpi_co_stream_request; - struct dlpi_co_stream_response_struct *dlpi_co_stream_response; - struct dlpi_co_stream_results_struct *dlpi_co_stream_results; - - dlpi_co_stream_request = (struct dlpi_co_stream_request_struct *)netperf_request.content.test_specific_data; - dlpi_co_stream_response = (struct dlpi_co_stream_response_struct *)netperf_response.content.test_specific_data; - dlpi_co_stream_results = (struct dlpi_co_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_dlpi_co_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - netperf_response.content.response_type = DLPI_CO_STREAM_RESPONSE; - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug > 1) { - fprintf(where,"recv_dlpi_co_stream: requested alignment of %d\n", - dlpi_co_stream_request->recv_alignment); - fflush(where); - } - - - /* Grab a descriptor to listen on, and then listen on it. */ - - if (debug > 1) { - fprintf(where,"recv_dlpi_co_stream: grabbing a descriptor...\n"); - fflush(where); - } - - - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) dlpi_co_stream_request->dlpi_device; - lastword = initword + ((dlpi_co_stream_request->dev_name_len + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = htonl(*charword); - } - } -#endif /* __alpha */ - - data_descriptor = dl_open(dlpi_co_stream_request->dlpi_device, - dlpi_co_stream_request->ppa); - if (data_descriptor < 0) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* Let's get an address assigned to this descriptor so we can tell the */ - /* initiator how to reach the data descriptor. There may be a desire to */ - /* nail this descriptor to a specific address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - /* bind the sap and retrieve the dlsap assigned by the system */ - dlpi_co_stream_response->station_addr_len = 14; /* arbitrary */ - if (dl_bind(data_descriptor, - dlpi_co_stream_request->sap, - DL_CODLS, - (char *)dlpi_co_stream_response->station_addr, - &dlpi_co_stream_response->station_addr_len) != 0) { - fprintf(where,"recv_dlpi_co_stream: bind failure\n"); - fflush(where); - exit(1); - } - - /* The initiator may have wished-us to modify the socket buffer */ - /* sizes. We should give it a shot. If he didn't ask us to change the */ - /* sizes, we should let him know what sizes were in use at this end. */ - /* If none of this code is compiled-in, then we will tell the */ - /* initiator that we were unable to play with the socket buffer by */ - /* setting the size in the response to -1. */ - -#ifdef DL_HP_SET_LOCAL_WIN_REQ - - if (dlpi_co_stream_request->recv_win_size) { - } - /* Now, we will find-out what the size actually became, and report */ - /* that back to the user. If the call fails, we will just report a -1 */ - /* back to the initiator for the recv buffer size. */ - -#else /* the system won't let us play with the buffers */ - - dlpi_co_stream_response->recv_win_size = -1; - -#endif /* DL_HP_SET_LOCAL_WIN_REQ */ - - /* what sort of sizes did we end-up with? */ - /* this bit of code whould default to the Interface MTU */ - if (dlpi_co_stream_request->receive_size == 0) { - recv_size = 1024; - } - else { - recv_size = dlpi_co_stream_request->receive_size; - } - - /* tell the other fellow what our receive size became */ - dlpi_co_stream_response->receive_size = recv_size; - - /* just a little prep work for when we may have to behave like the */ - /* sending side... */ - message = (char *)malloc(recv_size * 2); - if (message == NULL) { - printf("malloc(%d) failed!\n", recv_size * 2); - exit(1); - } - - message_ptr = ALIGN_BUFFER(message, dlpi_co_stream_request->recv_alignment, dlpi_co_stream_request->recv_offset); - recv_message.maxlen = recv_size; - recv_message.len = 0; - recv_message.buf = message_ptr; - - if (debug > 1) { - fprintf(where, - "recv_dlpi_co_stream: receive alignment and offset set...\n"); - fflush(where); - } - - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - dlpi_co_stream_response->cpu_rate = 0.0; /* assume no cpu */ - if (dlpi_co_stream_request->measure_cpu) { - dlpi_co_stream_response->measure_cpu = 1; - dlpi_co_stream_response->cpu_rate = - calibrate_local_cpu(dlpi_co_stream_request->cpu_rate); - } - - send_response(); - - /* accept a connection on this file descriptor. at some point, */ - /* dl_accept will "do the right thing" with the last two parms, but */ - /* for now it ignores them, so we will pass zeros. */ - - if(dl_accept(data_descriptor, 0, 0) != 0) { - fprintf(where, - "recv_dlpi_co_stream: error in accept, errno %d\n", - errno); - fflush(where); - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - if (debug) { - fprintf(where,"netserver:recv_dlpi_co_stream: connection accepted\n"); - fflush(where); - } - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(dlpi_co_stream_request->measure_cpu); - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to recv. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - - dirty_count = dlpi_co_stream_request->dirty_count; - clean_count = dlpi_co_stream_request->clean_count; - message_int_ptr = (int *)message_ptr; - for (i = 0; i < dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < clean_count; i++) { - dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - - recv_message.len = recv_size; - while (recv_message.len == recv_size) { - if (getmsg(data_descriptor, - 0, - &recv_message, - &flags) != 0) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - bytes_received += recv_message.len; - receive_calls++; - - if (debug) { - fprintf(where, - "netserver:recv_dlpi_co_stream: getmsg accepted %d bytes\n", - recv_message.len); - fflush(where); - } - - -#ifdef DIRTY - message_int_ptr = (int *)message_ptr; - for (i = 0; i < dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < clean_count; i++) { - dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - - } - - /* The loop now exits due to zero bytes received. */ - /* should perform a disconnect to signal the sender that */ - /* we have received all the data sent. */ - - if (close(data_descriptor) == -1) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - cpu_stop(dlpi_co_stream_request->measure_cpu,&elapsed_time); - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_dlpi_co_stream: got %d bytes\n", - bytes_received); - fprintf(where, - "recv_dlpi_co_stream: got %d recvs\n", - receive_calls); - fflush(where); - } - - dlpi_co_stream_results->bytes_received = bytes_received; - dlpi_co_stream_results->elapsed_time = elapsed_time; - dlpi_co_stream_results->recv_calls = receive_calls; - - if (dlpi_co_stream_request->measure_cpu) { - dlpi_co_stream_results->cpu_util = calc_cpu_util(0.0); - }; - - if (debug > 1) { - fprintf(where, - "recv_dlpi_co_stream: test complete, sending results.\n"); - fflush(where); - } - - send_response(); -} - -/*********************************/ - -int send_dlpi_co_rr(char remote_host[]) -{ - - char *tput_title = "\ - Local /Remote\n\ - Window Size Request Resp. Elapsed Trans.\n\ - Send Recv Size Size Time Rate \n\ - frames frames bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ - %-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ - %-6d %-6d\n"; - - char *cpu_title = "\ - Local /Remote\n\ - Window Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ - Send Recv Size Size Time Rate local remote local remote\n\ - frames frames bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f\n"; - - char *cpu_fmt_1_line_1 = "\ - %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ - %-6d %-6d\n"; - - char *ksink_fmt = "\ - Alignment Offset\n\ - Local Remote Local Remote\n\ - Send Recv Send Recv\n\ - %5d %5d %5d %5d\n"; - - - int timed_out = 0; - float elapsed_time; - int dlsap_len; - char dlsap[BUFSIZ]; - - int flags = 0; - char *send_message_ptr; - char *recv_message_ptr; - char *temp_message_ptr; - struct strbuf send_message; - struct strbuf recv_message; - - int nummessages; - int send_descriptor; - int trans_remaining; - double bytes_xferd; - - int rsp_bytes_left; - - /* we assume that station adresses fit within two ints */ - unsigned int remote_address[1]; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct dlpi_co_rr_request_struct *dlpi_co_rr_request; - struct dlpi_co_rr_response_struct *dlpi_co_rr_response; - struct dlpi_co_rr_results_struct *dlpi_co_rr_result; - - dlpi_co_rr_request = - (struct dlpi_co_rr_request_struct *)netperf_request.content.test_specific_data; - dlpi_co_rr_response = - (struct dlpi_co_rr_response_struct *)netperf_response.content.test_specific_data; - dlpi_co_rr_result = - (struct dlpi_co_rr_results_struct *)netperf_response.content.test_specific_data; - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - if ( print_headers ) { - fprintf(where,"DLPI CO REQUEST/RESPONSE TEST\n"); - if (local_cpu_usage || remote_cpu_usage) - fprintf(where,cpu_title,format_units()); - else - fprintf(where,tput_title,format_units()); - } - - /* initialize a few counters */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - - /* set-up the data buffers with the requested alignment and offset */ - temp_message_ptr = (char *)malloc(req_size+MAXALIGNMENT+MAXOFFSET); - if (temp_message_ptr == NULL) { - printf("malloc(%d) failed!\n", req_size+MAXALIGNMENT+MAXOFFSET); - exit(1); - } - send_message_ptr = (char *)(( (long) temp_message_ptr + - (long) local_send_align - 1) & - ~((long) local_send_align - 1)); - send_message_ptr = send_message_ptr + local_send_offset; - send_message.maxlen = req_size+MAXALIGNMENT+MAXOFFSET; - send_message.len = req_size; - send_message.buf = send_message_ptr; - - temp_message_ptr = (char *)malloc(rsp_size+MAXALIGNMENT+MAXOFFSET); - if (temp_message_ptr == NULL) { - printf("malloc(%d) failed!\n", rsp_size+MAXALIGNMENT+MAXOFFSET); - exit(1); - } - recv_message_ptr = (char *)(( (long) temp_message_ptr + - (long) local_recv_align - 1) & - ~((long) local_recv_align - 1)); - recv_message_ptr = recv_message_ptr + local_recv_offset; - recv_message.maxlen = rsp_size+MAXALIGNMENT+MAXOFFSET; - recv_message.len = 0; - recv_message.buf = send_message_ptr; - - /*set up the data socket */ - - send_descriptor = dl_open(loc_dlpi_device,loc_ppa); - if (send_descriptor < 0){ - perror("netperf: send_dlpi_co_rr: tcp stream data descriptor"); - exit(1); - } - - if (debug) { - fprintf(where,"send_dlpi_co_rr: send_descriptor obtained...\n"); - } - - /* bind the puppy and get the assigned dlsap */ - - dlsap_len = BUFSIZ; - if (dl_bind(send_descriptor, - dlpi_sap, DL_CODLS, dlsap, &dlsap_len) != 0) { - fprintf(where,"send_dlpi_co_rr: bind failure\n"); - fflush(where); - exit(1); - } - - /* Modify the local socket size. The reason we alter the send buffer */ - /* size here rather than when the connection is made is to take care */ - /* of decreases in buffer size. Decreasing the window size after */ - /* connection establishment is a TCP no-no. Also, by setting the */ - /* buffer (window) size before the connection is established, we can */ - /* control the TCP MSS (segment size). The MSS is never more that 1/2 */ - /* the minimum receive buffer size at each half of the connection. */ - /* This is why we are altering the receive buffer size on the sending */ - /* size of a unidirectional transfer. If the user has not requested */ - /* that the socket buffers be altered, we will try to find-out what */ - /* their values are. If we cannot touch the socket buffer in any way, */ - /* we will set the values to -1 to indicate that. */ - -#ifdef DL_HP_SET_LOCAL_WIN_REQ - if (lsw_size > 0) { - if (debug > 1) { - fprintf(where,"netperf: send_dlpi_co_rr: socket send size altered from system default...\n"); - fprintf(where," send: %d\n",lsw_size); - } - } - if (lrw_size > 0) { - if (debug > 1) { - fprintf(where,"netperf: send_dlpi_co_rr: socket recv size altered from system default...\n"); - fprintf(where," recv: %d\n",lrw_size); - } - } - - - /* Now, we will find-out what the size actually became, and report */ - /* that back to the user. If the call fails, we will just report a -1 */ - /* back to the initiator for the recv buffer size. */ - - - if (debug) { - fprintf(where,"netperf: send_dlpi_co_rr: socket sizes determined...\n"); - fprintf(where," send: %d recv: %d\n",lsw_size,lrw_size); - } - -#else /* DL_HP_SET_LOCAL_WIN_REQ */ - - lsw_size = -1; - lrw_size = -1; - -#endif /* DL_HP_SET_LOCAL_WIN_REQ */ - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_DLPI_CO_RR; - dlpi_co_rr_request->recv_win_size = rrw_size; - dlpi_co_rr_request->send_win_size = rsw_size; - dlpi_co_rr_request->recv_alignment = remote_recv_align; - dlpi_co_rr_request->recv_offset = remote_recv_offset; - dlpi_co_rr_request->send_alignment = remote_send_align; - dlpi_co_rr_request->send_offset = remote_send_offset; - dlpi_co_rr_request->request_size = req_size; - dlpi_co_rr_request->response_size = rsp_size; - dlpi_co_rr_request->measure_cpu = remote_cpu_usage; - dlpi_co_rr_request->cpu_rate = remote_cpu_rate; - dlpi_co_rr_request->ppa = rem_ppa; - dlpi_co_rr_request->sap = dlpi_sap; - dlpi_co_rr_request->dev_name_len = strlen(rem_dlpi_device); - strcpy(dlpi_co_rr_request->dlpi_device, - rem_dlpi_device); -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) dlpi_co_rr_request->dlpi_device; - lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = ntohl(*charword); - } - } -#endif /* __alpha */ - - if (test_time) { - dlpi_co_rr_request->test_length = test_time; - } - else { - dlpi_co_rr_request->test_length = test_trans * -1; - } - - if (debug > 1) { - fprintf(where,"netperf: send_dlpi_co_rr: requesting TCP stream test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right */ - /* after the connect returns. The remote will grab the counter right */ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rrw_size = dlpi_co_rr_response->recv_win_size; - rsw_size = dlpi_co_rr_response->send_win_size; - remote_cpu_usage= dlpi_co_rr_response->measure_cpu; - remote_cpu_rate = dlpi_co_rr_response->cpu_rate; - - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /*Connect up to the remote port on the data descriptor */ - - if(dl_connect(send_descriptor, - dlpi_co_rr_response->station_addr, - dlpi_co_rr_response->station_addr_len) != 0) { - fprintf(where,"send_dlpi_co_rr: connect failure\n"); - fflush(where); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - - while ((!times_up) || (trans_remaining > 0)) { - /* send the request */ - if((putmsg(send_descriptor, - 0, - &send_message, - 0)) != 0) { - if (errno == EINTR) { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("send_dlpi_co_rr: putmsg error"); - exit(1); - } - - if (debug) { - fprintf(where,"recv_message.len %d\n",recv_message.len); - fprintf(where,"send_message.len %d\n",send_message.len); - fflush(where); - } - - /* receive the response */ - /* this needs some work with streams buffers if we are going to */ - /* support requests and responses larger than the MTU of the */ - /* network, but this can wait until later */ - rsp_bytes_left = rsp_size; - recv_message.len = rsp_size; - while(rsp_bytes_left > 0) { - if((getmsg(send_descriptor, - 0, - &recv_message, - &flags)) < 0) { - if (errno == EINTR) { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } - perror("send_dlpi_co_rr: data recv error"); - exit(1); - } - rsp_bytes_left -= recv_message.len; - } - - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - fprintf(where, - "Transaction %d completed\n", - nummessages); - fflush(where); - } - } - - /* At this point we used to call shutdown onthe data socket to be */ - /* sure all the data was delivered, but this was not germane in a */ - /* request/response test, and it was causing the tests to "hang" when */ - /* they were being controlled by time. So, I have replaced this */ - /* shutdown call with a call to close that can be found later in the */ - /* procedure. */ - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ - /* how long did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a TCP stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) We use */ - /* Kbytes/s as the units of thruput for a TCP stream test, where K = */ - /* 1024. A future enhancement *might* be to choose from a couple of */ - /* unit selections. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = calc_thruput(bytes_xferd); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where,"Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where,"Remote CPU usage numbers based on process information only!\n"); - fflush(where); - } - remote_cpu_utilization = dlpi_co_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - dlpi_co_rr_result->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lsw_size, /* local sendbuf size */ - lrw_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - nummessages/elapsed_time, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rsw_size, - rrw_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - nummessages/elapsed_time); - break; - case 1: - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lsw_size, - lrw_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - nummessages/elapsed_time); - fprintf(where, - tput_fmt_1_line_2, - rsw_size, /* remote recvbuf size */ - rrw_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt); - } - /* The test is over. Kill the data descriptor */ - - if (close(send_descriptor) == -1) { - perror("send_dlpi_co_rr: cannot shutdown tcp stream descriptor"); - } - -} - -void - send_dlpi_cl_stream(char remote_host[]) -{ - /************************************************************************/ - /* */ - /* UDP Unidirectional Send Test */ - /* */ - /************************************************************************/ - char *tput_title = - "Window Message Elapsed Messages \n\ -Size Size Time Okay Errors Throughput\n\ -frames bytes secs # # %s/sec\n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = - "%5d %5d %-7.2f %7d %6d %7.2f\n\ -%5d %-7.2f %7d %7.2f\n\n"; - - - char *cpu_title = - "Window Message Elapsed Messages CPU Service\n\ -Size Size Time Okay Errors Throughput Util Demand\n\ -frames bytes secs # # %s/sec %% us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.2f\n"; - - char *cpu_fmt_1 = - "%5d %5d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\ -%5d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n"; - - int messages_recvd; - float elapsed_time, - local_cpu_utilization, - remote_cpu_utilization; - - float local_service_demand, remote_service_demand; - double local_thruput, remote_thruput; - double bytes_sent; - double bytes_recvd; - - - int *message_int_ptr; - char *message_ptr; - char *message; - char sctl_data[BUFSIZ]; - struct strbuf send_message; - struct strbuf sctl_message; - dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data; - - char dlsap[BUFSIZ]; - int dlsap_len; - int message_offset; - int message_max_offset; - int failed_sends; - int failed_cows; - int messages_sent; - int data_descriptor; - - -#ifdef WANT_INTERVALS - int interval_count; -#endif /* WANT_INTERVALS */ -#ifdef DIRTY - int i; -#endif /* DIRTY */ - - struct dlpi_cl_stream_request_struct *dlpi_cl_stream_request; - struct dlpi_cl_stream_response_struct *dlpi_cl_stream_response; - struct dlpi_cl_stream_results_struct *dlpi_cl_stream_results; - - dlpi_cl_stream_request = (struct dlpi_cl_stream_request_struct *)netperf_request.content.test_specific_data; - dlpi_cl_stream_response = (struct dlpi_cl_stream_response_struct *)netperf_response.content.test_specific_data; - dlpi_cl_stream_results = (struct dlpi_cl_stream_results_struct *)netperf_response.content.test_specific_data; - - if ( print_headers ) { - printf("DLPI CL UNIDIRECTIONAL SEND TEST\n"); - if (local_cpu_usage || remote_cpu_usage) - printf(cpu_title,format_units()); - else - printf(tput_title,format_units()); - } - - failed_sends = 0; - messages_sent = 0; - times_up = 0; - - /*set up the data descriptor */ - - data_descriptor = dl_open(loc_dlpi_device,loc_ppa); - if (data_descriptor < 0){ - perror("send_dlpi_cl_stream: data descriptor"); - exit(1); - } - - /* bind the puppy and get the assigned dlsap */ - dlsap_len = BUFSIZ; - if (dl_bind(data_descriptor, - dlpi_sap, DL_CLDLS, dlsap, &dlsap_len) != 0) { - fprintf(where,"send_dlpi_cl_stream: bind failure\n"); - fflush(where); - exit(1); - } - - /* Modify the local socket size (SNDBUF size) */ - -#ifdef DL_HP_SET_LOCAL_WIN_REQ - if (lsw_size > 0) { - if (debug > 1) { - fprintf(where,"netperf: send_dlpi_cl_stream: descriptor send size altered from system default...\n"); - fprintf(where," send: %d\n",lsw_size); - } - } - if (lrw_size > 0) { - if (debug > 1) { - fprintf(where,"netperf: send_dlpi_cl_stream: descriptor recv size altered from system default...\n"); - fprintf(where," recv: %d\n",lrw_size); - } - } - - - /* Now, we will find-out what the size actually became, and report */ - /* that back to the user. If the call fails, we will just report a -1 */ - /* back to the initiator for the recv buffer size. */ - -#else /* DL_HP_SET_LOCAL_WIN_REQ */ - - lsw_size = -1; - lrw_size = -1; - -#endif /* DL_HP_SET_LOCAL_WIN_REQ */ - - /* now, we want to see if we need to set the send_size */ - if (send_size == 0) { - send_size = 1024; - } - - - /* set-up the data buffer with the requested alignment and offset, */ - /* most of the numbers here are just a hack to pick something nice */ - /* and big in an attempt to never try to send a buffer a second time */ - /* before it leaves the node...unless the user set the width */ - /* explicitly. */ - if (send_width == 0) send_width = 32; - message = (char *)malloc(send_size * (send_width + 1) + local_send_align + local_send_offset); - if (message == NULL) { - printf("malloc(%d) failed!\n", send_size * (send_width + 1) + local_send_align + local_send_offset); - exit(1); - } - message_ptr = (char *)(( (long) message + - (long) local_send_align - 1) & - ~((long) local_send_align - 1)); - message_ptr = message_ptr + local_send_offset; - message = message_ptr; - send_message.maxlen = send_size; - send_message.len = send_size; - send_message.buf = message; - - sctl_message.maxlen = BUFSIZ; - sctl_message.len = 0; - sctl_message.buf = sctl_data; - - /* if the user supplied a cpu rate, this call will complete rather */ - /* quickly, otherwise, the cpu rate will be retured to us for */ - /* possible display. The Library will keep it's own copy of this data */ - /* for use elsewhere. We will only display it. (Does that make it */ - /* "opaque" to us?) */ - - if (local_cpu_usage) - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - - /* Tell the remote end to set up the data connection. The server */ - /* sends back the port number and alters the socket parameters there. */ - /* Of course this is a datagram service so no connection is actually */ - /* set up, the server just sets up the socket and binds it. */ - - netperf_request.content.request_type = DO_DLPI_CL_STREAM; - dlpi_cl_stream_request->recv_win_size = rrw_size; - dlpi_cl_stream_request->message_size = send_size; - dlpi_cl_stream_request->recv_alignment = remote_recv_align; - dlpi_cl_stream_request->recv_offset = remote_recv_offset; - dlpi_cl_stream_request->measure_cpu = remote_cpu_usage; - dlpi_cl_stream_request->cpu_rate = remote_cpu_rate; - dlpi_cl_stream_request->ppa = rem_ppa; - dlpi_cl_stream_request->sap = dlpi_sap; - dlpi_cl_stream_request->dev_name_len = strlen(rem_dlpi_device); - strcpy(dlpi_cl_stream_request->dlpi_device, - rem_dlpi_device); - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) dlpi_cl_stream_request->dlpi_device; - lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = ntohl(*charword); - } - } -#endif /* __alpha */ - - if (test_time) { - dlpi_cl_stream_request->test_length = test_time; - } - else { - dlpi_cl_stream_request->test_length = test_bytes * -1; - } - - - send_request(); - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"send_dlpi_cl_stream: remote data connection done.\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("send_dlpi_cl_stream: error on remote"); - exit(1); - } - - /* place some of the remote's addressing information into the send */ - /* structure so our sends can be sent to the correct place. Also get */ - /* some of the returned socket buffer information for user display. */ - - /* set-up the destination addressing control info */ - data_req->dl_primitive = DL_UNITDATA_REQ; - bcopy((char *)(dlpi_cl_stream_response->station_addr), - ((char *)data_req + sizeof(dl_unitdata_req_t)), - dlpi_cl_stream_response->station_addr_len); - data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t); - data_req->dl_dest_addr_length = dlpi_cl_stream_response->station_addr_len; - /* there is a dl_priority structure too, but I am ignoring it for */ - /* the time being. */ - /* however... it is best to put some value in there lest some code - get grumpy about it - fix from Nicolas Thomas */ - data_req->dl_priority.dl_min = DL_QOS_DONT_CARE; - data_req->dl_priority.dl_max = DL_QOS_DONT_CARE; - - sctl_message.len = sizeof(dl_unitdata_req_t) + - data_req->dl_dest_addr_length; - - rrw_size = dlpi_cl_stream_response->recv_win_size; - rsw_size = dlpi_cl_stream_response->send_win_size; - remote_cpu_rate = dlpi_cl_stream_response->cpu_rate; - - - /* set up the timer to call us after test_time */ - start_timer(test_time); - - /* Get the start count for the idle counter and the start time */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - interval_count = interval_burst; -#endif /* WANT_INTERVALS */ - - /* Send datagrams like there was no tomorrow */ - while (!times_up) { -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - message_int_ptr = (int *)message_ptr; - for (i = 0; i < loc_dirty_count; i++) { - *message_int_ptr = 4; - message_int_ptr++; - } - for (i = 0; i < loc_clean_count; i++) { - loc_dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - if (putmsg(data_descriptor, - &sctl_message, - &send_message, - 0) != 0) { - if (errno == EINTR) { - break; - } - if (errno == ENOBUFS) { - /* we might not ever hit this with STREAMS, it would probably */ - /* be better to do a getinfo request at the end of the test to */ - /* get all sorts of gory statistics. in the meantime, we will */ - /* keep this code in place. */ - failed_sends++; - continue; - } - perror("send_dlpi_cl_stream: data send error"); - if (debug) { - fprintf(where,"messages_sent %u\n",messages_sent); - fflush(where); - } - exit(1); - } - messages_sent++; - - /* now we want to move our pointer to the next position in the */ - /* data buffer...since there was a successful send */ - - -#ifdef WANT_INTERVALS - /* in this case, the interval count is the count-down couter */ - /* to decide to sleep for a little bit */ - if ((interval_burst) && (--interval_count == 0)) { - /* call the sleep routine for some milliseconds, if our */ - /* timer popped while we were in there, we want to */ - /* break out of the loop. */ - if (msec_sleep(interval_wate)) { - break; - } - interval_count = interval_burst; - } - -#endif /* WANT_INTERVALS */ - - } - - /* This is a timed test, so the remote will be returning to us after */ - /* a time. We should not need to send any "strange" messages to tell */ - /* the remote that the test is completed, unless we decide to add a */ - /* number of messages to the test. */ - - /* the test is over, so get stats and stuff */ - cpu_stop(local_cpu_usage, - &elapsed_time); - - /* Get the statistics from the remote end */ - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"send_dlpi_cl_stream: remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("send_dlpi_cl_stream: error on remote"); - exit(1); - } - - bytes_sent = send_size * messages_sent; - local_thruput = calc_thruput(bytes_sent); - - messages_recvd = dlpi_cl_stream_results->messages_recvd; - bytes_recvd = send_size * messages_recvd; - - /* we asume that the remote ran for as long as we did */ - - remote_thruput = calc_thruput(bytes_recvd); - - /* print the results for this descriptor and message size */ - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) We pass zeros for the local */ - /* cpu utilization and elapsed time to tell the routine to use */ - /* the libraries own values for those. */ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where,"Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - /* The local calculations could use variables being kept by */ - /* the local netlib routines. The remote calcuations need to */ - /* have a few things passed to them. */ - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where,"REMOTE CPU usage numbers based on process information only!\n"); - fflush(where); - } - - remote_cpu_utilization = dlpi_cl_stream_results->cpu_util; - remote_service_demand = calc_service_demand(bytes_recvd, - 0.0, - remote_cpu_utilization, - dlpi_cl_stream_results->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - fprintf(where, - cpu_fmt_1, /* the format string */ - lsw_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - messages_sent, - failed_sends, - local_thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - local_service_demand, /* local service demand */ - rrw_size, - elapsed_time, - messages_recvd, - remote_thruput, - remote_cpu_utilization, /* remote cpu */ - remote_service_demand); /* remote service demand */ - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - local_thruput); - break; - case 1: - fprintf(where, - tput_fmt_1, /* the format string */ - lsw_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - messages_sent, - failed_sends, - local_thruput, - rrw_size, /* remote recvbuf size */ - elapsed_time, - messages_recvd, - remote_thruput - ); - break; - } - } -} - -int - recv_dlpi_cl_stream() -{ - - char *message; - int data_descriptor; - int len; - char *message_ptr; - char rctl_data[BUFSIZ]; - struct strbuf recv_message; - struct strbuf rctl_message; - int flags = 0; - /* these are to make reading some of the DLPI control messages easier */ - dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data; - dl_uderror_ind_t *uder_ind = (dl_uderror_ind_t *)rctl_data; - - int bytes_received = 0; - float elapsed_time; - - int message_size; - int messages_recvd = 0; - int measure_cpu; - - struct dlpi_cl_stream_request_struct *dlpi_cl_stream_request; - struct dlpi_cl_stream_response_struct *dlpi_cl_stream_response; - struct dlpi_cl_stream_results_struct *dlpi_cl_stream_results; - - dlpi_cl_stream_request = (struct dlpi_cl_stream_request_struct *)netperf_request.content.test_specific_data; - dlpi_cl_stream_response = (struct dlpi_cl_stream_response_struct *)netperf_response.content.test_specific_data; - dlpi_cl_stream_results = (struct dlpi_cl_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_dlpi_cl_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen descriptor with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug > 1) { - fprintf(where,"recv_dlpi_cl_stream: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = DLPI_CL_STREAM_RESPONSE; - - if (debug > 2) { - fprintf(where,"recv_dlpi_cl_stream: the response type is set...\n"); - fflush(where); - } - - /* set-up the data buffer with the requested alignment and offset */ - message = (char *)malloc(DATABUFFERLEN); - if (message == NULL) { - printf("malloc(%d) failed!\n", DATABUFFERLEN); - exit(1); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug > 1) { - fprintf(where,"recv_dlpi_cl_stream: requested alignment of %d\n", - dlpi_cl_stream_request->recv_alignment); - fflush(where); - } - - message_ptr = ALIGN_BUFFER(message, dlpi_cl_stream_request->recv_alignment, dlpi_cl_stream_request->recv_offset); - - if (dlpi_cl_stream_request->message_size > 0) { - recv_message.maxlen = dlpi_cl_stream_request->message_size; - } - else { - recv_message.maxlen = 4096; - } - recv_message.len = 0; - recv_message.buf = message_ptr; - - rctl_message.maxlen = BUFSIZ; - rctl_message.len = 0; - rctl_message.buf = rctl_data; - - if (debug > 1) { - fprintf(where, - "recv_dlpi_cl_stream: receive alignment and offset set...\n"); - fflush(where); - } - - if (debug > 1) { - fprintf(where,"recv_dlpi_cl_stream: grabbing a descriptor...\n"); - fflush(where); - } - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) dlpi_cl_stream_request->dlpi_device; - lastword = initword + ((dlpi_cl_stream_request->dev_name_len + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = htonl(*charword); - } - } -#endif /* __alpha */ - - data_descriptor = dl_open(dlpi_cl_stream_request->dlpi_device, - dlpi_cl_stream_request->ppa); - if (data_descriptor < 0) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* The initiator may have wished-us to modify the window */ - /* sizes. We should give it a shot. If he didn't ask us to change the */ - /* sizes, we should let him know what sizes were in use at this end. */ - /* If none of this code is compiled-in, then we will tell the */ - /* initiator that we were unable to play with the sizes by */ - /* setting the size in the response to -1. */ - -#ifdef DL_HP_SET_LOCAL_WIN_REQ - - if (dlpi_cl_stream_request->recv_win_size) { - dlpi_cl_stream_response->recv_win_size = -1; - } - -#else /* the system won't let us play with the buffers */ - - dlpi_cl_stream_response->recv_win_size = -1; - -#endif /* DL_HP_SET_LOCAL_WIN_REQ */ - - dlpi_cl_stream_response->test_length = dlpi_cl_stream_request->test_length; - - /* bind the sap and retrieve the dlsap assigned by the system */ - dlpi_cl_stream_response->station_addr_len = 14; /* arbitrary */ - if (dl_bind(data_descriptor, - dlpi_cl_stream_request->sap, - DL_CLDLS, - (char *)dlpi_cl_stream_response->station_addr, - &dlpi_cl_stream_response->station_addr_len) != 0) { - fprintf(where,"send_dlpi_cl_stream: bind failure\n"); - fflush(where); - exit(1); - } - - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - dlpi_cl_stream_response->cpu_rate = 0.0; /* assume no cpu */ - if (dlpi_cl_stream_request->measure_cpu) { - /* We will pass the rate into the calibration routine. If the */ - /* user did not specify one, it will be 0.0, and we will do a */ - /* "real" calibration. Otherwise, all it will really do is */ - /* store it away... */ - dlpi_cl_stream_response->measure_cpu = 1; - dlpi_cl_stream_response->cpu_rate = calibrate_local_cpu(dlpi_cl_stream_request->cpu_rate); - } - - message_size = dlpi_cl_stream_request->message_size; - test_time = dlpi_cl_stream_request->test_length; - - send_response(); - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(dlpi_cl_stream_request->measure_cpu); - - /* The loop will exit when the timer pops, or if we happen to recv a */ - /* message of less than send_size bytes... */ - - times_up = 0; - start_timer(test_time + PAD_TIME); - - if (debug) { - fprintf(where,"recv_dlpi_cl_stream: about to enter inner sanctum.\n"); - fflush(where); - } - - while (!times_up) { - if((getmsg(data_descriptor, - &rctl_message, - &recv_message, - &flags) != 0) || - (data_ind->dl_primitive != DL_UNITDATA_IND)) { - if (errno == EINTR) { - /* Again, we have likely hit test-end time */ - break; - } - fprintf(where, - "dlpi_recv_cl_stream: getmsg failure: errno %d primitive 0x%x\n", - errno, - data_ind->dl_primitive); - fflush(where); - netperf_response.content.serv_errno = 996; - send_response(); - exit(1); - } - messages_recvd++; - } - - if (debug) { - fprintf(where,"recv_dlpi_cl_stream: got %d messages.\n",messages_recvd); - fflush(where); - } - - - /* The loop now exits due timer or < send_size bytes received. */ - - cpu_stop(dlpi_cl_stream_request->measure_cpu,&elapsed_time); - - if (times_up) { - /* we ended on a timer, subtract the PAD_TIME */ - elapsed_time -= (float)PAD_TIME; - } - else { - stop_timer(); - } - - if (debug) { - fprintf(where,"recv_dlpi_cl_stream: test ended in %f seconds.\n",elapsed_time); - fflush(where); - } - - - /* We will count the "off" message */ - bytes_received = (messages_recvd * message_size) + len; - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_dlpi_cl_stream: got %d bytes\n", - bytes_received); - fflush(where); - } - - netperf_response.content.response_type = DLPI_CL_STREAM_RESULTS; - dlpi_cl_stream_results->bytes_received = bytes_received; - dlpi_cl_stream_results->messages_recvd = messages_recvd; - dlpi_cl_stream_results->elapsed_time = elapsed_time; - if (dlpi_cl_stream_request->measure_cpu) { - dlpi_cl_stream_results->cpu_util = calc_cpu_util(elapsed_time); - } - else { - dlpi_cl_stream_results->cpu_util = -1.0; - } - - if (debug > 1) { - fprintf(where, - "recv_dlpi_cl_stream: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - -} - -int send_dlpi_cl_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Window Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -frames frames bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Window Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -frames frames bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - float elapsed_time; - - int dlsap_len; - int flags = 0; - char *send_message_ptr; - char *recv_message_ptr; - char *temp_message_ptr; - char sctl_data[BUFSIZ]; - char rctl_data[BUFSIZ]; - char dlsap[BUFSIZ]; - struct strbuf send_message; - struct strbuf recv_message; - struct strbuf sctl_message; - struct strbuf rctl_message; - - /* these are to make reading some of the DLPI control messages easier */ - dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data; - dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data; - dl_uderror_ind_t *uder_ind = (dl_uderror_ind_t *)rctl_data; - - int nummessages; - int send_descriptor; - int trans_remaining; - int bytes_xferd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - -#ifdef WANT_INTERVALS - /* timing stuff */ -#define MAX_KEPT_TIMES 1024 - int time_index = 0; - int unused_buckets; - int kept_times[MAX_KEPT_TIMES]; - int sleep_usecs; - unsigned int total_times=0; - struct timezone dummy_zone; - struct timeval send_time; - struct timeval recv_time; - struct timeval sleep_timeval; -#endif /* WANT_INTERVALS */ - - struct dlpi_cl_rr_request_struct *dlpi_cl_rr_request; - struct dlpi_cl_rr_response_struct *dlpi_cl_rr_response; - struct dlpi_cl_rr_results_struct *dlpi_cl_rr_result; - - dlpi_cl_rr_request = - (struct dlpi_cl_rr_request_struct *)netperf_request.content.test_specific_data; - dlpi_cl_rr_response = - (struct dlpi_cl_rr_response_struct *)netperf_response.content.test_specific_data; - dlpi_cl_rr_result = - (struct dlpi_cl_rr_results_struct *)netperf_response.content.test_specific_data; - - /* we want to zero out the times, so we can detect unused entries. */ -#ifdef WANT_INTERVALS - time_index = 0; - while (time_index < MAX_KEPT_TIMES) { - kept_times[time_index] = 0; - time_index += 1; - } - time_index = 0; -#endif /* WANT_INTERVALS */ - - if (print_headers) { - fprintf(where,"DLPI CL REQUEST/RESPONSE TEST\n"); - if (local_cpu_usage || remote_cpu_usage) - fprintf(where,cpu_title,format_units()); - else - fprintf(where,tput_title,format_units()); - } - - /* initialize a few counters */ - - nummessages = 0; - bytes_xferd = 0; - times_up = 0; - - /* set-up the data buffer with the requested alignment and offset */ - temp_message_ptr = (char *)malloc(req_size+MAXALIGNMENT+MAXOFFSET); - if (temp_message_ptr == NULL) { - printf("malloc(%d) failed!\n", req_size+MAXALIGNMENT+MAXOFFSET); - exit(1); - } - send_message_ptr = (char *)(( (long)temp_message_ptr + - (long) local_send_align - 1) & - ~((long) local_send_align - 1)); - send_message_ptr = send_message_ptr + local_send_offset; - send_message.maxlen = req_size; - send_message.len = req_size; - send_message.buf = send_message_ptr; - - temp_message_ptr = (char *)malloc(rsp_size+MAXALIGNMENT+MAXOFFSET); - if (temp_message_ptr == NULL) { - printf("malloc(%d) failed!\n", rsp_size+MAXALIGNMENT+MAXOFFSET); - exit(1); - } - recv_message_ptr = (char *)(( (long)temp_message_ptr + - (long) local_recv_align - 1) & - ~((long) local_recv_align - 1)); - recv_message_ptr = recv_message_ptr + local_recv_offset; - recv_message.maxlen = rsp_size; - recv_message.len = 0; - recv_message.buf = recv_message_ptr; - - sctl_message.maxlen = BUFSIZ; - sctl_message.len = 0; - sctl_message.buf = sctl_data; - - rctl_message.maxlen = BUFSIZ; - rctl_message.len = 0; - rctl_message.buf = rctl_data; - - /* lets get ourselves a file descriptor */ - - send_descriptor = dl_open(loc_dlpi_device,loc_ppa); - if (send_descriptor < 0){ - perror("netperf: send_dlpi_cl_rr: dlpi cl rr send descriptor"); - exit(1); - } - - if (debug) { - fprintf(where,"send_dlpi_cl_rr: send_descriptor obtained...\n"); - } - - /* bind the sap to the descriptor and get the dlsap */ - dlsap_len = BUFSIZ; - if (dl_bind(send_descriptor, - dlpi_sap, - DL_CLDLS, - dlsap, - &dlsap_len) != 0) { - fprintf(where,"send_dlpi_cl_rr: bind failure\n"); - fflush(where); - exit(1); - } - - /* Modify the local socket size. If the user has not requested that */ - /* the socket buffers be altered, we will try to find-out what their */ - /* values are. If we cannot touch the socket buffer in any way, we */ - /* will set the values to -1 to indicate that. The receive socket */ - /* must have enough space to hold addressing information so += a */ - /* sizeof struct sockaddr_in to it. */ - - /* this is actually nothing code, and should be replaced with the */ - /* alalagous calls in the STREAM test where the window size is set */ - /* with the HP DLPI Extension. raj 8/94 */ -#ifdef SO_SNDBUF - if (lsw_size > 0) { - if (debug > 1) { - fprintf(where,"netperf: send_dlpi_cl_rr: local window size altered from system default...\n"); - fprintf(where," window: %d\n",lsw_size); - } - } - if (lrw_size > 0) { - if (debug > 1) { - fprintf(where,"netperf: send_dlpi_cl_rr: remote window size altered from system default...\n"); - fprintf(where," remote: %d\n",lrw_size); - } - } - - - /* Now, we will find-out what the size actually became, and report */ - /* that back to the user. If the call fails, we will just report a -1 */ - /* back to the initiator for the recv buffer size. */ - - if (debug) { - fprintf(where,"netperf: send_dlpi_cl_rr: socket sizes determined...\n"); - fprintf(where," send: %d recv: %d\n",lsw_size,lrw_size); - } - -#else /* SO_SNDBUF */ - - lsw_size = -1; - lrw_size = -1; - -#endif /* SO_SNDBUF */ - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. If */ - /* there is no idle counter in the kernel idle loop, the */ - /* local_cpu_rate will be set to -1. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_DLPI_CL_RR; - dlpi_cl_rr_request->recv_win_size = rrw_size; - dlpi_cl_rr_request->send_win_size = rsw_size; - dlpi_cl_rr_request->recv_alignment = remote_recv_align; - dlpi_cl_rr_request->recv_offset = remote_recv_offset; - dlpi_cl_rr_request->send_alignment = remote_send_align; - dlpi_cl_rr_request->send_offset = remote_send_offset; - dlpi_cl_rr_request->request_size = req_size; - dlpi_cl_rr_request->response_size = rsp_size; - dlpi_cl_rr_request->measure_cpu = remote_cpu_usage; - dlpi_cl_rr_request->cpu_rate = remote_cpu_rate; - dlpi_cl_rr_request->ppa = rem_ppa; - dlpi_cl_rr_request->sap = dlpi_sap; - dlpi_cl_rr_request->dev_name_len = strlen(rem_dlpi_device); - strcpy(dlpi_cl_rr_request->dlpi_device, - rem_dlpi_device); - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) dlpi_cl_rr_request->dlpi_device; - lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = ntohl(*charword); - } - } -#endif /* __alpha */ - - if (test_time) { - dlpi_cl_rr_request->test_length = test_time; - } - else { - dlpi_cl_rr_request->test_length = test_trans * -1; - } - - if (debug > 1) { - fprintf(where,"netperf: send_dlpi_cl_rr: requesting DLPI CL request/response test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right */ - /* after the connect returns. The remote will grab the counter right */ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rrw_size = dlpi_cl_rr_response->recv_win_size; - rsw_size = dlpi_cl_rr_response->send_win_size; - remote_cpu_usage= dlpi_cl_rr_response->measure_cpu; - remote_cpu_rate = dlpi_cl_rr_response->cpu_rate; - - /* set-up the destination addressing control info */ - data_req->dl_primitive = DL_UNITDATA_REQ; - bcopy((char *)(dlpi_cl_rr_response->station_addr), - ((char *)data_req + sizeof(dl_unitdata_req_t)), - dlpi_cl_rr_response->station_addr_len); - data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t); - data_req->dl_dest_addr_length = dlpi_cl_rr_response->station_addr_len; - /* there is a dl_priority structure too, but I am ignoring it for */ - /* the time being. */ - sctl_message.len = sizeof(dl_unitdata_req_t) + - data_req->dl_dest_addr_length; - /* famous last words - some DLPI providers get unhappy if the - priority stuff is not initialized. fix from Nicolas Thomas. */ - data_req->dl_priority.dl_min = DL_QOS_DONT_CARE; - data_req->dl_priority.dl_max = DL_QOS_DONT_CARE; - - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - while ((!times_up) || (trans_remaining > 0)) { - /* send the request */ -#ifdef WANT_INTERVALS - gettimeofday(&send_time,&dummy_zone); -#endif /* WANT_INTERVALS */ - if(putmsg(send_descriptor, - &sctl_message, - &send_message, - 0) != 0) { - if (errno == EINTR) { - /* We likely hit */ - /* test-end time. */ - break; - } - /* there is more we could do here, but it can wait */ - perror("send_dlpi_cl_rr: data send error"); - exit(1); - } - - /* receive the response. at some point, we will need to handle */ - /* sending responses which are greater than the datalink MTU. we */ - /* may also want to add some DLPI error checking, but for now we */ - /* will ignore that and just let errors stop the test with little */ - /* indication of what might actually be wrong. */ - - if((getmsg(send_descriptor, - &rctl_message, - &recv_message, - &flags) != 0) || - (data_ind->dl_primitive != DL_UNITDATA_IND)) { - if (errno == EINTR) { - /* Again, we have likely hit test-end time */ - break; - } - fprintf(where, - "send_dlpi_cl_rr: recv error: errno %d primitive 0x%x\n", - errno, - data_ind->dl_primitive); - fflush(where); - exit(1); - } -#ifdef WANT_INTERVALS - gettimeofday(&recv_time,&dummy_zone); - - /* now we do some arithmatic on the two timevals */ - if (recv_time.tv_usec < send_time.tv_usec) { - /* we wrapped around a second */ - recv_time.tv_usec += 1000000; - recv_time.tv_sec -= 1; - } - - /* and store it away */ - kept_times[time_index] = (recv_time.tv_sec - send_time.tv_sec) * 1000000; - kept_times[time_index] += (recv_time.tv_usec - send_time.tv_usec); - - /* at this point, we may wish to sleep for some period of */ - /* time, so we see how long that last transaction just took, */ - /* and sleep for the difference of that and the interval. We */ - /* will not sleep if the time would be less than a */ - /* millisecond. */ - if (interval_usecs > 0) { - sleep_usecs = interval_usecs - kept_times[time_index]; - if (sleep_usecs > 1000) { - /* we sleep */ - sleep_timeval.tv_sec = sleep_usecs / 1000000; - sleep_timeval.tv_usec = sleep_usecs % 1000000; - select(0, - 0, - 0, - 0, - &sleep_timeval); - } - } - - /* now up the time index */ - time_index = (time_index +1)%MAX_KEPT_TIMES; -#endif /* WANT_INTERVALS */ - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - fprintf(where,"Transaction %d completed\n",nummessages); - fflush(where); - } - - } - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ - /* how long did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a UDP stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) We use */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = calc_thruput(bytes_xferd); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where,"Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where,"Remote CPU usage numbers based on process information only!\n"); - fflush(where); - } - remote_cpu_utilization = dlpi_cl_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - dlpi_cl_rr_result->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - case 2: - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lsw_size, /* local sendbuf size */ - lrw_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - nummessages/elapsed_time, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rsw_size, - rrw_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - nummessages/elapsed_time); - break; - case 1: - case 2: - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lsw_size, - lrw_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - nummessages/elapsed_time); - fprintf(where, - tput_fmt_1_line_2, - rsw_size, /* remote recvbuf size */ - rrw_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* UDP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - -#ifdef WANT_INTERVALS - kept_times[MAX_KEPT_TIMES] = 0; - time_index = 0; - while (time_index < MAX_KEPT_TIMES) { - if (kept_times[time_index] > 0) { - total_times += kept_times[time_index]; - } - else - unused_buckets++; - time_index += 1; - } - total_times /= (MAX_KEPT_TIMES-unused_buckets); - fprintf(where, - "Average response time %d usecs\n", - total_times); -#endif - } -} - -int - recv_dlpi_cl_rr() -{ - - char *message; - int data_descriptor; - int flags = 0; - int measure_cpu; - - char *recv_message_ptr; - char *send_message_ptr; - char sctl_data[BUFSIZ]; - char rctl_data[BUFSIZ]; - char dlsap[BUFSIZ]; - struct strbuf send_message; - struct strbuf recv_message; - struct strbuf sctl_message; - struct strbuf rctl_message; - - /* these are to make reading some of the DLPI control messages easier */ - dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data; - dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data; - dl_uderror_ind_t *uder_ind = (dl_uderror_ind_t *)rctl_data; - - int trans_received; - int trans_remaining; - float elapsed_time; - - struct dlpi_cl_rr_request_struct *dlpi_cl_rr_request; - struct dlpi_cl_rr_response_struct *dlpi_cl_rr_response; - struct dlpi_cl_rr_results_struct *dlpi_cl_rr_results; - - dlpi_cl_rr_request = - (struct dlpi_cl_rr_request_struct *)netperf_request.content.test_specific_data; - dlpi_cl_rr_response = - (struct dlpi_cl_rr_response_struct *)netperf_response.content.test_specific_data; - dlpi_cl_rr_results = - (struct dlpi_cl_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_dlpi_cl_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen descriptor with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the descriptor sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_dlpi_cl_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = DLPI_CL_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_dlpi_cl_rr: the response type is set...\n"); - fflush(where); - } - - /* set-up the data buffer with the requested alignment and offset */ - message = (char *)malloc(DATABUFFERLEN); - if (message == NULL) { - printf("malloc(%d) failed!\n", DATABUFFERLEN); - exit(1); - } - - /* We now alter the message_ptr variables to be at the desired */ - /* alignments with the desired offsets. */ - - if (debug) { - fprintf(where, - "recv_dlpi_cl_rr: requested recv alignment of %d offset %d\n", - dlpi_cl_rr_request->recv_alignment, - dlpi_cl_rr_request->recv_offset); - fprintf(where, - "recv_dlpi_cl_rr: requested send alignment of %d offset %d\n", - dlpi_cl_rr_request->send_alignment, - dlpi_cl_rr_request->send_offset); - fflush(where); - } - - recv_message_ptr = ALIGN_BUFFER(message, dlpi_cl_rr_request->recv_alignment, dlpi_cl_rr_request->recv_offset); - recv_message.maxlen = dlpi_cl_rr_request->request_size; - recv_message.len = 0; - recv_message.buf = recv_message_ptr; - - send_message_ptr = ALIGN_BUFFER(message, dlpi_cl_rr_request->send_alignment, dlpi_cl_rr_request->send_offset); - send_message.maxlen = dlpi_cl_rr_request->response_size; - send_message.len = dlpi_cl_rr_request->response_size; - send_message.buf = send_message_ptr; - - sctl_message.maxlen = BUFSIZ; - sctl_message.len = 0; - sctl_message.buf = sctl_data; - - rctl_message.maxlen = BUFSIZ; - rctl_message.len = 0; - rctl_message.buf = rctl_data; - - if (debug) { - fprintf(where,"recv_dlpi_cl_rr: receive alignment and offset set...\n"); - fprintf(where,"recv_dlpi_cl_rr: grabbing a socket...\n"); - fflush(where); - } - - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) dlpi_cl_rr_request->dlpi_device; - lastword = initword + ((dlpi_cl_rr_request->dev_name_len + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = htonl(*charword); - } - } -#endif /* __alpha */ - - data_descriptor = dl_open(dlpi_cl_rr_request->dlpi_device, - dlpi_cl_rr_request->ppa); - if (data_descriptor < 0) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - - /* The initiator may have wished-us to modify the window */ - /* sizes. We should give it a shot. If he didn't ask us to change the */ - /* sizes, we should let him know what sizes were in use at this end. */ - /* If none of this code is compiled-in, then we will tell the */ - /* initiator that we were unable to play with the sizes by */ - /* setting the size in the response to -1. */ - -#ifdef DL_HP_SET_LOCAL_WIN_REQ - - if (dlpi_cl_rr_request->recv_win_size) { - } - - if (dlpi_cl_rr_request->send_win_size) { - } - - /* Now, we will find-out what the sizes actually became, and report */ - /* them back to the user. If the calls fail, we will just report a -1 */ - /* back to the initiator for the buffer size. */ - -#else /* the system won't let us play with the buffers */ - - dlpi_cl_rr_response->recv_win_size = -1; - dlpi_cl_rr_response->send_win_size = -1; - -#endif /* DL_HP_SET_LOCAL_WIN_REQ */ - - /* bind the sap and retrieve the dlsap assigned by the system */ - dlpi_cl_rr_response->station_addr_len = 14; /* arbitrary */ - if (dl_bind(data_descriptor, - dlpi_cl_rr_request->sap, - DL_CLDLS, - (char *)dlpi_cl_rr_response->station_addr, - &dlpi_cl_rr_response->station_addr_len) != 0) { - fprintf(where,"send_dlpi_cl_rr: bind failure\n"); - fflush(where); - exit(1); - } - - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - dlpi_cl_rr_response->cpu_rate = 0.0; /* assume no cpu */ - if (dlpi_cl_rr_request->measure_cpu) { - dlpi_cl_rr_response->measure_cpu = 1; - dlpi_cl_rr_response->cpu_rate = calibrate_local_cpu(dlpi_cl_rr_request->cpu_rate); - } - - send_response(); - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start receiving. */ - - cpu_start(dlpi_cl_rr_request->measure_cpu); - - if (dlpi_cl_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(dlpi_cl_rr_request->test_length + PAD_TIME); - } -else { - times_up = 1; - trans_remaining = dlpi_cl_rr_request->test_length * -1; -} - - while ((!times_up) || (trans_remaining > 0)) { - - /* receive the request from the other side. at some point we need */ - /* to handle "logical" requests and responses which are larger */ - /* than the data link MTU */ - - if((getmsg(data_descriptor, - &rctl_message, - &recv_message, - &flags) != 0) || - (data_ind->dl_primitive != DL_UNITDATA_IND)) { - if (errno == EINTR) { - /* Again, we have likely hit test-end time */ - break; - } - fprintf(where, - "dlpi_recv_cl_rr: getmsg failure: errno %d primitive 0x%x\n", - errno, - data_ind->dl_primitive); - fprintf(where, - " recevied %u transactions\n", - trans_received); - fflush(where); - netperf_response.content.serv_errno = 995; - send_response(); - exit(1); - } - - /* Now, send the response to the remote. first copy the dlsap */ - /* information from the receive to the sending control message */ - - data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t); - bcopy((char *)data_ind + data_ind->dl_src_addr_offset, - (char *)data_req + data_req->dl_dest_addr_offset, - data_ind->dl_src_addr_length); - data_req->dl_dest_addr_length = data_ind->dl_src_addr_length; - data_req->dl_primitive = DL_UNITDATA_REQ; - /* be sure to initialize the priority fields. fix from Nicholas - Thomas */ - data_req->dl_priority.dl_min = DL_QOS_DONT_CARE; - data_req->dl_priority.dl_max = DL_QOS_DONT_CARE; - - sctl_message.len = sizeof(dl_unitdata_req_t) + - data_ind->dl_src_addr_length; - if(putmsg(data_descriptor, - &sctl_message, - &send_message, - 0) != 0) { - if (errno == EINTR) { - /* We likely hit */ - /* test-end time. */ - break; - } - /* there is more we could do here, but it can wait */ - fprintf(where, - "dlpi_recv_cl_rr: putmsg failure: errno %d\n", - errno); - fflush(where); - netperf_response.content.serv_errno = 993; - send_response(); - exit(1); - } - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug) { - fprintf(where, - "recv_dlpi_cl_rr: Transaction %d complete.\n", - trans_received); - fflush(where); - } - - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(dlpi_cl_rr_request->measure_cpu,&elapsed_time); - - if (times_up) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_dlpi_cl_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - dlpi_cl_rr_results->bytes_received = (trans_received * - (dlpi_cl_rr_request->request_size + - dlpi_cl_rr_request->response_size)); - dlpi_cl_rr_results->trans_received = trans_received; - dlpi_cl_rr_results->elapsed_time = elapsed_time; - if (dlpi_cl_rr_request->measure_cpu) { - dlpi_cl_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_dlpi_cl_rr: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - -} - -int - recv_dlpi_co_rr() -{ - - char *message; - SOCKET s_listen,data_descriptor; - - int measure_cpu; - - int flags = 0; - char *recv_message_ptr; - char *send_message_ptr; - struct strbuf send_message; - struct strbuf recv_message; - - int trans_received; - int trans_remaining; - int request_bytes_remaining; - int timed_out = 0; - float elapsed_time; - - struct dlpi_co_rr_request_struct *dlpi_co_rr_request; - struct dlpi_co_rr_response_struct *dlpi_co_rr_response; - struct dlpi_co_rr_results_struct *dlpi_co_rr_results; - - dlpi_co_rr_request = (struct dlpi_co_rr_request_struct *)netperf_request.content.test_specific_data; - dlpi_co_rr_response = (struct dlpi_co_rr_response_struct *)netperf_response.content.test_specific_data; - dlpi_co_rr_results = (struct dlpi_co_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_dlpi_co_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_dlpi_co_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = DLPI_CO_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_dlpi_co_rr: the response type is set...\n"); - fflush(where); - } - - /* set-up the data buffer with the requested alignment and offset */ - message = (char *)malloc(DATABUFFERLEN); - if (message == NULL) { - printf("malloc(%d) failed!\n", DATABUFFERLEN); - exit(1); - } - - /* We now alter the message_ptr variables to be at the desired */ - /* alignments with the desired offsets. */ - - if (debug) { - fprintf(where, - "recv_dlpi_co_rr: requested recv alignment of %d offset %d\n", - dlpi_co_rr_request->recv_alignment, - dlpi_co_rr_request->recv_offset); - fprintf(where, - "recv_dlpi_co_rr: requested send alignment of %d offset %d\n", - dlpi_co_rr_request->send_alignment, - dlpi_co_rr_request->send_offset); - fflush(where); - } - - recv_message_ptr = ALIGN_BUFFER(message, dlpi_co_rr_request->recv_alignment, dlpi_co_rr_request->recv_offset); - recv_message.maxlen = dlpi_co_rr_request->request_size; - recv_message.len = 0; - recv_message.buf = recv_message_ptr; - - send_message_ptr = ALIGN_BUFFER(message, dlpi_co_rr_request->send_alignment, dlpi_co_rr_request->send_offset); - send_message.maxlen = dlpi_co_rr_request->response_size; - send_message.len = dlpi_co_rr_request->response_size; - send_message.buf = send_message_ptr; - - if (debug) { - fprintf(where,"recv_dlpi_co_rr: receive alignment and offset set...\n"); - fprintf(where,"recv_dlpi_co_rr: send_message.buf %x .len %d .maxlen %d\n", - send_message.buf,send_message.len,send_message.maxlen); - fprintf(where,"recv_dlpi_co_rr: recv_message.buf %x .len %d .maxlen %d\n", - recv_message.buf,recv_message.len,recv_message.maxlen); - fflush(where); - } - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_dlpi_co_rr: grabbing a socket...\n"); - fflush(where); - } - - /* lets grab a file descriptor for a particular link */ - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) dlpi_co_rr_request->dlpi_device; - lastword = initword + ((dlpi_co_rr_request->dev_name_len + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = htonl(*charword); - } - } -#endif /* __alpha */ - - if ((data_descriptor = dl_open(dlpi_co_rr_request->dlpi_device, - dlpi_co_rr_request->ppa)) < 0) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* bind the file descriptor to a sap and get the resultant dlsap */ - dlpi_co_rr_response->station_addr_len = 14; /*arbitrary needs fixing */ - if (dl_bind(data_descriptor, - dlpi_co_rr_request->sap, - DL_CODLS, - (char *)dlpi_co_rr_response->station_addr, - &dlpi_co_rr_response->station_addr_len) != 0) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* The initiator may have wished-us to modify the socket buffer */ - /* sizes. We should give it a shot. If he didn't ask us to change the */ - /* sizes, we should let him know what sizes were in use at this end. */ - /* If none of this code is compiled-in, then we will tell the */ - /* initiator that we were unable to play with the socket buffer by */ - /* setting the size in the response to -1. */ - -#ifdef DL_HP_SET_LOCAL_WIN_REQ - - if (dlpi_co_rr_request->recv_win_size) { - /* SMOP */ - } - - if (dlpi_co_rr_request->send_win_size) { - /* SMOP */ - } - - /* Now, we will find-out what the sizes actually became, and report */ - /* them back to the user. If the calls fail, we will just report a -1 */ - /* back to the initiator for the buffer size. */ - -#else /* the system won't let us play with the buffers */ - - dlpi_co_rr_response->recv_win_size = -1; - dlpi_co_rr_response->send_win_size = -1; - -#endif /* DL_HP_SET_LOCAL_WIN_REQ */ - - /* we may have been requested to enable the copy avoidance features. */ - /* can we actually do this with DLPI, the world wonders */ - - if (dlpi_co_rr_request->so_rcvavoid) { -#ifdef SO_RCV_COPYAVOID - dlpi_co_rr_response->so_rcvavoid = 0; -#else - /* it wasn't compiled in... */ - dlpi_co_rr_response->so_rcvavoid = 0; -#endif - } - - if (dlpi_co_rr_request->so_sndavoid) { -#ifdef SO_SND_COPYAVOID - dlpi_co_rr_response->so_sndavoid = 0; -#else - /* it wasn't compiled in... */ - dlpi_co_rr_response->so_sndavoid = 0; -#endif - } - - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - dlpi_co_rr_response->cpu_rate = 0.0; /* assume no cpu */ - if (dlpi_co_rr_request->measure_cpu) { - dlpi_co_rr_response->measure_cpu = 1; - dlpi_co_rr_response->cpu_rate = calibrate_local_cpu(dlpi_co_rr_request->cpu_rate); - } - - send_response(); - - /* accept a connection on this file descriptor. at some point, */ - /* dl_accept will "do the right thing" with the last two parms, but */ - /* for now it ignores them, so we will pass zeros. */ - - if(dl_accept(data_descriptor, 0, 0) != 0) { - fprintf(where, - "recv_dlpi_co_rr: error in accept, errno %d\n", - errno); - fflush(where); - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - if (debug) { - fprintf(where, - "recv_dlpi_co_rr: accept completes on the data connection.\n"); - fflush(where); - } - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(dlpi_co_rr_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - if (dlpi_co_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(dlpi_co_rr_request->test_length + PAD_TIME); - } -else { - times_up = 1; - trans_remaining = dlpi_co_rr_request->test_length * -1; -} - - while ((!times_up) || (trans_remaining > 0)) { - request_bytes_remaining = dlpi_co_rr_request->request_size; - - /* receive the request from the other side. there needs to be some */ - /* more login in place for handling messages larger than link mtu, */ - /* but that can wait for later */ - while(request_bytes_remaining > 0) { - if((getmsg(data_descriptor, - 0, - &recv_message, - &flags)) < 0) { - if (errno == EINTR) { - /* the timer popped */ - timed_out = 1; - break; - } - - if (debug) { - fprintf(where,"failed getmsg call errno %d\n",errno); - fprintf(where,"recv_message.len %d\n",recv_message.len); - fprintf(where,"send_message.len %d\n",send_message.len); - fflush(where); - } - - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - else { - request_bytes_remaining -= recv_message.len; - } - } - - if (timed_out) { - /* we hit the end of the test based on time - lets bail out of */ - /* here now... */ - break; - } - - if (debug) { - fprintf(where,"recv_message.len %d\n",recv_message.len); - fprintf(where,"send_message.len %d\n",send_message.len); - fflush(where); - } - - /* Now, send the response to the remote */ - if((putmsg(data_descriptor, - 0, - &send_message, - 0)) != 0) { - if (errno == EINTR) { - /* the test timer has popped */ - timed_out = 1; - break; - } - netperf_response.content.serv_errno = 994; - send_response(); - exit(1); - } - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug) { - fprintf(where, - "recv_dlpi_co_rr: Transaction %d complete\n", - trans_received); - fflush(where); - } - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(dlpi_co_rr_request->measure_cpu,&elapsed_time); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_dlpi_co_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - dlpi_co_rr_results->bytes_received = (trans_received * - (dlpi_co_rr_request->request_size + - dlpi_co_rr_request->response_size)); - dlpi_co_rr_results->trans_received = trans_received; - dlpi_co_rr_results->elapsed_time = elapsed_time; - if (dlpi_co_rr_request->measure_cpu) { - dlpi_co_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_dlpi_co_rr: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - -} - -/* this routine will display the usage string for the DLPI tests */ -void - print_dlpi_usage() - -{ - fwrite(dlpi_usage, sizeof(char), strlen(dlpi_usage), stdout); -} - - -/* this routine will scan the command line for DLPI test arguments */ -void - scan_dlpi_args(int argc, char *argv[]) -{ - extern int optind, opterrs; /* index of first unused arg */ - extern char *optarg; /* pointer to option string */ - - int c; - - char arg1[BUFSIZ], /* argument holders */ - arg2[BUFSIZ]; - - if (no_control) { - fprintf(where, - "The DLPI tests do not know how to run with no control connection\n"); - exit(-1); - } - - /* Go through all the command line arguments and break them */ - /* out. For those options that take two parms, specifying only */ - /* the first will set both to that value. Specifying only the */ - /* second will leave the first untouched. To change only the */ - /* first, use the form first, (see the routine break_args.. */ - -#define DLPI_ARGS "D:hM:m:p:r:s:W:w:" - - while ((c= getopt(argc, argv, DLPI_ARGS)) != EOF) { - switch (c) { - case '?': - case 'h': - print_dlpi_usage(); - exit(1); - case 'D': - /* set the dlpi device file name(s) */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - strcpy(loc_dlpi_device,arg1); - if (arg2[0]) - strcpy(rem_dlpi_device,arg2); - break; - case 'm': - /* set the send size */ - send_size = atoi(optarg); - break; - case 'M': - /* set the recv size */ - recv_size = atoi(optarg); - break; - case 'p': - /* set the local/remote ppa */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - loc_ppa = atoi(arg1); - if (arg2[0]) - rem_ppa = atoi(arg2); - break; - case 'r': - /* set the request/response sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - req_size = atoi(arg1); - if (arg2[0]) - rsp_size = atoi(arg2); - break; - case 's': - /* set the 802.2 sap for the test */ - dlpi_sap = atoi(optarg); - break; - case 'w': - /* set local window sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - lsw_size = atoi(arg1); - if (arg2[0]) - lrw_size = atoi(arg2); - break; - case 'W': - /* set remote window sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - rsw_size = atoi(arg1); - if (arg2[0]) - rrw_size = atoi(arg2); - break; - }; - } -} - - -#endif /* WANT_DLPI */ diff --git a/nettest_dlpi.h b/nettest_dlpi.h deleted file mode 100644 index 8169237..0000000 --- a/nettest_dlpi.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - Copyright (C) 1993, Hewlett-Packard Company -*/ - - /* This file contains the test-specific definitions for netperf's */ - /* DLPI tests */ - - -struct dlpi_co_stream_request_struct { - int recv_win_size; - int send_win_size; - int receive_size; /* how many bytes do we want to */ - /* receive at one time? */ - int recv_alignment; /* what is the alignment of the */ - /* receive buffer? */ - int recv_offset; /* and at what offset from that */ - /* alignment? */ - int measure_cpu; /* does the client want server cpu */ - /* utilization measured? */ - float cpu_rate; /* do we know how fast the cpu is */ - /* already? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid */ - /* copies on receives? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dirty_count; /* how many integers in the receive buffer */ - /* should be made dirty before calling recv? */ - int clean_count; /* how many integers should be read from the */ - /* recv buffer before calling recv? */ - int sap; /* */ - int ppa; /* which device do we wish to use? */ - int dev_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char dlpi_device[32]; /* the path to the dlpi device */ -}; - -struct dlpi_co_stream_response_struct { - int recv_win_size; /* how big does the client want it */ - int send_win_size; - int receive_size; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ - int station_addr_len; - int station_addr[1];/* what is the station address for the */ - /* specified ppa? */ -}; - -struct dlpi_co_stream_results_struct { - int bytes_received; /* ignored initially */ - int recv_calls; /* ignored initially */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was CPU util measured? */ - int num_cpus; /* how many CPUs were there? */ -}; - -struct dlpi_co_rr_request_struct { - int recv_win_size; /* how big does the client want it */ - int send_win_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int ppa; /* which device do we wish to use? */ - int sap; /* which sap should be used? */ - int dev_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char dlpi_device[32]; /* the path to the dlpi device */ -}; - -struct dlpi_co_rr_response_struct { - int recv_win_size; /* how big does the client want it */ - int send_win_size; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ - int station_addr_len; /* the length of the station address */ - int station_addr[1]; /* the remote's station address */ -}; - -struct dlpi_co_rr_results_struct { - int bytes_received; /* ignored initially */ - int recv_calls; /* ignored initially */ - int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was CPU util measured? */ - int num_cpus; /* how many CPUs were there? */ -}; - -struct dlpi_cl_stream_request_struct { - int recv_win_size; - int message_size; - int recv_alignment; - int recv_offset; - int checksum_off; - int measure_cpu; - float cpu_rate; - int test_length; - int so_rcvavoid; /* do we want the remote to avoid receive copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int ppa; /* which device do we wish to use? */ - int sap; - int dev_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char dlpi_device[32]; /* the path to the dlpi device */ -}; - -struct dlpi_cl_stream_response_struct { - int recv_win_size; - int send_win_size; - int measure_cpu; - int test_length; - int data_port_number; - float cpu_rate; - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ - int station_addr_len; /* the length of the station address */ - int station_addr[1]; /* the remote's station address */ -}; - -struct dlpi_cl_stream_results_struct { - int messages_recvd; - int bytes_received; - float elapsed_time; - float cpu_util; - int num_cpus; -}; - - -struct dlpi_cl_rr_request_struct { - int recv_win_size; /* how big does the client want it */ - int send_win_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int ppa; /* which device do we wish to use? */ - int sap; /* which sap? */ - int dev_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char dlpi_device[32]; /* the path to the dlpi device */ -}; - -struct dlpi_cl_rr_response_struct { - int recv_win_size; /* how big does the client want it */ - int send_win_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ - int station_addr_len; /* the length of the station address */ - int station_addr[1]; /* the remote's station address */ -}; - -struct dlpi_cl_rr_results_struct { - int bytes_received; /* ignored initially */ - int recv_calls; /* ignored initially */ - int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was CPU util measured? */ - int num_cpus; /* how many CPUs were there? */ -}; - -extern void send_dlpi_co_stream(); - -extern int recv_dlpi_co_stream(); - -extern int send_dlpi_co_rr(char remote_host[]); - -extern void send_dlpi_cl_stream(char remote_host[]); - -extern int recv_dlpi_cl_stream(); - -extern int send_dlpi_cl_rr(char remote_host[]); - -extern int recv_dlpi_cl_rr(); - -extern int recv_dlpi_co_rr(); - -extern void scan_dlpi_args(int argc, char *argv[]); diff --git a/nettest_sctp.c b/nettest_sctp.c deleted file mode 100644 index 7cfcd9f..0000000 --- a/nettest_sctp.c +++ /dev/null @@ -1,4869 +0,0 @@ -#ifndef lint -char nettest_sctp[]="\ -@(#)nettest_sctp.c (c) Copyright 2005-2007 Hewlett-Packard Co. Version 2.4.3"; -#else -#define DIRTY -#define WANT_HISTOGRAM -#define WANT_INTERVALS -#endif /* lint */ - -/****************************************************************/ -/* */ -/* nettest_sctp.c */ -/* */ -/* */ -/* scan_sctp_args() get the sctp command line args */ -/* */ -/* the actual test routines... */ -/* */ -/* send_sctp_stream() perform a sctp stream test */ -/* recv_sctp_stream() */ -/* send_sctp_rr() perform a sctp request/response */ -/* recv_sctp_rr() */ -/* send_sctp_stream_udp() perform a sctp request/response */ -/* recv_sctp_stream_upd() using UDP style API */ -/* send_sctp_rr_udp() perform a sctp request/response */ -/* recv_sctp_rr_upd() using UDP style API */ -/* */ -/* relies on create_data_socket in nettest_bsd.c */ -/****************************************************************/ - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(WANT_SCTP) - -#include <sys/types.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <stdio.h> -#include <string.h> -#include <time.h> -#ifdef NOSTDLIBH -#include <malloc.h> -#else /* NOSTDLIBH */ -#include <stdlib.h> -#endif /* NOSTDLIBH */ - -#if !defined(__VMS) -#include <sys/ipc.h> -#endif /* !defined(__VMS) */ -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <netinet/sctp.h> -#include <arpa/inet.h> -#include <netdb.h> - -/* would seem that not all sctp.h files define a MSG_EOF, but that - MSG_EOF can be the same as MSG_FIN so lets work with that - assumption. initial find by Jon Pedersen. raj 2006-02-01 */ -#ifndef MSG_EOF -#ifdef MSG_FIN -#define MSG_EOF MSG_FIN -#else -#error Must have either MSG_EOF or MSG_FIN defined -#endif -#endif - -#include "netlib.h" -#include "netsh.h" -/* get some of the functions from nettest_bsd.c */ -#include "nettest_bsd.h" -#include "nettest_sctp.h" - -#ifdef WANT_HISTOGRAM -#ifdef __sgi -#include <sys/time.h> -#endif /* __sgi */ -#include "hist.h" -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_FIRST_BURST -extern int first_burst_size; -#endif /* WANT_FIRST_BURST */ - - - -/* these variables are specific to SCTP tests. declare */ -/* them static to make them global only to this file. */ - -static int - msg_count = 0, /* number of messages to transmit on association */ - non_block = 0, /* default to blocking sockets */ - num_associations = 1; /* number of associations on the endpoint */ - -static int confidence_iteration; -static char local_cpu_method; -static char remote_cpu_method; - -#ifdef WANT_HISTOGRAM -static struct timeval time_one; -static struct timeval time_two; -static HIST time_hist; -#endif /* WANT_HISTOGRAM */ - - -char sctp_usage[] = "\n\ -Usage: netperf [global options] -- [test options] \n\ -\n\ -SCTP Sockets Test Options:\n\ - -b number Send number requests at the start of _RR tests\n\ - -D [L][,R] Set SCTP_NODELAY locally and/or remotely\n\ - -h Display this text\n\ - -H name,fam Use name (or IP) and family as target of data connection\n\ - -L name,fam Use name (or IP) and family as source of data connextion\n\ - -m bytes Set the size of each sent message\n\ - -M bytes Set the size of each received messages\n\ - -P local[,remote] Set the local/remote port for the data socket\n\ - -r req,[rsp] Set request/response sizes (_RR tests)\n\ - -s send[,recv] Set local socket send/recv buffer sizes\n\ - -S send[,recv] Set remote socket send/recv buffer sizes\n\ - -V Enable copy avoidance if supported\n\ - -N number Specifies the number of messages to send (_STREAM tests)\n\ - -B run the test in non-blocking mode\n\ - -T number Number of associations to create (_MANY tests)\n\ - -4 Use AF_INET (eg IPv4) on both ends of the data conn\n\ - -6 Use AF_INET6 (eg IPv6) on both ends of the data conn\n\ -\n\ -For those options taking two parms, at least one must be specified;\n\ -specifying one value without a comma will set both parms to that\n\ -value, specifying a value with a leading comma will set just the second\n\ -parm, a value with a trailing comma will set just the first. To set\n\ -each parm to unique values, specify both and separate them with a\n\ -comma.\n"; - - - /* This routine is intended to retrieve interesting aspects of tcp */ - /* for the data connection. at first, it attempts to retrieve the */ - /* maximum segment size. later, it might be modified to retrieve */ - /* other information, but it must be information that can be */ - /* retrieved quickly as it is called during the timing of the test. */ - /* for that reason, a second routine may be created that can be */ - /* called outside of the timing loop */ -static -void -get_sctp_info(socket, mss) - int socket; - int *mss; -{ - - int sock_opt_len; - - if (sctp_opt_info(socket, - 0, - SCTP_MAXSEG, - mss, - &sock_opt_len) < 0) { - lss_size = -1; - } -} - - -static -void -sctp_enable_events(socket, ev_mask) - int socket; - int ev_mask; -{ - struct sctp_event_subscribe ev; - - bzero(&ev, sizeof(ev)); - - if (ev_mask & SCTP_SNDRCV_INFO_EV) - ev.sctp_data_io_event = 1; - - if (ev_mask & SCTP_ASSOC_CHANGE_EV) - ev.sctp_association_event = 1; - - if (ev_mask & SCTP_PEERADDR_CHANGE_EV) - ev.sctp_address_event = 1; - - if (ev_mask & SCTP_SND_FAILED_EV) - ev.sctp_send_failure_event = 1; - - if (ev_mask & SCTP_REMOTE_ERROR_EV) - ev.sctp_peer_error_event = 1; - - if (ev_mask & SCTP_SHUTDOWN_EV) - ev.sctp_shutdown_event = 1; - - if (ev_mask & SCTP_PD_EV) - ev.sctp_partial_delivery_event = 1; - - if (ev_mask & SCTP_ADAPT_EV) -#ifdef HAVE_SCTP_ADAPTATION_LAYER_EVENT - ev.sctp_adaptation_layer_event = 1; -#else - ev.sctp_adaption_layer_event = 1; -#endif - - if (setsockopt(socket, - IPPROTO_SCTP, -#ifdef SCTP_EVENTS - SCTP_EVENTS, -#else - SCTP_SET_EVENTS, -#endif - (const char*)&ev, - sizeof(ev)) != 0 ) { - fprintf(where, - "sctp_enable_event: could not set sctp events errno %d\n", - errno); - fflush(where); - exit(1); - } -} - - -static -sctp_disposition_t -sctp_process_event(socket, buf) - int socket; - void *buf; -{ - - struct sctp_assoc_change *sac; - struct sctp_send_failed *ssf; - struct sctp_paddr_change *spc; - struct sctp_remote_error *sre; - union sctp_notification *snp; - - snp = buf; - - switch (snp->sn_header.sn_type) { - case SCTP_ASSOC_CHANGE: - if (debug) { - fprintf(where, "\tSCTP_ASSOC_CHANGE event, type:"); - fflush(where); - } - sac = &snp->sn_assoc_change; - switch (sac->sac_type) { - case SCTP_COMM_UP: - if (debug) { - fprintf(where, " SCTP_COMM_UP\n"); - fflush(where); - } - break; - case SCTP_RESTART: - if (debug) { - fprintf(where, " SCTP_RESTART\n"); - fflush(where); - } - break; - case SCTP_CANT_STR_ASSOC: - if (debug) { - fprintf(where, " SCTP_CANT_STR_ASSOC\n"); - fflush(where); - } - break; /* FIXME ignore above status changes */ - case SCTP_COMM_LOST: - if (debug) { - fprintf(where, " SCTP_COMM_LOST\n"); - fflush(where); - } - return SCTP_CLOSE; - case SCTP_SHUTDOWN_COMP: - if (debug) { - fprintf(where, " SCTP_SHUTDOWN_COMPLETE\n"); - fflush(where); - } - return SCTP_CLOSE; - break; - } - - case SCTP_SEND_FAILED: - if (debug) { - fprintf(where, "\tSCTP_SEND_FAILED event\n"); - fflush(where); - } - ssf = &snp->sn_send_failed; - break; /* FIXME ??? ignore this for now */ - - case SCTP_PEER_ADDR_CHANGE: - if (debug) { - fprintf(where, "\tSCTP_PEER_ADDR_CHANGE event\n"); - fflush(where); - } - spc = &snp->sn_paddr_change; - break; /* FIXME ??? ignore this for now */ - - case SCTP_REMOTE_ERROR: - if (debug) { - fprintf(where, "\tSCTP_REMOTE_ERROR event\n"); - fflush(where); - } - sre = &snp->sn_remote_error; - break; /* FIXME ??? ignore this for now */ - case SCTP_SHUTDOWN_EVENT: - if (debug) { - fprintf(where, "\tSCTP_SHUTDOWN event\n"); - fflush(where); - } - return SCTP_CLOSE; - default: - fprintf(where, "unknown type: %hu\n", snp->sn_header.sn_type); - fflush(where); - break; - } - return SCTP_OK; -} - - - -/* This routine implements the SCTP unidirectional data transfer test */ -/* (a.k.a. stream) for the sockets interface. It receives its */ -/* parameters via global variables from the shell and writes its */ -/* output to the standard output. */ - - -void -send_sctp_stream(remote_host) -char remote_host[]; -{ - - char *tput_title = "\ -Recv Send Send \n\ -Socket Socket Message Elapsed \n\ -Size Size Size Time Throughput \n\ -bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f \n"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Socket Socket Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - - char *cpu_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ -Local Remote Local Remote Xfered Per Per\n\ -Send Recv Send Recv Send (avg) Recv (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - - char *ksink_fmt2 = "\n\ -Maximum\n\ -Segment\n\ -Size (bytes)\n\ -%6d\n"; - - - float elapsed_time; - -#ifdef WANT_INTERVALS - int interval_count; - sigset_t signal_set; -#endif - - /* what we want is to have a buffer space that is at least one */ - /* send-size greater than our send window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - -#ifdef DIRTY - int *message_int_ptr; -#endif - - struct ring_elt *send_ring; - - int len; - unsigned int nummessages = 0; - int send_socket; - int bytes_remaining; - int sctp_mss; - int timed_out; - - /* with links like fddi, one can send > 32 bits worth of bytes */ - /* during a test... ;-) at some point, this should probably become a */ - /* 64bit integral type, but those are not entirely common yet */ - double bytes_sent = 0.0; - -#ifdef DIRTY - int i; -#endif /* DIRTY */ - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - - double thruput; - - struct addrinfo *remote_res; - struct addrinfo *local_res; - struct addrinfo *local_remote_res; - struct addrinfo *local_local_res; - - struct sctp_stream_request_struct *sctp_stream_request; - struct sctp_stream_response_struct *sctp_stream_response; - struct sctp_stream_results_struct *sctp_stream_result; - - sctp_stream_request = - (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data; - sctp_stream_response = - (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data; - sctp_stream_result = - (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - time_hist = HIST_new(); -#endif /* WANT_HISTOGRAM */ - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - /* complete_addrinfos will either succede or exit the process */ - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_SCTP, - 0); - - if ( print_headers ) { - print_top_test_header("SCTP STREAM TEST", local_res, remote_res); - } - - send_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - timed_out = 0; - - /*set up the data socket */ - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_sctp_stream: sctp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_sctp_stream: send_socket obtained...\n"); - } - - /* at this point, we have either retrieved the socket buffer sizes, */ - /* or have tried to set them, so now, we may want to set the send */ - /* size based on that (because the user either did not use a -m */ - /* option, or used one with an argument of 0). If the socket buffer */ - /* size is not available, we will set the send size to 4KB - no */ - /* particular reason, just arbitrary... */ - if (send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - - /* set-up the data buffer ring with the requested alignment and offset. */ - /* note also that we have allocated a quantity */ - /* of memory that is at least one send-size greater than our socket */ - /* buffer size. We want to be sure that there are at least two */ - /* buffers allocated - this can be a bit of a problem when the */ - /* send_size is bigger than the socket size, so we must check... the */ - /* user may have wanted to explicitly set the "width" of our send */ - /* buffers, we should respect that wish... */ - if (send_width == 0) { - send_width = (lss_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - if (send_ring == NULL) { - /* only allocate the send ring once. this is a networking test, */ - /* not a memory allocation test. this way, we do not need a */ - /* deallocate_buffer_ring() routine, and I don't feel like */ - /* writing one anyway :) raj 11/94 */ - send_ring = allocate_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 1, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_SCTP_STREAM; - sctp_stream_request->send_buf_size = rss_size_req; - sctp_stream_request->recv_buf_size = rsr_size_req; - sctp_stream_request->receive_size = recv_size; - sctp_stream_request->no_delay = rem_nodelay; - sctp_stream_request->recv_alignment = remote_recv_align; - sctp_stream_request->recv_offset = remote_recv_offset; - sctp_stream_request->measure_cpu = remote_cpu_usage; - sctp_stream_request->cpu_rate = remote_cpu_rate; - if (test_time) { - sctp_stream_request->test_length = test_time; - } - else { - if (msg_count) - test_bytes = send_size * msg_count; - - sctp_stream_request->test_length = test_bytes; - } - sctp_stream_request->so_rcvavoid = rem_rcvavoid; - sctp_stream_request->so_sndavoid = rem_sndavoid; -#ifdef DIRTY - sctp_stream_request->dirty_count = rem_dirty_count; - sctp_stream_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - sctp_stream_request->port = htonl(atoi(remote_data_port)); - sctp_stream_request->ipfamily = af_to_nf(remote_res->ai_family); - sctp_stream_request->non_blocking = non_block; - - - if (debug > 1) { - fprintf(where, - "netperf: send_sctp_stream: requesting sctp stream test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right*/ - /* after the connect returns. The remote will grab the counter right*/ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the sctp tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = sctp_stream_response->recv_buf_size; - rss_size = sctp_stream_response->send_buf_size; - rem_nodelay = sctp_stream_response->no_delay; - remote_cpu_usage= sctp_stream_response->measure_cpu; - remote_cpu_rate = sctp_stream_response->cpu_rate; - - /* we have to make sure that the server port number is in */ - /* network order */ - set_port_number(remote_res, (short)sctp_stream_response->data_port_number); - - rem_rcvavoid = sctp_stream_response->so_rcvavoid; - rem_sndavoid = sctp_stream_response->so_sndavoid; - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET) { - perror("netperf: send_sctp_stream: data socket connect failed"); - exit(1); - } - - sctp_enable_events(send_socket, SCTP_ASSOC_CHANGE_EV); - - if (non_block) { - /* now that we are connected, mark the socket as non-blocking */ - if (!set_nonblock(send_socket)) { - perror("netperf: fcntl"); - exit(1); - } - } - - /* Data Socket set-up is finished. If there were problems, either */ - /* the connect would have failed, or the previous response would */ - /* have indicated a problem. I failed to see the value of the */ - /* extra message after the accept on the remote. If it failed, */ - /* we'll see it here. If it didn't, we might as well start pumping */ - /* data. */ - - /* Set-up the test end conditions. For a stream test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - /* in previous revisions, we had the same code repeated throught */ - /* all the test suites. this was unnecessary, and meant more */ - /* work for me when I wanted to switch to POSIX signals, so I */ - /* have abstracted this out into a routine in netlib.c. if you */ - /* are experiencing signal problems, you might want to look */ - /* there. raj 11/94 */ - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - bytes_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - if ((interval_burst) || (demo_mode)) { - /* zero means that we never pause, so we never should need the */ - /* interval timer, unless we are in demo_mode */ - start_itimer(interval_wate); - } - interval_count = interval_burst; - /* get the signal set for the call to sigsuspend */ - if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { - fprintf(where, - "send_sctp_stream: unable to get sigmask errno %d\n", - errno); - fflush(where); - exit(1); - } -#endif /* WANT_INTERVALS */ - -#ifdef DIRTY - /* initialize the random number generator for putting dirty stuff */ - /* into the send buffer. raj */ - srand((int) getpid()); -#endif - - /* before we start, initialize a few variables */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. */ - - while ((!times_up) || (bytes_remaining > 0)) { - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. at some point, we might want to replace */ - /* the rand() call with something from a table to reduce our call */ - /* overhead during the test, but it is not a high priority item. */ - message_int_ptr = (int *)(send_ring->buffer_ptr); - for (i = 0; i < loc_dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < loc_clean_count; i++) { - loc_dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - -#ifdef WANT_HISTOGRAM - /* timestamp just before we go into send and then again just after */ - /* we come out raj 8/94 */ - HIST_timestamp(&time_one); -#endif /* WANT_HISTOGRAM */ - - while ((len=sctp_sendmsg(send_socket, - send_ring->buffer_ptr, send_size, - NULL, 0, - 0, 0, 0, 0, 0)) != send_size) { - if (non_block && errno == EAGAIN) - continue; - else if ((len >=0) || SOCKET_EINTR(len)) { - /* the test was interrupted, must be the end of test */ - timed_out = 1; - break; - } - perror("netperf: data send error"); - printf("len was %d\n",len); - exit(1); - } - - if (timed_out) - break; /* we timed out durint sendmsg, done with test */ - -#ifdef WANT_HISTOGRAM - /* timestamp the exit from the send call and update the histogram */ - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_INTERVALS - if (demo_mode) { - units_this_tick += send_size; - } - /* in this case, the interval count is the count-down couter */ - /* to decide to sleep for a little bit */ - if ((interval_burst) && (--interval_count == 0)) { - /* call sigsuspend and wait for the interval timer to get us */ - /* out */ - if (debug > 1) { - fprintf(where,"about to suspend\n"); - fflush(where); - } - if (sigsuspend(&signal_set) == EFAULT) { - fprintf(where, - "send_sctp_stream: fault with sigsuspend.\n"); - fflush(where); - exit(1); - } - interval_count = interval_burst; - } -#endif /* WANT_INTERVALS */ - - /* now we want to move our pointer to the next position in the */ - /* data buffer...we may also want to wrap back to the "beginning" */ - /* of the bufferspace, so we will mod the number of messages sent */ - /* by the send width, and use that to calculate the offset to add */ - /* to the base pointer. */ - nummessages++; - send_ring = send_ring->next; - if (bytes_remaining) { - bytes_remaining -= send_size; - } - } - - /* The test is over. Flush the buffers to the remote end. We do a */ - /* graceful release to insure that all data has been taken by the */ - /* remote. */ - - /* but first, if the verbosity is greater than 1, find-out what */ - /* the sctp maximum segment_size was (if possible) */ - if (verbosity > 1) { - sctp_mss = -1; - get_sctp_info(send_socket, &sctp_mss); - } - - shutdown(send_socket, SHUT_WR); - - /* The test server will signal to us when it wants to shutdown. - * In blocking mode, we can call recvmsg. In non-blocking - * mode, we need to select on the socket for reading. - * We'll assume that all returns are succefull - */ - if (non_block) { - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(send_socket, &readfds); - select(send_socket+1, &readfds, NULL, NULL, NULL); - } else { - sctp_recvmsg(send_socket, send_ring->buffer_ptr, send_size, NULL, - 0, NULL, 0); - } - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured and how */ - /* long did we really */ - /* run? */ - - /* we are finished with the socket, so close it to prevent hitting */ - /* the limit on maximum open files. */ - close(send_socket); - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a sctp stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) */ - - bytes_sent = ntohd(sctp_stream_result->bytes_received); - - thruput = (double) calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - - remote_cpu_utilization = sctp_stream_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - sctp_stream_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - } - - /* at this point, we have finished making all the runs that we */ - /* will be making. so, we should extract what the calcuated values */ - /* are for all the confidence stuff. we could make the values */ - /* global, but that seemed a little messy, and it did not seem worth */ - /* all the mucking with header files. so, we create a routine much */ - /* like calcualte_confidence, which just returns the mean values. */ - /* raj 11/94 */ - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(sctp_stream_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - fprintf(where, - tput_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - thruput);/* how fast did it go */ - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* sctp statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - /* this stuff needs to be worked-out in the presence of confidence */ - /* intervals and multiple iterations of the test... raj 11/94 */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_send_align, - remote_recv_align, - local_send_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)sctp_stream_result->recv_calls, - sctp_stream_result->recv_calls); - fprintf(where, - ksink_fmt2, - sctp_mss); - fflush(where); -#ifdef WANT_HISTOGRAM - fprintf(where,"\n\nHistogram of time spent in send() call.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } - -} - - - - -/* This is the server-side routine for the sctp stream test. It is */ -/* implemented as one routine. I could break things-out somewhat, but */ -/* didn't feel it was necessary. */ - -void -recv_sctp_stream() -{ - - struct sockaddr_in myaddr_in; /* needed to get port number */ - struct sockaddr_storage peeraddr; /* used in accept */ - int s_listen,s_data; - int addrlen; - int len; - unsigned int receive_calls; - float elapsed_time; - double bytes_received; - - struct ring_elt *recv_ring; - - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - int msg_flags = 0; - -#ifdef DIRTY - int *message_int_ptr; - int dirty_count; - int clean_count; - int i; -#endif - -#ifdef DO_SELECT - fd_set readfds; - struct timeval timeout; -#endif /* DO_SELECT */ - - struct sctp_stream_request_struct *sctp_stream_request; - struct sctp_stream_response_struct *sctp_stream_response; - struct sctp_stream_results_struct *sctp_stream_results; - -#ifdef DO_SELECT - FD_ZERO(&readfds); - timeout.tv_sec = 1; - timeout.tv_usec = 0; -#endif /* DO_SELECT */ - - sctp_stream_request = - (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data; - sctp_stream_response = - (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data; - sctp_stream_results = - (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_sctp_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_sctp_stream: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = SCTP_STREAM_RESPONSE; - - if (debug) { - fprintf(where,"recv_sctp_stream: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug) { - fprintf(where,"recv_sctp_stream: requested alignment of %d\n", - sctp_stream_request->recv_alignment); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = sctp_stream_request->send_buf_size; - lsr_size_req = sctp_stream_request->recv_buf_size; - loc_nodelay = sctp_stream_request->no_delay; - loc_rcvavoid = sctp_stream_request->so_rcvavoid; - loc_sndavoid = sctp_stream_request->so_sndavoid; - non_block = sctp_stream_request->non_blocking; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(sctp_stream_request->ipfamily), - sctp_stream_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(sctp_stream_request->ipfamily), - SOCK_STREAM, - IPPROTO_SCTP, - 0); - - s_listen = create_data_socket(local_res); - - if (s_listen < 0) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* what sort of sizes did we end-up with? */ - if (sctp_stream_request->receive_size == 0) { - if (lsr_size > 0) { - recv_size = lsr_size; - } - else { - recv_size = 4096; - } - } - else { - recv_size = sctp_stream_request->receive_size; - } - - /* we want to set-up our recv_ring in a manner analagous to what we */ - /* do on the sending side. this is more for the sake of symmetry */ - /* than for the needs of say copy avoidance, but it might also be */ - /* more realistic - this way one could conceivably go with a */ - /* double-buffering scheme when taking the data an putting it into */ - /* the filesystem or something like that. raj 7/94 */ - - if (recv_width == 0) { - recv_width = (lsr_size/recv_size) + 1; - if (recv_width == 1) recv_width++; - } - - recv_ring = allocate_buffer_ring(recv_width, - recv_size, - sctp_stream_request->recv_alignment, - sctp_stream_request->recv_offset); - - if (debug) { - fprintf(where,"recv_sctp_stream: set recv_size = %d, align = %d, offset = %d.\n", - recv_size, sctp_stream_request->recv_alignment, - sctp_stream_request->recv_offset); - fflush(where); - } - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == -1){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - sctp_stream_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - sctp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */ - if (sctp_stream_request->measure_cpu) { - sctp_stream_response->measure_cpu = 1; - sctp_stream_response->cpu_rate = - calibrate_local_cpu(sctp_stream_request->cpu_rate); - } - else { - sctp_stream_response->measure_cpu = 0; - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - sctp_stream_response->send_buf_size = lss_size; - sctp_stream_response->recv_buf_size = lsr_size; - sctp_stream_response->no_delay = loc_nodelay; - sctp_stream_response->so_rcvavoid = loc_rcvavoid; - sctp_stream_response->so_sndavoid = loc_sndavoid; - sctp_stream_response->receive_size = recv_size; - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == -1) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - send_response(); - - addrlen = sizeof(peeraddr); - - if ((s_data = accept(s_listen, - (struct sockaddr *)&peeraddr, - &addrlen)) == INVALID_SOCKET) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - exit(1); - } - - sctp_enable_events(s_data, SCTP_ASSOC_CHANGE_EV | SCTP_SHUTDOWN_EV); - - /* now that we are connected, mark the socket as non-blocking */ - if (non_block) { - fprintf(where, "setting socket as nonblocking\n"); - fflush(where); - if (!set_nonblock(s_data)) { - close(s_data); - exit(1); - } - } - -#ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass */ - /* attributes across an accept() call. Including this goes against */ - /* my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(sctp_stream_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to recv. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - - dirty_count = sctp_stream_request->dirty_count; - clean_count = sctp_stream_request->clean_count; - message_int_ptr = (int *)recv_ring->buffer_ptr; - for (i = 0; i < dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < clean_count; i++) { - dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - - bytes_received = 0; - receive_calls = 0; - - while ((len = sctp_recvmsg(s_data, - recv_ring->buffer_ptr, recv_size, - NULL, 0, NULL, &msg_flags)) != 0) { - if (len == SOCKET_ERROR) { - if (non_block && errno == EAGAIN) { - if (debug){ - fprintf(where, - "recv_sctp_stream: sctp_recvmsg timed out, trying again\n"); - fflush(where); - } - Set_errno(0); - continue; - } - if (debug) { - fprintf(where, - "recv_sctp_stream: sctp_recvmsg error %d, exiting", - errno); - fflush(where); - } - netperf_response.content.serv_errno = errno; - send_response(); - close(s_data); - exit(1); - } - - if (msg_flags & MSG_NOTIFICATION) { - msg_flags = 0; - if (debug) { - fprintf(where, - "recv_sctp_stream: Got notification... processing\n"); - fflush(where); - } - if (sctp_process_event(s_data, recv_ring->buffer_ptr) == SCTP_CLOSE) - break; /* break out of the recvmsg loop */ - - continue; - } - - bytes_received += len; - receive_calls++; - - /* more to the next buffer in the recv_ring */ - recv_ring = recv_ring->next; - -#ifdef PAUSE - sleep(1); -#endif /* PAUSE */ - -#ifdef DIRTY - message_int_ptr = (int *)(recv_ring->buffer_ptr); - for (i = 0; i < dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < clean_count; i++) { - dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - -#ifdef DO_SELECT - FD_SET(s_data,&readfds); - select(s_data+1,&readfds,NULL,NULL,&timeout); -#endif /* DO_SELECT */ - - } - - /* perform a shutdown to signal the sender that */ - /* we have received all the data sent. raj 4/93 */ - - if (close(s_data) == -1) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - cpu_stop(sctp_stream_request->measure_cpu,&elapsed_time); - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_sctp_stream: got %g bytes\n", - bytes_received); - fprintf(where, - "recv_sctp_stream: got %d recvs\n", - receive_calls); - fflush(where); - } - - sctp_stream_results->bytes_received = htond(bytes_received); - sctp_stream_results->elapsed_time = elapsed_time; - sctp_stream_results->recv_calls = receive_calls; - - if (sctp_stream_request->measure_cpu) { - sctp_stream_results->cpu_util = calc_cpu_util(0.0); - }; - - if (debug) { - fprintf(where, - "recv_sctp_stream: test complete, sending results.\n"); - fprintf(where, - " bytes_received %g receive_calls %d\n", - bytes_received, - receive_calls); - fprintf(where, - " len %d\n", - len); - fflush(where); - } - - sctp_stream_results->cpu_method = cpu_method; - sctp_stream_results->num_cpus = lib_num_loc_cpus; - send_response(); - - /* we are now done with the sockets */ - close(s_listen); - -} - - -/* This routine implements the SCTP unidirectional data transfer test */ -/* (a.k.a. stream) for the sockets interface. It receives its */ -/* parameters via global variables from the shell and writes its */ -/* output to the standard output. */ - - -void -send_sctp_stream_1toMany(remote_host) -char remote_host[]; -{ - - char *tput_title = "\ -Recv Send Send \n\ -Socket Socket Message Elapsed \n\ -Size Size Size Time Throughput \n\ -bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f \n"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Socket Socket Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - - char *cpu_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ -Local Remote Local Remote Xfered Per Per\n\ -Send Recv Send Recv Send (avg) Recv (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - - char *ksink_fmt2 = "\n\ -Maximum\n\ -Segment\n\ -Size (bytes)\n\ -%6d\n"; - - - float elapsed_time; - -#ifdef WANT_INTERVALS - int interval_count; - sigset_t signal_set; -#endif - - /* what we want is to have a buffer space that is at least one */ - /* send-size greater than our send window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - -#ifdef DIRTY - int *message_int_ptr; -#endif - - struct ring_elt *send_ring; - - int len; - unsigned int nummessages = 0; - int *send_socket; - int bytes_remaining; - int sctp_mss; - - /* with links like fddi, one can send > 32 bits worth of bytes */ - /* during a test... ;-) at some point, this should probably become a */ - /* 64bit integral type, but those are not entirely common yet */ - double bytes_sent = 0.0; - -#ifdef DIRTY - int i; -#endif /* DIRTY */ - int j; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - - double thruput; - - struct addrinfo *remote_res; - struct addrinfo *local_res; - struct addrinfo *last_remote_res; - struct addrinfo *last_local_res; - - struct sctp_stream_request_struct *sctp_stream_request; - struct sctp_stream_response_struct *sctp_stream_response; - struct sctp_stream_results_struct *sctp_stream_result; - - sctp_stream_request = - (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data; - sctp_stream_response = - (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data; - sctp_stream_result = - (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - time_hist = HIST_new(); -#endif /* WANT_HISTOGRAM */ - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_SEQPACKET, - IPPROTO_SCTP, - 0); - - if ( print_headers ) { - print_top_test_header("SCTP 1-TO-MANY STREAM TEST",local_res,remote_res); - } - - send_ring = NULL; - confidence_iteration = 1; - init_stat(); - - send_socket = malloc(sizeof (int) * num_associations); - if (send_socket == NULL) { - fprintf(where, "send_sctp_stream_1toMany: failed to allocation sockets!\n"); - exit(1); - } - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - int j=0; - int timed_out = 0; - - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - - /* at this point, we have either retrieved the socket buffer sizes, */ - /* or have tried to set them, so now, we may want to set the send */ - /* size based on that (because the user either did not use a -m */ - /* option, or used one with an argument of 0). If the socket buffer */ - /* size is not available, we will set the send size to 4KB - no */ - /* particular reason, just arbitrary... */ - if (send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - - /* set-up the data buffer ring with the requested alignment and offset. */ - /* note also that we have allocated a quantity */ - /* of memory that is at least one send-size greater than our socket */ - /* buffer size. We want to be sure that there are at least two */ - /* buffers allocated - this can be a bit of a problem when the */ - /* send_size is bigger than the socket size, so we must check... the */ - /* user may have wanted to explicitly set the "width" of our send */ - /* buffers, we should respect that wish... */ - if (send_width == 0) { - send_width = (lss_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - if (send_ring == NULL) { - /* only allocate the send ring once. this is a networking test, */ - /* not a memory allocation test. this way, we do not need a */ - /* deallocate_buffer_ring() routine, and I don't feel like */ - /* writing one anyway :) raj 11/94 */ - send_ring = allocate_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 1, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_SCTP_STREAM_MANY; - sctp_stream_request->send_buf_size = rss_size_req; - sctp_stream_request->recv_buf_size = rsr_size_req; - sctp_stream_request->receive_size = recv_size; - sctp_stream_request->no_delay = rem_nodelay; - sctp_stream_request->recv_alignment = remote_recv_align; - sctp_stream_request->recv_offset = remote_recv_offset; - sctp_stream_request->measure_cpu = remote_cpu_usage; - sctp_stream_request->cpu_rate = remote_cpu_rate; - if (test_time) { - sctp_stream_request->test_length = test_time; - } - else { - if (msg_count) - test_bytes = send_size * msg_count; - - sctp_stream_request->test_length = test_bytes*num_associations; - } - sctp_stream_request->so_rcvavoid = rem_rcvavoid; - sctp_stream_request->so_sndavoid = rem_sndavoid; -#ifdef DIRTY - sctp_stream_request->dirty_count = rem_dirty_count; - sctp_stream_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - sctp_stream_request->port = (atoi(remote_data_port)); - sctp_stream_request->ipfamily = af_to_nf(remote_res->ai_family); - sctp_stream_request->non_blocking = non_block; - - - if (debug > 1) { - fprintf(where, - "netperf: send_sctp_stream_1toMany: requesting sctp stream test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right*/ - /* after the connect returns. The remote will grab the counter right*/ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the sctp tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = sctp_stream_response->recv_buf_size; - rss_size = sctp_stream_response->send_buf_size; - rem_nodelay = sctp_stream_response->no_delay; - remote_cpu_usage= sctp_stream_response->measure_cpu; - remote_cpu_rate = sctp_stream_response->cpu_rate; - - /* we have to make sure that the server port number is in */ - /* network order */ - set_port_number(remote_res, (unsigned short)sctp_stream_response->data_port_number); - rem_rcvavoid = sctp_stream_response->so_rcvavoid; - rem_sndavoid = sctp_stream_response->so_sndavoid; - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /*set up the the array of data sockets and connect them to the server */ - - for (j = 0; j < num_associations; j++) { - send_socket[j] = create_data_socket(local_res); - - if (send_socket[j] < 0){ - perror("netperf: send_sctp_stream_1toMany: sctp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_sctp_stream_1toMany: send_socket obtained...\n"); - } - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket[j], - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("netperf: send_sctp_stream_1toMany: data socket connect failed"); - exit(1); - } - - /* Do it after connect is successfull, so that we don't see COMM_UP */ - sctp_enable_events(send_socket[j], SCTP_ASSOC_CHANGE_EV); - - if (non_block) { - /* now that we are connected, mark the socket as non-blocking */ - if (!set_nonblock(send_socket[j])) { - perror("netperf: fcntl"); - exit(1); - } - } - } - - /* Data Socket set-up is finished. If there were problems, either */ - /* the connect would have failed, or the previous response would */ - /* have indicated a problem. I failed to see the value of the */ - /* extra message after the accept on the remote. If it failed, */ - /* we'll see it here. If it didn't, we might as well start pumping */ - /* data. */ - - /* Set-up the test end conditions. For a stream test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - /* in previous revisions, we had the same code repeated throught */ - /* all the test suites. this was unnecessary, and meant more */ - /* work for me when I wanted to switch to POSIX signals, so I */ - /* have abstracted this out into a routine in netlib.c. if you */ - /* are experiencing signal problems, you might want to look */ - /* there. raj 11/94 */ - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - bytes_remaining = test_bytes * num_associations; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - if ((interval_burst) || (demo_mode)) { - /* zero means that we never pause, so we never should need the */ - /* interval timer, unless we are in demo_mode */ - start_itimer(interval_wate); - } - interval_count = interval_burst; - /* get the signal set for the call to sigsuspend */ - if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { - fprintf(where, - "send_sctp_stream_1toMany: unable to get sigmask errno %d\n", - errno); - fflush(where); - exit(1); - } -#endif /* WANT_INTERVALS */ - -#ifdef DIRTY - /* initialize the random number generator for putting dirty stuff */ - /* into the send buffer. raj */ - srand((int) getpid()); -#endif - - /* before we start, initialize a few variables */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. */ - - while ((!times_up) || (bytes_remaining > 0)) { - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. at some point, we might want to replace */ - /* the rand() call with something from a table to reduce our call */ - /* overhead during the test, but it is not a high priority item. */ - message_int_ptr = (int *)(send_ring->buffer_ptr); - for (i = 0; i < loc_dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < loc_clean_count; i++) { - loc_dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - -#ifdef WANT_HISTOGRAM - /* timestamp just before we go into send and then again just after */ - /* we come out raj 8/94 */ - gettimeofday(&time_one,NULL); -#endif /* WANT_HISTOGRAM */ - - for (j = 0; j < num_associations; j++) { - - if((len=sctp_sendmsg(send_socket[j], - send_ring->buffer_ptr, - send_size, - (struct sockaddr *)remote_res->ai_addr, - remote_res->ai_addrlen, - 0, 0, 0, 0, 0)) != send_size) { - if ((len >=0) || SOCKET_EINTR(len)) { - /* the test was interrupted, must be the end of test */ - timed_out = 1; - break; - } else if (non_block && errno == EAGAIN) { - j--; /* send again on the same socket */ - Set_errno(0); - continue; - } - perror("netperf: data send error"); - printf("len was %d\n",len); - exit(1); - } - } - - if (timed_out) - break; /* test is over, try next iteration */ - -#ifdef WANT_HISTOGRAM - /* timestamp the exit from the send call and update the histogram */ - gettimeofday(&time_two,NULL); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_INTERVALS - if (demo_mode) { - units_this_tick += send_size; - } - /* in this case, the interval count is the count-down couter */ - /* to decide to sleep for a little bit */ - if ((interval_burst) && (--interval_count == 0)) { - /* call sigsuspend and wait for the interval timer to get us */ - /* out */ - if (debug > 1) { - fprintf(where,"about to suspend\n"); - fflush(where); - } - if (sigsuspend(&signal_set) == EFAULT) { - fprintf(where, - "send_sctp_stream_1toMany: fault with sigsuspend.\n"); - fflush(where); - exit(1); - } - interval_count = interval_burst; - } -#endif /* WANT_INTERVALS */ - - /* now we want to move our pointer to the next position in the */ - /* data buffer...we may also want to wrap back to the "beginning" */ - /* of the bufferspace, so we will mod the number of messages sent */ - /* by the send width, and use that to calculate the offset to add */ - /* to the base pointer. */ - nummessages++; - send_ring = send_ring->next; - if (bytes_remaining) { - bytes_remaining -= send_size; - } - } - - /* The test is over. Flush the buffers to the remote end. We do a */ - /* graceful release to insure that all data has been taken by the */ - /* remote. */ - - /* but first, if the verbosity is greater than 1, find-out what */ - /* the sctp maximum segment_size was (if possible) */ - if (verbosity > 1) { - sctp_mss = -1; - get_sctp_info(send_socket[0], &sctp_mss); - } - - /* signal the server that we are all done writing, this will - * initiate a shutdonw of one of the associations on the - * server and trigger an event telling the server it's all done - */ - sctp_sendmsg(send_socket[0], NULL, 0, remote_res->ai_addr, - remote_res->ai_addrlen, 0, MSG_EOF, 0, 0, 0); - - - /* The test server will initiate closure of all associations - * when it's done reading. We want a basic mechanism to catch this - * and are using SCTP events for this. - * In blocking mode, we can call recvmsg with the last socket we created. - * In non-blocking mode, we need to select on the socket for reading. - * We'll assume that all returns are succefull and signify - * closure. - * It is sufficient to do this on a single socket in the client. - * We choose to do it on a socket other then the one that send MSG_EOF. - * This means that anything comming in on that socket will be a shutdown. - */ - if (non_block) { - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(send_socket[num_associations-1], &readfds); - select(send_socket[num_associations-1]+1, &readfds, NULL, NULL, NULL); - } else { - sctp_recvmsg(send_socket[num_associations], send_ring->buffer_ptr, - send_size, NULL, 0, NULL, 0); - } - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured and how */ - /* long did we really */ - /* run? */ - - /* we are finished with our sockets, so close them to prevent hitting */ - /* the limit on maximum open files. */ - for (j = 0; j < num_associations; j++) - close(send_socket[j]); - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a sctp stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) */ - - bytes_sent = ntohd(sctp_stream_result->bytes_received); - - thruput = (double) calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - - remote_cpu_utilization = sctp_stream_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - sctp_stream_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - } - - /* at this point, we have finished making all the runs that we */ - /* will be making. so, we should extract what the calcuated values */ - /* are for all the confidence stuff. we could make the values */ - /* global, but that seemed a little messy, and it did not seem worth */ - /* all the mucking with header files. so, we create a routine much */ - /* like calcualte_confidence, which just returns the mean values. */ - /* raj 11/94 */ - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(sctp_stream_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - fprintf(where, - tput_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - thruput);/* how fast did it go */ - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* sctp statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - /* this stuff needs to be worked-out in the presence of confidence */ - /* intervals and multiple iterations of the test... raj 11/94 */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_send_align, - remote_recv_align, - local_send_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)sctp_stream_result->recv_calls, - sctp_stream_result->recv_calls); - fprintf(where, - ksink_fmt2, - sctp_mss); - fflush(where); -#ifdef WANT_HISTOGRAM - fprintf(where,"\n\nHistogram of time spent in send() call.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } - -} - - - -/* This is the server-side routine for the sctp stream test. It is */ -/* implemented as one routine. I could break things-out somewhat, but */ -/* didn't feel it was necessary. */ - -void -recv_sctp_stream_1toMany() -{ - - struct sockaddr_in myaddr_in; - int s_recv; - int addrlen; - int len; - unsigned int receive_calls; - float elapsed_time; - double bytes_received; - int msg_flags = 0; - - struct ring_elt *recv_ring; - - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - -#ifdef DIRTY - int *message_int_ptr; - int dirty_count; - int clean_count; - int i; -#endif - -#ifdef DO_SELECT - fd_set readfds; - struct timeval timeout; -#endif - - struct sctp_stream_request_struct *sctp_stream_request; - struct sctp_stream_response_struct *sctp_stream_response; - struct sctp_stream_results_struct *sctp_stream_results; - -#ifdef DO_SELECT - FD_ZERO(&readfds); - timeout.tv_sec = 1; - timeout.tv_usec = 0; -#endif - - sctp_stream_request = - (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data; - sctp_stream_response = - (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data; - sctp_stream_results = - (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_sctp_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_sctp_stream_1toMany: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = SCTP_STREAM_MANY_RESPONSE; - - if (debug) { - fprintf(where,"recv_sctp_stream_1toMany: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug) { - fprintf(where,"recv_sctp_stream_1toMany: requested alignment of %d\n", - sctp_stream_request->recv_alignment); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = sctp_stream_request->send_buf_size; - lsr_size_req = sctp_stream_request->recv_buf_size; - loc_nodelay = sctp_stream_request->no_delay; - loc_rcvavoid = sctp_stream_request->so_rcvavoid; - loc_sndavoid = sctp_stream_request->so_sndavoid; - non_block = sctp_stream_request->non_blocking; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(sctp_stream_request->ipfamily), - sctp_stream_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(sctp_stream_request->ipfamily), - SOCK_SEQPACKET, - IPPROTO_SCTP, - 0); - - s_recv = create_data_socket(local_res); - - if (s_recv < 0) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* what sort of sizes did we end-up with? */ - if (sctp_stream_request->receive_size == 0) { - if (lsr_size > 0) { - recv_size = lsr_size; - } - else { - recv_size = 4096; - } - } - else { - recv_size = sctp_stream_request->receive_size; - } - - /* we want to set-up our recv_ring in a manner analagous to what we */ - /* do on the sending side. this is more for the sake of symmetry */ - /* than for the needs of say copy avoidance, but it might also be */ - /* more realistic - this way one could conceivably go with a */ - /* double-buffering scheme when taking the data an putting it into */ - /* the filesystem or something like that. raj 7/94 */ - - if (recv_width == 0) { - recv_width = (lsr_size/recv_size) + 1; - if (recv_width == 1) recv_width++; - } - - recv_ring = allocate_buffer_ring(recv_width, - recv_size, - sctp_stream_request->recv_alignment, - sctp_stream_request->recv_offset); - - if (debug) { - fprintf(where,"recv_sctp_stream: receive alignment and offset set...\n"); - fflush(where); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_recv, 5) == -1) { - netperf_response.content.serv_errno = errno; - close(s_recv); - send_response(); - - exit(1); - } - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_recv, - (struct sockaddr *)&myaddr_in, - &addrlen) == -1){ - netperf_response.content.serv_errno = errno; - close(s_recv); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - sctp_stream_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - sctp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */ - if (sctp_stream_request->measure_cpu) { - sctp_stream_response->measure_cpu = 1; - sctp_stream_response->cpu_rate = - calibrate_local_cpu(sctp_stream_request->cpu_rate); - } - else { - sctp_stream_response->measure_cpu = 0; - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - sctp_stream_response->send_buf_size = lss_size; - sctp_stream_response->recv_buf_size = lsr_size; - sctp_stream_response->no_delay = loc_nodelay; - sctp_stream_response->so_rcvavoid = loc_rcvavoid; - sctp_stream_response->so_sndavoid = loc_sndavoid; - sctp_stream_response->receive_size = recv_size; - - send_response(); - - - sctp_enable_events(s_recv, SCTP_ASSOC_CHANGE_EV | SCTP_SHUTDOWN_EV); - - /* now that we are connected, mark the socket as non-blocking */ - if (non_block) { - if (!set_nonblock(s_recv)) { - close(s_recv); - exit(1); - } - } - - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(sctp_stream_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to recv. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - - dirty_count = sctp_stream_request->dirty_count; - clean_count = sctp_stream_request->clean_count; - message_int_ptr = (int *)recv_ring->buffer_ptr; - for (i = 0; i < dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < clean_count; i++) { - dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - - bytes_received = 0; - receive_calls = 0; - - while ((len = sctp_recvmsg(s_recv, recv_ring->buffer_ptr, recv_size, - NULL, 0, /* we don't care who it's from */ - NULL, &msg_flags)) != 0) { - if (len < 0) { - if (non_block && errno == EAGAIN) { - Set_errno(0); - continue; - } - netperf_response.content.serv_errno = errno; - send_response(); - close(s_recv); - exit(1); - } - - if (msg_flags & MSG_NOTIFICATION) { - if (sctp_process_event(s_recv, recv_ring->buffer_ptr) == SCTP_CLOSE) - break; - - continue; - } - - bytes_received += len; - receive_calls++; - - /* more to the next buffer in the recv_ring */ - recv_ring = recv_ring->next; - -#ifdef PAUSE - sleep(1); -#endif /* PAUSE */ - -#ifdef DIRTY - message_int_ptr = (int *)(recv_ring->buffer_ptr); - for (i = 0; i < dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < clean_count; i++) { - dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - -#ifdef DO_SELECT - FD_SET(s_recv,&readfds); - select(s_recv+1,&readfds,NULL,NULL,&timeout); -#endif /* DO_SELECT */ - - } - - /* perform a shutdown to signal the sender. in this case, sctp - * will close all associations on this socket - */ - if (close(s_recv) == -1) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - cpu_stop(sctp_stream_request->measure_cpu,&elapsed_time); - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_sctp_stream: got %g bytes\n", - bytes_received); - fprintf(where, - "recv_sctp_stream: got %d recvs\n", - receive_calls); - fflush(where); - } - - sctp_stream_results->bytes_received = htond(bytes_received); - sctp_stream_results->elapsed_time = elapsed_time; - sctp_stream_results->recv_calls = receive_calls; - - if (sctp_stream_request->measure_cpu) { - sctp_stream_results->cpu_util = calc_cpu_util(0.0); - }; - - if (debug) { - fprintf(where, - "recv_sctp_stream: test complete, sending results.\n"); - fprintf(where, - " bytes_received %g receive_calls %d\n", - bytes_received, - receive_calls); - fprintf(where, - " len %d\n", - len); - fflush(where); - } - - sctp_stream_results->cpu_method = cpu_method; - sctp_stream_results->num_cpus = lib_num_loc_cpus; - send_response(); -} - - - /* this routine implements the sending (netperf) side of the SCTP_RR */ - /* test. */ - -void -send_sctp_rr(remote_host) - char remote_host[]; -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - int timed_out = 0; - float elapsed_time; - - int len; - char *temp_message_ptr; - int nummessages; - int send_socket; - int trans_remaining; - int msg_flags = 0; - double bytes_xferd; - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - int rsp_bytes_left; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct sockaddr_storage peer; - struct addrinfo *remote_res; - struct addrinfo *local_res; - - struct sctp_rr_request_struct *sctp_rr_request; - struct sctp_rr_response_struct *sctp_rr_response; - struct sctp_rr_results_struct *sctp_rr_result; - -#ifdef WANT_INTERVALS - int interval_count; - sigset_t signal_set; -#endif /* WANT_INTERVALS */ - - sctp_rr_request = - (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data; - sctp_rr_response = - (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data; - sctp_rr_result = - (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - time_hist = HIST_new(); -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - /* complete_addrinfos will either succede or exit the process */ - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_SCTP, - 0); - - if ( print_headers ) { - print_top_test_header("SCTP REQUEST/RESPONSE TEST", local_res, remote_res); - } - - /* initialize a few counters */ - - send_ring = NULL; - recv_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - timed_out = 0; - trans_remaining = 0; - - /* set-up the data buffers with the requested alignment and offset. */ - /* since this is a request/response test, default the send_width and */ - /* recv_width to 1 and not two raj 7/94 */ - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - if (send_ring == NULL) { - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - } - - if (recv_ring == NULL) { - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - } - - /*set up the data socket */ - send_socket = create_data_socket(local_res); - - if (send_socket < 0){ - perror("netperf: send_sctp_rr: sctp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_sctp_rr: send_socket obtained...\n"); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_SCTP_RR; - sctp_rr_request->recv_buf_size = rsr_size_req; - sctp_rr_request->send_buf_size = rss_size_req; - sctp_rr_request->recv_alignment = remote_recv_align; - sctp_rr_request->recv_offset = remote_recv_offset; - sctp_rr_request->send_alignment = remote_send_align; - sctp_rr_request->send_offset = remote_send_offset; - sctp_rr_request->request_size = req_size; - sctp_rr_request->response_size = rsp_size; - sctp_rr_request->no_delay = rem_nodelay; - sctp_rr_request->measure_cpu = remote_cpu_usage; - sctp_rr_request->cpu_rate = remote_cpu_rate; - sctp_rr_request->so_rcvavoid = rem_rcvavoid; - sctp_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - sctp_rr_request->test_length = test_time; - } - else { - sctp_rr_request->test_length = test_trans * -1; - } - sctp_rr_request->non_blocking = non_block; - sctp_rr_request->ipfamily = af_to_nf(remote_res->ai_family); - - if (debug > 1) { - fprintf(where,"netperf: send_sctp_rr: requesting SCTP rr test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right*/ - /* after the connect returns. The remote will grab the counter right*/ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the sctp tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = sctp_rr_response->recv_buf_size; - rss_size = sctp_rr_response->send_buf_size; - rem_nodelay = sctp_rr_response->no_delay; - remote_cpu_usage = sctp_rr_response->measure_cpu; - remote_cpu_rate = sctp_rr_response->cpu_rate; - /* make sure that port numbers are in network order */ - set_port_number(remote_res, - (unsigned short)sctp_rr_response->data_port_number); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) <0){ - perror("netperf: send_sctp_rr data socket connect failed"); - exit(1); - } - - /* don't need events for 1-to-1 API with request-response tests */ - sctp_enable_events(send_socket, 0); - - /* set non-blocking if needed */ - if (non_block) { - if (!set_nonblock(send_socket)) { - close(send_socket); - exit(1); - } - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - if ((interval_burst) || (demo_mode)) { - /* zero means that we never pause, so we never should need the */ - /* interval timer, unless we are in demo_mode */ - start_itimer(interval_wate); - } - interval_count = interval_burst; - /* get the signal set for the call to sigsuspend */ - if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { - fprintf(where, - "send_sctp_rr: unable to get sigmask errno %d\n", - errno); - fflush(where); - exit(1); - } -#endif /* WANT_INTERVALS */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - -#ifdef WANT_FIRST_BURST - { - int i; - for (i = 0; i < first_burst_size; i++) { - if((len=sctp_sendmsg(send_socket, - send_ring->buffer_ptr, req_size, - NULL, 0, /* don't need addrs with 1-to-1 */ - 0, 0, 0, 0, 0)) != req_size) { - /* we should never hit the end of the test in the first burst */ - perror("send_sctp_rr: initial burst data send error"); - exit(1); - } - } - } -#endif /* WANT_FIRST_BURST */ - - while ((!times_up) || (trans_remaining > 0)) { - /* send the request. we assume that if we use a blocking socket, */ - /* the request will be sent at one shot. */ - -#ifdef WANT_HISTOGRAM - /* timestamp just before our call to send, and then again just */ - /* after the receive raj 8/94 */ - HIST_timestamp(&time_one); -#endif /* WANT_HISTOGRAM */ - - while ((len=sctp_sendmsg(send_socket, - send_ring->buffer_ptr, req_size, - NULL, 0, /* don't need addrs with 1-to-1 */ - 0, 0, 0, 0, 0)) != req_size) { - if (non_block && errno == EAGAIN) { - /* try sending again */ - continue; - } else if (SOCKET_EINTR(len) || (errno == 0)) { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("send_sctp_rr: data send error"); - exit(1); - } - - if (timed_out) { - /* we timed out while sending. break out another level */ - break; - } - send_ring = send_ring->next; - - /* receive the response */ - rsp_bytes_left = rsp_size; - temp_message_ptr = recv_ring->buffer_ptr; - do { - msg_flags = 0; - if ((rsp_bytes_recvd=sctp_recvmsg(send_socket, - temp_message_ptr, rsp_bytes_left, - NULL, 0, - NULL, &msg_flags)) < 0) { - if (errno == EINTR) { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } else if (non_block && errno == EAGAIN) { - continue; - } - perror("send_sctp_rr: data recv error"); - exit(1); - } - rsp_bytes_left -= rsp_bytes_recvd; - temp_message_ptr += rsp_bytes_recvd; - } while (!(msg_flags & MSG_EOR)); - - recv_ring = recv_ring->next; - - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - -#ifdef WANT_HISTOGRAM - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); -#endif /* WANT_HISTOGRAM */ -#ifdef WANT_INTERVALS - if (demo_mode) { - units_this_tick += 1; - } - /* in this case, the interval count is the count-down couter */ - /* to decide to sleep for a little bit */ - if ((interval_burst) && (--interval_count == 0)) { - /* call sigsuspend and wait for the interval timer to get us */ - /* out */ - if (debug > 1) { - fprintf(where,"about to suspend\n"); - fflush(where); - } - if (sigsuspend(&signal_set) == EFAULT) { - fprintf(where, - "send_sctp_rr: fault with signal set!\n"); - fflush(where); - exit(1); - } - interval_count = interval_burst; - } -#endif /* WANT_INTERVALS */ - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - if ((nummessages % 100) == 0) { - fprintf(where, - "Transaction %d completed\n", - nummessages); - fflush(where); - } - } - } - - /* At this point we used to call shutdown on the data socket to be */ - /* sure all the data was delivered, but this was not germane in a */ - /* request/response test, and it was causing the tests to "hang" when */ - /* they were being controlled by time. So, I have replaced this */ - /* shutdown call with a call to close that can be found later in the */ - /* procedure. */ - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured? how long */ - /* did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated CPU utilization. If it wasn't supposed to care, it */ - /* will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where,"netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - - /* We now calculate what our throughput was for the test. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = nummessages/elapsed_time; - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - remote_cpu_utilization = sctp_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - sctp_rr_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - - /* we are now done with the socket, so close it */ - close(send_socket); - - } - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(sctp_rr_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - thruput, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - thruput); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - /* how to handle the verbose information in the presence of */ - /* confidence intervals is yet to be determined... raj 11/94 */ - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt, - local_send_align, - remote_recv_offset, - local_send_offset, - remote_recv_offset); - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/response times\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - - } - -} - - - /* this routine implements the receive (netserver) side of a TCP_RR */ - /* test */ -void -recv_sctp_rr() -{ - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - - struct sockaddr_in myaddr_in, peeraddr_in; - int s_listen, s_data; - int addrlen; - char *temp_message_ptr; - int trans_received; - int trans_remaining; - int bytes_sent; - int request_bytes_recvd; - int request_bytes_remaining; - int timed_out = 0; - float elapsed_time; - - struct sctp_rr_request_struct *sctp_rr_request; - struct sctp_rr_response_struct *sctp_rr_response; - struct sctp_rr_results_struct *sctp_rr_results; - - sctp_rr_request = - (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data; - sctp_rr_response = - (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data; - sctp_rr_results = - (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_sctp_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_sctp_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = SCTP_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_sctp_rr: the response type is set...\n"); - fflush(where); - } - - /* allocate the recv and send rings with the requested alignments */ - /* and offsets. raj 7/94 */ - if (debug) { - fprintf(where,"recv_sctp_rr: requested recv alignment of %d offset %d\n", - sctp_rr_request->recv_alignment, - sctp_rr_request->recv_offset); - fprintf(where,"recv_sctp_rr: requested send alignment of %d offset %d\n", - sctp_rr_request->send_alignment, - sctp_rr_request->send_offset); - fflush(where); - } - - /* at some point, these need to come to us from the remote system */ - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - sctp_rr_request->response_size, - sctp_rr_request->send_alignment, - sctp_rr_request->send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - sctp_rr_request->request_size, - sctp_rr_request->recv_alignment, - sctp_rr_request->recv_offset); - - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_sctp_rr: grabbing a socket...\n"); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = sctp_rr_request->send_buf_size; - lsr_size_req = sctp_rr_request->recv_buf_size; - loc_nodelay = sctp_rr_request->no_delay; - loc_rcvavoid = sctp_rr_request->so_rcvavoid; - loc_sndavoid = sctp_rr_request->so_sndavoid; - non_block = sctp_rr_request->non_blocking; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(sctp_rr_request->ipfamily), - sctp_rr_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(sctp_rr_request->ipfamily), - SOCK_STREAM, - IPPROTO_SCTP, - 0); - - s_listen = create_data_socket(local_res); - - if (s_listen < 0) { - netperf_response.content.serv_errno = errno; - send_response(); - - exit(1); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == -1) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, &addrlen) == -1){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - sctp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - sctp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */ - sctp_rr_response->measure_cpu = 0; - - if (sctp_rr_request->measure_cpu) { - sctp_rr_response->measure_cpu = 1; - sctp_rr_response->cpu_rate = calibrate_local_cpu(sctp_rr_request->cpu_rate); - } - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - sctp_rr_response->send_buf_size = lss_size; - sctp_rr_response->recv_buf_size = lsr_size; - sctp_rr_response->no_delay = loc_nodelay; - sctp_rr_response->so_rcvavoid = loc_rcvavoid; - sctp_rr_response->so_sndavoid = loc_sndavoid; - sctp_rr_response->test_length = sctp_rr_request->test_length; - send_response(); - - addrlen = sizeof(peeraddr_in); - - if ((s_data = accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == -1) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - - exit(1); - } - - /* we do not need events on a 1-to-1 RR test. The test will finish - * once all transactions are done. - */ - - /* now that we are connected, mark the socket as non-blocking */ - if (non_block) { - if (!set_nonblock(s_data)) { - perror("netperf: set_nonblock"); - exit(1); - } - } - -#ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass */ - /* attributes across an accept() call. Including this goes against */ - /* my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - - if (debug) { - fprintf(where,"recv_sctp_rr: accept completes on the data connection.\n"); - fflush(where); - } - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(sctp_rr_request->measure_cpu); - - /* The loop will exit when we hit the end of the test time, or when */ - /* we have exchanged the requested number of transactions. */ - - if (sctp_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(sctp_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = sctp_rr_request->test_length * -1; - } - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - int msg_flags = 0; - - temp_message_ptr = recv_ring->buffer_ptr; - request_bytes_remaining = sctp_rr_request->request_size; - while(!(msg_flags & MSG_EOR)) { - if((request_bytes_recvd=sctp_recvmsg(s_data, - temp_message_ptr, - request_bytes_remaining, - NULL, 0, - NULL, &msg_flags)) < 0) { - if (errno == EINTR) { - /* the timer popped */ - timed_out = 1; - break; - } else if (non_block && errno == EAGAIN) { - continue; /* while request_bytes_remaining */ - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - request_bytes_remaining -= request_bytes_recvd; - temp_message_ptr += request_bytes_recvd; - } - - recv_ring = recv_ring->next; - - if (timed_out) { - /* we hit the end of the test based on time - lets */ - /* bail out of here now... */ - if (debug) { - fprintf(where,"yo55\n"); - fflush(where); - } - break; - } - - - /* Now, send the response to the remote - * In 1-to-1 API destination addr is not needed. - */ - while ((bytes_sent=sctp_sendmsg(s_data, - send_ring->buffer_ptr, - sctp_rr_request->response_size, - NULL, 0, - 0, 0, 0, 0, 0)) == -1) { - if (errno == EINTR) { - /* the test timer has popped */ - timed_out = 1; - break; - } else if (non_block && errno == EAGAIN) { - continue; - } - - netperf_response.content.serv_errno = 982; - send_response(); - exit(1); - } - - if (timed_out) { - /* we hit the end of the test based on time - lets */ - /* bail out of here now... */ - if (debug) { - fprintf(where,"yo6\n"); - fflush(where); - } - break; - } - - send_ring = send_ring->next; - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(sctp_rr_request->measure_cpu,&elapsed_time); - - stop_timer(); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_sctp_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - sctp_rr_results->bytes_received = (trans_received * - (sctp_rr_request->request_size + - sctp_rr_request->response_size)); - sctp_rr_results->trans_received = trans_received; - sctp_rr_results->elapsed_time = elapsed_time; - sctp_rr_results->cpu_method = cpu_method; - sctp_rr_results->num_cpus = lib_num_loc_cpus; - if (sctp_rr_request->measure_cpu) { - sctp_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_sctp_rr: test complete, sending results.\n"); - fflush(where); - } - - /* we are now done with the sockets */ - send_response(); - - close(s_data); - close(s_listen); - -} - - - -/* this routine implements the sending (netperf) side of the - SCTP_RR_1TOMANY test */ - -void -send_sctp_rr_1toMany(remote_host) - char remote_host[]; -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - int timed_out = 0; - float elapsed_time; - - int len, j = 0; - char *temp_message_ptr; - int nummessages; - int *send_socket; - int trans_remaining; - double bytes_xferd; - int msg_flags = 0; - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - int rsp_bytes_left; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct sockaddr_storage peer; - struct addrinfo *local_res; - struct addrinfo *remote_res; - - struct sctp_rr_request_struct *sctp_rr_request; - struct sctp_rr_response_struct *sctp_rr_response; - struct sctp_rr_results_struct *sctp_rr_result; - -#ifdef WANT_INTERVALS - int interval_count; - sigset_t signal_set; -#endif /* WANT_INTERVALS */ - - sctp_rr_request = - (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data; - sctp_rr_response = - (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data; - sctp_rr_result = - (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - time_hist = HIST_new(); -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_SEQPACKET, - IPPROTO_SCTP, - 0); - - if ( print_headers ) { - print_top_test_header("SCTP 1-TO-MANY REQUEST/RESPONSE TEST",local_res,remote_res); - } - - /* initialize a few counters */ - - send_ring = NULL; - recv_ring = NULL; - confidence_iteration = 1; - init_stat(); - - send_socket = malloc(sizeof(int) * num_associations); - if (send_socket == NULL) { - fprintf(where, - "Could not create the socket array for %d associations", - num_associations); - fflush(where); - exit(1); - } - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - timed_out = 0; - trans_remaining = 0; - - /* set-up the data buffers with the requested alignment and offset. */ - /* since this is a request/response test, default the send_width and */ - /* recv_width to 1 and not two raj 7/94 */ - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - if (send_ring == NULL) { - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - } - - if (recv_ring == NULL) { - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_SCTP_RR_MANY; - sctp_rr_request->recv_buf_size = rsr_size_req; - sctp_rr_request->send_buf_size = rss_size_req; - sctp_rr_request->recv_alignment = remote_recv_align; - sctp_rr_request->recv_offset = remote_recv_offset; - sctp_rr_request->send_alignment = remote_send_align; - sctp_rr_request->send_offset = remote_send_offset; - sctp_rr_request->request_size = req_size; - sctp_rr_request->response_size = rsp_size; - sctp_rr_request->no_delay = rem_nodelay; - sctp_rr_request->measure_cpu = remote_cpu_usage; - sctp_rr_request->cpu_rate = remote_cpu_rate; - sctp_rr_request->so_rcvavoid = rem_rcvavoid; - sctp_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - sctp_rr_request->test_length = test_time; - } - else { - sctp_rr_request->test_length = test_trans * num_associations - * -1; - } - sctp_rr_request->non_blocking = non_block; - sctp_rr_request->port = atoi(remote_data_port); - sctp_rr_request->ipfamily = af_to_nf(remote_res->ai_family); - if (debug > 1) { - fprintf(where,"netperf: send_sctp_rr_1toMany: requesting SCTP rr test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right*/ - /* after the connect returns. The remote will grab the counter right*/ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the sctp tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - rsr_size = sctp_rr_response->recv_buf_size; - rss_size = sctp_rr_response->send_buf_size; - rem_nodelay = sctp_rr_response->no_delay; - remote_cpu_usage = sctp_rr_response->measure_cpu; - remote_cpu_rate = sctp_rr_response->cpu_rate; - /* make sure that port numbers are in network order */ - set_port_number(remote_res, - (unsigned short)sctp_rr_response->data_port_number); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /*set up the data socket list */ - for (j = 0; j < num_associations; j++) { - send_socket[j] = create_data_socket(local_res); - - if (send_socket < 0){ - perror("netperf: send_sctp_rr_1toMany: sctp stream data socket"); - exit(1); - } - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket[j], - remote_res->ai_addr, - remote_res->ai_addrlen) < 0){ - perror("netperf: data socket connect failed"); - - exit(1); - } - - /* The client end of the 1-to-Many test uses 1-to-1 sockets. - * it doesn't need events. - */ - sctp_enable_events(send_socket[j], 0); - - if (non_block) { - if (!set_nonblock(send_socket[j])) { - close(send_socket[j]); - exit(1); - } - } - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes * num_associations; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - if ((interval_burst) || (demo_mode)) { - /* zero means that we never pause, so we never should need the */ - /* interval timer, unless we are in demo_mode */ - start_itimer(interval_wate); - } - interval_count = interval_burst; - /* get the signal set for the call to sigsuspend */ - if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { - fprintf(where, - "send_sctp_rr_1toMany: unable to get sigmask errno %d\n", - errno); - fflush(where); - exit(1); - } -#endif /* WANT_INTERVALS */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - -#ifdef WANT_FIRST_BURST - { - int i; - for (j = 0; j < num_associations; j++) { - for (i = 0; i < first_burst_size; i++) { - if((len=sctp_sendmsg(send_socket[j], - send_ring->buffer_ptr, send_size, - remote_res->ai_addr, - remote_res->ai_addrlen, - 0, 0, 0, 0, 0)) != req_size) { - /* we should never hit the end of the test in the first burst */ - perror("send_sctp_rr_1toMany: initial burst data send error"); - exit(1); - } - } - } - } -#endif /* WANT_FIRST_BURST */ - - while ((!times_up) || (trans_remaining > 0)) { - /* send the request. we assume that if we use a blocking socket, */ - /* the request will be sent at one shot. */ - - /* this is a fairly poor way of testing 1toMany connections. - * For each association we measure round trip time to account for - * any delay in lookups and delivery. To stress the server a bit - * more we would need a distributed client test, or at least multiple - * processes. I want to force as much paralellism as possible, but - * this will do for the fist take. vlad - */ - for (j = 0; j < num_associations; j++) { -#ifdef WANT_HISTOGRAM - /* timestamp just before our call to send, and then again just */ - /* after the receive raj 8/94 */ - gettimeofday(&time_one,NULL); -#endif /* WANT_HISTOGRAM */ - - while ((len=sctp_sendmsg(send_socket[j], - send_ring->buffer_ptr, send_size, - remote_res->ai_addr, - remote_res->ai_addrlen, - 0, 0, 0, 0, 0)) != req_size) { - if (non_block && errno == EAGAIN) { - /* try sending again */ - continue; - } else if ((errno == EINTR) || (errno == 0)) { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("send_sctp_rr_1toMany: data send error"); - exit(1); - } - - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - - /* setup for the next time */ - send_ring = send_ring->next; - - rsp_bytes_left = rsp_size; - temp_message_ptr = recv_ring->buffer_ptr; - while (!(msg_flags & MSG_EOR)) { - if((rsp_bytes_recvd = sctp_recvmsg(send_socket[j], - temp_message_ptr, - rsp_bytes_left, - NULL, 0, - NULL, &msg_flags)) < 0) { - if (errno == EINTR) { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } else if (non_block && errno == EAGAIN) { - continue; - } - perror("send_sctp_rr_1toMany: data recv error"); - exit(1); - } - rsp_bytes_left -= rsp_bytes_recvd; - temp_message_ptr += rsp_bytes_recvd; - } - recv_ring = recv_ring->next; - - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - -#ifdef WANT_HISTOGRAM - gettimeofday(&time_two,NULL); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); -#endif /* WANT_HISTOGRAM */ - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - if ((nummessages % 100) == 0) { - fprintf(where, - "Transaction %d completed\n", - nummessages); - fflush(where); - } - } - } - } - - /* At this point we used to call shutdown on the data socket to be */ - /* sure all the data was delivered, but this was not germane in a */ - /* request/response test, and it was causing the tests to "hang" when */ - /* they were being controlled by time. So, I have replaced this */ - /* shutdown call with a call to close that can be found later in the */ - /* procedure. */ - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured? how long */ - /* did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated CPU utilization. If it wasn't supposed to care, it */ - /* will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where,"netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - - /* We now calculate what our throughput was for the test. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = nummessages/elapsed_time; - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - remote_cpu_utilization = sctp_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - sctp_rr_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - - /* we are now done with the socket, so close it */ - for (j = 0; j < num_associations; j++) - close(send_socket[j]); - } - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(sctp_rr_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - thruput, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - thruput); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - /* how to handle the verbose information in the presence of */ - /* confidence intervals is yet to be determined... raj 11/94 */ - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt, - local_send_align, - remote_recv_offset, - local_send_offset, - remote_recv_offset); - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/response times\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - - } - -} - - - /* this routine implements the receive (netserver) side of a TCP_RR */ - /* test */ -void -recv_sctp_rr_1toMany() -{ - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - - struct sockaddr_in myaddr_in; /* needed to get the port number */ - struct sockaddr_storage peeraddr; /* to communicate with peer */ - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - int msg_flags; - - int s_rcv; - int addrlen; - char *temp_message_ptr; - int trans_received; - int trans_remaining; - int bytes_sent; - int bytes_recvd; - int recv_buf_size; - int timed_out = 0; - float elapsed_time; - - struct sctp_rr_request_struct *sctp_rr_request; - struct sctp_rr_response_struct *sctp_rr_response; - struct sctp_rr_results_struct *sctp_rr_results; - - sctp_rr_request = - (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data; - sctp_rr_response = - (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data; - sctp_rr_results = - (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_sctp_rr_1toMany: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_sctp_rr_1toMany: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = SCTP_RR_MANY_RESPONSE; - - if (debug) { - fprintf(where,"recv_sctp_rr_1toMany: the response type is set...\n"); - fflush(where); - } - - /* allocate the recv and send rings with the requested alignments */ - /* and offsets. raj 7/94 */ - if (debug) { - fprintf(where,"recv_sctp_rr_1toMany: requested recv alignment of %d offset %d\n", - sctp_rr_request->recv_alignment, - sctp_rr_request->recv_offset); - fprintf(where,"recv_sctp_rr_1toMany: requested send alignment of %d offset %d\n", - sctp_rr_request->send_alignment, - sctp_rr_request->send_offset); - fflush(where); - } - - /* at some point, these need to come to us from the remote system */ - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - sctp_rr_request->response_size, - sctp_rr_request->send_alignment, - sctp_rr_request->send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - sctp_rr_request->request_size, - sctp_rr_request->recv_alignment, - sctp_rr_request->recv_offset); - - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = sctp_rr_request->send_buf_size; - lsr_size_req = sctp_rr_request->recv_buf_size; - loc_nodelay = sctp_rr_request->no_delay; - loc_rcvavoid = sctp_rr_request->so_rcvavoid; - loc_sndavoid = sctp_rr_request->so_sndavoid; - non_block = sctp_rr_request->non_blocking; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(sctp_rr_request->ipfamily), - sctp_rr_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(sctp_rr_request->ipfamily), - SOCK_SEQPACKET, - IPPROTO_SCTP, - 0); - - /* Grab a socket to listen on, and then listen on it. */ - if (debug) { - fprintf(where,"recv_sctp_rr_1toMany: grabbing a socket...\n"); - fflush(where); - } - - s_rcv = create_data_socket(local_res); - - if (s_rcv < 0) { - netperf_response.content.serv_errno = errno; - send_response(); - - exit(1); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_rcv, 5) == -1) { - netperf_response.content.serv_errno = errno; - close(s_rcv); - send_response(); - - exit(1); - } - - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_rcv, - (struct sockaddr *)&myaddr_in, &addrlen) == -1){ - netperf_response.content.serv_errno = errno; - close(s_rcv); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - sctp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - sctp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */ - sctp_rr_response->measure_cpu = 0; - - if (sctp_rr_request->measure_cpu) { - sctp_rr_response->measure_cpu = 1; - sctp_rr_response->cpu_rate = calibrate_local_cpu(sctp_rr_request->cpu_rate); - } - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - sctp_rr_response->send_buf_size = lss_size; - sctp_rr_response->recv_buf_size = lsr_size; - sctp_rr_response->no_delay = loc_nodelay; - sctp_rr_response->so_rcvavoid = loc_rcvavoid; - sctp_rr_response->so_sndavoid = loc_sndavoid; - sctp_rr_response->test_length = sctp_rr_request->test_length; - send_response(); - - /* Don't need events */ - sctp_enable_events(s_rcv, 0); - - /* now that we are connected, mark the socket as non-blocking */ - if (non_block) { - if (!set_nonblock(s_rcv)) { - perror("netperf: set_nonblock"); - exit(1); - } - } - - /* FIXME: The way 1-to-Many test operates right now, we are including - * association setup time into our measurements. The reason for this - * is that the client creates multiple endpoints and connects each - * endpoint to us using the connect call. On this end we simply call - * recvmsg() to get data becuase there is no equivalen of accept() for - * 1-to-Many API. - * I think this is OK, but if it were to be fixed, the server side - * would need to know how many associations are being setup and - * have a recvmsg() loop with SCTP_ASSOC_CHANGE events waiting for - * all the associations to be be established. - * I am punting on this for now. - */ - - - addrlen = sizeof(peeraddr); - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(sctp_rr_request->measure_cpu); - - /* The loop will exit when we hit the end of the test time, or when */ - /* we have exchanged the requested number of transactions. */ - - if (sctp_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(sctp_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = sctp_rr_request->test_length * -1; - } - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - - recv_buf_size = sctp_rr_request->request_size; - - /* Receive the data. We don't particularly care which association - * the data came in on. We'll simply be doing a receive untill - * we get and MSG_EOR flag (meaning that a single transmission was - * received) and a send to the same address, so the RR would be for - * the same associations. - * We can get away with this because the client will establish all - * the associations before transmitting any data. Any partial data - * will not have EOR thus will we will not send a response untill - * we get everything. - */ - - do { - msg_flags = 0; - if((bytes_recvd = sctp_recvmsg(s_rcv, - recv_ring->buffer_ptr, - recv_buf_size, - (struct sockaddr *)&peeraddr, &addrlen, - 0, &msg_flags)) == SOCKET_ERROR) { - if (SOCKET_EINTR(bytes_recvd)) { - /* the timer popped */ - timed_out = 1; - break; - } else if (non_block & errno == EAGAIN) { - /* do recvmsg again */ - continue; - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - } while(!(msg_flags & MSG_EOR)); - - recv_ring = recv_ring->next; - - if (timed_out) { - /* we hit the end of the test based on time - lets */ - /* bail out of here now... */ - if (debug) { - fprintf(where,"yo5\n"); - fflush(where); - } - break; - } - - /* Now, send the response to the remote */ - while ((bytes_sent=sctp_sendmsg(s_rcv, - send_ring->buffer_ptr, - sctp_rr_request->response_size, - (struct sockaddr *)&peeraddr, addrlen, - 0, 0, 0, 0, 0)) == SOCKET_ERROR) { - if (SOCKET_EINTR(bytes_sent)) { - /* the test timer has popped */ - timed_out = 1; - break; - } else if (non_block && errno == EAGAIN) { - continue; - } - - netperf_response.content.serv_errno = 992; - send_response(); - exit(1); - } - - if (timed_out) { - if (debug) { - fprintf(where,"yo6\n"); - fflush(where); - } - /* we hit the end of the test based on time - lets */ - /* bail out of here now... */ - break; - } - - send_ring = send_ring->next; - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(sctp_rr_request->measure_cpu,&elapsed_time); - - stop_timer(); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_sctp_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - sctp_rr_results->bytes_received = (trans_received * - (sctp_rr_request->request_size + - sctp_rr_request->response_size)); - sctp_rr_results->trans_received = trans_received; - sctp_rr_results->elapsed_time = elapsed_time; - sctp_rr_results->cpu_method = cpu_method; - sctp_rr_results->num_cpus = lib_num_loc_cpus; - if (sctp_rr_request->measure_cpu) { - sctp_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_sctp_rr: test complete, sending results.\n"); - fflush(where); - } - - /* we are now done with the sockets */ - close(s_rcv); - - send_response(); - -} - - -void -print_sctp_usage() -{ - - printf("%s",sctp_usage); - exit(1); - -} -void -scan_sctp_args(argc, argv) - int argc; - char *argv[]; - -{ - -#define SOCKETS_ARGS "BDhH:I:L:m:M:P:r:s:S:VN:T:46" - - extern char *optarg; /* pointer to option string */ - - int c; - - char - arg1[BUFSIZ], /* argument holders */ - arg2[BUFSIZ]; - - if (no_control) { - fprintf(where, - "The SCTP tests do not know how to deal with no control tests\n"); - exit(-1); - } - - strncpy(local_data_port,"0",sizeof(local_data_port)); - strncpy(remote_data_port,"0",sizeof(remote_data_port)); - - /* Go through all the command line arguments and break them */ - /* out. For those options that take two parms, specifying only */ - /* the first will set both to that value. Specifying only the */ - /* second will leave the first untouched. To change only the */ - /* first, use the form "first," (see the routine break_args.. */ - - while ((c= getopt(argc, argv, SOCKETS_ARGS)) != EOF) { - switch (c) { - case '?': - case '4': - remote_data_family = AF_INET; - local_data_family = AF_INET; - break; - case '6': -#if defined(AF_INET6) - remote_data_family = AF_INET6; - local_data_family = AF_INET6; -#else - fprintf(stderr, - "This netperf was not compiled on an IPv6 capable host!\n"); - fflush(stderr); - exit(-1); -#endif - break; - case 'h': - print_sctp_usage(); - exit(1); - case 'b': -#ifdef WANT_FIRST_BURST - first_burst_size = atoi(optarg); -#else /* WANT_FIRST_BURST */ - printf("Initial request burst functionality not compiled-in!\n"); -#endif /* WANT_FIRST_BURST */ - break; - case 'D': - /* set the nodelay flag */ - loc_nodelay = 1; - rem_nodelay = 1; - break; - case 'H': - break_args_explicit(optarg,arg1,arg2); - if (arg1[0]) { - /* make sure we leave room for the NULL termination boys and - girls. raj 2005-02-82 */ - remote_data_address = malloc(strlen(arg1)+1); - strncpy(remote_data_address,arg1,strlen(arg1)); - } - if (arg2[0]) - remote_data_family = parse_address_family(arg2); - break; - case 'L': - break_args_explicit(optarg,arg1,arg2); - if (arg1[0]) { - /* make sure we leave room for the NULL termination boys and - girls. raj 2005-02-82 */ - local_data_address = malloc(strlen(arg1)+1); - strncpy(local_data_address,arg1,strlen(arg1)); - } - if (arg2[0]) - local_data_family = parse_address_family(arg2); - break; - case 'P': - /* set the local and remote data port numbers for the tests to - allow them to run through those blankety blank end-to-end - breaking firewalls. raj 2004-06-15 */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - strncpy(local_data_port,arg1,sizeof(local_data_port)); - if (arg2[0]) - strncpy(remote_data_port,arg2,sizeof(remote_data_port)); - break; - case 's': - /* set local socket sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - lss_size_req = convert(arg1); - if (arg2[0]) - lsr_size_req = convert(arg2); - break; - case 'S': - /* set remote socket sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - rss_size_req = convert(arg1); - if (arg2[0]) - rsr_size_req = convert(arg2); - break; - case 'r': - /* set the request/response sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - req_size = convert(arg1); - if (arg2[0]) - rsp_size = convert(arg2); - break; - case 'm': - /* set size of the buffer for each sent message */ - send_size = convert(optarg); - break; - case 'M': - /* set the size of the buffer for each received message */ - recv_size = convert(optarg); - break; - case 't': - /* set the test name */ - strcpy(test_name,optarg); - break; - case 'W': - /* set the "width" of the user space data */ - /* buffer. This will be the number of */ - /* send_size buffers malloc'd in the */ - /* *_STREAM test. It may be enhanced to set */ - /* both send and receive "widths" but for now */ - /* it is just the sending *_STREAM. */ - send_width = convert(optarg); - break; - case 'V': - /* we want to do copy avoidance and will set */ - /* it for everything, everywhere, if we really */ - /* can. of course, we don't know anything */ - /* about the remote... */ -#ifdef SO_SND_COPYAVOID - loc_sndavoid = 1; -#else - loc_sndavoid = 0; - printf("Local send copy avoidance not available.\n"); -#endif -#ifdef SO_RCV_COPYAVOID - loc_rcvavoid = 1; -#else - loc_rcvavoid = 0; - printf("Local recv copy avoidance not available.\n"); -#endif - rem_sndavoid = 1; - rem_rcvavoid = 1; - break; - case 'N': - /* this opton allows the user to set the number of - * messages to send. This in effect modifies the test - * time. If we know the message size, then the we can - * express the test time as message_size * number_messages - */ - msg_count = convert (optarg); - if (msg_count > 0) - test_time = 0; - break; - case 'B': - non_block = 1; - break; - case 'T': - num_associations = atoi(optarg); - if (num_associations <= 1) { - printf("Number of SCTP associations must be >= 1\n"); - exit(1); - } - break; - }; - } -} - -#endif /* WANT_SCTP */ diff --git a/nettest_sctp.h b/nettest_sctp.h deleted file mode 100644 index 5297853..0000000 --- a/nettest_sctp.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - Copyright (C) 1993-2003 Hewlett-Packard Company -*/ - - /* This file contains the test-specific definitions for netperf's BSD */ - /* sockets tests */ - - -struct sctp_stream_request_struct { - int send_buf_size; - int recv_buf_size; /* how big does the client want it - the */ - /* receive socket buffer that is */ - int receive_size; /* how many bytes do we want to receive at one */ - /* time? */ - int recv_alignment; /* what is the alignment of the receive */ - /* buffer? */ - int recv_offset; /* and at what offset from that alignment? */ - int no_delay; /* do we disable the nagle algorithm for send */ - /* coalescing? */ - int measure_cpu; /* does the client want server cpu utilization */ - /* measured? */ - float cpu_rate; /* do we know how fast the cpu is already? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid copies on */ - /* receives? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dirty_count; /* how many integers in the receive buffer */ - /* should be made dirty before calling recv? */ - int clean_count; /* how many integers should be read from the */ - /* recv buffer before calling recv? */ - int port; /* the to port to which recv side should bind - to allow netperf to run through firewalls */ - int ipfamily; /* address family of ipaddress */ - int non_blocking; /* run the test in non-blocking mode */ -}; - -struct sctp_stream_response_struct { - int recv_buf_size; /* how big does the client want it */ - int receive_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ - int non_blocking; /* run the test in non-blocking mode */ -}; - -struct sctp_stream_results_struct { - double bytes_received; - unsigned int recv_calls; - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -struct sctp_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int port; /* the to port to which recv side should bind - to allow netperf to run through firewalls */ - int ipfamily; /* address family of ipaddress */ - int non_blocking; /* run the test in non-blocking mode */ -}; - -struct sctp_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ - int non_blocking; /* run the test in non-blocking mode */ -}; - -struct sctp_rr_results_struct { - unsigned int bytes_received; /* ignored initially */ - unsigned int recv_calls; /* ignored initially */ - unsigned int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -#define SCTP_SNDRCV_INFO_EV 0x01 -#define SCTP_ASSOC_CHANGE_EV 0x02 -#define SCTP_PEERADDR_CHANGE_EV 0x04 -#define SCTP_SND_FAILED_EV 0x08 -#define SCTP_REMOTE_ERROR_EV 0x10 -#define SCTP_SHUTDOWN_EV 0x20 -#define SCTP_PD_EV 0x40 -#define SCTP_ADAPT_EV 0x80 - -typedef enum sctp_disposition { - SCTP_OK = 1, - SCTP_CLOSE, -} sctp_disposition_t; - -extern void send_sctp_stream(); -extern void send_sctp_rr(); - -extern void recv_sctp_stream(); -extern void recv_sctp_rr(); - -extern void loc_cpu_rate(); -extern void rem_cpu_rate(); diff --git a/nettest_sdp.c b/nettest_sdp.c deleted file mode 100644 index 696fd3e..0000000 --- a/nettest_sdp.c +++ /dev/null @@ -1,3553 +0,0 @@ -#ifndef lint -char nettest_sdp[]="\ -@(#)nettest_sdp.c (c) Copyright 2007 Hewlett-Packard Co. Version 2.4.4"; -#else -#define DIRTY -#define WANT_HISTOGRAM -#define WANT_INTERVALS -#endif /* lint */ - -/****************************************************************/ -/* */ -/* nettest_sdp.c */ -/* */ -/* */ -/* scan_sdp_args() get the sdp command line args */ -/* */ -/* the actual test routines... */ -/* */ -/* send_sdp_stream() perform a sdp stream test */ -/* recv_sdp_stream() */ -/* send_sdp_rr() perform a sdp request/response */ -/* recv_sdp_rr() */ -/* */ -/* relies on create_data_socket in nettest_bsd.c */ -/****************************************************************/ - -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#if defined(WANT_SDP) - -#include <sys/types.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <stdio.h> -#include <string.h> -#include <time.h> -#ifdef NOSTDLIBH -#include <malloc.h> -#else /* NOSTDLIBH */ -#include <stdlib.h> -#endif /* NOSTDLIBH */ - -#if !defined(__VMS) -#include <sys/ipc.h> -#endif /* !defined(__VMS) */ -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <netdb.h> - -/* would seem that not all sdp.h files define a MSG_EOF, but that - MSG_EOF can be the same as MSG_FIN so lets work with that - assumption. initial find by Jon Pedersen. raj 2006-02-01 */ -#ifndef MSG_EOF -#ifdef MSG_FIN -#define MSG_EOF MSG_FIN -#else -#error Must have either MSG_EOF or MSG_FIN defined -#endif -#endif - -#include "netlib.h" -#include "netsh.h" -/* get some of the functions from nettest_bsd.c */ -#include "nettest_bsd.h" -#include "nettest_sdp.h" - -#ifdef WANT_HISTOGRAM -#ifdef __sgi -#include <sys/time.h> -#endif /* __sgi */ -#include "hist.h" -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_FIRST_BURST -extern int first_burst_size; -#endif /* WANT_FIRST_BURST */ - - - -/* these variables are specific to SDP tests. declare */ -/* them static to make them global only to this file. */ - -static int - msg_count = 0, /* number of messages to transmit on association */ - non_block = 0, /* default to blocking sockets */ - num_associations = 1; /* number of associations on the endpoint */ - -static int confidence_iteration; -static char local_cpu_method; -static char remote_cpu_method; - -#ifdef WANT_HISTOGRAM -static struct timeval time_one; -static struct timeval time_two; -static HIST time_hist; -#endif /* WANT_HISTOGRAM */ - - -char sdp_usage[] = "\n\ -Usage: netperf [global options] -- [test options] \n\ -\n\ -SDP Sockets Test Options:\n\ - -b number Send number requests at the start of _RR tests\n\ - -D [L][,R] Set SDP_NODELAY locally and/or remotely\n\ - -h Display this text\n\ - -H name,fam Use name (or IP) and family as target of data connection\n\ - -L name,fam Use name (or IP) and family as source of data connextion\n\ - -m bytes Set the size of each sent message\n\ - -M bytes Set the size of each received messages\n\ - -P local[,remote] Set the local/remote port for the data socket\n\ - -r req,[rsp] Set request/response sizes (_RR tests)\n\ - -s send[,recv] Set local socket send/recv buffer sizes\n\ - -S send[,recv] Set remote socket send/recv buffer sizes\n\ - -V Enable copy avoidance if supported\n\ - -4 Use AF_INET (eg IPv4) on both ends of the data conn\n\ - -6 Use AF_INET6 (eg IPv6) on both ends of the data conn\n\ -\n\ -For those options taking two parms, at least one must be specified;\n\ -specifying one value without a comma will set both parms to that\n\ -value, specifying a value with a leading comma will set just the second\n\ -parm, a value with a trailing comma will set just the first. To set\n\ -each parm to unique values, specify both and separate them with a\n\ -comma.\n"; - - - /* This routine is intended to retrieve interesting aspects of sdp */ - /* for the data connection. at first, it attempts to retrieve the */ - /* maximum segment size. later, it might be modified to retrieve */ - /* other information, but it must be information that can be */ - /* retrieved quickly as it is called during the timing of the test. */ - /* for that reason, a second routine may be created that can be */ - /* called outside of the timing loop */ -static -void -get_sdp_info(int socket, int * mss) -{ - -#ifdef TCP_MAXSEG - netperf_socklen_t sock_opt_len; - - sock_opt_len = sizeof(netperf_socklen_t); - if (getsockopt(socket, - getprotobyname("tcp")->p_proto, - TCP_MAXSEG, - (char *)mss, - &sock_opt_len) == SOCKET_ERROR) { - fprintf(where, - "netperf: get_sdp_info: getsockopt TCP_MAXSEG: errno %d\n", - errno); - fflush(where); - *mss = -1; - } -#else - *mss = -1; -#endif /* TCP_MAXSEG */ - -} - -void -send_sdp_stream(char remote_host[]) -{ - - char *tput_title = "\ -Recv Send Send \n\ -Socket Socket Message Elapsed \n\ -Size Size Size Time Throughput \n\ -bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f %s\n"; - - char *tput_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %s\n"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Socket Socket Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c %s\n"; - - char *cpu_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ -Local Remote Local Remote Xfered Per Per\n\ -Send Recv Send Recv Send (avg) Recv (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - - char *ksink_fmt2 = "\n\ -Maximum\n\ -Segment\n\ -Size (bytes)\n\ -%6d\n"; - - - float elapsed_time; - - /* what we want is to have a buffer space that is at least one */ - /* send-size greater than our send window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - - struct ring_elt *send_ring; - - int len; - unsigned int nummessages = 0; - SOCKET send_socket; - int bytes_remaining; - int sdp_mss = -1; /* possibly uninitialized on printf far below */ - - /* with links like fddi, one can send > 32 bits worth of bytes */ - /* during a test... ;-) at some point, this should probably become a */ - /* 64bit integral type, but those are not entirely common yet */ - - unsigned long long local_bytes_sent = 0; - double bytes_sent = 0.0; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - - double thruput; - - struct addrinfo *remote_res; - struct addrinfo *local_res; - - struct sdp_stream_request_struct *sdp_stream_request; - struct sdp_stream_response_struct *sdp_stream_response; - struct sdp_stream_results_struct *sdp_stream_result; - - sdp_stream_request = - (struct sdp_stream_request_struct *)netperf_request.content.test_specific_data; - sdp_stream_response = - (struct sdp_stream_response_struct *)netperf_response.content.test_specific_data; - sdp_stream_result = - (struct sdp_stream_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - /* complete_addrinfos will either succede or exit the process */ - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("SDP STREAM TEST",local_res,remote_res); - } - - send_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - - /*set up the data socket */ - /* fake things out by changing local_res->ai_family to AF_INET_SDP */ - local_res->ai_family = AF_INET_SDP; - local_res->ai_protocol = 0; - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_sdp_stream: sdp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_sdp_stream: send_socket obtained...\n"); - } - - /* at this point, we have either retrieved the socket buffer sizes, */ - /* or have tried to set them, so now, we may want to set the send */ - /* size based on that (because the user either did not use a -m */ - /* option, or used one with an argument of 0). If the socket buffer */ - /* size is not available, we will set the send size to 4KB - no */ - /* particular reason, just arbitrary... */ - if (send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - - /* set-up the data buffer ring with the requested alignment and offset. */ - /* note also that we have allocated a quantity */ - /* of memory that is at least one send-size greater than our socket */ - /* buffer size. We want to be sure that there are at least two */ - /* buffers allocated - this can be a bit of a problem when the */ - /* send_size is bigger than the socket size, so we must check... the */ - /* user may have wanted to explicitly set the "width" of our send */ - /* buffers, we should respect that wish... */ - if (send_width == 0) { - send_width = (lss_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - if (send_ring == NULL) { - /* only allocate the send ring once. this is a networking test, */ - /* not a memory allocation test. this way, we do not need a */ - /* deallocate_buffer_ring() routine, and I don't feel like */ - /* writing one anyway :) raj 11/94 */ - send_ring = allocate_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - if (!no_control) { - /* Tell the remote end to do a listen. The server alters the - socket paramters on the other side at this point, hence the - reason for all the values being passed in the setup - message. If the user did not specify any of the parameters, - they will be passed as 0, which will indicate to the remote - that no changes beyond the system's default should be - used. Alignment is the exception, it will default to 1, which - will be no alignment alterations. */ - - netperf_request.content.request_type = DO_SDP_STREAM; - sdp_stream_request->send_buf_size = rss_size_req; - sdp_stream_request->recv_buf_size = rsr_size_req; - sdp_stream_request->receive_size = recv_size; - sdp_stream_request->no_delay = rem_nodelay; - sdp_stream_request->recv_alignment = remote_recv_align; - sdp_stream_request->recv_offset = remote_recv_offset; - sdp_stream_request->measure_cpu = remote_cpu_usage; - sdp_stream_request->cpu_rate = remote_cpu_rate; - if (test_time) { - sdp_stream_request->test_length = test_time; - } - else { - sdp_stream_request->test_length = test_bytes; - } - sdp_stream_request->so_rcvavoid = rem_rcvavoid; - sdp_stream_request->so_sndavoid = rem_sndavoid; -#ifdef DIRTY - sdp_stream_request->dirty_count = rem_dirty_count; - sdp_stream_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - sdp_stream_request->port = atoi(remote_data_port); - sdp_stream_request->ipfamily = af_to_nf(remote_res->ai_family); - if (debug > 1) { - fprintf(where, - "netperf: send_sdp_stream: requesting SDP stream test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant - socket parameters for this test type. We will put them back - into the variables here so they can be displayed if desired. - The remote will have calibrated CPU if necessary, and will - have done all the needed set-up we will have calibrated the - cpu locally before sending the request, and will grab the - counter value right after the connect returns. The remote - will grab the counter right after the accept call. This saves - the hassle of extra messages being sent for the SDP - tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = sdp_stream_response->recv_buf_size; - rss_size = sdp_stream_response->send_buf_size; - rem_nodelay = sdp_stream_response->no_delay; - remote_cpu_usage= sdp_stream_response->measure_cpu; - remote_cpu_rate = sdp_stream_response->cpu_rate; - - /* we have to make sure that the server port number is in - network order */ - set_port_number(remote_res, - (short)sdp_stream_response->data_port_number); - - rem_rcvavoid = sdp_stream_response->so_rcvavoid; - rem_sndavoid = sdp_stream_response->so_sndavoid; - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - } - -#ifdef WANT_DEMO - DEMO_STREAM_SETUP(lss_size,rsr_size) -#endif - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("netperf: send_sdp_stream: data socket connect failed"); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either */ - /* the connect would have failed, or the previous response would */ - /* have indicated a problem. I failed to see the value of the */ - /* extra message after the accept on the remote. If it failed, */ - /* we'll see it here. If it didn't, we might as well start pumping */ - /* data. */ - - /* Set-up the test end conditions. For a stream test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - /* in previous revisions, we had the same code repeated throught */ - /* all the test suites. this was unnecessary, and meant more */ - /* work for me when I wanted to switch to POSIX signals, so I */ - /* have abstracted this out into a routine in netlib.c. if you */ - /* are experiencing signal problems, you might want to look */ - /* there. raj 11/94 */ - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - bytes_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - - /* we only start the interval timer if we are using the - timer-timed intervals rather than the sit and spin ones. raj - 2006-02-06 */ -#if defined(WANT_INTERVALS) - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - - /* before we start, initialize a few variables */ - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. */ - - while ((!times_up) || (bytes_remaining > 0)) { - -#ifdef DIRTY - access_buffer(send_ring->buffer_ptr, - send_size, - loc_dirty_count, - loc_clean_count); -#endif /* DIRTY */ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before we go into send and then again just - after we come out raj 8/94 */ - /* but lets only do this if there is going to be a histogram - displayed */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - if((len=send(send_socket, - send_ring->buffer_ptr, - send_size, - 0)) != send_size) { - if ((len >=0) || SOCKET_EINTR(len)) { - /* the test was interrupted, must be the end of test */ - break; - } - perror("netperf: data send error"); - printf("len was %d\n",len); - exit(1); - } - - local_bytes_sent += send_size; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp the exit from the send call and update the histogram */ - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_DEMO - DEMO_STREAM_INTERVAL(send_size) -#endif - -#if defined(WANT_INTERVALS) - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - /* now we want to move our pointer to the next position in the */ - /* data buffer...we may also want to wrap back to the "beginning" */ - /* of the bufferspace, so we will mod the number of messages sent */ - /* by the send width, and use that to calculate the offset to add */ - /* to the base pointer. */ - nummessages++; - send_ring = send_ring->next; - if (bytes_remaining) { - bytes_remaining -= send_size; - } - } - - /* The test is over. Flush the buffers to the remote end. We do a */ - /* graceful release to insure that all data has been taken by the */ - /* remote. */ - - /* but first, if the verbosity is greater than 1, find-out what */ - /* the SDP maximum segment_size was (if possible) */ - if (verbosity > 1) { - sdp_mss = -1; - get_sdp_info(send_socket,&sdp_mss); - } - - if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) { - perror("netperf: cannot shutdown sdp stream socket"); - exit(1); - } - - /* hang a recv() off the socket to block until the remote has */ - /* brought all the data up into the application. it will do a */ - /* shutdown to cause a FIN to be sent our way. We will assume that */ - /* any exit from the recv() call is good... raj 4/93 */ - - recv(send_socket, send_ring->buffer_ptr, send_size, 0); - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured and how */ - /* long did we really */ - /* run? */ - - /* we are finished with the socket, so close it to prevent hitting */ - /* the limit on maximum open files. */ - - close(send_socket); - - if (!no_control) { - /* Get the statistics from the remote end. The remote will have - calculated service demand and all those interesting - things. If it wasn't supposed to care, it will return obvious - values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the - future, we may want to include a calculation of the thruput - measured by the remote, but it should be the case that for a - SDP stream test, that the two numbers should be *very* - close... We calculate bytes_sent regardless of the way the - test length was controlled. If it was time, we needed to, - and if it was by bytes, the user may have specified a number - of bytes that wasn't a multiple of the send_size, so we - really didn't send what he asked for ;-) */ - - bytes_sent = ntohd(sdp_stream_result->bytes_received); - } - else { - bytes_sent = (double)local_bytes_sent; - } - - thruput = calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - - remote_cpu_utilization = sdp_stream_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - sdp_stream_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - } - - /* at this point, we have finished making all the runs that we */ - /* will be making. so, we should extract what the calcuated values */ - /* are for all the confidence stuff. we could make the values */ - /* global, but that seemed a little messy, and it did not seem worth */ - /* all the mucking with header files. so, we create a routine much */ - /* like calcualte_confidence, which just returns the mean values. */ - /* raj 11/94 */ - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(sdp_stream_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand, /* remote service demand */ - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - fprintf(where, - tput_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - thruput, /* how fast did it go */ - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* SDP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - /* this stuff needs to be worked-out in the presence of confidence */ - /* intervals and multiple iterations of the test... raj 11/94 */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_send_align, - remote_recv_align, - local_send_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)sdp_stream_result->recv_calls, - sdp_stream_result->recv_calls); - fprintf(where, - ksink_fmt2, - sdp_mss); - fflush(where); -#ifdef WANT_HISTOGRAM - fprintf(where,"\n\nHistogram of time spent in send() call.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } - -} - - - -/* This routine implements the netperf-side SDP unidirectional data - transfer test (a.k.a. stream) for the sockets interface where the - data flow is from the netserver to the netperf. It receives its - parameters via global variables from the shell and writes its - output to the standard output. */ - - -void -send_sdp_maerts(char remote_host[]) -{ - - char *tput_title = "\ -Recv Send Send \n\ -Socket Socket Message Elapsed \n\ -Size Size Size Time Throughput \n\ -bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f %s\n"; - - char *tput_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f \n %s"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Socket Socket Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c %s\n"; - - char *cpu_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Recvs %-8.8s Sends\n\ -Local Remote Local Remote Xfered Per Per\n\ -Recv Send Recv Send Recv (avg) Send (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - - char *ksink_fmt2 = "\n\ -Maximum\n\ -Segment\n\ -Size (bytes)\n\ -%6d\n"; - - - float elapsed_time; - - /* what we want is to have a buffer space that is at least one */ - /* recv-size greater than our recv window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - - struct ring_elt *recv_ring; - - int len; - unsigned int nummessages = 0; - SOCKET recv_socket; - int bytes_remaining; - int sdp_mss = -1; /* possibly uninitialized on printf far below */ - - /* with links like fddi, one can recv > 32 bits worth of bytes */ - /* during a test... ;-) at some point, this should probably become a */ - /* 64bit integral type, but those are not entirely common yet */ - double bytes_sent = 0.0; - unsigned long long local_bytes_recvd = 0; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - - double thruput; - - struct addrinfo *remote_res; - struct addrinfo *local_res; - - struct sdp_maerts_request_struct *sdp_maerts_request; - struct sdp_maerts_response_struct *sdp_maerts_response; - struct sdp_maerts_results_struct *sdp_maerts_result; - - sdp_maerts_request = - (struct sdp_maerts_request_struct *)netperf_request.content.test_specific_data; - sdp_maerts_response = - (struct sdp_maerts_response_struct *)netperf_response.content.test_specific_data; - sdp_maerts_result = - (struct sdp_maerts_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("SDP MAERTS TEST",local_res,remote_res); - } - - recv_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - - /*set up the data socket */ - /* fake things out by changing local_res->ai_family to AF_INET_SDP */ - local_res->ai_family = AF_INET_SDP; - local_res->ai_protocol = 0; - recv_socket = create_data_socket(local_res); - - if (recv_socket == INVALID_SOCKET){ - perror("netperf: send_sdp_maerts: sdp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_sdp_maerts: recv_socket obtained...\n"); - } - - /* at this point, we have either retrieved the socket buffer sizes, */ - /* or have tried to set them, so now, we may want to set the recv */ - /* size based on that (because the user either did not use a -m */ - /* option, or used one with an argument of 0). If the socket buffer */ - /* size is not available, we will set the recv size to 4KB - no */ - /* particular reason, just arbitrary... */ - if (recv_size == 0) { - if (lsr_size > 0) { - recv_size = lsr_size; - } - else { - recv_size = 4096; - } - } - - /* set-up the data buffer ring with the requested alignment and offset. */ - /* note also that we have allocated a quantity */ - /* of memory that is at least one recv-size greater than our socket */ - /* buffer size. We want to be sure that there are at least two */ - /* buffers allocated - this can be a bit of a problem when the */ - /* recv_size is bigger than the socket size, so we must check... the */ - /* user may have wanted to explicitly set the "width" of our recv */ - /* buffers, we should respect that wish... */ - if (recv_width == 0) { - recv_width = (lsr_size/recv_size) + 1; - if (recv_width == 1) recv_width++; - } - - if (recv_ring == NULL) { - /* only allocate the recv ring once. this is a networking test, */ - /* not a memory allocation test. this way, we do not need a */ - /* deallocate_buffer_ring() routine, and I don't feel like */ - /* writing one anyway :) raj 11/94 */ - recv_ring = allocate_buffer_ring(recv_width, - recv_size, - local_recv_align, - local_recv_offset); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - if (!no_control) { - /* Tell the remote end to do a listen. The server alters the - socket paramters on the other side at this point, hence the - reason for all the values being passed in the setup - message. If the user did not specify any of the parameters, - they will be passed as 0, which will indicate to the remote - that no changes beyond the system's default should be - used. Alignment is the exception, it will default to 1, which - will be no alignment alterations. */ - - netperf_request.content.request_type = DO_SDP_MAERTS; - sdp_maerts_request->send_buf_size = rss_size_req; - sdp_maerts_request->recv_buf_size = rsr_size_req; - sdp_maerts_request->send_size = send_size; - sdp_maerts_request->no_delay = rem_nodelay; - sdp_maerts_request->send_alignment = remote_send_align; - sdp_maerts_request->send_offset = remote_send_offset; - sdp_maerts_request->measure_cpu = remote_cpu_usage; - sdp_maerts_request->cpu_rate = remote_cpu_rate; - if (test_time) { - sdp_maerts_request->test_length = test_time; - } - else { - sdp_maerts_request->test_length = test_bytes; - } - sdp_maerts_request->so_rcvavoid = rem_rcvavoid; - sdp_maerts_request->so_sndavoid = rem_sndavoid; -#ifdef DIRTY - sdp_maerts_request->dirty_count = rem_dirty_count; - sdp_maerts_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - sdp_maerts_request->port = atoi(remote_data_port); - sdp_maerts_request->ipfamily = af_to_nf(remote_res->ai_family); - if (debug > 1) { - fprintf(where, - "netperf: send_sdp_maerts: requesting SDP maerts test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant - socket parameters for this test type. We will put them back - into the variables here so they can be displayed if desired. - The remote will have calibrated CPU if necessary, and will - have done all the needed set-up we will have calibrated the - cpu locally before sending the request, and will grab the - counter value right after the connect returns. The remote - will grab the counter right after the accept call. This saves - the hassle of extra messages being sent for the SDP - tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = sdp_maerts_response->recv_buf_size; - rss_size = sdp_maerts_response->send_buf_size; - rem_nodelay = sdp_maerts_response->no_delay; - remote_cpu_usage= sdp_maerts_response->measure_cpu; - remote_cpu_rate = sdp_maerts_response->cpu_rate; - send_size = sdp_maerts_response->send_size; - - /* we have to make sure that the server port number is in - network order */ - set_port_number(remote_res, - (short)sdp_maerts_response->data_port_number); - rem_rcvavoid = sdp_maerts_response->so_rcvavoid; - rem_sndavoid = sdp_maerts_response->so_sndavoid; - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - } - -#ifdef WANT_DEMO - DEMO_STREAM_SETUP(lsr_size,rss_size) -#endif - - /*Connect up to the remote port on the data socket */ - if (connect(recv_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("netperf: send_sdp_maerts: data socket connect failed"); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either */ - /* the connect would have failed, or the previous response would */ - /* have indicated a problem. I failed to see the value of the */ - /* extra message after the accept on the remote. If it failed, */ - /* we'll see it here. If it didn't, we might as well start pumping */ - /* data. */ - - /* Set-up the test end conditions. For a maerts test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - /* in previous revisions, we had the same code repeated throught */ - /* all the test suites. this was unnecessary, and meant more */ - /* work for me when I wanted to switch to POSIX signals, so I */ - /* have abstracted this out into a routine in netlib.c. if you */ - /* are experiencing signal problems, you might want to look */ - /* there. raj 11/94 */ - if (!no_control) { - /* this is a netperf to netserver test, netserver will close - to tell us the test is over, so use PAD_TIME to avoid - causing the netserver fits. */ - start_timer(test_time + PAD_TIME); - } - else { - /* this is a netperf to data source test, no PAD_TIME */ - start_timer(test_time); - } - } - else { - /* The tester wanted to recv a number of bytes. we don't do that - in a SDP_MAERTS test. sorry. raj 2002-06-21 */ - printf("netperf: send_sdp_maerts: test must be timed\n"); - exit(1); - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - - /* before we start, initialize a few variables */ - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - /* the test will continue until we either get a zero-byte recv() - on the socket or our failsafe timer expires. most of the time - we trust that we get a zero-byte recieve from the socket. raj - 2002-06-21 */ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before we go into recv and then again just - after we come out raj 8/94 */ - /* but only if we are actually going to display a histogram. raj - 2006-02-07 */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - while ((!times_up) && (len=recv(recv_socket, - recv_ring->buffer_ptr, - recv_size, - 0)) > 0 ) { - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp the exit from the recv call and update the histogram */ - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - -#ifdef DIRTY - access_buffer(recv_ring->buffer_ptr, - recv_size, - loc_dirty_count, - loc_clean_count); -#endif /* DIRTY */ - -#ifdef WANT_DEMO - DEMO_STREAM_INTERVAL(len); -#endif - -#ifdef WANT_INTERVALS - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - /* now we want to move our pointer to the next position in the */ - /* data buffer...we may also want to wrap back to the "beginning" */ - /* of the bufferspace, so we will mod the number of messages sent */ - /* by the recv width, and use that to calculate the offset to add */ - /* to the base pointer. */ - nummessages++; - recv_ring = recv_ring->next; - if (bytes_remaining) { - bytes_remaining -= len; - } - - local_bytes_recvd += len; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* make sure we timestamp just before we go into recv */ - /* raj 2004-06-15 */ - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - } - - /* an EINTR is to be expected when this is a no_control test */ - if (((len < 0) || SOCKET_EINTR(len)) && (!no_control)) { - perror("send_sdp_maerts: data recv error"); - printf("len was %d\n",len); - exit(1); - } - - /* if we get here, it must mean we had a recv return of 0 before - the watchdog timer expired, or the watchdog timer expired and - this was a no_control test */ - - /* The test is over. Flush the buffers to the remote end. We do a - graceful release to tell the remote we have all the data. */ - - /* but first, if the verbosity is greater than 1, find-out what */ - /* the SDP maximum segment_size was (if possible) */ - if (verbosity > 1) { - sdp_mss = -1; - get_sdp_info(recv_socket,&sdp_mss); - } - - if (shutdown(recv_socket,SHUT_WR) == SOCKET_ERROR) { - perror("netperf: cannot shutdown sdp maerts socket"); - exit(1); - } - - stop_timer(); - - /* this call will always give us the local elapsed time for the - test, and will also store-away the necessaries for cpu - utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured and how */ - /* long did we really */ - /* run? */ - - /* we are finished with the socket, so close it to prevent hitting */ - /* the limit on maximum open files. */ - - close(recv_socket); - - if (!no_control) { - /* Get the statistics from the remote end. The remote will have - calculated service demand and all those interesting - things. If it wasn't supposed to care, it will return obvious - values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the - future, we may want to include a calculation of the thruput - measured by the remote, but it should be the case that for a - SDP maerts test, that the two numbers should be *very* - close... We calculate bytes_sent regardless of the way the - test length was controlled. If it was time, we needed to, - and if it was by bytes, the user may have specified a number - of bytes that wasn't a multiple of the recv_size, so we - really didn't recv what he asked for ;-) */ - - bytes_sent = ntohd(sdp_maerts_result->bytes_sent); - } - else { - bytes_sent = (double)local_bytes_recvd; - } - - - thruput = calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - - remote_cpu_utilization = sdp_maerts_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - sdp_maerts_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - } - - /* at this point, we have finished making all the runs that we */ - /* will be making. so, we should extract what the calcuated values */ - /* are for all the confidence stuff. we could make the values */ - /* global, but that seemed a little messy, and it did not seem worth */ - /* all the mucking with header files. so, we create a routine much */ - /* like calcualte_confidence, which just returns the mean values. */ - /* raj 11/94 */ - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(sdp_maerts_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the recvs */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand, /* remote service demand */ - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - fprintf(where, - tput_fmt_1, /* the format string */ - lsr_size, /* local recvbuf size */ - rss_size, /* remot sendbuf size */ - send_size, /* how large were the recvs */ - elapsed_time, /* how long did it take */ - thruput, /* how fast did it go */ - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* SDP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - /* this stuff needs to be worked-out in the presence of confidence */ - /* intervals and multiple iterations of the test... raj 11/94 */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_recv_align, - remote_recv_align, - local_recv_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)sdp_maerts_result->send_calls, - sdp_maerts_result->send_calls); - fprintf(where, - ksink_fmt2, - sdp_mss); - fflush(where); -#ifdef WANT_HISTOGRAM - fprintf(where,"\n\nHistogram of time spent in recv() call.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } - -} -/* This is the server-side routine for the sdp stream test. It is */ -/* implemented as one routine. I could break things-out somewhat, but */ -/* didn't feel it was necessary. */ - -void -recv_sdp_stream() -{ - - struct sockaddr_in myaddr_in, peeraddr_in; - SOCKET s_listen,s_data; - netperf_socklen_t addrlen; - int len; - unsigned int receive_calls; - float elapsed_time; - double bytes_received; - - struct ring_elt *recv_ring; - - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - -#ifdef DO_SELECT - fd_set readfds; - struct timeval timeout; -#endif /* DO_SELECT */ - - struct sdp_stream_request_struct *sdp_stream_request; - struct sdp_stream_response_struct *sdp_stream_response; - struct sdp_stream_results_struct *sdp_stream_results; - -#ifdef DO_SELECT - FD_ZERO(&readfds); - timeout.tv_sec = 1; - timeout.tv_usec = 0; -#endif /* DO_SELECT */ - - sdp_stream_request = - (struct sdp_stream_request_struct *)netperf_request.content.test_specific_data; - sdp_stream_response = - (struct sdp_stream_response_struct *)netperf_response.content.test_specific_data; - sdp_stream_results = - (struct sdp_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_sdp_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_sdp_stream: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = SDP_STREAM_RESPONSE; - - if (debug) { - fprintf(where,"recv_sdp_stream: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug) { - fprintf(where,"recv_sdp_stream: requested alignment of %d\n", - sdp_stream_request->recv_alignment); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = sdp_stream_request->send_buf_size; - lsr_size_req = sdp_stream_request->recv_buf_size; - loc_nodelay = sdp_stream_request->no_delay; - loc_rcvavoid = sdp_stream_request->so_rcvavoid; - loc_sndavoid = sdp_stream_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(sdp_stream_request->ipfamily), - sdp_stream_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(sdp_stream_request->ipfamily), - SOCK_STREAM, - IPPROTO_TCP, - 0); - - /* fake things out by changing local_res->ai_family to AF_INET_SDP */ - local_res->ai_family = AF_INET_SDP; - local_res->ai_protocol = 0; - s_listen = create_data_socket(local_res); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - -#ifdef WIN32 - /* The test timer can fire during operations on the listening socket, - so to make the start_timer below work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket2 = s_listen; -#endif - - /* what sort of sizes did we end-up with? */ - if (sdp_stream_request->receive_size == 0) { - if (lsr_size > 0) { - recv_size = lsr_size; - } - else { - recv_size = 4096; - } - } - else { - recv_size = sdp_stream_request->receive_size; - } - - /* we want to set-up our recv_ring in a manner analagous to what we */ - /* do on the sending side. this is more for the sake of symmetry */ - /* than for the needs of say copy avoidance, but it might also be */ - /* more realistic - this way one could conceivably go with a */ - /* double-buffering scheme when taking the data an putting it into */ - /* the filesystem or something like that. raj 7/94 */ - - if (recv_width == 0) { - recv_width = (lsr_size/recv_size) + 1; - if (recv_width == 1) recv_width++; - } - - recv_ring = allocate_buffer_ring(recv_width, - recv_size, - sdp_stream_request->recv_alignment, - sdp_stream_request->recv_offset); - - if (debug) { - fprintf(where,"recv_sdp_stream: receive alignment and offset set...\n"); - fflush(where); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - sdp_stream_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - sdp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */ - if (sdp_stream_request->measure_cpu) { - sdp_stream_response->measure_cpu = 1; - sdp_stream_response->cpu_rate = - calibrate_local_cpu(sdp_stream_request->cpu_rate); - } - else { - sdp_stream_response->measure_cpu = 0; - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - sdp_stream_response->send_buf_size = lss_size; - sdp_stream_response->recv_buf_size = lsr_size; - sdp_stream_response->no_delay = loc_nodelay; - sdp_stream_response->so_rcvavoid = loc_rcvavoid; - sdp_stream_response->so_sndavoid = loc_sndavoid; - sdp_stream_response->receive_size = recv_size; - - send_response(); - - addrlen = sizeof(peeraddr_in); - - if ((s_data=accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - exit(1); - } - -#ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass */ - /* attributes across an accept() call. Including this goes against */ - /* my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(sdp_stream_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - /* there used to be an #ifdef DIRTY call to access_buffer() here, - but we have switched from accessing the buffer before the recv() - call to accessing the buffer after the recv() call. The - accessing before was, IIRC, related to having dirty data when - doing page-flipping copy avoidance. */ - - bytes_received = 0; - receive_calls = 0; - - while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) { - if (len == SOCKET_ERROR ) - { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - bytes_received += len; - receive_calls++; - -#ifdef DIRTY - /* we access the buffer after the recv() call now, rather than before */ - access_buffer(recv_ring->buffer_ptr, - recv_size, - sdp_stream_request->dirty_count, - sdp_stream_request->clean_count); -#endif /* DIRTY */ - - - /* move to the next buffer in the recv_ring */ - recv_ring = recv_ring->next; - -#ifdef PAUSE - sleep(1); -#endif /* PAUSE */ - -#ifdef DO_SELECT - FD_SET(s_data,&readfds); - select(s_data+1,&readfds,NULL,NULL,&timeout); -#endif /* DO_SELECT */ - - } - - /* perform a shutdown to signal the sender that */ - /* we have received all the data sent. raj 4/93 */ - - if (shutdown(s_data,SHUT_WR) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - cpu_stop(sdp_stream_request->measure_cpu,&elapsed_time); - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_sdp_stream: got %g bytes\n", - bytes_received); - fprintf(where, - "recv_sdp_stream: got %d recvs\n", - receive_calls); - fflush(where); - } - - sdp_stream_results->bytes_received = htond(bytes_received); - sdp_stream_results->elapsed_time = elapsed_time; - sdp_stream_results->recv_calls = receive_calls; - - sdp_stream_results->cpu_method = cpu_method; - sdp_stream_results->num_cpus = lib_num_loc_cpus; - - if (sdp_stream_request->measure_cpu) { - sdp_stream_results->cpu_util = calc_cpu_util(0.0); - }; - - if (debug) { - fprintf(where, - "recv_sdp_stream: test complete, sending results.\n"); - fprintf(where, - " bytes_received %g receive_calls %d\n", - bytes_received, - receive_calls); - fprintf(where, - " len %d\n", - len); - fflush(where); - } - - send_response(); - - /* we are now done with the sockets */ - close(s_data); - close(s_listen); - - } - -/* This is the server-side routine for the sdp maerts test. It is - implemented as one routine. I could break things-out somewhat, but - didn't feel it was necessary. */ - -void -recv_sdp_maerts() -{ - - struct sockaddr_in myaddr_in, peeraddr_in; - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - - SOCKET s_listen,s_data; - netperf_socklen_t addrlen; - int len; - unsigned int send_calls; - float elapsed_time; - double bytes_sent = 0.0 ; - - struct ring_elt *send_ring; - - struct sdp_maerts_request_struct *sdp_maerts_request; - struct sdp_maerts_response_struct *sdp_maerts_response; - struct sdp_maerts_results_struct *sdp_maerts_results; - - sdp_maerts_request = - (struct sdp_maerts_request_struct *)netperf_request.content.test_specific_data; - sdp_maerts_response = - (struct sdp_maerts_response_struct *)netperf_response.content.test_specific_data; - sdp_maerts_results = - (struct sdp_maerts_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_sdp_maerts: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired - parameters and then let the initiator know that all is ready. If - socket size defaults are to be used, then the initiator will have - sent us 0's. If the socket sizes cannot be changed, then we will - send-back what they are. If that information cannot be - determined, then we send-back -1's for the sizes. If things go - wrong for any reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It - would be best if the error that the remote reports to the user is - the actual error we encountered, rather than some bogus - unexpected response type message. */ - - if (debug) { - fprintf(where,"recv_sdp_maerts: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = SDP_MAERTS_RESPONSE; - - if (debug) { - fprintf(where,"recv_sdp_maerts: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug) { - fprintf(where,"recv_sdp_maerts: requested alignment of %d\n", - sdp_maerts_request->send_alignment); - fflush(where); - } - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_sdp_maerts: grabbing a socket...\n"); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = sdp_maerts_request->send_buf_size; - lsr_size_req = sdp_maerts_request->recv_buf_size; - loc_nodelay = sdp_maerts_request->no_delay; - loc_rcvavoid = sdp_maerts_request->so_rcvavoid; - loc_sndavoid = sdp_maerts_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(sdp_maerts_request->ipfamily), - sdp_maerts_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(sdp_maerts_request->ipfamily), - SOCK_STREAM, - IPPROTO_TCP, - 0); - - /* fake things out by changing local_res->ai_family to AF_INET_SDP */ - local_res->ai_family = AF_INET_SDP; - local_res->ai_protocol = 0; - s_listen = create_data_socket(local_res); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - -#ifdef WIN32 - /* The test timer can fire during operations on the listening socket, - so to make the start_timer below work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket2 = s_listen; -#endif - - - /* what sort of sizes did we end-up with? */ - if (sdp_maerts_request->send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - else { - send_size = sdp_maerts_request->send_size; - } - - /* we want to set-up our recv_ring in a manner analagous to what we */ - /* do on the recving side. this is more for the sake of symmetry */ - /* than for the needs of say copy avoidance, but it might also be */ - /* more realistic - this way one could conceivably go with a */ - /* double-buffering scheme when taking the data an putting it into */ - /* the filesystem or something like that. raj 7/94 */ - - if (send_width == 0) { - send_width = (lsr_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - send_ring = allocate_buffer_ring(send_width, - send_size, - sdp_maerts_request->send_alignment, - sdp_maerts_request->send_offset); - - if (debug) { - fprintf(where,"recv_sdp_maerts: receive alignment and offset set...\n"); - fflush(where); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - sdp_maerts_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - sdp_maerts_response->cpu_rate = (float)0.0; /* assume no cpu */ - if (sdp_maerts_request->measure_cpu) { - sdp_maerts_response->measure_cpu = 1; - sdp_maerts_response->cpu_rate = - calibrate_local_cpu(sdp_maerts_request->cpu_rate); - } - else { - sdp_maerts_response->measure_cpu = 0; - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - sdp_maerts_response->send_buf_size = lss_size; - sdp_maerts_response->recv_buf_size = lsr_size; - sdp_maerts_response->no_delay = loc_nodelay; - sdp_maerts_response->so_rcvavoid = loc_rcvavoid; - sdp_maerts_response->so_sndavoid = loc_sndavoid; - sdp_maerts_response->send_size = send_size; - - send_response(); - - addrlen = sizeof(peeraddr_in); - - /* we will start the timer before the accept() to be somewhat - analagous to the starting of the timer before the connect() call - in the SDP_STREAM test. raj 2002-06-21 */ - - start_timer(sdp_maerts_request->test_length); - - /* Now it's time to start receiving data on the connection. We will - first grab the apropriate counters and then start grabbing. */ - - cpu_start(sdp_maerts_request->measure_cpu); - - - if ((s_data=accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - exit(1); - } - -#ifdef KLUDGE_SOCKET_OPTIONS - - /* this is for those systems which *INCORRECTLY* fail to pass - attributes across an accept() call. Including this goes against - my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - bytes_sent = 0.0; - send_calls = 0; - - len = 0; /* nt-lint; len is not initialized (printf far below) if - times_up initially true.*/ - times_up = 0; /* must remember to initialize this little beauty */ - while (!times_up) { - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - - access_buffer(send_ring->buffer_ptr, - send_size, - sdp_maerts_request->dirty_count, - sdp_maerts_request->clean_count); - -#endif /* DIRTY */ - - if((len=send(s_data, - send_ring->buffer_ptr, - send_size, - 0)) != send_size) { - if ((len >=0) || SOCKET_EINTR(len)) { - /* the test was interrupted, must be the end of test */ - break; - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - bytes_sent += len; - send_calls++; - - /* more to the next buffer in the send_ring */ - send_ring = send_ring->next; - - } - - /* perform a shutdown to signal the sender that */ - /* we have received all the data sent. raj 4/93 */ - - if (shutdown(s_data,SHUT_WR) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* hang a recv() off the socket to block until the remote has - brought all the data up into the application. it will do a - shutdown to cause a FIN to be sent our way. We will assume that - any exit from the recv() call is good... raj 4/93 */ - - recv(s_data, send_ring->buffer_ptr, send_size, 0); - - - cpu_stop(sdp_maerts_request->measure_cpu,&elapsed_time); - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_sdp_maerts: got %g bytes\n", - bytes_sent); - fprintf(where, - "recv_sdp_maerts: got %d sends\n", - send_calls); - fflush(where); - } - - sdp_maerts_results->bytes_sent = htond(bytes_sent); - sdp_maerts_results->elapsed_time = elapsed_time; - sdp_maerts_results->send_calls = send_calls; - - if (sdp_maerts_request->measure_cpu) { - sdp_maerts_results->cpu_util = calc_cpu_util(0.0); - }; - - if (debug) { - fprintf(where, - "recv_sdp_maerts: test complete, sending results.\n"); - fprintf(where, - " bytes_sent %g send_calls %d\n", - bytes_sent, - send_calls); - fprintf(where, - " len %d\n", - len); - fflush(where); - } - - sdp_maerts_results->cpu_method = cpu_method; - sdp_maerts_results->num_cpus = lib_num_loc_cpus; - send_response(); - - /* we are now done with the sockets */ - close(s_data); - close(s_listen); - - } - - - /* this routine implements the sending (netperf) side of the SDP_RR */ - /* test. */ - -void -send_sdp_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f %s\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f %s\n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c %s\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - int timed_out = 0; - float elapsed_time; - - int len; - char *temp_message_ptr; - int nummessages; - SOCKET send_socket; - int trans_remaining; - double bytes_xferd; - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - int rsp_bytes_left; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct addrinfo *local_res; - struct addrinfo *remote_res; - - struct sdp_rr_request_struct *sdp_rr_request; - struct sdp_rr_response_struct *sdp_rr_response; - struct sdp_rr_results_struct *sdp_rr_result; - -#ifdef WANT_FIRST_BURST -#define REQUEST_CWND_INITIAL 2 - /* "in the beginning..." the WANT_FIRST_BURST stuff was like both - Unix and the state of New Jersey - both were simple an unspoiled. - then it was realized that some stacks are quite picky about - initial congestion windows and a non-trivial initial burst of - requests would not be individual segments even with TCP_NODELAY - set. so, we have to start tracking a poor-man's congestion window - up here in window space because we want to try to make something - happen that frankly, we cannot guarantee with the specification - of SDP. ain't that grand?-) raj 2006-01-30 */ - int requests_outstanding = 0; - int request_cwnd = REQUEST_CWND_INITIAL; /* we ass-u-me that having - three requests - outstanding at the - beginning of the test - is ok with SDP stacks - of interest. the first - two will come from our - first_burst loop, and - the third from our - regularly scheduled - send */ -#endif - - sdp_rr_request = - (struct sdp_rr_request_struct *)netperf_request.content.test_specific_data; - sdp_rr_response= - (struct sdp_rr_response_struct *)netperf_response.content.test_specific_data; - sdp_rr_result = - (struct sdp_rr_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - time_hist = HIST_new(); - } -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - complete_addrinfos(&remote_res, - &local_res, - remote_host, - SOCK_STREAM, - IPPROTO_TCP, - 0); - - if ( print_headers ) { - print_top_test_header("SDP REQUEST/RESPONSE TEST",local_res,remote_res); - } - - /* initialize a few counters */ - - send_ring = NULL; - recv_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - timed_out = 0; - trans_remaining = 0; - -#ifdef WANT_FIRST_BURST - /* we have to remember to reset the number of transactions - outstanding and the "congestion window for each new - iteration. raj 2006-01-31 */ - requests_outstanding = 0; - request_cwnd = REQUEST_CWND_INITIAL; -#endif - - - /* set-up the data buffers with the requested alignment and offset. */ - /* since this is a request/response test, default the send_width and */ - /* recv_width to 1 and not two raj 7/94 */ - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - if (send_ring == NULL) { - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - } - - if (recv_ring == NULL) { - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - } - - /*set up the data socket */ - /* fake things out by changing local_res->ai_family to AF_INET_SDP */ - local_res->ai_family = AF_INET_SDP; - local_res->ai_protocol = 0; - send_socket = create_data_socket(local_res); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_sdp_rr: sdp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_sdp_rr: send_socket obtained...\n"); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - if (!no_control) { - /* Tell the remote end to do a listen. The server alters the - socket paramters on the other side at this point, hence the - reason for all the values being passed in the setup - message. If the user did not specify any of the parameters, - they will be passed as 0, which will indicate to the remote - that no changes beyond the system's default should be - used. Alignment is the exception, it will default to 8, which - will be no alignment alterations. */ - - netperf_request.content.request_type = DO_SDP_RR; - sdp_rr_request->recv_buf_size = rsr_size_req; - sdp_rr_request->send_buf_size = rss_size_req; - sdp_rr_request->recv_alignment = remote_recv_align; - sdp_rr_request->recv_offset = remote_recv_offset; - sdp_rr_request->send_alignment = remote_send_align; - sdp_rr_request->send_offset = remote_send_offset; - sdp_rr_request->request_size = req_size; - sdp_rr_request->response_size = rsp_size; - sdp_rr_request->no_delay = rem_nodelay; - sdp_rr_request->measure_cpu = remote_cpu_usage; - sdp_rr_request->cpu_rate = remote_cpu_rate; - sdp_rr_request->so_rcvavoid = rem_rcvavoid; - sdp_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - sdp_rr_request->test_length = test_time; - } - else { - sdp_rr_request->test_length = test_trans * -1; - } - sdp_rr_request->port = atoi(remote_data_port); - sdp_rr_request->ipfamily = af_to_nf(remote_res->ai_family); - - if (debug > 1) { - fprintf(where,"netperf: send_sdp_rr: requesting SDP rr test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant - socket parameters for this test type. We will put them back - into the variables here so they can be displayed if desired. - The remote will have calibrated CPU if necessary, and will - have done all the needed set-up we will have calibrated the - cpu locally before sending the request, and will grab the - counter value right after the connect returns. The remote - will grab the counter right after the accept call. This saves - the hassle of extra messages being sent for the SDP - tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = sdp_rr_response->recv_buf_size; - rss_size = sdp_rr_response->send_buf_size; - rem_nodelay = sdp_rr_response->no_delay; - remote_cpu_usage = sdp_rr_response->measure_cpu; - remote_cpu_rate = sdp_rr_response->cpu_rate; - /* make sure that port numbers are in network order */ - set_port_number(remote_res,(short)sdp_rr_response->data_port_number); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where, - "netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - - exit(1); - } - } - -#ifdef WANT_DEMO - DEMO_RR_SETUP(1000) -#endif - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - remote_res->ai_addr, - remote_res->ai_addrlen) == INVALID_SOCKET){ - perror("netperf: data socket connect failed"); - - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - INTERVALS_INIT(); -#endif /* WANT_INTERVALS */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - -#ifdef WANT_DEMO - if (demo_mode) { - HIST_timestamp(demo_one_ptr); - } -#endif - - while ((!times_up) || (trans_remaining > 0)) { - /* send the request. we assume that if we use a blocking socket, */ - /* the request will be sent at one shot. */ - -#ifdef WANT_FIRST_BURST - /* we can inject no more than request_cwnd, which will grow with - time, and no more than first_burst_size. we don't use <= to - account for the "regularly scheduled" send call. of course - that makes it more a "max_outstanding_ than a - "first_burst_size" but for now we won't fix the names. also, - I suspect the extra check against < first_burst_size is - redundant since later I expect to make sure that request_cwnd - can never get larger than first_burst_size, but just at the - moment I'm feeling like a belt and suspenders kind of - programmer. raj 2006-01-30 */ - while ((first_burst_size > 0) && - (requests_outstanding < request_cwnd) && - (requests_outstanding < first_burst_size)) { - if (debug) { - fprintf(where, - "injecting, req_outstndng %d req_cwnd %d burst %d\n", - requests_outstanding, - request_cwnd, - first_burst_size); - } - if ((len = send(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - /* we should never hit the end of the test in the first burst */ - perror("send_sdp_rr: initial burst data send error"); - exit(-1); - } - requests_outstanding += 1; - } - -#endif /* WANT_FIRST_BURST */ - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - /* timestamp just before our call to send, and then again just - after the receive raj 8/94 */ - /* but only if we are actually going to display one. raj - 2007-02-07 */ - - HIST_timestamp(&time_one); - } -#endif /* WANT_HISTOGRAM */ - - if ((len = send(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - if (SOCKET_EINTR(len) || (errno == 0)) { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("send_sdp_rr: data send error"); - exit(1); - } - send_ring = send_ring->next; - -#ifdef WANT_FIRST_BURST - requests_outstanding += 1; -#endif - - /* receive the response */ - rsp_bytes_left = rsp_size; - temp_message_ptr = recv_ring->buffer_ptr; - while(rsp_bytes_left > 0) { - if((rsp_bytes_recvd=recv(send_socket, - temp_message_ptr, - rsp_bytes_left, - 0)) == SOCKET_ERROR) { - if ( SOCKET_EINTR(rsp_bytes_recvd) ) { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } - perror("send_sdp_rr: data recv error"); - exit(1); - } - rsp_bytes_left -= rsp_bytes_recvd; - temp_message_ptr += rsp_bytes_recvd; - } - recv_ring = recv_ring->next; - -#ifdef WANT_FIRST_BURST - /* so, since we've gotten a response back, update the - bookkeeping accordingly. there is one less request - outstanding and we can put one more out there than before. */ - requests_outstanding -= 1; - if (request_cwnd < first_burst_size) { - request_cwnd += 1; - if (debug) { - fprintf(where, - "incr req_cwnd to %d first_burst %d reqs_outstndng %d\n", - request_cwnd, - first_burst_size, - requests_outstanding); - } - } -#endif - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - } -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_DEMO - DEMO_RR_INTERVAL(1); -#endif - -#ifdef WANT_INTERVALS - INTERVALS_WAIT(); -#endif /* WANT_INTERVALS */ - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - if ((nummessages % 100) == 0) { - fprintf(where, - "Transaction %d completed\n", - nummessages); - fflush(where); - } - } - } - - /* At this point we used to call shutdown on the data socket to be - sure all the data was delivered, but this was not germane in a - request/response test, and it was causing the tests to "hang" - when they were being controlled by time. So, I have replaced - this shutdown call with a call to close that can be found later - in the procedure. */ - - /* this call will always give us the elapsed time for the test, - and will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured? how long */ - /* did we really run? */ - - if (!no_control) { - /* Get the statistics from the remote end. The remote will have - calculated CPU utilization. If it wasn't supposed to care, it - will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - fprintf(where,"netperf: remote error %d", - netperf_response.content.serv_errno); - perror(""); - fflush(where); - exit(1); - } - } - - /* We now calculate what our throughput was for the test. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = nummessages/elapsed_time; - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu - utilization for the system(s) Of course, some of the - information might be bogus because there was no idle counter in - the kernel(s). We need to make a note of this for the user's - benefit... */ - if (local_cpu_usage) { - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will - multiply the number of transaction by 1024 to get "good" - numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - } - - if (remote_cpu_usage) { - remote_cpu_utilization = sdp_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will - multiply the number of transaction by 1024 to get "good" - numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - sdp_rr_result->num_cpus); - } - else { - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = (float) -1.0; - local_service_demand = (float) -1.0; - remote_cpu_utilization = (float) -1.0; - remote_service_demand = (float) -1.0; - } - - /* at this point, we want to calculate the confidence information. - if debugging is on, calculate_confidence will print-out the - parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - - /* we are now done with the socket, so close it */ - close(send_socket); - - } - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user has - specified zero-level verbosity, we will just print the local - service demand, or the remote service demand. If the user has - requested verbosity level 1, he will get the basic "streamperf" - numbers. If the user has specified a verbosity of greater than 1, - we will display a veritable plethora of background information - from outside of this block as it it not cpu_measurement - specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(sdp_rr_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - thruput, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand, /* remote service demand */ - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - thruput, - ((print_headers) || - (result_brand == NULL)) ? "" : result_brand); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - /* how to handle the verbose information in the presence of */ - /* confidence intervals is yet to be determined... raj 11/94 */ - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* SDP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt, - local_send_align, - remote_recv_offset, - local_send_offset, - remote_recv_offset); - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/response times\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - - } - -} - /* this routine implements the receive (netserver) side of a SDP_RR */ - /* test */ -void -recv_sdp_rr() -{ - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - struct addrinfo *local_res; - char local_name[BUFSIZ]; - char port_buffer[PORTBUFSIZE]; - - struct sockaddr_in myaddr_in, - peeraddr_in; - SOCKET s_listen,s_data; - netperf_socklen_t addrlen; - char *temp_message_ptr; - int trans_received; - int trans_remaining; - int bytes_sent; - int request_bytes_recvd; - int request_bytes_remaining; - int timed_out = 0; - int sock_closed = 0; - float elapsed_time; - - struct sdp_rr_request_struct *sdp_rr_request; - struct sdp_rr_response_struct *sdp_rr_response; - struct sdp_rr_results_struct *sdp_rr_results; - - sdp_rr_request = - (struct sdp_rr_request_struct *)netperf_request.content.test_specific_data; - sdp_rr_response = - (struct sdp_rr_response_struct *)netperf_response.content.test_specific_data; - sdp_rr_results = - (struct sdp_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_sdp_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_sdp_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = SDP_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_sdp_rr: the response type is set...\n"); - fflush(where); - } - - /* allocate the recv and send rings with the requested alignments */ - /* and offsets. raj 7/94 */ - if (debug) { - fprintf(where,"recv_sdp_rr: requested recv alignment of %d offset %d\n", - sdp_rr_request->recv_alignment, - sdp_rr_request->recv_offset); - fprintf(where,"recv_sdp_rr: requested send alignment of %d offset %d\n", - sdp_rr_request->send_alignment, - sdp_rr_request->send_offset); - fflush(where); - } - - /* at some point, these need to come to us from the remote system */ - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - sdp_rr_request->response_size, - sdp_rr_request->send_alignment, - sdp_rr_request->send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - sdp_rr_request->request_size, - sdp_rr_request->recv_alignment, - sdp_rr_request->recv_offset); - - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_sdp_rr: grabbing a socket...\n"); - fflush(where); - } - - /* create_data_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = sdp_rr_request->send_buf_size; - lsr_size_req = sdp_rr_request->recv_buf_size; - loc_nodelay = sdp_rr_request->no_delay; - loc_rcvavoid = sdp_rr_request->so_rcvavoid; - loc_sndavoid = sdp_rr_request->so_sndavoid; - - set_hostname_and_port(local_name, - port_buffer, - nf_to_af(sdp_rr_request->ipfamily), - sdp_rr_request->port); - - local_res = complete_addrinfo(local_name, - local_name, - port_buffer, - nf_to_af(sdp_rr_request->ipfamily), - SOCK_STREAM, - IPPROTO_TCP, - 0); - - /* fake things out by changing local_res->ai_family to AF_INET_SDP */ - local_res->ai_family = AF_INET_SDP; - local_res->ai_protocol = 0; - s_listen = create_data_socket(local_res); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - - exit(1); - } - - -#ifdef WIN32 - /* The test timer can fire during operations on the listening socket, - so to make the start_timer below work we have to move - it to close s_listen while we are blocked on accept. */ - win_kludge_socket2 = s_listen; -#endif - - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - sdp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - sdp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */ - sdp_rr_response->measure_cpu = 0; - - if (sdp_rr_request->measure_cpu) { - sdp_rr_response->measure_cpu = 1; - sdp_rr_response->cpu_rate = calibrate_local_cpu(sdp_rr_request->cpu_rate); - } - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - sdp_rr_response->send_buf_size = lss_size; - sdp_rr_response->recv_buf_size = lsr_size; - sdp_rr_response->no_delay = loc_nodelay; - sdp_rr_response->so_rcvavoid = loc_rcvavoid; - sdp_rr_response->so_sndavoid = loc_sndavoid; - sdp_rr_response->test_length = sdp_rr_request->test_length; - send_response(); - - addrlen = sizeof(peeraddr_in); - - if ((s_data = accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - - exit(1); - } - -#ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass */ - /* attributes across an accept() call. Including this goes against */ - /* my better judgement :( raj 11/95 */ - - kludge_socket_options(s_data); - -#endif /* KLUDGE_SOCKET_OPTIONS */ - -#ifdef WIN32 - /* this is used so the timer thread can close the socket out from */ - /* under us, which to date is the easiest/cleanest/least */ - /* Windows-specific way I can find to force the winsock calls to */ - /* return WSAEINTR with the test is over. anything that will run on */ - /* 95 and NT and is closer to what netperf expects from Unix signals */ - /* and such would be appreciated raj 1/96 */ - win_kludge_socket = s_data; -#endif /* WIN32 */ - - if (debug) { - fprintf(where,"recv_sdp_rr: accept completes on the data connection.\n"); - fflush(where); - } - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(sdp_rr_request->measure_cpu); - - /* The loop will exit when we hit the end of the test time, or when */ - /* we have exchanged the requested number of transactions. */ - - if (sdp_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(sdp_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = sdp_rr_request->test_length * -1; - } - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - temp_message_ptr = recv_ring->buffer_ptr; - request_bytes_remaining = sdp_rr_request->request_size; - while(request_bytes_remaining > 0) { - if((request_bytes_recvd=recv(s_data, - temp_message_ptr, - request_bytes_remaining, - 0)) == SOCKET_ERROR) { - if (SOCKET_EINTR(request_bytes_recvd)) - { - timed_out = 1; - break; - } - - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - else if( request_bytes_recvd == 0 ) { - if (debug) { - fprintf(where,"zero is my hero\n"); - fflush(where); - } - sock_closed = 1; - break; - } - else { - request_bytes_remaining -= request_bytes_recvd; - temp_message_ptr += request_bytes_recvd; - } - } - - recv_ring = recv_ring->next; - - if ((timed_out) || (sock_closed)) { - /* we hit the end of the test based on time - or the socket - closed on us along the way. bail out of here now... */ - if (debug) { - fprintf(where,"yo5\n"); - fflush(where); - } - break; - } - - /* Now, send the response to the remote */ - if((bytes_sent=send(s_data, - send_ring->buffer_ptr, - sdp_rr_request->response_size, - 0)) == SOCKET_ERROR) { - if (SOCKET_EINTR(bytes_sent)) { - /* the test timer has popped */ - timed_out = 1; - fprintf(where,"yo6\n"); - fflush(where); - break; - } - netperf_response.content.serv_errno = 992; - send_response(); - exit(1); - } - - send_ring = send_ring->next; - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(sdp_rr_request->measure_cpu,&elapsed_time); - - stop_timer(); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_sdp_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - sdp_rr_results->bytes_received = (trans_received * - (sdp_rr_request->request_size + - sdp_rr_request->response_size)); - sdp_rr_results->trans_received = trans_received; - sdp_rr_results->elapsed_time = elapsed_time; - sdp_rr_results->cpu_method = cpu_method; - sdp_rr_results->num_cpus = lib_num_loc_cpus; - if (sdp_rr_request->measure_cpu) { - sdp_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_sdp_rr: test complete, sending results.\n"); - fflush(where); - } - - /* we are now done with the sockets */ - close(s_data); - close(s_listen); - - send_response(); - -} - - - -void -print_sdp_usage() -{ - - printf("%s",sdp_usage); - exit(1); - -} -void -scan_sdp_args(argc, argv) - int argc; - char *argv[]; - -{ - -#define SOCKETS_ARGS "b:DhH:I:L:m:M:P:r:s:S:V46" - - extern char *optarg; /* pointer to option string */ - - int c; - - char - arg1[BUFSIZ], /* argument holders */ - arg2[BUFSIZ]; - - if (no_control) { - fprintf(where, - "The SDP tests do not know how to deal with no control tests\n"); - exit(-1); - } - - strncpy(local_data_port,"0",sizeof(local_data_port)); - strncpy(remote_data_port,"0",sizeof(remote_data_port)); - - /* Go through all the command line arguments and break them */ - /* out. For those options that take two parms, specifying only */ - /* the first will set both to that value. Specifying only the */ - /* second will leave the first untouched. To change only the */ - /* first, use the form "first," (see the routine break_args.. */ - - while ((c= getopt(argc, argv, SOCKETS_ARGS)) != EOF) { - switch (c) { - case '?': - case '4': - remote_data_family = AF_INET; - local_data_family = AF_INET; - break; - case '6': -#if defined(AF_INET6) - remote_data_family = AF_INET6; - local_data_family = AF_INET6; -#else - fprintf(stderr, - "This netperf was not compiled on an IPv6 capable host!\n"); - fflush(stderr); - exit(-1); -#endif - break; - case 'h': - print_sdp_usage(); - exit(1); - case 'b': -#ifdef WANT_FIRST_BURST - first_burst_size = atoi(optarg); -#else /* WANT_FIRST_BURST */ - printf("Initial request burst functionality not compiled-in!\n"); -#endif /* WANT_FIRST_BURST */ - break; - case 'D': - /* set the nodelay flag */ - loc_nodelay = 1; - rem_nodelay = 1; - break; - case 'H': - break_args_explicit(optarg,arg1,arg2); - if (arg1[0]) { - /* make sure we leave room for the NULL termination boys and - girls. raj 2005-02-82 */ - remote_data_address = malloc(strlen(arg1)+1); - strncpy(remote_data_address,arg1,strlen(arg1)); - } - if (arg2[0]) - remote_data_family = parse_address_family(arg2); - break; - case 'L': - break_args_explicit(optarg,arg1,arg2); - if (arg1[0]) { - /* make sure we leave room for the NULL termination boys and - girls. raj 2005-02-82 */ - local_data_address = malloc(strlen(arg1)+1); - strncpy(local_data_address,arg1,strlen(arg1)); - } - if (arg2[0]) - local_data_family = parse_address_family(arg2); - break; - case 'P': - /* set the local and remote data port numbers for the tests to - allow them to run through those blankety blank end-to-end - breaking firewalls. raj 2004-06-15 */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - strncpy(local_data_port,arg1,sizeof(local_data_port)); - if (arg2[0]) - strncpy(remote_data_port,arg2,sizeof(remote_data_port)); - break; - case 's': - /* set local socket sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - lss_size_req = convert(arg1); - if (arg2[0]) - lsr_size_req = convert(arg2); - break; - case 'S': - /* set remote socket sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - rss_size_req = convert(arg1); - if (arg2[0]) - rsr_size_req = convert(arg2); - break; - case 'r': - /* set the request/response sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - req_size = convert(arg1); - if (arg2[0]) - rsp_size = convert(arg2); - break; - case 'm': - /* set size of the buffer for each sent message */ - send_size = convert(optarg); - break; - case 'M': - /* set the size of the buffer for each received message */ - recv_size = convert(optarg); - break; - case 't': - /* set the test name */ - strcpy(test_name,optarg); - break; - case 'W': - /* set the "width" of the user space data */ - /* buffer. This will be the number of */ - /* send_size buffers malloc'd in the */ - /* *_STREAM test. It may be enhanced to set */ - /* both send and receive "widths" but for now */ - /* it is just the sending *_STREAM. */ - send_width = convert(optarg); - break; - case 'V': - /* we want to do copy avoidance and will set */ - /* it for everything, everywhere, if we really */ - /* can. of course, we don't know anything */ - /* about the remote... */ -#ifdef SO_SND_COPYAVOID - loc_sndavoid = 1; -#else - loc_sndavoid = 0; - printf("Local send copy avoidance not available.\n"); -#endif -#ifdef SO_RCV_COPYAVOID - loc_rcvavoid = 1; -#else - loc_rcvavoid = 0; - printf("Local recv copy avoidance not available.\n"); -#endif - rem_sndavoid = 1; - rem_rcvavoid = 1; - break; - case 'N': - /* this opton allows the user to set the number of - * messages to send. This in effect modifies the test - * time. If we know the message size, then the we can - * express the test time as message_size * number_messages - */ - msg_count = convert (optarg); - if (msg_count > 0) - test_time = 0; - break; - case 'B': - non_block = 1; - break; - case 'T': - num_associations = atoi(optarg); - if (num_associations <= 1) { - printf("Number of SDP associations must be >= 1\n"); - exit(1); - } - break; - }; - } -} - -#endif /* WANT_SDP */ diff --git a/nettest_sdp.h b/nettest_sdp.h deleted file mode 100644 index 31d76bc..0000000 --- a/nettest_sdp.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - Copyright (C) 2007 Hewlett-Packard Company -*/ - - /* This file contains the test-specific definitions for netperf's SDP */ - /* sockets tests */ - -/* one of these days, this should not be required */ -#ifndef AF_INET_SDP -#define AF_INET_SDP 27 -#define PF_INET_SDP AF_INET_SDP -#endif - -struct sdp_stream_request_struct { - int send_buf_size; - int recv_buf_size; /* how big does the client want it - the */ - /* receive socket buffer that is */ - int receive_size; /* how many bytes do we want to receive at one */ - /* time? */ - int recv_alignment; /* what is the alignment of the receive */ - /* buffer? */ - int recv_offset; /* and at what offset from that alignment? */ - int no_delay; /* do we disable the nagle algorithm for send */ - /* coalescing? */ - int measure_cpu; /* does the client want server cpu utilization */ - /* measured? */ - float cpu_rate; /* do we know how fast the cpu is already? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid copies on */ - /* receives? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dirty_count; /* how many integers in the receive buffer */ - /* should be made dirty before calling recv? */ - int clean_count; /* how many integers should be read from the */ - /* recv buffer before calling recv? */ - int port; /* the to port to which recv side should bind - to allow netperf to run through firewalls */ - int ipfamily; /* address family of ipaddress */ - int non_blocking; /* run the test in non-blocking mode */ -}; - -struct sdp_stream_response_struct { - int recv_buf_size; /* how big does the client want it */ - int receive_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ - int non_blocking; /* run the test in non-blocking mode */ -}; - -struct sdp_stream_results_struct { - double bytes_received; - unsigned int recv_calls; - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -struct sdp_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int port; /* the to port to which recv side should bind - to allow netperf to run through firewalls */ - int ipfamily; /* address family of ipaddress */ - int non_blocking; /* run the test in non-blocking mode */ -}; - -struct sdp_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ - int non_blocking; /* run the test in non-blocking mode */ -}; - -struct sdp_rr_results_struct { - unsigned int bytes_received; /* ignored initially */ - unsigned int recv_calls; /* ignored initially */ - unsigned int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -struct sdp_maerts_request_struct { - int send_buf_size; - int recv_buf_size; /* how big does the client want it - the */ - /* receive socket buffer that is */ - int send_size; /* how many bytes do we want netserver to send - at one time? */ - int send_alignment; /* what is the alignment of the send */ - /* buffer? */ - int send_offset; /* and at what offset from that alignment? */ - int no_delay; /* do we disable the nagle algorithm for send */ - /* coalescing? */ - int measure_cpu; /* does the client want server cpu utilization */ - /* measured? */ - float cpu_rate; /* do we know how fast the cpu is already? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid copies on */ - /* receives? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dirty_count; /* how many integers in the send buffer */ - /* should be made dirty before calling recv? */ - int clean_count; /* how many integers should be read from the */ - /* recv buffer before calling recv? */ - int port; /* the port to which the recv side should bind - to allow netperf to run through those evil - firewall things */ - int ipfamily; -}; - -struct sdp_maerts_response_struct { - int recv_buf_size; /* how big does the client want it */ - int send_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct sdp_maerts_results_struct { - double bytes_sent; - unsigned int send_calls; - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs had the remote? */ -}; - -extern void send_sdp_stream(); -extern void send_sdp_rr(); - -extern void recv_sdp_stream(); -extern void recv_sdp_rr(); - -extern void loc_cpu_rate(); -extern void rem_cpu_rate(); diff --git a/nettest_unix.c b/nettest_unix.c deleted file mode 100644 index e4716a4..0000000 --- a/nettest_unix.c +++ /dev/null @@ -1,3431 +0,0 @@ -#ifdef lint -#define WANT_UNIX -#define DIRTY -#define WANT_INTERVALS -#endif /* lint */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef WANT_UNIX -char nettest_unix_id[]="\ -@(#)nettest_unix.c (c) Copyright 1994-2007 Hewlett-Packard Co. Version 2.4.3"; - -/****************************************************************/ -/* */ -/* nettest_bsd.c */ -/* */ -/* the BSD sockets parsing routine... */ -/* */ -/* scan_unix_args() */ -/* */ -/* the actual test routines... */ -/* */ -/* send_stream_stream() perform a stream stream test */ -/* recv_stream_stream() */ -/* send_stream_rr() perform a stream request/response */ -/* recv_stream_rr() */ -/* send_dg_stream() perform a dg stream test */ -/* recv_dg_stream() */ -/* send_dg_rr() perform a dg request/response */ -/* recv_dg_rr() */ -/* loc_cpu_rate() determine the local cpu maxrate */ -/* rem_cpu_rate() find the remote cpu maxrate */ -/* */ -/****************************************************************/ - - /* at some point, I might want to go-in and see if I really need all */ - /* these includes, but for the moment, we'll let them all just sit */ - /* there. raj 8/94 */ -#include <sys/types.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#ifndef WIN32 -#include <sys/ipc.h> -#include <sys/socket.h> -#include <errno.h> -#include <signal.h> -#include <sys/un.h> -#include <unistd.h> -#else /* WIN32 */ -#include <process.h> -#include <winsock2.h> -#include <windows.h> -#endif /* WIN32 */ -#include <string.h> -#include <time.h> -#include <sys/time.h> - -#ifdef NOSTDLIBH -#include <malloc.h> -#else /* NOSTDLIBH */ -#include <stdlib.h> -#endif /* NOSTDLIBH */ - -#include <sys/stat.h> - - -#include "netlib.h" -#include "netsh.h" -#include "nettest_unix.h" - - - - /* these variables are specific to the UNIX sockets tests. declare */ - /* them static to make them global only to this file. */ - -#define UNIX_PRFX "netperf." -#define UNIX_LENGTH_MAX 0xFFFF - 28 - -static char - path_prefix[32]; - -static int - rss_size, /* remote socket send buffer size */ - rsr_size, /* remote socket recv buffer size */ - lss_size_req, /* requested local socket send buffer size */ - lsr_size_req, /* requested local socket recv buffer size */ - lss_size, /* local socket send buffer size */ - lsr_size, /* local socket recv buffer size */ - req_size = 1, /* request size */ - rsp_size = 1, /* response size */ - send_size, /* how big are individual sends */ - recv_size; /* how big are individual receives */ - - /* different options for the sockets */ - - -char unix_usage[] = "\n\ -Usage: netperf [global options] -- [test options] \n\ -\n\ -STREAM/DG UNIX Sockets Test Options:\n\ - -h Display this text\n\ - -m bytes Set the send size (STREAM_STREAM, DG_STREAM)\n\ - -M bytes Set the recv size (STREAM_STREAM, DG_STREAM)\n\ - -p dir Set the directory where pipes are created\n\ - -r req,res Set request,response size (STREAM_RR, DG_RR)\n\ - -s send[,recv] Set local socket send/recv buffer sizes\n\ - -S send[,recv] Set remote socket send/recv buffer sizes\n\ -\n\ -For those options taking two parms, at least one must be specified;\n\ -specifying one value without a comma will set both parms to that\n\ -value, specifying a value with a leading comma will set just the second\n\ -parm, a value with a trailing comma will set just the first. To set\n\ -each parm to unique values, specify both and separate them with a\n\ -comma.\n"; - - /* this routing initializes all the test specific variables */ - -static void -init_test_vars() -{ - rss_size = 0; - rsr_size = 0; - lss_size_req = 0; - lsr_size_req = 0; - lss_size = 0; - lsr_size = 0; - req_size = 1; - rsp_size = 1; - send_size = 0; - recv_size = 0; - - strcpy(path_prefix,"/tmp"); - -} - - /* This routine will create a data (listen) socket with the apropriate */ - /* options set and return it to the caller. this replaces all the */ - /* duplicate code in each of the test routines and should help make */ - /* things a little easier to understand. since this routine can be */ - /* called by either the netperf or netserver programs, all output */ - /* should be directed towards "where." family is generally AF_UNIX, */ - /* and type will be either SOCK_STREAM or SOCK_DGRAM */ -SOCKET -create_unix_socket(int family, int type) -{ - - SOCKET temp_socket; - int sock_opt_len; - - /*set up the data socket */ - temp_socket = socket(family, - type, - 0); - - if (temp_socket == INVALID_SOCKET){ - fprintf(where, - "netperf: create_unix_socket: socket: %d\n", - errno); - fflush(where); - exit(1); - } - - if (debug) { - fprintf(where,"create_unix_socket: socket %d obtained...\n",temp_socket); - fflush(where); - } - - /* Modify the local socket size. The reason we alter the send buffer */ - /* size here rather than when the connection is made is to take care */ - /* of decreases in buffer size. Decreasing the window size after */ - /* connection establishment is a STREAM no-no. Also, by setting the */ - /* buffer (window) size before the connection is established, we can */ - /* control the STREAM MSS (segment size). The MSS is never more that 1/2 */ - /* the minimum receive buffer size at each half of the connection. */ - /* This is why we are altering the receive buffer size on the sending */ - /* size of a unidirectional transfer. If the user has not requested */ - /* that the socket buffers be altered, we will try to find-out what */ - /* their values are. If we cannot touch the socket buffer in any way, */ - /* we will set the values to -1 to indicate that. */ - - set_sock_buffer(temp_socket, SEND_BUFFER, lss_size_req, &lss_size); - set_sock_buffer(temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size); - - return(temp_socket); - -} - - -/* This routine implements the STREAM unidirectional data transfer test */ -/* (a.k.a. stream) for the sockets interface. It receives its */ -/* parameters via global variables from the shell and writes its */ -/* output to the standard output. */ - - -void -send_stream_stream(char remote_host[]) -{ - - char *tput_title = "\ -Recv Send Send \n\ -Socket Socket Message Elapsed \n\ -Size Size Size Time Throughput \n\ -bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = - "%5d %5d %6d %-6.2f %7.2f \n"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Socket Socket Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -bytes bytes bytes secs. %-8.8s/s %% %% us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f\n"; - - char *cpu_fmt_1 = - "%5d %5d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ -Local Remote Local Remote Xfered Per Per\n\ -Send Recv Send Recv Send (avg) Recv (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - - - float elapsed_time; - -#ifdef WANT_INTERVALS - int interval_count; -#endif - - /* what we want is to have a buffer space that is at least one */ - /* send-size greater than our send window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - -#ifdef DIRTY - int *message_int_ptr; -#endif -#include <sys/stat.h> - - struct ring_elt *send_ring; - - int len = 0; - int nummessages; - SOCKET send_socket; - int bytes_remaining; - /* with links like fddi, one can send > 32 bits worth of bytes */ - /* during a test... ;-) */ - double bytes_sent; - -#ifdef DIRTY - int i; -#endif /* DIRTY */ - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct sockaddr_un server; - - struct stream_stream_request_struct *stream_stream_request; - struct stream_stream_response_struct *stream_stream_response; - struct stream_stream_results_struct *stream_stream_result; - - stream_stream_request = - (struct stream_stream_request_struct *)netperf_request.content.test_specific_data; - stream_stream_response = - (struct stream_stream_response_struct *)netperf_response.content.test_specific_data; - stream_stream_result = - (struct stream_stream_results_struct *)netperf_response.content.test_specific_data; - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - bzero((char *)&server, - sizeof(server)); - server.sun_family = AF_UNIX; - - - if ( print_headers ) { - fprintf(where,"STREAM STREAM TEST\n"); - if (local_cpu_usage || remote_cpu_usage) - fprintf(where,cpu_title,format_units()); - else - fprintf(where,tput_title,format_units()); - } - - /* initialize a few counters */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - - /*set up the data socket */ - send_socket = create_unix_socket(AF_UNIX, - SOCK_STREAM); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_stream_stream: stream stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_stream_stream: send_socket obtained...\n"); - } - - /* at this point, we have either retrieved the socket buffer sizes, */ - /* or have tried to set them, so now, we may want to set the send */ - /* size based on that (because the user either did not use a -m */ - /* option, or used one with an argument of 0). If the socket buffer */ - /* size is not available, we will set the send size to 4KB - no */ - /* particular reason, just arbitrary... */ - if (send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - - /* set-up the data buffer ring with the requested alignment and offset. */ - /* note also that we have allocated a quantity */ - /* of memory that is at least one send-size greater than our socket */ - /* buffer size. We want to be sure that there are at least two */ - /* buffers allocated - this can be a bit of a problem when the */ - /* send_size is bigger than the socket size, so we must check... the */ - /* user may have wanted to explicitly set the "width" of our send */ - /* buffers, we should respect that wish... */ - if (send_width == 0) { - send_width = (lss_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - send_ring = allocate_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset); - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 1, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_STREAM_STREAM; - stream_stream_request->send_buf_size = rss_size; - stream_stream_request->recv_buf_size = rsr_size; - stream_stream_request->receive_size = recv_size; - stream_stream_request->recv_alignment = remote_recv_align; - stream_stream_request->recv_offset = remote_recv_offset; - stream_stream_request->measure_cpu = remote_cpu_usage; - stream_stream_request->cpu_rate = remote_cpu_rate; - if (test_time) { - stream_stream_request->test_length = test_time; - } - else { - stream_stream_request->test_length = test_bytes; - } -#ifdef DIRTY - stream_stream_request->dirty_count = rem_dirty_count; - stream_stream_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - - - if (debug > 1) { - fprintf(where, - "netperf: send_stream_stream: requesting STREAM stream test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right */ - /* after the connect returns. The remote will grab the counter right */ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the STREAM tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = stream_stream_response->recv_buf_size; - rss_size = stream_stream_response->send_buf_size; - remote_cpu_usage = stream_stream_response->measure_cpu; - remote_cpu_rate = stream_stream_response->cpu_rate; - strcpy(server.sun_path,stream_stream_response->unix_path); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: send_stream_stream: remote error"); - exit(1); - } - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - (struct sockaddr *)&server, - sizeof(server)) == INVALID_SOCKET){ - perror("netperf: send_stream_stream: data socket connect failed"); - printf(" path: %s\n",server.sun_path); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a stream test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - bytes_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. */ - -#ifdef DIRTY - /* initialize the random number generator for putting dirty stuff */ - /* into the send buffer. raj */ - srand((int) getpid()); -#endif - - while ((!times_up) || (bytes_remaining > 0)) { - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. at some point, we might want to replace */ - /* the rand() call with something from a table to reduce our call */ - /* overhead during the test, but it is not a high priority item. */ - message_int_ptr = (int *)(send_ring->buffer_ptr); - for (i = 0; i < loc_dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < loc_clean_count; i++) { - loc_dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - - if((len=send(send_socket, - send_ring->buffer_ptr, - send_size, - 0)) != send_size) { - if ((len >=0) || (errno == EINTR)) { - /* the test was interrupted, must be the end of test */ - break; - } - perror("netperf: data send error"); - printf("len was %d\n",len); - exit(1); - } -#ifdef WANT_INTERVALS - for (interval_count = 0; - interval_count < interval_wate; - interval_count++); -#endif - - /* now we want to move our pointer to the next position in the */ - /* data buffer...we may also want to wrap back to the "beginning" */ - /* of the bufferspace, so we will mod the number of messages sent */ - /* by the send width, and use that to calculate the offset to add */ - /* to the base pointer. */ - nummessages++; - send_ring = send_ring->next; - if (bytes_remaining) { - bytes_remaining -= send_size; - } - } - - /* The test is over. Flush the buffers to the remote end. We do a */ - /* graceful release to insure that all data has been taken by the */ - /* remote. */ - - if (close(send_socket) == -1) { - perror("netperf: send_stream_stream: cannot close socket"); - exit(1); - } - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured and how */ - /* long did we really */ - /* run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a STREAM stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) */ - - bytes_sent = ((double) send_size * (double) nummessages) + len; - thruput = calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where,"Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where,"Remote CPU usage numbers based on process information only!\n"); - fflush(where); - } - remote_cpu_utilization = stream_stream_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - stream_stream_result->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - case 2: - fprintf(where, - cpu_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput); - break; - case 1: - case 2: - fprintf(where, - tput_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - thruput);/* how fast did it go */ - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* STREAM statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_send_align, - remote_recv_align, - local_send_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)stream_stream_result->recv_calls, - stream_stream_result->recv_calls); - } - -} - - -/* This is the server-side routine for the stream stream test. It is */ -/* implemented as one routine. I could break things-out somewhat, but */ -/* didn't feel it was necessary. */ - -void -recv_stream_stream() -{ - - struct sockaddr_un myaddr_un, peeraddr_un; - SOCKET s_listen,s_data; - int addrlen; - int len; - int receive_calls = 0; - float elapsed_time; - int bytes_received; - - struct ring_elt *recv_ring; - -#ifdef DIRTY - char *message_ptr; - int *message_int_ptr; - int dirty_count; - int clean_count; - int i; -#endif - - struct stream_stream_request_struct *stream_stream_request; - struct stream_stream_response_struct *stream_stream_response; - struct stream_stream_results_struct *stream_stream_results; - - stream_stream_request = - (struct stream_stream_request_struct *)netperf_request.content.test_specific_data; - stream_stream_response = - (struct stream_stream_response_struct *)netperf_response.content.test_specific_data; - stream_stream_results = - (struct stream_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_stream_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_stream_stream: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = STREAM_STREAM_RESPONSE; - - if (debug) { - fprintf(where,"recv_stream_stream: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug) { - fprintf(where,"recv_stream_stream: requested alignment of %d\n", - stream_stream_request->recv_alignment); - fflush(where); - } - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - bzero((char *)&myaddr_un, - sizeof(myaddr_un)); - myaddr_un.sun_family = AF_UNIX; - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_stream_stream: grabbing a socket...\n"); - fflush(where); - } - - /* create_unix_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = stream_stream_request->send_buf_size; - lsr_size_req = stream_stream_request->recv_buf_size; - - s_listen = create_unix_socket(AF_UNIX, - SOCK_STREAM); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf.")); - if (debug) { - fprintf(where,"selected a path of %s\n",myaddr_un.sun_path); - fflush(where); - } - if (bind(s_listen, - (struct sockaddr *)&myaddr_un, - sizeof(myaddr_un)) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - fprintf(where,"could not bind to path\n"); - close(s_listen); - send_response(); - - exit(1); - } - - chmod(myaddr_un.sun_path, 0666); - - /* what sort of sizes did we end-up with? */ - if (stream_stream_request->receive_size == 0) { - if (lsr_size > 0) { - recv_size = lsr_size; - } - else { - recv_size = 4096; - } - } - else { - recv_size = stream_stream_request->receive_size; - } - - /* we want to set-up our recv_ring in a manner analagous to what we */ - /* do on the sending side. this is more for the sake of symmetry */ - /* than for the needs of say copy avoidance, but it might also be */ - /* more realistic - this way one could conceivably go with a */ - /* double-buffering scheme when taking the data an putting it into */ - /* the filesystem or something like that. raj 7/94 */ - - if (recv_width == 0) { - recv_width = (lsr_size/recv_size) + 1; - if (recv_width == 1) recv_width++; - } - - recv_ring = allocate_buffer_ring(recv_width, - recv_size, - stream_stream_request->recv_alignment, - stream_stream_request->recv_offset); - - if (debug) { - fprintf(where,"recv_stream_stream: receive alignment and offset set...\n"); - fflush(where); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_un); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_un, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_un contains the path */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - strcpy(stream_stream_response->unix_path,myaddr_un.sun_path); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - stream_stream_response->cpu_rate = 0.0; /* assume no cpu */ - if (stream_stream_request->measure_cpu) { - stream_stream_response->measure_cpu = 1; - stream_stream_response->cpu_rate = - calibrate_local_cpu(stream_stream_request->cpu_rate); - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - stream_stream_response->send_buf_size = lss_size; - stream_stream_response->recv_buf_size = lsr_size; - stream_stream_response->receive_size = recv_size; - - send_response(); - - addrlen = sizeof(peeraddr_un); - - if ((s_data=accept(s_listen, - (struct sockaddr *)&peeraddr_un, - &addrlen)) == INVALID_SOCKET) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - exit(1); - } - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(stream_stream_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to recv. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - - dirty_count = stream_stream_request->dirty_count; - clean_count = stream_stream_request->clean_count; - message_int_ptr = (int *)recv_ring->buffer_ptr; - for (i = 0; i < dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < clean_count; i++) { - dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - bytes_received = 0; - - while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) { - if (len == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - bytes_received += len; - receive_calls++; - - /* more to the next buffer in the recv_ring */ - recv_ring = recv_ring->next; - -#ifdef DIRTY - message_int_ptr = (int *)(recv_ring->buffer_ptr); - for (i = 0; i < dirty_count; i++) { - *message_int_ptr = rand(); - message_int_ptr++; - } - for (i = 0; i < clean_count; i++) { - dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - } - - /* The loop now exits due to zero bytes received. we will have */ - /* counted one too many messages received, so decrement the */ - /* receive_calls counter by one. raj 7/94 */ - receive_calls--; - - /* perform a shutdown to signal the sender that */ - /* we have received all the data sent. raj 4/93 */ - - if (shutdown(s_data,1) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - cpu_stop(stream_stream_request->measure_cpu,&elapsed_time); - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_stream_stream: got %d bytes\n", - bytes_received); - fprintf(where, - "recv_stream_stream: got %d recvs\n", - receive_calls); - fflush(where); - } - - stream_stream_results->bytes_received = bytes_received; - stream_stream_results->elapsed_time = elapsed_time; - stream_stream_results->recv_calls = receive_calls; - - if (stream_stream_request->measure_cpu) { - stream_stream_results->cpu_util = calc_cpu_util(0.0); - }; - - if (debug > 1) { - fprintf(where, - "recv_stream_stream: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - unlink(myaddr_un.sun_path); -} - - - /* this routine implements the sending (netperf) side of the STREAM_RR */ - /* test. */ - -void -send_stream_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - int timed_out = 0; - float elapsed_time; - - int len; - char *temp_message_ptr; - int nummessages; - SOCKET send_socket; - int trans_remaining; - double bytes_xferd; - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - int rsp_bytes_left; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct sockaddr_un server; - - struct stream_rr_request_struct *stream_rr_request; - struct stream_rr_response_struct *stream_rr_response; - struct stream_rr_results_struct *stream_rr_result; - - stream_rr_request = - (struct stream_rr_request_struct *)netperf_request.content.test_specific_data; - stream_rr_response= - (struct stream_rr_response_struct *)netperf_response.content.test_specific_data; - stream_rr_result = - (struct stream_rr_results_struct *)netperf_response.content.test_specific_data; - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - bzero((char *)&server, - sizeof(server)); - - server.sun_family = AF_UNIX; - - - if ( print_headers ) { - fprintf(where,"STREAM REQUEST/RESPONSE TEST\n"); - if (local_cpu_usage || remote_cpu_usage) - fprintf(where,cpu_title,format_units()); - else - fprintf(where,tput_title,format_units()); - } - - /* initialize a few counters */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - - /* set-up the data buffers with the requested alignment and offset. */ - /* since this is a request/response test, default the send_width and */ - /* recv_width to 1 and not two raj 7/94 */ - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - - /*set up the data socket */ - send_socket = create_unix_socket(AF_UNIX, - SOCK_STREAM); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_stream_rr: stream stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_stream_rr: send_socket obtained...\n"); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_STREAM_RR; - stream_rr_request->recv_buf_size = rsr_size; - stream_rr_request->send_buf_size = rss_size; - stream_rr_request->recv_alignment= remote_recv_align; - stream_rr_request->recv_offset = remote_recv_offset; - stream_rr_request->send_alignment= remote_send_align; - stream_rr_request->send_offset = remote_send_offset; - stream_rr_request->request_size = req_size; - stream_rr_request->response_size = rsp_size; - stream_rr_request->measure_cpu = remote_cpu_usage; - stream_rr_request->cpu_rate = remote_cpu_rate; - if (test_time) { - stream_rr_request->test_length = test_time; - } - else { - stream_rr_request->test_length = test_trans * -1; - } - - if (debug > 1) { - fprintf(where,"netperf: send_stream_rr: requesting STREAM rr test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right */ - /* after the connect returns. The remote will grab the counter right */ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the STREAM tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = stream_rr_response->recv_buf_size; - rss_size = stream_rr_response->send_buf_size; - remote_cpu_usage= stream_rr_response->measure_cpu; - remote_cpu_rate = stream_rr_response->cpu_rate; - /* make sure that port numbers are in network order */ - strcpy(server.sun_path,stream_rr_response->unix_path); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /*Connect up to the remote port on the data socket */ - if (connect(send_socket, - (struct sockaddr *)&server, - sizeof(server)) == INVALID_SOCKET){ - perror("netperf: data socket connect failed"); - - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - - while ((!times_up) || (trans_remaining > 0)) { - /* send the request. we assume that if we use a blocking socket, */ - /* the request will be sent at one shot. */ - if((len=send(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - if (errno == EINTR) { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("send_stream_rr: data send error"); - exit(1); - } - send_ring = send_ring->next; - - /* receive the response */ - rsp_bytes_left = rsp_size; - temp_message_ptr = recv_ring->buffer_ptr; - while(rsp_bytes_left > 0) { - if((rsp_bytes_recvd=recv(send_socket, - temp_message_ptr, - rsp_bytes_left, - 0)) == SOCKET_ERROR) { - if (errno == EINTR) { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } - perror("send_stream_rr: data recv error"); - exit(1); - } - rsp_bytes_left -= rsp_bytes_recvd; - temp_message_ptr += rsp_bytes_recvd; - } - recv_ring = recv_ring->next; - - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - fprintf(where, - "Transaction %d completed\n", - nummessages); - fflush(where); - } - } - - /* At this point we used to call shutdown on the data socket to be */ - /* sure all the data was delivered, but this was not germane in a */ - /* request/response test, and it was causing the tests to "hang" when */ - /* they were being controlled by time. So, I have replaced this */ - /* shutdown call with a call to close that can be found later in the */ - /* procedure. */ - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ - /* how long did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a STREAM stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) We use */ - /* Kbytes/s as the units of thruput for a STREAM stream test, where K = */ - /* 1024. A future enhancement *might* be to choose from a couple of */ - /* unit selections. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = calc_thruput(bytes_xferd); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where,"Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where,"Remote CPU usage numbers based on process information only!\n"); - fflush(where); - } - remote_cpu_utilization = stream_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - stream_rr_result->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - nummessages/elapsed_time, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - nummessages/elapsed_time); - break; - case 1: - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - nummessages/elapsed_time); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* STREAM statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt); - } - /* The test is over. Kill the data socket */ - - if (close(send_socket) == -1) { - perror("send_stream_rr: cannot shutdown stream stream socket"); - } - -} - -void -send_dg_stream(char remote_host[]) -{ - /************************************************************************/ - /* */ - /* DG Unidirectional Send Test */ - /* */ - /************************************************************************/ - char *tput_title = - "Socket Message Elapsed Messages \n\ -Size Size Time Okay Errors Throughput\n\ -bytes bytes secs # # %s/sec\n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = - "%5d %5d %-7.2f %7d %6d %7.2f\n\ -%5d %-7.2f %7d %7.2f\n\n"; - - - char *cpu_title = - "Socket Message Elapsed Messages CPU Service\n\ -Size Size Time Okay Errors Throughput Util Demand\n\ -bytes bytes secs # # %s/sec %% us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.2f\n"; - - char *cpu_fmt_1 = - "%5d %5d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\ -%5d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n"; - - int messages_recvd; - float elapsed_time, - local_cpu_utilization, - remote_cpu_utilization; - - float local_service_demand, remote_service_demand; - double local_thruput, remote_thruput; - double bytes_sent; - double bytes_recvd; - - - int len; - struct ring_elt *send_ring; - int failed_sends; - int failed_cows; - int messages_sent; - SOCKET data_socket; - - -#ifdef WANT_INTERVALS - int interval_count; -#endif /* WANT_INTERVALS */ -#ifdef DIRTY - int *message_int_ptr; - int i; -#endif /* DIRTY */ - - struct sockaddr_un server; - - struct dg_stream_request_struct *dg_stream_request; - struct dg_stream_response_struct *dg_stream_response; - struct dg_stream_results_struct *dg_stream_results; - - dg_stream_request = (struct dg_stream_request_struct *)netperf_request.content.test_specific_data; - dg_stream_response = (struct dg_stream_response_struct *)netperf_response.content.test_specific_data; - dg_stream_results = (struct dg_stream_results_struct *)netperf_response.content.test_specific_data; - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - bzero((char *)&server, - sizeof(server)); - - server.sun_family = AF_UNIX; - - if ( print_headers ) { - printf("DG UNIDIRECTIONAL SEND TEST\n"); - if (local_cpu_usage || remote_cpu_usage) - printf(cpu_title,format_units()); - else - printf(tput_title,format_units()); - } - - failed_sends = 0; - failed_cows = 0; - messages_sent = 0; - times_up = 0; - - /*set up the data socket */ - data_socket = create_unix_socket(AF_UNIX, - SOCK_DGRAM); - - if (data_socket == INVALID_SOCKET){ - perror("dg_send: data socket"); - exit(1); - } - - /* now, we want to see if we need to set the send_size */ - if (send_size == 0) { - if (lss_size > 0) { - send_size = (lss_size < UNIX_LENGTH_MAX ? lss_size : UNIX_LENGTH_MAX); - } - else { - send_size = 4096; - } - } - - - /* set-up the data buffer with the requested alignment and offset, */ - /* most of the numbers here are just a hack to pick something nice */ - /* and big in an attempt to never try to send a buffer a second time */ - /* before it leaves the node...unless the user set the width */ - /* explicitly. */ - if (send_width == 0) send_width = 32; - - send_ring = allocate_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset); - - /* At this point, we want to do things like disable DG checksumming */ - /* and measure the cpu rate and all that so we are ready to go */ - /* immediately after the test response message is delivered. */ - - /* if the user supplied a cpu rate, this call will complete rather */ - /* quickly, otherwise, the cpu rate will be retured to us for */ - /* possible display. The Library will keep it's own copy of this data */ - /* for use elsewhere. We will only display it. (Does that make it */ - /* "opaque" to us?) */ - - if (local_cpu_usage) - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - - /* Tell the remote end to set up the data connection. The server */ - /* sends back the port number and alters the socket parameters there. */ - /* Of course this is a datagram service so no connection is actually */ - /* set up, the server just sets up the socket and binds it. */ - - netperf_request.content.request_type = DO_DG_STREAM; - dg_stream_request->recv_buf_size = rsr_size; - dg_stream_request->message_size = send_size; - dg_stream_request->recv_alignment = remote_recv_align; - dg_stream_request->recv_offset = remote_recv_offset; - dg_stream_request->measure_cpu = remote_cpu_usage; - dg_stream_request->cpu_rate = remote_cpu_rate; - dg_stream_request->test_length = test_time; - - send_request(); - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"send_dg_stream: remote data connection done.\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("send_dg_stream: error on remote"); - exit(1); - } - - /* Place the port number returned by the remote into the sockaddr */ - /* structure so our sends can be sent to the correct place. Also get */ - /* some of the returned socket buffer information for user display. */ - - /* make sure that port numbers are in the proper order */ - strcpy(server.sun_path,dg_stream_response->unix_path); - rsr_size = dg_stream_response->recv_buf_size; - rss_size = dg_stream_response->send_buf_size; - remote_cpu_rate = dg_stream_response->cpu_rate; - - /* We "connect" up to the remote post to allow is to use the send */ - /* call instead of the sendto call. Presumeably, this is a little */ - /* simpler, and a little more efficient. I think that it also means */ - /* that we can be informed of certain things, but am not sure yet... */ - - if (connect(data_socket, - (struct sockaddr *)&server, - sizeof(server)) == INVALID_SOCKET){ - perror("send_dg_stream: data socket connect failed"); - exit(1); - } - - /* set up the timer to call us after test_time */ - start_timer(test_time); - - /* Get the start count for the idle counter and the start time */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - interval_count = interval_burst; -#endif - - /* Send datagrams like there was no tomorrow. at somepoint it might */ - /* be nice to set this up so that a quantity of bytes could be sent, */ - /* but we still need some sort of end of test trigger on the receive */ - /* side. that could be a select with a one second timeout, but then */ - /* if there is a test where none of the data arrives for awile and */ - /* then starts again, we would end the test too soon. something to */ - /* think about... */ - while (!times_up) { - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - message_int_ptr = (int *)(send_ring->buffer_ptr); - for (i = 0; i < loc_dirty_count; i++) { - *message_int_ptr = 4; - message_int_ptr++; - } - for (i = 0; i < loc_clean_count; i++) { - loc_dirty_count = *message_int_ptr; - message_int_ptr++; - } -#endif /* DIRTY */ - - if ((len=send(data_socket, - send_ring->buffer_ptr, - send_size, - 0)) != send_size) { - if ((len >= 0) || (errno == EINTR)) - break; - if (errno == ENOBUFS) { - failed_sends++; - continue; - } - perror("dg_send: data send error"); - exit(1); - } - messages_sent++; - - /* now we want to move our pointer to the next position in the */ - /* data buffer... */ - - send_ring = send_ring->next; - - -#ifdef WANT_INTERVALS - /* in this case, the interval count is the count-down couter */ - /* to decide to sleep for a little bit */ - if ((interval_burst) && (--interval_count == 0)) { - /* call the sleep routine for some milliseconds, if our */ - /* timer popped while we were in there, we want to */ - /* break out of the loop. */ - if (msec_sleep(interval_wate)) { - break; - } - interval_count = interval_burst; - } - -#endif - - } - - /* This is a timed test, so the remote will be returning to us after */ - /* a time. We should not need to send any "strange" messages to tell */ - /* the remote that the test is completed, unless we decide to add a */ - /* number of messages to the test. */ - - /* the test is over, so get stats and stuff */ - cpu_stop(local_cpu_usage, - &elapsed_time); - - /* Get the statistics from the remote end */ - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"send_dg_stream: remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("send_dg_stream: error on remote"); - exit(1); - } - - bytes_sent = send_size * messages_sent; - local_thruput = calc_thruput(bytes_sent); - - messages_recvd = dg_stream_results->messages_recvd; - bytes_recvd = send_size * messages_recvd; - - /* we asume that the remote ran for as long as we did */ - - remote_thruput = calc_thruput(bytes_recvd); - - /* print the results for this socket and message size */ - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) We pass zeros for the local */ - /* cpu utilization and elapsed time to tell the routine to use */ - /* the libraries own values for those. */ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where,"Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - /* The local calculations could use variables being kept by */ - /* the local netlib routines. The remote calcuations need to */ - /* have a few things passed to them. */ - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where,"REMOTE CPU usage numbers based on process information only!\n"); - fflush(where); - } - - remote_cpu_utilization = dg_stream_results->cpu_util; - remote_service_demand = calc_service_demand(bytes_recvd, - 0.0, - remote_cpu_utilization, - dg_stream_results->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - fprintf(where, - cpu_fmt_1, /* the format string */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - messages_sent, - failed_sends, - local_thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - local_service_demand, /* local service demand */ - rsr_size, - elapsed_time, - messages_recvd, - remote_thruput, - remote_cpu_utilization, /* remote cpu */ - remote_service_demand); /* remote service demand */ - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - local_thruput); - break; - case 1: - fprintf(where, - tput_fmt_1, /* the format string */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - messages_sent, - failed_sends, - local_thruput, - rsr_size, /* remote recvbuf size */ - elapsed_time, - messages_recvd, - remote_thruput - ); - break; - } - } -} - - - /* this routine implements the receive side (netserver) of the */ - /* DG_STREAM performance test. */ - -void -recv_dg_stream() -{ - struct ring_elt *recv_ring; - - struct sockaddr_un myaddr_un; - SOCKET s_data; - int len = 0; - int bytes_received = 0; - float elapsed_time; - - int message_size; - int messages_recvd = 0; - - struct dg_stream_request_struct *dg_stream_request; - struct dg_stream_response_struct *dg_stream_response; - struct dg_stream_results_struct *dg_stream_results; - - dg_stream_request = - (struct dg_stream_request_struct *)netperf_request.content.test_specific_data; - dg_stream_response = - (struct dg_stream_response_struct *)netperf_response.content.test_specific_data; - dg_stream_results = - (struct dg_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_dg_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug > 1) { - fprintf(where,"recv_dg_stream: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = DG_STREAM_RESPONSE; - - if (debug > 2) { - fprintf(where,"recv_dg_stream: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug > 1) { - fprintf(where,"recv_dg_stream: requested alignment of %d\n", - dg_stream_request->recv_alignment); - fflush(where); - } - - if (recv_width == 0) recv_width = 1; - - recv_ring = allocate_buffer_ring(recv_width, - dg_stream_request->message_size, - dg_stream_request->recv_alignment, - dg_stream_request->recv_offset); - - if (debug > 1) { - fprintf(where,"recv_dg_stream: receive alignment and offset set...\n"); - fflush(where); - } - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - bzero((char *)&myaddr_un, - sizeof(myaddr_un)); - myaddr_un.sun_family = AF_UNIX; - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug > 1) { - fprintf(where,"recv_dg_stream: grabbing a socket...\n"); - fflush(where); - } - - /* create_unix_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lsr_size = dg_stream_request->recv_buf_size; - - s_data = create_unix_socket(AF_UNIX, - SOCK_DGRAM); - - if (s_data == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf.")); - if (bind(s_data, - (struct sockaddr *)&myaddr_un, - sizeof(myaddr_un)) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - chmod(myaddr_un.sun_path, 0666); - - dg_stream_response->test_length = dg_stream_request->test_length; - - /* Now myaddr_un contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - strcpy(dg_stream_response->unix_path,myaddr_un.sun_path); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - dg_stream_response->cpu_rate = 0.0; /* assume no cpu */ - if (dg_stream_request->measure_cpu) { - /* We will pass the rate into the calibration routine. If the */ - /* user did not specify one, it will be 0.0, and we will do a */ - /* "real" calibration. Otherwise, all it will really do is */ - /* store it away... */ - dg_stream_response->measure_cpu = 1; - dg_stream_response->cpu_rate = - calibrate_local_cpu(dg_stream_request->cpu_rate); - } - - message_size = dg_stream_request->message_size; - test_time = dg_stream_request->test_length; - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - dg_stream_response->send_buf_size = lss_size; - dg_stream_response->recv_buf_size = lsr_size; - - send_response(); - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(dg_stream_request->measure_cpu); - - /* The loop will exit when the timer pops, or if we happen to recv a */ - /* message of less than send_size bytes... */ - - times_up = 0; - start_timer(test_time + PAD_TIME); - - if (debug) { - fprintf(where,"recv_dg_stream: about to enter inner sanctum.\n"); - fflush(where); - } - - while (!times_up) { - if ((len = recv(s_data, - recv_ring->buffer_ptr, - message_size, - 0)) != message_size) { - if ((len == SOCKET_ERROR) && (errno != EINTR)) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - break; - } - messages_recvd++; - recv_ring = recv_ring->next; - } - - if (debug) { - fprintf(where,"recv_dg_stream: got %d messages.\n",messages_recvd); - fflush(where); - } - - - /* The loop now exits due timer or < send_size bytes received. */ - - cpu_stop(dg_stream_request->measure_cpu,&elapsed_time); - - if (times_up) { - /* we ended on a timer, subtract the PAD_TIME */ - elapsed_time -= (float)PAD_TIME; - } - else { - stop_timer(); - } - - if (debug) { - fprintf(where,"recv_dg_stream: test ended in %f seconds.\n",elapsed_time); - fflush(where); - } - - - /* We will count the "off" message that got us out of the loop */ - bytes_received = (messages_recvd * message_size) + len; - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_dg_stream: got %d bytes\n", - bytes_received); - fflush(where); - } - - netperf_response.content.response_type = DG_STREAM_RESULTS; - dg_stream_results->bytes_received = bytes_received; - dg_stream_results->messages_recvd = messages_recvd; - dg_stream_results->elapsed_time = elapsed_time; - if (dg_stream_request->measure_cpu) { - dg_stream_results->cpu_util = calc_cpu_util(elapsed_time); - } - else { - dg_stream_results->cpu_util = -1.0; - } - - if (debug > 1) { - fprintf(where, - "recv_dg_stream: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - -} - -void -send_dg_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - float elapsed_time; - - /* we add MAXALIGNMENT and MAXOFFSET to insure that there is enough */ - /* space for a maximally aligned, maximally sized message. At some */ - /* point, we may want to actually make this even larger and cycle */ - /* through the thing one piece at a time.*/ - - int len; - char *send_message_ptr; - char *recv_message_ptr; - char *temp_message_ptr; - int nummessages; - SOCKET send_socket; - int trans_remaining; - int bytes_xferd; - - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - -#ifdef WANT_INTERVALS - /* timing stuff */ -#define MAX_KEPT_TIMES 1024 - int time_index = 0; - int unused_buckets; - int kept_times[MAX_KEPT_TIMES]; - int sleep_usecs; - unsigned int total_times=0; - struct timezone dummy_zone; - struct timeval send_time; - struct timeval recv_time; - struct timeval sleep_timeval; -#endif - - struct sockaddr_un server, myaddr_un; - - struct dg_rr_request_struct *dg_rr_request; - struct dg_rr_response_struct *dg_rr_response; - struct dg_rr_results_struct *dg_rr_result; - - dg_rr_request = - (struct dg_rr_request_struct *)netperf_request.content.test_specific_data; - dg_rr_response= - (struct dg_rr_response_struct *)netperf_response.content.test_specific_data; - dg_rr_result = - (struct dg_rr_results_struct *)netperf_response.content.test_specific_data; - - /* we want to zero out the times, so we can detect unused entries. */ -#ifdef WANT_INTERVALS - time_index = 0; - while (time_index < MAX_KEPT_TIMES) { - kept_times[time_index] = 0; - time_index += 1; - } - time_index = 0; -#endif - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - bzero((char *)&server, - sizeof(server)); - server.sun_family = AF_UNIX; - - bzero((char *)&myaddr_un, - sizeof(myaddr_un)); - myaddr_un.sun_family = AF_UNIX; - - strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf.")); - - if ( print_headers ) { - fprintf(where,"DG REQUEST/RESPONSE TEST\n"); - if (local_cpu_usage || remote_cpu_usage) - fprintf(where,cpu_title,format_units()); - else - fprintf(where,tput_title,format_units()); - } - - /* initialize a few counters */ - - nummessages = 0; - bytes_xferd = 0; - times_up = 0; - - /* set-up the data buffer with the requested alignment and offset */ - temp_message_ptr = (char *)malloc(DATABUFFERLEN); - if (temp_message_ptr == NULL) { - printf("malloc(%d) failed!\n", DATABUFFERLEN); - exit(1); - } - send_message_ptr = (char *)(( (long)temp_message_ptr + - (long) local_send_align - 1) & - ~((long) local_send_align - 1)); - send_message_ptr = send_message_ptr + local_send_offset; - temp_message_ptr = (char *)malloc(DATABUFFERLEN); - if (temp_message_ptr == NULL) { - printf("malloc(%d) failed!\n", DATABUFFERLEN); - exit(1); - } - recv_message_ptr = (char *)(( (long)temp_message_ptr + - (long) local_recv_align - 1) & - ~((long) local_recv_align - 1)); - recv_message_ptr = recv_message_ptr + local_recv_offset; - - /*set up the data socket */ - send_socket = create_unix_socket(AF_UNIX, - SOCK_DGRAM); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_dg_rr: dg rr data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_dg_rr: send_socket obtained...\n"); - } - - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. If */ - /* there is no idle counter in the kernel idle loop, the */ - /* local_cpu_rate will be set to -1. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_DG_RR; - dg_rr_request->recv_buf_size = rsr_size; - dg_rr_request->send_buf_size = rss_size; - dg_rr_request->recv_alignment = remote_recv_align; - dg_rr_request->recv_offset = remote_recv_offset; - dg_rr_request->send_alignment = remote_send_align; - dg_rr_request->send_offset = remote_send_offset; - dg_rr_request->request_size = req_size; - dg_rr_request->response_size = rsp_size; - dg_rr_request->measure_cpu = remote_cpu_usage; - dg_rr_request->cpu_rate = remote_cpu_rate; - if (test_time) { - dg_rr_request->test_length = test_time; - } - else { - dg_rr_request->test_length = test_trans * -1; - } - - if (debug > 1) { - fprintf(where,"netperf: send_dg_rr: requesting DG request/response test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right */ - /* after the connect returns. The remote will grab the counter right */ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the DG tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = dg_rr_response->recv_buf_size; - rss_size = dg_rr_response->send_buf_size; - remote_cpu_usage= dg_rr_response->measure_cpu; - remote_cpu_rate = dg_rr_response->cpu_rate; - /* port numbers in proper order */ - strcpy(server.sun_path,dg_rr_response->unix_path); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* Connect up to the remote port on the data socket. This will set */ - /* the default destination address on this socket. we need to bind */ - /* out socket so that the remote gets something from a recvfrom */ - if (bind(send_socket, - (struct sockaddr *)&myaddr_un, - sizeof(myaddr_un)) == SOCKET_ERROR) { - perror("netperf: send_dg_rr"); - unlink(myaddr_un.sun_path); - close(send_socket); - exit(1); - } - - if (connect(send_socket, - (struct sockaddr *)&server, - sizeof(server)) == INVALID_SOCKET ) { - perror("netperf: data socket connect failed"); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - while ((!times_up) || (trans_remaining > 0)) { - /* send the request */ -#ifdef WANT_INTERVALS - gettimeofday(&send_time,&dummy_zone); -#endif - if((len=send(send_socket, - send_message_ptr, - req_size, - 0)) != req_size) { - if (errno == EINTR) { - /* We likely hit */ - /* test-end time. */ - break; - } - perror("send_dg_rr: data send error"); - exit(1); - } - - /* receive the response. with DG we will get it all, or nothing */ - - if((rsp_bytes_recvd=recv(send_socket, - recv_message_ptr, - rsp_size, - 0)) != rsp_size) { - if (errno == EINTR) { - /* Again, we have likely hit test-end time */ - break; - } - perror("send_dg_rr: data recv error"); - exit(1); - } -#ifdef WANT_INTERVALS - gettimeofday(&recv_time,&dummy_zone); - - /* now we do some arithmatic on the two timevals */ - if (recv_time.tv_usec < send_time.tv_usec) { - /* we wrapped around a second */ - recv_time.tv_usec += 1000000; - recv_time.tv_sec -= 1; - } - - /* and store it away */ - kept_times[time_index] = (recv_time.tv_sec - send_time.tv_sec) * 1000000; - kept_times[time_index] += (recv_time.tv_usec - send_time.tv_usec); - - /* at this point, we may wish to sleep for some period of */ - /* time, so we see how long that last transaction just took, */ - /* and sleep for the difference of that and the interval. We */ - /* will not sleep if the time would be less than a */ - /* millisecond. */ - if (interval_usecs > 0) { - sleep_usecs = interval_usecs - kept_times[time_index]; - if (sleep_usecs > 1000) { - /* we sleep */ - sleep_timeval.tv_sec = sleep_usecs / 1000000; - sleep_timeval.tv_usec = sleep_usecs % 1000000; - select(0, - 0, - 0, - 0, - &sleep_timeval); - } - } - - /* now up the time index */ - time_index = (time_index +1)%MAX_KEPT_TIMES; -#endif - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - fprintf(where,"Transaction %d completed\n",nummessages); - fflush(where); - } - - } - - /* The test is over. Flush the buffers to the remote end. We do a */ - /* graceful release to insure that all data has been taken by the */ - /* remote. Of course, since this was a request/response test, there */ - /* should be no data outstanding on the socket ;-) */ - - if (shutdown(send_socket,1) == SOCKET_ERROR) { - perror("netperf: cannot shutdown dg stream socket"); - - exit(1); - } - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ - /* how long did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a DG stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) We use */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = calc_thruput(bytes_xferd); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where,"Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where,"Remote CPU usage numbers based on process information only!\n"); - fflush(where); - } - remote_cpu_utilization = dg_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - dg_rr_result->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - case 2: - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - nummessages/elapsed_time, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - nummessages/elapsed_time); - break; - case 1: - case 2: - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - nummessages/elapsed_time); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* DG statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - -#ifdef WANT_INTERVALS - kept_times[MAX_KEPT_TIMES] = 0; - time_index = 0; - while (time_index < MAX_KEPT_TIMES) { - if (kept_times[time_index] > 0) { - total_times += kept_times[time_index]; - } - else - unused_buckets++; - time_index += 1; - } - total_times /= (MAX_KEPT_TIMES-unused_buckets); - fprintf(where, - "Average response time %d usecs\n", - total_times); -#endif - } - unlink(myaddr_un.sun_path); -} - - /* this routine implements the receive side (netserver) of a DG_RR */ - /* test. */ -void -recv_dg_rr() -{ - - struct ring_elt *recv_ring; - struct ring_elt *send_ring; - - struct sockaddr_un myaddr_un, - peeraddr_un; - SOCKET s_data; - int addrlen; - int trans_received = 0; - int trans_remaining; - float elapsed_time; - - struct dg_rr_request_struct *dg_rr_request; - struct dg_rr_response_struct *dg_rr_response; - struct dg_rr_results_struct *dg_rr_results; - - dg_rr_request = - (struct dg_rr_request_struct *)netperf_request.content.test_specific_data; - dg_rr_response = - (struct dg_rr_response_struct *)netperf_response.content.test_specific_data; - dg_rr_results = - (struct dg_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_dg_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_dg_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = DG_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_dg_rr: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variables to be at the desired */ - /* alignments with the desired offsets. */ - - if (debug) { - fprintf(where,"recv_dg_rr: requested recv alignment of %d offset %d\n", - dg_rr_request->recv_alignment, - dg_rr_request->recv_offset); - fprintf(where,"recv_dg_rr: requested send alignment of %d offset %d\n", - dg_rr_request->send_alignment, - dg_rr_request->send_offset); - fflush(where); - } - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - recv_ring = allocate_buffer_ring(recv_width, - dg_rr_request->request_size, - dg_rr_request->recv_alignment, - dg_rr_request->recv_offset); - - send_ring = allocate_buffer_ring(send_width, - dg_rr_request->response_size, - dg_rr_request->send_alignment, - dg_rr_request->send_offset); - - if (debug) { - fprintf(where,"recv_dg_rr: receive alignment and offset set...\n"); - fflush(where); - } - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - bzero((char *)&myaddr_un, - sizeof(myaddr_un)); - myaddr_un.sun_family = AF_UNIX; - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_dg_rr: grabbing a socket...\n"); - fflush(where); - } - - - /* create_unix_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = dg_rr_request->send_buf_size; - lsr_size_req = dg_rr_request->recv_buf_size; - - s_data = create_unix_socket(AF_UNIX, - SOCK_DGRAM); - - if (s_data == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - - exit(1); - } - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf.")); - if (bind(s_data, - (struct sockaddr *)&myaddr_un, - sizeof(myaddr_un)) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - unlink(myaddr_un.sun_path); - close(s_data); - send_response(); - - exit(1); - } - - /* Now myaddr_un contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - strcpy(dg_rr_response->unix_path,myaddr_un.sun_path); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - dg_rr_response->cpu_rate = 0.0; /* assume no cpu */ - if (dg_rr_request->measure_cpu) { - dg_rr_response->measure_cpu = 1; - dg_rr_response->cpu_rate = calibrate_local_cpu(dg_rr_request->cpu_rate); - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - dg_rr_response->send_buf_size = lss_size; - dg_rr_response->recv_buf_size = lsr_size; - - send_response(); - - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(dg_rr_request->measure_cpu); - - if (dg_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(dg_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = dg_rr_request->test_length * -1; - } - - addrlen = sizeof(peeraddr_un); - bzero((char *)&peeraddr_un, addrlen); - - while ((!times_up) || (trans_remaining > 0)) { - - /* receive the request from the other side */ - fprintf(where,"socket %d ptr %p size %d\n", - s_data, - recv_ring->buffer_ptr, - dg_rr_request->request_size); - fflush(where); - if (recvfrom(s_data, - recv_ring->buffer_ptr, - dg_rr_request->request_size, - 0, - (struct sockaddr *)&peeraddr_un, - &addrlen) != dg_rr_request->request_size) { - if (errno == EINTR) { - /* we must have hit the end of test time. */ - break; - } - netperf_response.content.serv_errno = errno; - fprintf(where,"error on recvfrom errno %d\n",errno); - fflush(where); - send_response(); - unlink(myaddr_un.sun_path); - exit(1); - } - recv_ring = recv_ring->next; - - /* Now, send the response to the remote */ - if (sendto(s_data, - send_ring->buffer_ptr, - dg_rr_request->response_size, - 0, - (struct sockaddr *)&peeraddr_un, - addrlen) != dg_rr_request->response_size) { - if (errno == EINTR) { - /* we have hit end of test time. */ - break; - } - netperf_response.content.serv_errno = errno; - fprintf(where,"error on recvfrom errno %d\n",errno); - fflush(where); - unlink(myaddr_un.sun_path); - send_response(); - exit(1); - } - send_ring = send_ring->next; - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug) { - fprintf(where, - "recv_dg_rr: Transaction %d complete.\n", - trans_received); - fflush(where); - } - - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(dg_rr_request->measure_cpu,&elapsed_time); - - if (times_up) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_dg_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - dg_rr_results->bytes_received = (trans_received * - (dg_rr_request->request_size + - dg_rr_request->response_size)); - dg_rr_results->trans_received = trans_received; - dg_rr_results->elapsed_time = elapsed_time; - if (dg_rr_request->measure_cpu) { - dg_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_dg_rr: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - unlink(myaddr_un.sun_path); - -} - /* this routine implements the receive (netserver) side of a STREAM_RR */ - /* test */ - -void -recv_stream_rr() -{ - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - struct sockaddr_un myaddr_un, - peeraddr_un; - SOCKET s_listen,s_data; - int addrlen; - char *temp_message_ptr; - int trans_received = 0; - int trans_remaining; - int bytes_sent; - int request_bytes_recvd; - int request_bytes_remaining; - int timed_out = 0; - float elapsed_time; - - struct stream_rr_request_struct *stream_rr_request; - struct stream_rr_response_struct *stream_rr_response; - struct stream_rr_results_struct *stream_rr_results; - - stream_rr_request = - (struct stream_rr_request_struct *)netperf_request.content.test_specific_data; - stream_rr_response = - (struct stream_rr_response_struct *)netperf_response.content.test_specific_data; - stream_rr_results = - (struct stream_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_stream_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_stream_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = STREAM_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_stream_rr: the response type is set...\n"); - fflush(where); - } - - /* allocate the recv and send rings with the requested alignments */ - /* and offsets. raj 7/94 */ - if (debug) { - fprintf(where,"recv_stream_rr: requested recv alignment of %d offset %d\n", - stream_rr_request->recv_alignment, - stream_rr_request->recv_offset); - fprintf(where,"recv_stream_rr: requested send alignment of %d offset %d\n", - stream_rr_request->send_alignment, - stream_rr_request->send_offset); - fflush(where); - } - - /* at some point, these need to come to us from the remote system */ - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - stream_rr_request->response_size, - stream_rr_request->send_alignment, - stream_rr_request->send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - stream_rr_request->request_size, - stream_rr_request->recv_alignment, - stream_rr_request->recv_offset); - - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - bzero((char *)&myaddr_un, - sizeof(myaddr_un)); - myaddr_un.sun_family = AF_UNIX; - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_stream_rr: grabbing a socket...\n"); - fflush(where); - } - - /* create_unix_socket expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size_req = stream_rr_request->send_buf_size; - lsr_size_req = stream_rr_request->recv_buf_size; - - s_listen = create_unix_socket(AF_UNIX, - SOCK_STREAM); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - - exit(1); - } - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf.")); - if (bind(s_listen, - (struct sockaddr *)&myaddr_un, - sizeof(myaddr_un)) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - unlink(myaddr_un.sun_path); - close(s_listen); - send_response(); - - exit(1); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - - exit(1); - } - - /* Now myaddr_un contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - strcpy(stream_rr_response->unix_path,myaddr_un.sun_path); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - stream_rr_response->cpu_rate = 0.0; /* assume no cpu */ - if (stream_rr_request->measure_cpu) { - stream_rr_response->measure_cpu = 1; - stream_rr_response->cpu_rate = calibrate_local_cpu(stream_rr_request->cpu_rate); - } - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - stream_rr_response->send_buf_size = lss_size; - stream_rr_response->recv_buf_size = lsr_size; - - send_response(); - - addrlen = sizeof(peeraddr_un); - - if ((s_data = accept(s_listen, - (struct sockaddr *)&peeraddr_un, - &addrlen)) == INVALID_SOCKET) { - /* Let's just punt. The remote will be given some information */ - close(s_listen); - - exit(1); - } - - if (debug) { - fprintf(where,"recv_stream_rr: accept completes on the data connection.\n"); - fflush(where); - } - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(stream_rr_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - if (stream_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(stream_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = stream_rr_request->test_length * -1; - } - - while ((!times_up) || (trans_remaining > 0)) { - temp_message_ptr = recv_ring->buffer_ptr; - request_bytes_remaining = stream_rr_request->request_size; - - /* receive the request from the other side */ - if (debug) { - fprintf(where,"about to receive for trans %d\n",trans_received); - fprintf(where,"temp_message_ptr is %p\n",temp_message_ptr); - fflush(where); - } - while(request_bytes_remaining > 0) { - if((request_bytes_recvd=recv(s_data, - temp_message_ptr, - request_bytes_remaining, - 0)) == SOCKET_ERROR) { - if (errno == EINTR) { - /* the timer popped */ - timed_out = 1; - break; - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - else { - request_bytes_remaining -= request_bytes_recvd; - temp_message_ptr += request_bytes_recvd; - } - if (debug) { - fprintf(where,"just received for trans %d\n",trans_received); - fflush(where); - } - } - - recv_ring = recv_ring->next; - - if (timed_out) { - /* we hit the end of the test based on time - lets */ - /* bail out of here now... */ - fprintf(where,"yo5\n"); - fflush(where); - break; - } - - /* Now, send the response to the remote */ - if (debug) { - fprintf(where,"about to send for trans %d\n",trans_received); - fflush(where); - } - if((bytes_sent=send(s_data, - send_ring->buffer_ptr, - stream_rr_request->response_size, - 0)) == SOCKET_ERROR) { - if (errno == EINTR) { - /* the test timer has popped */ - timed_out = 1; - fprintf(where,"yo6\n"); - fflush(where); - break; - } - netperf_response.content.serv_errno = 997; - send_response(); - exit(1); - } - - send_ring = send_ring->next; - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug) { - fprintf(where, - "recv_stream_rr: Transaction %d complete\n", - trans_received); - fflush(where); - } - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(stream_rr_request->measure_cpu,&elapsed_time); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_stream_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - stream_rr_results->bytes_received = (trans_received * - (stream_rr_request->request_size + - stream_rr_request->response_size)); - stream_rr_results->trans_received = trans_received; - stream_rr_results->elapsed_time = elapsed_time; - if (stream_rr_request->measure_cpu) { - stream_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_stream_rr: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - unlink(myaddr_un.sun_path); -} - -void -print_unix_usage() -{ - - fwrite(unix_usage, sizeof(char), strlen(unix_usage), stdout); - exit(1); - -} -void -scan_unix_args(int argc, char *argv[]) -{ -#define UNIX_ARGS "hm:M:p:r:s:S:" - extern char *optarg; /* pointer to option string */ - - int c; - - char - arg1[BUFSIZ], /* argument holders */ - arg2[BUFSIZ]; - - init_test_vars(); - - if (no_control) { - fprintf(where, - "The UNIX tests do not know how to run with no control connection\n"); - exit(-1); - } - - /* Go through all the command line arguments and break them */ - /* out. For those options that take two parms, specifying only */ - /* the first will set both to that value. Specifying only the */ - /* second will leave the first untouched. To change only the */ - /* first, use the form "first," (see the routine break_args.. */ - - while ((c= getopt(argc, argv, UNIX_ARGS)) != EOF) { - switch (c) { - case '?': - case 'h': - print_unix_usage(); - exit(1); - case 'p': - /* set the path prefix (directory) that should be used for the */ - /* pipes. at some point, there should be some error checking. */ - strcpy(path_prefix,optarg); - break; - case 's': - /* set local socket sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - lss_size_req = atoi(arg1); - if (arg2[0]) - lsr_size_req = atoi(arg2); - break; - case 'S': - /* set remote socket sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - rss_size = atoi(arg1); - if (arg2[0]) - rsr_size = atoi(arg2); - break; - case 'r': - /* set the request/response sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - req_size = atoi(arg1); - if (arg2[0]) - rsp_size = atoi(arg2); - break; - case 'm': - /* set the send size */ - send_size = atoi(optarg); - break; - case 'M': - /* set the recv size */ - recv_size = atoi(optarg); - break; - }; - } -} -#endif /* WANT_UNIX */ diff --git a/nettest_unix.h b/nettest_unix.h deleted file mode 100644 index 8eb393b..0000000 --- a/nettest_unix.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - Copyright (C) 1993-2004 Hewlett-Packard Company -*/ - - /* This file contains the test-specific definitions for netperf's */ - /* DLPI tests */ - -struct stream_stream_request_struct { - int recv_buf_size; - int send_buf_size; - int receive_size; /* how many bytes do we want to */ - /* receive at one time? */ - int recv_alignment; /* what is the alignment of the */ - /* receive buffer? */ - int recv_offset; /* and at what offset from that */ - /* alignment? */ - int so_rcvavoid; /* do we want the remote to avoid receive copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int measure_cpu; /* does the client want server cpu */ - /* utilization measured? */ - float cpu_rate; /* do we know how fast the cpu is */ - /* already? */ - int test_length; /* how long is the test? */ - int dirty_count; /* how many integers in the receive buffer */ - /* should be made dirty before calling recv? */ - int clean_count; /* how many integers should be read from the */ - /* recv buffer before calling recv? */ - int path_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char unix_path[32]; /* the path */ -}; - -struct stream_stream_response_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int receive_size; - int so_rcvavoid; /* do we want the remote to avoid receive copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int path_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char unix_path[32]; /* the path */ -}; - -struct stream_stream_results_struct { - int bytes_received; /* ignored initially */ - int recv_calls; /* ignored initially */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int num_cpus; -}; - -struct stream_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int so_rcvavoid; /* do we want the remote to avoid receive copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int path_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char unix_path[32]; /* the path */ -}; - -struct stream_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int so_rcvavoid; /* do we want the remote to avoid receive copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - float cpu_rate; /* could we measure */ - int path_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char unix_path[32]; /* the path to the dlpi device */ -}; - -struct stream_rr_results_struct { - int bytes_received; /* ignored initially */ - int recv_calls; /* ignored initially */ - int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int num_cpus; -}; - -struct dg_stream_request_struct { - int recv_buf_size; - int message_size; - int recv_alignment; - int recv_offset; - int measure_cpu; - float cpu_rate; - int test_length; - int so_rcvavoid; /* do we want the remote to avoid receive copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int path_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char unix_path[32]; /* the path */ -}; - -struct dg_stream_response_struct { - int recv_buf_size; - int send_buf_size; - int measure_cpu; - int test_length; - float cpu_rate; - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ - int path_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char unix_path[32]; /* the path */ -}; - -struct dg_stream_results_struct { - int messages_recvd; - int bytes_received; - float elapsed_time; - float cpu_util; - int num_cpus; -}; - - -struct dg_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int path_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char unix_path[32]; /* the path */ -}; - -struct dg_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ - int path_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char unix_path[32]; /* the path */ -}; - -struct dg_rr_results_struct { - int bytes_received; /* ignored initially */ - int recv_calls; /* ignored initially */ - int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int num_cpus; -}; - -extern void scan_unix_args(int argc, char *argv[]); - -extern void send_stream_stream(char remote_host[]); -extern void send_stream_rr(char remote_host[]); -extern void send_dg_stream(char remote_host[]); -extern void send_dg_rr(char remote_host[]); - -extern void recv_stream_stream(); -extern void recv_stream_rr(); -extern void recv_dg_stream(); -extern void recv_dg_rr(); diff --git a/nettest_xti.c b/nettest_xti.c deleted file mode 100644 index 9d27f25..0000000 --- a/nettest_xti.c +++ /dev/null @@ -1,6026 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef WANT_XTI -#ifndef lint -char nettest_xti_id[]="\ -@(#)nettest_xti.c (c) Copyright 1995-2007 Hewlett-Packard Co. Version 2.4.3"; -#else -#define DIRTY -#define WANT_HISTOGRAM -#define WANT_INTERVALS -#endif /* lint */ -/****************************************************************/ -/* */ -/* nettest_xti.c */ -/* */ -/* the XTI args parsing routine... */ -/* */ -/* scan_xti_args() */ -/* */ -/* the actual test routines... */ -/* */ -/* send_xti_tcp_stream() perform a tcp stream test */ -/* recv_xti_tcp_stream() */ -/* send_xti_tcp_rr() perform a tcp request/response */ -/* recv_xti_tcp_rr() */ -/* send_xti_tcp_conn_rr() an RR test including connect */ -/* recv_xti_tcp_conn_rr() */ -/* send_xti_udp_stream() perform a udp stream test */ -/* recv_xti_udp_stream() */ -/* send_xti_udp_rr() perform a udp request/response */ -/* recv_xti_udp_rr() */ -/* */ -/****************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/types.h> -#include <fcntl.h> -#ifndef WIN32 -#include <sys/ipc.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <errno.h> -#include <signal.h> -#else /* WIN32 */ -#include <process.h> -#include <winsock2.h> -#include <windows.h> -#endif /* WIN32 */ -#include <stdio.h> -#include <time.h> -#include <malloc.h> - /* xti.h should be included *after* in.h because there are name */ - /* conflicts!( Silly standards people... raj 2/95 fortuenately, the */ - /* confilcts are on IP_TOP and IP_TTL, whcih netperf does not yet use */ -#include <xti.h> - -#include "netlib.h" -#include "netsh.h" -#include "nettest_xti.h" - -#ifdef WANT_HISTOGRAM -#ifdef __sgi -#include <sys/time.h> -#endif /* __sgi */ -#include "hist.h" -#endif /* WANT_HISTOGRAM */ - - - - /* these variables are specific to the XTI sockets tests. declare */ - /* them static to make them global only to this file. */ - -static int - rss_size, /* remote socket send buffer size */ - rsr_size, /* remote socket recv buffer size */ - lss_size, /* local socket send buffer size */ - lsr_size, /* local socket recv buffer size */ - req_size = 1, /* request size */ - rsp_size = 1, /* response size */ - send_size, /* how big are individual sends */ - recv_size; /* how big are individual receives */ - -static int confidence_iteration; -static char local_cpu_method; -static char remote_cpu_method; - - /* different options for the xti */ - -static int - loc_nodelay, /* don't/do use NODELAY locally */ - rem_nodelay, /* don't/do use NODELAY remotely */ - loc_sndavoid, /* avoid send copies locally */ - loc_rcvavoid, /* avoid recv copies locally */ - rem_sndavoid, /* avoid send copies remotely */ - rem_rcvavoid; /* avoid recv_copies remotely */ - -static struct t_info info_struct; - -#ifdef WANT_HISTOGRAM -#ifdef HAVE_GETHRTIME -hrtime_t time_one; -hrtime_t time_two; -#else -static struct timeval time_one; -static struct timeval time_two; -#endif /* HAVE_GETHRTIME */ -static HIST time_hist; -#endif /* WANT_HISTOGRAM */ - -static char loc_xti_device[32] = "/dev/tcp"; -static char rem_xti_device[32] = "/dev/tcp"; - -static int xti_flags = 0; - -char xti_usage[] = "\n\ -Usage: netperf [global options] -- [test options] \n\ -\n\ -TCP/UDP XTI API Test Options:\n\ - -D [L][,R] Set XTI_TCP_NODELAY locally and/or remotely (XTI_TCP_*)\n\ - -h Display this text\n\ - -m bytes Set the send size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\ - -M bytes Set the recv size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\ - -r bytes Set request size (XTI_TCP_RR, XTI_UDP_RR)\n\ - -R bytes Set response size (XTI_TCP_RR, XTI_UDP_RR)\n\ - -s send[,recv] Set local socket send/recv buffer sizes\n\ - -S send[,recv] Set remote socket send/recv buffer sizes\n\ - -X dev[,dev] Set the local/remote XTI device file name\n\ -\n\ -For those options taking two parms, at least one must be specified;\n\ -specifying one value without a comma will set both parms to that\n\ -value, specifying a value with a leading comma will set just the second\n\ -parm, a value with a trailing comma will set just the first. To set\n\ -each parm to unique values, specify both and separate them with a\n\ -comma.\n"; - - - /* This routine is intended to retrieve interesting aspects of tcp */ - /* for the data connection. at first, it attempts to retrieve the */ - /* maximum segment size. later, it might be modified to retrieve */ - /* other information, but it must be information that can be */ - /* retrieved quickly as it is called during the timing of the test. */ - /* for that reason, a second routine may be created that can be */ - /* called outside of the timing loop */ -void -get_xti_info(socket, info_struct) - int socket; - struct t_info *info_struct; -{ - -} - - - /* This routine will create a data (listen) socket with the apropriate */ - /* options set and return it to the caller. this replaces all the */ - /* duplicate code in each of the test routines and should help make */ - /* things a little easier to understand. since this routine can be */ - /* called by either the netperf or netserver programs, all output */ - /* should be directed towards "where." family is generally AF_INET, */ - /* and type will be either SOCK_STREAM or SOCK_DGRAM */ -SOCKET -create_xti_endpoint(char *name) -{ - - SOCKET temp_socket; - - struct t_optmgmt *opt_req; /* we request an option */ - struct t_optmgmt *opt_ret; /* it tells us what we got */ - - /* we use this to pass-in BSD-like socket options through t_optmgmt. */ - /* it ends up being about as clear as mud. raj 2/95 */ - struct sock_option { - struct t_opthdr myopthdr; - long value; - } *sock_option; - - if (debug) { - fprintf(where,"create_xti_endpoint: attempting to open %s\n", - name); - fflush(where); - } - - /*set up the data socket */ - temp_socket = t_open(name,O_RDWR,NULL); - - if (temp_socket == INVALID_SOCKET){ - fprintf(where, - "netperf: create_xti_endpoint: t_open %s: errno %d t_errno %d\n", - name, - errno, - t_errno); - fflush(where); - exit(1); - } - - if (debug) { - fprintf(where,"create_xti_endpoint: socket %d obtained...\n",temp_socket); - fflush(where); - } - - /* allocate what we need for option mgmt */ - if ((opt_req = (struct t_optmgmt *)t_alloc(temp_socket,T_OPTMGMT,T_ALL)) == - NULL) { - fprintf(where, - "netperf: create_xti_endpoint: t_alloc: opt_req errno %d\n", - errno); - fflush(where); - exit(1); - } - - if (debug) { - fprintf(where, - "create_xti_endpoint: opt_req->opt.buf %x maxlen %d len %d\n", - opt_req->opt.buf, - opt_req->opt.maxlen, - opt_req->opt.len); - - fflush(where); - } - - if ((opt_ret = (struct t_optmgmt *) t_alloc(temp_socket,T_OPTMGMT,T_ALL)) == - NULL) { - fprintf(where, - "netperf: create_xti_endpoint: t_alloc: opt_ret errno %d\n", - errno); - fflush(where); - exit(1); - } - - if (debug) { - fprintf(where, - "create_xti_endpoint: opt_ret->opt.buf %x maxlen %d len %d\n", - opt_ret->opt.buf, - opt_ret->opt.maxlen, - opt_ret->opt.len); - fflush(where); - } - - /* Modify the local socket size. The reason we alter the send buffer */ - /* size here rather than when the connection is made is to take care */ - /* of decreases in buffer size. Decreasing the window size after */ - /* connection establishment is a TCP no-no. Also, by setting the */ - /* buffer (window) size before the connection is established, we can */ - /* control the TCP MSS (segment size). The MSS is never more that 1/2 */ - /* the minimum receive buffer size at each half of the connection. */ - /* This is why we are altering the receive buffer size on the sending */ - /* size of a unidirectional transfer. If the user has not requested */ - /* that the socket buffers be altered, we will try to find-out what */ - /* their values are. If we cannot touch the socket buffer in any way, */ - /* we will set the values to -1 to indicate that. */ - -#ifdef XTI_SNDBUF - if (lss_size > 0) { - /* we want to "negotiate" the option */ - opt_req->flags = T_NEGOTIATE; - } - else { - /* we want to accept the default, and know what it is. I assume */ - /* that when nothing has been changed, that T_CURRENT will return */ - /* the same as T_DEFAULT raj 3/95 */ - opt_req->flags = T_CURRENT; - } - - /* the first part is for the netbuf that holds the option we want */ - /* to negotiate or check */ - /* the buffer of the netbuf points at the socket options structure */ - - /* we assume that the t_alloc call allocated a buffer that started */ - /* on a proper alignment */ - sock_option = (struct sock_option *)opt_req->opt.buf; - - /* and next, set the fields in the sock_option structure */ - sock_option->myopthdr.level = XTI_GENERIC; - sock_option->myopthdr.name = XTI_SNDBUF; - sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long); - sock_option->value = lss_size; - - opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long); - - /* now, set-up the stuff to return the value in the end */ - /* we assume that the t_alloc call allocated a buffer that started */ - /* on a proper alignment */ - sock_option = (struct sock_option *)opt_ret->opt.buf; - - /* finally, call t_optmgmt. clear as mud. */ - if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) { - fprintf(where, - "netperf: create_xti_endpoint: XTI_SNDBUF option: t_errno %d\n", - t_errno); - fflush(where); - exit(1); - } - - if (sock_option->myopthdr.status == T_SUCCESS) { - lss_size = sock_option->value; - } - else { - fprintf(where,"create_xti_endpoint: XTI_SNDBUF option status 0x%.4x", - sock_option->myopthdr.status); - fprintf(where," value %d\n", - sock_option->value); - fflush(where); - lss_size = -1; - } - - if (lsr_size > 0) { - /* we want to "negotiate" the option */ - opt_req->flags = T_NEGOTIATE; - } - else { - /* we want to accept the default, and know what it is. I assume */ - /* that when nothing has been changed, that T_CURRENT will return */ - /* the same as T_DEFAULT raj 3/95 */ - opt_req->flags = T_CURRENT; - } - - /* the first part is for the netbuf that holds the option we want */ - /* to negotiate or check */ - /* the buffer of the netbuf points at the socket options structure */ - - /* we assume that the t_alloc call allocated a buffer that started */ - /* on a proper alignment */ - sock_option = (struct sock_option *)opt_req->opt.buf; - - /* and next, set the fields in the sock_option structure */ - sock_option->myopthdr.level = XTI_GENERIC; - sock_option->myopthdr.name = XTI_RCVBUF; - sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long); - sock_option->value = lsr_size; - - opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long); - - /* now, set-up the stuff to return the value in the end */ - /* we assume that the t_alloc call allocated a buffer that started */ - /* on a proper alignment */ - sock_option = (struct sock_option *)opt_ret->opt.buf; - - /* finally, call t_optmgmt. clear as mud. */ - if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) { - fprintf(where, - "netperf: create_xti_endpoint: XTI_RCVBUF option: t_errno %d\n", - t_errno); - fflush(where); - exit(1); - } - lsr_size = sock_option->value; - - /* this needs code */ - - if (debug) { - fprintf(where,"netperf: create_xti_endpoint: socket sizes determined...\n"); - fprintf(where," send: %d recv: %d\n", - lss_size,lsr_size); - fflush(where); - } - -#else /* XTI_SNDBUF */ - - lss_size = -1; - lsr_size = -1; - -#endif /* XTI_SNDBUF */ - - /* now, we may wish to enable the copy avoidance features on the */ - /* local system. of course, this may not be possible... */ - - if (loc_rcvavoid) { - fprintf(where, - "netperf: create_xti_endpoint: Could not enable receive copy avoidance"); - fflush(where); - loc_rcvavoid = 0; - } - - if (loc_sndavoid) { - fprintf(where, - "netperf: create_xti_endpoint: Could not enable send copy avoidance"); - fflush(where); - loc_sndavoid = 0; - } - - /* Now, we will see about setting the TCP_NODELAY flag on the local */ - /* socket. We will only do this for those systems that actually */ - /* support the option. If it fails, note the fact, but keep going. */ - /* If the user tries to enable TCP_NODELAY on a UDP socket, this */ - /* will cause an error to be displayed */ - -#ifdef TCP_NODELAY - if ((strcmp(test_name,"XTI_TCP_STREAM") == 0) || - (strcmp(test_name,"XTI_TCP_RR") == 0) || - (strcmp(test_name,"XTI_TCP_CRR") == 0)) { - if (loc_nodelay) { - /* we want to "negotiate" the option */ - opt_req->flags = T_NEGOTIATE; - } - else { - /* we want to accept the default, and know what it is. I assume */ - /* that when nothing has been changed, that T_CURRENT will return */ - /* the same as T_DEFAULT raj 3/95 */ - opt_req->flags = T_CURRENT; - } - - /* the first part is for the netbuf that holds the option we want */ - /* to negotiate or check the buffer of the netbuf points at the */ - /* socket options structure */ - - /* we assume that the t_alloc call allocated a buffer that started */ - /* on a proper alignment */ - sock_option = (struct sock_option *)opt_req->opt.buf; - - /* and next, set the fields in the sock_option structure */ - sock_option->myopthdr.level = INET_TCP; - sock_option->myopthdr.name = TCP_NODELAY; - sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long); - sock_option->value = T_YES; - - opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long); - - /* now, set-up the stuff to return the value in the end */ - /* we assume that the t_alloc call allocated a buffer that started */ - /* on a proper alignment */ - sock_option = (struct sock_option *)opt_ret->opt.buf; - - /* finally, call t_optmgmt. clear as mud. */ - if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) { - fprintf(where, - "create_xti_endpoint: TCP_NODELAY option: errno %d t_errno %d\n", - errno, - t_errno); - fflush(where); - exit(1); - } - loc_nodelay = sock_option->value; - } -#else /* TCP_NODELAY */ - - loc_nodelay = 0; - -#endif /* TCP_NODELAY */ - - return(temp_socket); - -} - - -/* This routine implements the TCP unidirectional data transfer test */ -/* (a.k.a. stream) for the xti interface. It receives its */ -/* parameters via global variables from the shell and writes its */ -/* output to the standard output. */ - - -void -send_xti_tcp_stream(char remote_host[]) -{ - - char *tput_title = "\ -Recv Send Send \n\ -Socket Socket Message Elapsed \n\ -Size Size Size Time Throughput \n\ -bytes bytes bytes secs. %s/sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f \n"; - - char *cpu_title = "\ -Recv Send Send Utilization Service Demand\n\ -Socket Socket Message Elapsed Send Recv Send Recv\n\ -Size Size Size Time Throughput local remote local remote\n\ -bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - - char *cpu_fmt_1 = - "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *ksink_fmt = "\n\ -Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\ -Local Remote Local Remote Xfered Per Per\n\ -Send Recv Send Recv Send (avg) Recv (avg)\n\ -%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n"; - - char *ksink_fmt2 = "\n\ -Maximum\n\ -Segment\n\ -Size (bytes)\n\ -%6d\n"; - - - float elapsed_time; - -#ifdef WANT_INTERVALS - int interval_count; - sigset_t signal_set; -#endif - - /* what we want is to have a buffer space that is at least one */ - /* send-size greater than our send window. this will insure that we */ - /* are never trying to re-use a buffer that may still be in the hands */ - /* of the transport. This buffer will be malloc'd after we have found */ - /* the size of the local senc socket buffer. We will want to deal */ - /* with alignment and offset concerns as well. */ - - int *message_int_ptr; - - struct ring_elt *send_ring; - - int len; - unsigned int nummessages; - SOCKET send_socket; - int bytes_remaining; - int tcp_mss = -1; /* possibly uninitialized on printf far below */ - - /* with links like fddi, one can send > 32 bits worth of bytes */ - /* during a test... ;-) at some point, this should probably become a */ - /* 64bit integral type, but those are not entirely common yet */ - - double bytes_sent; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - - double thruput; - - /* some addressing information */ - struct hostent *hp; - struct sockaddr_in server; - unsigned int addr; - - struct t_call server_call; - - struct xti_tcp_stream_request_struct *xti_tcp_stream_request; - struct xti_tcp_stream_response_struct *xti_tcp_stream_response; - struct xti_tcp_stream_results_struct *xti_tcp_stream_result; - - xti_tcp_stream_request = - (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data; - xti_tcp_stream_response = - (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data; - xti_tcp_stream_result = - (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - time_hist = HIST_new(); -#endif /* WANT_HISTOGRAM */ - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - bzero((char *)&server, - sizeof(server)); - - /* it would seem that while HP-UX will allow an IP address (as a */ - /* string) in a call to gethostbyname, other, less enlightened */ - /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */ - /* order changed to check for IP address first. raj 7/96 */ - - if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) { - /* it was not an IP address, try it as a name */ - if ((hp = gethostbyname(remote_host)) == NULL) { - /* we have no idea what it is */ - fprintf(where, - "establish_control: could not resolve the destination %s\n", - remote_host); - fflush(where); - exit(1); - } - else { - /* it was a valid remote_host */ - bcopy(hp->h_addr, - (char *)&server.sin_addr, - hp->h_length); - server.sin_family = hp->h_addrtype; - } - } - else { - /* it was a valid IP address */ - server.sin_addr.s_addr = addr; - server.sin_family = AF_INET; - } - - if ( print_headers ) { - /* we want to have some additional, interesting information in */ - /* the headers. we know some of it here, but not all, so we will */ - /* only print the test title here and will print the results */ - /* titles after the test is finished */ - fprintf(where,"XTI TCP STREAM TEST"); - fprintf(where," to %s", remote_host); - if (iteration_max > 1) { - fprintf(where, - " : +/-%3.1f%% @ %2d%% conf.", - interval/0.02, - confidence_level); - } - if (loc_nodelay || rem_nodelay) { - fprintf(where," : nodelay"); - } - if (loc_sndavoid || - loc_rcvavoid || - rem_sndavoid || - rem_rcvavoid) { - fprintf(where," : copy avoidance"); - } -#ifdef WANT_HISTOGRAM - fprintf(where," : histogram"); -#endif /* WANT_HISTOGRAM */ -#ifdef WANT_INTERVALS - fprintf(where," : interval"); -#endif /* WANT_INTERVALS */ -#ifdef DIRTY - fprintf(where," : dirty data"); -#endif /* DIRTY */ - fprintf(where,"\n"); - } - - send_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_sent = 0.0; - times_up = 0; - - /*set up the data socket */ - send_socket = create_xti_endpoint(loc_xti_device); - - if (send_socket == INVALID_SOCKET) { - perror("netperf: send_xti_tcp_stream: tcp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_xti_tcp_stream: send_socket obtained...\n"); - } - - /* it would seem that with XTI, there is no implicit bind on a */ - /* connect, so we have to make a call to t_bind. this is not */ - /* terribly convenient, but I suppose that "standard is better */ - /* than better" :) raj 2/95 */ - - if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) { - t_error("send_xti_tcp_stream: t_bind"); - exit(1); - } - - /* at this point, we have either retrieved the socket buffer sizes, */ - /* or have tried to set them, so now, we may want to set the send */ - /* size based on that (because the user either did not use a -m */ - /* option, or used one with an argument of 0). If the socket buffer */ - /* size is not available, we will set the send size to 4KB - no */ - /* particular reason, just arbitrary... */ - if (send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - - /* set-up the data buffer ring with the requested alignment and offset. */ - /* note also that we have allocated a quantity */ - /* of memory that is at least one send-size greater than our socket */ - /* buffer size. We want to be sure that there are at least two */ - /* buffers allocated - this can be a bit of a problem when the */ - /* send_size is bigger than the socket size, so we must check... the */ - /* user may have wanted to explicitly set the "width" of our send */ - /* buffers, we should respect that wish... */ - - if (send_width == 0) { - send_width = (lss_size/send_size) + 1; - if (send_width == 1) send_width++; - } - - if (send_ring == NULL) { - /* only allocate the send ring once. this is a networking test, */ - /* not a memory allocation test. this way, we do not need a */ - /* deallocate_buffer_ring() routine, and I don't feel like */ - /* writing one anyway :) raj 11/94 */ - send_ring = allocate_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 1, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_XTI_TCP_STREAM; - xti_tcp_stream_request->send_buf_size = rss_size; - xti_tcp_stream_request->recv_buf_size = rsr_size; - xti_tcp_stream_request->receive_size = recv_size; - xti_tcp_stream_request->no_delay = rem_nodelay; - xti_tcp_stream_request->recv_alignment = remote_recv_align; - xti_tcp_stream_request->recv_offset = remote_recv_offset; - xti_tcp_stream_request->measure_cpu = remote_cpu_usage; - xti_tcp_stream_request->cpu_rate = remote_cpu_rate; - if (test_time) { - xti_tcp_stream_request->test_length = test_time; - } - else { - xti_tcp_stream_request->test_length = test_bytes; - } - xti_tcp_stream_request->so_rcvavoid = rem_rcvavoid; - xti_tcp_stream_request->so_sndavoid = rem_sndavoid; - - strcpy(xti_tcp_stream_request->xti_device, rem_xti_device); - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I didn't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) xti_tcp_stream_request->xti_device; - lastword = initword + ((strlen(rem_xti_device) + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = ntohl(*charword); - } - } -#endif /* __alpha */ - -#ifdef DIRTY - xti_tcp_stream_request->dirty_count = rem_dirty_count; - xti_tcp_stream_request->clean_count = rem_clean_count; -#endif /* DIRTY */ - - - if (debug > 1) { - fprintf(where, - "netperf: send_xti_tcp_stream: requesting TCP stream test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right*/ - /* after the connect returns. The remote will grab the counter right*/ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = xti_tcp_stream_response->recv_buf_size; - rss_size = xti_tcp_stream_response->send_buf_size; - rem_nodelay = xti_tcp_stream_response->no_delay; - remote_cpu_usage = xti_tcp_stream_response->measure_cpu; - remote_cpu_rate = xti_tcp_stream_response->cpu_rate; - - /* we have to make sure that the server port number is in */ - /* network order */ - server.sin_port = (short)xti_tcp_stream_response->data_port_number; - server.sin_port = htons(server.sin_port); - rem_rcvavoid = xti_tcp_stream_response->so_rcvavoid; - rem_sndavoid = xti_tcp_stream_response->so_sndavoid; - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /*Connect up to the remote port on the data socket */ - memset (&server_call, 0, sizeof(server_call)); - server_call.addr.maxlen = sizeof(struct sockaddr_in); - server_call.addr.len = sizeof(struct sockaddr_in); - server_call.addr.buf = (char *)&server; - - if (t_connect(send_socket, - &server_call, - NULL) == INVALID_SOCKET){ - t_error("netperf: send_xti_tcp_stream: data socket connect failed"); - printf(" port: %d\n",ntohs(server.sin_port)); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either */ - /* the connect would have failed, or the previous response would */ - /* have indicated a problem. I failed to see the value of the */ - /* extra message after the accept on the remote. If it failed, */ - /* we'll see it here. If it didn't, we might as well start pumping */ - /* data. */ - - /* Set-up the test end conditions. For a stream test, they can be */ - /* either time or byte-count based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - bytes_remaining = 0; - /* in previous revisions, we had the same code repeated throught */ - /* all the test suites. this was unnecessary, and meant more */ - /* work for me when I wanted to switch to POSIX signals, so I */ - /* have abstracted this out into a routine in netlib.c. if you */ - /* are experiencing signal problems, you might want to look */ - /* there. raj 11/94 */ - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - bytes_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - if ((interval_burst) || (demo_mode)) { - /* zero means that we never pause, so we never should need the */ - /* interval timer, unless we are in demo_mode */ - start_itimer(interval_wate); - } - interval_count = interval_burst; - /* get the signal set for the call to sigsuspend */ - if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { - fprintf(where, - "send_xti_tcp_stream: unable to get sigmask errno %d\n", - errno); - fflush(where); - exit(1); - } -#endif /* WANT_INTERVALS */ - - /* before we start, initialize a few variables */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. */ - - while ((!times_up) || (bytes_remaining > 0)) { - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. at some point, we might want to replace */ - /* the rand() call with something from a table to reduce our call */ - /* overhead during the test, but it is not a high priority item. */ - access_buffer(send_ring->buffer_ptr, - send_size, - loc_dirty_count, - loc_clean_count); -#endif /* DIRTY */ - -#ifdef WANT_HISTOGRAM - /* timestamp just before we go into send and then again just after */ - /* we come out raj 8/94 */ - HIST_timestamp(&time_one); -#endif /* WANT_HISTOGRAM */ - - if((len=t_snd(send_socket, - send_ring->buffer_ptr, - send_size, - 0)) != send_size) { - if ((len >=0) || (errno == EINTR)) { - /* the test was interrupted, must be the end of test */ - break; - } - fprintf(where, - "send_xti_tcp_stream: t_snd: errno %d t_errno %d t_look 0x%.4x\n", - errno, - t_errno, - t_look(send_socket)); - fflush(where); - exit(1); - } - -#ifdef WANT_HISTOGRAM - /* timestamp the exit from the send call and update the histogram */ - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); -#endif /* WANT_HISTOGRAM */ - -#ifdef WANT_INTERVALS - if (demo_mode) { - units_this_tick += send_size; - } - /* in this case, the interval count is the count-down couter */ - /* to decide to sleep for a little bit */ - if ((interval_burst) && (--interval_count == 0)) { - /* call sigsuspend and wait for the interval timer to get us */ - /* out */ - if (debug) { - fprintf(where,"about to suspend\n"); - fflush(where); - } - if (sigsuspend(&signal_set) == EFAULT) { - fprintf(where, - "send_xti_tcp_stream: fault with signal set!\n"); - fflush(where); - exit(1); - } - interval_count = interval_burst; - } -#endif /* WANT_INTERVALS */ - - /* now we want to move our pointer to the next position in the */ - /* data buffer...we may also want to wrap back to the "beginning" */ - /* of the bufferspace, so we will mod the number of messages sent */ - /* by the send width, and use that to calculate the offset to add */ - /* to the base pointer. */ - nummessages++; - send_ring = send_ring->next; - if (bytes_remaining) { - bytes_remaining -= send_size; - } - } - - /* The test is over. Flush the buffers to the remote end. We do a */ - /* graceful release to insure that all data has been taken by the */ - /* remote. */ - - /* but first, if the verbosity is greater than 1, find-out what */ - /* the TCP maximum segment_size was (if possible) */ - if (verbosity > 1) { - tcp_mss = -1; - get_xti_info(send_socket,info_struct); - } - - if (t_sndrel(send_socket) == -1) { - t_error("netperf: cannot shutdown tcp stream socket"); - exit(1); - } - - /* hang a t_rcvrel() off the socket to block until the remote has */ - /* brought all the data up into the application. it will do a */ - /* t_sedrel to cause a FIN to be sent our way. We will assume that */ - /* any exit from the t_rcvrel() call is good... raj 2/95 */ - - if (debug > 1) { - fprintf(where,"about to hang a receive for graceful release.\n"); - fflush(where); - } - - t_rcvrel(send_socket); - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured and how */ - /* long did we really */ - /* run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a TCP stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) */ - - bytes_sent = xti_tcp_stream_result->bytes_received; - - thruput = calc_thruput(bytes_sent); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - - local_cpu_utilization = calc_cpu_util(0.0); - local_service_demand = calc_service_demand(bytes_sent, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - if (remote_cpu_usage) { - - remote_cpu_utilization = xti_tcp_stream_result->cpu_util; - remote_service_demand = calc_service_demand(bytes_sent, - 0.0, - remote_cpu_utilization, - xti_tcp_stream_result->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - } - - /* at this point, we have finished making all the runs that we */ - /* will be making. so, we should extract what the calcuated values */ - /* are for all the confidence stuff. we could make the values */ - /* global, but that seemed a little messy, and it did not seem worth */ - /* all the mucking with header files. so, we create a routine much */ - /* like calcualte_confidence, which just returns the mean values. */ - /* raj 11/94 */ - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(xti_tcp_stream_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - fprintf(where, - tput_fmt_1, /* the format string */ - rsr_size, /* remote recvbuf size */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - thruput);/* how fast did it go */ - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - /* this stuff needs to be worked-out in the presence of confidence */ - /* intervals and multiple iterations of the test... raj 11/94 */ - - fprintf(where, - ksink_fmt, - "Bytes", - "Bytes", - "Bytes", - local_send_align, - remote_recv_align, - local_send_offset, - remote_recv_offset, - bytes_sent, - bytes_sent / (double)nummessages, - nummessages, - bytes_sent / (double)xti_tcp_stream_result->recv_calls, - xti_tcp_stream_result->recv_calls); - fprintf(where, - ksink_fmt2, - tcp_mss); - fflush(where); -#ifdef WANT_HISTOGRAM - fprintf(where,"\n\nHistogram of time spent in send() call.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } - -} - - -/* This is the server-side routine for the tcp stream test. It is */ -/* implemented as one routine. I could break things-out somewhat, but */ -/* didn't feel it was necessary. */ - -void -recv_xti_tcp_stream() -{ - - struct sockaddr_in myaddr_in, peeraddr_in; - struct t_bind bind_req, bind_resp; - struct t_call call_req; - - SOCKET s_listen,s_data; - int addrlen; - int len; - unsigned int receive_calls; - float elapsed_time; - double bytes_received; - - struct ring_elt *recv_ring; - - int *message_int_ptr; - int i; - - struct xti_tcp_stream_request_struct *xti_tcp_stream_request; - struct xti_tcp_stream_response_struct *xti_tcp_stream_response; - struct xti_tcp_stream_results_struct *xti_tcp_stream_results; - - xti_tcp_stream_request = - (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data; - xti_tcp_stream_response = - (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data; - xti_tcp_stream_results = - (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_xti_tcp_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_xti_tcp_stream: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = XTI_TCP_STREAM_RESPONSE; - - if (debug) { - fprintf(where,"recv_xti_tcp_stream: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug) { - fprintf(where,"recv_xti_tcp_stream: requested alignment of %d\n", - xti_tcp_stream_request->recv_alignment); - fflush(where); - } - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - bzero((char *)&myaddr_in, - sizeof(myaddr_in)); - myaddr_in.sin_family = AF_INET; - myaddr_in.sin_addr.s_addr = INADDR_ANY; - myaddr_in.sin_port = 0; - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_xti_tcp_stream: grabbing a socket...\n"); - fflush(where); - } - - /* create_xti_endpoint expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size = xti_tcp_stream_request->send_buf_size; - lsr_size = xti_tcp_stream_request->recv_buf_size; - loc_nodelay = xti_tcp_stream_request->no_delay; - loc_rcvavoid = xti_tcp_stream_request->so_rcvavoid; - loc_sndavoid = xti_tcp_stream_request->so_sndavoid; - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) xti_tcp_stream_request->xti_device; - lastword = initword + ((xti_tcp_stream_request->dev_name_len + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = htonl(*charword); - } - } - -#endif /* __alpha */ - - s_listen = create_xti_endpoint(xti_tcp_stream_request->xti_device); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - bind_req.addr.maxlen = sizeof(struct sockaddr_in); - bind_req.addr.len = sizeof(struct sockaddr_in); - bind_req.addr.buf = (char *)&myaddr_in; - bind_req.qlen = 1; - - bind_resp.addr.maxlen = sizeof(struct sockaddr_in); - bind_resp.addr.len = sizeof(struct sockaddr_in); - bind_resp.addr.buf = (char *)&myaddr_in; - bind_resp.qlen = 1; - - if (t_bind(s_listen, - &bind_req, - &bind_resp) == SOCKET_ERROR) { - netperf_response.content.serv_errno = t_errno; - close(s_listen); - send_response(); - - exit(1); - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_stream: t_bind complete port %d\n", - ntohs(myaddr_in.sin_port)); - fflush(where); - } - - /* what sort of sizes did we end-up with? */ - if (xti_tcp_stream_request->receive_size == 0) { - if (lsr_size > 0) { - recv_size = lsr_size; - } - else { - recv_size = 4096; - } - } - else { - recv_size = xti_tcp_stream_request->receive_size; - } - - /* we want to set-up our recv_ring in a manner analagous to what we */ - /* do on the sending side. this is more for the sake of symmetry */ - /* than for the needs of say copy avoidance, but it might also be */ - /* more realistic - this way one could conceivably go with a */ - /* double-buffering scheme when taking the data an putting it into */ - /* the filesystem or something like that. raj 7/94 */ - - if (recv_width == 0) { - recv_width = (lsr_size/recv_size) + 1; - if (recv_width == 1) recv_width++; - } - - recv_ring = allocate_buffer_ring(recv_width, - recv_size, - xti_tcp_stream_request->recv_alignment, - xti_tcp_stream_request->recv_offset); - - if (debug) { - fprintf(where,"recv_xti_tcp_stream: recv alignment and offset set...\n"); - fflush(where); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - xti_tcp_stream_response->data_port_number = - (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - xti_tcp_stream_response->cpu_rate = 0.0; /* assume no cpu */ - if (xti_tcp_stream_request->measure_cpu) { - xti_tcp_stream_response->measure_cpu = 1; - xti_tcp_stream_response->cpu_rate = - calibrate_local_cpu(xti_tcp_stream_request->cpu_rate); - } - else { - xti_tcp_stream_response->measure_cpu = 0; - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - xti_tcp_stream_response->send_buf_size = lss_size; - xti_tcp_stream_response->recv_buf_size = lsr_size; - xti_tcp_stream_response->no_delay = loc_nodelay; - xti_tcp_stream_response->so_rcvavoid = loc_rcvavoid; - xti_tcp_stream_response->so_sndavoid = loc_sndavoid; - xti_tcp_stream_response->receive_size = recv_size; - - send_response(); - - /* Now, let's set-up the socket to listen for connections. for xti, */ - /* the t_listen call is blocking by default - this is different */ - /* semantics from BSD - probably has to do with being able to reject */ - /* a call before an accept */ - call_req.addr.maxlen = sizeof(struct sockaddr_in); - call_req.addr.len = sizeof(struct sockaddr_in); - call_req.addr.buf = (char *)&peeraddr_in; - call_req.opt.maxlen = 0; - call_req.opt.len = 0; - call_req.opt.buf = NULL; - call_req.udata.maxlen= 0; - call_req.udata.len = 0; - call_req.udata.buf = 0; - - if (t_listen(s_listen, &call_req) == -1) { - fprintf(where, - "recv_xti_tcp_stream: t_listen: errno %d t_errno %d\n", - errno, - t_errno); - fflush(where); - netperf_response.content.serv_errno = t_errno; - close(s_listen); - send_response(); - exit(1); - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_stream: t_listen complete t_look 0x%.4x\n", - t_look(s_listen)); - fflush(where); - } - - /* now just rubber stamp the thing. we want to use the same fd? so */ - /* we will just equate s_data with s_listen. this seems a little */ - /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */ - s_data = s_listen; - if (t_accept(s_listen, - s_data, - &call_req) == -1) { - fprintf(where, - "recv_xti_tcp_stream: t_accept: errno %d t_errno %d\n", - errno, - t_errno); - fflush(where); - close(s_listen); - exit(1); - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_stream: t_accept complete t_look 0x%.4x\n", - t_look(s_data)); - fprintf(where, - " remote is %s port %d\n", - inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr), - ntohs(peeraddr_in.sin_port)); - fflush(where); - } - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(xti_tcp_stream_request->measure_cpu); - - /* The loop will exit when the sender does a t_sndrel, which will */ - /* return T_LOOK error from the t_recv */ - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to recv. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - - access_buffer(recv_ring->buffer_ptr, - recv_size, - xti_tcp_stream_request->dirty_count, - xti_tcp_stream_request->clean_count); - -#endif /* DIRTY */ - - bytes_received = 0; - receive_calls = 0; - - while ((len = t_rcv(s_data, - recv_ring->buffer_ptr, - recv_size, - &xti_flags)) != -1) { - bytes_received += len; - receive_calls++; - - /* more to the next buffer in the recv_ring */ - recv_ring = recv_ring->next; - -#ifdef DIRTY - - access_buffer(recv_ring->buffer_ptr, - recv_size, - xti_tcp_stream_request->dirty_count, - xti_tcp_stream_request->clean_count); - -#endif /* DIRTY */ - } - - if (t_look(s_data) == T_ORDREL) { - /* this is a normal exit path */ - if (debug) { - fprintf(where, - "recv_xti_tcp_stream: t_rcv T_ORDREL indicated\n"); - fflush(where); - } - } - else { - /* something went wrong */ - fprintf(where, - "recv_xti_tcp_stream: t_rcv: errno %d t_errno %d len %d", - errno, - t_errno, - len); - fprintf(where, - " t_look 0x%.4x", - t_look(s_data)); - fflush(where); - netperf_response.content.serv_errno = t_errno; - send_response(); - exit(1); - } - - /* receive the release and let the initiator know that we have */ - /* received all the data. raj 3/95 */ - - if (t_rcvrel(s_data) == -1) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_stream: t_rcvrel complete\n"); - fflush(where); - } - - if (t_sndrel(s_data) == -1) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_stream: t_sndrel complete\n"); - fflush(where); - } - - cpu_stop(xti_tcp_stream_request->measure_cpu,&elapsed_time); - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_xti_tcp_stream: got %g bytes\n", - bytes_received); - fprintf(where, - "recv_xti_tcp_stream: got %d recvs\n", - receive_calls); - fflush(where); - } - - xti_tcp_stream_results->bytes_received = bytes_received; - xti_tcp_stream_results->elapsed_time = elapsed_time; - xti_tcp_stream_results->recv_calls = receive_calls; - - if (xti_tcp_stream_request->measure_cpu) { - xti_tcp_stream_results->cpu_util = calc_cpu_util(0.0); - }; - - if (debug) { - fprintf(where, - "recv_xti_tcp_stream: test complete, sending results.\n"); - fprintf(where, - " bytes_received %g receive_calls %d\n", - bytes_received, - receive_calls); - fprintf(where, - " len %d\n", - len); - fflush(where); - } - - xti_tcp_stream_results->cpu_method = cpu_method; - send_response(); - - /* we are now done with the socket */ - t_close(s_data); - -} - - - /* this routine implements the sending (netperf) side of the XTI_TCP_RR */ - /* test. */ - -void -send_xti_tcp_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - int timed_out = 0; - float elapsed_time; - - int len; - char *temp_message_ptr; - int nummessages; - SOCKET send_socket; - int trans_remaining; - double bytes_xferd; - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - int rsp_bytes_left; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct hostent *hp; - struct sockaddr_in server; - unsigned int addr; - - struct t_call server_call; - - struct xti_tcp_rr_request_struct *xti_tcp_rr_request; - struct xti_tcp_rr_response_struct *xti_tcp_rr_response; - struct xti_tcp_rr_results_struct *xti_tcp_rr_result; - -#ifdef WANT_INTERVALS - int interval_count; - sigset_t signal_set; -#endif /* WANT_INTERVALS */ - - xti_tcp_rr_request = - (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data; - xti_tcp_rr_response= - (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data; - xti_tcp_rr_result = - (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - time_hist = HIST_new(); -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - bzero((char *)&server, - sizeof(server)); - - /* it would seem that while HP-UX will allow an IP address (as a */ - /* string) in a call to gethostbyname, other, less enlightened */ - /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */ - /* order changed to check for IP address first. raj 7/96 */ - - if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) { - /* it was not an IP address, try it as a name */ - if ((hp = gethostbyname(remote_host)) == NULL) { - /* we have no idea what it is */ - fprintf(where, - "establish_control: could not resolve the destination %s\n", - remote_host); - fflush(where); - exit(1); - } - else { - /* it was a valid remote_host */ - bcopy(hp->h_addr, - (char *)&server.sin_addr, - hp->h_length); - server.sin_family = hp->h_addrtype; - } - } - else { - /* it was a valid IP address */ - server.sin_addr.s_addr = addr; - server.sin_family = AF_INET; - } - - if ( print_headers ) { - fprintf(where,"XTI TCP REQUEST/RESPONSE TEST"); - fprintf(where," to %s", remote_host); - if (iteration_max > 1) { - fprintf(where, - " : +/-%3.1f%% @ %2d%% conf.", - interval/0.02, - confidence_level); - } - if (loc_nodelay || rem_nodelay) { - fprintf(where," : nodelay"); - } - if (loc_sndavoid || - loc_rcvavoid || - rem_sndavoid || - rem_rcvavoid) { - fprintf(where," : copy avoidance"); - } -#ifdef WANT_HISTOGRAM - fprintf(where," : histogram"); -#endif /* WANT_HISTOGRAM */ -#ifdef WANT_INTERVALS - fprintf(where," : interval"); -#endif /* WANT_INTERVALS */ -#ifdef DIRTY - fprintf(where," : dirty data"); -#endif /* DIRTY */ - fprintf(where,"\n"); - } - - /* initialize a few counters */ - - send_ring = NULL; - recv_ring = NULL; - confidence_iteration = 1; - init_stat(); - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - timed_out = 0; - trans_remaining = 0; - - /* set-up the data buffers with the requested alignment and offset. */ - /* since this is a request/response test, default the send_width and */ - /* recv_width to 1 and not two raj 7/94 */ - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - if (send_ring == NULL) { - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - } - - if (recv_ring == NULL) { - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - } - - /*set up the data socket */ - send_socket = create_xti_endpoint(loc_xti_device); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_xti_tcp_rr: tcp stream data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_xti_tcp_rr: send_socket obtained...\n"); - } - - /* it would seem that with XTI, there is no implicit bind on a */ - /* connect, so we have to make a call to t_bind. this is not */ - /* terribly convenient, but I suppose that "standard is better */ - /* than better" :) raj 2/95 */ - - if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) { - t_error("send_xti_tcp_stream: t_bind"); - exit(1); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_XTI_TCP_RR; - xti_tcp_rr_request->recv_buf_size = rsr_size; - xti_tcp_rr_request->send_buf_size = rss_size; - xti_tcp_rr_request->recv_alignment = remote_recv_align; - xti_tcp_rr_request->recv_offset = remote_recv_offset; - xti_tcp_rr_request->send_alignment = remote_send_align; - xti_tcp_rr_request->send_offset = remote_send_offset; - xti_tcp_rr_request->request_size = req_size; - xti_tcp_rr_request->response_size = rsp_size; - xti_tcp_rr_request->no_delay = rem_nodelay; - xti_tcp_rr_request->measure_cpu = remote_cpu_usage; - xti_tcp_rr_request->cpu_rate = remote_cpu_rate; - xti_tcp_rr_request->so_rcvavoid = rem_rcvavoid; - xti_tcp_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - xti_tcp_rr_request->test_length = test_time; - } - else { - xti_tcp_rr_request->test_length = test_trans * -1; - } - - strcpy(xti_tcp_rr_request->xti_device, rem_xti_device); - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I didn't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) xti_tcp_rr_request->xti_device; - lastword = initword + ((strlen(rem_xti_device) + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = ntohl(*charword); - } - } -#endif /* __alpha */ - - if (debug > 1) { - fprintf(where,"netperf: send_xti_tcp_rr: requesting TCP rr test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right*/ - /* after the connect returns. The remote will grab the counter right*/ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = xti_tcp_rr_response->recv_buf_size; - rss_size = xti_tcp_rr_response->send_buf_size; - rem_nodelay = xti_tcp_rr_response->no_delay; - remote_cpu_usage = xti_tcp_rr_response->measure_cpu; - remote_cpu_rate = xti_tcp_rr_response->cpu_rate; - /* make sure that port numbers are in network order */ - server.sin_port = (short)xti_tcp_rr_response->data_port_number; - server.sin_port = htons(server.sin_port); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /*Connect up to the remote port on the data socket */ - memset (&server_call, 0, sizeof(server_call)); - server_call.addr.maxlen = sizeof(struct sockaddr_in); - server_call.addr.len = sizeof(struct sockaddr_in); - server_call.addr.buf = (char *)&server; - - if (t_connect(send_socket, - &server_call, - NULL) == INVALID_SOCKET){ - t_error("netperf: send_xti_tcp_rr: data socket connect failed"); - printf(" port: %d\n",ntohs(server.sin_port)); - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - if ((interval_burst) || (demo_mode)) { - /* zero means that we never pause, so we never should need the */ - /* interval timer, unless we are in demo_mode */ - start_itimer(interval_wate); - } - interval_count = interval_burst; - /* get the signal set for the call to sigsuspend */ - if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { - fprintf(where, - "send_xti_tcp_rr: unable to get sigmask errno %d\n", - errno); - fflush(where); - exit(1); - } -#endif /* WANT_INTERVALS */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - - while ((!times_up) || (trans_remaining > 0)) { - /* send the request. we assume that if we use a blocking socket, */ - /* the request will be sent at one shot. */ - -#ifdef WANT_HISTOGRAM - /* timestamp just before our call to send, and then again just */ - /* after the receive raj 8/94 */ - HIST_timestamp(&time_one); -#endif /* WANT_HISTOGRAM */ - - if((len=t_snd(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - if ((errno == EINTR) || (errno == 0)) { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - fprintf(where, - "send_xti_tcp_rr: t_snd: errno %d t_errno %d t_look 0x%.4x\n", - errno, - t_errno, - t_look(send_socket)); - fflush(where); - exit(1); - } - send_ring = send_ring->next; - - /* receive the response */ - rsp_bytes_left = rsp_size; - temp_message_ptr = recv_ring->buffer_ptr; - while(rsp_bytes_left > 0) { - if((rsp_bytes_recvd=t_rcv(send_socket, - temp_message_ptr, - rsp_bytes_left, - &xti_flags)) == SOCKET_ERROR) { - if (errno == EINTR) { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } - fprintf(where, - "send_xti_tcp_rr: t_rcv: errno %d t_errno %d t_look 0x%x\n", - errno, - t_errno, - t_look(send_socket)); - fflush(where); - exit(1); - } - rsp_bytes_left -= rsp_bytes_recvd; - temp_message_ptr += rsp_bytes_recvd; - } - recv_ring = recv_ring->next; - - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - -#ifdef WANT_HISTOGRAM - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); -#endif /* WANT_HISTOGRAM */ -#ifdef WANT_INTERVALS - if (demo_mode) { - units_this_tick += 1; - } - /* in this case, the interval count is the count-down couter */ - /* to decide to sleep for a little bit */ - if ((interval_burst) && (--interval_count == 0)) { - /* call sigsuspend and wait for the interval timer to get us */ - /* out */ - if (debug) { - fprintf(where,"about to suspend\n"); - fflush(where); - } - if (sigsuspend(&signal_set) == EFAULT) { - fprintf(where, - "send_xti_udp_rr: fault with signal set!\n"); - fflush(where); - exit(1); - } - interval_count = interval_burst; - } -#endif /* WANT_INTERVALS */ - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - if ((nummessages % 100) == 0) { - fprintf(where, - "Transaction %d completed\n", - nummessages); - fflush(where); - } - } - } - - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured? how long */ - /* did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* We now calculate what our thruput was for the test. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = nummessages/elapsed_time; - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - if (remote_cpu_usage) { - remote_cpu_utilization = xti_tcp_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - xti_tcp_rr_result->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - - /* we are now done with the socket, so close it */ - t_close(send_socket); - - } - - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(xti_tcp_rr_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - thruput, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - thruput); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - thruput); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - /* how to handle the verbose information in the presence of */ - /* confidence intervals is yet to be determined... raj 11/94 */ - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt, - local_send_align, - remote_recv_offset, - local_send_offset, - remote_recv_offset); - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/response times\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - - } - -} - -void -send_xti_udp_stream(char remote_host[]) -{ - /**********************************************************************/ - /* */ - /* UDP Unidirectional Send Test */ - /* */ - /**********************************************************************/ - char *tput_title = "\ -Socket Message Elapsed Messages \n\ -Size Size Time Okay Errors Throughput\n\ -bytes bytes secs # # %s/sec\n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1 = "\ -%6d %6d %-7.2f %7d %6d %7.2f\n\ -%6d %-7.2f %7d %7.2f\n\n"; - - - char *cpu_title = "\ -Socket Message Elapsed Messages CPU Service\n\ -Size Size Time Okay Errors Throughput Util Demand\n\ -bytes bytes secs # # %s/sec %% %c%c us/KB\n\n"; - - char *cpu_fmt_0 = - "%6.2f %c\n"; - - char *cpu_fmt_1 = "\ -%6d %6d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\ -%6d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n"; - - unsigned int messages_recvd; - unsigned int messages_sent; - unsigned int failed_sends; - - float elapsed_time, - recv_elapsed, - local_cpu_utilization, - remote_cpu_utilization; - - float local_service_demand, remote_service_demand; - double local_thruput, remote_thruput; - double bytes_sent; - double bytes_recvd; - - - int len; - int *message_int_ptr; - struct ring_elt *send_ring; - SOCKET data_socket; - - unsigned int sum_messages_sent; - unsigned int sum_messages_recvd; - unsigned int sum_failed_sends; - double sum_local_thruput; - -#ifdef WANT_INTERVALS - int interval_count; - sigset_t signal_set; -#endif /* WANT_INTERVALS */ - - struct hostent *hp; - struct sockaddr_in server; - unsigned int addr; - - struct t_unitdata unitdata; - - struct xti_udp_stream_request_struct *xti_udp_stream_request; - struct xti_udp_stream_response_struct *xti_udp_stream_response; - struct xti_udp_stream_results_struct *xti_udp_stream_results; - - xti_udp_stream_request = - (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data; - xti_udp_stream_response = - (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data; - xti_udp_stream_results = - (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - time_hist = HIST_new(); -#endif /* WANT_HISTOGRAM */ - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - bzero((char *)&server, - sizeof(server)); - - /* it would seem that while HP-UX will allow an IP address (as a */ - /* string) in a call to gethostbyname, other, less enlightened */ - /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */ - /* order changed to check for IP address first. raj 7/96 */ - - if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) { - /* it was not an IP address, try it as a name */ - if ((hp = gethostbyname(remote_host)) == NULL) { - /* we have no idea what it is */ - fprintf(where, - "establish_control: could not resolve the destination %s\n", - remote_host); - fflush(where); - exit(1); - } - else { - /* it was a valid remote_host */ - bcopy(hp->h_addr, - (char *)&server.sin_addr, - hp->h_length); - server.sin_family = hp->h_addrtype; - } - } - else { - /* it was a valid IP address */ - server.sin_addr.s_addr = addr; - server.sin_family = AF_INET; - } - - if ( print_headers ) { - fprintf(where,"UDP UNIDIRECTIONAL SEND TEST"); - fprintf(where," to %s", remote_host); - if (iteration_max > 1) { - fprintf(where, - " : +/-%3.1f%% @ %2d%% conf.", - interval/0.02, - confidence_level); - } - if (loc_sndavoid || - loc_rcvavoid || - rem_sndavoid || - rem_rcvavoid) { - fprintf(where," : copy avoidance"); - } -#ifdef WANT_HISTOGRAM - fprintf(where," : histogram"); -#endif /* WANT_HISTOGRAM */ -#ifdef WANT_INTERVALS - fprintf(where," : interval"); -#endif /* WANT_INTERVALS */ -#ifdef DIRTY - fprintf(where," : dirty data"); -#endif /* DIRTY */ - fprintf(where,"\n"); - } - - send_ring = NULL; - confidence_iteration = 1; - init_stat(); - sum_messages_sent = 0; - sum_messages_recvd = 0; - sum_failed_sends = 0; - sum_local_thruput = 0.0; - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - /* initialize a few counters. we have to remember that we might be */ - /* going through the loop more than once. */ - messages_sent = 0; - messages_recvd = 0; - failed_sends = 0; - times_up = 0; - - /*set up the data socket */ - data_socket = create_xti_endpoint(loc_xti_device); - - if (data_socket == INVALID_SOCKET) { - perror("send_xti_udp_stream: create_xti_endpoint"); - exit(1); - } - - if (t_bind(data_socket, NULL, NULL) == SOCKET_ERROR) { - t_error("send_xti_udp_stream: t_bind"); - exit(1); - } - - /* now, we want to see if we need to set the send_size */ - if (send_size == 0) { - if (lss_size > 0) { - send_size = lss_size; - } - else { - send_size = 4096; - } - } - - /* set-up the data buffer with the requested alignment and offset, */ - /* most of the numbers here are just a hack to pick something nice */ - /* and big in an attempt to never try to send a buffer a second time */ - /* before it leaves the node...unless the user set the width */ - /* explicitly. */ - if (send_width == 0) send_width = 32; - - if (send_ring == NULL ) { - send_ring = allocate_buffer_ring(send_width, - send_size, - local_send_align, - local_send_offset); - } - - - /* if the user supplied a cpu rate, this call will complete rather */ - /* quickly, otherwise, the cpu rate will be retured to us for */ - /* possible display. The Library will keep it's own copy of this data */ - /* for use elsewhere. We will only display it. (Does that make it */ - /* "opaque" to us?) */ - - if (local_cpu_usage) - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - - /* Tell the remote end to set up the data connection. The server */ - /* sends back the port number and alters the socket parameters there. */ - /* Of course this is a datagram service so no connection is actually */ - /* set up, the server just sets up the socket and binds it. */ - - netperf_request.content.request_type = DO_XTI_UDP_STREAM; - xti_udp_stream_request->recv_buf_size = rsr_size; - xti_udp_stream_request->message_size = send_size; - xti_udp_stream_request->recv_alignment = remote_recv_align; - xti_udp_stream_request->recv_offset = remote_recv_offset; - xti_udp_stream_request->measure_cpu = remote_cpu_usage; - xti_udp_stream_request->cpu_rate = remote_cpu_rate; - xti_udp_stream_request->test_length = test_time; - xti_udp_stream_request->so_rcvavoid = rem_rcvavoid; - xti_udp_stream_request->so_sndavoid = rem_sndavoid; - - strcpy(xti_udp_stream_request->xti_device, rem_xti_device); - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I didn't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) xti_udp_stream_request->xti_device; - lastword = initword + ((strlen(rem_xti_device) + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = ntohl(*charword); - } - } -#endif /* __alpha */ - - send_request(); - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"send_xti_udp_stream: remote data connection done.\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("send_xti_udp_stream: error on remote"); - exit(1); - } - - /* Place the port number returned by the remote into the sockaddr */ - /* structure so our sends can be sent to the correct place. Also get */ - /* some of the returned socket buffer information for user display. */ - - /* make sure that port numbers are in the proper order */ - server.sin_port = (short)xti_udp_stream_response->data_port_number; - server.sin_port = htons(server.sin_port); - rsr_size = xti_udp_stream_response->recv_buf_size; - rss_size = xti_udp_stream_response->send_buf_size; - remote_cpu_rate = xti_udp_stream_response->cpu_rate; - - /* it would seem that XTI does not allow the expedient of */ - /* "connecting" a UDP end-point the way BSD does. so, we will do */ - /* everything with t_sndudata and t_rcvudata. Our "virtual" */ - /* connect here will be to assign the destination portion of the */ - /* t_unitdata struct here, where we would have otherwise called */ - /* t_connect() raj 3/95 */ - - memset (&unitdata, 0, sizeof(unitdata)); - unitdata.addr.maxlen = sizeof(struct sockaddr_in); - unitdata.addr.len = sizeof(struct sockaddr_in); - unitdata.addr.buf = (char *)&server; - - /* we don't use any options, so might as well set that part here */ - /* too */ - - unitdata.opt.maxlen = 0; - unitdata.opt.len = 0; - unitdata.opt.buf = NULL; - - /* we need to initialize the send buffer for the first time as */ - /* well since we move to the next pointer after the send call. */ - - unitdata.udata.maxlen = send_size; - unitdata.udata.len = send_size; - unitdata.udata.buf = send_ring->buffer_ptr; - - /* set up the timer to call us after test_time. one of these days, */ - /* it might be nice to figure-out a nice reliable way to have the */ - /* test controlled by a byte count as well, but since UDP is not */ - /* reliable, that could prove difficult. so, in the meantime, we */ - /* only allow a XTI_UDP_STREAM test to be a timed test. */ - - if (test_time) { - times_up = 0; - start_timer(test_time); - } - else { - fprintf(where,"Sorry, XTI_UDP_STREAM tests must be timed.\n"); - fflush(where); - exit(1); - } - - /* Get the start count for the idle counter and the start time */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - if ((interval_burst) || (demo_mode)) { - /* zero means that we never pause, so we never should need the */ - /* interval timer, unless we are in demo_mode */ - start_itimer(interval_wate); - } - interval_count = interval_burst; - /* get the signal set for the call to sigsuspend */ - if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { - fprintf(where, - "send_xti_udp_stream: unable to get sigmask errno %d\n", - errno); - fflush(where); - exit(1); - } -#endif /* WANT_INTERVALS */ - - /* Send datagrams like there was no tomorrow. at somepoint it might */ - /* be nice to set this up so that a quantity of bytes could be sent, */ - /* but we still need some sort of end of test trigger on the receive */ - /* side. that could be a select with a one second timeout, but then */ - /* if there is a test where none of the data arrives for awile and */ - /* then starts again, we would end the test too soon. something to */ - /* think about... */ - while (!times_up) { - -#ifdef DIRTY - /* we want to dirty some number of consecutive integers in the buffer */ - /* we are about to send. we may also want to bring some number of */ - /* them cleanly into the cache. The clean ones will follow any dirty */ - /* ones into the cache. */ - - access_buffer(send_ring->buffer_ptr, - send_size, - loc_dirty_count, - loc_clean_count); - -#endif /* DIRTY */ - -#ifdef WANT_HISTOGRAM - HIST_timestamp(&time_one); -#endif /* WANT_HISTOGRAM */ - - if ((t_sndudata(data_socket, - &unitdata)) != 0) { - if (errno == EINTR) - break; - if (errno == ENOBUFS) { - failed_sends++; - continue; - } - perror("xti_udp_send: data send error"); - t_error("xti_udp_send: data send error"); - exit(1); - } - messages_sent++; - - /* now we want to move our pointer to the next position in the */ - /* data buffer...and update the unitdata structure */ - - send_ring = send_ring->next; - unitdata.udata.buf = send_ring->buffer_ptr; - -#ifdef WANT_HISTOGRAM - /* get the second timestamp */ - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); -#endif /* WANT_HISTOGRAM */ -#ifdef WANT_INTERVALS - if (demo_mode) { - units_this_tick += send_size; - } - /* in this case, the interval count is the count-down couter */ - /* to decide to sleep for a little bit */ - if ((interval_burst) && (--interval_count == 0)) { - /* call sigsuspend and wait for the interval timer to get us */ - /* out */ - if (debug) { - fprintf(where,"about to suspend\n"); - fflush(where); - } - if (sigsuspend(&signal_set) == EFAULT) { - fprintf(where, - "send_xti_udp_stream: fault with signal set!\n"); - fflush(where); - exit(1); - } - interval_count = interval_burst; - } -#endif /* WANT_INTERVALS */ - - } - - /* This is a timed test, so the remote will be returning to us after */ - /* a time. We should not need to send any "strange" messages to tell */ - /* the remote that the test is completed, unless we decide to add a */ - /* number of messages to the test. */ - - /* the test is over, so get stats and stuff */ - cpu_stop(local_cpu_usage, - &elapsed_time); - - /* Get the statistics from the remote end */ - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"send_xti_udp_stream: remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("send_xti_udp_stream: error on remote"); - exit(1); - } - - bytes_sent = (double) send_size * (double) messages_sent; - local_thruput = calc_thruput(bytes_sent); - - messages_recvd = xti_udp_stream_results->messages_recvd; - bytes_recvd = (double) send_size * (double) messages_recvd; - - /* we asume that the remote ran for as long as we did */ - - remote_thruput = calc_thruput(bytes_recvd); - - /* print the results for this socket and message size */ - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) We pass zeros for the local */ - /* cpu utilization and elapsed time to tell the routine to use */ - /* the libraries own values for those. */ - if (local_cpu_usage) { - local_cpu_utilization = calc_cpu_util(0.0); - /* shouldn't this really be based on bytes_recvd, since that is */ - /* the effective throughput of the test? I think that it should, */ - /* so will make the change raj 11/94 */ - local_service_demand = calc_service_demand(bytes_recvd, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - /* The local calculations could use variables being kept by */ - /* the local netlib routines. The remote calcuations need to */ - /* have a few things passed to them. */ - if (remote_cpu_usage) { - remote_cpu_utilization = xti_udp_stream_results->cpu_util; - remote_service_demand = calc_service_demand(bytes_recvd, - 0.0, - remote_cpu_utilization, - xti_udp_stream_results->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - remote_thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - /* since the routine calculate_confidence is rather generic, and */ - /* we have a few other parms of interest, we will do a little work */ - /* here to caclulate their average. */ - sum_messages_sent += messages_sent; - sum_messages_recvd += messages_recvd; - sum_failed_sends += failed_sends; - sum_local_thruput += local_thruput; - - confidence_iteration++; - - /* this datapoint is done, so we don't need the socket any longer */ - close(data_socket); - - } - - /* we should reach this point once the test is finished */ - - retrieve_confident_values(&elapsed_time, - &remote_thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* some of the interesting values aren't covered by the generic */ - /* confidence routine */ - messages_sent = sum_messages_sent / (confidence_iteration -1); - messages_recvd = sum_messages_recvd / (confidence_iteration -1); - failed_sends = sum_failed_sends / (confidence_iteration -1); - local_thruput = sum_local_thruput / (confidence_iteration -1); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(xti_udp_stream_results->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - local_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - format_units(), - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1, /* the format string */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long was the test */ - messages_sent, - failed_sends, - local_thruput, /* what was the xfer rate */ - local_cpu_utilization, /* local cpu */ - local_service_demand, /* local service demand */ - rsr_size, - elapsed_time, - messages_recvd, - remote_thruput, - remote_cpu_utilization, /* remote cpu */ - remote_service_demand); /* remote service demand */ - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - local_thruput); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - fprintf(where, - tput_fmt_1, /* the format string */ - lss_size, /* local sendbuf size */ - send_size, /* how large were the sends */ - elapsed_time, /* how long did it take */ - messages_sent, - failed_sends, - local_thruput, - rsr_size, /* remote recvbuf size */ - elapsed_time, - messages_recvd, - remote_thruput); - break; - } - } - - fflush(where); -#ifdef WANT_HISTOGRAM - if (verbosity > 1) { - fprintf(where,"\nHistogram of time spent in send() call\n"); - fflush(where); - HIST_report(time_hist); - } -#endif /* WANT_HISTOGRAM */ - -} - - - /* this routine implements the receive side (netserver) of the */ - /* XTI_UDP_STREAM performance test. */ - -void -recv_xti_udp_stream() -{ - struct ring_elt *recv_ring; - - struct t_bind bind_req, bind_resp; - struct t_unitdata unitdata; - int flags = 0; - - struct sockaddr_in myaddr_in; - struct sockaddr_in fromaddr_in; - - SOCKET s_data; - int addrlen; - unsigned int bytes_received = 0; - float elapsed_time; - - unsigned int message_size; - unsigned int messages_recvd = 0; - - struct xti_udp_stream_request_struct *xti_udp_stream_request; - struct xti_udp_stream_response_struct *xti_udp_stream_response; - struct xti_udp_stream_results_struct *xti_udp_stream_results; - - xti_udp_stream_request = - (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data; - xti_udp_stream_response = - (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data; - xti_udp_stream_results = - (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_xti_udp_stream: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug > 1) { - fprintf(where,"recv_xti_udp_stream: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = XTI_UDP_STREAM_RESPONSE; - - if (debug > 2) { - fprintf(where,"recv_xti_udp_stream: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variable to be at the desired */ - /* alignment with the desired offset. */ - - if (debug > 1) { - fprintf(where,"recv_xti_udp_stream: requested alignment of %d\n", - xti_udp_stream_request->recv_alignment); - fflush(where); - } - - if (recv_width == 0) recv_width = 1; - - recv_ring = allocate_buffer_ring(recv_width, - xti_udp_stream_request->message_size, - xti_udp_stream_request->recv_alignment, - xti_udp_stream_request->recv_offset); - - if (debug > 1) { - fprintf(where,"recv_xti_udp_stream: receive alignment and offset set...\n"); - fflush(where); - } - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - bzero((char *)&myaddr_in, - sizeof(myaddr_in)); - myaddr_in.sin_family = AF_INET; - myaddr_in.sin_addr.s_addr = INADDR_ANY; - myaddr_in.sin_port = 0; - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug > 1) { - fprintf(where,"recv_xti_udp_stream: grabbing a socket...\n"); - fflush(where); - } - - /* create_xti_endpoint expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lsr_size = xti_udp_stream_request->recv_buf_size; - loc_rcvavoid = xti_udp_stream_request->so_rcvavoid; - loc_sndavoid = xti_udp_stream_request->so_sndavoid; - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) xti_udp_stream_request->xti_device; - lastword = initword + ((xti_udp_stream_request->dev_name_len + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = htonl(*charword); - } - } - -#endif /* __alpha */ - - s_data = create_xti_endpoint(xti_udp_stream_request->xti_device); - - if (s_data == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - bind_req.addr.maxlen = sizeof(struct sockaddr_in); - bind_req.addr.len = sizeof(struct sockaddr_in); - bind_req.addr.buf = (char *)&myaddr_in; - bind_req.qlen = 1; - - bind_resp.addr.maxlen = sizeof(struct sockaddr_in); - bind_resp.addr.len = sizeof(struct sockaddr_in); - bind_resp.addr.buf = (char *)&myaddr_in; - bind_resp.qlen = 1; - - if (t_bind(s_data, - &bind_req, - &bind_resp) == SOCKET_ERROR) { - netperf_response.content.serv_errno = t_errno; - send_response(); - - exit(1); - } - - xti_udp_stream_response->test_length = - xti_udp_stream_request->test_length; - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - xti_udp_stream_response->data_port_number = - (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a -1 to */ - /* the initiator. */ - - xti_udp_stream_response->cpu_rate = 0.0; /* assume no cpu */ - xti_udp_stream_response->measure_cpu = 0; - if (xti_udp_stream_request->measure_cpu) { - /* We will pass the rate into the calibration routine. If the */ - /* user did not specify one, it will be 0.0, and we will do a */ - /* "real" calibration. Otherwise, all it will really do is */ - /* store it away... */ - xti_udp_stream_response->measure_cpu = 1; - xti_udp_stream_response->cpu_rate = - calibrate_local_cpu(xti_udp_stream_request->cpu_rate); - } - - message_size = xti_udp_stream_request->message_size; - test_time = xti_udp_stream_request->test_length; - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - xti_udp_stream_response->send_buf_size = lss_size; - xti_udp_stream_response->recv_buf_size = lsr_size; - xti_udp_stream_response->so_rcvavoid = loc_rcvavoid; - xti_udp_stream_response->so_sndavoid = loc_sndavoid; - - /* since we are going to call t_rcvudata() instead of t_rcv() we */ - /* need to init the unitdata structure raj 3/95 */ - - unitdata.addr.maxlen = sizeof(fromaddr_in); - unitdata.addr.len = sizeof(fromaddr_in); - unitdata.addr.buf = (char *)&fromaddr_in; - - unitdata.opt.maxlen = 0; - unitdata.opt.len = 0; - unitdata.opt.buf = NULL; - - unitdata.udata.maxlen = xti_udp_stream_request->message_size; - unitdata.udata.len = xti_udp_stream_request->message_size; - unitdata.udata.buf = recv_ring->buffer_ptr; - - send_response(); - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(xti_udp_stream_request->measure_cpu); - - /* The loop will exit when the timer pops, or if we happen to recv a */ - /* message of less than send_size bytes... */ - - times_up = 0; - start_timer(test_time + PAD_TIME); - - if (debug) { - fprintf(where,"recv_xti_udp_stream: about to enter inner sanctum.\n"); - fflush(where); - } - - while (!times_up) { -#ifdef RAJ_DEBUG - if (debug) { - fprintf(where,"t_rcvudata, errno %d, t_errno %d", - errno, - t_errno); - fprintf(where," after %d messages\n",messages_recvd); - fprintf(where,"addrmax %d addrlen %d addrbuf %x\n", - unitdata.addr.maxlen, - unitdata.addr.len, - unitdata.addr.buf); - fprintf(where,"optmax %d optlen %d optbuf %x\n", - unitdata.opt.maxlen, - unitdata.opt.len, - unitdata.opt.buf); - fprintf(where,"udatamax %d udatalen %d udatabuf %x\n", - unitdata.udata.maxlen, - unitdata.udata.len, - unitdata.udata.buf); - fflush(where); - } -#endif /* RAJ_DEBUG */ - if (t_rcvudata(s_data, - &unitdata, - &flags) != 0) { - if (errno == TNODATA) { - continue; - } - if (errno != EINTR) { - netperf_response.content.serv_errno = t_errno; - send_response(); - exit(1); - } - break; - } - messages_recvd++; - recv_ring = recv_ring->next; - unitdata.udata.buf = recv_ring->buffer_ptr; - } - - if (debug) { - fprintf(where,"recv_xti_udp_stream: got %d messages.\n",messages_recvd); - fflush(where); - } - - - /* The loop now exits due timer or < send_size bytes received. */ - - cpu_stop(xti_udp_stream_request->measure_cpu,&elapsed_time); - - if (times_up) { - /* we ended on a timer, subtract the PAD_TIME */ - elapsed_time -= (float)PAD_TIME; - } - else { - stop_timer(); - } - - if (debug) { - fprintf(where,"recv_xti_udp_stream: test ended in %f seconds.\n",elapsed_time); - fflush(where); - } - - bytes_received = (messages_recvd * message_size); - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_xti_udp_stream: got %d bytes\n", - bytes_received); - fflush(where); - } - - netperf_response.content.response_type = XTI_UDP_STREAM_RESULTS; - xti_udp_stream_results->bytes_received = bytes_received; - xti_udp_stream_results->messages_recvd = messages_recvd; - xti_udp_stream_results->elapsed_time = elapsed_time; - xti_udp_stream_results->cpu_method = cpu_method; - if (xti_udp_stream_request->measure_cpu) { - xti_udp_stream_results->cpu_util = calc_cpu_util(elapsed_time); - } - else { - xti_udp_stream_results->cpu_util = -1.0; - } - - if (debug > 1) { - fprintf(where, - "recv_xti_udp_stream: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - -} - -void send_xti_udp_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f %c\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - float elapsed_time; - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - struct t_bind bind_req, bind_resp; - struct t_unitdata unitdata; - struct t_unitdata send_unitdata; - struct t_unitdata recv_unitdata; - int flags = 0; - - int len; - int nummessages; - SOCKET send_socket; - int trans_remaining; - int bytes_xferd; - - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct hostent *hp; - struct sockaddr_in server, myaddr_in; - unsigned int addr; - int addrlen; - - struct xti_udp_rr_request_struct *xti_udp_rr_request; - struct xti_udp_rr_response_struct *xti_udp_rr_response; - struct xti_udp_rr_results_struct *xti_udp_rr_result; - -#ifdef WANT_INTERVALS - int interval_count; - sigset_t signal_set; -#endif /* WANT_INTERVALS */ - - xti_udp_rr_request = - (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data; - xti_udp_rr_response = - (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data; - xti_udp_rr_result = - (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data; - -#ifdef WANT_HISTOGRAM - time_hist = HIST_new(); -#endif - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - bzero((char *)&server, - sizeof(server)); - - /* it would seem that while HP-UX will allow an IP address (as a */ - /* string) in a call to gethostbyname, other, less enlightened */ - /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */ - /* order changed to check for IP address first. raj 7/96 */ - - if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) { - /* it was not an IP address, try it as a name */ - if ((hp = gethostbyname(remote_host)) == NULL) { - /* we have no idea what it is */ - fprintf(where, - "establish_control: could not resolve the destination %s\n", - remote_host); - fflush(where); - exit(1); - } - else { - /* it was a valid remote_host */ - bcopy(hp->h_addr, - (char *)&server.sin_addr, - hp->h_length); - server.sin_family = hp->h_addrtype; - } - } - else { - /* it was a valid IP address */ - server.sin_addr.s_addr = addr; - server.sin_family = AF_INET; - } - - if ( print_headers ) { - fprintf(where,"XTI UDP REQUEST/RESPONSE TEST"); - fprintf(where," to %s", remote_host); - if (iteration_max > 1) { - fprintf(where, - " : +/-%3.1f%% @ %2d%% conf.", - interval/0.02, - confidence_level); - } - if (loc_sndavoid || - loc_rcvavoid || - rem_sndavoid || - rem_rcvavoid) { - fprintf(where," : copy avoidance"); - } -#ifdef WANT_HISTOGRAM - fprintf(where," : histogram"); -#endif /* WANT_HISTOGRAM */ -#ifdef WANT_INTERVALS - fprintf(where," : interval"); -#endif /* WANT_INTERVALS */ -#ifdef DIRTY - fprintf(where," : dirty data"); -#endif /* DIRTY */ - fprintf(where,"\n"); - } - - /* initialize a few counters */ - - send_ring = NULL; - recv_ring = NULL; - nummessages = 0; - bytes_xferd = 0; - times_up = 0; - confidence_iteration = 1; - init_stat(); - - - /* we have a great-big while loop which controls the number of times */ - /* we run a particular test. this is for the calculation of a */ - /* confidence interval (I really should have stayed awake during */ - /* probstats :). If the user did not request confidence measurement */ - /* (no confidence is the default) then we will only go though the */ - /* loop once. the confidence stuff originates from the folks at IBM */ - - while (((confidence < 0) && (confidence_iteration < iteration_max)) || - (confidence_iteration <= iteration_min)) { - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - trans_remaining = 0; - - /* set-up the data buffers with the requested alignment and offset */ - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - if (send_ring == NULL) { - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - } - - if (recv_ring == NULL) { - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - } - - /* since we are going to call t_rcvudata() instead of t_rcv() we */ - /* need to init the unitdata structure raj 8/95 */ - - memset (&recv_unitdata, 0, sizeof(recv_unitdata)); - recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in); - recv_unitdata.addr.len = sizeof(struct sockaddr_in); - recv_unitdata.addr.buf = (char *)&server; - - recv_unitdata.opt.maxlen = 0; - recv_unitdata.opt.len = 0; - recv_unitdata.opt.buf = NULL; - - recv_unitdata.udata.maxlen = rsp_size; - recv_unitdata.udata.len = rsp_size; - recv_unitdata.udata.buf = recv_ring->buffer_ptr; - - /* since we are going to call t_sndudata() instead of t_snd() we */ - /* need to init the unitdata structure raj 8/95 */ - - memset (&send_unitdata, 0, sizeof(send_unitdata)); - send_unitdata.addr.maxlen = sizeof(struct sockaddr_in); - send_unitdata.addr.len = sizeof(struct sockaddr_in); - send_unitdata.addr.buf = (char *)&server; - - send_unitdata.opt.maxlen = 0; - send_unitdata.opt.len = 0; - send_unitdata.opt.buf = NULL; - - send_unitdata.udata.maxlen = req_size; - send_unitdata.udata.len = req_size; - send_unitdata.udata.buf = send_ring->buffer_ptr; - - /*set up the data socket */ - send_socket = create_xti_endpoint(loc_xti_device); - - if (send_socket == INVALID_SOCKET){ - perror("netperf: send_xti_udp_rr: udp rr data socket"); - exit(1); - } - - if (debug) { - fprintf(where,"send_xti_udp_rr: send_socket obtained...\n"); - } - - /* it would seem that with XTI, there is no implicit bind */ - /* so we have to make a call to t_bind. this is not */ - /* terribly convenient, but I suppose that "standard is better */ - /* than better" :) raj 2/95 */ - - if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) { - t_error("send_xti_tcp_stream: t_bind"); - exit(1); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back. If */ - /* there is no idle counter in the kernel idle loop, the */ - /* local_cpu_rate will be set to -1. */ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_XTI_UDP_RR; - xti_udp_rr_request->recv_buf_size = rsr_size; - xti_udp_rr_request->send_buf_size = rss_size; - xti_udp_rr_request->recv_alignment = remote_recv_align; - xti_udp_rr_request->recv_offset = remote_recv_offset; - xti_udp_rr_request->send_alignment = remote_send_align; - xti_udp_rr_request->send_offset = remote_send_offset; - xti_udp_rr_request->request_size = req_size; - xti_udp_rr_request->response_size = rsp_size; - xti_udp_rr_request->measure_cpu = remote_cpu_usage; - xti_udp_rr_request->cpu_rate = remote_cpu_rate; - xti_udp_rr_request->so_rcvavoid = rem_rcvavoid; - xti_udp_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - xti_udp_rr_request->test_length = test_time; - } - else { - xti_udp_rr_request->test_length = test_trans * -1; - } - - strcpy(xti_udp_rr_request->xti_device, rem_xti_device); - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I didn't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) xti_udp_rr_request->xti_device; - lastword = initword + ((strlen(rem_xti_device) + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = ntohl(*charword); - } - } -#endif /* __alpha */ - - if (debug > 1) { - fprintf(where,"netperf: send_xti_udp_rr: requesting UDP r/r test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right*/ - /* after the connect returns. The remote will grab the counter right*/ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the UDP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote listen done.\n"); - rsr_size = xti_udp_rr_response->recv_buf_size; - rss_size = xti_udp_rr_response->send_buf_size; - remote_cpu_usage = xti_udp_rr_response->measure_cpu; - remote_cpu_rate = xti_udp_rr_response->cpu_rate; - /* port numbers in proper order */ - server.sin_port = (short)xti_udp_rr_response->data_port_number; - server.sin_port = htons(server.sin_port); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* Data Socket set-up is finished. If there were problems, either the */ - /* connect would have failed, or the previous response would have */ - /* indicated a problem. I failed to see the value of the extra */ - /* message after the accept on the remote. If it failed, we'll see it */ - /* here. If it didn't, we might as well start pumping data. */ - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - -#ifdef WANT_INTERVALS - if ((interval_burst) || (demo_mode)) { - /* zero means that we never pause, so we never should need the */ - /* interval timer, unless we are in demo_mode */ - start_itimer(interval_wate); - } - interval_count = interval_burst; - /* get the signal set for the call to sigsuspend */ - if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { - fprintf(where, - "send_xti_udp_rr: unable to get sigmask errno %d\n", - errno); - fflush(where); - exit(1); - } -#endif /* WANT_INTERVALS */ - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return */ - /* false. When the test is controlled by byte count, the time test */ - /* will always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think */ - /* I just arbitrarily decrement trans_remaining for the timed */ - /* test, but will not do that just yet... One other question is */ - /* whether or not the send buffer and the receive buffer should be */ - /* the same buffer. */ - - while ((!times_up) || (trans_remaining > 0)) { - /* send the request */ -#ifdef WANT_HISTOGRAM - HIST_timestamp(&time_one); -#endif - if((t_sndudata(send_socket, - &send_unitdata)) != 0) { - if (errno == EINTR) { - /* We likely hit */ - /* test-end time. */ - break; - } - fprintf(where, - "send_xti_udp_rr: t_sndudata: errno %d t_errno %d t_look 0x%.4x\n", - errno, - t_errno, - t_look(send_socket)); - fflush(where); - exit(1); - } - send_ring = send_ring->next; - - /* receive the response. with UDP we will get it all, or nothing */ - - if((t_rcvudata(send_socket, - &recv_unitdata, - &flags)) != 0) { - if (errno == TNODATA) { - continue; - } - if (errno == EINTR) { - /* Again, we have likely hit test-end time */ - break; - } - fprintf(where, - "send_xti_udp_rr: t_rcvudata: errno %d t_errno %d t_look 0x%x\n", - errno, - t_errno, - t_look(send_socket)); - fprintf(where, - "recv_unitdata.udata.buf %x\n",recv_unitdata.udata.buf); - fprintf(where, - "recv_unitdata.udata.maxlen %x\n",recv_unitdata.udata.maxlen); - fprintf(where, - "recv_unitdata.udata.len %x\n",recv_unitdata.udata.len); - fprintf(where, - "recv_unitdata.addr.buf %x\n",recv_unitdata.addr.buf); - fprintf(where, - "recv_unitdata.addr.maxlen %x\n",recv_unitdata.addr.maxlen); - fprintf(where, - "recv_unitdata.addr.len %x\n",recv_unitdata.addr.len); - fflush(where); - exit(1); - } - recv_ring = recv_ring->next; - -#ifdef WANT_HISTOGRAM - HIST_timestamp(&time_two); - HIST_add(time_hist,delta_micro(&time_one,&time_two)); - - /* at this point, we may wish to sleep for some period of */ - /* time, so we see how long that last transaction just took, */ - /* and sleep for the difference of that and the interval. We */ - /* will not sleep if the time would be less than a */ - /* millisecond. */ -#endif -#ifdef WANT_INTERVALS - if (demo_mode) { - units_this_tick += 1; - } - /* in this case, the interval count is the count-down couter */ - /* to decide to sleep for a little bit */ - if ((interval_burst) && (--interval_count == 0)) { - /* call sigsuspend and wait for the interval timer to get us */ - /* out */ - if (debug) { - fprintf(where,"about to suspend\n"); - fflush(where); - } - if (sigsuspend(&signal_set) == EFAULT) { - fprintf(where, - "send_xti_udp_rr: fault with signal set!\n"); - fflush(where); - exit(1); - } - interval_count = interval_burst; - } -#endif /* WANT_INTERVALS */ - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - if ((nummessages % 100) == 0) { - fprintf(where,"Transaction %d completed\n",nummessages); - fflush(where); - } - } - - } - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */ - /* measured? how long */ - /* did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If */ - /* it wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the */ - /* future, we may want to include a calculation of the thruput */ - /* measured by the remote, but it should be the case that for a */ - /* UDP rr test, that the two numbers should be *very* close... */ - /* We calculate bytes_sent regardless of the way the test length */ - /* was controlled. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = nummessages / elapsed_time; - - if (local_cpu_usage || remote_cpu_usage) { - - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) Of course, some of the */ - /* information might be bogus because there was no idle counter */ - /* in the kernel(s). We need to make a note of this for the */ - /* user's benefit by placing a code for the metod used in the */ - /* test banner */ - - if (local_cpu_usage) { - local_cpu_utilization = calc_cpu_util(0.0); - - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - if (remote_cpu_usage) { - remote_cpu_utilization = xti_udp_rr_result->cpu_util; - - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - xti_udp_rr_result->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - } - else { - /* we were not measuring cpu, for the confidence stuff, we */ - /* should make it -1.0 */ - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* at this point, we want to calculate the confidence information. */ - /* if debugging is on, calculate_confidence will print-out the */ - /* parameters we pass it */ - - calculate_confidence(confidence_iteration, - elapsed_time, - thruput, - local_cpu_utilization, - remote_cpu_utilization, - local_service_demand, - remote_service_demand); - - - confidence_iteration++; - - /* we are done with the socket */ - t_close(send_socket); - } - - /* at this point, we have made all the iterations we are going to */ - /* make. */ - retrieve_confident_values(&elapsed_time, - &thruput, - &local_cpu_utilization, - &remote_cpu_utilization, - &local_service_demand, - &remote_service_demand); - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - if (confidence < 0) { - /* we did not hit confidence, but were we asked to look for it? */ - if (iteration_max > 1) { - display_confidence(); - } - } - - if (local_cpu_usage || remote_cpu_usage) { - local_cpu_method = format_cpu_method(cpu_method); - remote_cpu_method = format_cpu_method(xti_udp_rr_result->cpu_method); - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand, - local_cpu_method); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand, - remote_cpu_method); - } - break; - case 1: - case 2: - if (print_headers) { - fprintf(where, - cpu_title, - local_cpu_method, - remote_cpu_method); - } - - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - nummessages/elapsed_time, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - nummessages/elapsed_time); - break; - case 1: - case 2: - if (print_headers) { - fprintf(where,tput_title,format_units()); - } - - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - nummessages/elapsed_time); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - fflush(where); - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - /* how to handle the verbose information in the presence of */ - /* confidence intervals is yet to be determined... raj 11/94 */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* UDP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - -#ifdef WANT_HISTOGRAM - fprintf(where,"\nHistogram of request/reponse times.\n"); - fflush(where); - HIST_report(time_hist); -#endif /* WANT_HISTOGRAM */ - } -} - - /* this routine implements the receive side (netserver) of a XTI_UDP_RR */ - /* test. */ -void - recv_xti_udp_rr() -{ - - struct ring_elt *recv_ring; - struct ring_elt *send_ring; - - struct t_bind bind_req, bind_resp; - struct t_unitdata send_unitdata; - struct t_unitdata recv_unitdata; - int flags = 0; - - struct sockaddr_in myaddr_in, peeraddr_in; - SOCKET s_data; - int addrlen; - int trans_received; - int trans_remaining; - float elapsed_time; - - struct xti_udp_rr_request_struct *xti_udp_rr_request; - struct xti_udp_rr_response_struct *xti_udp_rr_response; - struct xti_udp_rr_results_struct *xti_udp_rr_results; - - - /* a little variable initialization */ - memset (&myaddr_in, 0, sizeof(struct sockaddr_in)); - myaddr_in.sin_family = AF_INET; - myaddr_in.sin_addr.s_addr = INADDR_ANY; - myaddr_in.sin_port = 0; - memset (&peeraddr_in, 0, sizeof(struct sockaddr_in)); - - /* and some not so paranoid :) */ - xti_udp_rr_request = - (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data; - xti_udp_rr_response = - (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data; - xti_udp_rr_results = - (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_xti_udp_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_xti_udp_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = XTI_UDP_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_xti_udp_rr: the response type is set...\n"); - fflush(where); - } - - /* We now alter the message_ptr variables to be at the desired */ - /* alignments with the desired offsets. */ - - if (debug) { - fprintf(where,"recv_xti_udp_rr: requested recv alignment of %d offset %d\n", - xti_udp_rr_request->recv_alignment, - xti_udp_rr_request->recv_offset); - fprintf(where,"recv_xti_udp_rr: requested send alignment of %d offset %d\n", - xti_udp_rr_request->send_alignment, - xti_udp_rr_request->send_offset); - fflush(where); - } - - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - recv_ring = allocate_buffer_ring(recv_width, - xti_udp_rr_request->request_size, - xti_udp_rr_request->recv_alignment, - xti_udp_rr_request->recv_offset); - - send_ring = allocate_buffer_ring(send_width, - xti_udp_rr_request->response_size, - xti_udp_rr_request->send_alignment, - xti_udp_rr_request->send_offset); - - if (debug) { - fprintf(where,"recv_xti_udp_rr: receive alignment and offset set...\n"); - fflush(where); - } - - /* create_xti_endpoint expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size = xti_udp_rr_request->send_buf_size; - lsr_size = xti_udp_rr_request->recv_buf_size; - loc_rcvavoid = xti_udp_rr_request->so_rcvavoid; - loc_sndavoid = xti_udp_rr_request->so_sndavoid; - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) xti_udp_rr_request->xti_device; - lastword = initword + ((xti_udp_rr_request->dev_name_len + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = htonl(*charword); - } - } - -#endif /* __alpha */ - - s_data = create_xti_endpoint(xti_udp_rr_request->xti_device); - - if (s_data == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - - if (debug) { - fprintf(where,"recv_xti_udp_rr: endpoint created...\n"); - fflush(where); - } - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - bind_req.addr.maxlen = sizeof(struct sockaddr_in); - bind_req.addr.len = sizeof(struct sockaddr_in); - bind_req.addr.buf = (char *)&myaddr_in; - bind_req.qlen = 1; - - bind_resp.addr.maxlen = sizeof(struct sockaddr_in); - bind_resp.addr.len = sizeof(struct sockaddr_in); - bind_resp.addr.buf = (char *)&myaddr_in; - bind_resp.qlen = 1; - - if (t_bind(s_data, - &bind_req, - &bind_resp) == SOCKET_ERROR) { - if (debug) { - fprintf(where, - "recv_xti_udp_rr: t_bind failed, t_errno %d errno %d\n", - t_errno, - errno); - fflush(where); - } - - netperf_response.content.serv_errno = t_errno; - send_response(); - - exit(1); - } - - if (debug) { - fprintf(where, - "recv_xti_udp_rr: endpoint bound to port %d...\n", - ntohs(myaddr_in.sin_port)); - fflush(where); - } - - xti_udp_rr_response->test_length = - xti_udp_rr_request->test_length; - - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - xti_udp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - fprintf(where,"recv port number %d\n",myaddr_in.sin_port); - fflush(where); - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - xti_udp_rr_response->cpu_rate = 0.0; /* assume no cpu */ - xti_udp_rr_response->measure_cpu = 0; - if (xti_udp_rr_request->measure_cpu) { - xti_udp_rr_response->measure_cpu = 1; - xti_udp_rr_response->cpu_rate = - calibrate_local_cpu(xti_udp_rr_request->cpu_rate); - } - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - xti_udp_rr_response->send_buf_size = lss_size; - xti_udp_rr_response->recv_buf_size = lsr_size; - xti_udp_rr_response->so_rcvavoid = loc_rcvavoid; - xti_udp_rr_response->so_sndavoid = loc_sndavoid; - - /* since we are going to call t_rcvudata() instead of t_rcv() we */ - /* need to init the unitdata structure raj 3/95 */ - - memset (&recv_unitdata, 0, sizeof(recv_unitdata)); - recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in); - recv_unitdata.addr.len = sizeof(struct sockaddr_in); - recv_unitdata.addr.buf = (char *)&peeraddr_in; - - recv_unitdata.opt.maxlen = 0; - recv_unitdata.opt.len = 0; - recv_unitdata.opt.buf = NULL; - - recv_unitdata.udata.maxlen = xti_udp_rr_request->request_size; - recv_unitdata.udata.len = xti_udp_rr_request->request_size; - recv_unitdata.udata.buf = recv_ring->buffer_ptr; - - /* since we are going to call t_sndudata() instead of t_snd() we */ - /* need to init the unitdata structure raj 8/95 */ - - memset (&send_unitdata, 0, sizeof(send_unitdata)); - send_unitdata.addr.maxlen = sizeof(struct sockaddr_in); - send_unitdata.addr.len = sizeof(struct sockaddr_in); - send_unitdata.addr.buf = (char *)&peeraddr_in; - - send_unitdata.opt.maxlen = 0; - send_unitdata.opt.len = 0; - send_unitdata.opt.buf = NULL; - - send_unitdata.udata.maxlen = xti_udp_rr_request->response_size; - send_unitdata.udata.len = xti_udp_rr_request->response_size; - send_unitdata.udata.buf = send_ring->buffer_ptr; - - send_response(); - - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(xti_udp_rr_request->measure_cpu); - - if (xti_udp_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(xti_udp_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = xti_udp_rr_request->test_length * -1; - } - - addrlen = sizeof(peeraddr_in); - bzero((char *)&peeraddr_in, addrlen); - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - - /* receive the request from the other side */ - if (t_rcvudata(s_data, - &recv_unitdata, - &flags) != 0) { - if (errno == TNODATA) { - continue; - } - if (errno == EINTR) { - /* we must have hit the end of test time. */ - break; - } - if (debug) { - fprintf(where, - "recv_xti_udp_rr: t_rcvudata failed, t_errno %d errno %d\n", - t_errno, - errno); - fflush(where); - } - netperf_response.content.serv_errno = t_errno; - send_response(); - exit(1); - } - recv_ring = recv_ring->next; - recv_unitdata.udata.buf = recv_ring->buffer_ptr; - - /* Now, send the response to the remote */ - if (t_sndudata(s_data, - &send_unitdata) != 0) { - if (errno == EINTR) { - /* we have hit end of test time. */ - break; - } - if (debug) { - fprintf(where, - "recv_xti_udp_rr: t_sndudata failed, t_errno %d errno %d\n", - t_errno, - errno); - fflush(where); - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - send_ring = send_ring->next; - send_unitdata.udata.buf = send_ring->buffer_ptr; - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug) { - fprintf(where, - "recv_xti_udp_rr: Transaction %d complete.\n", - trans_received); - fflush(where); - } - - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(xti_udp_rr_request->measure_cpu,&elapsed_time); - - if (times_up) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_xti_udp_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - xti_udp_rr_results->bytes_received = (trans_received * - (xti_udp_rr_request->request_size + - xti_udp_rr_request->response_size)); - xti_udp_rr_results->trans_received = trans_received; - xti_udp_rr_results->elapsed_time = elapsed_time; - xti_udp_rr_results->cpu_method = cpu_method; - if (xti_udp_rr_request->measure_cpu) { - xti_udp_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_xti_udp_rr: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - - /* we are done with the socket now */ - close(s_data); - -} - - /* this routine implements the receive (netserver) side of a XTI_TCP_RR */ - /* test */ -void -recv_xti_tcp_rr() -{ - - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - - struct sockaddr_in myaddr_in, peeraddr_in; - struct t_bind bind_req, bind_resp; - struct t_call call_req; - - SOCKET s_listen,s_data; - int addrlen; - char *temp_message_ptr; - int trans_received; - int trans_remaining; - int bytes_sent; - int request_bytes_recvd; - int request_bytes_remaining; - int timed_out = 0; - float elapsed_time; - - struct xti_tcp_rr_request_struct *xti_tcp_rr_request; - struct xti_tcp_rr_response_struct *xti_tcp_rr_response; - struct xti_tcp_rr_results_struct *xti_tcp_rr_results; - - xti_tcp_rr_request = - (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data; - xti_tcp_rr_response = - (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data; - xti_tcp_rr_results = - (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_xti_tcp_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_xti_tcp_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = XTI_TCP_RR_RESPONSE; - - if (debug) { - fprintf(where,"recv_xti_tcp_rr: the response type is set...\n"); - fflush(where); - } - - /* allocate the recv and send rings with the requested alignments */ - /* and offsets. raj 7/94 */ - if (debug) { - fprintf(where,"recv_xti_tcp_rr: requested recv alignment of %d offset %d\n", - xti_tcp_rr_request->recv_alignment, - xti_tcp_rr_request->recv_offset); - fprintf(where,"recv_xti_tcp_rr: requested send alignment of %d offset %d\n", - xti_tcp_rr_request->send_alignment, - xti_tcp_rr_request->send_offset); - fflush(where); - } - - /* at some point, these need to come to us from the remote system */ - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - xti_tcp_rr_request->response_size, - xti_tcp_rr_request->send_alignment, - xti_tcp_rr_request->send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - xti_tcp_rr_request->request_size, - xti_tcp_rr_request->recv_alignment, - xti_tcp_rr_request->recv_offset); - - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - bzero((char *)&myaddr_in, - sizeof(myaddr_in)); - myaddr_in.sin_family = AF_INET; - myaddr_in.sin_addr.s_addr = INADDR_ANY; - myaddr_in.sin_port = 0; - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_xti_tcp_rr: grabbing a socket...\n"); - fflush(where); - } - - /* create_xti_endpoint expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size = xti_tcp_rr_request->send_buf_size; - lsr_size = xti_tcp_rr_request->recv_buf_size; - loc_nodelay = xti_tcp_rr_request->no_delay; - loc_rcvavoid = xti_tcp_rr_request->so_rcvavoid; - loc_sndavoid = xti_tcp_rr_request->so_sndavoid; - -#ifdef __alpha - - /* ok - even on a DEC box, strings are strings. I din't really want */ - /* to ntohl the words of a string. since I don't want to teach the */ - /* send_ and recv_ _request and _response routines about the types, */ - /* I will put "anti-ntohl" calls here. I imagine that the "pure" */ - /* solution would be to use XDR, but I am still leary of being able */ - /* to find XDR libs on all platforms I want running netperf. raj */ - { - int *charword; - int *initword; - int *lastword; - - initword = (int *) xti_tcp_rr_request->xti_device; - lastword = initword + ((xti_tcp_rr_request->dev_name_len + 3) / 4); - - for (charword = initword; - charword < lastword; - charword++) { - - *charword = htonl(*charword); - } - } - -#endif /* __alpha */ - - s_listen = create_xti_endpoint(xti_tcp_rr_request->xti_device); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - - exit(1); - } - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - bind_req.addr.maxlen = sizeof(struct sockaddr_in); - bind_req.addr.len = sizeof(struct sockaddr_in); - bind_req.addr.buf = (char *)&myaddr_in; - bind_req.qlen = 1; - - bind_resp.addr.maxlen = sizeof(struct sockaddr_in); - bind_resp.addr.len = sizeof(struct sockaddr_in); - bind_resp.addr.buf = (char *)&myaddr_in; - bind_resp.qlen = 1; - - if (t_bind(s_listen, - &bind_req, - &bind_resp) == SOCKET_ERROR) { - netperf_response.content.serv_errno = t_errno; - close(s_listen); - send_response(); - - exit(1); - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_rr: t_bind complete port %d\n", - ntohs(myaddr_in.sin_port)); - fflush(where); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - xti_tcp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - xti_tcp_rr_response->cpu_rate = 0.0; /* assume no cpu */ - xti_tcp_rr_response->measure_cpu = 0; - - if (xti_tcp_rr_request->measure_cpu) { - xti_tcp_rr_response->measure_cpu = 1; - xti_tcp_rr_response->cpu_rate = calibrate_local_cpu(xti_tcp_rr_request->cpu_rate); - } - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - xti_tcp_rr_response->send_buf_size = lss_size; - xti_tcp_rr_response->recv_buf_size = lsr_size; - xti_tcp_rr_response->no_delay = loc_nodelay; - xti_tcp_rr_response->so_rcvavoid = loc_rcvavoid; - xti_tcp_rr_response->so_sndavoid = loc_sndavoid; - xti_tcp_rr_response->test_length = xti_tcp_rr_request->test_length; - send_response(); - - /* Now, let's set-up the socket to listen for connections. for xti, */ - /* the t_listen call is blocking by default - this is different */ - /* semantics from BSD - probably has to do with being able to reject */ - /* a call before an accept */ - call_req.addr.maxlen = sizeof(struct sockaddr_in); - call_req.addr.len = sizeof(struct sockaddr_in); - call_req.addr.buf = (char *)&peeraddr_in; - call_req.opt.maxlen = 0; - call_req.opt.len = 0; - call_req.opt.buf = NULL; - call_req.udata.maxlen= 0; - call_req.udata.len = 0; - call_req.udata.buf = 0; - - if (t_listen(s_listen, &call_req) == -1) { - fprintf(where, - "recv_xti_tcp_rr: t_listen: errno %d t_errno %d\n", - errno, - t_errno); - fflush(where); - netperf_response.content.serv_errno = t_errno; - close(s_listen); - send_response(); - exit(1); - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_rr: t_listen complete t_look 0x%.4x\n", - t_look(s_listen)); - fflush(where); - } - - /* now just rubber stamp the thing. we want to use the same fd? so */ - /* we will just equate s_data with s_listen. this seems a little */ - /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */ - s_data = s_listen; - if (t_accept(s_listen, - s_data, - &call_req) == -1) { - fprintf(where, - "recv_xti_tcp_rr: t_accept: errno %d t_errno %d\n", - errno, - t_errno); - fflush(where); - close(s_listen); - exit(1); - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_rr: t_accept complete t_look 0x%.4x", - t_look(s_data)); - fprintf(where, - " remote is %s port %d\n", - inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr), - ntohs(peeraddr_in.sin_port)); - fflush(where); - } - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(xti_tcp_rr_request->measure_cpu); - - if (xti_tcp_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(xti_tcp_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = xti_tcp_rr_request->test_length * -1; - } - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - temp_message_ptr = recv_ring->buffer_ptr; - request_bytes_remaining = xti_tcp_rr_request->request_size; - while(request_bytes_remaining > 0) { - if((request_bytes_recvd=t_rcv(s_data, - temp_message_ptr, - request_bytes_remaining, - &xti_flags)) == SOCKET_ERROR) { - if (errno == EINTR) { - /* the timer popped */ - timed_out = 1; - break; - } - fprintf(where, - "recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d", - errno, - t_errno, - request_bytes_recvd); - fprintf(where, - " t_look 0x%x", - t_look(s_data)); - fflush(where); - netperf_response.content.serv_errno = t_errno; - send_response(); - exit(1); - } - else { - request_bytes_remaining -= request_bytes_recvd; - temp_message_ptr += request_bytes_recvd; - } - } - - recv_ring = recv_ring->next; - - if (timed_out) { - /* we hit the end of the test based on time - lets */ - /* bail out of here now... */ - if (debug) { - fprintf(where,"yo5\n"); - fflush(where); - } - break; - } - - /* Now, send the response to the remote */ - if((bytes_sent=t_snd(s_data, - send_ring->buffer_ptr, - xti_tcp_rr_request->response_size, - 0)) == -1) { - if (errno == EINTR) { - /* the test timer has popped */ - timed_out = 1; - if (debug) { - fprintf(where,"yo6\n"); - fflush(where); - } - break; - } - fprintf(where, - "recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d", - errno, - t_errno, - bytes_sent); - fprintf(where, - " t_look 0x%x", - t_look(s_data)); - fflush(where); - netperf_response.content.serv_errno = t_errno; - send_response(); - exit(1); - } - - send_ring = send_ring->next; - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(xti_tcp_rr_request->measure_cpu,&elapsed_time); - - stop_timer(); /* this is probably unnecessary, but it shouldn't hurt */ - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_xti_tcp_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - xti_tcp_rr_results->bytes_received = (trans_received * - (xti_tcp_rr_request->request_size + - xti_tcp_rr_request->response_size)); - xti_tcp_rr_results->trans_received = trans_received; - xti_tcp_rr_results->elapsed_time = elapsed_time; - xti_tcp_rr_results->cpu_method = cpu_method; - if (xti_tcp_rr_request->measure_cpu) { - xti_tcp_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_rr: test complete, sending results.\n"); - fflush(where); - } - - /* we are done with the socket, free it */ - t_close(s_data); - - send_response(); - -} - - - - /* this test is intended to test the performance of establishing a */ - /* connection, exchanging a request/response pair, and repeating. it */ - /* is expected that this would be a good starting-point for */ - /* comparision of T/TCP with classic TCP for transactional workloads. */ - /* it will also look (can look) much like the communication pattern */ - /* of http for www access. */ - -void -send_xti_tcp_conn_rr(char remote_host[]) -{ - - char *tput_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans.\n\ -Send Recv Size Size Time Rate \n\ -bytes Bytes bytes bytes secs. per sec \n\n"; - - char *tput_fmt_0 = - "%7.2f\n"; - - char *tput_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %7.2f \n"; - char *tput_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *cpu_title = "\ -Local /Remote\n\ -Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\ -Send Recv Size Size Time Rate local remote local remote\n\ -bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n"; - - char *cpu_fmt_0 = - "%6.3f\n"; - - char *cpu_fmt_1_line_1 = "\ -%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n"; - - char *cpu_fmt_1_line_2 = "\ -%-6d %-6d\n"; - - char *ksink_fmt = "\ -Alignment Offset\n\ -Local Remote Local Remote\n\ -Send Recv Send Recv\n\ -%5d %5d %5d %5d\n"; - - - int one = 1; - int timed_out = 0; - float elapsed_time; - - int len; - struct ring_elt *send_ring; - struct ring_elt *recv_ring; - char *temp_message_ptr; - int nummessages; - SOCKET send_socket; - int trans_remaining; - double bytes_xferd; - int sock_opt_len = sizeof(int); - int rsp_bytes_left; - int rsp_bytes_recvd; - - float local_cpu_utilization; - float local_service_demand; - float remote_cpu_utilization; - float remote_service_demand; - double thruput; - - struct hostent *hp; - struct sockaddr_in server; - struct sockaddr_in *myaddr; - unsigned int addr; - int myport; - - struct xti_tcp_conn_rr_request_struct *xti_tcp_conn_rr_request; - struct xti_tcp_conn_rr_response_struct *xti_tcp_conn_rr_response; - struct xti_tcp_conn_rr_results_struct *xti_tcp_conn_rr_result; - - xti_tcp_conn_rr_request = - (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data; - xti_tcp_conn_rr_response = - (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data; - xti_tcp_conn_rr_result = - (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data; - - /* since we are now disconnected from the code that established the */ - /* control socket, and since we want to be able to use different */ - /* protocols and such, we are passed the name of the remote host and */ - /* must turn that into the test specific addressing information. */ - - myaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in)); - if (myaddr == NULL) { - printf("malloc(%d) failed!\n", sizeof(struct sockaddr_in)); - exit(1); - } - - bzero((char *)&server, - sizeof(server)); - bzero((char *)myaddr, - sizeof(struct sockaddr_in)); - myaddr->sin_family = AF_INET; - - /* it would seem that while HP-UX will allow an IP address (as a */ - /* string) in a call to gethostbyname, other, less enlightened */ - /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */ - /* order changed to check for IP address first. raj 7/96 */ - - if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) { - /* it was not an IP address, try it as a name */ - if ((hp = gethostbyname(remote_host)) == NULL) { - /* we have no idea what it is */ - fprintf(where, - "establish_control: could not resolve the destination %s\n", - remote_host); - fflush(where); - exit(1); - } - else { - /* it was a valid remote_host */ - bcopy(hp->h_addr, - (char *)&server.sin_addr, - hp->h_length); - server.sin_family = hp->h_addrtype; - } - } - else { - /* it was a valid IP address */ - server.sin_addr.s_addr = addr; - server.sin_family = AF_INET; - } - - if ( print_headers ) { - fprintf(where,"TCP Connect/Request/Response Test\n"); - if (local_cpu_usage || remote_cpu_usage) - fprintf(where,cpu_title,format_units()); - else - fprintf(where,tput_title,format_units()); - } - - /* initialize a few counters */ - - nummessages = 0; - bytes_xferd = 0.0; - times_up = 0; - - /* set-up the data buffers with the requested alignment and offset */ - if (send_width == 0) send_width = 1; - if (recv_width == 0) recv_width = 1; - - send_ring = allocate_buffer_ring(send_width, - req_size, - local_send_align, - local_send_offset); - - recv_ring = allocate_buffer_ring(recv_width, - rsp_size, - local_recv_align, - local_recv_offset); - - - if (debug) { - fprintf(where,"send_xti_tcp_conn_rr: send_socket obtained...\n"); - } - - /* If the user has requested cpu utilization measurements, we must */ - /* calibrate the cpu(s). We will perform this task within the tests */ - /* themselves. If the user has specified the cpu rate, then */ - /* calibrate_local_cpu will return rather quickly as it will have */ - /* nothing to do. If local_cpu_rate is zero, then we will go through */ - /* all the "normal" calibration stuff and return the rate back.*/ - - if (local_cpu_usage) { - local_cpu_rate = calibrate_local_cpu(local_cpu_rate); - } - - /* Tell the remote end to do a listen. The server alters the socket */ - /* paramters on the other side at this point, hence the reason for */ - /* all the values being passed in the setup message. If the user did */ - /* not specify any of the parameters, they will be passed as 0, which */ - /* will indicate to the remote that no changes beyond the system's */ - /* default should be used. Alignment is the exception, it will */ - /* default to 8, which will be no alignment alterations. */ - - netperf_request.content.request_type = DO_XTI_TCP_CRR; - xti_tcp_conn_rr_request->recv_buf_size = rsr_size; - xti_tcp_conn_rr_request->send_buf_size = rss_size; - xti_tcp_conn_rr_request->recv_alignment = remote_recv_align; - xti_tcp_conn_rr_request->recv_offset = remote_recv_offset; - xti_tcp_conn_rr_request->send_alignment = remote_send_align; - xti_tcp_conn_rr_request->send_offset = remote_send_offset; - xti_tcp_conn_rr_request->request_size = req_size; - xti_tcp_conn_rr_request->response_size = rsp_size; - xti_tcp_conn_rr_request->no_delay = rem_nodelay; - xti_tcp_conn_rr_request->measure_cpu = remote_cpu_usage; - xti_tcp_conn_rr_request->cpu_rate = remote_cpu_rate; - xti_tcp_conn_rr_request->so_rcvavoid = rem_rcvavoid; - xti_tcp_conn_rr_request->so_sndavoid = rem_sndavoid; - if (test_time) { - xti_tcp_conn_rr_request->test_length = test_time; - } - else { - xti_tcp_conn_rr_request->test_length = test_trans * -1; - } - - if (debug > 1) { - fprintf(where,"netperf: send_xti_tcp_conn_rr: requesting TCP crr test\n"); - } - - send_request(); - - /* The response from the remote will contain all of the relevant */ - /* socket parameters for this test type. We will put them back into */ - /* the variables here so they can be displayed if desired. The */ - /* remote will have calibrated CPU if necessary, and will have done */ - /* all the needed set-up we will have calibrated the cpu locally */ - /* before sending the request, and will grab the counter value right */ - /* after the connect returns. The remote will grab the counter right */ - /* after the accept call. This saves the hassle of extra messages */ - /* being sent for the TCP tests. */ - - recv_response(); - - if (!netperf_response.content.serv_errno) { - rsr_size = xti_tcp_conn_rr_response->recv_buf_size; - rss_size = xti_tcp_conn_rr_response->send_buf_size; - rem_nodelay = xti_tcp_conn_rr_response->no_delay; - remote_cpu_usage= xti_tcp_conn_rr_response->measure_cpu; - remote_cpu_rate = xti_tcp_conn_rr_response->cpu_rate; - /* make sure that port numbers are in network order */ - server.sin_port = (short)xti_tcp_conn_rr_response->data_port_number; - server.sin_port = htons(server.sin_port); - if (debug) { - fprintf(where,"remote listen done.\n"); - fprintf(where,"remote port is %d\n",ntohs(server.sin_port)); - fflush(where); - } - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* Set-up the test end conditions. For a request/response test, they */ - /* can be either time or transaction based. */ - - if (test_time) { - /* The user wanted to end the test after a period of time. */ - times_up = 0; - trans_remaining = 0; - start_timer(test_time); - } - else { - /* The tester wanted to send a number of bytes. */ - trans_remaining = test_bytes; - times_up = 1; - } - - /* The cpu_start routine will grab the current time and possibly */ - /* value of the idle counter for later use in measuring cpu */ - /* utilization and/or service demand and thruput. */ - - cpu_start(local_cpu_usage); - - /* We use an "OR" to control test execution. When the test is */ - /* controlled by time, the byte count check will always return false. */ - /* When the test is controlled by byte count, the time test will */ - /* always return false. When the test is finished, the whole */ - /* expression will go false and we will stop sending data. I think I */ - /* just arbitrarily decrement trans_remaining for the timed test, but */ - /* will not do that just yet... One other question is whether or not */ - /* the send buffer and the receive buffer should be the same buffer. */ - - /* just for grins, start the port numbers at 65530. this should */ - /* quickly flush-out those broken implementations of TCP which treat */ - /* the port number as a signed 16 bit quantity. */ - myport = 65530; - myaddr->sin_port = htons(myport); - - while ((!times_up) || (trans_remaining > 0)) { - - /* set up the data socket */ - send_socket = create_xti_endpoint(loc_xti_device); - - if (send_socket == INVALID_SOCKET) { - perror("netperf: send_xti_tcp_conn_rr: tcp stream data socket"); - exit(1); - } - - /* we set SO_REUSEADDR on the premis that no unreserved port */ - /* number on the local system is going to be already connected to */ - /* the remote netserver's port number. we might still have a */ - /* problem if there is a port in the unconnected state. In that */ - /* case, we might want to throw-in a goto to the point where we */ - /* increment the port number by one and try again. of course, this */ - /* could lead to a big load of spinning. one thing that I might */ - /* try later is to have the remote actually allocate a couple of */ - /* port numbers and cycle through those as well. depends on if we */ - /* can get through all the unreserved port numbers in less than */ - /* the length of the TIME_WAIT state raj 8/94 */ - one = 1; - if(setsockopt(send_socket, SOL_SOCKET, SO_REUSEADDR, - (char *)&one, sock_opt_len) == SOCKET_ERROR) { - perror("netperf: send_xti_tcp_conn_rr: so_reuseaddr"); - exit(1); - } - - /* we want to bind our socket to a particular port number. */ - if (bind(send_socket, - (struct sockaddr *)myaddr, - sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("netperf: send_xti_tcp_conn_rr: tried to bind to port %d\n", - ntohs(myaddr->sin_port)); - perror("netperf: send_xti_tcp_conn_rr: bind"); - exit(1); - } - - /* Connect up to the remote port on the data socket */ - if (connect(send_socket, - (struct sockaddr *)&server, - sizeof(server)) == INVALID_SOCKET){ - if (errno == EINTR) { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("netperf: data socket connect failed"); - printf("\tattempted to connect on socket %d to port %d", - send_socket, - ntohs(server.sin_port)); - printf(" from port %d \n",ntohs(myaddr->sin_port)); - exit(1); - } - - /* send the request */ - if((len=send(send_socket, - send_ring->buffer_ptr, - req_size, - 0)) != req_size) { - if (errno == EINTR) { - /* we hit the end of a */ - /* timed test. */ - timed_out = 1; - break; - } - perror("send_xti_tcp_conn_rr: data send error"); - exit(1); - } - send_ring = send_ring->next; - - /* receive the response */ - rsp_bytes_left = rsp_size; - temp_message_ptr = recv_ring->buffer_ptr; - while(rsp_bytes_left > 0) { - if((rsp_bytes_recvd=recv(send_socket, - temp_message_ptr, - rsp_bytes_left, - 0)) == SOCKET_ERROR) { - if (errno == EINTR) { - /* We hit the end of a timed test. */ - timed_out = 1; - break; - } - perror("send_xti_tcp_conn_rr: data recv error"); - exit(1); - } - rsp_bytes_left -= rsp_bytes_recvd; - temp_message_ptr += rsp_bytes_recvd; - } - recv_ring = recv_ring->next; - - if (timed_out) { - /* we may have been in a nested while loop - we need */ - /* another call to break. */ - break; - } - - close(send_socket); - - nummessages++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug > 3) { - fprintf(where, - "Transaction %d completed on local port %d\n", - nummessages, - ntohs(myaddr->sin_port)); - fflush(where); - } - -newport: - /* pick a new port number */ - myport = ntohs(myaddr->sin_port); - myport++; - /* we do not want to use the port number that the server is */ - /* sitting at - this would cause us to fail in a loopback test */ - - if (myport == ntohs(server.sin_port)) myport++; - - /* wrap the port number when we get to 65535. NOTE, some broken */ - /* TCP's might treat the port number as a signed 16 bit quantity. */ - /* we aren't interested in testing such broekn implementations :) */ - /* raj 8/94 */ - if (myport == 65535) { - myport = 5000; - } - myaddr->sin_port = htons(myport); - - if (debug) { - if ((myport % 1000) == 0) { - printf("port %d\n",myport); - } - } - - } - - /* this call will always give us the elapsed time for the test, and */ - /* will also store-away the necessaries for cpu utilization */ - - cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */ - /* how long did we really run? */ - - /* Get the statistics from the remote end. The remote will have */ - /* calculated service demand and all those interesting things. If it */ - /* wasn't supposed to care, it will return obvious values. */ - - recv_response(); - if (!netperf_response.content.serv_errno) { - if (debug) - fprintf(where,"remote results obtained\n"); - } - else { - Set_errno(netperf_response.content.serv_errno); - perror("netperf: remote error"); - - exit(1); - } - - /* We now calculate what our thruput was for the test. In the future, */ - /* we may want to include a calculation of the thruput measured by */ - /* the remote, but it should be the case that for a TCP stream test, */ - /* that the two numbers should be *very* close... We calculate */ - /* bytes_sent regardless of the way the test length was controlled. */ - /* If it was time, we needed to, and if it was by bytes, the user may */ - /* have specified a number of bytes that wasn't a multiple of the */ - /* send_size, so we really didn't send what he asked for ;-) We use */ - /* Kbytes/s as the units of thruput for a TCP stream test, where K = */ - /* 1024. A future enhancement *might* be to choose from a couple of */ - /* unit selections. */ - - bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages); - thruput = calc_thruput(bytes_xferd); - - if (local_cpu_usage || remote_cpu_usage) { - /* We must now do a little math for service demand and cpu */ - /* utilization for the system(s) */ - /* Of course, some of the information might be bogus because */ - /* there was no idle counter in the kernel(s). We need to make */ - /* a note of this for the user's benefit...*/ - if (local_cpu_usage) { - if (local_cpu_rate == 0.0) { - fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n"); - fprintf(where,"Local CPU usage numbers based on process information only!\n"); - fflush(where); - } - local_cpu_utilization = calc_cpu_util(0.0); - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - local_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - 0.0, - 0); - } - else { - local_cpu_utilization = -1.0; - local_service_demand = -1.0; - } - - if (remote_cpu_usage) { - if (remote_cpu_rate == 0.0) { - fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n"); - fprintf(where,"Remote CPU usage numbers based on process information only!\n"); - fflush(where); - } - remote_cpu_utilization = xti_tcp_conn_rr_result->cpu_util; - /* since calc_service demand is doing ms/Kunit we will */ - /* multiply the number of transaction by 1024 to get */ - /* "good" numbers */ - remote_service_demand = calc_service_demand((double) nummessages*1024, - 0.0, - remote_cpu_utilization, - xti_tcp_conn_rr_result->num_cpus); - } - else { - remote_cpu_utilization = -1.0; - remote_service_demand = -1.0; - } - - /* We are now ready to print all the information. If the user */ - /* has specified zero-level verbosity, we will just print the */ - /* local service demand, or the remote service demand. If the */ - /* user has requested verbosity level 1, he will get the basic */ - /* "streamperf" numbers. If the user has specified a verbosity */ - /* of greater than 1, we will display a veritable plethora of */ - /* background information from outside of this block as it it */ - /* not cpu_measurement specific... */ - - switch (verbosity) { - case 0: - if (local_cpu_usage) { - fprintf(where, - cpu_fmt_0, - local_service_demand); - } - else { - fprintf(where, - cpu_fmt_0, - remote_service_demand); - } - break; - case 1: - fprintf(where, - cpu_fmt_1_line_1, /* the format string */ - lss_size, /* local sendbuf size */ - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* guess */ - elapsed_time, /* how long was the test */ - nummessages/elapsed_time, - local_cpu_utilization, /* local cpu */ - remote_cpu_utilization, /* remote cpu */ - local_service_demand, /* local service demand */ - remote_service_demand); /* remote service demand */ - fprintf(where, - cpu_fmt_1_line_2, - rss_size, - rsr_size); - break; - } - } - else { - /* The tester did not wish to measure service demand. */ - switch (verbosity) { - case 0: - fprintf(where, - tput_fmt_0, - nummessages/elapsed_time); - break; - case 1: - fprintf(where, - tput_fmt_1_line_1, /* the format string */ - lss_size, - lsr_size, - req_size, /* how large were the requests */ - rsp_size, /* how large were the responses */ - elapsed_time, /* how long did it take */ - nummessages/elapsed_time); - fprintf(where, - tput_fmt_1_line_2, - rss_size, /* remote recvbuf size */ - rsr_size); - - break; - } - } - - /* it would be a good thing to include information about some of the */ - /* other parameters that may have been set for this test, but at the */ - /* moment, I do not wish to figure-out all the formatting, so I will */ - /* just put this comment here to help remind me that it is something */ - /* that should be done at a later time. */ - - if (verbosity > 1) { - /* The user wanted to know it all, so we will give it to him. */ - /* This information will include as much as we can find about */ - /* TCP statistics, the alignments of the sends and receives */ - /* and all that sort of rot... */ - - fprintf(where, - ksink_fmt); - } - -} - - -void -recv_xti_tcp_conn_rr() -{ - - char *message; - struct sockaddr_in myaddr_in, - peeraddr_in; - SOCKET s_listen,s_data; - int addrlen; - char *recv_message_ptr; - char *send_message_ptr; - char *temp_message_ptr; - int trans_received; - int trans_remaining; - int bytes_sent; - int request_bytes_recvd; - int request_bytes_remaining; - int timed_out = 0; - float elapsed_time; - - struct xti_tcp_conn_rr_request_struct *xti_tcp_conn_rr_request; - struct xti_tcp_conn_rr_response_struct *xti_tcp_conn_rr_response; - struct xti_tcp_conn_rr_results_struct *xti_tcp_conn_rr_results; - - xti_tcp_conn_rr_request = - (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data; - xti_tcp_conn_rr_response = - (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data; - xti_tcp_conn_rr_results = - (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data; - - if (debug) { - fprintf(where,"netserver: recv_xti_tcp_conn_rr: entered...\n"); - fflush(where); - } - - /* We want to set-up the listen socket with all the desired */ - /* parameters and then let the initiator know that all is ready. If */ - /* socket size defaults are to be used, then the initiator will have */ - /* sent us 0's. If the socket sizes cannot be changed, then we will */ - /* send-back what they are. If that information cannot be determined, */ - /* then we send-back -1's for the sizes. If things go wrong for any */ - /* reason, we will drop back ten yards and punt. */ - - /* If anything goes wrong, we want the remote to know about it. It */ - /* would be best if the error that the remote reports to the user is */ - /* the actual error we encountered, rather than some bogus unexpected */ - /* response type message. */ - - if (debug) { - fprintf(where,"recv_xti_tcp_conn_rr: setting the response type...\n"); - fflush(where); - } - - netperf_response.content.response_type = XTI_TCP_CRR_RESPONSE; - - if (debug) { - fprintf(where,"recv_xti_tcp_conn_rr: the response type is set...\n"); - fflush(where); - } - - /* set-up the data buffer with the requested alignment and offset */ - message = (char *)malloc(DATABUFFERLEN); - if (message == NULL) { - printf("malloc(%d) failed!\n", DATABUFFERLEN); - exit(1); - } - - /* We now alter the message_ptr variables to be at the desired */ - /* alignments with the desired offsets. */ - - if (debug) { - fprintf(where, - "recv_xti_tcp_conn_rr: requested recv alignment of %d offset %d\n", - xti_tcp_conn_rr_request->recv_alignment, - xti_tcp_conn_rr_request->recv_offset); - fprintf(where, - "recv_xti_tcp_conn_rr: requested send alignment of %d offset %d\n", - xti_tcp_conn_rr_request->send_alignment, - xti_tcp_conn_rr_request->send_offset); - fflush(where); - } - - recv_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->recv_alignment, xti_tcp_conn_rr_request->recv_offset); - - send_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->send_alignment, xti_tcp_conn_rr_request->send_offset); - - if (debug) { - fprintf(where,"recv_xti_tcp_conn_rr: receive alignment and offset set...\n"); - fflush(where); - } - - /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */ - /* can put in OUR values !-) At some point, we may want to nail this */ - /* socket to a particular network-level address, but for now, */ - /* INADDR_ANY should be just fine. */ - - bzero((char *)&myaddr_in, - sizeof(myaddr_in)); - myaddr_in.sin_family = AF_INET; - myaddr_in.sin_addr.s_addr = INADDR_ANY; - myaddr_in.sin_port = 0; - - /* Grab a socket to listen on, and then listen on it. */ - - if (debug) { - fprintf(where,"recv_xti_tcp_conn_rr: grabbing a socket...\n"); - fflush(where); - } - - /* create_xti_endpoint expects to find some things in the global */ - /* variables, so set the globals based on the values in the request. */ - /* once the socket has been created, we will set the response values */ - /* based on the updated value of those globals. raj 7/94 */ - lss_size = xti_tcp_conn_rr_request->send_buf_size; - lsr_size = xti_tcp_conn_rr_request->recv_buf_size; - loc_nodelay = xti_tcp_conn_rr_request->no_delay; - loc_rcvavoid = xti_tcp_conn_rr_request->so_rcvavoid; - loc_sndavoid = xti_tcp_conn_rr_request->so_sndavoid; - - s_listen = create_xti_endpoint(loc_xti_device); - - if (s_listen == INVALID_SOCKET) { - netperf_response.content.serv_errno = errno; - send_response(); - if (debug) { - fprintf(where,"could not create data socket\n"); - fflush(where); - } - exit(1); - } - - /* Let's get an address assigned to this socket so we can tell the */ - /* initiator how to reach the data socket. There may be a desire to */ - /* nail this socket to a specific IP address in a multi-homed, */ - /* multi-connection situation, but for now, we'll ignore the issue */ - /* and concentrate on single connection testing. */ - - if (bind(s_listen, - (struct sockaddr *)&myaddr_in, - sizeof(myaddr_in)) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - if (debug) { - fprintf(where,"could not bind\n"); - fflush(where); - } - exit(1); - } - - /* Now, let's set-up the socket to listen for connections */ - if (listen(s_listen, 5) == SOCKET_ERROR) { - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - if (debug) { - fprintf(where,"could not listen\n"); - fflush(where); - } - exit(1); - } - - /* now get the port number assigned by the system */ - addrlen = sizeof(myaddr_in); - if (getsockname(s_listen, - (struct sockaddr *)&myaddr_in, - &addrlen) == SOCKET_ERROR){ - netperf_response.content.serv_errno = errno; - close(s_listen); - send_response(); - if (debug) { - fprintf(where,"could not geetsockname\n"); - fflush(where); - } - exit(1); - } - - /* Now myaddr_in contains the port and the internet address this is */ - /* returned to the sender also implicitly telling the sender that the */ - /* socket buffer sizing has been done. */ - - xti_tcp_conn_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port); - if (debug) { - fprintf(where,"telling the remote to call me at %d\n", - xti_tcp_conn_rr_response->data_port_number); - fflush(where); - } - netperf_response.content.serv_errno = 0; - - /* But wait, there's more. If the initiator wanted cpu measurements, */ - /* then we must call the calibrate routine, which will return the max */ - /* rate back to the initiator. If the CPU was not to be measured, or */ - /* something went wrong with the calibration, we will return a 0.0 to */ - /* the initiator. */ - - xti_tcp_conn_rr_response->cpu_rate = 0.0; /* assume no cpu */ - if (xti_tcp_conn_rr_request->measure_cpu) { - xti_tcp_conn_rr_response->measure_cpu = 1; - xti_tcp_conn_rr_response->cpu_rate = - calibrate_local_cpu(xti_tcp_conn_rr_request->cpu_rate); - } - - - - /* before we send the response back to the initiator, pull some of */ - /* the socket parms from the globals */ - xti_tcp_conn_rr_response->send_buf_size = lss_size; - xti_tcp_conn_rr_response->recv_buf_size = lsr_size; - xti_tcp_conn_rr_response->no_delay = loc_nodelay; - xti_tcp_conn_rr_response->so_rcvavoid = loc_rcvavoid; - xti_tcp_conn_rr_response->so_sndavoid = loc_sndavoid; - - send_response(); - - addrlen = sizeof(peeraddr_in); - - /* Now it's time to start receiving data on the connection. We will */ - /* first grab the apropriate counters and then start grabbing. */ - - cpu_start(xti_tcp_conn_rr_request->measure_cpu); - - /* The loop will exit when the sender does a shutdown, which will */ - /* return a length of zero */ - - if (xti_tcp_conn_rr_request->test_length > 0) { - times_up = 0; - trans_remaining = 0; - start_timer(xti_tcp_conn_rr_request->test_length + PAD_TIME); - } - else { - times_up = 1; - trans_remaining = xti_tcp_conn_rr_request->test_length * -1; - } - - trans_received = 0; - - while ((!times_up) || (trans_remaining > 0)) { - - /* accept a connection from the remote */ - if ((s_data=accept(s_listen, - (struct sockaddr *)&peeraddr_in, - &addrlen)) == INVALID_SOCKET) { - if (errno == EINTR) { - /* the timer popped */ - timed_out = 1; - break; - } - fprintf(where,"recv_xti_tcp_conn_rr: accept: errno = %d\n",errno); - fflush(where); - close(s_listen); - - exit(1); - } - - if (debug) { - fprintf(where,"recv_xti_tcp_conn_rr: accepted data connection.\n"); - fflush(where); - } - - temp_message_ptr = recv_message_ptr; - request_bytes_remaining = xti_tcp_conn_rr_request->request_size; - - /* receive the request from the other side */ - while(request_bytes_remaining > 0) { - if((request_bytes_recvd=recv(s_data, - temp_message_ptr, - request_bytes_remaining, - 0)) == SOCKET_ERROR) { - if (errno == EINTR) { - /* the timer popped */ - timed_out = 1; - break; - } - netperf_response.content.serv_errno = errno; - send_response(); - exit(1); - } - else { - request_bytes_remaining -= request_bytes_recvd; - temp_message_ptr += request_bytes_recvd; - } - } - - if (timed_out) { - /* we hit the end of the test based on time - lets */ - /* bail out of here now... */ - fprintf(where,"yo5\n"); - fflush(where); - break; - } - - /* Now, send the response to the remote */ - if((bytes_sent=send(s_data, - send_message_ptr, - xti_tcp_conn_rr_request->response_size, - 0)) == SOCKET_ERROR) { - if (errno == EINTR) { - /* the test timer has popped */ - timed_out = 1; - fprintf(where,"yo6\n"); - fflush(where); - break; - } - netperf_response.content.serv_errno = 99; - send_response(); - exit(1); - } - - trans_received++; - if (trans_remaining) { - trans_remaining--; - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_conn_rr: Transaction %d complete\n", - trans_received); - fflush(where); - } - - /* close the connection */ - close(s_data); - - } - - - /* The loop now exits due to timeout or transaction count being */ - /* reached */ - - cpu_stop(xti_tcp_conn_rr_request->measure_cpu,&elapsed_time); - - if (timed_out) { - /* we ended the test by time, which was at least 2 seconds */ - /* longer than we wanted to run. so, we want to subtract */ - /* PAD_TIME from the elapsed_time. */ - elapsed_time -= PAD_TIME; - } - /* send the results to the sender */ - - if (debug) { - fprintf(where, - "recv_xti_tcp_conn_rr: got %d transactions\n", - trans_received); - fflush(where); - } - - xti_tcp_conn_rr_results->bytes_received = (trans_received * - (xti_tcp_conn_rr_request->request_size + - xti_tcp_conn_rr_request->response_size)); - xti_tcp_conn_rr_results->trans_received = trans_received; - xti_tcp_conn_rr_results->elapsed_time = elapsed_time; - if (xti_tcp_conn_rr_request->measure_cpu) { - xti_tcp_conn_rr_results->cpu_util = calc_cpu_util(elapsed_time); - } - - if (debug) { - fprintf(where, - "recv_xti_tcp_conn_rr: test complete, sending results.\n"); - fflush(where); - } - - send_response(); - -} - -void -print_xti_usage() -{ - - fwrite(xti_usage, sizeof(char), strlen(xti_usage), stdout); - exit(1); - -} - -void -scan_xti_args(int argc, char *argv[]) -{ -#define XTI_ARGS "Dhm:M:r:s:S:Vw:W:X:" - extern int optind, opterrs; /* index of first unused arg */ - extern char *optarg; /* pointer to option string */ - - int c; - - char - arg1[BUFSIZ], /* argument holders */ - arg2[BUFSIZ]; - - if (no_control) { - fprintf(where, - "The XTI tests do not know how to run with no control connection\n"); - exit(-1); - } - - /* Go through all the command line arguments and break them */ - /* out. For those options that take two parms, specifying only */ - /* the first will set both to that value. Specifying only the */ - /* second will leave the first untouched. To change only the */ - /* first, use the form "first," (see the routine break_args.. */ - - while ((c= getopt(argc, argv, XTI_ARGS)) != EOF) { - switch (c) { - case '?': - case 'h': - print_xti_usage(); - exit(1); - case 'D': - /* set the TCP nodelay flag */ - loc_nodelay = 1; - rem_nodelay = 1; - break; - case 's': - /* set local socket sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - lss_size = convert(arg1); - if (arg2[0]) - lsr_size = convert(arg2); - break; - case 'S': - /* set remote socket sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - rss_size = convert(arg1); - if (arg2[0]) - rsr_size = convert(arg2); - break; - case 'r': - /* set the request/response sizes */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - req_size = convert(arg1); - if (arg2[0]) - rsp_size = convert(arg2); - break; - case 'm': - /* set the send size */ - send_size = convert(optarg); - break; - case 'M': - /* set the recv size */ - recv_size = convert(optarg); - break; - case 'W': - /* set the "width" of the user space data */ - /* buffer. This will be the number of */ - /* send_size buffers malloc'd in the */ - /* *_STREAM test. It may be enhanced to set */ - /* both send and receive "widths" but for now */ - /* it is just the sending *_STREAM. */ - send_width = convert(optarg); - break; - case 'V' : - /* we want to do copy avoidance and will set */ - /* it for everything, everywhere, if we really */ - /* can. of course, we don't know anything */ - /* about the remote... */ -#ifdef SO_SND_COPYAVOID - loc_sndavoid = 1; -#else - loc_sndavoid = 0; - printf("Local send copy avoidance not available.\n"); -#endif -#ifdef SO_RCV_COPYAVOID - loc_rcvavoid = 1; -#else - loc_rcvavoid = 0; - printf("Local recv copy avoidance not available.\n"); -#endif - rem_sndavoid = 1; - rem_rcvavoid = 1; - break; - case 'X': - /* set the xti device file name(s) */ - break_args(optarg,arg1,arg2); - if (arg1[0]) - strcpy(loc_xti_device,arg1); - if (arg2[0]) - strcpy(rem_xti_device,arg2); - break; - }; - } -} -#endif /* WANT_XTI */ diff --git a/nettest_xti.h b/nettest_xti.h deleted file mode 100644 index 3bf9968..0000000 --- a/nettest_xti.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 1995,2004 Hewlett-Packard Company - */ - - /* This file contains the test-specific definitions for netperf's BSD */ - /* sockets tests */ - -struct xti_tcp_stream_request_struct { - int send_buf_size; - int recv_buf_size; /* how big does the client want it - the */ - /* receive socket buffer that is */ - int receive_size; /* how many bytes do we want to receive at one */ - /* time? */ - int recv_alignment; /* what is the alignment of the receive */ - /* buffer? */ - int recv_offset; /* and at what offset from that alignment? */ - int no_delay; /* do we disable the nagle algorithm for send */ - /* coalescing? */ - int measure_cpu; /* does the client want server cpu utilization */ - /* measured? */ - float cpu_rate; /* do we know how fast the cpu is already? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid copies on */ - /* receives? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dirty_count; /* how many integers in the receive buffer */ - /* should be made dirty before calling recv? */ - int clean_count; /* how many integers should be read from the */ - /* recv buffer before calling recv? */ - int dev_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char xti_device[32]; /* the path to the dlpi device */ -}; - -struct xti_tcp_stream_response_struct { - int recv_buf_size; /* how big does the client want it */ - int receive_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct xti_tcp_stream_results_struct { - double bytes_received; - unsigned int recv_calls; - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs were there */ -}; - -struct xti_tcp_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dev_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char xti_device[32]; /* the path to the dlpi device */ -}; - -struct xti_tcp_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct xti_tcp_rr_results_struct { - unsigned int bytes_received; /* ignored initially */ - unsigned int recv_calls; /* ignored initially */ - unsigned int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs were there */ -}; - -struct xti_tcp_conn_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dev_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char xti_device[32]; /* the path to the dlpi device */ -}; - - -struct xti_tcp_conn_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct xti_tcp_conn_rr_results_struct { - unsigned int bytes_received; /* ignored initially */ - unsigned int recv_calls; /* ignored initially */ - unsigned int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs were there */ -}; - -struct xti_udp_stream_request_struct { - int recv_buf_size; - int message_size; - int recv_alignment; - int recv_offset; - int checksum_off; /* not used. left in for compatibility */ - int measure_cpu; - float cpu_rate; - int test_length; - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dev_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char xti_device[32]; /* the path to the dlpi device */ -}; - -struct xti_udp_stream_response_struct { - int recv_buf_size; - int send_buf_size; - int measure_cpu; - int test_length; - int data_port_number; - float cpu_rate; - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct xti_udp_stream_results_struct { - unsigned int messages_recvd; - unsigned int bytes_received; - float elapsed_time; - float cpu_util; - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs were there */ -}; - - -struct xti_udp_rr_request_struct { - int recv_buf_size; /* how big does the client want it */ - int send_buf_size; - int recv_alignment; - int recv_offset; - int send_alignment; - int send_offset; - int request_size; - int response_size; - int no_delay; - int measure_cpu; /* does the client want server cpu */ - float cpu_rate; /* do we know how fast the cpu is? */ - int test_length; /* how long is the test? */ - int so_rcvavoid; /* do we want the remote to avoid receive */ - /* copies? */ - int so_sndavoid; /* do we want the remote to avoid send copies? */ - int dev_name_len; /* the length of the device name string. this */ - /* is used to put it into the proper order on */ - /* @#$% byte-swapped boxes... */ - char xti_device[32]; /* the path to the dlpi device */ -}; - -struct xti_udp_rr_response_struct { - int recv_buf_size; /* how big does the client want it */ - int no_delay; - int measure_cpu; /* does the client want server cpu */ - int test_length; /* how long is the test? */ - int send_buf_size; - int data_port_number; /* connect to me here */ - float cpu_rate; /* could we measure */ - int so_rcvavoid; /* could the remote avoid receive copies? */ - int so_sndavoid; /* could the remote avoid send copies? */ -}; - -struct xti_udp_rr_results_struct { - unsigned int bytes_received; /* ignored initially */ - unsigned int recv_calls; /* ignored initially */ - unsigned int trans_received; /* not ignored */ - float elapsed_time; /* how long the test ran */ - float cpu_util; /* -1 if not measured */ - float serv_dem; /* -1 if not measured */ - int cpu_method; /* how was cpu util measured? */ - int num_cpus; /* how many CPUs were there */ -}; - -extern void send_xti_tcp_stream(char remote_host[]); - -extern void recv_xti_tcp_stream(); - -extern void send_xti_tcp_rr(char remote_host[]); - -extern void send_xti_udp_stream(char remote_host[]); - -extern void recv_xti_udp_stream(); - -extern void send_xti_udp_rr(char remote_host[]); - -extern void recv_xti_udp_rr(); - -extern void recv_xti_tcp_rr(); - -extern void send_xti_tcp_conn_rr(char remote_host[]); - -extern void recv_xti_tcp_conn_rr(); - -extern void scan_xti_args(int argc, char *argv[]); - - - - - - - - - - |