Code/Resource
Windows Develop
Linux-Unix program
Internet-Socket-Network
Web Server
Browser Client
Ftp Server
Ftp Client
Browser Plugins
Proxy Server
Email Server
Email Client
WEB Mail
Firewall-Security
Telnet Server
Telnet Client
ICQ-IM-Chat
Search Engine
Sniffer Package capture
Remote Control
xml-soap-webservice
P2P
WEB(ASP,PHP,...)
TCP/IP Stack
SNMP
Grid Computing
SilverLight
DNS
Cluster Service
Network Security
Communication-Mobile
Game Program
Editor
Multimedia program
Graph program
Compiler program
Compress-Decompress algrithms
Crypt_Decrypt algrithms
Mathimatics-Numerical algorithms
MultiLanguage
Disk/Storage
Java Develop
assembly language
Applications
Other systems
Database system
Embeded-SCM Develop
FlashMX/Flex
source in ebook
Delphi VCL
OS Develop
MiddleWare
MPI
MacOS develop
LabView
ELanguage
Software/Tools
E-Books
Artical/Document
nettest_bsd.c
Package: netperf-2.4.4.tar.gz [view]
Upload User: kvgkvg
Upload Date: 2015-05-07
Package Size: 1129k
Code Size: 385k
Category:
Linux-Unix program
Development Platform:
C/C++
- #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 %dn",
- __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 suspendn");
- 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 suspendn");
- 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 secondsn",
- 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 secondsn",
- 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 testsn
- -C Set TCP_CORK when availablen
- -D [L][,R] Set TCP_NODELAY locally and/or remotely (TCP_*)n
- -h Display this textn
- -H name,fam Use name (or IP) and family as target of data connectionn
- -L name,fam Use name (or IP) and family as source of data connectionn
- -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 locallyn
- -N Use the connected socket for UDP remotelyn
- -p min[,max] Set the min/max port numbers for TCP_CRR, TCP_TRRn
- -P local[,remote] Set the local/remote port for the data socketn
- -r req,[rsp] Set request/response sizes (TCP_RR, UDP_RR)n
- -s send[,recv] Set local socket send/recv buffer sizesn
- -S send[,recv] Set remote socket send/recv buffer sizesn
- -4 Use AF_INET (eg IPv4) on both ends of the data connn
- -6 Use AF_INET6 (eg IPv6) on both ends of the data connn
- 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 thatn
- value, specifying a value with a leading comma will set just the secondn
- parm, a value with a trailing comma will set just the first. To setn
- each parm to unique values, specify both and separate them with an
- 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 %dn",
- 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%xn",
- 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_AGAINn");
- 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,
- "ntgetaddrinfo returned %d %sn",
- 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 %dn",
- 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 %dn",
- 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 notn");
- fprintf(where,
- "match the requested type. Please contact your vendor forn");
- 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 then");
- fprintf(where,
- "requested protocol. Please contact your vendor forn");
- 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 infon");
- 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 %un",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 %un",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 %sn",
- 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 %dn",
- 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 %dn",
- 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 %dn",
- errno);
- fprintf(where," port: %dn",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 %dn",
- 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_addressn");
- 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] = '';
- 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] = '';
- 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 nn";
- char *tput_fmt_0 =
- "%7.2f %sn";
- char *tput_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f %sn";
- char *cpu_title = "
- Recv Send Send Utilization Service Demandn
- Socket Socket Message Elapsed Send Recv Send Recvn
- Size Size Size Time Throughput local remote local remoten
- bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KBnn";
- char *cpu_fmt_0 =
- "%6.3f %c %sn";
- char *cpu_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f %sn";
- char *ksink_fmt = "n
- Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvsn
- Local Remote Local Remote Xfered Per Pern
- Send Recv Send Recv Send (avg) Recv (avg)n
- %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6dn";
- char *ksink_fmt2 = "n
- Maximumn
- Segmentn
- Size (bytes)n
- %6dn";
- 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 testn");
- }
- 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 %dn",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 obtainedn");
- }
- 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,"nnHistogram 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 nn";
- char *tput_fmt_0 =
- "%7.2f %sn";
- char *tput_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f %s n";
- char *cpu_title = "
- Recv Send Send Utilization Service Demandn
- Socket Socket Message Elapsed Send Recv Send Recvn
- Size Size Size Time Throughput local remote local remoten
- bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KBnn";
- char *cpu_fmt_0 =
- "%6.3f %c %sn";
- char *cpu_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f %sn";
- char *ksink_fmt = "n
- Alignment Offset %-8.8s %-8.8s Recvs %-8.8s Sendsn
- Local Remote Local Remote Xfered Per Pern
- Recv Send Recv Send Recv (avg) Send (avg)n
- %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6dn";
- char *ksink_fmt2 = "n
- Maximumn
- Segmentn
- Size (bytes)n
- %6dn";
- 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 testn");
- }
- 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 timedn");
- 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 %dn",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 obtainedn");
- }
- 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,"nnHistogram 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 nn";
- char *tput_fmt_0 =
- "%7.2fn";
- char *tput_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f n";
- char *cpu_title = "
- Recv Send Send Utilization Service Demandn
- Socket Socket Message Elapsed Send Recv Send Recvn
- Size Size Size Time Throughput local remote local remoten
- bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KBnn";
- char *cpu_fmt_0 =
- "%6.3f %cn";
- char *cpu_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3fn";
- char *ksink_fmt = "n
- Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvsn
- Local Remote Local Remote Xfered Per Pern
- Send Recv Send Recv Send (avg) Recv (avg)n
- %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6dn";
- char *ksink_fmt2 = "n
- Maximumn
- Segmentn
- Size (bytes)n
- %6dn";
- 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=%dn", 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 testn");
- }
- 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 */