1 #ifndef lint
2 char nettest_id[]="\
3 @(#)nettest_bsd.c (c) Copyright 1993-2004 Hewlett-Packard Co. Version 2.4.3";
4 #endif /* lint */
5
6
7 /****************************************************************/
8 /* */
9 /* nettest_bsd.c */
10 /* */
11 /* the BSD sockets parsing routine... */
12 /* ...with the addition of Windows NT, this is now also */
13 /* a Winsock test... sigh :) */
14 /* */
15 /* scan_sockets_args() */
16 /* */
17 /* the actual test routines... */
18 /* */
19 /* send_tcp_stream() perform a tcp stream test */
20 /* recv_tcp_stream() */
21 /* send_tcp_maerts() perform a tcp stream test */
22 /* recv_tcp_maerts() in the other direction */
23 /* send_tcp_rr() perform a tcp request/response */
24 /* recv_tcp_rr() */
25 /* send_tcp_conn_rr() an RR test including connect */
26 /* recv_tcp_conn_rr() */
27 /* send_tcp_cc() a connect/disconnect test with */
28 /* recv_tcp_cc() no RR */
29 /* send_udp_stream() perform a udp stream test */
30 /* recv_udp_stream() */
31 /* send_udp_rr() perform a udp request/response */
32 /* recv_udp_rr() */
33 /* loc_cpu_rate() determine the local cpu maxrate */
34 /* rem_cpu_rate() find the remote cpu maxrate */
35 /* */
36 /****************************************************************/
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <stdio.h>
43 #if HAVE_SYS_TYPES_H
44 # include <sys/types.h>
45 #endif
46 #if HAVE_SYS_STAT_H
47 # include <sys/stat.h>
48 #endif
49 #if STDC_HEADERS
50 # include <stdlib.h>
51 # include <stddef.h>
52 #else
53 # if HAVE_STDLIB_H
54 # include <stdlib.h>
55 # endif
56 #endif
57 #if HAVE_STRING_H
58 # if !STDC_HEADERS && HAVE_MEMORY_H
59 # include <memory.h>
60 # endif
61 # include <string.h>
62 #endif
63 #if HAVE_STRINGS_H
64 # include <strings.h>
65 #endif
66 #if HAVE_INTTYPES_H
67 # include <inttypes.h>
68 #else
69 # if HAVE_STDINT_H
70 # include <stdint.h>
71 # endif
72 #endif
73 #if HAVE_UNISTD_H
74 # include <unistd.h>
75 #endif
76
77 #include <fcntl.h>
78 #ifndef WIN32
79 #include <errno.h>
80 #include <signal.h>
81 #endif
82
83 #if TIME_WITH_SYS_TIME
84 # include <sys/time.h>
85 # include <time.h>
86 #else
87 # if HAVE_SYS_TIME_H
88 # include <sys/time.h>
89 # else
90 # include <time.h>
91 # endif
92 #endif
93
94 #ifdef NOSTDLIBH
95 #include <malloc.h>
96 #endif /* NOSTDLIBH */
97
98 #ifndef WIN32
99 #if !defined(__VMS)
100 #include <sys/ipc.h>
101 #endif /* !defined(__VMS) */
102 #include <sys/socket.h>
103 #include <netinet/in.h>
104 #include <netinet/tcp.h>
105 #include <arpa/inet.h>
106 #include <netdb.h>
107 #else /* WIN32 */
108 #include <process.h>
109 #define netperf_socklen_t socklen_t
110 #include <winsock2.h>
111
112 /* while it is unlikely that anyone running Windows 2000 or NT 4 is
113 going to be trying to compile this, if they are they will want to
114 define DONT_IPV6 in the sources file */
115 #ifndef DONT_IPV6
116 #include <ws2tcpip.h>
117 #endif
118 #include <windows.h>
119
120 #define sleep(x) Sleep((x)*1000)
121
122 #define __func__ __FUNCTION__
123 #endif /* WIN32 */
124
125 /* We don't want to use bare constants in the shutdown() call. In the
126 extremely unlikely event that SHUT_WR isn't defined, we will define
127 it to the value we used to be passing to shutdown() anyway. raj
128 2007-02-08 */
129 #if !defined(SHUT_WR)
130 #define SHUT_WR 1
131 #endif
132
133 #if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
134 # include "missing/getaddrinfo.h"
135 #endif
136
137 #include "netlib.h"
138 #include "netsh.h"
139 #include "nettest_bsd.h"
140
141 #if defined(WANT_HISTOGRAM) || defined(WANT_DEMO)
142 #include "hist.h"
143 #endif /* WANT_HISTOGRAM */
144
145 /* make first_burst_size unconditional so we can use it easily enough
146 when calculating transaction latency for the TCP_RR test. raj
147 2007-06-08 */
148 int first_burst_size=0;
149
150 #if defined(HAVE_SENDFILE) && (defined(__linux) || defined(__sun__))
151 #include <sys/sendfile.h>
152 #endif /* HAVE_SENDFILE && (__linux || __sun__) */
153
154
155
156 /* these variables are specific to the BSD sockets tests, but can
157 * be used elsewhere if needed. They are externed through nettest_bsd.h
158 */
159
160 int
161 rss_size_req = -1, /* requested remote socket send buffer size */
162 rsr_size_req = -1, /* requested remote socket recv buffer size */
163 rss_size, /* remote socket send buffer size */
164 rsr_size, /* remote socket recv buffer size */
165 lss_size_req = -1, /* requested local socket send buffer size */
166 lsr_size_req = -1, /* requested local socket recv buffer size */
167 lss_size, /* local socket send buffer size */
168 lsr_size, /* local socket recv buffer size */
169 req_size = 1, /* request size */
170 rsp_size = 1, /* response size */
171 send_size, /* how big are individual sends */
172 recv_size; /* how big are individual receives */
173
174 static int confidence_iteration;
175 static char local_cpu_method;
176 static char remote_cpu_method;
177
178 /* these will control the width of port numbers we try to use in the */
179 /* TCP_CRR and/or TCP_TRR tests. raj 3/95 */
180 static int client_port_min = 5000;
181 static int client_port_max = 65535;
182
183 /* different options for the sockets */
184
185 int
186 loc_nodelay, /* don't/do use NODELAY locally */
187 rem_nodelay, /* don't/do use NODELAY remotely */
188 #ifdef TCP_CORK
189 loc_tcpcork=0, /* don't/do use TCP_CORK locally */
190 rem_tcpcork=0, /* don't/do use TCP_CORK remotely */
191 #endif /* TCP_CORK */
192 loc_sndavoid, /* avoid send copies locally */
193 loc_rcvavoid, /* avoid recv copies locally */
194 rem_sndavoid, /* avoid send copies remotely */
195 rem_rcvavoid, /* avoid recv_copies remotely */
196 local_connected = 0, /* local socket type, connected/non-connected */
197 remote_connected = 0; /* remote socket type, connected/non-connected */
198
199 #ifdef WANT_HISTOGRAM
200 #ifdef HAVE_GETHRTIME
201 static hrtime_t time_one;
202 static hrtime_t time_two;
203 #elif HAVE_GET_HRT
204 #include "hrt.h"
205 static hrt_t time_one;
206 static hrt_t time_two;
207 #elif defined(WIN32)
208 static LARGE_INTEGER time_one;
209 static LARGE_INTEGER time_two;
210 #else
211 static struct timeval time_one;
212 static struct timeval time_two;
213 #endif /* HAVE_GETHRTIME */
214 static HIST time_hist;
215 #endif /* WANT_HISTOGRAM */
216
217 #ifdef WANT_INTERVALS
218 int interval_count;
219 #ifndef WANT_SPIN
220 sigset_t signal_set;
221 #define INTERVALS_INIT() \
222 if (interval_burst) { \
223 /* zero means that we never pause, so we never should need the \
224 interval timer. we used to use it for demo mode, but we deal \
225 with that with a variant on watching the clock rather than \
226 waiting for a timer. raj 2006-02-06 */ \
227 start_itimer(interval_wate); \
228 } \
229 interval_count = interval_burst; \
230 /* get the signal set for the call to sigsuspend */ \
231 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { \
232 fprintf(where, \
233 "%s: unable to get sigmask errno %d\n", \
234 __func__, \
235 errno); \
236 fflush(where); \
237 exit(1); \
238 }
239
240 #define INTERVALS_WAIT() \
241 /* in this case, the interval count is the count-down couter \
242 to decide to sleep for a little bit */ \
243 if ((interval_burst) && (--interval_count == 0)) { \
244 /* call sigsuspend and wait for the interval timer to get us \
245 out */ \
246 if (debug > 1) { \
247 fprintf(where,"about to suspend\n"); \
248 fflush(where); \
249 } \
250 if (sigsuspend(&signal_set) == EFAULT) { \
251 fprintf(where, \
252 "%s: fault with sigsuspend.\n", \
253 __func__); \
254 fflush(where); \
255 exit(1); \
256 } \
257 interval_count = interval_burst; \
258 }
259 #else
260 /* first out timestamp */
261 #ifdef HAVE_GETHRTIME
262 static hrtime_t intvl_one;
263 static hrtime_t intvl_two;
264 static hrtime_t *intvl_one_ptr = &intvl_one;
265 static hrtime_t *intvl_two_ptr = &intvl_two;
266 static hrtime_t *temp_intvl_ptr = &intvl_one;
267 #elif defined(WIN32)
268 static LARGE_INTEGER intvl_one;
269 static LARGE_INTEGER intvl_two;
270 static LARGE_INTEGER *intvl_one_ptr = &intvl_one;
271 static LARGE_INTEGER *intvl_two_ptr = &intvl_two;
272 static LARGE_INTEGER *temp_intvl_ptr = &intvl_one;
273 #else
274 static struct timeval intvl_one;
275 static struct timeval intvl_two;
276 static struct timeval *intvl_one_ptr = &intvl_one;
277 static struct timeval *intvl_two_ptr = &intvl_two;
278 static struct timeval *temp_intvl_ptr = &intvl_one;
279 #endif
280
281 #define INTERVALS_INIT() \
282 if (interval_burst) { \
283 HIST_timestamp(intvl_one_ptr); \
284 } \
285 interval_count = interval_burst; \
286
287 #define INTERVALS_WAIT() \
288 /* in this case, the interval count is the count-down couter \
289 to decide to sleep for a little bit */ \
290 if ((interval_burst) && (--interval_count == 0)) { \
291 /* call sigsuspend and wait for the interval timer to get us \
292 out */ \
293 if (debug > 1) { \
294 fprintf(where,"about to spin suspend\n"); \
295 fflush(where); \
296 } \
297 HIST_timestamp(intvl_two_ptr); \
298 while(delta_micro(intvl_one_ptr,intvl_two_ptr) < interval_usecs) { \
299 HIST_timestamp(intvl_two_ptr); \
300 } \
301 temp_intvl_ptr = intvl_one_ptr; \
302 intvl_one_ptr = intvl_two_ptr; \
303 intvl_two_ptr = temp_intvl_ptr; \
304 interval_count = interval_burst; \
305 }
306 #endif
307 #endif
308
309 #ifdef WANT_DEMO
310 #ifdef HAVE_GETHRTIME
311 static hrtime_t demo_one;
312 static hrtime_t demo_two;
313 static hrtime_t *demo_one_ptr = &demo_one;
314 static hrtime_t *demo_two_ptr = &demo_two;
315 static hrtime_t *temp_demo_ptr = &demo_one;
316 #elif defined(WIN32)
317 static LARGE_INTEGER demo_one;
318 static LARGE_INTEGER demo_two;
319 static LARGE_INTEGER *demo_one_ptr = &demo_one;
320 static LARGE_INTEGER *demo_two_ptr = &demo_two;
321 static LARGE_INTEGER *temp_demo_ptr = &demo_one;
322 #else
323 static struct timeval demo_one;
324 static struct timeval demo_two;
325 static struct timeval *demo_one_ptr = &demo_one;
326 static struct timeval *demo_two_ptr = &demo_two;
327 static struct timeval *temp_demo_ptr = &demo_one;
328 #endif
329
330 /* for a _STREAM test, "a" should be lss_size and "b" should be
331 rsr_size. for a _MAERTS test, "a" should be lsr_size and "b" should
332 be rss_size. raj 2005-04-06 */
333 #define DEMO_STREAM_SETUP(a,b) \
334 if ((demo_mode) && (demo_units == 0)) { \
335 /* take our default value of demo_units to be the larger of \
336 twice the remote's SO_RCVBUF or twice our SO_SNDBUF */ \
337 if (a > b) { \
338 demo_units = 2*a; \
339 } \
340 else { \
341 demo_units = 2*b; \
342 } \
343 }
344
345 #define DEMO_STREAM_INTERVAL(units) \
346 if (demo_mode) { \
347 double actual_interval; \
348 units_this_tick += units; \
349 if (units_this_tick >= demo_units) { \
350 /* time to possibly update demo_units and maybe output an \
351 interim result */ \
352 HIST_timestamp(demo_two_ptr); \
353 actual_interval = delta_micro(demo_one_ptr,demo_two_ptr); \
354 /* we always want to fine-tune demo_units here whether we \
355 emit an interim result or not. if we are short, this \
356 will lengthen demo_units. if we are long, this will \
357 shorten it */ \
358 demo_units = demo_units * (demo_interval / actual_interval); \
359 if (actual_interval >= demo_interval) { \
360 /* time to emit an interim result */ \
361 fprintf(where, \
362 "Interim result: %7.2f %s/s over %.2f seconds\n", \
363 calc_thruput_interval(units_this_tick, \
364 actual_interval/1000000.0), \
365 format_units(), \
366 actual_interval/1000000.0); \
367 fflush(where); \
368 units_this_tick = 0.0; \
369 /* now get a new starting timestamp. we could be clever \
370 and swap pointers - the math we do probably does not \
371 take all that long, but for now this will suffice */ \
372 temp_demo_ptr = demo_one_ptr; \
373 demo_one_ptr = demo_two_ptr; \
374 demo_two_ptr = temp_demo_ptr; \
375 } \
376 } \
377 }
378
379 #define DEMO_RR_SETUP(a) \
380 if ((demo_mode) && (demo_units == 0)) { \
381 /* take whatever we are given */ \
382 demo_units = a; \
383 }
384
385 #define DEMO_RR_INTERVAL(units) \
386 if (demo_mode) { \
387 double actual_interval; \
388 units_this_tick += units; \
389 if (units_this_tick >= demo_units) { \
390 /* time to possibly update demo_units and maybe output an \
391 interim result */ \
392 HIST_timestamp(demo_two_ptr); \
393 actual_interval = delta_micro(demo_one_ptr,demo_two_ptr); \
394 /* we always want to fine-tune demo_units here whether we \
395 emit an interim result or not. if we are short, this \
396 will lengthen demo_units. if we are long, this will \
397 shorten it */ \
398 demo_units = demo_units * (demo_interval / actual_interval); \
399 if (actual_interval >= demo_interval) { \
400 /* time to emit an interim result */ \
401 fprintf(where, \
402 "Interim result: %.2f %s/s over %.2f seconds\n", \
403 units_this_tick / (actual_interval/1000000.0), \
404 "Trans", \
405 actual_interval/1000000.0); \
406 units_this_tick = 0.0; \
407 /* now get a new starting timestamp. we could be clever \
408 and swap pointers - the math we do probably does not \
409 take all that long, but for now this will suffice */ \
410 temp_demo_ptr = demo_one_ptr; \
411 demo_one_ptr = demo_two_ptr; \
412 demo_two_ptr = temp_demo_ptr; \
413 } \
414 } \
415 }
416 #endif
417
418 char sockets_usage[] = "\n\
419 Usage: netperf [global options] -- [test options] \n\
420 \n\
421 TCP/UDP BSD Sockets Test Options:\n\
422 -b number Send number requests at start of _RR tests\n\
423 -C Set TCP_CORK when available\n\
424 -D [L][,R] Set TCP_NODELAY locally and/or remotely (TCP_*)\n\
425 -h Display this text\n\
426 -H name,fam Use name (or IP) and family as target of data connection\n\
427 -L name,fam Use name (or IP) and family as source of data connection\n\
428 -m bytes Set the send size (TCP_STREAM, UDP_STREAM)\n\
429 -M bytes Set the recv size (TCP_STREAM, UDP_STREAM)\n\
430 -n Use the connected socket for UDP locally\n\
431 -N Use the connected socket for UDP remotely\n\
432 -p min[,max] Set the min/max port numbers for TCP_CRR, TCP_TRR\n\
433 -P local[,remote] Set the local/remote port for the data socket\n\
434 -r req,[rsp] Set request/response sizes (TCP_RR, UDP_RR)\n\
435 -s send[,recv] Set local socket send/recv buffer sizes\n\
436 -S send[,recv] Set remote socket send/recv buffer sizes\n\
437 -4 Use AF_INET (eg IPv4) on both ends of the data conn\n\
438 -6 Use AF_INET6 (eg IPv6) on both ends of the data conn\n\
439 \n\
440 For those options taking two parms, at least one must be specified;\n\
441 specifying one value without a comma will set both parms to that\n\
442 value, specifying a value with a leading comma will set just the second\n\
443 parm, a value with a trailing comma will set just the first. To set\n\
444 each parm to unique values, specify both and separate them with a\n\
445 comma.\n";
446
447
448
449 /* these routines convert between the AF address space and the NF
450 address space since the numeric values of AF_mumble are not the
451 same across the platforms. raj 2005-02-08 */
452
453 int
nf_to_af(int nf)454 nf_to_af(int nf) {
455 switch(nf) {
456 case NF_INET:
457 return AF_INET;
458 break;
459 case NF_UNSPEC:
460 return AF_UNSPEC;
461 break;
462 case NF_INET6:
463 #if defined(AF_INET6)
464 return AF_INET6;
465 #else
466 return AF_UNSPEC;
467 #endif
468 break;
469 default:
470 return AF_UNSPEC;
471 break;
472 }
473 }
474
475 int
af_to_nf(int af)476 af_to_nf(int af) {
477
478 switch(af) {
479 case AF_INET:
480 return NF_INET;
481 break;
482 case AF_UNSPEC:
483 return NF_UNSPEC;
484 break;
485 #if defined(AF_INET6)
486 case AF_INET6:
487 return NF_INET6;
488 break;
489 #endif
490 default:
491 return NF_UNSPEC;
492 break;
493 }
494 }
495
496
497 /* This routine is intended to retrieve interesting aspects of tcp */
498 /* for the data connection. at first, it attempts to retrieve the */
499 /* maximum segment size. later, it might be modified to retrieve */
500 /* other information, but it must be information that can be */
501 /* retrieved quickly as it is called during the timing of the test. */
502 /* for that reason, a second routine may be created that can be */
503 /* called outside of the timing loop */
504 static
505 void
get_tcp_info(SOCKET socket,int * mss)506 get_tcp_info(SOCKET socket, int *mss)
507 {
508
509 #ifdef TCP_MAXSEG
510 netperf_socklen_t sock_opt_len;
511
512 sock_opt_len = sizeof(netperf_socklen_t);
513 if (getsockopt(socket,
514 getprotobyname("tcp")->p_proto,
515 TCP_MAXSEG,
516 (char *)mss,
517 &sock_opt_len) == SOCKET_ERROR) {
518 fprintf(where,
519 "netperf: get_tcp_info: getsockopt TCP_MAXSEG: errno %d\n",
520 errno);
521 fflush(where);
522 *mss = -1;
523 }
524 #else
525 *mss = -1;
526 #endif /* TCP_MAXSEG */
527 }
528
529
530 /* return a pointer to a completed addrinfo chain - prefer
531 data_address to controlhost and utilize the specified address
532 family */
533
534 struct addrinfo *
complete_addrinfo(char * controlhost,char * data_address,char * port,int family,int type,int protocol,int flags)535 complete_addrinfo(char *controlhost, char *data_address, char *port, int family, int type, int protocol, int flags)
536 {
537 struct addrinfo hints;
538 struct addrinfo *res;
539 struct addrinfo *temp_res;
540
541 #define CHANGED_SOCK_TYPE 0x1
542 #define CHANGED_PROTOCOL 0x2
543 #define CHANGED_SCTP 0x4
544 int change_info = 0;
545 static int change_warning_displayed = 0;
546
547 int count = 0;
548 int error = 0;
549
550 char *hostname;
551
552 /* take data-address over controlhost */
553 if (data_address)
554 hostname = data_address;
555 else
556 hostname = controlhost;
557
558 if (debug) {
559 fprintf(where,
560 "complete_addrinfo using hostname %s port %s family %s type %s prot %s flags 0x%x\n",
561 hostname,
562 port,
563 inet_ftos(family),
564 inet_ttos(type),
565 inet_ptos(protocol),
566 flags);
567 fflush(where);
568 }
569
570 memset(&hints, 0, sizeof(hints));
571 hints.ai_family = family;
572 hints.ai_socktype = type;
573 hints.ai_protocol = protocol;
574 hints.ai_flags = flags|AI_CANONNAME;
575
576 count = 0;
577 do {
578 error = getaddrinfo((char *)hostname,
579 (char *)port,
580 &hints,
581 &res);
582 count += 1;
583 if (error == EAI_AGAIN) {
584 if (debug) {
585 fprintf(where,"Sleeping on getaddrinfo EAI_AGAIN\n");
586 fflush(where);
587 }
588 sleep(1);
589 }
590 /* while you see this kludge first, it is actually the second, the
591 first being the one for Solaris below. The need for this kludge
592 came after implementing the Solaris broken getaddrinfo kludge -
593 now we see a kludge in Linux getaddrinfo where if it is given
594 SOCK_STREAM and IPPROTO_SCTP it barfs with a -7
595 EAI_SOCKTYPE. so, we check if the error was EAI_SOCKTYPE and if
596 we were asking for IPPROTO_SCTP and if so, kludge, again... raj
597 2008-10-13 */
598 #ifdef WANT_SCTP
599 if (EAI_SOCKTYPE == error
600 #ifdef EAI_BADHINTS
601 || EAI_BADHINTS == error
602 #endif
603 ) {
604 /* we ass-u-me this is the Linux getaddrinfo bug, clear the
605 hints.ai_protocol field, and set some state "remembering"
606 that we did this so the code for the Solaris kludge can do
607 the fix-up for us. also flip error over to EAI_AGAIN and
608 make sure we don't "count" this time around the loop. */
609 hints.ai_protocol = 0;
610 error = EAI_AGAIN;
611 count -= 1;
612 change_info |= CHANGED_SCTP;
613 }
614 #endif
615 } while ((error == EAI_AGAIN) && (count <= 5));
616
617 if (error) {
618 fprintf(where,
619 "complete_addrinfo: could not resolve '%s' port '%s' af %d",
620 hostname,
621 port,
622 family);
623 fprintf(where,
624 "\n\tgetaddrinfo returned %d %s\n",
625 error,
626 gai_strerror(error));
627 fflush(where);
628 exit(-1);
629 }
630
631 /* there exists at least one platform - Solaris 10 - that does not
632 seem to completely honor the ai_protocol and/or ai_socktype one
633 sets in the hints parm to the getaddrinfo call. so, we need to
634 walk the list of entries returned and if either of those do not
635 match what we asked for, we need to go ahead and set them
636 "correctly" this is based in part on some earlier SCTP-only code
637 from previous revisions. raj 2006-10-09 */
638
639 temp_res = res;
640
641 while (temp_res) {
642
643 if ((type) &&
644 (temp_res->ai_socktype != type)) {
645 change_info |= CHANGED_SOCK_TYPE;
646 if (debug) {
647 fprintf(where,
648 "WARNING! Changed bogus getaddrinfo socket type %d to %d\n",
649 temp_res->ai_socktype,
650 type);
651 fflush(where);
652 }
653 temp_res->ai_socktype = type;
654 }
655
656 if ((protocol) &&
657 (temp_res->ai_protocol != protocol)) {
658 change_info |= CHANGED_PROTOCOL;
659 if (debug) {
660 fprintf(where,
661 "WARNING! Changed bogus getaddrinfo protocol %d to %d\n",
662 temp_res->ai_protocol,
663 protocol);
664 fflush(where);
665 }
666 temp_res->ai_protocol = protocol;
667 }
668 temp_res = temp_res->ai_next;
669 }
670
671 if ((change_info & CHANGED_SOCK_TYPE) &&
672 !(change_warning_displayed & CHANGED_SOCK_TYPE)) {
673 change_warning_displayed |= CHANGED_SOCK_TYPE;
674 fprintf(where,
675 "WARNING! getaddrinfo returned a socket type which did not\n");
676 fprintf(where,
677 "match the requested type. Please contact your vendor for\n");
678 fprintf(where,
679 "a fix to this bug in getaddrinfo()\n");
680 fflush(where);
681 }
682
683 /* if we dropped the protocol hint, it would be for a protocol that
684 getaddrinfo() wasn't supporting yet, not for the bug that it took
685 our hint and still returned zero. raj 2006-10-16 */
686 if ((change_info & CHANGED_PROTOCOL) &&
687 !(change_warning_displayed & CHANGED_PROTOCOL) &&
688 (hints.ai_protocol != 0)) {
689 change_warning_displayed |= CHANGED_PROTOCOL;
690 fprintf(where,
691 "WARNING! getaddrinfo returned a protocol other than the\n");
692 fprintf(where,
693 "requested protocol. Please contact your vendor for\n");
694 fprintf(where,
695 "a fix to this bug in getaddrinfo()\n");
696 fflush(where);
697 }
698
699 if ((change_info & CHANGED_SCTP) &&
700 !(change_warning_displayed & CHANGED_SCTP)) {
701 change_warning_displayed |= CHANGED_SCTP;
702 fprintf(where,
703 "WARNING! getaddrinfo on this platform does not accept IPPROTO_SCTP!\n");
704 fprintf(where,
705 "Please contact your vendor for a fix to this bug in getaddrinfo().\n");
706 fflush(where);
707 }
708
709
710 if (debug) {
711 dump_addrinfo(where, res, hostname, port, family);
712 }
713
714 return(res);
715 }
716
717 void
complete_addrinfos(struct addrinfo ** remote,struct addrinfo ** local,char remote_host[],int type,int protocol,int flags)718 complete_addrinfos(struct addrinfo **remote,struct addrinfo **local, char remote_host[], int type, int protocol, int flags) {
719
720 *remote = complete_addrinfo(remote_host,
721 remote_data_address,
722 remote_data_port,
723 remote_data_family,
724 type,
725 protocol,
726 flags);
727
728 /* OK, if the user has not specified a local data endpoint address
729 (test-specific -L), pick the local data endpoint address based on
730 the remote data family info (test-specific -H or -4 or -6
731 option). if the user has not specified remote data addressing
732 info (test-specific -H, -4 -6) pick something based on the local
733 control connection address (ie the global -L option). */
734
735 if (NULL == local_data_address) {
736 local_data_address = malloc(HOSTNAMESIZE);
737 if (NULL == remote_data_address) {
738 if (debug) {
739 fprintf(where,
740 "local_data_address not set, using local_host_name of '%s'\n",
741 local_host_name);
742 fflush(where);
743 }
744 strcpy(local_data_address,local_host_name);
745 }
746 else {
747 if (debug) {
748 fprintf(where,
749 "local_data_address not set, using address family info\n");
750 fflush(where);
751 }
752 /* by default, use 0.0.0.0 - assume IPv4 */
753 strcpy(local_data_address,"0.0.0.0");
754 #if defined(AF_INET6)
755 if ((AF_INET6 == local_data_family) ||
756 ((AF_UNSPEC == local_data_family) &&
757 (AF_INET6 == remote_data_family)) ||
758 ((AF_UNSPEC == local_data_family) &&
759 (AF_INET6 == (*remote)->ai_family))) {
760 strcpy(local_data_address,"::0");
761 }
762 #endif
763 }
764 }
765
766 *local = complete_addrinfo("what to put here?",
767 local_data_address,
768 local_data_port,
769 local_data_family,
770 type,
771 protocol,
772 flags|AI_PASSIVE);
773
774 }
775
776 void
set_hostname_and_port(char * hostname,char * portstr,int family,int port)777 set_hostname_and_port(char *hostname, char *portstr, int family, int port)
778 {
779 strcpy(hostname,"0.0.0.0");
780 #if defined AF_INET6
781 if (AF_INET6 == family) {
782 strcpy(hostname,"::0");
783 }
784 #endif
785
786 sprintf(portstr, "%u", port);
787
788 }
789
790 static unsigned short
get_port_number(struct addrinfo * res)791 get_port_number(struct addrinfo *res)
792 {
793 switch(res->ai_family) {
794 case AF_INET: {
795 struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr;
796 return(ntohs(foo->sin_port));
797 break;
798 }
799 #if defined(AF_INET6)
800 case AF_INET6: {
801 struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr;
802 return(ntohs(foo->sin6_port));
803 break;
804 }
805 #endif
806 default:
807 fprintf(where,
808 "Unexpected Address Family of %u\n",res->ai_family);
809 fflush(where);
810 exit(-1);
811 }
812 }
813
814 /* this routine will set the port number of the sockaddr in the
815 addrinfo to the specified value, based on the address family */
816 void
set_port_number(struct addrinfo * res,unsigned short port)817 set_port_number(struct addrinfo *res, unsigned short port)
818 {
819 switch(res->ai_family) {
820 case AF_INET: {
821 struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr;
822 foo->sin_port = htons(port);
823 break;
824 }
825 #if defined(AF_INET6)
826 case AF_INET6: {
827 struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr;
828 foo->sin6_port = htons(port);
829 break;
830 }
831 #endif
832 default:
833 fprintf(where,
834 "Unexpected Address Family of %u\n",res->ai_family);
835 fflush(where);
836 exit(-1);
837 }
838 }
839
840
841
842 /* This routine will create a data (listen) socket with the
843 apropriate options set and return it to the caller. this replaces
844 all the duplicate code in each of the test routines and should help
845 make things a little easier to understand. since this routine can be
846 called by either the netperf or netserver programs, all output
847 should be directed towards "where." family is generally AF_INET and
848 type will be either SOCK_STREAM or SOCK_DGRAM. This routine will
849 also be used by the "SCTP" tests, hence the slightly strange-looking
850 SCTP stuff in the classic bsd sockets test file... vlad/raj
851 2005-03-15 */
852
853 SOCKET
create_data_socket(struct addrinfo * res)854 create_data_socket(struct addrinfo *res)
855 {
856
857 SOCKET temp_socket;
858 int one;
859 int on = 1;
860
861
862 /*set up the data socket */
863 temp_socket = socket(res->ai_family,
864 res->ai_socktype,
865 res->ai_protocol);
866
867 if (temp_socket == INVALID_SOCKET){
868 fprintf(where,
869 "netperf: create_data_socket: socket: errno %d fam %s type %s prot %s errmsg %s\n",
870 errno,
871 inet_ftos(res->ai_family),
872 inet_ttos(res->ai_socktype),
873 inet_ptos(res->ai_protocol),
874 strerror(errno));
875 fflush(where);
876 exit(1);
877 }
878
879 if (debug) {
880 fprintf(where,"create_data_socket: socket %d obtained...\n",temp_socket);
881 fflush(where);
882 }
883
884 /* Modify the local socket size. The reason we alter the send buffer
885 size here rather than when the connection is made is to take care
886 of decreases in buffer size. Decreasing the window size after
887 connection establishment is a TCP no-no. Also, by setting the
888 buffer (window) size before the connection is established, we can
889 control the TCP MSS (segment size). The MSS is never (well, should
890 never be) more that 1/2 the minimum receive buffer size at each
891 half of the connection. This is why we are altering the receive
892 buffer size on the sending size of a unidirectional transfer. If
893 the user has not requested that the socket buffers be altered, we
894 will try to find-out what their values are. If we cannot touch the
895 socket buffer in any way, we will set the values to -1 to indicate
896 that. */
897
898 /* all the oogy nitty gritty stuff moved from here into the routine
899 being called below, per patches from davidm to workaround the bug
900 in Linux getsockopt(). raj 2004-06-15 */
901 set_sock_buffer (temp_socket, SEND_BUFFER, lss_size_req, &lss_size);
902 set_sock_buffer (temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size);
903
904 /* now, we may wish to enable the copy avoidance features on the */
905 /* local system. of course, this may not be possible... */
906
907 #ifdef SO_RCV_COPYAVOID
908 if (loc_rcvavoid) {
909 if (setsockopt(temp_socket,
910 SOL_SOCKET,
911 SO_RCV_COPYAVOID,
912 (const char *)&loc_rcvavoid,
913 sizeof(int)) == SOCKET_ERROR) {
914 fprintf(where,
915 "netperf: create_data_socket: Could not enable receive copy avoidance");
916 fflush(where);
917 loc_rcvavoid = 0;
918 }
919 }
920 #else
921 /* it wasn't compiled in... */
922 loc_rcvavoid = 0;
923 #endif /* SO_RCV_COPYAVOID */
924
925 #ifdef SO_SND_COPYAVOID
926 if (loc_sndavoid) {
927 if (setsockopt(temp_socket,
928 SOL_SOCKET,
929 SO_SND_COPYAVOID,
930 (const char *)&loc_sndavoid,
931 sizeof(int)) == SOCKET_ERROR) {
932 fprintf(where,
933 "netperf: create_data_socket: Could not enable send copy avoidance");
934 fflush(where);
935 loc_sndavoid = 0;
936 }
937 }
938 #else
939 /* it was not compiled in... */
940 loc_sndavoid = 0;
941 #endif
942
943 /* Now, we will see about setting the TCP_NODELAY flag on the local */
944 /* socket. We will only do this for those systems that actually */
945 /* support the option. If it fails, note the fact, but keep going. */
946 /* If the user tries to enable TCP_NODELAY on a UDP socket, this */
947 /* will cause an error to be displayed */
948
949 /* well..... long ago and far away that would have happened, in
950 particular because we would always use IPPROTO_TCP here.
951 however, now we are using res->ai_protocol, which will be
952 IPPROT_UDP, and while HP-UX, and I suspect no-one else on the
953 planet has a UDP_mumble option that overlaps with TCP_NODELAY,
954 sure as knuth made little green programs, linux has a UDP_CORK
955 option that is defined as a value of 1, which is the same a
956 TCP_NODELAY under Linux. So, when asking for -D and
957 "TCP_NODELAY" under Linux, we are actually setting UDP_CORK
958 instead of getting an error like every other OS on the
959 planet. joy and rupture. this stops a UDP_RR test cold sooo we
960 have to make sure that res->ai_protocol actually makes sense for
961 a _NODELAY setsockopt() or a UDP_RR test on Linux where someone
962 mistakenly sets -D will hang. raj 2005-04-21 */
963
964 #if defined(TCP_NODELAY) || defined(SCTP_NODELAY)
965 if ((loc_nodelay) && (res->ai_protocol != IPPROTO_UDP)) {
966
967 /* strictly speaking, since the if defined above is an OR, we
968 should probably check against TCP_NODELAY being defined here.
969 however, the likelihood of SCTP_NODELAY being defined and
970 TCP_NODELAY _NOT_ being defined is, probably :), epsilon. raj
971 2005-03-15 */
972
973 int option = TCP_NODELAY;
974
975 /* I suspect that WANT_SCTP would suffice here since that is the
976 only time we would have called getaddrinfo with a hints asking
977 for SCTP, but just in case there is an SCTP implementation out
978 there _without_ SCTP_NODELAY... raj 2005-03-15 */
979
980 #if defined(WANT_SCTP) && defined(SCTP_NODELAY)
981 if (IPPROTO_SCTP == res->ai_protocol) {
982 option = SCTP_NODELAY;
983 }
984 #endif
985
986 one = 1;
987 if(setsockopt(temp_socket,
988 res->ai_protocol,
989 option,
990 (char *)&one,
991 sizeof(one)) == SOCKET_ERROR) {
992 fprintf(where,
993 "netperf: create_data_socket: nodelay: errno %d\n",
994 errno);
995 fflush(where);
996 }
997
998 if (debug > 1) {
999 fprintf(where,
1000 "netperf: create_data_socket: [TCP|SCTP]_NODELAY requested...\n");
1001 fflush(where);
1002 }
1003 }
1004 #else /* TCP_NODELAY */
1005
1006 loc_nodelay = 0;
1007
1008 #endif /* TCP_NODELAY */
1009
1010 #if defined(TCP_CORK)
1011
1012 if (loc_tcpcork != 0) {
1013 /* the user wishes for us to set TCP_CORK on the socket */
1014 int one = 1;
1015 if (setsockopt(temp_socket,
1016 getprotobyname("tcp")->p_proto,
1017 TCP_CORK,
1018 (char *)&one,
1019 sizeof(one)) == SOCKET_ERROR) {
1020 perror("netperf: sendfile_tcp_stream: tcp_cork");
1021 exit(1);
1022 }
1023 if (debug) {
1024 fprintf(where,"sendfile_tcp_stream: tcp_cork...\n");
1025 }
1026 }
1027
1028 #endif /* TCP_CORK */
1029
1030 /* since some of the UDP tests do not do anything to cause an
1031 implicit bind() call, we need to be rather explicit about our
1032 bind() call here. even if the address and/or the port are zero
1033 (INADDR_ANY etc). raj 2004-07-20 */
1034
1035 if (setsockopt(temp_socket,
1036 SOL_SOCKET,
1037 SO_REUSEADDR,
1038 (const char *)&on,
1039 sizeof(on)) < 0) {
1040 fprintf(where,
1041 "netperf: create_data_socket: SO_REUSEADDR failed %d\n",
1042 errno);
1043 fflush(where);
1044 }
1045
1046 if (bind(temp_socket,
1047 res->ai_addr,
1048 res->ai_addrlen) < 0) {
1049 if (debug) {
1050 fprintf(where,
1051 "netperf: create_data_socket: data socket bind failed errno %d\n",
1052 errno);
1053 fprintf(where," port: %d\n",get_port_number(res));
1054 fflush(where);
1055 }
1056 }
1057
1058
1059 return(temp_socket);
1060
1061 }
1062
1063 #ifdef KLUDGE_SOCKET_OPTIONS
1064
1065
1066 /* This routine is for those BROKEN systems which do not correctly */
1067 /* pass socket attributes through calls such as accept(). It should */
1068 /* only be called for those broken systems. I *really* don't want to */
1069 /* have this, but even broken systems must be measured. raj 11/95 */
1070 void
kludge_socket_options(int temp_socket)1071 kludge_socket_options(int temp_socket)
1072 {
1073
1074 set_sock_buffer(temp_socket, SEND_BUFFER, lss_size_req, &lss_size);
1075 set_sock_buffer(temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size);
1076
1077 /* now, we may wish to enable the copy avoidance features on the */
1078 /* local system. of course, this may not be possible... */
1079 /* those calls were only valid for HP-UX, and I know that HP-UX is */
1080 /* written correctly, and so we do not need to include those calls */
1081 /* in this kludgy routine. raj 11/95 */
1082
1083
1084 /* Now, we will see about setting the TCP_NODELAY flag on the local */
1085 /* socket. We will only do this for those systems that actually */
1086 /* support the option. If it fails, note the fact, but keep going. */
1087 /* If the user tries to enable TCP_NODELAY on a UDP socket, this */
1088 /* will cause an error to be displayed */
1089
1090 #ifdef TCP_NODELAY
1091 if (loc_nodelay) {
1092 one = 1;
1093 if(setsockopt(temp_socket,
1094 getprotobyname("tcp")->p_proto,
1095 TCP_NODELAY,
1096 (char *)&one,
1097 sizeof(one)) == SOCKET_ERROR) {
1098 fprintf(where,"netperf: kludge_socket_options: nodelay: errno %d\n",
1099 errno);
1100 fflush(where);
1101 }
1102
1103 if (debug > 1) {
1104 fprintf(where,
1105 "netperf: kludge_socket_options: TCP_NODELAY requested...\n");
1106 fflush(where);
1107 }
1108 }
1109 #else /* TCP_NODELAY */
1110
1111 loc_nodelay = 0;
1112
1113 #endif /* TCP_NODELAY */
1114
1115 }
1116
1117 #endif /* KLUDGE_SOCKET_OPTIONS */
1118
1119
1120 static void *
get_address_address(struct addrinfo * info)1121 get_address_address(struct addrinfo *info)
1122 {
1123 struct sockaddr_in *sin;
1124 #if defined(AF_INET6)
1125 struct sockaddr_in6 *sin6;
1126 #endif
1127
1128 switch(info->ai_family) {
1129 case AF_INET:
1130 sin = (struct sockaddr_in *)info->ai_addr;
1131 return(&(sin->sin_addr));
1132 break;
1133 #if defined(AF_INET6)
1134 case AF_INET6:
1135 sin6 = (struct sockaddr_in6 *)info->ai_addr;
1136 return(&(sin6->sin6_addr));
1137 break;
1138 #endif
1139 default:
1140 fprintf(stderr,"we never expected to get here in get_address_address\n");
1141 fflush(stderr);
1142 exit(-1);
1143 }
1144 }
1145
1146 #if defined(WIN32)
1147 /* +*+ Why isn't this in the winsock headers yet? */
1148 const char *
1149 inet_ntop(int af, const void *src, char *dst, size_t size);
1150 #endif
1151
1152 /* This routine is a generic test header printer for the topmost header */
1153 void
print_top_test_header(char test_name[],struct addrinfo * source,struct addrinfo * destination)1154 print_top_test_header(char test_name[], struct addrinfo *source, struct addrinfo *destination)
1155 {
1156
1157 #if defined(AF_INET6)
1158 char address_buf[INET6_ADDRSTRLEN];
1159 #else
1160 char address_buf[16]; /* magic constant */
1161 #endif
1162
1163 /* we want to have some additional, interesting information in */
1164 /* the headers. we know some of it here, but not all, so we will */
1165 /* only print the test title here and will print the results */
1166 /* titles after the test is finished */
1167 fprintf(where, "%s", test_name);
1168 address_buf[0] = '\0';
1169 inet_ntop(source->ai_family,get_address_address(source),address_buf,sizeof(address_buf));
1170 fprintf(where,
1171 " from %s (%s) port %u %s",
1172 source->ai_canonname,
1173 address_buf,
1174 get_port_number(source),
1175 inet_ftos(source->ai_family));
1176 address_buf[0] = '\0';
1177 inet_ntop(destination->ai_family,get_address_address(destination),address_buf,sizeof(address_buf));
1178 fprintf(where,
1179 " to %s (%s) port %u %s",
1180 destination->ai_canonname,
1181 address_buf,
1182 get_port_number(destination),
1183 inet_ftos(destination->ai_family));
1184
1185 if (iteration_max > 1) {
1186 fprintf(where,
1187 " : +/-%3.1f%% @ %2d%% conf. %s",
1188 interval/0.02,
1189 confidence_level,
1190 result_confidence_only ? " on result only" : "");
1191 }
1192 if ((loc_nodelay > 0) || (rem_nodelay > 0)) {
1193 fprintf(where," : nodelay");
1194 }
1195 if ((loc_sndavoid > 0) ||
1196 (loc_rcvavoid > 0) ||
1197 (rem_sndavoid > 0) ||
1198 (rem_rcvavoid > 0)) {
1199 fprintf(where," : copy avoidance");
1200 }
1201
1202 if (no_control) {
1203 fprintf(where," : no control");
1204 }
1205
1206 #ifdef WANT_HISTOGRAM
1207 fprintf(where," : histogram");
1208 #endif /* WANT_HISTOGRAM */
1209
1210 #ifdef WANT_INTERVALS
1211 #ifndef WANT_SPIN
1212 fprintf(where," : interval");
1213 #else
1214 fprintf(where," : spin interval");
1215 #endif
1216 #endif /* WANT_INTERVALS */
1217
1218 #ifdef DIRTY
1219 fprintf(where," : dirty data");
1220 #endif /* DIRTY */
1221 #ifdef WANT_DEMO
1222 fprintf(where," : demo");
1223 #endif
1224 #ifdef WANT_FIRST_BURST
1225 /* a little hokey perhaps, but we really only want this to be
1226 emitted for tests where it actually is used, which means a
1227 "REQUEST/RESPONSE" test. raj 2005-11-10 */
1228 if (strstr(test_name,"REQUEST/RESPONSE")) {
1229 fprintf(where," : first burst %d",first_burst_size);
1230 }
1231 #endif
1232 if (cpu_binding_requested) {
1233 fprintf(where," : cpu bind");
1234 }
1235 fprintf(where,"\n");
1236
1237 }
1238
1239
1240 /* This routine implements the TCP unidirectional data transfer test */
1241 /* (a.k.a. stream) for the sockets interface. It receives its */
1242 /* parameters via global variables from the shell and writes its */
1243 /* output to the standard output. */
1244
1245
1246 void
send_tcp_stream(char remote_host[])1247 send_tcp_stream(char remote_host[])
1248 {
1249
1250 char *tput_title = "\
1251 Recv Send Send \n\
1252 Socket Socket Message Elapsed \n\
1253 Size Size Size Time Throughput \n\
1254 bytes bytes bytes secs. %s/sec \n\n";
1255
1256 char *tput_fmt_0 =
1257 "%7.2f %s\n";
1258
1259 char *tput_fmt_1 =
1260 "%6d %6d %6d %-6.2f %7.2f %s\n";
1261
1262 char *cpu_title = "\
1263 Recv Send Send Utilization Service Demand\n\
1264 Socket Socket Message Elapsed Send Recv Send Recv\n\
1265 Size Size Size Time Throughput local remote local remote\n\
1266 bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
1267
1268 char *cpu_fmt_0 =
1269 "%6.3f %c %s\n";
1270
1271 char *cpu_fmt_1 =
1272 "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n";
1273
1274 char *ksink_fmt = "\n\
1275 Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
1276 Local Remote Local Remote Xfered Per Per\n\
1277 Send Recv Send Recv Send (avg) Recv (avg)\n\
1278 %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
1279
1280 char *ksink_fmt2 = "\n\
1281 Maximum\n\
1282 Segment\n\
1283 Size (bytes)\n\
1284 %6d\n";
1285
1286
1287 float elapsed_time;
1288
1289 /* what we want is to have a buffer space that is at least one */
1290 /* send-size greater than our send window. this will insure that we */
1291 /* are never trying to re-use a buffer that may still be in the hands */
1292 /* of the transport. This buffer will be malloc'd after we have found */
1293 /* the size of the local senc socket buffer. We will want to deal */
1294 /* with alignment and offset concerns as well. */
1295
1296 struct ring_elt *send_ring;
1297
1298 int len;
1299 unsigned int nummessages = 0;
1300 SOCKET send_socket;
1301 int bytes_remaining;
1302 int tcp_mss = -1; /* possibly uninitialized on printf far below */
1303
1304 /* with links like fddi, one can send > 32 bits worth of bytes */
1305 /* during a test... ;-) at some point, this should probably become a */
1306 /* 64bit integral type, but those are not entirely common yet */
1307
1308 unsigned long long local_bytes_sent = 0;
1309 double bytes_sent = 0.0;
1310
1311 float local_cpu_utilization;
1312 float local_service_demand;
1313 float remote_cpu_utilization;
1314 float remote_service_demand;
1315
1316 double thruput;
1317
1318 struct addrinfo *remote_res;
1319 struct addrinfo *local_res;
1320
1321 struct tcp_stream_request_struct *tcp_stream_request;
1322 struct tcp_stream_response_struct *tcp_stream_response;
1323 struct tcp_stream_results_struct *tcp_stream_result;
1324
1325 tcp_stream_request =
1326 (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data;
1327 tcp_stream_response =
1328 (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data;
1329 tcp_stream_result =
1330 (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data;
1331
1332 #ifdef WANT_HISTOGRAM
1333 if (verbosity > 1) {
1334 time_hist = HIST_new();
1335 }
1336 #endif /* WANT_HISTOGRAM */
1337 /* since we are now disconnected from the code that established the */
1338 /* control socket, and since we want to be able to use different */
1339 /* protocols and such, we are passed the name of the remote host and */
1340 /* must turn that into the test specific addressing information. */
1341
1342 /* complete_addrinfos will either succede or exit the process */
1343 complete_addrinfos(&remote_res,
1344 &local_res,
1345 remote_host,
1346 SOCK_STREAM,
1347 IPPROTO_TCP,
1348 0);
1349
1350 if ( print_headers ) {
1351 print_top_test_header("TCP STREAM TEST",local_res,remote_res);
1352 }
1353
1354 send_ring = NULL;
1355 confidence_iteration = 1;
1356 init_stat();
1357
1358 /* we have a great-big while loop which controls the number of times */
1359 /* we run a particular test. this is for the calculation of a */
1360 /* confidence interval (I really should have stayed awake during */
1361 /* probstats :). If the user did not request confidence measurement */
1362 /* (no confidence is the default) then we will only go though the */
1363 /* loop once. the confidence stuff originates from the folks at IBM */
1364
1365 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
1366 (confidence_iteration <= iteration_min)) {
1367
1368 /* initialize a few counters. we have to remember that we might be */
1369 /* going through the loop more than once. */
1370
1371 nummessages = 0;
1372 bytes_sent = 0.0;
1373 times_up = 0;
1374
1375 /*set up the data socket */
1376 send_socket = create_data_socket(local_res);
1377
1378 if (send_socket == INVALID_SOCKET){
1379 perror("netperf: send_tcp_stream: tcp stream data socket");
1380 exit(1);
1381 }
1382
1383 if (debug) {
1384 fprintf(where,"send_tcp_stream: send_socket obtained...\n");
1385 }
1386
1387 /* at this point, we have either retrieved the socket buffer sizes, */
1388 /* or have tried to set them, so now, we may want to set the send */
1389 /* size based on that (because the user either did not use a -m */
1390 /* option, or used one with an argument of 0). If the socket buffer */
1391 /* size is not available, we will set the send size to 4KB - no */
1392 /* particular reason, just arbitrary... */
1393 if (send_size == 0) {
1394 if (lss_size > 0) {
1395 send_size = lss_size;
1396 }
1397 else {
1398 send_size = 4096;
1399 }
1400 }
1401
1402 /* set-up the data buffer ring with the requested alignment and offset. */
1403 /* note also that we have allocated a quantity */
1404 /* of memory that is at least one send-size greater than our socket */
1405 /* buffer size. We want to be sure that there are at least two */
1406 /* buffers allocated - this can be a bit of a problem when the */
1407 /* send_size is bigger than the socket size, so we must check... the */
1408 /* user may have wanted to explicitly set the "width" of our send */
1409 /* buffers, we should respect that wish... */
1410 if (send_width == 0) {
1411 send_width = (lss_size/send_size) + 1;
1412 if (send_width == 1) send_width++;
1413 }
1414
1415 if (send_ring == NULL) {
1416 /* only allocate the send ring once. this is a networking test, */
1417 /* not a memory allocation test. this way, we do not need a */
1418 /* deallocate_buffer_ring() routine, and I don't feel like */
1419 /* writing one anyway :) raj 11/94 */
1420 send_ring = allocate_buffer_ring(send_width,
1421 send_size,
1422 local_send_align,
1423 local_send_offset);
1424 }
1425
1426 /* If the user has requested cpu utilization measurements, we must */
1427 /* calibrate the cpu(s). We will perform this task within the tests */
1428 /* themselves. If the user has specified the cpu rate, then */
1429 /* calibrate_local_cpu will return rather quickly as it will have */
1430 /* nothing to do. If local_cpu_rate is zero, then we will go through */
1431 /* all the "normal" calibration stuff and return the rate back. */
1432
1433 if (local_cpu_usage) {
1434 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1435 }
1436
1437 if (!no_control) {
1438 /* Tell the remote end to do a listen. The server alters the
1439 socket paramters on the other side at this point, hence the
1440 reason for all the values being passed in the setup
1441 message. If the user did not specify any of the parameters,
1442 they will be passed as 0, which will indicate to the remote
1443 that no changes beyond the system's default should be
1444 used. Alignment is the exception, it will default to 1, which
1445 will be no alignment alterations. */
1446
1447 netperf_request.content.request_type = DO_TCP_STREAM;
1448 tcp_stream_request->send_buf_size = rss_size_req;
1449 tcp_stream_request->recv_buf_size = rsr_size_req;
1450 tcp_stream_request->receive_size = recv_size;
1451 tcp_stream_request->no_delay = rem_nodelay;
1452 tcp_stream_request->recv_alignment = remote_recv_align;
1453 tcp_stream_request->recv_offset = remote_recv_offset;
1454 tcp_stream_request->measure_cpu = remote_cpu_usage;
1455 tcp_stream_request->cpu_rate = remote_cpu_rate;
1456 if (test_time) {
1457 tcp_stream_request->test_length = test_time;
1458 }
1459 else {
1460 tcp_stream_request->test_length = test_bytes;
1461 }
1462 tcp_stream_request->so_rcvavoid = rem_rcvavoid;
1463 tcp_stream_request->so_sndavoid = rem_sndavoid;
1464 #ifdef DIRTY
1465 tcp_stream_request->dirty_count = rem_dirty_count;
1466 tcp_stream_request->clean_count = rem_clean_count;
1467 #endif /* DIRTY */
1468 tcp_stream_request->port = atoi(remote_data_port);
1469 tcp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
1470 if (debug > 1) {
1471 fprintf(where,
1472 "netperf: send_tcp_stream: requesting TCP stream test\n");
1473 }
1474
1475 send_request();
1476
1477 /* The response from the remote will contain all of the relevant
1478 socket parameters for this test type. We will put them back
1479 into the variables here so they can be displayed if desired.
1480 The remote will have calibrated CPU if necessary, and will
1481 have done all the needed set-up we will have calibrated the
1482 cpu locally before sending the request, and will grab the
1483 counter value right after the connect returns. The remote
1484 will grab the counter right after the accept call. This saves
1485 the hassle of extra messages being sent for the TCP
1486 tests. */
1487
1488 recv_response();
1489
1490 if (!netperf_response.content.serv_errno) {
1491 if (debug)
1492 fprintf(where,"remote listen done.\n");
1493 rsr_size = tcp_stream_response->recv_buf_size;
1494 rss_size = tcp_stream_response->send_buf_size;
1495 rem_nodelay = tcp_stream_response->no_delay;
1496 remote_cpu_usage= tcp_stream_response->measure_cpu;
1497 remote_cpu_rate = tcp_stream_response->cpu_rate;
1498
1499 /* we have to make sure that the server port number is in
1500 network order */
1501 set_port_number(remote_res,
1502 (short)tcp_stream_response->data_port_number);
1503
1504 rem_rcvavoid = tcp_stream_response->so_rcvavoid;
1505 rem_sndavoid = tcp_stream_response->so_sndavoid;
1506 }
1507 else {
1508 Set_errno(netperf_response.content.serv_errno);
1509 fprintf(where,
1510 "netperf: remote error %d",
1511 netperf_response.content.serv_errno);
1512 perror("");
1513 fflush(where);
1514
1515 exit(1);
1516 }
1517 }
1518
1519 #ifdef WANT_DEMO
1520 DEMO_STREAM_SETUP(lss_size,rsr_size)
1521 #endif
1522
1523 /*Connect up to the remote port on the data socket */
1524 if (connect(send_socket,
1525 remote_res->ai_addr,
1526 remote_res->ai_addrlen) == INVALID_SOCKET){
1527 perror("netperf: send_tcp_stream: data socket connect failed");
1528 exit(1);
1529 }
1530
1531 /* Data Socket set-up is finished. If there were problems, either */
1532 /* the connect would have failed, or the previous response would */
1533 /* have indicated a problem. I failed to see the value of the */
1534 /* extra message after the accept on the remote. If it failed, */
1535 /* we'll see it here. If it didn't, we might as well start pumping */
1536 /* data. */
1537
1538 /* Set-up the test end conditions. For a stream test, they can be */
1539 /* either time or byte-count based. */
1540
1541 if (test_time) {
1542 /* The user wanted to end the test after a period of time. */
1543 times_up = 0;
1544 bytes_remaining = 0;
1545 /* in previous revisions, we had the same code repeated throught */
1546 /* all the test suites. this was unnecessary, and meant more */
1547 /* work for me when I wanted to switch to POSIX signals, so I */
1548 /* have abstracted this out into a routine in netlib.c. if you */
1549 /* are experiencing signal problems, you might want to look */
1550 /* there. raj 11/94 */
1551 start_timer(test_time);
1552 }
1553 else {
1554 /* The tester wanted to send a number of bytes. */
1555 bytes_remaining = test_bytes;
1556 times_up = 1;
1557 }
1558
1559 /* The cpu_start routine will grab the current time and possibly */
1560 /* value of the idle counter for later use in measuring cpu */
1561 /* utilization and/or service demand and thruput. */
1562
1563 cpu_start(local_cpu_usage);
1564
1565 /* we only start the interval timer if we are using the
1566 timer-timed intervals rather than the sit and spin ones. raj
1567 2006-02-06 */
1568 #if defined(WANT_INTERVALS)
1569 INTERVALS_INIT();
1570 #endif /* WANT_INTERVALS */
1571
1572 /* before we start, initialize a few variables */
1573
1574 #ifdef WANT_DEMO
1575 if (demo_mode) {
1576 HIST_timestamp(demo_one_ptr);
1577 }
1578 #endif
1579
1580
1581 /* We use an "OR" to control test execution. When the test is */
1582 /* controlled by time, the byte count check will always return false. */
1583 /* When the test is controlled by byte count, the time test will */
1584 /* always return false. When the test is finished, the whole */
1585 /* expression will go false and we will stop sending data. */
1586
1587 while ((!times_up) || (bytes_remaining > 0)) {
1588
1589 #ifdef DIRTY
1590 access_buffer(send_ring->buffer_ptr,
1591 send_size,
1592 loc_dirty_count,
1593 loc_clean_count);
1594 #endif /* DIRTY */
1595
1596 #ifdef WANT_HISTOGRAM
1597 if (verbosity > 1) {
1598 /* timestamp just before we go into send and then again just
1599 after we come out raj 8/94 */
1600 /* but lets only do this if there is going to be a histogram
1601 displayed */
1602 HIST_timestamp(&time_one);
1603 }
1604 #endif /* WANT_HISTOGRAM */
1605
1606 if((len=send(send_socket,
1607 send_ring->buffer_ptr,
1608 send_size,
1609 0)) != send_size) {
1610 if ((len >=0) || SOCKET_EINTR(len)) {
1611 /* the test was interrupted, must be the end of test */
1612 break;
1613 }
1614 perror("netperf: data send error");
1615 printf("len was %d\n",len);
1616 exit(1);
1617 }
1618
1619 local_bytes_sent += send_size;
1620
1621 #ifdef WANT_HISTOGRAM
1622 if (verbosity > 1) {
1623 /* timestamp the exit from the send call and update the histogram */
1624 HIST_timestamp(&time_two);
1625 HIST_add(time_hist,delta_micro(&time_one,&time_two));
1626 }
1627 #endif /* WANT_HISTOGRAM */
1628
1629 #ifdef WANT_DEMO
1630 DEMO_STREAM_INTERVAL(send_size)
1631 #endif
1632
1633 #if defined(WANT_INTERVALS)
1634 INTERVALS_WAIT();
1635 #endif /* WANT_INTERVALS */
1636
1637 /* now we want to move our pointer to the next position in the */
1638 /* data buffer...we may also want to wrap back to the "beginning" */
1639 /* of the bufferspace, so we will mod the number of messages sent */
1640 /* by the send width, and use that to calculate the offset to add */
1641 /* to the base pointer. */
1642 nummessages++;
1643 send_ring = send_ring->next;
1644 if (bytes_remaining) {
1645 bytes_remaining -= send_size;
1646 }
1647 }
1648
1649 /* The test is over. Flush the buffers to the remote end. We do a */
1650 /* graceful release to insure that all data has been taken by the */
1651 /* remote. */
1652
1653 /* but first, if the verbosity is greater than 1, find-out what */
1654 /* the TCP maximum segment_size was (if possible) */
1655 if (verbosity > 1) {
1656 tcp_mss = -1;
1657 get_tcp_info(send_socket,&tcp_mss);
1658 }
1659
1660 if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) {
1661 perror("netperf: cannot shutdown tcp stream socket");
1662 exit(1);
1663 }
1664
1665 /* hang a recv() off the socket to block until the remote has */
1666 /* brought all the data up into the application. it will do a */
1667 /* shutdown to cause a FIN to be sent our way. We will assume that */
1668 /* any exit from the recv() call is good... raj 4/93 */
1669
1670 recv(send_socket, send_ring->buffer_ptr, send_size, 0);
1671
1672 /* this call will always give us the elapsed time for the test, and */
1673 /* will also store-away the necessaries for cpu utilization */
1674
1675 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
1676 /* measured and how */
1677 /* long did we really */
1678 /* run? */
1679
1680 /* we are finished with the socket, so close it to prevent hitting */
1681 /* the limit on maximum open files. */
1682
1683 close(send_socket);
1684
1685 if (!no_control) {
1686 /* Get the statistics from the remote end. The remote will have
1687 calculated service demand and all those interesting
1688 things. If it wasn't supposed to care, it will return obvious
1689 values. */
1690
1691 recv_response();
1692 if (!netperf_response.content.serv_errno) {
1693 if (debug)
1694 fprintf(where,"remote results obtained\n");
1695 }
1696 else {
1697 Set_errno(netperf_response.content.serv_errno);
1698 fprintf(where,
1699 "netperf: remote error %d",
1700 netperf_response.content.serv_errno);
1701 perror("");
1702 fflush(where);
1703
1704 exit(1);
1705 }
1706
1707 /* We now calculate what our thruput was for the test. In the
1708 future, we may want to include a calculation of the thruput
1709 measured by the remote, but it should be the case that for a
1710 TCP stream test, that the two numbers should be *very*
1711 close... We calculate bytes_sent regardless of the way the
1712 test length was controlled. If it was time, we needed to,
1713 and if it was by bytes, the user may have specified a number
1714 of bytes that wasn't a multiple of the send_size, so we
1715 really didn't send what he asked for ;-) */
1716
1717 bytes_sent = ntohd(tcp_stream_result->bytes_received);
1718 }
1719 else {
1720 bytes_sent = (double)local_bytes_sent;
1721 }
1722
1723 thruput = calc_thruput(bytes_sent);
1724
1725 if (local_cpu_usage || remote_cpu_usage) {
1726 /* We must now do a little math for service demand and cpu */
1727 /* utilization for the system(s) */
1728 /* Of course, some of the information might be bogus because */
1729 /* there was no idle counter in the kernel(s). We need to make */
1730 /* a note of this for the user's benefit...*/
1731 if (local_cpu_usage) {
1732
1733 local_cpu_utilization = calc_cpu_util(0.0);
1734 local_service_demand = calc_service_demand(bytes_sent,
1735 0.0,
1736 0.0,
1737 0);
1738 }
1739 else {
1740 local_cpu_utilization = (float) -1.0;
1741 local_service_demand = (float) -1.0;
1742 }
1743
1744 if (remote_cpu_usage) {
1745
1746 remote_cpu_utilization = tcp_stream_result->cpu_util;
1747 remote_service_demand = calc_service_demand(bytes_sent,
1748 0.0,
1749 remote_cpu_utilization,
1750 tcp_stream_result->num_cpus);
1751 }
1752 else {
1753 remote_cpu_utilization = (float) -1.0;
1754 remote_service_demand = (float) -1.0;
1755 }
1756 }
1757 else {
1758 /* we were not measuring cpu, for the confidence stuff, we */
1759 /* should make it -1.0 */
1760 local_cpu_utilization = (float) -1.0;
1761 local_service_demand = (float) -1.0;
1762 remote_cpu_utilization = (float) -1.0;
1763 remote_service_demand = (float) -1.0;
1764 }
1765
1766 /* at this point, we want to calculate the confidence information. */
1767 /* if debugging is on, calculate_confidence will print-out the */
1768 /* parameters we pass it */
1769
1770 calculate_confidence(confidence_iteration,
1771 elapsed_time,
1772 thruput,
1773 local_cpu_utilization,
1774 remote_cpu_utilization,
1775 local_service_demand,
1776 remote_service_demand);
1777
1778
1779 confidence_iteration++;
1780 }
1781
1782 /* at this point, we have finished making all the runs that we */
1783 /* will be making. so, we should extract what the calcuated values */
1784 /* are for all the confidence stuff. we could make the values */
1785 /* global, but that seemed a little messy, and it did not seem worth */
1786 /* all the mucking with header files. so, we create a routine much */
1787 /* like calcualte_confidence, which just returns the mean values. */
1788 /* raj 11/94 */
1789
1790 retrieve_confident_values(&elapsed_time,
1791 &thruput,
1792 &local_cpu_utilization,
1793 &remote_cpu_utilization,
1794 &local_service_demand,
1795 &remote_service_demand);
1796
1797 /* We are now ready to print all the information. If the user */
1798 /* has specified zero-level verbosity, we will just print the */
1799 /* local service demand, or the remote service demand. If the */
1800 /* user has requested verbosity level 1, he will get the basic */
1801 /* "streamperf" numbers. If the user has specified a verbosity */
1802 /* of greater than 1, we will display a veritable plethora of */
1803 /* background information from outside of this block as it it */
1804 /* not cpu_measurement specific... */
1805
1806 if (confidence < 0) {
1807 /* we did not hit confidence, but were we asked to look for it? */
1808 if (iteration_max > 1) {
1809 display_confidence();
1810 }
1811 }
1812
1813 if (local_cpu_usage || remote_cpu_usage) {
1814 local_cpu_method = format_cpu_method(cpu_method);
1815 remote_cpu_method = format_cpu_method(tcp_stream_result->cpu_method);
1816
1817 switch (verbosity) {
1818 case 0:
1819 if (local_cpu_usage) {
1820 fprintf(where,
1821 cpu_fmt_0,
1822 local_service_demand,
1823 local_cpu_method,
1824 ((print_headers) ||
1825 (result_brand == NULL)) ? "" : result_brand);
1826 }
1827 else {
1828 fprintf(where,
1829 cpu_fmt_0,
1830 remote_service_demand,
1831 remote_cpu_method,
1832 ((print_headers) ||
1833 (result_brand == NULL)) ? "" : result_brand);
1834 }
1835 break;
1836 case 1:
1837 case 2:
1838 if (print_headers) {
1839 fprintf(where,
1840 cpu_title,
1841 format_units(),
1842 local_cpu_method,
1843 remote_cpu_method);
1844 }
1845
1846 fprintf(where,
1847 cpu_fmt_1, /* the format string */
1848 rsr_size, /* remote recvbuf size */
1849 lss_size, /* local sendbuf size */
1850 send_size, /* how large were the sends */
1851 elapsed_time, /* how long was the test */
1852 thruput, /* what was the xfer rate */
1853 local_cpu_utilization, /* local cpu */
1854 remote_cpu_utilization, /* remote cpu */
1855 local_service_demand, /* local service demand */
1856 remote_service_demand, /* remote service demand */
1857 ((print_headers) ||
1858 (result_brand == NULL)) ? "" : result_brand);
1859 break;
1860 }
1861 }
1862 else {
1863 /* The tester did not wish to measure service demand. */
1864
1865 switch (verbosity) {
1866 case 0:
1867 fprintf(where,
1868 tput_fmt_0,
1869 thruput,
1870 ((print_headers) ||
1871 (result_brand == NULL)) ? "" : result_brand);
1872 break;
1873 case 1:
1874 case 2:
1875 if (print_headers) {
1876 fprintf(where,tput_title,format_units());
1877 }
1878 fprintf(where,
1879 tput_fmt_1, /* the format string */
1880 rsr_size, /* remote recvbuf size */
1881 lss_size, /* local sendbuf size */
1882 send_size, /* how large were the sends */
1883 elapsed_time, /* how long did it take */
1884 thruput, /* how fast did it go */
1885 ((print_headers) ||
1886 (result_brand == NULL)) ? "" : result_brand);
1887 break;
1888 }
1889 }
1890
1891 /* it would be a good thing to include information about some of the */
1892 /* other parameters that may have been set for this test, but at the */
1893 /* moment, I do not wish to figure-out all the formatting, so I will */
1894 /* just put this comment here to help remind me that it is something */
1895 /* that should be done at a later time. */
1896
1897 if (verbosity > 1) {
1898 /* The user wanted to know it all, so we will give it to him. */
1899 /* This information will include as much as we can find about */
1900 /* TCP statistics, the alignments of the sends and receives */
1901 /* and all that sort of rot... */
1902
1903 /* this stuff needs to be worked-out in the presence of confidence */
1904 /* intervals and multiple iterations of the test... raj 11/94 */
1905
1906 fprintf(where,
1907 ksink_fmt,
1908 "Bytes",
1909 "Bytes",
1910 "Bytes",
1911 local_send_align,
1912 remote_recv_align,
1913 local_send_offset,
1914 remote_recv_offset,
1915 bytes_sent,
1916 bytes_sent / (double)nummessages,
1917 nummessages,
1918 bytes_sent / (double)tcp_stream_result->recv_calls,
1919 tcp_stream_result->recv_calls);
1920 fprintf(where,
1921 ksink_fmt2,
1922 tcp_mss);
1923 fflush(where);
1924 #ifdef WANT_HISTOGRAM
1925 fprintf(where,"\n\nHistogram of time spent in send() call.\n");
1926 fflush(where);
1927 HIST_report(time_hist);
1928 #endif /* WANT_HISTOGRAM */
1929 }
1930
1931 }
1932
1933
1934
1935 /* This routine implements the netperf-side TCP unidirectional data
1936 transfer test (a.k.a. stream) for the sockets interface where the
1937 data flow is from the netserver to the netperf. It receives its
1938 parameters via global variables from the shell and writes its
1939 output to the standard output. */
1940
1941
1942 void
send_tcp_maerts(char remote_host[])1943 send_tcp_maerts(char remote_host[])
1944 {
1945
1946 char *tput_title = "\
1947 Recv Send Send \n\
1948 Socket Socket Message Elapsed \n\
1949 Size Size Size Time Throughput \n\
1950 bytes bytes bytes secs. %s/sec \n\n";
1951
1952 char *tput_fmt_0 =
1953 "%7.2f %s\n";
1954
1955 char *tput_fmt_1 =
1956 "%6d %6d %6d %-6.2f %7.2f %s \n";
1957
1958 char *cpu_title = "\
1959 Recv Send Send Utilization Service Demand\n\
1960 Socket Socket Message Elapsed Send Recv Send Recv\n\
1961 Size Size Size Time Throughput local remote local remote\n\
1962 bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
1963
1964 char *cpu_fmt_0 =
1965 "%6.3f %c %s\n";
1966
1967 char *cpu_fmt_1 =
1968 "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n";
1969
1970 char *ksink_fmt = "\n\
1971 Alignment Offset %-8.8s %-8.8s Recvs %-8.8s Sends\n\
1972 Local Remote Local Remote Xfered Per Per\n\
1973 Recv Send Recv Send Recv (avg) Send (avg)\n\
1974 %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
1975
1976 char *ksink_fmt2 = "\n\
1977 Maximum\n\
1978 Segment\n\
1979 Size (bytes)\n\
1980 %6d\n";
1981
1982
1983 float elapsed_time;
1984
1985 /* what we want is to have a buffer space that is at least one */
1986 /* recv-size greater than our recv window. this will insure that we */
1987 /* are never trying to re-use a buffer that may still be in the hands */
1988 /* of the transport. This buffer will be malloc'd after we have found */
1989 /* the size of the local senc socket buffer. We will want to deal */
1990 /* with alignment and offset concerns as well. */
1991
1992 struct ring_elt *recv_ring;
1993
1994 int len;
1995 unsigned int nummessages = 0;
1996 SOCKET recv_socket;
1997 int bytes_remaining;
1998 int tcp_mss = -1; /* possibly uninitialized on printf far below */
1999
2000 /* with links like fddi, one can recv > 32 bits worth of bytes */
2001 /* during a test... ;-) at some point, this should probably become a */
2002 /* 64bit integral type, but those are not entirely common yet */
2003 double bytes_sent = 0.0;
2004 unsigned long long local_bytes_recvd = 0;
2005
2006 float local_cpu_utilization;
2007 float local_service_demand;
2008 float remote_cpu_utilization;
2009 float remote_service_demand;
2010
2011 double thruput;
2012
2013 struct addrinfo *remote_res;
2014 struct addrinfo *local_res;
2015
2016 struct tcp_maerts_request_struct *tcp_maerts_request;
2017 struct tcp_maerts_response_struct *tcp_maerts_response;
2018 struct tcp_maerts_results_struct *tcp_maerts_result;
2019
2020 tcp_maerts_request =
2021 (struct tcp_maerts_request_struct *)netperf_request.content.test_specific_data;
2022 tcp_maerts_response =
2023 (struct tcp_maerts_response_struct *)netperf_response.content.test_specific_data;
2024 tcp_maerts_result =
2025 (struct tcp_maerts_results_struct *)netperf_response.content.test_specific_data;
2026
2027 #ifdef WANT_HISTOGRAM
2028 if (verbosity > 1) {
2029 time_hist = HIST_new();
2030 }
2031 #endif /* WANT_HISTOGRAM */
2032 /* since we are now disconnected from the code that established the */
2033 /* control socket, and since we want to be able to use different */
2034 /* protocols and such, we are passed the name of the remote host and */
2035 /* must turn that into the test specific addressing information. */
2036
2037 complete_addrinfos(&remote_res,
2038 &local_res,
2039 remote_host,
2040 SOCK_STREAM,
2041 IPPROTO_TCP,
2042 0);
2043
2044 if ( print_headers ) {
2045 print_top_test_header("TCP MAERTS TEST",local_res,remote_res);
2046 }
2047
2048 recv_ring = NULL;
2049 confidence_iteration = 1;
2050 init_stat();
2051
2052 /* we have a great-big while loop which controls the number of times */
2053 /* we run a particular test. this is for the calculation of a */
2054 /* confidence interval (I really should have stayed awake during */
2055 /* probstats :). If the user did not request confidence measurement */
2056 /* (no confidence is the default) then we will only go though the */
2057 /* loop once. the confidence stuff originates from the folks at IBM */
2058
2059 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
2060 (confidence_iteration <= iteration_min)) {
2061
2062 /* initialize a few counters. we have to remember that we might be */
2063 /* going through the loop more than once. */
2064
2065 nummessages = 0;
2066 bytes_sent = 0.0;
2067 times_up = 0;
2068
2069 /*set up the data socket */
2070 recv_socket = create_data_socket(local_res);
2071
2072 if (recv_socket == INVALID_SOCKET){
2073 perror("netperf: send_tcp_maerts: tcp stream data socket");
2074 exit(1);
2075 }
2076
2077 if (debug) {
2078 fprintf(where,"send_tcp_maerts: recv_socket obtained...\n");
2079 }
2080
2081 /* at this point, we have either retrieved the socket buffer sizes, */
2082 /* or have tried to set them, so now, we may want to set the recv */
2083 /* size based on that (because the user either did not use a -m */
2084 /* option, or used one with an argument of 0). If the socket buffer */
2085 /* size is not available, we will set the recv size to 4KB - no */
2086 /* particular reason, just arbitrary... */
2087 if (recv_size == 0) {
2088 if (lsr_size > 0) {
2089 recv_size = lsr_size;
2090 }
2091 else {
2092 recv_size = 4096;
2093 }
2094 }
2095
2096 /* set-up the data buffer ring with the requested alignment and offset. */
2097 /* note also that we have allocated a quantity */
2098 /* of memory that is at least one recv-size greater than our socket */
2099 /* buffer size. We want to be sure that there are at least two */
2100 /* buffers allocated - this can be a bit of a problem when the */
2101 /* recv_size is bigger than the socket size, so we must check... the */
2102 /* user may have wanted to explicitly set the "width" of our recv */
2103 /* buffers, we should respect that wish... */
2104 if (recv_width == 0) {
2105 recv_width = (lsr_size/recv_size) + 1;
2106 if (recv_width == 1) recv_width++;
2107 }
2108
2109 if (recv_ring == NULL) {
2110 /* only allocate the recv ring once. this is a networking test, */
2111 /* not a memory allocation test. this way, we do not need a */
2112 /* deallocate_buffer_ring() routine, and I don't feel like */
2113 /* writing one anyway :) raj 11/94 */
2114 recv_ring = allocate_buffer_ring(recv_width,
2115 recv_size,
2116 local_recv_align,
2117 local_recv_offset);
2118 }
2119
2120 /* If the user has requested cpu utilization measurements, we must */
2121 /* calibrate the cpu(s). We will perform this task within the tests */
2122 /* themselves. If the user has specified the cpu rate, then */
2123 /* calibrate_local_cpu will return rather quickly as it will have */
2124 /* nothing to do. If local_cpu_rate is zero, then we will go through */
2125 /* all the "normal" calibration stuff and return the rate back. */
2126
2127 if (local_cpu_usage) {
2128 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
2129 }
2130
2131 if (!no_control) {
2132 /* Tell the remote end to do a listen. The server alters the
2133 socket paramters on the other side at this point, hence the
2134 reason for all the values being passed in the setup
2135 message. If the user did not specify any of the parameters,
2136 they will be passed as 0, which will indicate to the remote
2137 that no changes beyond the system's default should be
2138 used. Alignment is the exception, it will default to 1, which
2139 will be no alignment alterations. */
2140
2141 netperf_request.content.request_type = DO_TCP_MAERTS;
2142 tcp_maerts_request->send_buf_size = rss_size_req;
2143 tcp_maerts_request->recv_buf_size = rsr_size_req;
2144 tcp_maerts_request->send_size = send_size;
2145 tcp_maerts_request->no_delay = rem_nodelay;
2146 tcp_maerts_request->send_alignment = remote_send_align;
2147 tcp_maerts_request->send_offset = remote_send_offset;
2148 tcp_maerts_request->measure_cpu = remote_cpu_usage;
2149 tcp_maerts_request->cpu_rate = remote_cpu_rate;
2150 if (test_time) {
2151 tcp_maerts_request->test_length = test_time;
2152 }
2153 else {
2154 tcp_maerts_request->test_length = test_bytes;
2155 }
2156 tcp_maerts_request->so_rcvavoid = rem_rcvavoid;
2157 tcp_maerts_request->so_sndavoid = rem_sndavoid;
2158 #ifdef DIRTY
2159 tcp_maerts_request->dirty_count = rem_dirty_count;
2160 tcp_maerts_request->clean_count = rem_clean_count;
2161 #endif /* DIRTY */
2162 tcp_maerts_request->port = atoi(remote_data_port);
2163 tcp_maerts_request->ipfamily = af_to_nf(remote_res->ai_family);
2164 if (debug > 1) {
2165 fprintf(where,
2166 "netperf: send_tcp_maerts: requesting TCP maerts test\n");
2167 }
2168
2169 send_request();
2170
2171 /* The response from the remote will contain all of the relevant
2172 socket parameters for this test type. We will put them back
2173 into the variables here so they can be displayed if desired.
2174 The remote will have calibrated CPU if necessary, and will
2175 have done all the needed set-up we will have calibrated the
2176 cpu locally before sending the request, and will grab the
2177 counter value right after the connect returns. The remote
2178 will grab the counter right after the accept call. This saves
2179 the hassle of extra messages being sent for the TCP
2180 tests. */
2181
2182 recv_response();
2183
2184 if (!netperf_response.content.serv_errno) {
2185 if (debug)
2186 fprintf(where,"remote listen done.\n");
2187 rsr_size = tcp_maerts_response->recv_buf_size;
2188 rss_size = tcp_maerts_response->send_buf_size;
2189 rem_nodelay = tcp_maerts_response->no_delay;
2190 remote_cpu_usage= tcp_maerts_response->measure_cpu;
2191 remote_cpu_rate = tcp_maerts_response->cpu_rate;
2192 send_size = tcp_maerts_response->send_size;
2193
2194 /* we have to make sure that the server port number is in
2195 network order */
2196 set_port_number(remote_res,
2197 (short)tcp_maerts_response->data_port_number);
2198 rem_rcvavoid = tcp_maerts_response->so_rcvavoid;
2199 rem_sndavoid = tcp_maerts_response->so_sndavoid;
2200 }
2201 else {
2202 Set_errno(netperf_response.content.serv_errno);
2203 fprintf(where,
2204 "netperf: remote error %d",
2205 netperf_response.content.serv_errno);
2206 perror("");
2207 fflush(where);
2208
2209 exit(1);
2210 }
2211 }
2212
2213 #ifdef WANT_DEMO
2214 DEMO_STREAM_SETUP(lsr_size,rss_size)
2215 #endif
2216
2217 /*Connect up to the remote port on the data socket */
2218 if (connect(recv_socket,
2219 remote_res->ai_addr,
2220 remote_res->ai_addrlen) == INVALID_SOCKET){
2221 perror("netperf: send_tcp_maerts: data socket connect failed");
2222 exit(1);
2223 }
2224
2225 /* Data Socket set-up is finished. If there were problems, either */
2226 /* the connect would have failed, or the previous response would */
2227 /* have indicated a problem. I failed to see the value of the */
2228 /* extra message after the accept on the remote. If it failed, */
2229 /* we'll see it here. If it didn't, we might as well start pumping */
2230 /* data. */
2231
2232 /* Set-up the test end conditions. For a maerts test, they can be */
2233 /* either time or byte-count based. */
2234
2235 if (test_time) {
2236 /* The user wanted to end the test after a period of time. */
2237 times_up = 0;
2238 bytes_remaining = 0;
2239 /* in previous revisions, we had the same code repeated throught */
2240 /* all the test suites. this was unnecessary, and meant more */
2241 /* work for me when I wanted to switch to POSIX signals, so I */
2242 /* have abstracted this out into a routine in netlib.c. if you */
2243 /* are experiencing signal problems, you might want to look */
2244 /* there. raj 11/94 */
2245 if (!no_control) {
2246 /* this is a netperf to netserver test, netserver will close
2247 to tell us the test is over, so use PAD_TIME to avoid
2248 causing the netserver fits. */
2249 start_timer(test_time + PAD_TIME);
2250 }
2251 else {
2252 /* this is a netperf to data source test, no PAD_TIME */
2253 start_timer(test_time);
2254 }
2255 }
2256 else {
2257 /* The tester wanted to recv a number of bytes. we don't do that
2258 in a TCP_MAERTS test. sorry. raj 2002-06-21 */
2259 printf("netperf: send_tcp_maerts: test must be timed\n");
2260 exit(1);
2261 }
2262
2263 /* The cpu_start routine will grab the current time and possibly */
2264 /* value of the idle counter for later use in measuring cpu */
2265 /* utilization and/or service demand and thruput. */
2266
2267 cpu_start(local_cpu_usage);
2268
2269 #ifdef WANT_INTERVALS
2270 INTERVALS_INIT();
2271 #endif /* WANT_INTERVALS */
2272
2273 /* before we start, initialize a few variables */
2274
2275 #ifdef WANT_DEMO
2276 if (demo_mode) {
2277 HIST_timestamp(demo_one_ptr);
2278 }
2279 #endif
2280
2281 /* the test will continue until we either get a zero-byte recv()
2282 on the socket or our failsafe timer expires. most of the time
2283 we trust that we get a zero-byte recieve from the socket. raj
2284 2002-06-21 */
2285
2286 #ifdef WANT_HISTOGRAM
2287 if (verbosity > 1) {
2288 /* timestamp just before we go into recv and then again just
2289 after we come out raj 8/94 */
2290 /* but only if we are actually going to display a histogram. raj
2291 2006-02-07 */
2292 HIST_timestamp(&time_one);
2293 }
2294 #endif /* WANT_HISTOGRAM */
2295
2296 while ((!times_up) && (len=recv(recv_socket,
2297 recv_ring->buffer_ptr,
2298 recv_size,
2299 0)) > 0 ) {
2300
2301 #ifdef WANT_HISTOGRAM
2302 if (verbosity > 1) {
2303 /* timestamp the exit from the recv call and update the histogram */
2304 HIST_timestamp(&time_two);
2305 HIST_add(time_hist,delta_micro(&time_one,&time_two));
2306 }
2307 #endif /* WANT_HISTOGRAM */
2308
2309 #ifdef DIRTY
2310 access_buffer(recv_ring->buffer_ptr,
2311 recv_size,
2312 loc_dirty_count,
2313 loc_clean_count);
2314 #endif /* DIRTY */
2315
2316 #ifdef WANT_DEMO
2317 DEMO_STREAM_INTERVAL(len);
2318 #endif
2319
2320 #ifdef WANT_INTERVALS
2321 INTERVALS_WAIT();
2322 #endif /* WANT_INTERVALS */
2323
2324 /* now we want to move our pointer to the next position in the */
2325 /* data buffer...we may also want to wrap back to the "beginning" */
2326 /* of the bufferspace, so we will mod the number of messages sent */
2327 /* by the recv width, and use that to calculate the offset to add */
2328 /* to the base pointer. */
2329 nummessages++;
2330 recv_ring = recv_ring->next;
2331 if (bytes_remaining) {
2332 bytes_remaining -= len;
2333 }
2334
2335 local_bytes_recvd += len;
2336
2337 #ifdef WANT_HISTOGRAM
2338 if (verbosity > 1) {
2339 /* make sure we timestamp just before we go into recv */
2340 /* raj 2004-06-15 */
2341 HIST_timestamp(&time_one);
2342 }
2343 #endif /* WANT_HISTOGRAM */
2344
2345 }
2346
2347 /* an EINTR is to be expected when this is a no_control test */
2348 if (((len < 0) || SOCKET_EINTR(len)) && (!no_control)) {
2349 perror("send_tcp_maerts: data recv error");
2350 printf("len was %d\n",len);
2351 exit(1);
2352 }
2353
2354 /* if we get here, it must mean we had a recv return of 0 before
2355 the watchdog timer expired, or the watchdog timer expired and
2356 this was a no_control test */
2357
2358 /* The test is over. Flush the buffers to the remote end. We do a
2359 graceful release to tell the remote we have all the data. */
2360
2361 /* but first, if the verbosity is greater than 1, find-out what */
2362 /* the TCP maximum segment_size was (if possible) */
2363 if (verbosity > 1) {
2364 tcp_mss = -1;
2365 get_tcp_info(recv_socket,&tcp_mss);
2366 }
2367
2368 if (shutdown(recv_socket,SHUT_WR) == SOCKET_ERROR) {
2369 perror("netperf: cannot shutdown tcp maerts socket");
2370 exit(1);
2371 }
2372
2373 stop_timer();
2374
2375 /* this call will always give us the local elapsed time for the
2376 test, and will also store-away the necessaries for cpu
2377 utilization */
2378
2379 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
2380 /* measured and how */
2381 /* long did we really */
2382 /* run? */
2383
2384 /* we are finished with the socket, so close it to prevent hitting */
2385 /* the limit on maximum open files. */
2386
2387 close(recv_socket);
2388
2389 if (!no_control) {
2390 /* Get the statistics from the remote end. The remote will have
2391 calculated service demand and all those interesting
2392 things. If it wasn't supposed to care, it will return obvious
2393 values. */
2394
2395 recv_response();
2396 if (!netperf_response.content.serv_errno) {
2397 if (debug)
2398 fprintf(where,"remote results obtained\n");
2399 }
2400 else {
2401 Set_errno(netperf_response.content.serv_errno);
2402 fprintf(where,
2403 "netperf: remote error %d",
2404 netperf_response.content.serv_errno);
2405 perror("");
2406 fflush(where);
2407
2408 exit(1);
2409 }
2410
2411 /* We now calculate what our thruput was for the test. In the
2412 future, we may want to include a calculation of the thruput
2413 measured by the remote, but it should be the case that for a
2414 TCP maerts test, that the two numbers should be *very*
2415 close... We calculate bytes_sent regardless of the way the
2416 test length was controlled. If it was time, we needed to,
2417 and if it was by bytes, the user may have specified a number
2418 of bytes that wasn't a multiple of the recv_size, so we
2419 really didn't recv what he asked for ;-) */
2420
2421 bytes_sent = ntohd(tcp_maerts_result->bytes_sent);
2422 }
2423 else {
2424 bytes_sent = (double)local_bytes_recvd;
2425 }
2426
2427
2428 thruput = calc_thruput(bytes_sent);
2429
2430 if (local_cpu_usage || remote_cpu_usage) {
2431 /* We must now do a little math for service demand and cpu */
2432 /* utilization for the system(s) */
2433 /* Of course, some of the information might be bogus because */
2434 /* there was no idle counter in the kernel(s). We need to make */
2435 /* a note of this for the user's benefit...*/
2436 if (local_cpu_usage) {
2437
2438 local_cpu_utilization = calc_cpu_util(0.0);
2439 local_service_demand = calc_service_demand(bytes_sent,
2440 0.0,
2441 0.0,
2442 0);
2443 }
2444 else {
2445 local_cpu_utilization = (float) -1.0;
2446 local_service_demand = (float) -1.0;
2447 }
2448
2449 if (remote_cpu_usage) {
2450
2451 remote_cpu_utilization = tcp_maerts_result->cpu_util;
2452 remote_service_demand = calc_service_demand(bytes_sent,
2453 0.0,
2454 remote_cpu_utilization,
2455 tcp_maerts_result->num_cpus);
2456 }
2457 else {
2458 remote_cpu_utilization = (float) -1.0;
2459 remote_service_demand = (float) -1.0;
2460 }
2461 }
2462 else {
2463 /* we were not measuring cpu, for the confidence stuff, we */
2464 /* should make it -1.0 */
2465 local_cpu_utilization = (float) -1.0;
2466 local_service_demand = (float) -1.0;
2467 remote_cpu_utilization = (float) -1.0;
2468 remote_service_demand = (float) -1.0;
2469 }
2470
2471 /* at this point, we want to calculate the confidence information. */
2472 /* if debugging is on, calculate_confidence will print-out the */
2473 /* parameters we pass it */
2474
2475 calculate_confidence(confidence_iteration,
2476 elapsed_time,
2477 thruput,
2478 local_cpu_utilization,
2479 remote_cpu_utilization,
2480 local_service_demand,
2481 remote_service_demand);
2482
2483
2484 confidence_iteration++;
2485 }
2486
2487 /* at this point, we have finished making all the runs that we */
2488 /* will be making. so, we should extract what the calcuated values */
2489 /* are for all the confidence stuff. we could make the values */
2490 /* global, but that seemed a little messy, and it did not seem worth */
2491 /* all the mucking with header files. so, we create a routine much */
2492 /* like calcualte_confidence, which just returns the mean values. */
2493 /* raj 11/94 */
2494
2495 retrieve_confident_values(&elapsed_time,
2496 &thruput,
2497 &local_cpu_utilization,
2498 &remote_cpu_utilization,
2499 &local_service_demand,
2500 &remote_service_demand);
2501
2502 /* We are now ready to print all the information. If the user */
2503 /* has specified zero-level verbosity, we will just print the */
2504 /* local service demand, or the remote service demand. If the */
2505 /* user has requested verbosity level 1, he will get the basic */
2506 /* "streamperf" numbers. If the user has specified a verbosity */
2507 /* of greater than 1, we will display a veritable plethora of */
2508 /* background information from outside of this block as it it */
2509 /* not cpu_measurement specific... */
2510
2511 if (confidence < 0) {
2512 /* we did not hit confidence, but were we asked to look for it? */
2513 if (iteration_max > 1) {
2514 display_confidence();
2515 }
2516 }
2517
2518 if (local_cpu_usage || remote_cpu_usage) {
2519 local_cpu_method = format_cpu_method(cpu_method);
2520 remote_cpu_method = format_cpu_method(tcp_maerts_result->cpu_method);
2521
2522 switch (verbosity) {
2523 case 0:
2524 if (local_cpu_usage) {
2525 fprintf(where,
2526 cpu_fmt_0,
2527 local_service_demand,
2528 local_cpu_method,
2529 ((print_headers) ||
2530 (result_brand == NULL)) ? "" : result_brand);
2531 }
2532 else {
2533 fprintf(where,
2534 cpu_fmt_0,
2535 remote_service_demand,
2536 remote_cpu_method,
2537 ((print_headers) ||
2538 (result_brand == NULL)) ? "" : result_brand);
2539 }
2540 break;
2541 case 1:
2542 case 2:
2543 if (print_headers) {
2544 fprintf(where,
2545 cpu_title,
2546 format_units(),
2547 local_cpu_method,
2548 remote_cpu_method);
2549 }
2550
2551 fprintf(where,
2552 cpu_fmt_1, /* the format string */
2553 rsr_size, /* remote recvbuf size */
2554 lss_size, /* local sendbuf size */
2555 send_size, /* how large were the recvs */
2556 elapsed_time, /* how long was the test */
2557 thruput, /* what was the xfer rate */
2558 local_cpu_utilization, /* local cpu */
2559 remote_cpu_utilization, /* remote cpu */
2560 local_service_demand, /* local service demand */
2561 remote_service_demand, /* remote service demand */
2562 ((print_headers) ||
2563 (result_brand == NULL)) ? "" : result_brand);
2564 break;
2565 }
2566 }
2567 else {
2568 /* The tester did not wish to measure service demand. */
2569
2570 switch (verbosity) {
2571 case 0:
2572 fprintf(where,
2573 tput_fmt_0,
2574 thruput,
2575 ((print_headers) ||
2576 (result_brand == NULL)) ? "" : result_brand);
2577 break;
2578 case 1:
2579 case 2:
2580 if (print_headers) {
2581 fprintf(where,tput_title,format_units());
2582 }
2583 fprintf(where,
2584 tput_fmt_1, /* the format string */
2585 lsr_size, /* local recvbuf size */
2586 rss_size, /* remot sendbuf size */
2587 send_size, /* how large were the recvs */
2588 elapsed_time, /* how long did it take */
2589 thruput, /* how fast did it go */
2590 ((print_headers) ||
2591 (result_brand == NULL)) ? "" : result_brand);
2592 break;
2593 }
2594 }
2595
2596 /* it would be a good thing to include information about some of the */
2597 /* other parameters that may have been set for this test, but at the */
2598 /* moment, I do not wish to figure-out all the formatting, so I will */
2599 /* just put this comment here to help remind me that it is something */
2600 /* that should be done at a later time. */
2601
2602 if (verbosity > 1) {
2603 /* The user wanted to know it all, so we will give it to him. */
2604 /* This information will include as much as we can find about */
2605 /* TCP statistics, the alignments of the sends and receives */
2606 /* and all that sort of rot... */
2607
2608 /* this stuff needs to be worked-out in the presence of confidence */
2609 /* intervals and multiple iterations of the test... raj 11/94 */
2610
2611 fprintf(where,
2612 ksink_fmt,
2613 "Bytes",
2614 "Bytes",
2615 "Bytes",
2616 local_recv_align,
2617 remote_recv_align,
2618 local_recv_offset,
2619 remote_recv_offset,
2620 bytes_sent,
2621 bytes_sent / (double)nummessages,
2622 nummessages,
2623 bytes_sent / (double)tcp_maerts_result->send_calls,
2624 tcp_maerts_result->send_calls);
2625 fprintf(where,
2626 ksink_fmt2,
2627 tcp_mss);
2628 fflush(where);
2629 #ifdef WANT_HISTOGRAM
2630 fprintf(where,"\n\nHistogram of time spent in recv() call.\n");
2631 fflush(where);
2632 HIST_report(time_hist);
2633 #endif /* WANT_HISTOGRAM */
2634 }
2635
2636 }
2637
2638
2639
2640 #ifdef HAVE_ICSC_EXS
2641
2642 #include <sys/exs.h>
2643
2644
2645 /* This routine implements the TCP unidirectional data transfer test */
2646 /* (a.k.a. stream) for the sockets interface. It receives its */
2647 /* parameters via global variables from the shell and writes its */
2648 /* output to the standard output. */
2649
2650 void
send_exs_tcp_stream(char remote_host[])2651 send_exs_tcp_stream(char remote_host[])
2652 {
2653
2654 char *tput_title = "\
2655 Recv Send Send \n\
2656 Socket Socket Message Elapsed \n\
2657 Size Size Size Time Throughput \n\
2658 bytes bytes bytes secs. %s/sec \n\n";
2659
2660 char *tput_fmt_0 =
2661 "%7.2f\n";
2662
2663 char *tput_fmt_1 =
2664 "%6d %6d %6d %-6.2f %7.2f \n";
2665
2666 char *cpu_title = "\
2667 Recv Send Send Utilization Service Demand\n\
2668 Socket Socket Message Elapsed Send Recv Send Recv\n\
2669 Size Size Size Time Throughput local remote local remote\n\
2670 bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
2671
2672 char *cpu_fmt_0 =
2673 "%6.3f %c\n";
2674
2675 char *cpu_fmt_1 =
2676 "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
2677
2678 char *ksink_fmt = "\n\
2679 Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
2680 Local Remote Local Remote Xfered Per Per\n\
2681 Send Recv Send Recv Send (avg) Recv (avg)\n\
2682 %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
2683
2684 char *ksink_fmt2 = "\n\
2685 Maximum\n\
2686 Segment\n\
2687 Size (bytes)\n\
2688 %6d\n";
2689
2690
2691 float elapsed_time;
2692
2693 /* what we want is to have a buffer space that is at least one */
2694 /* send-size greater than our send window. this will insure that we */
2695 /* are never trying to re-use a buffer that may still be in the hands */
2696 /* of the transport. This buffer will be malloc'd after we have found */
2697 /* the size of the local senc socket buffer. We will want to deal */
2698 /* with alignment and offset concerns as well. */
2699
2700 struct ring_elt *send_ring;
2701
2702 int len;
2703 unsigned int nummessages = 0;
2704 SOCKET send_socket;
2705 int bytes_remaining;
2706 int tcp_mss = -1; /* possibly uninitialized on printf far below */
2707
2708 exs_mhandle_t exs_mhandle;
2709 exs_qhandle_t exs_qhandle;
2710 #define NETPERF_EXS_PENDING 16
2711 int exs_aio_pending;
2712 int exs_aio_eagain;
2713 int exs_aio_dequeued;
2714 int exs_aio_dequeuecnt;
2715 int exs_evtcnt;
2716 #define NETPERF_EXS_QSIZE 128
2717 exs_event_t exs_evtvec[NETPERF_EXS_QSIZE];
2718
2719 /* with links like fddi, one can send > 32 bits worth of bytes */
2720 /* during a test... ;-) at some point, this should probably become a */
2721 /* 64bit integral type, but those are not entirely common yet */
2722
2723 double bytes_sent = 0.0;
2724
2725 float local_cpu_utilization;
2726 float local_service_demand;
2727 float remote_cpu_utilization;
2728 float remote_service_demand;
2729
2730 double thruput;
2731
2732 struct addrinfo *remote_res;
2733 struct addrinfo *local_res;
2734
2735 struct tcp_stream_request_struct *tcp_stream_request;
2736 struct tcp_stream_response_struct *tcp_stream_response;
2737 struct tcp_stream_results_struct *tcp_stream_result;
2738
2739 tcp_stream_request =
2740 (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data;
2741 tcp_stream_response =
2742 (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data;
2743 tcp_stream_result =
2744 (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data;
2745
2746 #if 0 /* def WANT_HISTOGRAM */
2747 time_hist = HIST_new();
2748 #endif /* WANT_HISTOGRAM */
2749 /* since we are now disconnected from the code that established the */
2750 /* control socket, and since we want to be able to use different */
2751 /* protocols and such, we are passed the name of the remote host and */
2752 /* must turn that into the test specific addressing information. */
2753
2754 /* complete_addrinfos will either succede or exit the process */
2755 complete_addrinfos(&remote_res,
2756 &local_res,
2757 remote_host,
2758 SOCK_STREAM,
2759 IPPROTO_TCP,
2760 0);
2761
2762 if ( print_headers ) {
2763 print_top_test_header("EXS TCP STREAM TEST",local_res,remote_res);
2764 }
2765
2766 send_ring = NULL;
2767 confidence_iteration = 1;
2768 init_stat();
2769
2770 /* initialize EXS API and create event queue */
2771 if (exs_init (EXS_VERSION) == -1) {
2772 perror ("netperf: send_exs_tcp_stream: exs_init failed");
2773 exit (1);
2774 }
2775
2776 if ((exs_qhandle = exs_qcreate (NETPERF_EXS_QSIZE)) == EXS_QHANDLE_INVALID) {
2777 perror ("netperf: send_exs_tcp_stream: exs_qcreate failed");
2778 exit (1);
2779 }
2780 if (debug) {
2781 fprintf (where, "send_exs_tcp_stream: qhandle=%d\n", exs_qhandle);
2782 }
2783
2784 /* we have a great-big while loop which controls the number of times */
2785 /* we run a particular test. this is for the calculation of a */
2786 /* confidence interval (I really should have stayed awake during */
2787 /* probstats :). If the user did not request confidence measurement */
2788 /* (no confidence is the default) then we will only go though the */
2789 /* loop once. the confidence stuff originates from the folks at IBM */
2790
2791 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
2792 (confidence_iteration <= iteration_min)) {
2793
2794 /* initialize a few counters. we have to remember that we might be */
2795 /* going through the loop more than once. */
2796
2797 nummessages = 0;
2798 bytes_sent = 0.0;
2799 times_up = 0;
2800
2801 /*set up the data socket */
2802 send_socket = create_data_socket(local_res);
2803
2804 if (send_socket == INVALID_SOCKET){
2805 perror("netperf: send_tcp_stream: tcp stream data socket");
2806 exit(1);
2807 }
2808
2809 if (debug) {
2810 fprintf(where,"send_tcp_stream: send_socket obtained...\n");
2811 }
2812
2813 /* at this point, we have either retrieved the socket buffer sizes, */
2814 /* or have tried to set them, so now, we may want to set the send */
2815 /* size based on that (because the user either did not use a -m */
2816 /* option, or used one with an argument of 0). If the socket buffer */
2817 /* size is not available, we will set the send size to 4KB - no */
2818 /* particular reason, just arbitrary... */
2819 if (send_size == 0) {
2820 if (lss_size > 0) {
2821 send_size = lss_size;
2822 }
2823 else {
2824 send_size = 4096;
2825 }
2826 }
2827
2828 /* set-up the data buffer ring with the requested alignment and offset. */
2829 /* note also that we have allocated a quantity */
2830 /* of memory that is at least one send-size greater than our socket */
2831 /* buffer size. We want to be sure that there are at least two */
2832 /* buffers allocated - this can be a bit of a problem when the */
2833 /* send_size is bigger than the socket size, so we must check... the */
2834 /* user may have wanted to explicitly set the "width" of our send */
2835 /* buffers, we should respect that wish... */
2836 if (send_width == 0) {
2837 send_width = (lss_size/send_size) + 1;
2838 if (send_width == 1) send_width++;
2839 }
2840
2841 if (send_ring == NULL) {
2842 /* only allocate the send ring once. this is a networking test, */
2843 /* not a memory allocation test. this way, we do not need a */
2844 /* deallocate_buffer_ring() routine, and I don't feel like */
2845 /* writing one anyway :) raj 11/94 */
2846 send_ring = allocate_exs_buffer_ring(send_width,
2847 send_size,
2848 local_send_align,
2849 local_send_offset,
2850 &exs_mhandle);
2851 }
2852
2853 /* If the user has requested cpu utilization measurements, we must */
2854 /* calibrate the cpu(s). We will perform this task within the tests */
2855 /* themselves. If the user has specified the cpu rate, then */
2856 /* calibrate_local_cpu will return rather quickly as it will have */
2857 /* nothing to do. If local_cpu_rate is zero, then we will go through */
2858 /* all the "normal" calibration stuff and return the rate back. */
2859
2860 if (local_cpu_usage) {
2861 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
2862 }
2863
2864 /* Tell the remote end to do a listen. The server alters the socket */
2865 /* paramters on the other side at this point, hence the reason for */
2866 /* all the values being passed in the setup message. If the user did */
2867 /* not specify any of the parameters, they will be passed as 0, which */
2868 /* will indicate to the remote that no changes beyond the system's */
2869 /* default should be used. Alignment is the exception, it will */
2870 /* default to 1, which will be no alignment alterations. */
2871
2872 netperf_request.content.request_type = DO_TCP_STREAM;
2873 tcp_stream_request->send_buf_size = rss_size_req;
2874 tcp_stream_request->recv_buf_size = rsr_size_req;
2875 tcp_stream_request->receive_size = recv_size;
2876 tcp_stream_request->no_delay = rem_nodelay;
2877 tcp_stream_request->recv_alignment = remote_recv_align;
2878 tcp_stream_request->recv_offset = remote_recv_offset;
2879 tcp_stream_request->measure_cpu = remote_cpu_usage;
2880 tcp_stream_request->cpu_rate = remote_cpu_rate;
2881 if (test_time) {
2882 tcp_stream_request->test_length = test_time;
2883 }
2884 else {
2885 tcp_stream_request->test_length = test_bytes;
2886 }
2887 tcp_stream_request->so_rcvavoid = rem_rcvavoid;
2888 tcp_stream_request->so_sndavoid = rem_sndavoid;
2889 #ifdef DIRTY
2890 tcp_stream_request->dirty_count = rem_dirty_count;
2891 tcp_stream_request->clean_count = rem_clean_count;
2892 #endif /* DIRTY */
2893 tcp_stream_request->port = atoi(remote_data_port);
2894 tcp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
2895 if (debug > 1) {
2896 fprintf(where,
2897 "netperf: send_tcp_stream: requesting TCP stream test\n");
2898 }
2899
2900 send_request();
2901
2902 /* The response from the remote will contain all of the relevant */
2903 /* socket parameters for this test type. We will put them back into */
2904 /* the variables here so they can be displayed if desired. The */
2905 /* remote will have calibrated CPU if necessary, and will have done */
2906 /* all the needed set-up we will have calibrated the cpu locally */
2907 /* before sending the request, and will grab the counter value right*/
2908 /* after the connect returns. The remote will grab the counter right*/
2909 /* after the accept call. This saves the hassle of extra messages */
2910 /* being sent for the TCP tests. */
2911
2912 recv_response();
2913
2914 if (!netperf_response.content.serv_errno) {
2915 if (debug)
2916 fprintf(where,"remote listen done.\n");
2917 rsr_size = tcp_stream_response->recv_buf_size;
2918 rss_size = tcp_stream_response->send_buf_size;
2919 rem_nodelay = tcp_stream_response->no_delay;
2920 remote_cpu_usage= tcp_stream_response->measure_cpu;
2921 remote_cpu_rate = tcp_stream_response->cpu_rate;
2922
2923 /* we have to make sure that the server port number is in */
2924 /* network order */
2925 set_port_number(remote_res,(short)tcp_stream_response->data_port_number);
2926
2927 rem_rcvavoid = tcp_stream_response->so_rcvavoid;
2928 rem_sndavoid = tcp_stream_response->so_sndavoid;
2929 }
2930 else {
2931 Set_errno(netperf_response.content.serv_errno);
2932 fprintf(where,
2933 "netperf: remote error %d",
2934 netperf_response.content.serv_errno);
2935 perror("");
2936 fflush(where);
2937
2938 exit(1);
2939 }
2940
2941 #if 0 /* def WANT_DEMO */
2942 DEMO_STREAM_SETUP(lss_size,rsr_size)
2943 #endif
2944
2945 /*Connect up to the remote port on the data socket */
2946 if (connect(send_socket,
2947 remote_res->ai_addr,
2948 remote_res->ai_addrlen) == INVALID_SOCKET){
2949 perror("netperf: send_tcp_stream: data socket connect failed");
2950 exit(1);
2951 }
2952
2953 /* Data Socket set-up is finished. If there were problems, either */
2954 /* the connect would have failed, or the previous response would */
2955 /* have indicated a problem. I failed to see the value of the */
2956 /* extra message after the accept on the remote. If it failed, */
2957 /* we'll see it here. If it didn't, we might as well start pumping */
2958 /* data. */
2959
2960 /* Set-up the test end conditions. For a stream test, they can be */
2961 /* either time or byte-count based. */
2962
2963 if (test_time) {
2964 /* The user wanted to end the test after a period of time. */
2965 times_up = 0;
2966 bytes_remaining = 0;
2967 /* in previous revisions, we had the same code repeated throught */
2968 /* all the test suites. this was unnecessary, and meant more */
2969 /* work for me when I wanted to switch to POSIX signals, so I */
2970 /* have abstracted this out into a routine in netlib.c. if you */
2971 /* are experiencing signal problems, you might want to look */
2972 /* there. raj 11/94 */
2973 start_timer(test_time);
2974 }
2975 else {
2976 /* The tester wanted to send a number of bytes. */
2977 bytes_remaining = test_bytes;
2978 times_up = 1;
2979 }
2980
2981 /* The cpu_start routine will grab the current time and possibly */
2982 /* value of the idle counter for later use in measuring cpu */
2983 /* utilization and/or service demand and thruput. */
2984
2985 cpu_start(local_cpu_usage);
2986
2987 #if 0 /* def WANT_INTERVALS */
2988 INTERVALS_INIT();
2989 #endif /* WANT_INTERVALS */
2990
2991 /* before we start, initialize a few variables */
2992
2993 #if 0 /* def WANT_DEMO */
2994 if (demo_mode) {
2995 HIST_timestamp(demo_one_ptr);
2996 }
2997 #endif
2998
2999
3000 /* We use an "OR" to control test execution. When the test is */
3001 /* controlled by time, the byte count check will always return false. */
3002 /* When the test is controlled by byte count, the time test will */
3003 /* always return false. When the test is finished, the whole */
3004 /* expression will go false and we will stop sending data. */
3005
3006 exs_aio_pending = 0;
3007 exs_aio_eagain = 0;
3008 exs_aio_dequeuecnt = 0;
3009
3010 while ((!times_up) || (bytes_remaining > 0)) {
3011
3012 #ifdef DIRTY
3013 access_buffer(send_ring->buffer_ptr,
3014 send_size,
3015 loc_dirty_count,
3016 loc_clean_count);
3017 #endif /* DIRTY */
3018
3019 #if 0 /* def WANT_HISTOGRAM */
3020 /* timestamp just before we go into send and then again just after */
3021 /* we come out raj 8/94 */
3022 HIST_timestamp(&time_one);
3023 #endif /* WANT_HISTOGRAM */
3024
3025
3026 /* post up to NETPERF_EXS_PENDING I/Os */
3027 while ((exs_aio_pending < NETPERF_EXS_PENDING) &&
3028 (exs_send (send_socket, send_ring->buffer_ptr, send_size,
3029 0, exs_qhandle, (exs_ahandle_t)-1, exs_mhandle) == 0)) {
3030 exs_aio_pending++;
3031
3032 /* now we want to move our pointer to the next
3033 position in the data buffer...we may also want to
3034 wrap back to the "beginning" of the bufferspace, so
3035 we will mod the number of messages sent by the send
3036 width, and use that to calculate the offset to add
3037 to the base pointer. */
3038
3039 nummessages++;
3040 send_ring = send_ring->next;
3041 if (bytes_remaining) {
3042 bytes_remaining -= send_size;
3043 }
3044 }
3045
3046 /* check exs_send result */
3047 if (exs_aio_pending < NETPERF_EXS_PENDING) {
3048 /* standard flow control case */
3049 if (errno == EAGAIN)
3050 exs_aio_eagain++;
3051 /* case of times_up */
3052 else if (errno == EINTR)
3053 break;
3054 /* strange, let's stop */
3055 else {
3056 perror ("netperf: exs_send error");
3057 exit (1);
3058 }
3059 }
3060
3061 /* dequeue events with "threshold" on 1/2 posted */
3062 exs_aio_dequeued =
3063 exs_qdequeue (exs_qhandle, exs_evtvec,
3064 -(exs_aio_pending>>1), NULL);
3065 exs_aio_dequeuecnt++;
3066
3067 /* check exs_dequeue result */
3068 if (exs_aio_dequeued < 0) {
3069 /* case of times_up */
3070 if (errno == EINTR)
3071 break;
3072 /* strange, let's stop */
3073 else {
3074 perror ("netperf: exs_send error");
3075 exit (1);
3076 }
3077 }
3078 /* update number of pending I/Os */
3079 else {
3080 exs_aio_pending -= exs_aio_dequeued;
3081 }
3082
3083
3084 #if 0 /* def WANT_HISTOGRAM */
3085 /* timestamp the exit from the send call and update the histogram */
3086 HIST_timestamp(&time_two);
3087 HIST_add(time_hist,delta_micro(&time_one,&time_two));
3088 #endif /* WANT_HISTOGRAM */
3089
3090 #if 0 /* def WANT_DEMO */
3091 DEMO_STREAM_INTERVAL(send_size);
3092 #endif
3093
3094 #if 0 /* def WANT_INTERVALS */
3095 INTERVALS_WAIT();
3096 #endif /* WANT_INTERVALS */
3097
3098 }
3099
3100 /* Collect the last completion events */
3101 exs_aio_dequeued =
3102 exs_qdequeue (exs_qhandle, exs_evtvec, -exs_aio_pending, NULL);
3103 exs_aio_dequeuecnt++;
3104 /* check exs_dequeue result and update number of pending I/Os */
3105 if (exs_aio_dequeued < 0) {
3106 perror ("netperf: exs_send error");
3107 exit (1);
3108 }
3109 exs_aio_pending -= exs_aio_dequeued;
3110
3111 /* Display some async I/O debug info */
3112 if (debug) {
3113 fprintf (where, "send_exs_tcp_stream: "
3114 "aio sent=%d eagain=%d dequeue=%d pending=%d\n",
3115 nummessages, exs_aio_eagain, exs_aio_dequeuecnt, exs_aio_pending);
3116 }
3117
3118 /* The test is over. Flush the buffers to the remote end. We do a */
3119 /* graceful release to insure that all data has been taken by the */
3120 /* remote. */
3121
3122 /* but first, if the verbosity is greater than 1, find-out what */
3123 /* the TCP maximum segment_size was (if possible) */
3124 if (verbosity > 1) {
3125 tcp_mss = -1;
3126 get_tcp_info(send_socket,&tcp_mss);
3127 }
3128
3129 if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) {
3130 perror("netperf: cannot shutdown tcp stream socket");
3131 exit(1);
3132 }
3133
3134 /* hang a recv() off the socket to block until the remote has */
3135 /* brought all the data up into the application. it will do a */
3136 /* shutdown to cause a FIN to be sent our way. We will assume that */
3137 /* any exit from the recv() call is good... raj 4/93 */
3138
3139 recv(send_socket, send_ring->buffer_ptr, send_size, 0);
3140
3141 /* this call will always give us the elapsed time for the test, and */
3142 /* will also store-away the necessaries for cpu utilization */
3143
3144 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
3145 /* measured and how */
3146 /* long did we really */
3147 /* run? */
3148
3149 /* we are finished with the socket, so close it to prevent hitting */
3150 /* the limit on maximum open files. */
3151
3152 close(send_socket);
3153
3154 /* Get the statistics from the remote end. The remote will have */
3155 /* calculated service demand and all those interesting things. If it */
3156 /* wasn't supposed to care, it will return obvious values. */
3157
3158 recv_response();
3159 if (!netperf_response.content.serv_errno) {
3160 if (debug)
3161 fprintf(where,"remote results obtained\n");
3162 }
3163 else {
3164 Set_errno(netperf_response.content.serv_errno);
3165 fprintf(where,
3166 "netperf: remote error %d",
3167 netperf_response.content.serv_errno);
3168 perror("");
3169 fflush(where);
3170
3171 exit(1);
3172 }
3173
3174 /* We now calculate what our thruput was for the test. In the future, */
3175 /* we may want to include a calculation of the thruput measured by */
3176 /* the remote, but it should be the case that for a TCP stream test, */
3177 /* that the two numbers should be *very* close... We calculate */
3178 /* bytes_sent regardless of the way the test length was controlled. */
3179 /* If it was time, we needed to, and if it was by bytes, the user may */
3180 /* have specified a number of bytes that wasn't a multiple of the */
3181 /* send_size, so we really didn't send what he asked for ;-) */
3182
3183 bytes_sent = ntohd(tcp_stream_result->bytes_received);
3184
3185 thruput = calc_thruput(bytes_sent);
3186
3187 if (local_cpu_usage || remote_cpu_usage) {
3188 /* We must now do a little math for service demand and cpu */
3189 /* utilization for the system(s) */
3190 /* Of course, some of the information might be bogus because */
3191 /* there was no idle counter in the kernel(s). We need to make */
3192 /* a note of this for the user's benefit...*/
3193 if (local_cpu_usage) {
3194
3195 local_cpu_utilization = calc_cpu_util(0.0);
3196 local_service_demand = calc_service_demand(bytes_sent,
3197 0.0,
3198 0.0,
3199 0);
3200 }
3201 else {
3202 local_cpu_utilization = (float) -1.0;
3203 local_service_demand = (float) -1.0;
3204 }
3205
3206 if (remote_cpu_usage) {
3207
3208 remote_cpu_utilization = tcp_stream_result->cpu_util;
3209 remote_service_demand = calc_service_demand(bytes_sent,
3210 0.0,
3211 remote_cpu_utilization,
3212 tcp_stream_result->num_cpus);
3213 }
3214 else {
3215 remote_cpu_utilization = (float) -1.0;
3216 remote_service_demand = (float) -1.0;
3217 }
3218 }
3219 else {
3220 /* we were not measuring cpu, for the confidence stuff, we */
3221 /* should make it -1.0 */
3222 local_cpu_utilization = (float) -1.0;
3223 local_service_demand = (float) -1.0;
3224 remote_cpu_utilization = (float) -1.0;
3225 remote_service_demand = (float) -1.0;
3226 }
3227
3228 /* at this point, we want to calculate the confidence information. */
3229 /* if debugging is on, calculate_confidence will print-out the */
3230 /* parameters we pass it */
3231
3232 calculate_confidence(confidence_iteration,
3233 elapsed_time,
3234 thruput,
3235 local_cpu_utilization,
3236 remote_cpu_utilization,
3237 local_service_demand,
3238 remote_service_demand);
3239
3240
3241 confidence_iteration++;
3242 }
3243
3244 /* at this point, we have finished making all the runs that we */
3245 /* will be making. so, we should extract what the calcuated values */
3246 /* are for all the confidence stuff. we could make the values */
3247 /* global, but that seemed a little messy, and it did not seem worth */
3248 /* all the mucking with header files. so, we create a routine much */
3249 /* like calcualte_confidence, which just returns the mean values. */
3250 /* raj 11/94 */
3251
3252 retrieve_confident_values(&elapsed_time,
3253 &thruput,
3254 &local_cpu_utilization,
3255 &remote_cpu_utilization,
3256 &local_service_demand,
3257 &remote_service_demand);
3258
3259 /* We are now ready to print all the information. If the user */
3260 /* has specified zero-level verbosity, we will just print the */
3261 /* local service demand, or the remote service demand. If the */
3262 /* user has requested verbosity level 1, he will get the basic */
3263 /* "streamperf" numbers. If the user has specified a verbosity */
3264 /* of greater than 1, we will display a veritable plethora of */
3265 /* background information from outside of this block as it it */
3266 /* not cpu_measurement specific... */
3267
3268 if (confidence < 0) {
3269 /* we did not hit confidence, but were we asked to look for it? */
3270 if (iteration_max > 1) {
3271 display_confidence();
3272 }
3273 }
3274
3275 if (local_cpu_usage || remote_cpu_usage) {
3276 local_cpu_method = format_cpu_method(cpu_method);
3277 remote_cpu_method = format_cpu_method(tcp_stream_result->cpu_method);
3278
3279 switch (verbosity) {
3280 case 0:
3281 if (local_cpu_usage) {
3282 fprintf(where,
3283 cpu_fmt_0,
3284 local_service_demand,
3285 local_cpu_method);
3286 }
3287 else {
3288 fprintf(where,
3289 cpu_fmt_0,
3290 remote_service_demand,
3291 remote_cpu_method);
3292 }
3293 break;
3294 case 1:
3295 case 2:
3296 if (print_headers) {
3297 fprintf(where,
3298 cpu_title,
3299 format_units(),
3300 local_cpu_method,
3301 remote_cpu_method);
3302 }
3303
3304 fprintf(where,
3305 cpu_fmt_1, /* the format string */
3306 rsr_size, /* remote recvbuf size */
3307 lss_size, /* local sendbuf size */
3308 send_size, /* how large were the sends */
3309 elapsed_time, /* how long was the test */
3310 thruput, /* what was the xfer rate */
3311 local_cpu_utilization, /* local cpu */
3312 remote_cpu_utilization, /* remote cpu */
3313 local_service_demand, /* local service demand */
3314 remote_service_demand); /* remote service demand */
3315 break;
3316 }
3317 }
3318 else {
3319 /* The tester did not wish to measure service demand. */
3320
3321 switch (verbosity) {
3322 case 0:
3323 fprintf(where,
3324 tput_fmt_0,
3325 thruput);
3326 break;
3327 case 1:
3328 case 2:
3329 if (print_headers) {
3330 fprintf(where,tput_title,format_units());
3331 }
3332 fprintf(where,
3333 tput_fmt_1, /* the format string */
3334 rsr_size, /* remote recvbuf size */
3335 lss_size, /* local sendbuf size */
3336 send_size, /* how large were the sends */
3337 elapsed_time, /* how long did it take */
3338 thruput);/* how fast did it go */
3339 break;
3340 }
3341 }
3342
3343 /* it would be a good thing to include information about some of the */
3344 /* other parameters that may have been set for this test, but at the */
3345 /* moment, I do not wish to figure-out all the formatting, so I will */
3346 /* just put this comment here to help remind me that it is something */
3347 /* that should be done at a later time. */
3348
3349 if (verbosity > 1) {
3350 /* The user wanted to know it all, so we will give it to him. */
3351 /* This information will include as much as we can find about */
3352 /* TCP statistics, the alignments of the sends and receives */
3353 /* and all that sort of rot... */
3354
3355 /* this stuff needs to be worked-out in the presence of confidence */
3356 /* intervals and multiple iterations of the test... raj 11/94 */
3357
3358 fprintf(where,
3359 ksink_fmt,
3360 "Bytes",
3361 "Bytes",
3362 "Bytes",
3363 local_send_align,
3364 remote_recv_align,
3365 local_send_offset,
3366 remote_recv_offset,
3367 bytes_sent,
3368 bytes_sent / (double)nummessages,
3369 nummessages,
3370 bytes_sent / (double)tcp_stream_result->recv_calls,
3371 tcp_stream_result->recv_calls);
3372 fprintf(where,
3373 ksink_fmt2,
3374 tcp_mss);
3375 fflush(where);
3376 #if 0 /* def WANT_HISTOGRAM */
3377 fprintf(where,"\n\nHistogram of time spent in send() call.\n");
3378 fflush(where);
3379 HIST_report(time_hist);
3380 #endif /* WANT_HISTOGRAM */
3381 }
3382
3383 }
3384
3385 #endif /* HAVE_ICSC_EXS */
3386
3387
3388
3389 #if defined(HAVE_SENDFILE)
3390
3391 #if defined(QUICK_SENDPATH)
3392
3393 /*
3394 * a temporary stub for the sendpath() system call
3395 * which is defined & implemented in the kernel
3396 * but which has no libc stub.
3397 */
3398 #include <sys/types.h>
3399 #include <sys/scall_define.h>
3400 #include <sys/uio.h>
3401
3402 ssize_t
sendpath(int s,char * path,off_t offset,size_t nbytes,const struct iovec * hdtrl,int flags)3403 sendpath(int s, char *path, off_t offset, size_t nbytes,
3404 const struct iovec *hdtrl, int flags)
3405 {
3406 return syscall(SYS_sendpath, s, path, offset, nbytes, hdtrl, flags);
3407 }
3408 #endif /* QUICK_SENDPATH */
3409
3410 /* This routine implements the TCP unidirectional data transfer test
3411 (a.k.a. stream) for the sockets interface using the sendfile()
3412 system call - TCP_SENDFILE. It receives its parameters via global
3413 variables from the shell and writes its output to the standard
3414 output. Basically, this is the same test as the send_tcp_stream()
3415 logic and we even tell the remote to do a TCP_STREAM test since for
3416 all it knows, nothig is different. */
3417
3418 void
sendfile_tcp_stream(remote_host)3419 sendfile_tcp_stream(remote_host)
3420 char remote_host[];
3421 {
3422
3423 char *tput_title = "\
3424 Recv Send Send \n\
3425 Socket Socket Message Elapsed \n\
3426 Size Size Size Time Throughput \n\
3427 bytes bytes bytes secs. %s/sec \n\n";
3428
3429 char *tput_fmt_0 =
3430 "%7.2f\n";
3431
3432 char *tput_fmt_1 =
3433 "%6d %6d %6d %-6.2f %7.2f \n";
3434
3435 char *cpu_title = "\
3436 Recv Send Send Utilization Service Demand\n\
3437 Socket Socket Message Elapsed Send Recv Send Recv\n\
3438 Size Size Size Time Throughput local remote local remote\n\
3439 bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
3440
3441 char *cpu_fmt_0 =
3442 "%6.3f %c\n";
3443 char *cpu_fmt_1 =
3444 "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
3445
3446 char *ksink_fmt = "\n\
3447 Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
3448 Local Remote Local Remote Xfered Per Per\n\
3449 Send Recv Send Recv Send (avg) Recv (avg)\n\
3450 %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
3451
3452 char *ksink_fmt2 = "\n\
3453 Maximum\n\
3454 Segment\n\
3455 Size (bytes)\n\
3456 %6d\n";
3457
3458 float elapsed_time;
3459
3460 /* what we want is to have a buffer space that is at least one */
3461 /* send-size greater than our send window. this will insure that we */
3462 /* are never trying to re-use a buffer that may still be in the hands */
3463 /* of the transport. This buffer will be malloc'd after we have found */
3464 /* the size of the local senc socket buffer. We will want to deal */
3465 /* with alignment and offset concerns as well. */
3466
3467 struct sendfile_ring_elt *send_ring;
3468
3469 int len;
3470 unsigned int nummessages = 0;
3471 SOCKET send_socket;
3472 int bytes_remaining;
3473 int tcp_mss = -1; /* possibly uninitialized on printf far below */
3474
3475 /* with links like fddi, one can send > 32 bits worth of bytes */
3476 /* during a test... ;-) at some point, this should probably become a */
3477 /* 64bit integral type, but those are not entirely common yet */
3478 double bytes_sent = 0.0;
3479
3480 float local_cpu_utilization;
3481 float local_service_demand;
3482 float remote_cpu_utilization;
3483 float remote_service_demand;
3484
3485 double thruput;
3486
3487 struct addrinfo *remote_res;
3488 struct addrinfo *local_res;
3489 struct sockaddr_in server;
3490
3491 #if defined(__linux) || defined(__sun__)
3492 off_t scratch_offset; /* the linux sendfile() call will update
3493 the offset variable, which is
3494 something we do _not_ want to happen
3495 to the value in the send_ring! so, we
3496 have to use a scratch variable. */
3497 #endif /* __linux || defined(__sun__) */
3498 #if defined (USE_OSX)
3499 off_t scratch_len; /* Darwin 9.x need a value-result parameter */
3500 #endif
3501 #if defined (__sun__)
3502 size_t scratch_len; /* the sun sendfilev() needs a place to
3503 tell us how many bytes were written,
3504 even though it also returns the value */
3505 sendfilevec_t sv;
3506 #endif /* __sun__ */
3507
3508 struct tcp_stream_request_struct *tcp_stream_request;
3509 struct tcp_stream_response_struct *tcp_stream_response;
3510 struct tcp_stream_results_struct *tcp_stream_result;
3511
3512 tcp_stream_request =
3513 (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data;
3514 tcp_stream_response =
3515 (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data;
3516 tcp_stream_result =
3517 (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data;
3518
3519 #ifdef WANT_HISTOGRAM
3520 if (verbosity > 1) {
3521 time_hist = HIST_new();
3522 }
3523 #endif /* WANT_HISTOGRAM */
3524
3525 /* since we are now disconnected from the code that established the */
3526 /* control socket, and since we want to be able to use different */
3527 /* protocols and such, we are passed the name of the remote host and */
3528 /* must turn that into the test specific addressing information. */
3529
3530 bzero((char *)&server,
3531 sizeof(server));
3532
3533 complete_addrinfos(&remote_res,
3534 &local_res,
3535 remote_host,
3536 SOCK_STREAM,
3537 IPPROTO_TCP,
3538 0);
3539
3540 if ( print_headers ) {
3541 /* we want to have some additional, interesting information in */
3542 /* the headers. we know some of it here, but not all, so we will */
3543 /* only print the test title here and will print the results */
3544 /* titles after the test is finished */
3545 #ifdef QUICK_SENDPATH
3546 print_top_test_header("TCP SENDPATH TEST",local_res,remote_res);
3547 #else
3548 print_top_test_header("TCP SENDFILE TEST",local_res,remote_res);
3549 #endif /* QUICK_SENDPATH */
3550 }
3551 send_ring = NULL;
3552 confidence_iteration = 1;
3553 init_stat();
3554
3555 /* we have a great-big while loop which controls the number of times */
3556 /* we run a particular test. this is for the calculation of a */
3557 /* confidence interval (I really should have stayed awake during */
3558 /* probstats :). If the user did not request confidence measurement */
3559 /* (no confidence is the default) then we will only go though the */
3560 /* loop once. the confidence stuff originates from the folks at IBM */
3561
3562 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
3563 (confidence_iteration <= iteration_min)) {
3564
3565 /* initialize a few counters. we have to remember that we might be */
3566 /* going through the loop more than once. */
3567
3568 nummessages = 0;
3569 bytes_sent = 0.0;
3570 times_up = 0;
3571
3572 /* set up the data socket */
3573 send_socket = create_data_socket(local_res);
3574
3575 if (send_socket == INVALID_SOCKET){
3576 perror("netperf: sendfile_tcp_stream: tcp stream data socket");
3577 exit(1);
3578 }
3579
3580 if (debug) {
3581 fprintf(where,"sendfile_tcp_stream: send_socket obtained...\n");
3582 }
3583
3584 #if defined(TCP_CORK)
3585 /* should this even be here?!? */
3586 if (loc_tcpcork != 0) {
3587 /* the user wishes for us to set TCP_CORK on the socket */
3588 int one = 1;
3589 if (setsockopt(send_socket,
3590 getprotobyname("tcp")->p_proto,
3591 TCP_CORK,
3592 (char *)&one,
3593 sizeof(one)) == SOCKET_ERROR) {
3594 perror("netperf: sendfile_tcp_stream: tcp_cork");
3595 exit(1);
3596 }
3597 if (debug) {
3598 fprintf(where,"sendfile_tcp_stream: tcp_cork...\n");
3599 }
3600 }
3601
3602 #endif /* TCP_CORK */
3603
3604 /* at this point, we have either retrieved the socket buffer sizes, */
3605 /* or have tried to set them, so now, we may want to set the send */
3606 /* size based on that (because the user either did not use a -m */
3607 /* option, or used one with an argument of 0). If the socket buffer */
3608 /* size is not available, we will set the send size to 4KB - no */
3609 /* particular reason, just arbitrary... */
3610
3611 /*check for file size/ min file size here? create file here/ back out???*/
3612
3613 if (send_size == 0) {
3614 if (lss_size > 0) {
3615 send_size = lss_size;
3616 }
3617 else {
3618 send_size = 4096;
3619 }
3620 }
3621
3622 /* set-up the data buffer ring with the requested alignment and
3623 offset. note also that we have allocated a quantity of memory
3624 that is at least one send-size greater than our socket buffer
3625 size. We want to be sure that there are at least two buffers
3626 allocated - this can be a bit of a problem when the send_size
3627 is bigger than the socket size, so we must check... the user
3628 may have wanted to explicitly set the "width" of our send
3629 buffers, we should respect that wish... */
3630
3631 /*sendring -> an offset index that will shift the starting point of the*/
3632 /*section of the file sent throughout the file*/
3633
3634 if (send_width == 0) {
3635 send_width = (lss_size/send_size) + 1;
3636 if (send_width == 1) send_width++;
3637 }
3638
3639 if (send_ring == NULL) {
3640
3641 /* only allocate the send ring once. this is a networking test,
3642 not a memory allocation test. this way, we do not need a
3643 deallocate_buffer_ring() routine, and I don't feel like
3644 writing one anyway :) raj 11/94 */
3645
3646 send_ring = alloc_sendfile_buf_ring(send_width,
3647 send_size,
3648 local_send_align,
3649 local_send_offset);
3650 }
3651
3652 /* If the user has requested cpu utilization measurements, we must
3653 calibrate the cpu(s). We will perform this task within the
3654 tests themselves. If the user has specified the cpu rate, then
3655 calibrate_local_cpu will return rather quickly as it will have
3656 nothing to do. If local_cpu_rate is zero, then we will go
3657 through all the "normal" calibration stuff and return the rate
3658 back. */
3659
3660 if (local_cpu_usage) {
3661 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
3662 }
3663
3664 /* Tell the remote end to do a listen. The server alters the
3665 socket paramters on the other side at this point, hence the
3666 reason for all the values being passed in the setup
3667 message. If the user did not specify any of the parameters,
3668 they will be passed as 0, which will indicate to the remote
3669 that no changes beyond the system's default should be
3670 used. Alignment is the exception, it will default to 1, which
3671 will be no alignment alterations. */
3672
3673 netperf_request.content.request_type = DO_TCP_STREAM;
3674 tcp_stream_request->send_buf_size = rss_size_req;
3675 tcp_stream_request->recv_buf_size = rsr_size_req;
3676 tcp_stream_request->receive_size = recv_size;
3677 tcp_stream_request->no_delay = rem_nodelay;
3678 tcp_stream_request->recv_alignment = remote_recv_align;
3679 tcp_stream_request->recv_offset = remote_recv_offset;
3680 tcp_stream_request->measure_cpu = remote_cpu_usage;
3681 tcp_stream_request->cpu_rate = remote_cpu_rate;
3682
3683 if (test_time) {
3684 tcp_stream_request->test_length = test_time;
3685 }
3686 else {
3687 tcp_stream_request->test_length = test_bytes;
3688 }
3689
3690 tcp_stream_request->so_rcvavoid = rem_rcvavoid;
3691 tcp_stream_request->so_sndavoid = rem_sndavoid;
3692
3693 #ifdef DIRTY
3694 tcp_stream_request->dirty_count = rem_dirty_count;
3695 tcp_stream_request->clean_count = rem_clean_count;
3696 #endif /* DIRTY */
3697 tcp_stream_request->port = atoi(remote_data_port);
3698 tcp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
3699
3700 if (debug > 1) {
3701 fprintf(where,
3702 "netperf: send_tcp_stream: requesting TCP stream test\n");
3703 }
3704
3705 send_request();
3706
3707 /* The response from the remote will contain all of the relevant
3708 socket parameters for this test type. We will put them back
3709 into the variables here so they can be displayed if desired.
3710 The remote will have calibrated CPU if necessary, and will have
3711 done all the needed set-up we will have calibrated the cpu
3712 locally before sending the request, and will grab the counter
3713 value right after the connect returns. The remote will grab the
3714 counter right after the accept call. This saves the hassle of
3715 extra messages being sent for the TCP tests. */
3716
3717 recv_response();
3718
3719 if (!netperf_response.content.serv_errno) {
3720 if (debug)
3721 fprintf(where,"remote listen done.\n");
3722 rsr_size = tcp_stream_response->recv_buf_size;
3723 rss_size = tcp_stream_response->send_buf_size;
3724 rem_nodelay = tcp_stream_response->no_delay;
3725 remote_cpu_usage= tcp_stream_response->measure_cpu;
3726 remote_cpu_rate = tcp_stream_response->cpu_rate;
3727
3728 /* we have to make sure that the server port number is in */
3729 /* network order */
3730 set_port_number(remote_res,(short)tcp_stream_response->data_port_number);
3731 rem_rcvavoid = tcp_stream_response->so_rcvavoid;
3732 rem_sndavoid = tcp_stream_response->so_sndavoid;
3733 }
3734 else {
3735 Set_errno(netperf_response.content.serv_errno);
3736 fprintf(where,
3737 "netperf: remote error %d",
3738 netperf_response.content.serv_errno);
3739 perror("");
3740 fflush(where);
3741
3742 exit(1);
3743 }
3744
3745 #ifdef WANT_DEMO
3746 DEMO_STREAM_SETUP(lss_size,rsr_size)
3747 #endif
3748
3749 /*Connect up to the remote port on the data socket */
3750 if (connect(send_socket,
3751 remote_res->ai_addr,
3752 remote_res->ai_addrlen) == INVALID_SOCKET){
3753 perror("netperf: send_tcp_stream: data socket connect failed");
3754 printf(" port: %d\n",ntohs(server.sin_port));
3755 exit(1);
3756 }
3757
3758 /* Data Socket set-up is finished. If there were problems, either
3759 the connect would have failed, or the previous response would
3760 have indicated a problem. I failed to see the value of the
3761 extra message after the accept on the remote. If it failed,
3762 we'll see it here. If it didn't, we might as well start pumping
3763 data. */
3764
3765 /* Set-up the test end conditions. For a stream test, they can be */
3766 /* either time or byte-count based. */
3767
3768 if (test_time) {
3769 /* The user wanted to end the test after a period of time. */
3770 times_up = 0;
3771 bytes_remaining = 0;
3772
3773 /* in previous revisions, we had the same code repeated throught
3774 all the test suites. this was unnecessary, and meant more
3775 work for me when I wanted to switch to POSIX signals, so I
3776 have abstracted this out into a routine in netlib.c. if you
3777 are experiencing signal problems, you might want to look
3778 there. raj 11/94 */
3779
3780 start_timer(test_time);
3781 }
3782 else {
3783 /* The tester wanted to send a number of bytes. */
3784 bytes_remaining = test_bytes;
3785 times_up = 1;
3786 }
3787
3788 /* The cpu_start routine will grab the current time and possibly */
3789 /* value of the idle counter for later use in measuring cpu */
3790 /* utilization and/or service demand and thruput. */
3791
3792 cpu_start(local_cpu_usage);
3793
3794 #ifdef WANT_INTERVALS
3795 INTERVALS_INIT();
3796 #endif /* WANT_INTERVALS */
3797
3798
3799 /* before we start, initialize a few variables */
3800
3801 #ifdef WANT_DEMO
3802 if (demo_mode) {
3803 HIST_timestamp(demo_one_ptr);
3804 }
3805 #endif
3806
3807 /* We use an "OR" to control test execution. When the test is
3808 controlled by time, the byte count check will always return
3809 false. When the test is controlled by byte count, the time test
3810 will always return false. When the test is finished, the whole
3811 expression will go false and we will stop sending data. */
3812
3813 while ((!times_up) || (bytes_remaining > 0)) {
3814
3815 /* the sendfile_tcp_stream test does not support making the buffers
3816 dirty. 08/2000 */
3817
3818 #ifdef WANT_HISTOGRAM
3819 if (verbosity > 1) {
3820 /* timestamp just before we go into sendfile() and then again
3821 just after we come out raj 08/2000 */
3822 /* but only if we are actually going to display a histogram */
3823 HIST_timestamp(&time_one);
3824 }
3825 #endif /* WANT_HISTOGRAM */
3826
3827 /* you can look at netlib.h for a description of the fields we
3828 are passing to sendfile(). 08/2000 */
3829 #ifdef QUICK_SENDPATH
3830 if ((len=sendpath(send_socket,
3831 fill_file,
3832 send_ring->offset,
3833 send_ring->length,
3834 send_ring->hdtrl,
3835 send_ring->flags)) != send_size)
3836 #elif defined(__linux)
3837 scratch_offset = send_ring->offset;
3838 if ((len=sendfile(send_socket,
3839 send_ring->fildes,
3840 &scratch_offset, /* modified after the call! */
3841 send_ring->length)) != send_size)
3842 #elif defined (__sun__)
3843 /* We must call with SFV_NOWAIT and a large file size (>= 16MB) to
3844 get zero-copy, as well as compiling with -D_LARGEFILE_SOURCE
3845 -D_FILE_OFFSET_BITS=64 */
3846 sv.sfv_fd = send_ring->fildes;
3847 sv.sfv_flag = SFV_NOWAIT;
3848 sv.sfv_off = send_ring->offset;
3849 sv.sfv_len = send_ring->length;
3850 if ((len = sendfilev(send_socket, &sv, 1, &scratch_len)) != send_size)
3851 #elif defined(__FreeBSD__)
3852 /* so close to HP-UX and yet so far away... :) */
3853 if ((sendfile(send_ring->fildes,
3854 send_socket,
3855 send_ring->offset,
3856 send_ring->length,
3857 NULL,
3858 (off_t *)&len,
3859 send_ring->flags) != 0) ||
3860 (len != send_size))
3861 #elif defined(USE_OSX)
3862 scratch_len = send_ring->length;
3863 if ((sendfile(send_ring->fildes,
3864 send_socket,
3865 send_ring->offset,
3866 (off_t *)&scratch_len,
3867 NULL,
3868 send_ring->flags) != 0) ||
3869 (scratch_len != send_size))
3870 #else /* original sendile HP-UX */
3871 if ((len=sendfile(send_socket,
3872 send_ring->fildes,
3873 send_ring->offset,
3874 send_ring->length,
3875 send_ring->hdtrl,
3876 send_ring->flags)) != send_size)
3877 #endif /* QUICK_SENDPATH */
3878 {
3879 /* the test was interrupted, must be the end of test. the
3880 send_tcp_stream code has some WIN32 ifdefs that we do not
3881 need here. */
3882 if ((len >=0) || SOCKET_EINTR(len)) {
3883 break;
3884 }
3885 perror("netperf: data send error: sendfile");
3886 fprintf(stderr,
3887 "len was %d send_size was %d\n",
3888 len,
3889 send_size);
3890 fflush(stderr);
3891 exit(1);
3892 }
3893
3894 /* offset += len;*/
3895
3896 #ifdef WANT_HISTOGRAM
3897 if (verbosity > 1) {
3898 /* timestamp the exit from the send call and update the
3899 histogram */
3900
3901 HIST_timestamp(&time_two);
3902 HIST_add(time_hist,delta_micro(&time_one,&time_two));
3903 }
3904 #endif /* WANT_HISTOGRAM */
3905
3906 #ifdef WANT_DEMO
3907 DEMO_STREAM_INTERVAL(send_size);
3908 #endif
3909
3910 #ifdef WANT_INTERVALS
3911 INTERVALS_WAIT();
3912 #endif /* WANT_INTERVALS */
3913
3914 /* now we want to move our pointer to the next position in the */
3915 /* data buffer...we may also want to wrap back to the "beginning" */
3916 /* of the bufferspace, so we will mod the number of messages sent */
3917 /* by the send width, and use that to calculate the offset to add */
3918 /* to the base pointer. */
3919
3920 nummessages++;
3921 send_ring = send_ring->next;
3922 if (bytes_remaining) {
3923 bytes_remaining -= send_size;
3924 }
3925 }
3926
3927 /* The test is over. Flush the buffers to the remote end. We do a
3928 graceful release to insure that all data has been taken by the
3929 remote. */
3930
3931 /* but first, if the verbosity is greater than 1, find-out what */
3932 /* the TCP maximum segment_size was (if possible) */
3933 if (verbosity > 1) {
3934 tcp_mss = -1;
3935 get_tcp_info(send_socket,&tcp_mss);
3936 }
3937
3938 if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) {
3939 perror("netperf: cannot shutdown tcp stream socket");
3940 exit(1);
3941 }
3942
3943 /* hang a recv() off the socket to block until the remote has */
3944 /* brought all the data up into the application. it will do a */
3945 /* shutdown to cause a FIN to be sent our way. We will assume that */
3946 /* any exit from the recv() call is good... raj 4/93 */
3947
3948 /* since we are using sendfile() instead of send, we have no
3949 scratch buffer from the send_ring to use for the
3950 receive. however, since we "know" that the recv should be
3951 returning zero bytes (not that we are making the checks we
3952 should) we can pass the address of the flags field. raj 08/2000
3953 */
3954
3955 recv(send_socket,
3956 &(send_ring->flags),
3957 sizeof(send_ring->flags),
3958 0);
3959
3960 /* this call will always give us the elapsed time for the test, and */
3961 /* will also store-away the necessaries for cpu utilization */
3962
3963 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
3964 /* measured and how */
3965 /* long did we really */
3966 /* run? */
3967
3968 /* we are finished with the socket, so close it to prevent hitting */
3969 /* the limit on maximum open files. */
3970
3971 close(send_socket);
3972
3973 /* Get the statistics from the remote end. The remote will have */
3974 /* calculated service demand and all those interesting things. If it */
3975 /* wasn't supposed to care, it will return obvious values. */
3976
3977 recv_response();
3978
3979 if (!netperf_response.content.serv_errno) {
3980 if (debug)
3981 fprintf(where,"remote results obtained\n");
3982 }
3983
3984 else {
3985 Set_errno(netperf_response.content.serv_errno);
3986 fprintf(where,
3987 "netperf: remote error %d",
3988 netperf_response.content.serv_errno);
3989 perror("");
3990 fflush(where);
3991
3992 exit(1);
3993 }
3994
3995 /* We now calculate what our thruput was for the test. In the future, */
3996 /* we may want to include a calculation of the thruput measured by */
3997 /* the remote, but it should be the case that for a TCP stream test, */
3998 /* that the two numbers should be *very* close... We calculate */
3999 /* bytes_sent regardless of the way the test length was controlled. */
4000 /* If it was time, we needed to, and if it was by bytes, the user may */
4001 /* have specified a number of bytes that wasn't a multiple of the */
4002 /* send_size, so we really didn't send what he asked for ;-) */
4003
4004 bytes_sent = ntohd(tcp_stream_result->bytes_received);
4005
4006 thruput = calc_thruput(bytes_sent);
4007
4008 if (local_cpu_usage || remote_cpu_usage) {
4009
4010 /* We must now do a little math for service demand and cpu */
4011 /* utilization for the system(s) */
4012 /* Of course, some of the information might be bogus because */
4013 /* there was no idle counter in the kernel(s). We need to make */
4014 /* a note of this for the user's benefit...*/
4015 if (local_cpu_usage) {
4016
4017 local_cpu_utilization = calc_cpu_util(0.0);
4018 local_service_demand = calc_service_demand(bytes_sent,
4019 0.0,
4020 0.0,
4021 0);
4022 }
4023 else {
4024 local_cpu_utilization = (float) -1.0;
4025 local_service_demand = (float) -1.0;
4026 }
4027
4028 if (remote_cpu_usage) {
4029
4030 remote_cpu_utilization = tcp_stream_result->cpu_util;
4031 remote_service_demand = calc_service_demand(bytes_sent,
4032 0.0,
4033 remote_cpu_utilization,
4034 tcp_stream_result->num_cpus);
4035 }
4036 else {
4037 remote_cpu_utilization = (float) -1.0;
4038 remote_service_demand = (float) -1.0;
4039 }
4040 }
4041 else {
4042 /* we were not measuring cpu, for the confidence stuff, we */
4043 /* should make it -1.0 */
4044 local_cpu_utilization = (float) -1.0;
4045 local_service_demand = (float) -1.0;
4046 remote_cpu_utilization = (float) -1.0;
4047 remote_service_demand = (float) -1.0;
4048 }
4049
4050 /* at this point, we want to calculate the confidence information. */
4051 /* if debugging is on, calculate_confidence will print-out the */
4052 /* parameters we pass it */
4053
4054 calculate_confidence(confidence_iteration,
4055 elapsed_time,
4056 thruput,
4057 local_cpu_utilization,
4058 remote_cpu_utilization,
4059 local_service_demand,
4060 remote_service_demand);
4061
4062 confidence_iteration++;
4063 }
4064
4065 /* at this point, we have finished making all the runs that we */
4066 /* will be making. so, we should extract what the calcuated values */
4067 /* are for all the confidence stuff. we could make the values */
4068 /* global, but that seemed a little messy, and it did not seem worth */
4069 /* all the mucking with header files. so, we create a routine much */
4070 /* like calcualte_confidence, which just returns the mean values. */
4071 /* raj 11/94 */
4072
4073 retrieve_confident_values(&elapsed_time,
4074 &thruput,
4075 &local_cpu_utilization,
4076 &remote_cpu_utilization,
4077 &local_service_demand,
4078 &remote_service_demand);
4079
4080 /* We are now ready to print all the information. If the user */
4081 /* has specified zero-level verbosity, we will just print the */
4082 /* local service demand, or the remote service demand. If the */
4083 /* user has requested verbosity level 1, he will get the basic */
4084 /* "streamperf" numbers. If the user has specified a verbosity */
4085 /* of greater than 1, we will display a veritable plethora of */
4086 /* background information from outside of this block as it it */
4087 /* not cpu_measurement specific... */
4088
4089 if (confidence < 0) {
4090 /* we did not hit confidence, but were we asked to look for it? */
4091 if (iteration_max > 1) {
4092 display_confidence();
4093 }
4094 }
4095
4096 if (local_cpu_usage || remote_cpu_usage) {
4097 local_cpu_method = format_cpu_method(cpu_method);
4098 remote_cpu_method = format_cpu_method(tcp_stream_result->cpu_method);
4099
4100 switch (verbosity) {
4101 case 0:
4102
4103 if (local_cpu_usage) {
4104 fprintf(where,
4105 cpu_fmt_0,
4106 local_service_demand,
4107 local_cpu_method);
4108 }
4109
4110 else {
4111 fprintf(where,
4112 cpu_fmt_0,
4113 remote_service_demand,
4114 remote_cpu_method);
4115 }
4116
4117 break;
4118
4119 case 1:
4120 case 2:
4121 if (print_headers) {
4122 fprintf(where,
4123 cpu_title,
4124 format_units(),
4125 local_cpu_method,
4126 remote_cpu_method);
4127 }
4128
4129 fprintf(where,
4130 cpu_fmt_1, /* the format string */
4131 rsr_size, /* remote recvbuf size */
4132 lss_size, /* local sendbuf size */
4133 send_size, /* how large were the sends */
4134 elapsed_time, /* how long was the test */
4135 thruput, /* what was the xfer rate */
4136 local_cpu_utilization, /* local cpu */
4137 remote_cpu_utilization, /* remote cpu */
4138 local_service_demand, /* local service demand */
4139 remote_service_demand); /* remote service demand */
4140 break;
4141 }
4142
4143 }
4144
4145 else {
4146 /* The tester did not wish to measure service demand. */
4147
4148 switch (verbosity) {
4149
4150 case 0:
4151
4152 fprintf(where,
4153 tput_fmt_0,
4154 thruput);
4155 break;
4156
4157 case 1:
4158 case 2:
4159
4160 if (print_headers) {
4161 fprintf(where,tput_title,format_units());
4162 }
4163
4164 fprintf(where,
4165 tput_fmt_1, /* the format string */
4166 rsr_size, /* remote recvbuf size */
4167 lss_size, /* local sendbuf size */
4168 send_size, /* how large were the sends */
4169 elapsed_time, /* how long did it take */
4170 thruput);/* how fast did it go */
4171 break;
4172 }
4173 }
4174
4175 /* it would be a good thing to include information about some of the */
4176 /* other parameters that may have been set for this test, but at the */
4177 /* moment, I do not wish to figure-out all the formatting, so I will */
4178 /* just put this comment here to help remind me that it is something */
4179 /* that should be done at a later time. */
4180
4181 if (verbosity > 1) {
4182
4183 /* The user wanted to know it all, so we will give it to him. */
4184 /* This information will include as much as we can find about */
4185 /* TCP statistics, the alignments of the sends and receives */
4186 /* and all that sort of rot... */
4187
4188 /* this stuff needs to be worked-out in the presence of confidence */
4189 /* intervals and multiple iterations of the test... raj 11/94 */
4190
4191 fprintf(where,
4192 ksink_fmt,
4193 "Bytes",
4194 "Bytes",
4195 "Bytes",
4196 local_send_align,
4197 remote_recv_align,
4198 local_send_offset,
4199 remote_recv_offset,
4200 bytes_sent,
4201 bytes_sent / (double)nummessages,
4202 nummessages,
4203 bytes_sent / (double)tcp_stream_result->recv_calls,
4204 tcp_stream_result->recv_calls);
4205
4206 fprintf(where,
4207 ksink_fmt2,
4208 tcp_mss);
4209
4210 fflush(where);
4211
4212 #ifdef WANT_HISTOGRAM
4213
4214 fprintf(where,"\n\nHistogram of time spent in send() call.\n");
4215 fflush(where);
4216 HIST_report(time_hist);
4217 #endif /* WANT_HISTOGRAM */
4218 }
4219 }
4220
4221 #endif /* HAVE_SENDFILE */
4222
4223 /* This is the server-side routine for the tcp stream test. It is */
4224 /* implemented as one routine. I could break things-out somewhat, but */
4225 /* didn't feel it was necessary. */
4226
4227 void
recv_tcp_stream()4228 recv_tcp_stream()
4229 {
4230
4231 struct sockaddr_storage myaddr_in, peeraddr_in;
4232 SOCKET s_listen,s_data;
4233 netperf_socklen_t addrlen;
4234 int len;
4235 unsigned int receive_calls;
4236 float elapsed_time;
4237 double bytes_received;
4238
4239 struct ring_elt *recv_ring;
4240
4241 struct addrinfo *local_res;
4242 char local_name[BUFSIZ];
4243 char port_buffer[PORTBUFSIZE];
4244
4245 #ifdef DO_SELECT
4246 fd_set readfds;
4247 struct timeval timeout;
4248 #endif /* DO_SELECT */
4249
4250 struct tcp_stream_request_struct *tcp_stream_request;
4251 struct tcp_stream_response_struct *tcp_stream_response;
4252 struct tcp_stream_results_struct *tcp_stream_results;
4253
4254 #ifdef DO_SELECT
4255 FD_ZERO(&readfds);
4256 timeout.tv_sec = 1;
4257 timeout.tv_usec = 0;
4258 #endif /* DO_SELECT */
4259
4260 tcp_stream_request =
4261 (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data;
4262 tcp_stream_response =
4263 (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data;
4264 tcp_stream_results =
4265 (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data;
4266
4267 if (debug) {
4268 fprintf(where,"netserver: recv_tcp_stream: entered...\n");
4269 fflush(where);
4270 }
4271
4272 /* We want to set-up the listen socket with all the desired */
4273 /* parameters and then let the initiator know that all is ready. If */
4274 /* socket size defaults are to be used, then the initiator will have */
4275 /* sent us 0's. If the socket sizes cannot be changed, then we will */
4276 /* send-back what they are. If that information cannot be determined, */
4277 /* then we send-back -1's for the sizes. If things go wrong for any */
4278 /* reason, we will drop back ten yards and punt. */
4279
4280 /* If anything goes wrong, we want the remote to know about it. It */
4281 /* would be best if the error that the remote reports to the user is */
4282 /* the actual error we encountered, rather than some bogus unexpected */
4283 /* response type message. */
4284
4285 if (debug) {
4286 fprintf(where,"recv_tcp_stream: setting the response type...\n");
4287 fflush(where);
4288 }
4289
4290 netperf_response.content.response_type = TCP_STREAM_RESPONSE;
4291
4292 if (debug) {
4293 fprintf(where,"recv_tcp_stream: the response type is set...\n");
4294 fflush(where);
4295 }
4296
4297 /* We now alter the message_ptr variable to be at the desired */
4298 /* alignment with the desired offset. */
4299
4300 if (debug) {
4301 fprintf(where,"recv_tcp_stream: requested alignment of %d\n",
4302 tcp_stream_request->recv_alignment);
4303 fflush(where);
4304 }
4305
4306 /* create_data_socket expects to find some things in the global */
4307 /* variables, so set the globals based on the values in the request. */
4308 /* once the socket has been created, we will set the response values */
4309 /* based on the updated value of those globals. raj 7/94 */
4310 lss_size_req = tcp_stream_request->send_buf_size;
4311 lsr_size_req = tcp_stream_request->recv_buf_size;
4312 loc_nodelay = tcp_stream_request->no_delay;
4313 loc_rcvavoid = tcp_stream_request->so_rcvavoid;
4314 loc_sndavoid = tcp_stream_request->so_sndavoid;
4315
4316 set_hostname_and_port(local_name,
4317 port_buffer,
4318 nf_to_af(tcp_stream_request->ipfamily),
4319 tcp_stream_request->port);
4320
4321 local_res = complete_addrinfo(local_name,
4322 local_name,
4323 port_buffer,
4324 nf_to_af(tcp_stream_request->ipfamily),
4325 SOCK_STREAM,
4326 IPPROTO_TCP,
4327 0);
4328
4329 s_listen = create_data_socket(local_res);
4330
4331 if (s_listen == INVALID_SOCKET) {
4332 netperf_response.content.serv_errno = errno;
4333 send_response();
4334 exit(1);
4335 }
4336
4337 #ifdef WIN32
4338 /* The test timer can fire during operations on the listening socket,
4339 so to make the start_timer below work we have to move
4340 it to close s_listen while we are blocked on accept. */
4341 win_kludge_socket2 = s_listen;
4342 #endif
4343
4344 /* what sort of sizes did we end-up with? */
4345 if (tcp_stream_request->receive_size == 0) {
4346 if (lsr_size > 0) {
4347 recv_size = lsr_size;
4348 }
4349 else {
4350 recv_size = 4096;
4351 }
4352 }
4353 else {
4354 recv_size = tcp_stream_request->receive_size;
4355 }
4356
4357 /* we want to set-up our recv_ring in a manner analagous to what we */
4358 /* do on the sending side. this is more for the sake of symmetry */
4359 /* than for the needs of say copy avoidance, but it might also be */
4360 /* more realistic - this way one could conceivably go with a */
4361 /* double-buffering scheme when taking the data an putting it into */
4362 /* the filesystem or something like that. raj 7/94 */
4363
4364 if (recv_width == 0) {
4365 recv_width = (lsr_size/recv_size) + 1;
4366 if (recv_width == 1) recv_width++;
4367 }
4368
4369 recv_ring = allocate_buffer_ring(recv_width,
4370 recv_size,
4371 tcp_stream_request->recv_alignment,
4372 tcp_stream_request->recv_offset);
4373
4374 if (debug) {
4375 fprintf(where,"recv_tcp_stream: receive alignment and offset set...\n");
4376 fflush(where);
4377 }
4378
4379 /* Now, let's set-up the socket to listen for connections */
4380 if (listen(s_listen, 5) == SOCKET_ERROR) {
4381 netperf_response.content.serv_errno = errno;
4382 close(s_listen);
4383 send_response();
4384
4385 exit(1);
4386 }
4387
4388
4389 /* now get the port number assigned by the system */
4390 addrlen = sizeof(myaddr_in);
4391 if (getsockname(s_listen,
4392 (struct sockaddr *)&myaddr_in,
4393 &addrlen) == SOCKET_ERROR){
4394 netperf_response.content.serv_errno = errno;
4395 close(s_listen);
4396 send_response();
4397
4398 exit(1);
4399 }
4400
4401 /* Now myaddr_in contains the port and the internet address this is */
4402 /* returned to the sender also implicitly telling the sender that the */
4403 /* socket buffer sizing has been done. */
4404
4405 tcp_stream_response->data_port_number =
4406 (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
4407 netperf_response.content.serv_errno = 0;
4408
4409 /* But wait, there's more. If the initiator wanted cpu measurements, */
4410 /* then we must call the calibrate routine, which will return the max */
4411 /* rate back to the initiator. If the CPU was not to be measured, or */
4412 /* something went wrong with the calibration, we will return a -1 to */
4413 /* the initiator. */
4414
4415 tcp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */
4416 if (tcp_stream_request->measure_cpu) {
4417 tcp_stream_response->measure_cpu = 1;
4418 tcp_stream_response->cpu_rate =
4419 calibrate_local_cpu(tcp_stream_request->cpu_rate);
4420 }
4421 else {
4422 tcp_stream_response->measure_cpu = 0;
4423 }
4424
4425 /* before we send the response back to the initiator, pull some of */
4426 /* the socket parms from the globals */
4427 tcp_stream_response->send_buf_size = lss_size;
4428 tcp_stream_response->recv_buf_size = lsr_size;
4429 tcp_stream_response->no_delay = loc_nodelay;
4430 tcp_stream_response->so_rcvavoid = loc_rcvavoid;
4431 tcp_stream_response->so_sndavoid = loc_sndavoid;
4432 tcp_stream_response->receive_size = recv_size;
4433
4434 send_response();
4435
4436 addrlen = sizeof(peeraddr_in);
4437
4438 if ((s_data=accept(s_listen,
4439 (struct sockaddr *)&peeraddr_in,
4440 &addrlen)) == INVALID_SOCKET) {
4441 /* Let's just punt. The remote will be given some information */
4442 close(s_listen);
4443 exit(1);
4444 }
4445
4446 #ifdef KLUDGE_SOCKET_OPTIONS
4447 /* this is for those systems which *INCORRECTLY* fail to pass */
4448 /* attributes across an accept() call. Including this goes against */
4449 /* my better judgement :( raj 11/95 */
4450
4451 kludge_socket_options(s_data);
4452
4453 #endif /* KLUDGE_SOCKET_OPTIONS */
4454
4455 /* Now it's time to start receiving data on the connection. We will */
4456 /* first grab the apropriate counters and then start grabbing. */
4457
4458 cpu_start(tcp_stream_request->measure_cpu);
4459
4460 /* The loop will exit when the sender does a shutdown, which will */
4461 /* return a length of zero */
4462
4463 /* there used to be an #ifdef DIRTY call to access_buffer() here,
4464 but we have switched from accessing the buffer before the recv()
4465 call to accessing the buffer after the recv() call. The
4466 accessing before was, IIRC, related to having dirty data when
4467 doing page-flipping copy avoidance. */
4468
4469 bytes_received = 0;
4470 receive_calls = 0;
4471
4472 while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) {
4473 if (len == SOCKET_ERROR )
4474 {
4475 netperf_response.content.serv_errno = errno;
4476 send_response();
4477 exit(1);
4478 }
4479 bytes_received += len;
4480 receive_calls++;
4481
4482 #ifdef DIRTY
4483 /* we access the buffer after the recv() call now, rather than before */
4484 access_buffer(recv_ring->buffer_ptr,
4485 recv_size,
4486 tcp_stream_request->dirty_count,
4487 tcp_stream_request->clean_count);
4488 #endif /* DIRTY */
4489
4490
4491 /* move to the next buffer in the recv_ring */
4492 recv_ring = recv_ring->next;
4493
4494 #ifdef PAUSE
4495 sleep(1);
4496 #endif /* PAUSE */
4497
4498 #ifdef DO_SELECT
4499 FD_SET(s_data,&readfds);
4500 select(s_data+1,&readfds,NULL,NULL,&timeout);
4501 #endif /* DO_SELECT */
4502
4503 }
4504
4505 /* perform a shutdown to signal the sender that */
4506 /* we have received all the data sent. raj 4/93 */
4507
4508 if (shutdown(s_data,SHUT_WR) == SOCKET_ERROR) {
4509 netperf_response.content.serv_errno = errno;
4510 send_response();
4511 exit(1);
4512 }
4513
4514 cpu_stop(tcp_stream_request->measure_cpu,&elapsed_time);
4515
4516 /* send the results to the sender */
4517
4518 if (debug) {
4519 fprintf(where,
4520 "recv_tcp_stream: got %g bytes\n",
4521 bytes_received);
4522 fprintf(where,
4523 "recv_tcp_stream: got %d recvs\n",
4524 receive_calls);
4525 fflush(where);
4526 }
4527
4528 tcp_stream_results->bytes_received = htond(bytes_received);
4529 tcp_stream_results->elapsed_time = elapsed_time;
4530 tcp_stream_results->recv_calls = receive_calls;
4531
4532 tcp_stream_results->cpu_method = cpu_method;
4533 tcp_stream_results->num_cpus = lib_num_loc_cpus;
4534
4535 if (tcp_stream_request->measure_cpu) {
4536 tcp_stream_results->cpu_util = calc_cpu_util(0.0);
4537 };
4538
4539 if (debug) {
4540 fprintf(where,
4541 "recv_tcp_stream: test complete, sending results.\n");
4542 fprintf(where,
4543 " bytes_received %g receive_calls %d\n",
4544 bytes_received,
4545 receive_calls);
4546 fprintf(where,
4547 " len %d\n",
4548 len);
4549 fflush(where);
4550 }
4551
4552 send_response();
4553
4554 /* we are now done with the sockets */
4555 close(s_data);
4556 close(s_listen);
4557
4558 }
4559
4560 /* This is the server-side routine for the tcp maerts test. It is
4561 implemented as one routine. I could break things-out somewhat, but
4562 didn't feel it was necessary. */
4563
4564 void
recv_tcp_maerts()4565 recv_tcp_maerts()
4566 {
4567
4568 struct sockaddr_storage myaddr_in, peeraddr_in;
4569 struct addrinfo *local_res;
4570 char local_name[BUFSIZ];
4571 char port_buffer[PORTBUFSIZE];
4572
4573 SOCKET s_listen,s_data;
4574 netperf_socklen_t addrlen;
4575 int len;
4576 unsigned int send_calls;
4577 float elapsed_time;
4578 double bytes_sent = 0.0 ;
4579
4580 struct ring_elt *send_ring;
4581
4582 struct tcp_maerts_request_struct *tcp_maerts_request;
4583 struct tcp_maerts_response_struct *tcp_maerts_response;
4584 struct tcp_maerts_results_struct *tcp_maerts_results;
4585
4586 tcp_maerts_request =
4587 (struct tcp_maerts_request_struct *)netperf_request.content.test_specific_data;
4588 tcp_maerts_response =
4589 (struct tcp_maerts_response_struct *)netperf_response.content.test_specific_data;
4590 tcp_maerts_results =
4591 (struct tcp_maerts_results_struct *)netperf_response.content.test_specific_data;
4592
4593 if (debug) {
4594 fprintf(where,"netserver: recv_tcp_maerts: entered...\n");
4595 fflush(where);
4596 }
4597
4598 /* We want to set-up the listen socket with all the desired
4599 parameters and then let the initiator know that all is ready. If
4600 socket size defaults are to be used, then the initiator will have
4601 sent us 0's. If the socket sizes cannot be changed, then we will
4602 send-back what they are. If that information cannot be
4603 determined, then we send-back -1's for the sizes. If things go
4604 wrong for any reason, we will drop back ten yards and punt. */
4605
4606 /* If anything goes wrong, we want the remote to know about it. It
4607 would be best if the error that the remote reports to the user is
4608 the actual error we encountered, rather than some bogus
4609 unexpected response type message. */
4610
4611 if (debug) {
4612 fprintf(where,"recv_tcp_maerts: setting the response type...\n");
4613 fflush(where);
4614 }
4615
4616 netperf_response.content.response_type = TCP_MAERTS_RESPONSE;
4617
4618 if (debug) {
4619 fprintf(where,"recv_tcp_maerts: the response type is set...\n");
4620 fflush(where);
4621 }
4622
4623 /* We now alter the message_ptr variable to be at the desired */
4624 /* alignment with the desired offset. */
4625
4626 if (debug) {
4627 fprintf(where,"recv_tcp_maerts: requested alignment of %d\n",
4628 tcp_maerts_request->send_alignment);
4629 fflush(where);
4630 }
4631
4632 /* Grab a socket to listen on, and then listen on it. */
4633
4634 if (debug) {
4635 fprintf(where,"recv_tcp_maerts: grabbing a socket...\n");
4636 fflush(where);
4637 }
4638
4639 /* create_data_socket expects to find some things in the global */
4640 /* variables, so set the globals based on the values in the request. */
4641 /* once the socket has been created, we will set the response values */
4642 /* based on the updated value of those globals. raj 7/94 */
4643 lss_size_req = tcp_maerts_request->send_buf_size;
4644 lsr_size_req = tcp_maerts_request->recv_buf_size;
4645 loc_nodelay = tcp_maerts_request->no_delay;
4646 loc_rcvavoid = tcp_maerts_request->so_rcvavoid;
4647 loc_sndavoid = tcp_maerts_request->so_sndavoid;
4648
4649 set_hostname_and_port(local_name,
4650 port_buffer,
4651 nf_to_af(tcp_maerts_request->ipfamily),
4652 tcp_maerts_request->port);
4653
4654 local_res = complete_addrinfo(local_name,
4655 local_name,
4656 port_buffer,
4657 nf_to_af(tcp_maerts_request->ipfamily),
4658 SOCK_STREAM,
4659 IPPROTO_TCP,
4660 0);
4661
4662 s_listen = create_data_socket(local_res);
4663
4664 if (s_listen == INVALID_SOCKET) {
4665 netperf_response.content.serv_errno = errno;
4666 send_response();
4667 exit(1);
4668 }
4669
4670 #ifdef WIN32
4671 /* The test timer can fire during operations on the listening socket,
4672 so to make the start_timer below work we have to move
4673 it to close s_listen while we are blocked on accept. */
4674 win_kludge_socket2 = s_listen;
4675 #endif
4676
4677
4678 /* what sort of sizes did we end-up with? */
4679 if (tcp_maerts_request->send_size == 0) {
4680 if (lss_size > 0) {
4681 send_size = lss_size;
4682 }
4683 else {
4684 send_size = 4096;
4685 }
4686 }
4687 else {
4688 send_size = tcp_maerts_request->send_size;
4689 }
4690
4691 /* we want to set-up our recv_ring in a manner analagous to what we */
4692 /* do on the recving side. this is more for the sake of symmetry */
4693 /* than for the needs of say copy avoidance, but it might also be */
4694 /* more realistic - this way one could conceivably go with a */
4695 /* double-buffering scheme when taking the data an putting it into */
4696 /* the filesystem or something like that. raj 7/94 */
4697
4698 if (send_width == 0) {
4699 send_width = (lsr_size/send_size) + 1;
4700 if (send_width == 1) send_width++;
4701 }
4702
4703 send_ring = allocate_buffer_ring(send_width,
4704 send_size,
4705 tcp_maerts_request->send_alignment,
4706 tcp_maerts_request->send_offset);
4707
4708 if (debug) {
4709 fprintf(where,"recv_tcp_maerts: receive alignment and offset set...\n");
4710 fflush(where);
4711 }
4712
4713 /* Now, let's set-up the socket to listen for connections */
4714 if (listen(s_listen, 5) == SOCKET_ERROR) {
4715 netperf_response.content.serv_errno = errno;
4716 close(s_listen);
4717 send_response();
4718
4719 exit(1);
4720 }
4721
4722
4723 /* now get the port number assigned by the system */
4724 addrlen = sizeof(myaddr_in);
4725 if (getsockname(s_listen,
4726 (struct sockaddr *)&myaddr_in,
4727 &addrlen) == SOCKET_ERROR){
4728 netperf_response.content.serv_errno = errno;
4729 close(s_listen);
4730 send_response();
4731
4732 exit(1);
4733 }
4734
4735 /* Now myaddr_in contains the port and the internet address this is */
4736 /* returned to the sender also implicitly telling the sender that the */
4737 /* socket buffer sizing has been done. */
4738
4739 tcp_maerts_response->data_port_number =
4740 (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
4741 netperf_response.content.serv_errno = 0;
4742
4743 /* But wait, there's more. If the initiator wanted cpu measurements, */
4744 /* then we must call the calibrate routine, which will return the max */
4745 /* rate back to the initiator. If the CPU was not to be measured, or */
4746 /* something went wrong with the calibration, we will return a -1 to */
4747 /* the initiator. */
4748
4749 tcp_maerts_response->cpu_rate = (float)0.0; /* assume no cpu */
4750 if (tcp_maerts_request->measure_cpu) {
4751 tcp_maerts_response->measure_cpu = 1;
4752 tcp_maerts_response->cpu_rate =
4753 calibrate_local_cpu(tcp_maerts_request->cpu_rate);
4754 }
4755 else {
4756 tcp_maerts_response->measure_cpu = 0;
4757 }
4758
4759 /* before we send the response back to the initiator, pull some of */
4760 /* the socket parms from the globals */
4761 tcp_maerts_response->send_buf_size = lss_size;
4762 tcp_maerts_response->recv_buf_size = lsr_size;
4763 tcp_maerts_response->no_delay = loc_nodelay;
4764 tcp_maerts_response->so_rcvavoid = loc_rcvavoid;
4765 tcp_maerts_response->so_sndavoid = loc_sndavoid;
4766 tcp_maerts_response->send_size = send_size;
4767
4768 send_response();
4769
4770 addrlen = sizeof(peeraddr_in);
4771
4772 /* we will start the timer before the accept() to be somewhat
4773 analagous to the starting of the timer before the connect() call
4774 in the TCP_STREAM test. raj 2002-06-21 */
4775
4776 start_timer(tcp_maerts_request->test_length);
4777
4778 /* Now it's time to start receiving data on the connection. We will
4779 first grab the apropriate counters and then start grabbing. */
4780
4781 cpu_start(tcp_maerts_request->measure_cpu);
4782
4783
4784 if ((s_data=accept(s_listen,
4785 (struct sockaddr *)&peeraddr_in,
4786 &addrlen)) == INVALID_SOCKET) {
4787 /* Let's just punt. The remote will be given some information */
4788 close(s_listen);
4789 exit(1);
4790 }
4791
4792 #ifdef KLUDGE_SOCKET_OPTIONS
4793
4794 /* this is for those systems which *INCORRECTLY* fail to pass
4795 attributes across an accept() call. Including this goes against
4796 my better judgement :( raj 11/95 */
4797
4798 kludge_socket_options(s_data);
4799
4800 #endif /* KLUDGE_SOCKET_OPTIONS */
4801
4802 /* The loop will exit when the sender does a shutdown, which will */
4803 /* return a length of zero */
4804
4805 bytes_sent = 0.0;
4806 send_calls = 0;
4807
4808 len = 0; /* nt-lint; len is not initialized (printf far below) if
4809 times_up initially true.*/
4810 times_up = 0; /* must remember to initialize this little beauty */
4811 while (!times_up) {
4812
4813 #ifdef DIRTY
4814 /* we want to dirty some number of consecutive integers in the buffer */
4815 /* we are about to send. we may also want to bring some number of */
4816 /* them cleanly into the cache. The clean ones will follow any dirty */
4817 /* ones into the cache. */
4818
4819 access_buffer(send_ring->buffer_ptr,
4820 send_size,
4821 tcp_maerts_request->dirty_count,
4822 tcp_maerts_request->clean_count);
4823
4824 #endif /* DIRTY */
4825
4826 if((len=send(s_data,
4827 send_ring->buffer_ptr,
4828 send_size,
4829 0)) != send_size) {
4830 if ((len >=0) || SOCKET_EINTR(len)) {
4831 /* the test was interrupted, must be the end of test */
4832 break;
4833 }
4834 netperf_response.content.serv_errno = errno;
4835 send_response();
4836 exit(1);
4837 }
4838
4839 bytes_sent += len;
4840 send_calls++;
4841
4842 /* more to the next buffer in the send_ring */
4843 send_ring = send_ring->next;
4844
4845 }
4846
4847 /* perform a shutdown to signal the sender that */
4848 /* we have received all the data sent. raj 4/93 */
4849
4850 if (shutdown(s_data,SHUT_WR) == SOCKET_ERROR) {
4851 netperf_response.content.serv_errno = errno;
4852 send_response();
4853 exit(1);
4854 }
4855
4856 /* hang a recv() off the socket to block until the remote has
4857 brought all the data up into the application. it will do a
4858 shutdown to cause a FIN to be sent our way. We will assume that
4859 any exit from the recv() call is good... raj 4/93 */
4860
4861 recv(s_data, send_ring->buffer_ptr, send_size, 0);
4862
4863
4864 cpu_stop(tcp_maerts_request->measure_cpu,&elapsed_time);
4865
4866 /* send the results to the sender */
4867
4868 if (debug) {
4869 fprintf(where,
4870 "recv_tcp_maerts: got %g bytes\n",
4871 bytes_sent);
4872 fprintf(where,
4873 "recv_tcp_maerts: got %d sends\n",
4874 send_calls);
4875 fflush(where);
4876 }
4877
4878 tcp_maerts_results->bytes_sent = htond(bytes_sent);
4879 tcp_maerts_results->elapsed_time = elapsed_time;
4880 tcp_maerts_results->send_calls = send_calls;
4881
4882 if (tcp_maerts_request->measure_cpu) {
4883 tcp_maerts_results->cpu_util = calc_cpu_util(0.0);
4884 };
4885
4886 if (debug) {
4887 fprintf(where,
4888 "recv_tcp_maerts: test complete, sending results.\n");
4889 fprintf(where,
4890 " bytes_sent %g send_calls %d\n",
4891 bytes_sent,
4892 send_calls);
4893 fprintf(where,
4894 " len %d\n",
4895 len);
4896 fflush(where);
4897 }
4898
4899 tcp_maerts_results->cpu_method = cpu_method;
4900 tcp_maerts_results->num_cpus = lib_num_loc_cpus;
4901 send_response();
4902
4903 /* we are now done with the sockets */
4904 close(s_data);
4905 close(s_listen);
4906
4907 }
4908
4909
4910 /* this routine implements the sending (netperf) side of the TCP_RR */
4911 /* test. */
4912
4913 void
send_tcp_rr(char remote_host[])4914 send_tcp_rr(char remote_host[])
4915 {
4916
4917 char *tput_title = "\
4918 Local /Remote\n\
4919 Socket Size Request Resp. Elapsed Trans.\n\
4920 Send Recv Size Size Time Rate \n\
4921 bytes Bytes bytes bytes secs. per sec \n\n";
4922
4923 char *tput_title_band = "\
4924 Local /Remote\n\
4925 Socket Size Request Resp. Elapsed \n\
4926 Send Recv Size Size Time Throughput \n\
4927 bytes Bytes bytes bytes secs. %s/sec \n\n";
4928
4929 char *tput_fmt_0 =
4930 "%7.2f %s\n";
4931
4932 char *tput_fmt_1_line_1 = "\
4933 %-6d %-6d %-6d %-6d %-6.2f %7.2f %s\n";
4934 char *tput_fmt_1_line_2 = "\
4935 %-6d %-6d\n";
4936
4937 char *cpu_title = "\
4938 Local /Remote\n\
4939 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
4940 Send Recv Size Size Time Rate local remote local remote\n\
4941 bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
4942
4943 char *cpu_title_tput = "\
4944 Local /Remote\n\
4945 Socket Size Request Resp. Elapsed Tput CPU CPU S.dem S.dem\n\
4946 Send Recv Size Size Time %-8.8s local remote local remote\n\
4947 bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
4948
4949 char *cpu_fmt_0 =
4950 "%6.3f %c %s\n";
4951
4952 char *cpu_fmt_1_line_1 = "\
4953 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n";
4954
4955 char *cpu_fmt_1_line_2 = "\
4956 %-6d %-6d\n";
4957
4958 char *ksink_fmt = "\
4959 Alignment Offset RoundTrip Trans Throughput\n\
4960 Local Remote Local Remote Latency Rate %-8.8s/s\n\
4961 Send Recv Send Recv usec/Tran per sec Outbound Inbound\n\
4962 %5d %5d %5d %5d %-6.3f %-6.3f %-6.3f %-6.3f\n";
4963
4964
4965 int timed_out = 0;
4966 float elapsed_time;
4967
4968 int len;
4969 char *temp_message_ptr;
4970 int nummessages;
4971 SOCKET send_socket;
4972 int trans_remaining;
4973 double bytes_xferd;
4974
4975 struct ring_elt *send_ring;
4976 struct ring_elt *recv_ring;
4977
4978 int rsp_bytes_left;
4979 int rsp_bytes_recvd;
4980
4981 float local_cpu_utilization;
4982 float local_service_demand;
4983 float remote_cpu_utilization;
4984 float remote_service_demand;
4985 double thruput;
4986
4987 struct addrinfo *local_res;
4988 struct addrinfo *remote_res;
4989
4990 struct tcp_rr_request_struct *tcp_rr_request;
4991 struct tcp_rr_response_struct *tcp_rr_response;
4992 struct tcp_rr_results_struct *tcp_rr_result;
4993
4994 #ifdef WANT_FIRST_BURST
4995 #define REQUEST_CWND_INITIAL 2
4996 /* "in the beginning..." the WANT_FIRST_BURST stuff was like both
4997 Unix and the state of New Jersey - both were simple an unspoiled.
4998 then it was realized that some stacks are quite picky about
4999 initial congestion windows and a non-trivial initial burst of
5000 requests would not be individual segments even with TCP_NODELAY
5001 set. so, we have to start tracking a poor-man's congestion window
5002 up here in window space because we want to try to make something
5003 happen that frankly, we cannot guarantee with the specification
5004 of TCP. ain't that grand?-) raj 2006-01-30 */
5005 int requests_outstanding = 0;
5006 int request_cwnd = REQUEST_CWND_INITIAL; /* we ass-u-me that having
5007 three requests
5008 outstanding at the
5009 beginning of the test
5010 is ok with TCP stacks
5011 of interest. the first
5012 two will come from our
5013 first_burst loop, and
5014 the third from our
5015 regularly scheduled
5016 send */
5017 #endif
5018
5019 tcp_rr_request =
5020 (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
5021 tcp_rr_response=
5022 (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
5023 tcp_rr_result =
5024 (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
5025
5026 #ifdef WANT_HISTOGRAM
5027 if (verbosity > 1) {
5028 time_hist = HIST_new();
5029 }
5030 #endif /* WANT_HISTOGRAM */
5031
5032 /* since we are now disconnected from the code that established the */
5033 /* control socket, and since we want to be able to use different */
5034 /* protocols and such, we are passed the name of the remote host and */
5035 /* must turn that into the test specific addressing information. */
5036
5037 complete_addrinfos(&remote_res,
5038 &local_res,
5039 remote_host,
5040 SOCK_STREAM,
5041 IPPROTO_TCP,
5042 0);
5043
5044 if ( print_headers ) {
5045 print_top_test_header("TCP REQUEST/RESPONSE TEST",local_res,remote_res);
5046 }
5047
5048 /* initialize a few counters */
5049
5050 send_ring = NULL;
5051 recv_ring = NULL;
5052 confidence_iteration = 1;
5053 init_stat();
5054
5055 /* we have a great-big while loop which controls the number of times */
5056 /* we run a particular test. this is for the calculation of a */
5057 /* confidence interval (I really should have stayed awake during */
5058 /* probstats :). If the user did not request confidence measurement */
5059 /* (no confidence is the default) then we will only go though the */
5060 /* loop once. the confidence stuff originates from the folks at IBM */
5061
5062 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
5063 (confidence_iteration <= iteration_min)) {
5064
5065 /* initialize a few counters. we have to remember that we might be */
5066 /* going through the loop more than once. */
5067
5068 nummessages = 0;
5069 bytes_xferd = 0.0;
5070 times_up = 0;
5071 timed_out = 0;
5072 trans_remaining = 0;
5073
5074 #ifdef WANT_FIRST_BURST
5075 /* we have to remember to reset the number of transactions
5076 outstanding and the "congestion window for each new
5077 iteration. raj 2006-01-31 */
5078 requests_outstanding = 0;
5079 request_cwnd = REQUEST_CWND_INITIAL;
5080 #endif
5081
5082
5083 /* set-up the data buffers with the requested alignment and offset. */
5084 /* since this is a request/response test, default the send_width and */
5085 /* recv_width to 1 and not two raj 7/94 */
5086
5087 if (send_width == 0) send_width = 1;
5088 if (recv_width == 0) recv_width = 1;
5089
5090 if (send_ring == NULL) {
5091 send_ring = allocate_buffer_ring(send_width,
5092 req_size,
5093 local_send_align,
5094 local_send_offset);
5095 }
5096
5097 if (recv_ring == NULL) {
5098 recv_ring = allocate_buffer_ring(recv_width,
5099 rsp_size,
5100 local_recv_align,
5101 local_recv_offset);
5102 }
5103
5104 /*set up the data socket */
5105 send_socket = create_data_socket(local_res);
5106
5107 if (send_socket == INVALID_SOCKET){
5108 perror("netperf: send_tcp_rr: tcp stream data socket");
5109 exit(1);
5110 }
5111
5112 if (debug) {
5113 fprintf(where,"send_tcp_rr: send_socket obtained...\n");
5114 }
5115
5116 /* If the user has requested cpu utilization measurements, we must */
5117 /* calibrate the cpu(s). We will perform this task within the tests */
5118 /* themselves. If the user has specified the cpu rate, then */
5119 /* calibrate_local_cpu will return rather quickly as it will have */
5120 /* nothing to do. If local_cpu_rate is zero, then we will go through */
5121 /* all the "normal" calibration stuff and return the rate back.*/
5122
5123 if (local_cpu_usage) {
5124 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
5125 }
5126
5127 if (!no_control) {
5128 /* Tell the remote end to do a listen. The server alters the
5129 socket paramters on the other side at this point, hence the
5130 reason for all the values being passed in the setup
5131 message. If the user did not specify any of the parameters,
5132 they will be passed as 0, which will indicate to the remote
5133 that no changes beyond the system's default should be
5134 used. Alignment is the exception, it will default to 8, which
5135 will be no alignment alterations. */
5136
5137 netperf_request.content.request_type = DO_TCP_RR;
5138 tcp_rr_request->recv_buf_size = rsr_size_req;
5139 tcp_rr_request->send_buf_size = rss_size_req;
5140 tcp_rr_request->recv_alignment = remote_recv_align;
5141 tcp_rr_request->recv_offset = remote_recv_offset;
5142 tcp_rr_request->send_alignment = remote_send_align;
5143 tcp_rr_request->send_offset = remote_send_offset;
5144 tcp_rr_request->request_size = req_size;
5145 tcp_rr_request->response_size = rsp_size;
5146 tcp_rr_request->no_delay = rem_nodelay;
5147 tcp_rr_request->measure_cpu = remote_cpu_usage;
5148 tcp_rr_request->cpu_rate = remote_cpu_rate;
5149 tcp_rr_request->so_rcvavoid = rem_rcvavoid;
5150 tcp_rr_request->so_sndavoid = rem_sndavoid;
5151 if (test_time) {
5152 tcp_rr_request->test_length = test_time;
5153 }
5154 else {
5155 tcp_rr_request->test_length = test_trans * -1;
5156 }
5157 tcp_rr_request->port = atoi(remote_data_port);
5158 tcp_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
5159
5160 if (debug > 1) {
5161 fprintf(where,"netperf: send_tcp_rr: requesting TCP rr test\n");
5162 }
5163
5164 send_request();
5165
5166 /* The response from the remote will contain all of the relevant
5167 socket parameters for this test type. We will put them back
5168 into the variables here so they can be displayed if desired.
5169 The remote will have calibrated CPU if necessary, and will
5170 have done all the needed set-up we will have calibrated the
5171 cpu locally before sending the request, and will grab the
5172 counter value right after the connect returns. The remote
5173 will grab the counter right after the accept call. This saves
5174 the hassle of extra messages being sent for the TCP
5175 tests. */
5176
5177 recv_response();
5178
5179 if (!netperf_response.content.serv_errno) {
5180 if (debug)
5181 fprintf(where,"remote listen done.\n");
5182 rsr_size = tcp_rr_response->recv_buf_size;
5183 rss_size = tcp_rr_response->send_buf_size;
5184 rem_nodelay = tcp_rr_response->no_delay;
5185 remote_cpu_usage = tcp_rr_response->measure_cpu;
5186 remote_cpu_rate = tcp_rr_response->cpu_rate;
5187 /* make sure that port numbers are in network order */
5188 set_port_number(remote_res,(short)tcp_rr_response->data_port_number);
5189 }
5190 else {
5191 Set_errno(netperf_response.content.serv_errno);
5192 fprintf(where,
5193 "netperf: remote error %d",
5194 netperf_response.content.serv_errno);
5195 perror("");
5196 fflush(where);
5197
5198 exit(1);
5199 }
5200 }
5201
5202 #ifdef WANT_DEMO
5203 DEMO_RR_SETUP(1000)
5204 #endif
5205
5206 /*Connect up to the remote port on the data socket */
5207 if (connect(send_socket,
5208 remote_res->ai_addr,
5209 remote_res->ai_addrlen) == INVALID_SOCKET){
5210 perror("netperf: data socket connect failed");
5211
5212 exit(1);
5213 }
5214
5215 /* Data Socket set-up is finished. If there were problems, either the */
5216 /* connect would have failed, or the previous response would have */
5217 /* indicated a problem. I failed to see the value of the extra */
5218 /* message after the accept on the remote. If it failed, we'll see it */
5219 /* here. If it didn't, we might as well start pumping data. */
5220
5221 /* Set-up the test end conditions. For a request/response test, they */
5222 /* can be either time or transaction based. */
5223
5224 if (test_time) {
5225 /* The user wanted to end the test after a period of time. */
5226 times_up = 0;
5227 trans_remaining = 0;
5228 start_timer(test_time);
5229 }
5230 else {
5231 /* The tester wanted to send a number of bytes. */
5232 trans_remaining = test_bytes;
5233 times_up = 1;
5234 }
5235
5236 /* The cpu_start routine will grab the current time and possibly */
5237 /* value of the idle counter for later use in measuring cpu */
5238 /* utilization and/or service demand and thruput. */
5239
5240 cpu_start(local_cpu_usage);
5241
5242 #ifdef WANT_INTERVALS
5243 INTERVALS_INIT();
5244 #endif /* WANT_INTERVALS */
5245
5246 /* We use an "OR" to control test execution. When the test is */
5247 /* controlled by time, the byte count check will always return false. */
5248 /* When the test is controlled by byte count, the time test will */
5249 /* always return false. When the test is finished, the whole */
5250 /* expression will go false and we will stop sending data. I think I */
5251 /* just arbitrarily decrement trans_remaining for the timed test, but */
5252 /* will not do that just yet... One other question is whether or not */
5253 /* the send buffer and the receive buffer should be the same buffer. */
5254
5255 #ifdef WANT_DEMO
5256 if (demo_mode) {
5257 HIST_timestamp(demo_one_ptr);
5258 }
5259 #endif
5260
5261 while ((!times_up) || (trans_remaining > 0)) {
5262 /* send the request. we assume that if we use a blocking socket, */
5263 /* the request will be sent at one shot. */
5264
5265 #ifdef WANT_FIRST_BURST
5266 /* we can inject no more than request_cwnd, which will grow with
5267 time, and no more than first_burst_size. we don't use <= to
5268 account for the "regularly scheduled" send call. of course
5269 that makes it more a "max_outstanding_ than a
5270 "first_burst_size" but for now we won't fix the names. also,
5271 I suspect the extra check against < first_burst_size is
5272 redundant since later I expect to make sure that request_cwnd
5273 can never get larger than first_burst_size, but just at the
5274 moment I'm feeling like a belt and suspenders kind of
5275 programmer. raj 2006-01-30 */
5276 while ((first_burst_size > 0) &&
5277 (requests_outstanding < request_cwnd) &&
5278 (requests_outstanding < first_burst_size)) {
5279 if (debug) {
5280 fprintf(where,
5281 "injecting, req_outstndng %d req_cwnd %d burst %d\n",
5282 requests_outstanding,
5283 request_cwnd,
5284 first_burst_size);
5285 }
5286 if ((len = send(send_socket,
5287 send_ring->buffer_ptr,
5288 req_size,
5289 0)) != req_size) {
5290 /* we should never hit the end of the test in the first burst */
5291 perror("send_tcp_rr: initial burst data send error");
5292 exit(-1);
5293 }
5294 requests_outstanding += 1;
5295 }
5296
5297 #endif /* WANT_FIRST_BURST */
5298
5299 #ifdef WANT_HISTOGRAM
5300 if (verbosity > 1) {
5301 /* timestamp just before our call to send, and then again just
5302 after the receive raj 8/94 */
5303 /* but only if we are actually going to display one. raj
5304 2007-02-07 */
5305
5306 HIST_timestamp(&time_one);
5307 }
5308 #endif /* WANT_HISTOGRAM */
5309
5310 if ((len = send(send_socket,
5311 send_ring->buffer_ptr,
5312 req_size,
5313 0)) != req_size) {
5314 if (SOCKET_EINTR(len) || (errno == 0)) {
5315 /* we hit the end of a */
5316 /* timed test. */
5317 timed_out = 1;
5318 break;
5319 }
5320 perror("send_tcp_rr: data send error");
5321 exit(1);
5322 }
5323 send_ring = send_ring->next;
5324
5325 #ifdef WANT_FIRST_BURST
5326 requests_outstanding += 1;
5327 #endif
5328
5329 /* receive the response */
5330 rsp_bytes_left = rsp_size;
5331 temp_message_ptr = recv_ring->buffer_ptr;
5332 while(rsp_bytes_left > 0) {
5333 if((rsp_bytes_recvd=recv(send_socket,
5334 temp_message_ptr,
5335 rsp_bytes_left,
5336 0)) == SOCKET_ERROR) {
5337 if ( SOCKET_EINTR(rsp_bytes_recvd) ) {
5338 /* We hit the end of a timed test. */
5339 timed_out = 1;
5340 break;
5341 }
5342 perror("send_tcp_rr: data recv error");
5343 exit(1);
5344 }
5345 rsp_bytes_left -= rsp_bytes_recvd;
5346 temp_message_ptr += rsp_bytes_recvd;
5347 }
5348 recv_ring = recv_ring->next;
5349
5350 #ifdef WANT_FIRST_BURST
5351 /* so, since we've gotten a response back, update the
5352 bookkeeping accordingly. there is one less request
5353 outstanding and we can put one more out there than before. */
5354 requests_outstanding -= 1;
5355 if (request_cwnd < first_burst_size) {
5356 request_cwnd += 1;
5357 if (debug) {
5358 fprintf(where,
5359 "incr req_cwnd to %d first_burst %d reqs_outstndng %d\n",
5360 request_cwnd,
5361 first_burst_size,
5362 requests_outstanding);
5363 }
5364 }
5365 #endif
5366 if (timed_out) {
5367 /* we may have been in a nested while loop - we need */
5368 /* another call to break. */
5369 break;
5370 }
5371
5372 #ifdef WANT_HISTOGRAM
5373 if (verbosity > 1) {
5374 HIST_timestamp(&time_two);
5375 HIST_add(time_hist,delta_micro(&time_one,&time_two));
5376 }
5377 #endif /* WANT_HISTOGRAM */
5378
5379 #ifdef WANT_DEMO
5380 DEMO_RR_INTERVAL(1);
5381 #endif
5382
5383 #ifdef WANT_INTERVALS
5384 INTERVALS_WAIT();
5385 #endif /* WANT_INTERVALS */
5386
5387 nummessages++;
5388 if (trans_remaining) {
5389 trans_remaining--;
5390 }
5391
5392 if (debug > 3) {
5393 if ((nummessages % 100) == 0) {
5394 fprintf(where,
5395 "Transaction %d completed\n",
5396 nummessages);
5397 fflush(where);
5398 }
5399 }
5400 }
5401
5402 /* At this point we used to call shutdown on the data socket to be
5403 sure all the data was delivered, but this was not germane in a
5404 request/response test, and it was causing the tests to "hang"
5405 when they were being controlled by time. So, I have replaced
5406 this shutdown call with a call to close that can be found later
5407 in the procedure. */
5408
5409 /* this call will always give us the elapsed time for the test,
5410 and will also store-away the necessaries for cpu utilization */
5411
5412 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
5413 /* measured? how long */
5414 /* did we really run? */
5415
5416 if (!no_control) {
5417 /* Get the statistics from the remote end. The remote will have
5418 calculated CPU utilization. If it wasn't supposed to care, it
5419 will return obvious values. */
5420
5421 recv_response();
5422 if (!netperf_response.content.serv_errno) {
5423 if (debug)
5424 fprintf(where,"remote results obtained\n");
5425 }
5426 else {
5427 Set_errno(netperf_response.content.serv_errno);
5428 fprintf(where,"netperf: remote error %d",
5429 netperf_response.content.serv_errno);
5430 perror("");
5431 fflush(where);
5432 exit(1);
5433 }
5434 }
5435
5436 /* We now calculate what our "throughput" was for the test. */
5437
5438 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
5439 thruput = nummessages/elapsed_time;
5440
5441 if (local_cpu_usage || remote_cpu_usage) {
5442 /* We must now do a little math for service demand and cpu
5443 utilization for the system(s) Of course, some of the
5444 information might be bogus because there was no idle counter in
5445 the kernel(s). We need to make a note of this for the user's
5446 benefit... */
5447 if (local_cpu_usage) {
5448 local_cpu_utilization = calc_cpu_util(0.0);
5449 /* since calc_service demand is doing ms/Kunit we will
5450 multiply the number of transaction by 1024 to get "good"
5451 numbers */
5452 local_service_demand = calc_service_demand((double) nummessages*1024,
5453 0.0,
5454 0.0,
5455 0);
5456 }
5457 else {
5458 local_cpu_utilization = (float) -1.0;
5459 local_service_demand = (float) -1.0;
5460 }
5461
5462 if (remote_cpu_usage) {
5463 remote_cpu_utilization = tcp_rr_result->cpu_util;
5464 /* since calc_service demand is doing ms/Kunit we will
5465 multiply the number of transaction by 1024 to get "good"
5466 numbers */
5467 remote_service_demand = calc_service_demand((double) nummessages*1024,
5468 0.0,
5469 remote_cpu_utilization,
5470 tcp_rr_result->num_cpus);
5471 }
5472 else {
5473 remote_cpu_utilization = (float) -1.0;
5474 remote_service_demand = (float) -1.0;
5475 }
5476
5477 }
5478 else {
5479 /* we were not measuring cpu, for the confidence stuff, we */
5480 /* should make it -1.0 */
5481 local_cpu_utilization = (float) -1.0;
5482 local_service_demand = (float) -1.0;
5483 remote_cpu_utilization = (float) -1.0;
5484 remote_service_demand = (float) -1.0;
5485 }
5486
5487 /* at this point, we want to calculate the confidence information.
5488 if debugging is on, calculate_confidence will print-out the
5489 parameters we pass it */
5490
5491 calculate_confidence(confidence_iteration,
5492 elapsed_time,
5493 thruput,
5494 local_cpu_utilization,
5495 remote_cpu_utilization,
5496 local_service_demand,
5497 remote_service_demand);
5498
5499
5500 confidence_iteration++;
5501
5502 /* we are now done with the socket, so close it */
5503 close(send_socket);
5504
5505 }
5506
5507 retrieve_confident_values(&elapsed_time,
5508 &thruput,
5509 &local_cpu_utilization,
5510 &remote_cpu_utilization,
5511 &local_service_demand,
5512 &remote_service_demand);
5513
5514 /* We are now ready to print all the information. If the user has
5515 specified zero-level verbosity, we will just print the local
5516 service demand, or the remote service demand. If the user has
5517 requested verbosity level 1, he will get the basic "streamperf"
5518 numbers. If the user has specified a verbosity of greater than 1,
5519 we will display a veritable plethora of background information
5520 from outside of this block as it it not cpu_measurement
5521 specific... */
5522
5523 if (confidence < 0) {
5524 /* we did not hit confidence, but were we asked to look for it? */
5525 if (iteration_max > 1) {
5526 display_confidence();
5527 }
5528 }
5529
5530 if (local_cpu_usage || remote_cpu_usage) {
5531 local_cpu_method = format_cpu_method(cpu_method);
5532 remote_cpu_method = format_cpu_method(tcp_rr_result->cpu_method);
5533
5534 switch (verbosity) {
5535 case 0:
5536 if (local_cpu_usage) {
5537 fprintf(where,
5538 cpu_fmt_0,
5539 local_service_demand,
5540 local_cpu_method,
5541 ((print_headers) ||
5542 (result_brand == NULL)) ? "" : result_brand);
5543 }
5544 else {
5545 fprintf(where,
5546 cpu_fmt_0,
5547 remote_service_demand,
5548 remote_cpu_method,
5549 ((print_headers) ||
5550 (result_brand == NULL)) ? "" : result_brand);
5551 }
5552 break;
5553 case 1:
5554 case 2:
5555 if (print_headers) {
5556 if ('x' == libfmt) {
5557 fprintf(where,
5558 cpu_title,
5559 local_cpu_method,
5560 remote_cpu_method);
5561 }
5562 else {
5563 fprintf(where,
5564 cpu_title_tput,
5565 format_units(),
5566 local_cpu_method,
5567 remote_cpu_method);
5568 }
5569 }
5570
5571 fprintf(where,
5572 cpu_fmt_1_line_1, /* the format string */
5573 lss_size, /* local sendbuf size */
5574 lsr_size,
5575 req_size, /* how large were the requests */
5576 rsp_size, /* guess */
5577 elapsed_time, /* how long was the test */
5578 ('x' == libfmt) ? thruput :
5579 calc_thruput_interval_omni(thruput * (req_size+rsp_size),
5580 1.0),
5581 local_cpu_utilization, /* local cpu */
5582 remote_cpu_utilization, /* remote cpu */
5583 local_service_demand, /* local service demand */
5584 remote_service_demand, /* remote service demand */
5585 ((print_headers) ||
5586 (result_brand == NULL)) ? "" : result_brand);
5587 fprintf(where,
5588 cpu_fmt_1_line_2,
5589 rss_size,
5590 rsr_size);
5591 break;
5592 }
5593 }
5594 else {
5595 /* The tester did not wish to measure service demand. */
5596
5597 switch (verbosity) {
5598 case 0:
5599 fprintf(where,
5600 tput_fmt_0,
5601 ('x' == libfmt) ? thruput :
5602 calc_thruput_interval_omni(thruput * (req_size+rsp_size),
5603 1.0),
5604 ((print_headers) ||
5605 (result_brand == NULL)) ? "" : result_brand);
5606 break;
5607 case 1:
5608 case 2:
5609 if (print_headers) {
5610 fprintf(where,
5611 ('x' == libfmt) ? tput_title : tput_title_band,
5612 format_units());
5613 }
5614
5615 fprintf(where,
5616 tput_fmt_1_line_1, /* the format string */
5617 lss_size,
5618 lsr_size,
5619 req_size, /* how large were the requests */
5620 rsp_size, /* how large were the responses */
5621 elapsed_time, /* how long did it take */
5622 /* are we trans or do we need to convert to bytes then
5623 bits? at this point, thruput is in our "confident"
5624 transactions per second. we can convert to a
5625 bidirectional bitrate by multiplying that by the sum
5626 of the req_size and rsp_size. we pass that to
5627 calc_thruput_interval_omni with an elapsed time of
5628 1.0 s to get it converted to [kmg]bits/s or
5629 [KMG]Bytes/s */
5630 ('x' == libfmt) ? thruput :
5631 calc_thruput_interval_omni(thruput * (req_size+rsp_size),
5632 1.0),
5633 ((print_headers) ||
5634 (result_brand == NULL)) ? "" : result_brand);
5635 fprintf(where,
5636 tput_fmt_1_line_2,
5637 rss_size, /* remote recvbuf size */
5638 rsr_size);
5639
5640 break;
5641 }
5642 }
5643
5644 /* it would be a good thing to include information about some of the */
5645 /* other parameters that may have been set for this test, but at the */
5646 /* moment, I do not wish to figure-out all the formatting, so I will */
5647 /* just put this comment here to help remind me that it is something */
5648 /* that should be done at a later time. */
5649
5650 /* how to handle the verbose information in the presence of */
5651 /* confidence intervals is yet to be determined... raj 11/94 */
5652 if (verbosity > 1) {
5653 /* The user wanted to know it all, so we will give it to him. */
5654 /* This information will include as much as we can find about */
5655 /* TCP statistics, the alignments of the sends and receives */
5656 /* and all that sort of rot... */
5657
5658 /* normally, you might think that if we were messing about with
5659 the value of libfmt we would need to put it back again, but
5660 since this is basically the last thing we are going to do with
5661 it, it does not matter. so there :) raj 2007-06-08 */
5662 /* if the user was asking for transactions, then we report
5663 megabits per sedcond for the unidirectional throughput,
5664 otherwise we use the desired units. */
5665 if ('x' == libfmt) {
5666 libfmt = 'm';
5667 }
5668
5669 fprintf(where,
5670 ksink_fmt,
5671 format_units(),
5672 local_send_align,
5673 remote_recv_offset,
5674 local_send_offset,
5675 remote_recv_offset,
5676 /* if the user has enable burst mode, we have to remember
5677 to account for that in the number of transactions
5678 outstanding at any one time. otherwise we will
5679 underreport the latency of individual
5680 transactions. learned from saf by raj 2007-06-08 */
5681 (((double)1.0/thruput)*(double)1000000.0) *
5682 (double) (1+first_burst_size),
5683 thruput,
5684 calc_thruput_interval_omni(thruput * (double)req_size,1.0),
5685 calc_thruput_interval_omni(thruput * (double)rsp_size,1.0));
5686
5687 #ifdef WANT_HISTOGRAM
5688 fprintf(where,"\nHistogram of request/response times\n");
5689 fflush(where);
5690 HIST_report(time_hist);
5691 #endif /* WANT_HISTOGRAM */
5692
5693 }
5694
5695 }
5696
5697 void
send_udp_stream(char remote_host[])5698 send_udp_stream(char remote_host[])
5699 {
5700 /**********************************************************************/
5701 /* */
5702 /* UDP Unidirectional Send Test */
5703 /* */
5704 /**********************************************************************/
5705
5706 #define UDP_LENGTH_MAX 0XFFFF - 28
5707
5708 char *tput_title = "\
5709 Socket Message Elapsed Messages \n\
5710 Size Size Time Okay Errors Throughput\n\
5711 bytes bytes secs # # %s/sec\n\n";
5712
5713 char *tput_fmt_0 =
5714 "%7.2f\n";
5715
5716 char *tput_fmt_1 = "\
5717 %6d %6d %-7.2f %7d %6d %7.2f\n\
5718 %6d %-7.2f %7d %7.2f\n\n";
5719
5720
5721 char *cpu_title = "\
5722 Socket Message Elapsed Messages CPU Service\n\
5723 Size Size Time Okay Errors Throughput Util Demand\n\
5724 bytes bytes secs # # %s/sec %% %c%c us/KB\n\n";
5725
5726 char *cpu_fmt_0 =
5727 "%6.2f %c\n";
5728
5729 char *cpu_fmt_1 = "\
5730 %6d %6d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\
5731 %6d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n";
5732
5733 unsigned int messages_recvd;
5734 unsigned int messages_sent;
5735 unsigned int failed_sends;
5736
5737 float elapsed_time,
5738 local_cpu_utilization,
5739 remote_cpu_utilization;
5740
5741 float local_service_demand, remote_service_demand;
5742 double local_thruput, remote_thruput;
5743 double bytes_sent;
5744 double bytes_recvd;
5745
5746
5747 int len;
5748 struct ring_elt *send_ring;
5749 SOCKET data_socket;
5750
5751 unsigned int sum_messages_sent;
5752 unsigned int sum_messages_recvd;
5753 unsigned int sum_failed_sends;
5754 double sum_local_thruput;
5755
5756 struct addrinfo *local_res;
5757 struct addrinfo *remote_res;
5758
5759 struct udp_stream_request_struct *udp_stream_request;
5760 struct udp_stream_response_struct *udp_stream_response;
5761 struct udp_stream_results_struct *udp_stream_results;
5762
5763 udp_stream_request =
5764 (struct udp_stream_request_struct *)netperf_request.content.test_specific_data;
5765 udp_stream_response =
5766 (struct udp_stream_response_struct *)netperf_response.content.test_specific_data;
5767 udp_stream_results =
5768 (struct udp_stream_results_struct *)netperf_response.content.test_specific_data;
5769
5770 #ifdef WANT_HISTOGRAM
5771 if (verbosity > 1) {
5772 time_hist = HIST_new();
5773 }
5774 #endif /* WANT_HISTOGRAM */
5775
5776 /* since we are now disconnected from the code that established the */
5777 /* control socket, and since we want to be able to use different */
5778 /* protocols and such, we are passed the name of the remote host and */
5779 /* must turn that into the test specific addressing information. */
5780
5781 complete_addrinfos(&remote_res,
5782 &local_res,
5783 remote_host,
5784 SOCK_DGRAM,
5785 IPPROTO_UDP,
5786 0);
5787
5788 if ( print_headers ) {
5789 print_top_test_header("UDP UNIDIRECTIONAL SEND TEST",local_res,remote_res);
5790 }
5791
5792 send_ring = NULL;
5793 confidence_iteration = 1;
5794 init_stat();
5795 sum_messages_sent = 0;
5796 sum_messages_recvd = 0;
5797 sum_failed_sends = 0;
5798 sum_local_thruput = 0.0;
5799
5800 /* we have a great-big while loop which controls the number of times */
5801 /* we run a particular test. this is for the calculation of a */
5802 /* confidence interval (I really should have stayed awake during */
5803 /* probstats :). If the user did not request confidence measurement */
5804 /* (no confidence is the default) then we will only go though the */
5805 /* loop once. the confidence stuff originates from the folks at IBM */
5806
5807 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
5808 (confidence_iteration <= iteration_min)) {
5809
5810 /* initialize a few counters. we have to remember that we might be */
5811 /* going through the loop more than once. */
5812 messages_sent = 0;
5813 messages_recvd = 0;
5814 failed_sends = 0;
5815 times_up = 0;
5816
5817 /*set up the data socket */
5818 data_socket = create_data_socket(local_res);
5819
5820 if (data_socket == INVALID_SOCKET){
5821 perror("udp_send: data socket");
5822 exit(1);
5823 }
5824
5825 /* now, we want to see if we need to set the send_size */
5826 if (send_size == 0) {
5827 if (lss_size > 0) {
5828 send_size = (lss_size < UDP_LENGTH_MAX ? lss_size : UDP_LENGTH_MAX);
5829 }
5830 else {
5831 send_size = 4096;
5832 }
5833 }
5834
5835
5836 /* set-up the data buffer with the requested alignment and offset, */
5837 /* most of the numbers here are just a hack to pick something nice */
5838 /* and big in an attempt to never try to send a buffer a second time */
5839 /* before it leaves the node...unless the user set the width */
5840 /* explicitly. */
5841 if (send_width == 0) send_width = 32;
5842
5843 if (send_ring == NULL ) {
5844 send_ring = allocate_buffer_ring(send_width,
5845 send_size,
5846 local_send_align,
5847 local_send_offset);
5848 }
5849
5850
5851 /* if the user supplied a cpu rate, this call will complete rather */
5852 /* quickly, otherwise, the cpu rate will be retured to us for */
5853 /* possible display. The Library will keep it's own copy of this data */
5854 /* for use elsewhere. We will only display it. (Does that make it */
5855 /* "opaque" to us?) */
5856
5857 if (local_cpu_usage)
5858 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
5859
5860 if (!no_control) {
5861 /* Tell the remote end to set up the data connection. The server
5862 sends back the port number and alters the socket parameters
5863 there. Of course this is a datagram service so no connection
5864 is actually set up, the server just sets up the socket and
5865 binds it. */
5866
5867 netperf_request.content.request_type = DO_UDP_STREAM;
5868 udp_stream_request->recv_buf_size = rsr_size_req;
5869 udp_stream_request->message_size = send_size;
5870 udp_stream_request->recv_connected = remote_connected;
5871 udp_stream_request->recv_alignment = remote_recv_align;
5872 udp_stream_request->recv_offset = remote_recv_offset;
5873 udp_stream_request->measure_cpu = remote_cpu_usage;
5874 udp_stream_request->cpu_rate = remote_cpu_rate;
5875 udp_stream_request->test_length = test_time;
5876 udp_stream_request->so_rcvavoid = rem_rcvavoid;
5877 udp_stream_request->so_sndavoid = rem_sndavoid;
5878 udp_stream_request->port = atoi(remote_data_port);
5879 udp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
5880
5881 send_request();
5882
5883 recv_response();
5884
5885 if (!netperf_response.content.serv_errno) {
5886 if (debug)
5887 fprintf(where,"send_udp_stream: remote data connection done.\n");
5888 }
5889 else {
5890 Set_errno(netperf_response.content.serv_errno);
5891 perror("send_udp_stream: error on remote");
5892 exit(1);
5893 }
5894
5895 /* Place the port number returned by the remote into the sockaddr */
5896 /* structure so our sends can be sent to the correct place. Also get */
5897 /* some of the returned socket buffer information for user display. */
5898
5899 /* make sure that port numbers are in the proper order */
5900 set_port_number(remote_res,(short)udp_stream_response->data_port_number);
5901
5902 rsr_size = udp_stream_response->recv_buf_size;
5903 rss_size = udp_stream_response->send_buf_size;
5904 remote_cpu_rate = udp_stream_response->cpu_rate;
5905 }
5906
5907 #ifdef WANT_DEMO
5908 DEMO_STREAM_SETUP(lss_size,rsr_size)
5909 #endif
5910
5911 /* We "connect" up to the remote post to allow is to use the send */
5912 /* call instead of the sendto call. Presumeably, this is a little */
5913 /* simpler, and a little more efficient. I think that it also means */
5914 /* that we can be informed of certain things, but am not sure */
5915 /* yet...also, this is the way I would expect a client to behave */
5916 /* when talking to a server */
5917 if (local_connected) {
5918 if (connect(data_socket,
5919 remote_res->ai_addr,
5920 remote_res->ai_addrlen) == INVALID_SOCKET){
5921 perror("send_udp_stream: data socket connect failed");
5922 exit(1);
5923 } else if (debug) {
5924 fprintf(where,"send_udp_stream: connected data socket.\n");
5925 fflush(where);
5926 }
5927 }
5928
5929 /* set up the timer to call us after test_time. one of these days, */
5930 /* it might be nice to figure-out a nice reliable way to have the */
5931 /* test controlled by a byte count as well, but since UDP is not */
5932 /* reliable, that could prove difficult. so, in the meantime, we */
5933 /* only allow a UDP_STREAM test to be a timed test. */
5934
5935 if (test_time) {
5936 times_up = 0;
5937 start_timer(test_time);
5938 }
5939 else {
5940 fprintf(where,"Sorry, UDP_STREAM tests must be timed.\n");
5941 fflush(where);
5942 }
5943
5944 /* Get the start count for the idle counter and the start time */
5945
5946 cpu_start(local_cpu_usage);
5947
5948 #ifdef WANT_INTERVALS
5949 INTERVALS_INIT();
5950 #endif /* WANT_INTERVALS */
5951
5952 #ifdef WANT_DEMO
5953 if (demo_mode) {
5954 HIST_timestamp(demo_one_ptr);
5955 }
5956 #endif
5957
5958 /* Send datagrams like there was no tomorrow. at somepoint it might */
5959 /* be nice to set this up so that a quantity of bytes could be sent, */
5960 /* but we still need some sort of end of test trigger on the receive */
5961 /* side. that could be a select with a one second timeout, but then */
5962 /* if there is a test where none of the data arrives for awile and */
5963 /* then starts again, we would end the test too soon. something to */
5964 /* think about... */
5965 while (!times_up) {
5966
5967 #ifdef DIRTY
5968 /* we want to dirty some number of consecutive integers in the buffer */
5969 /* we are about to send. we may also want to bring some number of */
5970 /* them cleanly into the cache. The clean ones will follow any dirty */
5971 /* ones into the cache. */
5972
5973 access_buffer(send_ring->buffer_ptr,
5974 send_size,
5975 loc_dirty_count,
5976 loc_clean_count);
5977 #endif /* DIRTY */
5978
5979 #ifdef WANT_HISTOGRAM
5980 if (verbosity > 1) {
5981 HIST_timestamp(&time_one);
5982 }
5983 #endif /* WANT_HISTOGRAM */
5984
5985 if (local_connected) {
5986 len = send(data_socket,
5987 send_ring->buffer_ptr,
5988 send_size,
5989 0);
5990 } else {
5991 len = sendto(data_socket,
5992 send_ring->buffer_ptr,
5993 send_size,
5994 0,
5995 remote_res->ai_addr,
5996 remote_res->ai_addrlen);
5997 }
5998
5999 if (len != send_size) {
6000 if ((len >= 0) ||
6001 SOCKET_EINTR(len))
6002 break;
6003 if (errno == ENOBUFS) {
6004 failed_sends++;
6005 continue;
6006 }
6007 perror("udp_send: data send error");
6008 exit(1);
6009 }
6010 messages_sent++;
6011
6012 /* now we want to move our pointer to the next position in the */
6013 /* data buffer... */
6014
6015 send_ring = send_ring->next;
6016
6017
6018 #ifdef WANT_HISTOGRAM
6019 if (verbosity > 1) {
6020 /* get the second timestamp */
6021 HIST_timestamp(&time_two);
6022 HIST_add(time_hist,delta_micro(&time_one,&time_two));
6023 }
6024 #endif /* WANT_HISTOGRAM */
6025
6026 #ifdef WANT_DEMO
6027 DEMO_STREAM_INTERVAL(send_size)
6028 #endif
6029
6030 #ifdef WANT_INTERVALS
6031 INTERVALS_WAIT();
6032 #endif /* WANT_INTERVALS */
6033
6034 }
6035
6036 /* This is a timed test, so the remote will be returning to us after */
6037 /* a time. We should not need to send any "strange" messages to tell */
6038 /* the remote that the test is completed, unless we decide to add a */
6039 /* number of messages to the test. */
6040
6041 /* the test is over, so get stats and stuff */
6042 cpu_stop(local_cpu_usage,
6043 &elapsed_time);
6044
6045 if (!no_control) {
6046 /* Get the statistics from the remote end */
6047 recv_response();
6048 if (!netperf_response.content.serv_errno) {
6049 if (debug)
6050 fprintf(where,"send_udp_stream: remote results obtained\n");
6051 }
6052 else {
6053 Set_errno(netperf_response.content.serv_errno);
6054 perror("send_udp_stream: error on remote");
6055 exit(1);
6056 }
6057 messages_recvd = udp_stream_results->messages_recvd;
6058 bytes_recvd = (double) send_size * (double) messages_recvd;
6059 }
6060 else {
6061 /* since there was no control connection, we've no idea what was
6062 actually received. raj 2007-02-08 */
6063 messages_recvd = -1;
6064 bytes_recvd = -1.0;
6065 }
6066
6067 bytes_sent = (double) send_size * (double) messages_sent;
6068 local_thruput = calc_thruput(bytes_sent);
6069
6070
6071 /* we asume that the remote ran for as long as we did */
6072
6073 remote_thruput = calc_thruput(bytes_recvd);
6074
6075 /* print the results for this socket and message size */
6076
6077 if (local_cpu_usage || remote_cpu_usage) {
6078 /* We must now do a little math for service demand and cpu */
6079 /* utilization for the system(s) We pass zeros for the local */
6080 /* cpu utilization and elapsed time to tell the routine to use */
6081 /* the libraries own values for those. */
6082 if (local_cpu_usage) {
6083 local_cpu_utilization = calc_cpu_util(0.0);
6084 /* shouldn't this really be based on bytes_recvd, since that is */
6085 /* the effective throughput of the test? I think that it should, */
6086 /* so will make the change raj 11/94 */
6087 local_service_demand = calc_service_demand(bytes_recvd,
6088 0.0,
6089 0.0,
6090 0);
6091 }
6092 else {
6093 local_cpu_utilization = (float) -1.0;
6094 local_service_demand = (float) -1.0;
6095 }
6096
6097 /* The local calculations could use variables being kept by */
6098 /* the local netlib routines. The remote calcuations need to */
6099 /* have a few things passed to them. */
6100 if (remote_cpu_usage) {
6101 remote_cpu_utilization = udp_stream_results->cpu_util;
6102 remote_service_demand = calc_service_demand(bytes_recvd,
6103 0.0,
6104 remote_cpu_utilization,
6105 udp_stream_results->num_cpus);
6106 }
6107 else {
6108 remote_cpu_utilization = (float) -1.0;
6109 remote_service_demand = (float) -1.0;
6110 }
6111 }
6112 else {
6113 /* we were not measuring cpu, for the confidence stuff, we */
6114 /* should make it -1.0 */
6115 local_cpu_utilization = (float) -1.0;
6116 local_service_demand = (float) -1.0;
6117 remote_cpu_utilization = (float) -1.0;
6118 remote_service_demand = (float) -1.0;
6119 }
6120
6121 /* at this point, we want to calculate the confidence information. */
6122 /* if debugging is on, calculate_confidence will print-out the */
6123 /* parameters we pass it */
6124
6125 calculate_confidence(confidence_iteration,
6126 elapsed_time,
6127 remote_thruput,
6128 local_cpu_utilization,
6129 remote_cpu_utilization,
6130 local_service_demand,
6131 remote_service_demand);
6132
6133 /* since the routine calculate_confidence is rather generic, and */
6134 /* we have a few other parms of interest, we will do a little work */
6135 /* here to caclulate their average. */
6136 sum_messages_sent += messages_sent;
6137 sum_messages_recvd += messages_recvd;
6138 sum_failed_sends += failed_sends;
6139 sum_local_thruput += local_thruput;
6140
6141 confidence_iteration++;
6142
6143 /* this datapoint is done, so we don't need the socket any longer */
6144 close(data_socket);
6145
6146 }
6147
6148 /* we should reach this point once the test is finished */
6149
6150 retrieve_confident_values(&elapsed_time,
6151 &remote_thruput,
6152 &local_cpu_utilization,
6153 &remote_cpu_utilization,
6154 &local_service_demand,
6155 &remote_service_demand);
6156
6157 /* some of the interesting values aren't covered by the generic */
6158 /* confidence routine */
6159 messages_sent = sum_messages_sent / (confidence_iteration -1);
6160 messages_recvd = sum_messages_recvd / (confidence_iteration -1);
6161 failed_sends = sum_failed_sends / (confidence_iteration -1);
6162 local_thruput = sum_local_thruput / (confidence_iteration -1);
6163
6164 /* We are now ready to print all the information. If the user */
6165 /* has specified zero-level verbosity, we will just print the */
6166 /* local service demand, or the remote service demand. If the */
6167 /* user has requested verbosity level 1, he will get the basic */
6168 /* "streamperf" numbers. If the user has specified a verbosity */
6169 /* of greater than 1, we will display a veritable plethora of */
6170 /* background information from outside of this block as it it */
6171 /* not cpu_measurement specific... */
6172
6173
6174 if (confidence < 0) {
6175 /* we did not hit confidence, but were we asked to look for it? */
6176 if (iteration_max > 1) {
6177 display_confidence();
6178 }
6179 }
6180
6181 if (local_cpu_usage || remote_cpu_usage) {
6182 local_cpu_method = format_cpu_method(cpu_method);
6183 remote_cpu_method = format_cpu_method(udp_stream_results->cpu_method);
6184
6185 switch (verbosity) {
6186 case 0:
6187 if (local_cpu_usage) {
6188 fprintf(where,
6189 cpu_fmt_0,
6190 local_service_demand,
6191 local_cpu_method);
6192 }
6193 else {
6194 fprintf(where,
6195 cpu_fmt_0,
6196 remote_service_demand,
6197 local_cpu_method);
6198 }
6199 break;
6200 case 1:
6201 case 2:
6202 if (print_headers) {
6203 fprintf(where,
6204 cpu_title,
6205 format_units(),
6206 local_cpu_method,
6207 remote_cpu_method);
6208 }
6209
6210 fprintf(where,
6211 cpu_fmt_1, /* the format string */
6212 lss_size, /* local sendbuf size */
6213 send_size, /* how large were the sends */
6214 elapsed_time, /* how long was the test */
6215 messages_sent,
6216 failed_sends,
6217 local_thruput, /* what was the xfer rate */
6218 local_cpu_utilization, /* local cpu */
6219 local_service_demand, /* local service demand */
6220 rsr_size,
6221 elapsed_time,
6222 messages_recvd,
6223 remote_thruput,
6224 remote_cpu_utilization, /* remote cpu */
6225 remote_service_demand); /* remote service demand */
6226 break;
6227 }
6228 }
6229 else {
6230 /* The tester did not wish to measure service demand. */
6231 switch (verbosity) {
6232 case 0:
6233 fprintf(where,
6234 tput_fmt_0,
6235 local_thruput);
6236 break;
6237 case 1:
6238 case 2:
6239 if (print_headers) {
6240 fprintf(where,tput_title,format_units());
6241 }
6242 fprintf(where,
6243 tput_fmt_1, /* the format string */
6244 lss_size, /* local sendbuf size */
6245 send_size, /* how large were the sends */
6246 elapsed_time, /* how long did it take */
6247 messages_sent,
6248 failed_sends,
6249 local_thruput,
6250 rsr_size, /* remote recvbuf size */
6251 elapsed_time,
6252 messages_recvd,
6253 remote_thruput);
6254 break;
6255 }
6256 }
6257
6258 fflush(where);
6259 #ifdef WANT_HISTOGRAM
6260 if (verbosity > 1) {
6261 fprintf(where,"\nHistogram of time spent in send() call\n");
6262 fflush(where);
6263 HIST_report(time_hist);
6264 }
6265 #endif /* WANT_HISTOGRAM */
6266
6267 }
6268
6269
6270 /* this routine implements the receive side (netserver) of the */
6271 /* UDP_STREAM performance test. */
6272
6273 void
recv_udp_stream()6274 recv_udp_stream()
6275 {
6276 struct ring_elt *recv_ring;
6277 struct addrinfo *local_res;
6278 char local_name[BUFSIZ];
6279 char port_buffer[PORTBUFSIZE];
6280
6281 struct sockaddr_storage myaddr_in;
6282 SOCKET s_data;
6283 netperf_socklen_t addrlen;
6284 struct sockaddr_storage remote_addr;
6285 netperf_socklen_t remote_addrlen;
6286
6287 int len = 0;
6288 unsigned int bytes_received = 0;
6289 float elapsed_time;
6290
6291 int message_size;
6292 unsigned int messages_recvd = 0;
6293
6294 struct udp_stream_request_struct *udp_stream_request;
6295 struct udp_stream_response_struct *udp_stream_response;
6296 struct udp_stream_results_struct *udp_stream_results;
6297
6298 udp_stream_request =
6299 (struct udp_stream_request_struct *)netperf_request.content.test_specific_data;
6300 udp_stream_response =
6301 (struct udp_stream_response_struct *)netperf_response.content.test_specific_data;
6302 udp_stream_results =
6303 (struct udp_stream_results_struct *)netperf_response.content.test_specific_data;
6304
6305 if (debug) {
6306 fprintf(where,"netserver: recv_udp_stream: entered...\n");
6307 fflush(where);
6308 }
6309
6310 /* We want to set-up the listen socket with all the desired */
6311 /* parameters and then let the initiator know that all is ready. If */
6312 /* socket size defaults are to be used, then the initiator will have */
6313 /* sent us 0's. If the socket sizes cannot be changed, then we will */
6314 /* send-back what they are. If that information cannot be determined, */
6315 /* then we send-back -1's for the sizes. If things go wrong for any */
6316 /* reason, we will drop back ten yards and punt. */
6317
6318 /* If anything goes wrong, we want the remote to know about it. It */
6319 /* would be best if the error that the remote reports to the user is */
6320 /* the actual error we encountered, rather than some bogus unexpected */
6321 /* response type message. */
6322
6323 if (debug > 1) {
6324 fprintf(where,"recv_udp_stream: setting the response type...\n");
6325 fflush(where);
6326 }
6327
6328 netperf_response.content.response_type = UDP_STREAM_RESPONSE;
6329
6330 if (debug > 2) {
6331 fprintf(where,"recv_udp_stream: the response type is set...\n");
6332 fflush(where);
6333 }
6334
6335 /* We now alter the message_ptr variable to be at the desired */
6336 /* alignment with the desired offset. */
6337
6338 if (debug > 1) {
6339 fprintf(where,"recv_udp_stream: requested alignment of %d\n",
6340 udp_stream_request->recv_alignment);
6341 fflush(where);
6342 }
6343
6344 if (recv_width == 0) recv_width = 1;
6345
6346 recv_ring = allocate_buffer_ring(recv_width,
6347 udp_stream_request->message_size,
6348 udp_stream_request->recv_alignment,
6349 udp_stream_request->recv_offset);
6350
6351 if (debug > 1) {
6352 fprintf(where,"recv_udp_stream: receive alignment and offset set...\n");
6353 fflush(where);
6354 }
6355
6356 /* Grab a socket to listen on, and then listen on it. */
6357
6358 if (debug > 1) {
6359 fprintf(where,"recv_udp_stream: grabbing a socket...\n");
6360 fflush(where);
6361 }
6362
6363 /* create_data_socket expects to find some things in the global */
6364 /* variables, so set the globals based on the values in the request. */
6365 /* once the socket has been created, we will set the response values */
6366 /* based on the updated value of those globals. raj 7/94 */
6367 lsr_size_req = udp_stream_request->recv_buf_size;
6368 loc_rcvavoid = udp_stream_request->so_rcvavoid;
6369 loc_sndavoid = udp_stream_request->so_sndavoid;
6370 local_connected = udp_stream_request->recv_connected;
6371
6372 set_hostname_and_port(local_name,
6373 port_buffer,
6374 nf_to_af(udp_stream_request->ipfamily),
6375 udp_stream_request->port);
6376
6377 local_res = complete_addrinfo(local_name,
6378 local_name,
6379 port_buffer,
6380 nf_to_af(udp_stream_request->ipfamily),
6381 SOCK_DGRAM,
6382 IPPROTO_UDP,
6383 0);
6384
6385 s_data = create_data_socket(local_res);
6386
6387 if (s_data == INVALID_SOCKET) {
6388 netperf_response.content.serv_errno = errno;
6389 send_response();
6390 exit(1);
6391 }
6392
6393 udp_stream_response->test_length = udp_stream_request->test_length;
6394
6395 /* now get the port number assigned by the system */
6396 addrlen = sizeof(myaddr_in);
6397 if (getsockname(s_data,
6398 (struct sockaddr *)&myaddr_in,
6399 &addrlen) == SOCKET_ERROR){
6400 netperf_response.content.serv_errno = errno;
6401 close(s_data);
6402 send_response();
6403
6404 exit(1);
6405 }
6406
6407 /* Now myaddr_in contains the port and the internet address this is */
6408 /* returned to the sender also implicitly telling the sender that the */
6409 /* socket buffer sizing has been done. */
6410
6411 udp_stream_response->data_port_number =
6412 (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
6413 netperf_response.content.serv_errno = 0;
6414
6415 /* But wait, there's more. If the initiator wanted cpu measurements, */
6416 /* then we must call the calibrate routine, which will return the max */
6417 /* rate back to the initiator. If the CPU was not to be measured, or */
6418 /* something went wrong with the calibration, we will return a -1 to */
6419 /* the initiator. */
6420
6421 udp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */
6422 udp_stream_response->measure_cpu = 0;
6423 if (udp_stream_request->measure_cpu) {
6424 /* We will pass the rate into the calibration routine. If the */
6425 /* user did not specify one, it will be 0.0, and we will do a */
6426 /* "real" calibration. Otherwise, all it will really do is */
6427 /* store it away... */
6428 udp_stream_response->measure_cpu = 1;
6429 udp_stream_response->cpu_rate =
6430 calibrate_local_cpu(udp_stream_request->cpu_rate);
6431 }
6432
6433 message_size = udp_stream_request->message_size;
6434 test_time = udp_stream_request->test_length;
6435
6436 /* before we send the response back to the initiator, pull some of */
6437 /* the socket parms from the globals */
6438 udp_stream_response->send_buf_size = lss_size;
6439 udp_stream_response->recv_buf_size = lsr_size;
6440 udp_stream_response->so_rcvavoid = loc_rcvavoid;
6441 udp_stream_response->so_sndavoid = loc_sndavoid;
6442
6443 send_response();
6444
6445 /* Now it's time to start receiving data on the connection. We will */
6446 /* first grab the apropriate counters and then start grabbing. */
6447
6448 cpu_start(udp_stream_request->measure_cpu);
6449
6450 #ifdef WIN32
6451 /* this is used so the timer thread can close the socket out from */
6452 /* under us, which to date is the easiest/cleanest/least */
6453 /* Windows-specific way I can find to force the winsock calls to */
6454 /* return WSAEINTR with the test is over. anything that will run on */
6455 /* 95 and NT and is closer to what netperf expects from Unix signals */
6456 /* and such would be appreciated raj 1/96 */
6457 win_kludge_socket = s_data;
6458 #endif /* WIN32 */
6459
6460 /* The loop will exit when the timer pops, or if we happen to recv a */
6461 /* message of less than send_size bytes... */
6462
6463 times_up = 0;
6464
6465 start_timer(test_time + PAD_TIME);
6466
6467 if (debug) {
6468 fprintf(where,"recv_udp_stream: about to enter inner sanctum.\n");
6469 fflush(where);
6470 }
6471
6472 /* We "connect" up to the remote post to allow us to use the recv */
6473 /* call instead of the recvfrom call. Presumeably, this is a little */
6474 /* simpler, and a little more efficient. */
6475
6476 if (local_connected) {
6477
6478 /* Receive the first message using recvfrom to find the remote address */
6479 remote_addrlen = sizeof(remote_addr);
6480 len = recvfrom(s_data, recv_ring->buffer_ptr,
6481 message_size, 0,
6482 (struct sockaddr*)&remote_addr, &remote_addrlen);
6483 if (len != message_size) {
6484 if ((len == SOCKET_ERROR) && !SOCKET_EINTR(len)) {
6485 netperf_response.content.serv_errno = errno;
6486 send_response();
6487 exit(1);
6488 }
6489 }
6490 messages_recvd++;
6491 recv_ring = recv_ring->next;
6492
6493
6494 /* Now connect with the remote socket address */
6495 if (connect(s_data,
6496 (struct sockaddr*)&remote_addr,
6497 remote_addrlen )== INVALID_SOCKET) {
6498 netperf_response.content.serv_errno = errno;
6499 close(s_data);
6500 send_response();
6501 exit(1);
6502 }
6503
6504 if (debug) {
6505 fprintf(where,"recv_udp_stream: connected data socket\n");
6506 fflush(where);
6507 }
6508 }
6509
6510 while (!times_up) {
6511 if(local_connected) {
6512 len = recv(s_data,
6513 recv_ring->buffer_ptr,
6514 message_size,
6515 0);
6516 } else {
6517 len = recvfrom(s_data,
6518 recv_ring->buffer_ptr,
6519 message_size,
6520 0,0,0);
6521 }
6522
6523 if (len != message_size) {
6524 if ((len == SOCKET_ERROR) && !SOCKET_EINTR(len)) {
6525 netperf_response.content.serv_errno = errno;
6526 send_response();
6527 exit(1);
6528 }
6529 break;
6530 }
6531 messages_recvd++;
6532 recv_ring = recv_ring->next;
6533 }
6534
6535 if (debug) {
6536 fprintf(where,"recv_udp_stream: got %d messages.\n",messages_recvd);
6537 fflush(where);
6538 }
6539
6540
6541 /* The loop now exits due timer or < send_size bytes received. in */
6542 /* reality, we only really support a timed UDP_STREAM test. raj */
6543 /* 12/95 */
6544
6545 cpu_stop(udp_stream_request->measure_cpu,&elapsed_time);
6546
6547 if (times_up) {
6548 /* we ended on a timer, subtract the PAD_TIME */
6549 elapsed_time -= (float)PAD_TIME;
6550 }
6551 else {
6552 stop_timer();
6553 }
6554
6555 if (debug) {
6556 fprintf(where,"recv_udp_stream: test ended in %f seconds.\n",elapsed_time);
6557 fflush(where);
6558 }
6559
6560
6561 /* We will count the "off" message that got us out of the loop */
6562 bytes_received = (messages_recvd * message_size) + len;
6563
6564 /* send the results to the sender */
6565
6566 if (debug) {
6567 fprintf(where,
6568 "recv_udp_stream: got %d bytes\n",
6569 bytes_received);
6570 fflush(where);
6571 }
6572
6573 netperf_response.content.response_type = UDP_STREAM_RESULTS;
6574 udp_stream_results->bytes_received = htonl(bytes_received);
6575 udp_stream_results->messages_recvd = messages_recvd;
6576 udp_stream_results->elapsed_time = elapsed_time;
6577 udp_stream_results->cpu_method = cpu_method;
6578 udp_stream_results->num_cpus = lib_num_loc_cpus;
6579 if (udp_stream_request->measure_cpu) {
6580 udp_stream_results->cpu_util = calc_cpu_util(elapsed_time);
6581 }
6582 else {
6583 udp_stream_results->cpu_util = (float) -1.0;
6584 }
6585
6586 if (debug > 1) {
6587 fprintf(where,
6588 "recv_udp_stream: test complete, sending results.\n");
6589 fflush(where);
6590 }
6591
6592 send_response();
6593
6594 close(s_data);
6595
6596 }
6597
6598 void
send_udp_rr(char remote_host[])6599 send_udp_rr(char remote_host[])
6600 {
6601
6602 char *tput_title = "\
6603 Local /Remote\n\
6604 Socket Size Request Resp. Elapsed Trans.\n\
6605 Send Recv Size Size Time Rate \n\
6606 bytes Bytes bytes bytes secs. per sec \n\n";
6607
6608 char *tput_fmt_0 =
6609 "%7.2f\n";
6610
6611 char *tput_fmt_1_line_1 = "\
6612 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
6613 char *tput_fmt_1_line_2 = "\
6614 %-6d %-6d\n";
6615
6616 char *cpu_title = "\
6617 Local /Remote\n\
6618 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
6619 Send Recv Size Size Time Rate local remote local remote\n\
6620 bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
6621
6622 char *cpu_fmt_0 =
6623 "%6.3f %c\n";
6624
6625 char *cpu_fmt_1_line_1 = "\
6626 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
6627
6628 char *cpu_fmt_1_line_2 = "\
6629 %-6d %-6d\n";
6630
6631 float elapsed_time;
6632
6633 struct ring_elt *send_ring;
6634 struct ring_elt *recv_ring;
6635
6636 int len;
6637 int nummessages;
6638 SOCKET send_socket;
6639 int trans_remaining;
6640 int bytes_xferd;
6641
6642 int rsp_bytes_recvd;
6643
6644 float local_cpu_utilization;
6645 float local_service_demand;
6646 float remote_cpu_utilization;
6647 float remote_service_demand;
6648 double thruput;
6649
6650 struct addrinfo *local_res;
6651 struct addrinfo *remote_res;
6652
6653 struct udp_rr_request_struct *udp_rr_request;
6654 struct udp_rr_response_struct *udp_rr_response;
6655 struct udp_rr_results_struct *udp_rr_result;
6656
6657 udp_rr_request =
6658 (struct udp_rr_request_struct *)netperf_request.content.test_specific_data;
6659 udp_rr_response =
6660 (struct udp_rr_response_struct *)netperf_response.content.test_specific_data;
6661 udp_rr_result =
6662 (struct udp_rr_results_struct *)netperf_response.content.test_specific_data;
6663
6664 #ifdef WANT_HISTOGRAM
6665 if (verbosity > 1) {
6666 time_hist = HIST_new();
6667 }
6668 #endif
6669
6670 /* since we are now disconnected from the code that established the */
6671 /* control socket, and since we want to be able to use different */
6672 /* protocols and such, we are passed the name of the remote host and */
6673 /* must turn that into the test specific addressing information. */
6674
6675 complete_addrinfos(&remote_res,
6676 &local_res,
6677 remote_host,
6678 SOCK_DGRAM,
6679 IPPROTO_UDP,
6680 0);
6681
6682 if ( print_headers ) {
6683 print_top_test_header("UDP REQUEST/RESPONSE TEST",local_res,remote_res);
6684 }
6685
6686 /* initialize a few counters */
6687
6688 send_ring = NULL;
6689 recv_ring = NULL;
6690 nummessages = 0;
6691 bytes_xferd = 0;
6692 times_up = 0;
6693 confidence_iteration = 1;
6694 init_stat();
6695
6696 /* we have a great-big while loop which controls the number of times */
6697 /* we run a particular test. this is for the calculation of a */
6698 /* confidence interval (I really should have stayed awake during */
6699 /* probstats :). If the user did not request confidence measurement */
6700 /* (no confidence is the default) then we will only go though the */
6701 /* loop once. the confidence stuff originates from the folks at IBM */
6702
6703 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
6704 (confidence_iteration <= iteration_min)) {
6705
6706 nummessages = 0;
6707 bytes_xferd = 0;
6708 times_up = 0;
6709 trans_remaining = 0;
6710
6711 /* set-up the data buffers with the requested alignment and offset */
6712
6713 if (send_width == 0) send_width = 1;
6714 if (recv_width == 0) recv_width = 1;
6715
6716 if (send_ring == NULL) {
6717 send_ring = allocate_buffer_ring(send_width,
6718 req_size,
6719 local_send_align,
6720 local_send_offset);
6721 }
6722
6723 if (recv_ring == NULL) {
6724 recv_ring = allocate_buffer_ring(recv_width,
6725 rsp_size,
6726 local_recv_align,
6727 local_recv_offset);
6728 }
6729
6730 /*set up the data socket */
6731 send_socket = create_data_socket(local_res);
6732
6733 if (send_socket == INVALID_SOCKET){
6734 perror("netperf: send_udp_rr: udp rr data socket");
6735 exit(1);
6736 }
6737
6738 if (debug) {
6739 fprintf(where,"send_udp_rr: send_socket obtained...\n");
6740 }
6741
6742 /* If the user has requested cpu utilization measurements, we must */
6743 /* calibrate the cpu(s). We will perform this task within the tests */
6744 /* themselves. If the user has specified the cpu rate, then */
6745 /* calibrate_local_cpu will return rather quickly as it will have */
6746 /* nothing to do. If local_cpu_rate is zero, then we will go through */
6747 /* all the "normal" calibration stuff and return the rate back. If */
6748 /* there is no idle counter in the kernel idle loop, the */
6749 /* local_cpu_rate will be set to -1. */
6750
6751 if (local_cpu_usage) {
6752 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
6753 }
6754
6755 if (!no_control) {
6756 /* Tell the remote end to do a listen. The server alters the
6757 socket paramters on the other side at this point, hence the
6758 reason for all the values being passed in the setup
6759 message. If the user did not specify any of the parameters,
6760 they will be passed as 0, which will indicate to the remote
6761 that no changes beyond the system's default should be
6762 used. Alignment is the exception, it will default to 8, which
6763 will be no alignment alterations. */
6764
6765 netperf_request.content.request_type = DO_UDP_RR;
6766 udp_rr_request->recv_buf_size = rsr_size_req;
6767 udp_rr_request->send_buf_size = rss_size_req;
6768 udp_rr_request->recv_alignment = remote_recv_align;
6769 udp_rr_request->recv_offset = remote_recv_offset;
6770 udp_rr_request->send_alignment = remote_send_align;
6771 udp_rr_request->send_offset = remote_send_offset;
6772 udp_rr_request->request_size = req_size;
6773 udp_rr_request->response_size = rsp_size;
6774 udp_rr_request->measure_cpu = remote_cpu_usage;
6775 udp_rr_request->cpu_rate = remote_cpu_rate;
6776 udp_rr_request->so_rcvavoid = rem_rcvavoid;
6777 udp_rr_request->so_sndavoid = rem_sndavoid;
6778 if (test_time) {
6779 udp_rr_request->test_length = test_time;
6780 }
6781 else {
6782 udp_rr_request->test_length = test_trans * -1;
6783 }
6784 udp_rr_request->port = atoi(remote_data_port);
6785 udp_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
6786
6787 if (debug > 1) {
6788 fprintf(where,"netperf: send_udp_rr: requesting UDP r/r test\n");
6789 }
6790
6791 send_request();
6792
6793 /* The response from the remote will contain all of the relevant
6794 socket parameters for this test type. We will put them back
6795 into the variables here so they can be displayed if desired.
6796 The remote will have calibrated CPU if necessary, and will
6797 have done all the needed set-up we will have calibrated the
6798 cpu locally before sending the request, and will grab the
6799 counter value right after the connect returns. The remote
6800 will grab the counter right after the accept call. This saves
6801 the hassle of extra messages being sent for the UDP
6802 tests. */
6803
6804 recv_response();
6805
6806 if (!netperf_response.content.serv_errno) {
6807 if (debug)
6808 fprintf(where,"remote listen done.\n");
6809 rsr_size = udp_rr_response->recv_buf_size;
6810 rss_size = udp_rr_response->send_buf_size;
6811 remote_cpu_usage = udp_rr_response->measure_cpu;
6812 remote_cpu_rate = udp_rr_response->cpu_rate;
6813 /* port numbers in proper order */
6814 set_port_number(remote_res,(short)udp_rr_response->data_port_number);
6815 }
6816 else {
6817 Set_errno(netperf_response.content.serv_errno);
6818 fprintf(where,
6819 "netperf: remote error %d",
6820 netperf_response.content.serv_errno);
6821 perror("");
6822 fflush(where);
6823 exit(1);
6824 }
6825 }
6826
6827 #ifdef WANT_DEMO
6828 DEMO_RR_SETUP(100)
6829 #endif
6830
6831 /* Connect up to the remote port on the data socket. This will set */
6832 /* the default destination address on this socket. With UDP, this */
6833 /* does make a performance difference as we may not have to do as */
6834 /* many routing lookups, however, I expect that a client would */
6835 /* behave this way. raj 1/94 */
6836
6837 if ( connect(send_socket,
6838 remote_res->ai_addr,
6839 remote_res->ai_addrlen) == INVALID_SOCKET ) {
6840 perror("netperf: data socket connect failed");
6841 exit(1);
6842 }
6843
6844 /* Data Socket set-up is finished. If there were problems, either the */
6845 /* connect would have failed, or the previous response would have */
6846 /* indicated a problem. I failed to see the value of the extra */
6847 /* message after the accept on the remote. If it failed, we'll see it */
6848 /* here. If it didn't, we might as well start pumping data. */
6849
6850 /* Set-up the test end conditions. For a request/response test, they */
6851 /* can be either time or transaction based. */
6852
6853 if (test_time) {
6854 /* The user wanted to end the test after a period of time. */
6855 times_up = 0;
6856 trans_remaining = 0;
6857 start_timer(test_time);
6858 }
6859 else {
6860 /* The tester wanted to send a number of bytes. */
6861 trans_remaining = test_bytes;
6862 times_up = 1;
6863 }
6864
6865 /* The cpu_start routine will grab the current time and possibly */
6866 /* value of the idle counter for later use in measuring cpu */
6867 /* utilization and/or service demand and thruput. */
6868
6869 cpu_start(local_cpu_usage);
6870
6871 #ifdef WANT_DEMO
6872 if (demo_mode) {
6873 HIST_timestamp(demo_one_ptr);
6874 }
6875 #endif
6876
6877 #ifdef WANT_INTERVALS
6878 INTERVALS_INIT();
6879 #endif /* WANT_INTERVALS */
6880
6881 /* We use an "OR" to control test execution. When the test is */
6882 /* controlled by time, the byte count check will always return */
6883 /* false. When the test is controlled by byte count, the time test */
6884 /* will always return false. When the test is finished, the whole */
6885 /* expression will go false and we will stop sending data. I think */
6886 /* I just arbitrarily decrement trans_remaining for the timed */
6887 /* test, but will not do that just yet... One other question is */
6888 /* whether or not the send buffer and the receive buffer should be */
6889 /* the same buffer. */
6890
6891 #ifdef WANT_FIRST_BURST
6892 {
6893 int i;
6894 for (i = 0; i < first_burst_size; i++) {
6895 if((len=send(send_socket,
6896 send_ring->buffer_ptr,
6897 req_size,
6898 0)) != req_size) {
6899 /* we should never hit the end of the test in the first burst */
6900 perror("send_udp_rr: initial burst data send error");
6901 exit(-1);
6902 }
6903 }
6904 }
6905 #endif /* WANT_FIRST_BURST */
6906
6907 while ((!times_up) || (trans_remaining > 0)) {
6908 /* send the request */
6909 #ifdef WANT_HISTOGRAM
6910 if (verbosity > 1) {
6911 HIST_timestamp(&time_one);
6912 }
6913 #endif
6914 if((len=send(send_socket,
6915 send_ring->buffer_ptr,
6916 req_size,
6917 0)) != req_size) {
6918 if (SOCKET_EINTR(len)) {
6919 /* We likely hit */
6920 /* test-end time. */
6921 break;
6922 }
6923 perror("send_udp_rr: data send error");
6924 exit(1);
6925 }
6926 send_ring = send_ring->next;
6927
6928 /* receive the response. with UDP we will get it all, or nothing */
6929
6930 if((rsp_bytes_recvd=recv(send_socket,
6931 recv_ring->buffer_ptr,
6932 rsp_size,
6933 0)) != rsp_size) {
6934 if (SOCKET_EINTR(rsp_bytes_recvd))
6935 {
6936 /* Again, we have likely hit test-end time */
6937 break;
6938 }
6939 perror("send_udp_rr: data recv error");
6940 exit(1);
6941 }
6942 recv_ring = recv_ring->next;
6943
6944 #ifdef WANT_HISTOGRAM
6945 if (verbosity > 1) {
6946 HIST_timestamp(&time_two);
6947 HIST_add(time_hist,delta_micro(&time_one,&time_two));
6948 }
6949
6950 #endif
6951
6952 /* at this point, we may wish to sleep for some period of */
6953 /* time, so we see how long that last transaction just took, */
6954 /* and sleep for the difference of that and the interval. We */
6955 /* will not sleep if the time would be less than a */
6956 /* millisecond. */
6957
6958 #ifdef WANT_DEMO
6959 DEMO_RR_INTERVAL(1);
6960 #endif
6961
6962 #ifdef WANT_INTERVALS
6963 INTERVALS_WAIT();
6964 #endif /* WANT_INTERVALS */
6965
6966 nummessages++;
6967 if (trans_remaining) {
6968 trans_remaining--;
6969 }
6970
6971 if (debug > 3) {
6972 if ((nummessages % 100) == 0) {
6973 fprintf(where,"Transaction %d completed\n",nummessages);
6974 fflush(where);
6975 }
6976 }
6977
6978 }
6979
6980 /* for some strange reason, I used to call shutdown on the UDP */
6981 /* data socket here. I'm not sure why, because it would not have */
6982 /* any effect... raj 11/94 */
6983
6984 /* this call will always give us the elapsed time for the test, and */
6985 /* will also store-away the necessaries for cpu utilization */
6986
6987 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
6988 /* measured? how long */
6989 /* did we really run? */
6990
6991 if (!no_control) {
6992 /* Get the statistics from the remote end. The remote will have
6993 calculated service demand and all those interesting
6994 things. If it wasn't supposed to care, it will return obvious
6995 values. */
6996
6997 recv_response();
6998 if (!netperf_response.content.serv_errno) {
6999 if (debug)
7000 fprintf(where,"remote results obtained\n");
7001 }
7002 else {
7003 Set_errno(netperf_response.content.serv_errno);
7004 fprintf(where,
7005 "netperf: remote error %d",
7006 netperf_response.content.serv_errno);
7007 perror("");
7008 fflush(where);
7009 exit(1);
7010 }
7011 }
7012
7013 /* We now calculate what our thruput was for the test. In the */
7014 /* future, we may want to include a calculation of the thruput */
7015 /* measured by the remote, but it should be the case that for a */
7016 /* UDP rr test, that the two numbers should be *very* close... */
7017 /* We calculate bytes_sent regardless of the way the test length */
7018 /* was controlled. */
7019
7020 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
7021 thruput = nummessages / elapsed_time;
7022
7023 if (local_cpu_usage || remote_cpu_usage) {
7024
7025 /* We must now do a little math for service demand and cpu */
7026 /* utilization for the system(s) Of course, some of the */
7027 /* information might be bogus because there was no idle counter */
7028 /* in the kernel(s). We need to make a note of this for the */
7029 /* user's benefit by placing a code for the metod used in the */
7030 /* test banner */
7031
7032 if (local_cpu_usage) {
7033 local_cpu_utilization = calc_cpu_util(0.0);
7034
7035 /* since calc_service demand is doing ms/Kunit we will */
7036 /* multiply the number of transaction by 1024 to get */
7037 /* "good" numbers */
7038
7039 local_service_demand = calc_service_demand((double) nummessages*1024,
7040 0.0,
7041 0.0,
7042 0);
7043 }
7044 else {
7045 local_cpu_utilization = (float) -1.0;
7046 local_service_demand = (float) -1.0;
7047 }
7048
7049 if (remote_cpu_usage) {
7050 remote_cpu_utilization = udp_rr_result->cpu_util;
7051
7052 /* since calc_service demand is doing ms/Kunit we will */
7053 /* multiply the number of transaction by 1024 to get */
7054 /* "good" numbers */
7055
7056 remote_service_demand = calc_service_demand((double) nummessages*1024,
7057 0.0,
7058 remote_cpu_utilization,
7059 udp_rr_result->num_cpus);
7060 }
7061 else {
7062 remote_cpu_utilization = (float) -1.0;
7063 remote_service_demand = (float) -1.0;
7064 }
7065 }
7066 else {
7067 /* we were not measuring cpu, for the confidence stuff, we */
7068 /* should make it -1.0 */
7069 local_cpu_utilization = (float) -1.0;
7070 local_service_demand = (float) -1.0;
7071 remote_cpu_utilization = (float) -1.0;
7072 remote_service_demand = (float) -1.0;
7073 }
7074
7075 /* at this point, we want to calculate the confidence information. */
7076 /* if debugging is on, calculate_confidence will print-out the */
7077 /* parameters we pass it */
7078
7079 calculate_confidence(confidence_iteration,
7080 elapsed_time,
7081 thruput,
7082 local_cpu_utilization,
7083 remote_cpu_utilization,
7084 local_service_demand,
7085 remote_service_demand);
7086
7087
7088 confidence_iteration++;
7089
7090 /* we are done with the socket */
7091 close(send_socket);
7092 }
7093
7094 /* at this point, we have made all the iterations we are going to */
7095 /* make. */
7096 retrieve_confident_values(&elapsed_time,
7097 &thruput,
7098 &local_cpu_utilization,
7099 &remote_cpu_utilization,
7100 &local_service_demand,
7101 &remote_service_demand);
7102
7103 /* We are now ready to print all the information. If the user */
7104 /* has specified zero-level verbosity, we will just print the */
7105 /* local service demand, or the remote service demand. If the */
7106 /* user has requested verbosity level 1, he will get the basic */
7107 /* "streamperf" numbers. If the user has specified a verbosity */
7108 /* of greater than 1, we will display a veritable plethora of */
7109 /* background information from outside of this block as it it */
7110 /* not cpu_measurement specific... */
7111
7112 if (confidence < 0) {
7113 /* we did not hit confidence, but were we asked to look for it? */
7114 if (iteration_max > 1) {
7115 display_confidence();
7116 }
7117 }
7118
7119 if (local_cpu_usage || remote_cpu_usage) {
7120 local_cpu_method = format_cpu_method(cpu_method);
7121 remote_cpu_method = format_cpu_method(udp_rr_result->cpu_method);
7122
7123 switch (verbosity) {
7124 case 0:
7125 if (local_cpu_usage) {
7126 fprintf(where,
7127 cpu_fmt_0,
7128 local_service_demand,
7129 local_cpu_method);
7130 }
7131 else {
7132 fprintf(where,
7133 cpu_fmt_0,
7134 remote_service_demand,
7135 remote_cpu_method);
7136 }
7137 break;
7138 case 1:
7139 case 2:
7140 if (print_headers) {
7141 fprintf(where,
7142 cpu_title,
7143 local_cpu_method,
7144 remote_cpu_method);
7145 }
7146
7147 fprintf(where,
7148 cpu_fmt_1_line_1, /* the format string */
7149 lss_size, /* local sendbuf size */
7150 lsr_size,
7151 req_size, /* how large were the requests */
7152 rsp_size, /* guess */
7153 elapsed_time, /* how long was the test */
7154 nummessages/elapsed_time,
7155 local_cpu_utilization, /* local cpu */
7156 remote_cpu_utilization, /* remote cpu */
7157 local_service_demand, /* local service demand */
7158 remote_service_demand); /* remote service demand */
7159 fprintf(where,
7160 cpu_fmt_1_line_2,
7161 rss_size,
7162 rsr_size);
7163 break;
7164 }
7165 }
7166 else {
7167 /* The tester did not wish to measure service demand. */
7168 switch (verbosity) {
7169 case 0:
7170 fprintf(where,
7171 tput_fmt_0,
7172 nummessages/elapsed_time);
7173 break;
7174 case 1:
7175 case 2:
7176 if (print_headers) {
7177 fprintf(where,tput_title,format_units());
7178 }
7179
7180 fprintf(where,
7181 tput_fmt_1_line_1, /* the format string */
7182 lss_size,
7183 lsr_size,
7184 req_size, /* how large were the requests */
7185 rsp_size, /* how large were the responses */
7186 elapsed_time, /* how long did it take */
7187 nummessages/elapsed_time);
7188 fprintf(where,
7189 tput_fmt_1_line_2,
7190 rss_size, /* remote recvbuf size */
7191 rsr_size);
7192
7193 break;
7194 }
7195 }
7196 fflush(where);
7197
7198 /* it would be a good thing to include information about some of the */
7199 /* other parameters that may have been set for this test, but at the */
7200 /* moment, I do not wish to figure-out all the formatting, so I will */
7201 /* just put this comment here to help remind me that it is something */
7202 /* that should be done at a later time. */
7203
7204 /* how to handle the verbose information in the presence of */
7205 /* confidence intervals is yet to be determined... raj 11/94 */
7206
7207 if (verbosity > 1) {
7208 /* The user wanted to know it all, so we will give it to him. */
7209 /* This information will include as much as we can find about */
7210 /* UDP statistics, the alignments of the sends and receives */
7211 /* and all that sort of rot... */
7212
7213 #ifdef WANT_HISTOGRAM
7214 fprintf(where,"\nHistogram of request/reponse times.\n");
7215 fflush(where);
7216 HIST_report(time_hist);
7217 #endif /* WANT_HISTOGRAM */
7218 }
7219 }
7220
7221 /* this routine implements the receive side (netserver) of a UDP_RR */
7222 /* test. */
7223 void
recv_udp_rr()7224 recv_udp_rr()
7225 {
7226
7227 struct ring_elt *recv_ring;
7228 struct ring_elt *send_ring;
7229
7230 struct addrinfo *local_res;
7231 char local_name[BUFSIZ];
7232 char port_buffer[PORTBUFSIZE];
7233
7234 struct sockaddr_storage myaddr_in;
7235 struct sockaddr_storage peeraddr;
7236 SOCKET s_data;
7237 netperf_socklen_t addrlen;
7238 int trans_received;
7239 int trans_remaining;
7240 int request_bytes_recvd;
7241 int response_bytes_sent;
7242 float elapsed_time;
7243
7244 struct udp_rr_request_struct *udp_rr_request;
7245 struct udp_rr_response_struct *udp_rr_response;
7246 struct udp_rr_results_struct *udp_rr_results;
7247
7248 udp_rr_request =
7249 (struct udp_rr_request_struct *)netperf_request.content.test_specific_data;
7250 udp_rr_response =
7251 (struct udp_rr_response_struct *)netperf_response.content.test_specific_data;
7252 udp_rr_results =
7253 (struct udp_rr_results_struct *)netperf_response.content.test_specific_data;
7254
7255 if (debug) {
7256 fprintf(where,"netserver: recv_udp_rr: entered...\n");
7257 fflush(where);
7258 }
7259
7260 /* We want to set-up the listen socket with all the desired */
7261 /* parameters and then let the initiator know that all is ready. If */
7262 /* socket size defaults are to be used, then the initiator will have */
7263 /* sent us 0's. If the socket sizes cannot be changed, then we will */
7264 /* send-back what they are. If that information cannot be determined, */
7265 /* then we send-back -1's for the sizes. If things go wrong for any */
7266 /* reason, we will drop back ten yards and punt. */
7267
7268 /* If anything goes wrong, we want the remote to know about it. It */
7269 /* would be best if the error that the remote reports to the user is */
7270 /* the actual error we encountered, rather than some bogus unexpected */
7271 /* response type message. */
7272
7273 if (debug) {
7274 fprintf(where,"recv_udp_rr: setting the response type...\n");
7275 fflush(where);
7276 }
7277
7278 netperf_response.content.response_type = UDP_RR_RESPONSE;
7279
7280 if (debug) {
7281 fprintf(where,"recv_udp_rr: the response type is set...\n");
7282 fflush(where);
7283 }
7284
7285 /* We now alter the message_ptr variables to be at the desired */
7286 /* alignments with the desired offsets. */
7287
7288 if (debug) {
7289 fprintf(where,"recv_udp_rr: requested recv alignment of %d offset %d\n",
7290 udp_rr_request->recv_alignment,
7291 udp_rr_request->recv_offset);
7292 fprintf(where,"recv_udp_rr: requested send alignment of %d offset %d\n",
7293 udp_rr_request->send_alignment,
7294 udp_rr_request->send_offset);
7295 fflush(where);
7296 }
7297
7298 if (send_width == 0) send_width = 1;
7299 if (recv_width == 0) recv_width = 1;
7300
7301 recv_ring = allocate_buffer_ring(recv_width,
7302 udp_rr_request->request_size,
7303 udp_rr_request->recv_alignment,
7304 udp_rr_request->recv_offset);
7305
7306 send_ring = allocate_buffer_ring(send_width,
7307 udp_rr_request->response_size,
7308 udp_rr_request->send_alignment,
7309 udp_rr_request->send_offset);
7310
7311 if (debug) {
7312 fprintf(where,"recv_udp_rr: receive alignment and offset set...\n");
7313 fflush(where);
7314 }
7315
7316 /* Grab a socket to listen on, and then listen on it. */
7317
7318 if (debug) {
7319 fprintf(where,"recv_udp_rr: grabbing a socket...\n");
7320 fflush(where);
7321 }
7322
7323
7324 /* create_data_socket expects to find some things in the global */
7325 /* variables, so set the globals based on the values in the request. */
7326 /* once the socket has been created, we will set the response values */
7327 /* based on the updated value of those globals. raj 7/94 */
7328 lss_size_req = udp_rr_request->send_buf_size;
7329 lsr_size_req = udp_rr_request->recv_buf_size;
7330 loc_rcvavoid = udp_rr_request->so_rcvavoid;
7331 loc_sndavoid = udp_rr_request->so_sndavoid;
7332
7333 set_hostname_and_port(local_name,
7334 port_buffer,
7335 nf_to_af(udp_rr_request->ipfamily),
7336 udp_rr_request->port);
7337
7338 local_res = complete_addrinfo(local_name,
7339 local_name,
7340 port_buffer,
7341 nf_to_af(udp_rr_request->ipfamily),
7342 SOCK_DGRAM,
7343 IPPROTO_UDP,
7344 0);
7345
7346 s_data = create_data_socket(local_res);
7347
7348 if (s_data == INVALID_SOCKET) {
7349 netperf_response.content.serv_errno = errno;
7350 send_response();
7351
7352 exit(1);
7353 }
7354
7355 /* now get the port number assigned by the system */
7356 addrlen = sizeof(myaddr_in);
7357 if (getsockname(s_data,
7358 (struct sockaddr *)&myaddr_in,
7359 &addrlen) == SOCKET_ERROR){
7360 netperf_response.content.serv_errno = errno;
7361 close(s_data);
7362 send_response();
7363
7364 exit(1);
7365 }
7366
7367 /* Now myaddr_in contains the port and the internet address this is */
7368 /* returned to the sender also implicitly telling the sender that the */
7369 /* socket buffer sizing has been done. */
7370
7371 udp_rr_response->data_port_number =
7372 (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
7373 netperf_response.content.serv_errno = 0;
7374
7375 if (debug) {
7376 fprintf(where,
7377 "recv port number %d\n",
7378 ((struct sockaddr_in *)&myaddr_in)->sin_port);
7379 fflush(where);
7380 }
7381
7382 /* But wait, there's more. If the initiator wanted cpu measurements, */
7383 /* then we must call the calibrate routine, which will return the max */
7384 /* rate back to the initiator. If the CPU was not to be measured, or */
7385 /* something went wrong with the calibration, we will return a 0.0 to */
7386 /* the initiator. */
7387
7388 udp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */
7389 udp_rr_response->measure_cpu = 0;
7390 if (udp_rr_request->measure_cpu) {
7391 udp_rr_response->measure_cpu = 1;
7392 udp_rr_response->cpu_rate = calibrate_local_cpu(udp_rr_request->cpu_rate);
7393 }
7394
7395 /* before we send the response back to the initiator, pull some of */
7396 /* the socket parms from the globals */
7397 udp_rr_response->send_buf_size = lss_size;
7398 udp_rr_response->recv_buf_size = lsr_size;
7399 udp_rr_response->so_rcvavoid = loc_rcvavoid;
7400 udp_rr_response->so_sndavoid = loc_sndavoid;
7401
7402 send_response();
7403
7404
7405 /* Now it's time to start receiving data on the connection. We will */
7406 /* first grab the apropriate counters and then start grabbing. */
7407
7408 cpu_start(udp_rr_request->measure_cpu);
7409
7410 #ifdef WIN32
7411 /* this is used so the timer thread can close the socket out from */
7412 /* under us, which to date is the easiest/cleanest/least */
7413 /* Windows-specific way I can find to force the winsock calls to */
7414 /* return WSAEINTR with the test is over. anything that will run on */
7415 /* 95 and NT and is closer to what netperf expects from Unix signals */
7416 /* and such would be appreciated raj 1/96 */
7417 win_kludge_socket = s_data;
7418 #endif /* WIN32 */
7419
7420 if (udp_rr_request->test_length > 0) {
7421 times_up = 0;
7422 trans_remaining = 0;
7423 start_timer(udp_rr_request->test_length + PAD_TIME);
7424 }
7425 else {
7426 times_up = 1;
7427 trans_remaining = udp_rr_request->test_length * -1;
7428 }
7429
7430 addrlen = sizeof(peeraddr);
7431 bzero((char *)&peeraddr, addrlen);
7432
7433 trans_received = 0;
7434
7435 while ((!times_up) || (trans_remaining > 0)) {
7436
7437 /* receive the request from the other side */
7438 if ((request_bytes_recvd = recvfrom(s_data,
7439 recv_ring->buffer_ptr,
7440 udp_rr_request->request_size,
7441 0,
7442 (struct sockaddr *)&peeraddr,
7443 &addrlen)) != udp_rr_request->request_size) {
7444 if ( SOCKET_EINTR(request_bytes_recvd) )
7445 {
7446 /* we must have hit the end of test time. */
7447 break;
7448 }
7449 netperf_response.content.serv_errno = errno;
7450 send_response();
7451 exit(1);
7452 }
7453 recv_ring = recv_ring->next;
7454
7455 /* Now, send the response to the remote */
7456 if ((response_bytes_sent = sendto(s_data,
7457 send_ring->buffer_ptr,
7458 udp_rr_request->response_size,
7459 0,
7460 (struct sockaddr *)&peeraddr,
7461 addrlen)) !=
7462 udp_rr_request->response_size) {
7463 if ( SOCKET_EINTR(response_bytes_sent) )
7464 {
7465 /* we have hit end of test time. */
7466 break;
7467 }
7468 netperf_response.content.serv_errno = errno;
7469 send_response();
7470 exit(1);
7471 }
7472 send_ring = send_ring->next;
7473
7474 trans_received++;
7475 if (trans_remaining) {
7476 trans_remaining--;
7477 }
7478
7479 if (debug) {
7480 fprintf(where,
7481 "recv_udp_rr: Transaction %d complete.\n",
7482 trans_received);
7483 fflush(where);
7484 }
7485
7486 }
7487
7488
7489 /* The loop now exits due to timeout or transaction count being */
7490 /* reached */
7491
7492 cpu_stop(udp_rr_request->measure_cpu,&elapsed_time);
7493
7494 if (times_up) {
7495 /* we ended the test by time, which was at least 2 seconds */
7496 /* longer than we wanted to run. so, we want to subtract */
7497 /* PAD_TIME from the elapsed_time. */
7498 elapsed_time -= PAD_TIME;
7499 }
7500 /* send the results to the sender */
7501
7502 if (debug) {
7503 fprintf(where,
7504 "recv_udp_rr: got %d transactions\n",
7505 trans_received);
7506 fflush(where);
7507 }
7508
7509 udp_rr_results->bytes_received = (trans_received *
7510 (udp_rr_request->request_size +
7511 udp_rr_request->response_size));
7512 udp_rr_results->trans_received = trans_received;
7513 udp_rr_results->elapsed_time = elapsed_time;
7514 udp_rr_results->cpu_method = cpu_method;
7515 udp_rr_results->num_cpus = lib_num_loc_cpus;
7516 if (udp_rr_request->measure_cpu) {
7517 udp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
7518 }
7519
7520 if (debug) {
7521 fprintf(where,
7522 "recv_udp_rr: test complete, sending results.\n");
7523 fflush(where);
7524 }
7525
7526 send_response();
7527
7528 /* we are done with the socket now */
7529 close(s_data);
7530
7531 }
7532
7533
7534 /* this routine implements the receive (netserver) side of a TCP_RR */
7535 /* test */
7536 void
recv_tcp_rr()7537 recv_tcp_rr()
7538 {
7539
7540 struct ring_elt *send_ring;
7541 struct ring_elt *recv_ring;
7542
7543 struct addrinfo *local_res;
7544 char local_name[BUFSIZ];
7545 char port_buffer[PORTBUFSIZE];
7546
7547 struct sockaddr_storage myaddr_in,
7548 peeraddr_in;
7549 SOCKET s_listen,s_data;
7550 netperf_socklen_t addrlen;
7551 char *temp_message_ptr;
7552 int trans_received;
7553 int trans_remaining;
7554 int bytes_sent;
7555 int request_bytes_recvd;
7556 int request_bytes_remaining;
7557 int timed_out = 0;
7558 int sock_closed = 0;
7559 float elapsed_time;
7560
7561 struct tcp_rr_request_struct *tcp_rr_request;
7562 struct tcp_rr_response_struct *tcp_rr_response;
7563 struct tcp_rr_results_struct *tcp_rr_results;
7564
7565 tcp_rr_request =
7566 (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
7567 tcp_rr_response =
7568 (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
7569 tcp_rr_results =
7570 (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
7571
7572 if (debug) {
7573 fprintf(where,"netserver: recv_tcp_rr: entered...\n");
7574 fflush(where);
7575 }
7576
7577 /* We want to set-up the listen socket with all the desired */
7578 /* parameters and then let the initiator know that all is ready. If */
7579 /* socket size defaults are to be used, then the initiator will have */
7580 /* sent us 0's. If the socket sizes cannot be changed, then we will */
7581 /* send-back what they are. If that information cannot be determined, */
7582 /* then we send-back -1's for the sizes. If things go wrong for any */
7583 /* reason, we will drop back ten yards and punt. */
7584
7585 /* If anything goes wrong, we want the remote to know about it. It */
7586 /* would be best if the error that the remote reports to the user is */
7587 /* the actual error we encountered, rather than some bogus unexpected */
7588 /* response type message. */
7589
7590 if (debug) {
7591 fprintf(where,"recv_tcp_rr: setting the response type...\n");
7592 fflush(where);
7593 }
7594
7595 netperf_response.content.response_type = TCP_RR_RESPONSE;
7596
7597 if (debug) {
7598 fprintf(where,"recv_tcp_rr: the response type is set...\n");
7599 fflush(where);
7600 }
7601
7602 /* allocate the recv and send rings with the requested alignments */
7603 /* and offsets. raj 7/94 */
7604 if (debug) {
7605 fprintf(where,"recv_tcp_rr: requested recv alignment of %d offset %d\n",
7606 tcp_rr_request->recv_alignment,
7607 tcp_rr_request->recv_offset);
7608 fprintf(where,"recv_tcp_rr: requested send alignment of %d offset %d\n",
7609 tcp_rr_request->send_alignment,
7610 tcp_rr_request->send_offset);
7611 fflush(where);
7612 }
7613
7614 /* at some point, these need to come to us from the remote system */
7615 if (send_width == 0) send_width = 1;
7616 if (recv_width == 0) recv_width = 1;
7617
7618 send_ring = allocate_buffer_ring(send_width,
7619 tcp_rr_request->response_size,
7620 tcp_rr_request->send_alignment,
7621 tcp_rr_request->send_offset);
7622
7623 recv_ring = allocate_buffer_ring(recv_width,
7624 tcp_rr_request->request_size,
7625 tcp_rr_request->recv_alignment,
7626 tcp_rr_request->recv_offset);
7627
7628
7629 /* Grab a socket to listen on, and then listen on it. */
7630
7631 if (debug) {
7632 fprintf(where,"recv_tcp_rr: grabbing a socket...\n");
7633 fflush(where);
7634 }
7635
7636 /* create_data_socket expects to find some things in the global */
7637 /* variables, so set the globals based on the values in the request. */
7638 /* once the socket has been created, we will set the response values */
7639 /* based on the updated value of those globals. raj 7/94 */
7640 lss_size_req = tcp_rr_request->send_buf_size;
7641 lsr_size_req = tcp_rr_request->recv_buf_size;
7642 loc_nodelay = tcp_rr_request->no_delay;
7643 loc_rcvavoid = tcp_rr_request->so_rcvavoid;
7644 loc_sndavoid = tcp_rr_request->so_sndavoid;
7645
7646 set_hostname_and_port(local_name,
7647 port_buffer,
7648 nf_to_af(tcp_rr_request->ipfamily),
7649 tcp_rr_request->port);
7650
7651 local_res = complete_addrinfo(local_name,
7652 local_name,
7653 port_buffer,
7654 nf_to_af(tcp_rr_request->ipfamily),
7655 SOCK_STREAM,
7656 IPPROTO_TCP,
7657 0);
7658
7659 s_listen = create_data_socket(local_res);
7660
7661 if (s_listen == INVALID_SOCKET) {
7662 netperf_response.content.serv_errno = errno;
7663 send_response();
7664
7665 exit(1);
7666 }
7667
7668
7669 #ifdef WIN32
7670 /* The test timer can fire during operations on the listening socket,
7671 so to make the start_timer below work we have to move
7672 it to close s_listen while we are blocked on accept. */
7673 win_kludge_socket2 = s_listen;
7674 #endif
7675
7676
7677 /* Now, let's set-up the socket to listen for connections */
7678 if (listen(s_listen, 5) == SOCKET_ERROR) {
7679 netperf_response.content.serv_errno = errno;
7680 close(s_listen);
7681 send_response();
7682
7683 exit(1);
7684 }
7685
7686
7687 /* now get the port number assigned by the system */
7688 addrlen = sizeof(myaddr_in);
7689 if (getsockname(s_listen,
7690 (struct sockaddr *)&myaddr_in,
7691 &addrlen) == SOCKET_ERROR) {
7692 netperf_response.content.serv_errno = errno;
7693 close(s_listen);
7694 send_response();
7695
7696 exit(1);
7697 }
7698
7699 /* Now myaddr_in contains the port and the internet address this is */
7700 /* returned to the sender also implicitly telling the sender that the */
7701 /* socket buffer sizing has been done. */
7702
7703 tcp_rr_response->data_port_number =
7704 (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
7705 netperf_response.content.serv_errno = 0;
7706
7707 /* But wait, there's more. If the initiator wanted cpu measurements, */
7708 /* then we must call the calibrate routine, which will return the max */
7709 /* rate back to the initiator. If the CPU was not to be measured, or */
7710 /* something went wrong with the calibration, we will return a 0.0 to */
7711 /* the initiator. */
7712
7713 tcp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */
7714 tcp_rr_response->measure_cpu = 0;
7715
7716 if (tcp_rr_request->measure_cpu) {
7717 tcp_rr_response->measure_cpu = 1;
7718 tcp_rr_response->cpu_rate = calibrate_local_cpu(tcp_rr_request->cpu_rate);
7719 }
7720
7721
7722 /* before we send the response back to the initiator, pull some of */
7723 /* the socket parms from the globals */
7724 tcp_rr_response->send_buf_size = lss_size;
7725 tcp_rr_response->recv_buf_size = lsr_size;
7726 tcp_rr_response->no_delay = loc_nodelay;
7727 tcp_rr_response->so_rcvavoid = loc_rcvavoid;
7728 tcp_rr_response->so_sndavoid = loc_sndavoid;
7729 tcp_rr_response->test_length = tcp_rr_request->test_length;
7730 send_response();
7731
7732 addrlen = sizeof(peeraddr_in);
7733
7734 if ((s_data = accept(s_listen,
7735 (struct sockaddr *)&peeraddr_in,
7736 &addrlen)) == INVALID_SOCKET) {
7737 /* Let's just punt. The remote will be given some information */
7738 close(s_listen);
7739
7740 exit(1);
7741 }
7742
7743 #ifdef KLUDGE_SOCKET_OPTIONS
7744 /* this is for those systems which *INCORRECTLY* fail to pass */
7745 /* attributes across an accept() call. Including this goes against */
7746 /* my better judgement :( raj 11/95 */
7747
7748 kludge_socket_options(s_data);
7749
7750 #endif /* KLUDGE_SOCKET_OPTIONS */
7751
7752 #ifdef WIN32
7753 /* this is used so the timer thread can close the socket out from */
7754 /* under us, which to date is the easiest/cleanest/least */
7755 /* Windows-specific way I can find to force the winsock calls to */
7756 /* return WSAEINTR with the test is over. anything that will run on */
7757 /* 95 and NT and is closer to what netperf expects from Unix signals */
7758 /* and such would be appreciated raj 1/96 */
7759 win_kludge_socket = s_data;
7760 #endif /* WIN32 */
7761
7762 if (debug) {
7763 fprintf(where,"recv_tcp_rr: accept completes on the data connection.\n");
7764 fflush(where);
7765 }
7766
7767 /* Now it's time to start receiving data on the connection. We will */
7768 /* first grab the apropriate counters and then start grabbing. */
7769
7770 cpu_start(tcp_rr_request->measure_cpu);
7771
7772 /* The loop will exit when we hit the end of the test time, or when */
7773 /* we have exchanged the requested number of transactions. */
7774
7775 if (tcp_rr_request->test_length > 0) {
7776 times_up = 0;
7777 trans_remaining = 0;
7778 start_timer(tcp_rr_request->test_length + PAD_TIME);
7779 }
7780 else {
7781 times_up = 1;
7782 trans_remaining = tcp_rr_request->test_length * -1;
7783 }
7784
7785 trans_received = 0;
7786
7787 while ((!times_up) || (trans_remaining > 0)) {
7788 temp_message_ptr = recv_ring->buffer_ptr;
7789 request_bytes_remaining = tcp_rr_request->request_size;
7790 while(request_bytes_remaining > 0) {
7791 if((request_bytes_recvd=recv(s_data,
7792 temp_message_ptr,
7793 request_bytes_remaining,
7794 0)) == SOCKET_ERROR) {
7795 if (SOCKET_EINTR(request_bytes_recvd))
7796 {
7797 timed_out = 1;
7798 break;
7799 }
7800
7801 netperf_response.content.serv_errno = errno;
7802 send_response();
7803 exit(1);
7804 }
7805 else if( request_bytes_recvd == 0 ) {
7806 if (debug) {
7807 fprintf(where,"zero is my hero\n");
7808 fflush(where);
7809 }
7810 sock_closed = 1;
7811 break;
7812 }
7813 else {
7814 request_bytes_remaining -= request_bytes_recvd;
7815 temp_message_ptr += request_bytes_recvd;
7816 }
7817 }
7818
7819 recv_ring = recv_ring->next;
7820
7821 if ((timed_out) || (sock_closed)) {
7822 /* we hit the end of the test based on time - or the socket
7823 closed on us along the way. bail out of here now... */
7824 if (debug) {
7825 fprintf(where,"yo5\n");
7826 fflush(where);
7827 }
7828 break;
7829 }
7830
7831 /* Now, send the response to the remote */
7832 if((bytes_sent=send(s_data,
7833 send_ring->buffer_ptr,
7834 tcp_rr_request->response_size,
7835 0)) == SOCKET_ERROR) {
7836 if (SOCKET_EINTR(bytes_sent)) {
7837 /* the test timer has popped */
7838 timed_out = 1;
7839 fprintf(where,"yo6\n");
7840 fflush(where);
7841 break;
7842 }
7843 netperf_response.content.serv_errno = 992;
7844 send_response();
7845 exit(1);
7846 }
7847
7848 send_ring = send_ring->next;
7849
7850 trans_received++;
7851 if (trans_remaining) {
7852 trans_remaining--;
7853 }
7854 }
7855
7856
7857 /* The loop now exits due to timeout or transaction count being */
7858 /* reached */
7859
7860 cpu_stop(tcp_rr_request->measure_cpu,&elapsed_time);
7861
7862 stop_timer();
7863
7864 if (timed_out) {
7865 /* we ended the test by time, which was at least 2 seconds */
7866 /* longer than we wanted to run. so, we want to subtract */
7867 /* PAD_TIME from the elapsed_time. */
7868 elapsed_time -= PAD_TIME;
7869 }
7870
7871 /* send the results to the sender */
7872
7873 if (debug) {
7874 fprintf(where,
7875 "recv_tcp_rr: got %d transactions\n",
7876 trans_received);
7877 fflush(where);
7878 }
7879
7880 tcp_rr_results->bytes_received = (trans_received *
7881 (tcp_rr_request->request_size +
7882 tcp_rr_request->response_size));
7883 tcp_rr_results->trans_received = trans_received;
7884 tcp_rr_results->elapsed_time = elapsed_time;
7885 tcp_rr_results->cpu_method = cpu_method;
7886 tcp_rr_results->num_cpus = lib_num_loc_cpus;
7887 if (tcp_rr_request->measure_cpu) {
7888 tcp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
7889 }
7890
7891 if (debug) {
7892 fprintf(where,
7893 "recv_tcp_rr: test complete, sending results.\n");
7894 fflush(where);
7895 }
7896
7897 /* we are now done with the sockets */
7898 close(s_data);
7899 close(s_listen);
7900
7901 send_response();
7902
7903 }
7904
7905
7906 void
loc_cpu_rate()7907 loc_cpu_rate()
7908 {
7909 #if defined(USE_LOOPER)
7910 float dummy;
7911 #endif
7912
7913 /* a rather simple little test - it merely calibrates the local cpu */
7914 /* and prints the results. There are no headers to allow someone to */
7915 /* find a rate and use it in other tests automagically by setting a */
7916 /* variable equal to the output of this test. We ignore any rates */
7917 /* that may have been specified. In fact, we ignore all of the */
7918 /* command line args! */
7919
7920 fprintf(where,
7921 "%g",
7922 calibrate_local_cpu(0.0));
7923
7924 if (verbosity > 1)
7925 fprintf(where,
7926 "\nThere %s %d local %s\n",
7927 (lib_num_loc_cpus > 1) ? "are" : "is",
7928 lib_num_loc_cpus,
7929 (lib_num_loc_cpus > 1) ? "cpus" : "cpu");
7930
7931 /* we need the cpu_start, cpu_stop in the looper case to kill the */
7932 /* child proceses raj 4/95 */
7933
7934 #ifdef USE_LOOPER
7935 cpu_start(1);
7936 cpu_stop(1,&dummy);
7937 #endif /* USE_LOOPER */
7938
7939 }
7940
7941 void
rem_cpu_rate()7942 rem_cpu_rate()
7943 {
7944 /* this test is much like the local variant, except that it works for */
7945 /* the remote system, so in this case, we do pay attention to the */
7946 /* value of the '-H' command line argument. */
7947
7948 fprintf(where,
7949 "%g",
7950 calibrate_remote_cpu());
7951
7952 if (verbosity > 1)
7953 fprintf(where,
7954 "\nThere %s %d remote %s\n",
7955 (lib_num_rem_cpus > 1) ? "are" : "is",
7956 lib_num_rem_cpus,
7957 (lib_num_rem_cpus > 1) ? "cpus" : "cpu");
7958
7959 }
7960
7961
7962 /* this test is intended to test the performance of establishing a
7963 connection, exchanging a request/response pair, and repeating. it
7964 is expected that this would be a good starting-point for
7965 comparision of T/TCP with classic TCP for transactional workloads.
7966 it will also look (can look) much like the communication pattern
7967 of http for www access. */
7968
7969 void
send_tcp_conn_rr(char remote_host[])7970 send_tcp_conn_rr(char remote_host[])
7971 {
7972
7973 char *tput_title = "\
7974 Local /Remote\n\
7975 Socket Size Request Resp. Elapsed Trans.\n\
7976 Send Recv Size Size Time Rate \n\
7977 bytes Bytes bytes bytes secs. per sec \n\n";
7978
7979 char *tput_fmt_0 =
7980 "%7.2f\n";
7981
7982 char *tput_fmt_1_line_1 = "\
7983 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
7984 char *tput_fmt_1_line_2 = "\
7985 %-6d %-6d\n";
7986
7987 char *cpu_title = "\
7988 Local /Remote\n\
7989 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
7990 Send Recv Size Size Time Rate local remote local remote\n\
7991 bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
7992
7993 char *cpu_fmt_0 =
7994 "%6.3f\n";
7995
7996 char *cpu_fmt_1_line_1 = "\
7997 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
7998
7999 char *cpu_fmt_1_line_2 = "\
8000 %-6d %-6d\n";
8001
8002 char *ksink_fmt = "\n\
8003 Alignment Offset\n\
8004 Local Remote Local Remote\n\
8005 Send Recv Send Recv\n\
8006 %5d %5d %5d %5d\n";
8007
8008
8009 int timed_out = 0;
8010 float elapsed_time;
8011
8012 int len;
8013 struct ring_elt *send_ring;
8014 struct ring_elt *recv_ring;
8015 char *temp_message_ptr;
8016 int nummessages;
8017 SOCKET send_socket;
8018 int trans_remaining;
8019 double bytes_xferd;
8020 int rsp_bytes_left;
8021 int rsp_bytes_recvd;
8022
8023 float local_cpu_utilization;
8024 float local_service_demand;
8025 float remote_cpu_utilization;
8026 float remote_service_demand;
8027 double thruput;
8028
8029 struct addrinfo *local_res;
8030 struct addrinfo *remote_res;
8031
8032 int myport;
8033 int ret;
8034
8035 struct tcp_conn_rr_request_struct *tcp_conn_rr_request;
8036 struct tcp_conn_rr_response_struct *tcp_conn_rr_response;
8037 struct tcp_conn_rr_results_struct *tcp_conn_rr_result;
8038
8039 tcp_conn_rr_request =
8040 (struct tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
8041 tcp_conn_rr_response =
8042 (struct tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
8043 tcp_conn_rr_result =
8044 (struct tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
8045
8046
8047 #ifdef WANT_HISTOGRAM
8048 if (verbosity > 1) {
8049 time_hist = HIST_new();
8050 }
8051 #endif /* WANT_HISTOGRAM */
8052
8053 /* since we are now disconnected from the code that established the */
8054 /* control socket, and since we want to be able to use different */
8055 /* protocols and such, we are passed the name of the remote host and */
8056 /* must turn that into the test specific addressing information. */
8057
8058 complete_addrinfos(&remote_res,
8059 &local_res,
8060 remote_host,
8061 SOCK_STREAM,
8062 IPPROTO_TCP,
8063 0);
8064
8065 if ( print_headers ) {
8066 print_top_test_header("TCP Connect/Request/Response TEST",local_res,remote_res);
8067 }
8068
8069 /* initialize a few counters */
8070
8071 nummessages = 0;
8072 bytes_xferd = 0.0;
8073 times_up = 0;
8074
8075 /* set-up the data buffers with the requested alignment and offset */
8076 if (send_width == 0) send_width = 1;
8077 if (recv_width == 0) recv_width = 1;
8078
8079 send_ring = allocate_buffer_ring(send_width,
8080 req_size,
8081 local_send_align,
8082 local_send_offset);
8083
8084 recv_ring = allocate_buffer_ring(recv_width,
8085 rsp_size,
8086 local_recv_align,
8087 local_recv_offset);
8088
8089
8090 if (debug) {
8091 fprintf(where,"send_tcp_conn_rr: send_socket obtained...\n");
8092 }
8093
8094 /* If the user has requested cpu utilization measurements, we must */
8095 /* calibrate the cpu(s). We will perform this task within the tests */
8096 /* themselves. If the user has specified the cpu rate, then */
8097 /* calibrate_local_cpu will return rather quickly as it will have */
8098 /* nothing to do. If local_cpu_rate is zero, then we will go through */
8099 /* all the "normal" calibration stuff and return the rate back.*/
8100
8101 if (local_cpu_usage) {
8102 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
8103 }
8104
8105 if (!no_control) {
8106
8107 /* Tell the remote end to do a listen. The server alters the
8108 socket paramters on the other side at this point, hence the
8109 reason for all the values being passed in the setup message. If
8110 the user did not specify any of the parameters, they will be
8111 passed as 0, which will indicate to the remote that no changes
8112 beyond the system's default should be used. Alignment is the
8113 exception, it will default to 8, which will be no alignment
8114 alterations. */
8115
8116 netperf_request.content.request_type = DO_TCP_CRR;
8117 tcp_conn_rr_request->recv_buf_size = rsr_size_req;
8118 tcp_conn_rr_request->send_buf_size = rss_size_req;
8119 tcp_conn_rr_request->recv_alignment = remote_recv_align;
8120 tcp_conn_rr_request->recv_offset = remote_recv_offset;
8121 tcp_conn_rr_request->send_alignment = remote_send_align;
8122 tcp_conn_rr_request->send_offset = remote_send_offset;
8123 tcp_conn_rr_request->request_size = req_size;
8124 tcp_conn_rr_request->response_size = rsp_size;
8125 tcp_conn_rr_request->no_delay = rem_nodelay;
8126 tcp_conn_rr_request->measure_cpu = remote_cpu_usage;
8127 tcp_conn_rr_request->cpu_rate = remote_cpu_rate;
8128 tcp_conn_rr_request->so_rcvavoid = rem_rcvavoid;
8129 tcp_conn_rr_request->so_sndavoid = rem_sndavoid;
8130 if (test_time) {
8131 tcp_conn_rr_request->test_length = test_time;
8132 }
8133 else {
8134 tcp_conn_rr_request->test_length = test_trans * -1;
8135 }
8136 tcp_conn_rr_request->port = atoi(remote_data_port);
8137 tcp_conn_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
8138
8139 if (debug > 1) {
8140 fprintf(where,"netperf: send_tcp_conn_rr: requesting TCP crr test\n");
8141 }
8142
8143 send_request();
8144
8145 /* The response from the remote will contain all of the relevant
8146 socket parameters for this test type. We will put them back
8147 into the variables here so they can be displayed if desired.
8148 The remote will have calibrated CPU if necessary, and will have
8149 done all the needed set-up we will have calibrated the cpu
8150 locally before sending the request, and will grab the counter
8151 value right after the connect returns. The remote will grab the
8152 counter right after the accept call. This saves the hassle of
8153 extra messages being sent for the TCP tests. */
8154
8155 recv_response();
8156
8157 if (!netperf_response.content.serv_errno) {
8158 rsr_size = tcp_conn_rr_response->recv_buf_size;
8159 rss_size = tcp_conn_rr_response->send_buf_size;
8160 rem_nodelay = tcp_conn_rr_response->no_delay;
8161 remote_cpu_usage = tcp_conn_rr_response->measure_cpu;
8162 remote_cpu_rate = tcp_conn_rr_response->cpu_rate;
8163 /* make sure that port numbers are in network order */
8164 set_port_number(remote_res,
8165 (unsigned short)tcp_conn_rr_response->data_port_number);
8166
8167 if (debug) {
8168 fprintf(where,"remote listen done.\n");
8169 fprintf(where,"remote port is %u\n",get_port_number(remote_res));
8170 fflush(where);
8171 }
8172 }
8173 else {
8174 Set_errno(netperf_response.content.serv_errno);
8175 fprintf(where,
8176 "netperf: remote error %d",
8177 netperf_response.content.serv_errno);
8178 perror("");
8179 fflush(where);
8180 exit(1);
8181 }
8182 }
8183 #ifdef WANT_DEMO
8184 DEMO_RR_SETUP(100)
8185 #endif
8186
8187 /* pick a nice random spot between client_port_min and */
8188 /* client_port_max for our initial port number */
8189 srand(getpid());
8190 if (client_port_max - client_port_min) {
8191 myport = client_port_min +
8192 (rand() % (client_port_max - client_port_min));
8193 }
8194 else {
8195 myport = client_port_min;
8196 }
8197 /* there will be a ++ before the first call to bind, so subtract one */
8198 myport--;
8199 /* Set-up the test end conditions. For a request/response test, they */
8200 /* can be either time or transaction based. */
8201
8202 if (test_time) {
8203 /* The user wanted to end the test after a period of time. */
8204 times_up = 0;
8205 trans_remaining = 0;
8206 start_timer(test_time);
8207 }
8208 else {
8209 /* The tester wanted to send a number of bytes. */
8210 trans_remaining = test_bytes;
8211 times_up = 1;
8212 }
8213
8214 /* The cpu_start routine will grab the current time and possibly */
8215 /* value of the idle counter for later use in measuring cpu */
8216 /* utilization and/or service demand and thruput. */
8217
8218
8219 cpu_start(local_cpu_usage);
8220
8221 #ifdef WANT_DEMO
8222 if (demo_mode) {
8223 HIST_timestamp(demo_one_ptr);
8224 }
8225 #endif
8226
8227 /* We use an "OR" to control test execution. When the test is */
8228 /* controlled by time, the byte count check will always return false. */
8229 /* When the test is controlled by byte count, the time test will */
8230 /* always return false. When the test is finished, the whole */
8231 /* expression will go false and we will stop sending data. I think I */
8232 /* just arbitrarily decrement trans_remaining for the timed test, but */
8233 /* will not do that just yet... One other question is whether or not */
8234 /* the send buffer and the receive buffer should be the same buffer. */
8235
8236 while ((!times_up) || (trans_remaining > 0)) {
8237
8238 #ifdef WANT_HISTOGRAM
8239 if (verbosity > 1) {
8240 /* timestamp just before our call to create the socket, and then */
8241 /* again just after the receive raj 3/95 */
8242 HIST_timestamp(&time_one);
8243 }
8244 #endif /* WANT_HISTOGRAM */
8245
8246 newport:
8247 /* pick a new port number */
8248 myport++;
8249
8250 /* wrap the port number when we get to client_port_max. NOTE, some */
8251 /* broken TCP's might treat the port number as a signed 16 bit */
8252 /* quantity. we aren't interested in testing such broken */
8253 /* implementations :) so we won't make sure that it is below 32767 */
8254 /* raj 8/94 */
8255 if (myport >= client_port_max) {
8256 myport = client_port_min;
8257 }
8258
8259 /* we do not want to use the port number that the server is */
8260 /* sitting at - this would cause us to fail in a loopback test. we */
8261 /* could just rely on the failure of the bind to get us past this, */
8262 /* but I'm guessing that in this one case at least, it is much */
8263 /* faster, given that we *know* that port number is already in use */
8264 /* (or rather would be in a loopback test) */
8265
8266 if (myport == get_port_number(remote_res)) myport++;
8267
8268 if (debug) {
8269 if ((nummessages % 100) == 0) {
8270 printf("port %d\n",myport);
8271 }
8272 }
8273
8274 /* set up the data socket */
8275 set_port_number(local_res, (unsigned short)myport);
8276 send_socket = create_data_socket(local_res);
8277
8278 if (send_socket == INVALID_SOCKET) {
8279 perror("netperf: send_tcp_conn_rr: tcp stream data socket");
8280 exit(1);
8281 }
8282
8283
8284 /* we used to call bind here, but that is now taken-care-of by the
8285 create_data_socket routine. */
8286
8287 /* Connect up to the remote port on the data socket */
8288 if ((ret = connect(send_socket,
8289 remote_res->ai_addr,
8290 remote_res->ai_addrlen)) == INVALID_SOCKET){
8291 if (SOCKET_EINTR(ret))
8292 {
8293 /* we hit the end of a */
8294 /* timed test. */
8295 timed_out = 1;
8296 break;
8297 }
8298 if ((SOCKET_EADDRINUSE(ret)) || SOCKET_EADDRNOTAVAIL(ret)) {
8299 /* likely something our explicit bind() would have caught in
8300 the past, so go get another port, via create_data_socket.
8301 yes, this is a bit more overhead than before, but the
8302 condition should be rather rare. raj 2005-02-08 */
8303 close(send_socket);
8304 goto newport;
8305 }
8306 perror("netperf: data socket connect failed");
8307 printf("\tattempted to connect on socket %d to port %d",
8308 send_socket,
8309 get_port_number(remote_res));
8310 printf(" from port %d \n",get_port_number(local_res));
8311 exit(1);
8312 }
8313
8314
8315 /* send the request */
8316 if((len=send(send_socket,
8317 send_ring->buffer_ptr,
8318 req_size,
8319 0)) != req_size) {
8320 if (SOCKET_EINTR(len))
8321 {
8322 /* we hit the end of a */
8323 /* timed test. */
8324 timed_out = 1;
8325 break;
8326 }
8327 perror("send_tcp_conn_rr: data send error");
8328 exit(1);
8329 }
8330 send_ring = send_ring->next;
8331
8332 /* receive the response */
8333 rsp_bytes_left = rsp_size;
8334 temp_message_ptr = recv_ring->buffer_ptr;
8335
8336
8337 do {
8338 rsp_bytes_recvd = recv(send_socket,
8339 temp_message_ptr,
8340 rsp_bytes_left,
8341 0);
8342 if (rsp_bytes_recvd > 0) {
8343 rsp_bytes_left -= rsp_bytes_recvd;
8344 temp_message_ptr += rsp_bytes_recvd;
8345 }
8346 else {
8347 break;
8348 }
8349 } while (rsp_bytes_left);
8350
8351
8352 /* OK, we are out of the loop - now what? */
8353 if (rsp_bytes_recvd < 0) {
8354 /* did the timer hit, or was there an error? */
8355 if (SOCKET_EINTR(rsp_bytes_recvd))
8356 {
8357 /* We hit the end of a timed test. */
8358 timed_out = 1;
8359 break;
8360 }
8361 perror("send_tcp_conn_rr: data recv error");
8362 exit(1);
8363 }
8364
8365 /* if this is a no_control test, we initiate connection close,
8366 otherwise the remote netserver does it to remain just like
8367 previous behaviour. raj 2007-27-08 */
8368 if (!no_control) {
8369 shutdown(send_socket,SHUT_WR);
8370 }
8371
8372 /* we are expecting to get either a return of zero indicating
8373 connection close, or an error. */
8374 rsp_bytes_recvd = recv(send_socket,
8375 temp_message_ptr,
8376 1,
8377 0);
8378
8379 /* our exit from the while loop should generally be when */
8380 /* tmp_bytes_recvd is equal to zero, which implies the connection */
8381 /* has been closed by the server side. By waiting until we get the */
8382 /* zero return we can avoid race conditions that stick us with the */
8383 /* TIME_WAIT connection and not the server. raj 8/96 */
8384
8385 if (rsp_bytes_recvd == 0) {
8386 /* connection close, call close. we assume that the requisite */
8387 /* number of bytes have been received */
8388 recv_ring = recv_ring->next;
8389
8390 #ifdef WANT_HISTOGRAM
8391 if (verbosity > 1) {
8392 HIST_timestamp(&time_two);
8393 HIST_add(time_hist,delta_micro(&time_one,&time_two));
8394 }
8395 #endif /* WANT_HISTOGRAM */
8396
8397 #ifdef WANT_DEMO
8398 DEMO_RR_INTERVAL(1)
8399 #endif
8400
8401 nummessages++;
8402 if (trans_remaining) {
8403 trans_remaining--;
8404 }
8405
8406 if (debug > 3) {
8407 fprintf(where,
8408 "Transaction %d completed on local port %d\n",
8409 nummessages,
8410 get_port_number(local_res));
8411 fflush(where);
8412 }
8413
8414 close(send_socket);
8415
8416 }
8417 else {
8418 /* it was less than zero - an error occured */
8419 if (SOCKET_EINTR(rsp_bytes_recvd))
8420 {
8421 /* We hit the end of a timed test. */
8422 timed_out = 1;
8423 break;
8424 }
8425 perror("send_tcp_conn_rr: data recv error");
8426 exit(1);
8427 }
8428
8429 }
8430
8431
8432 /* this call will always give us the elapsed time for the test, and */
8433 /* will also store-away the necessaries for cpu utilization */
8434
8435 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
8436 /* how long did we really run? */
8437
8438 if (!no_control) {
8439 /* Get the statistics from the remote end. The remote will have
8440 calculated service demand and all those interesting things. If
8441 it wasn't supposed to care, it will return obvious values. */
8442
8443 recv_response();
8444 if (!netperf_response.content.serv_errno) {
8445 if (debug)
8446 fprintf(where,"remote results obtained\n");
8447 }
8448 else {
8449 Set_errno(netperf_response.content.serv_errno);
8450 fprintf(where,
8451 "netperf: remote error %d",
8452 netperf_response.content.serv_errno);
8453 perror("");
8454 fflush(where);
8455
8456 exit(1);
8457 }
8458 }
8459
8460 /* We now calculate what our thruput was for the test. In the future, */
8461 /* we may want to include a calculation of the thruput measured by */
8462 /* the remote, but it should be the case that for a TCP stream test, */
8463 /* that the two numbers should be *very* close... We calculate */
8464 /* bytes_sent regardless of the way the test length was controlled. */
8465 /* If it was time, we needed to, and if it was by bytes, the user may */
8466 /* have specified a number of bytes that wasn't a multiple of the */
8467 /* send_size, so we really didn't send what he asked for ;-) We use */
8468 /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
8469 /* 1024. A future enhancement *might* be to choose from a couple of */
8470 /* unit selections. */
8471
8472 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
8473 thruput = calc_thruput(bytes_xferd);
8474
8475 if (local_cpu_usage || remote_cpu_usage) {
8476 /* We must now do a little math for service demand and cpu */
8477 /* utilization for the system(s) */
8478 /* Of course, some of the information might be bogus because */
8479 /* there was no idle counter in the kernel(s). We need to make */
8480 /* a note of this for the user's benefit...*/
8481 if (local_cpu_usage) {
8482 if (local_cpu_rate == 0.0) {
8483 fprintf(where,
8484 "WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
8485 fprintf(where,
8486 "Local CPU usage numbers based on process information only!\n");
8487 fflush(where);
8488 }
8489 local_cpu_utilization = calc_cpu_util(0.0);
8490 /* since calc_service demand is doing ms/Kunit we will */
8491 /* multiply the number of transaction by 1024 to get */
8492 /* "good" numbers */
8493 local_service_demand = calc_service_demand((double) nummessages*1024,
8494 0.0,
8495 0.0,
8496 0);
8497 }
8498 else {
8499 local_cpu_utilization = (float) -1.0;
8500 local_service_demand = (float) -1.0;
8501 }
8502
8503 if (remote_cpu_usage) {
8504 if (remote_cpu_rate == 0.0) {
8505 fprintf(where,
8506 "DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
8507 fprintf(where,
8508 "Remote CPU usage numbers based on process information only!\n");
8509 fflush(where);
8510 }
8511 remote_cpu_utilization = tcp_conn_rr_result->cpu_util;
8512 /* since calc_service demand is doing ms/Kunit we will */
8513 /* multiply the number of transaction by 1024 to get */
8514 /* "good" numbers */
8515 remote_service_demand = calc_service_demand((double) nummessages*1024,
8516 0.0,
8517 remote_cpu_utilization,
8518 tcp_conn_rr_result->num_cpus);
8519 }
8520 else {
8521 remote_cpu_utilization = (float) -1.0;
8522 remote_service_demand = (float) -1.0;
8523 }
8524
8525 /* We are now ready to print all the information. If the user */
8526 /* has specified zero-level verbosity, we will just print the */
8527 /* local service demand, or the remote service demand. If the */
8528 /* user has requested verbosity level 1, he will get the basic */
8529 /* "streamperf" numbers. If the user has specified a verbosity */
8530 /* of greater than 1, we will display a veritable plethora of */
8531 /* background information from outside of this block as it it */
8532 /* not cpu_measurement specific... */
8533
8534 switch (verbosity) {
8535 case 0:
8536 if (local_cpu_usage) {
8537 fprintf(where,
8538 cpu_fmt_0,
8539 local_service_demand);
8540 }
8541 else {
8542 fprintf(where,
8543 cpu_fmt_0,
8544 remote_service_demand);
8545 }
8546 break;
8547 case 1:
8548 case 2:
8549
8550 if (print_headers) {
8551 fprintf(where,
8552 cpu_title,
8553 local_cpu_method,
8554 remote_cpu_method);
8555 }
8556
8557 fprintf(where,
8558 cpu_fmt_1_line_1, /* the format string */
8559 lss_size, /* local sendbuf size */
8560 lsr_size,
8561 req_size, /* how large were the requests */
8562 rsp_size, /* guess */
8563 elapsed_time, /* how long was the test */
8564 nummessages/elapsed_time,
8565 local_cpu_utilization, /* local cpu */
8566 remote_cpu_utilization, /* remote cpu */
8567 local_service_demand, /* local service demand */
8568 remote_service_demand); /* remote service demand */
8569 fprintf(where,
8570 cpu_fmt_1_line_2,
8571 rss_size,
8572 rsr_size);
8573 break;
8574 }
8575 }
8576 else {
8577 /* The tester did not wish to measure service demand. */
8578 switch (verbosity) {
8579 case 0:
8580 fprintf(where,
8581 tput_fmt_0,
8582 nummessages/elapsed_time);
8583 break;
8584 case 1:
8585 case 2:
8586 if (print_headers) {
8587 fprintf(where,tput_title,format_units());
8588 }
8589
8590 fprintf(where,
8591 tput_fmt_1_line_1, /* the format string */
8592 lss_size,
8593 lsr_size,
8594 req_size, /* how large were the requests */
8595 rsp_size, /* how large were the responses */
8596 elapsed_time, /* how long did it take */
8597 nummessages/elapsed_time);
8598 fprintf(where,
8599 tput_fmt_1_line_2,
8600 rss_size, /* remote recvbuf size */
8601 rsr_size);
8602
8603 break;
8604 }
8605 }
8606
8607 /* it would be a good thing to include information about some of the */
8608 /* other parameters that may have been set for this test, but at the */
8609 /* moment, I do not wish to figure-out all the formatting, so I will */
8610 /* just put this comment here to help remind me that it is something */
8611 /* that should be done at a later time. */
8612
8613 if (verbosity > 1) {
8614 /* The user wanted to know it all, so we will give it to him. */
8615 /* This information will include as much as we can find about */
8616 /* TCP statistics, the alignments of the sends and receives */
8617 /* and all that sort of rot... */
8618
8619 fprintf(where,
8620 ksink_fmt,
8621 local_send_align,
8622 remote_recv_offset,
8623 local_send_offset,
8624 remote_recv_offset);
8625
8626 #ifdef WANT_HISTOGRAM
8627 fprintf(where,"\nHistogram of request/response times\n");
8628 fflush(where);
8629 HIST_report(time_hist);
8630 #endif /* WANT_HISTOGRAM */
8631
8632 }
8633
8634 }
8635
8636
8637 void
recv_tcp_conn_rr()8638 recv_tcp_conn_rr()
8639 {
8640
8641 char *message;
8642 struct addrinfo *local_res;
8643 char local_name[BUFSIZ];
8644 char port_buffer[PORTBUFSIZE];
8645
8646 struct sockaddr_storage myaddr_in, peeraddr_in;
8647 SOCKET s_listen,s_data;
8648 netperf_socklen_t addrlen;
8649 char *recv_message_ptr;
8650 char *send_message_ptr;
8651 char *temp_message_ptr;
8652 int trans_received;
8653 int trans_remaining;
8654 int bytes_sent;
8655 int request_bytes_recvd;
8656 int request_bytes_remaining;
8657 int timed_out = 0;
8658 float elapsed_time;
8659
8660 struct tcp_conn_rr_request_struct *tcp_conn_rr_request;
8661 struct tcp_conn_rr_response_struct *tcp_conn_rr_response;
8662 struct tcp_conn_rr_results_struct *tcp_conn_rr_results;
8663
8664 tcp_conn_rr_request =
8665 (struct tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
8666 tcp_conn_rr_response =
8667 (struct tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
8668 tcp_conn_rr_results =
8669 (struct tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
8670
8671 if (debug) {
8672 fprintf(where,"netserver: recv_tcp_conn_rr: entered...\n");
8673 fflush(where);
8674 }
8675
8676 /* We want to set-up the listen socket with all the desired */
8677 /* parameters and then let the initiator know that all is ready. If */
8678 /* socket size defaults are to be used, then the initiator will have */
8679 /* sent us 0's. If the socket sizes cannot be changed, then we will */
8680 /* send-back what they are. If that information cannot be determined, */
8681 /* then we send-back -1's for the sizes. If things go wrong for any */
8682 /* reason, we will drop back ten yards and punt. */
8683
8684 /* If anything goes wrong, we want the remote to know about it. It */
8685 /* would be best if the error that the remote reports to the user is */
8686 /* the actual error we encountered, rather than some bogus unexpected */
8687 /* response type message. */
8688
8689 if (debug) {
8690 fprintf(where,"recv_tcp_conn_rr: setting the response type...\n");
8691 fflush(where);
8692 }
8693
8694 netperf_response.content.response_type = TCP_CRR_RESPONSE;
8695
8696 if (debug) {
8697 fprintf(where,"recv_tcp_conn_rr: the response type is set...\n");
8698 fflush(where);
8699 }
8700
8701 /* set-up the data buffer with the requested alignment and offset */
8702 message = (char *)malloc(DATABUFFERLEN);
8703 if (message == NULL) {
8704 printf("malloc(%d) failed!\n", DATABUFFERLEN);
8705 exit(1);
8706 }
8707
8708 /* We now alter the message_ptr variables to be at the desired */
8709 /* alignments with the desired offsets. */
8710
8711 if (debug) {
8712 fprintf(where,
8713 "recv_tcp_conn_rr: requested recv alignment of %d offset %d\n",
8714 tcp_conn_rr_request->recv_alignment,
8715 tcp_conn_rr_request->recv_offset);
8716 fprintf(where,
8717 "recv_tcp_conn_rr: requested send alignment of %d offset %d\n",
8718 tcp_conn_rr_request->send_alignment,
8719 tcp_conn_rr_request->send_offset);
8720 fflush(where);
8721 }
8722
8723 recv_message_ptr = ALIGN_BUFFER(message, tcp_conn_rr_request->recv_alignment, tcp_conn_rr_request->recv_offset);
8724
8725 send_message_ptr = ALIGN_BUFFER(message, tcp_conn_rr_request->send_alignment, tcp_conn_rr_request->send_offset);
8726
8727 if (debug) {
8728 fprintf(where,"recv_tcp_conn_rr: receive alignment and offset set...\n");
8729 fflush(where);
8730 }
8731
8732 /* Grab a socket to listen on, and then listen on it. */
8733
8734 if (debug) {
8735 fprintf(where,"recv_tcp_conn_rr: grabbing a socket...\n");
8736 fflush(where);
8737 }
8738
8739 /* create_data_socket expects to find some things in the global */
8740 /* variables, so set the globals based on the values in the request. */
8741 /* once the socket has been created, we will set the response values */
8742 /* based on the updated value of those globals. raj 7/94 */
8743 lss_size_req = tcp_conn_rr_request->send_buf_size;
8744 lsr_size_req = tcp_conn_rr_request->recv_buf_size;
8745 loc_nodelay = tcp_conn_rr_request->no_delay;
8746 loc_rcvavoid = tcp_conn_rr_request->so_rcvavoid;
8747 loc_sndavoid = tcp_conn_rr_request->so_sndavoid;
8748
8749 set_hostname_and_port(local_name,
8750 port_buffer,
8751 nf_to_af(tcp_conn_rr_request->ipfamily),
8752 tcp_conn_rr_request->port);
8753
8754 local_res = complete_addrinfo(local_name,
8755 local_name,
8756 port_buffer,
8757 nf_to_af(tcp_conn_rr_request->ipfamily),
8758 SOCK_STREAM,
8759 IPPROTO_TCP,
8760 0);
8761
8762 s_listen = create_data_socket(local_res);
8763
8764 if (s_listen == INVALID_SOCKET) {
8765 netperf_response.content.serv_errno = errno;
8766 send_response();
8767 if (debug) {
8768 fprintf(where,"could not create data socket\n");
8769 fflush(where);
8770 }
8771 exit(1);
8772 }
8773
8774 #ifdef WIN32
8775 /* The test timer can fire during operations on the listening socket,
8776 so to make the start_timer below work we have to move
8777 it to close s_listen while we are blocked on accept. */
8778 win_kludge_socket2 = s_listen;
8779 #endif
8780
8781
8782 /* Now, let's set-up the socket to listen for connections */
8783 if (listen(s_listen, 5) == SOCKET_ERROR) {
8784 netperf_response.content.serv_errno = errno;
8785 close(s_listen);
8786 send_response();
8787 if (debug) {
8788 fprintf(where,"could not listen\n");
8789 fflush(where);
8790 }
8791 exit(1);
8792 }
8793
8794 /* now get the port number assigned by the system */
8795 addrlen = sizeof(myaddr_in);
8796 if (getsockname(s_listen,
8797 (struct sockaddr *)&myaddr_in,
8798 &addrlen) == SOCKET_ERROR){
8799 netperf_response.content.serv_errno = errno;
8800 close(s_listen);
8801 send_response();
8802 if (debug) {
8803 fprintf(where,"could not getsockname\n");
8804 fflush(where);
8805 }
8806 exit(1);
8807 }
8808
8809 /* Now myaddr_in contains the port and the internet address this is */
8810 /* returned to the sender also implicitly telling the sender that the */
8811 /* socket buffer sizing has been done. */
8812
8813 tcp_conn_rr_response->data_port_number =
8814 (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
8815 if (debug) {
8816 fprintf(where,"telling the remote to call me at %d\n",
8817 tcp_conn_rr_response->data_port_number);
8818 fflush(where);
8819 }
8820 netperf_response.content.serv_errno = 0;
8821
8822 /* But wait, there's more. If the initiator wanted cpu measurements, */
8823 /* then we must call the calibrate routine, which will return the max */
8824 /* rate back to the initiator. If the CPU was not to be measured, or */
8825 /* something went wrong with the calibration, we will return a 0.0 to */
8826 /* the initiator. */
8827
8828 tcp_conn_rr_response->cpu_rate = (float)0.0; /* assume no cpu */
8829 if (tcp_conn_rr_request->measure_cpu) {
8830 tcp_conn_rr_response->measure_cpu = 1;
8831 tcp_conn_rr_response->cpu_rate =
8832 calibrate_local_cpu(tcp_conn_rr_request->cpu_rate);
8833 }
8834
8835
8836
8837 /* before we send the response back to the initiator, pull some of */
8838 /* the socket parms from the globals */
8839 tcp_conn_rr_response->send_buf_size = lss_size;
8840 tcp_conn_rr_response->recv_buf_size = lsr_size;
8841 tcp_conn_rr_response->no_delay = loc_nodelay;
8842 tcp_conn_rr_response->so_rcvavoid = loc_rcvavoid;
8843 tcp_conn_rr_response->so_sndavoid = loc_sndavoid;
8844
8845 send_response();
8846
8847 addrlen = sizeof(peeraddr_in);
8848
8849 /* Now it's time to start receiving data on the connection. We will */
8850 /* first grab the apropriate counters and then start grabbing. */
8851
8852 cpu_start(tcp_conn_rr_request->measure_cpu);
8853
8854 /* The loop will exit when the sender does a shutdown, which will */
8855 /* return a length of zero */
8856
8857 if (tcp_conn_rr_request->test_length > 0) {
8858 times_up = 0;
8859 trans_remaining = 0;
8860 start_timer(tcp_conn_rr_request->test_length + PAD_TIME);
8861 }
8862 else {
8863 times_up = 1;
8864 trans_remaining = tcp_conn_rr_request->test_length * -1;
8865 }
8866
8867 trans_received = 0;
8868
8869 while ((!times_up) || (trans_remaining > 0)) {
8870
8871 /* accept a connection from the remote */
8872 #ifdef WIN32
8873 /* The test timer will probably fire during this accept,
8874 so to make the start_timer above work we have to move
8875 it to close s_listen while we are blocked on accept. */
8876 win_kludge_socket = s_listen;
8877 #endif
8878 if ((s_data=accept(s_listen,
8879 (struct sockaddr *)&peeraddr_in,
8880 &addrlen)) == INVALID_SOCKET) {
8881 if (errno == EINTR) {
8882 /* the timer popped */
8883 timed_out = 1;
8884 break;
8885 }
8886 fprintf(where,"recv_tcp_conn_rr: accept: errno = %d\n",errno);
8887 fflush(where);
8888 close(s_listen);
8889
8890 exit(1);
8891 }
8892
8893 if (debug) {
8894 fprintf(where,"recv_tcp_conn_rr: accepted data connection.\n");
8895 fflush(where);
8896 }
8897
8898 #ifdef WIN32
8899 /* this is used so the timer thread can close the socket out from */
8900 /* under us, which to date is the easiest/cleanest/least */
8901 /* Windows-specific way I can find to force the winsock calls to */
8902 /* return WSAEINTR with the test is over. anything that will run on */
8903 /* 95 and NT and is closer to what netperf expects from Unix signals */
8904 /* and such would be appreciated raj 1/96 */
8905 win_kludge_socket = s_data;
8906 #endif /* WIN32 */
8907
8908 #ifdef KLUDGE_SOCKET_OPTIONS
8909 /* this is for those systems which *INCORRECTLY* fail to pass */
8910 /* attributes across an accept() call. Including this goes against */
8911 /* my better judgement :( raj 11/95 */
8912
8913 kludge_socket_options(s_data);
8914
8915 #endif /* KLUDGE_SOCKET_OPTIONS */
8916
8917 temp_message_ptr = recv_message_ptr;
8918 request_bytes_remaining = tcp_conn_rr_request->request_size;
8919
8920 /* receive the request from the other side */
8921 while (!times_up && (request_bytes_remaining > 0)) {
8922 if((request_bytes_recvd=recv(s_data,
8923 temp_message_ptr,
8924 request_bytes_remaining,
8925 0)) == SOCKET_ERROR) {
8926 if (SOCKET_EINTR(request_bytes_recvd))
8927 {
8928 /* the timer popped */
8929 timed_out = 1;
8930 break;
8931 }
8932 netperf_response.content.serv_errno = errno;
8933 send_response();
8934 exit(1);
8935 }
8936 else {
8937 request_bytes_remaining -= request_bytes_recvd;
8938 temp_message_ptr += request_bytes_recvd;
8939 }
8940 }
8941
8942 if (timed_out) {
8943 /* we hit the end of the test based on time - lets */
8944 /* bail out of here now... */
8945 fprintf(where,"yo5\n");
8946 fflush(where);
8947 break;
8948 }
8949
8950 /* Now, send the response to the remote */
8951 if((bytes_sent=send(s_data,
8952 send_message_ptr,
8953 tcp_conn_rr_request->response_size,
8954 0)) == SOCKET_ERROR) {
8955 if (errno == EINTR) {
8956 /* the test timer has popped */
8957 timed_out = 1;
8958 fprintf(where,"yo6\n");
8959 fflush(where);
8960 break;
8961 }
8962 netperf_response.content.serv_errno = 99;
8963 send_response();
8964 exit(1);
8965 }
8966
8967 trans_received++;
8968 if (trans_remaining) {
8969 trans_remaining--;
8970 }
8971
8972 if (debug) {
8973 fprintf(where,
8974 "recv_tcp_conn_rr: Transaction %d complete\n",
8975 trans_received);
8976 fflush(where);
8977 }
8978
8979 /* close the connection. the server will likely do a graceful */
8980 /* close of the connection, insuring that all data has arrived at */
8981 /* the client. for this it will call shutdown(), and then recv() and */
8982 /* then close(). I'm reasonably confident that this is the */
8983 /* appropriate sequence of calls - I would like to hear of */
8984 /* examples in web servers to the contrary. raj 10/95*/
8985 #ifdef TCP_CRR_SHUTDOWN
8986 shutdown(s_data,SHUT_WR);
8987 recv(s_data,
8988 recv_message_ptr,
8989 1,
8990 0);
8991 close(s_data);
8992 #else
8993 close(s_data);
8994 #endif /* TCP_CRR_SHUTDOWN */
8995
8996 }
8997
8998
8999 /* The loop now exits due to timeout or transaction count being */
9000 /* reached */
9001
9002 cpu_stop(tcp_conn_rr_request->measure_cpu,&elapsed_time);
9003
9004 if (timed_out) {
9005 /* we ended the test by time, which was at least 2 seconds */
9006 /* longer than we wanted to run. so, we want to subtract */
9007 /* PAD_TIME from the elapsed_time. */
9008 elapsed_time -= PAD_TIME;
9009 }
9010 /* send the results to the sender */
9011
9012 if (debug) {
9013 fprintf(where,
9014 "recv_tcp_conn_rr: got %d transactions\n",
9015 trans_received);
9016 fflush(where);
9017 }
9018
9019 tcp_conn_rr_results->bytes_received = (trans_received *
9020 (tcp_conn_rr_request->request_size +
9021 tcp_conn_rr_request->response_size));
9022 tcp_conn_rr_results->trans_received = trans_received;
9023 tcp_conn_rr_results->elapsed_time = elapsed_time;
9024 if (tcp_conn_rr_request->measure_cpu) {
9025 tcp_conn_rr_results->cpu_util = calc_cpu_util(elapsed_time);
9026 }
9027
9028 if (debug) {
9029 fprintf(where,
9030 "recv_tcp_conn_rr: test complete, sending results.\n");
9031 fflush(where);
9032 }
9033
9034 send_response();
9035
9036 }
9037
9038
9039 #ifdef DO_1644
9040
9041 /* this test is intended to test the performance of establishing a */
9042 /* connection, exchanging a request/response pair, and repeating. it */
9043 /* is expected that this would be a good starting-point for */
9044 /* comparision of T/TCP with classic TCP for transactional workloads. */
9045 /* it will also look (can look) much like the communication pattern */
9046 /* of http for www access. */
9047
9048 int
send_tcp_tran_rr(char remote_host[])9049 send_tcp_tran_rr(char remote_host[])
9050 {
9051
9052 char *tput_title = "\
9053 Local /Remote\n\
9054 Socket Size Request Resp. Elapsed Trans.\n\
9055 Send Recv Size Size Time Rate \n\
9056 bytes Bytes bytes bytes secs. per sec \n\n";
9057
9058 char *tput_fmt_0 =
9059 "%7.2f\n";
9060
9061 char *tput_fmt_1_line_1 = "\
9062 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
9063 char *tput_fmt_1_line_2 = "\
9064 %-6d %-6d\n";
9065
9066 char *cpu_title = "\
9067 Local /Remote\n\
9068 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
9069 Send Recv Size Size Time Rate local remote local remote\n\
9070 bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
9071
9072 char *cpu_fmt_0 =
9073 "%6.3f\n";
9074
9075 char *cpu_fmt_1_line_1 = "\
9076 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
9077
9078 char *cpu_fmt_1_line_2 = "\
9079 %-6d %-6d\n";
9080
9081 char *ksink_fmt = "\n\
9082 Alignment Offset\n\
9083 Local Remote Local Remote\n\
9084 Send Recv Send Recv\n\
9085 %5d %5d %5d %5d\n";
9086
9087
9088 int one = 1;
9089 int timed_out = 0;
9090 float elapsed_time;
9091
9092 int len;
9093 struct ring_elt *send_ring;
9094 struct ring_elt *recv_ring;
9095 char *temp_message_ptr;
9096 int nummessages;
9097 SOCKET send_socket;
9098 int trans_remaining;
9099 double bytes_xferd;
9100 int sock_opt_len = sizeof(int);
9101 int rsp_bytes_left;
9102 int rsp_bytes_recvd;
9103
9104 float local_cpu_utilization;
9105 float local_service_demand;
9106 float remote_cpu_utilization;
9107 float remote_service_demand;
9108 double thruput;
9109
9110 struct hostent *hp;
9111 struct sockaddr_in server;
9112 struct sockaddr_in *myaddr;
9113 unsigned int addr;
9114 int myport;
9115
9116 struct tcp_tran_rr_request_struct *tcp_tran_rr_request;
9117 struct tcp_tran_rr_response_struct *tcp_tran_rr_response;
9118 struct tcp_tran_rr_results_struct *tcp_tran_rr_result;
9119
9120 tcp_tran_rr_request =
9121 (struct tcp_tran_rr_request_struct *)netperf_request.content.test_specific_data;
9122 tcp_tran_rr_response =
9123 (struct tcp_tran_rr_response_struct *)netperf_response.content.test_specific_data;
9124 tcp_tran_rr_result =
9125 (struct tcp_tran_rr_results_struct *)netperf_response.content.test_specific_data;
9126
9127
9128 #ifdef WANT_HISTOGRAM
9129 if (verbosity > 1) {
9130 time_hist = HIST_new();
9131 }
9132 #endif /* WANT_HISTOGRAM */
9133
9134 /* since we are now disconnected from the code that established the */
9135 /* control socket, and since we want to be able to use different */
9136 /* protocols and such, we are passed the name of the remote host and */
9137 /* must turn that into the test specific addressing information. */
9138
9139 myaddr = (struct sockaddr_storage *)malloc(sizeof(struct sockaddr_storage));
9140 if (myaddr == NULL) {
9141 printf("malloc(%d) failed!\n", sizeof(struct sockaddr_storage));
9142 exit(1);
9143 }
9144
9145 bzero((char *)&server,
9146 sizeof(server));
9147 bzero((char *)myaddr,
9148 sizeof(struct sockaddr_storage));
9149 myaddr->sin_family = AF_INET;
9150
9151 complete_addrinfos(&remote_res,
9152 &local_res,
9153 remote_host,
9154 SOCK_STREAM,
9155 IPPROTO_TCP,
9156 0);
9157
9158 if ( print_headers ) {
9159 print_top_test_header("TCP Transactional/Request/Response TEST",local_res,remote_res);
9160 }
9161
9162 /* initialize a few counters */
9163
9164 nummessages = 0;
9165 bytes_xferd = 0.0;
9166 times_up = 0;
9167
9168 /* set-up the data buffers with the requested alignment and offset */
9169 if (send_width == 0) send_width = 1;
9170 if (recv_width == 0) recv_width = 1;
9171
9172 send_ring = allocate_buffer_ring(send_width,
9173 req_size,
9174 local_send_align,
9175 local_send_offset);
9176
9177 recv_ring = allocate_buffer_ring(recv_width,
9178 rsp_size,
9179 local_recv_align,
9180 local_recv_offset);
9181
9182
9183 if (debug) {
9184 fprintf(where,"send_tcp_tran_rr: send_socket obtained...\n");
9185 }
9186
9187 /* If the user has requested cpu utilization measurements, we must */
9188 /* calibrate the cpu(s). We will perform this task within the tests */
9189 /* themselves. If the user has specified the cpu rate, then */
9190 /* calibrate_local_cpu will return rather quickly as it will have */
9191 /* nothing to do. If local_cpu_rate is zero, then we will go through */
9192 /* all the "normal" calibration stuff and return the rate back.*/
9193
9194 if (local_cpu_usage) {
9195 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
9196 }
9197
9198 /* Tell the remote end to do a listen. The server alters the socket */
9199 /* paramters on the other side at this point, hence the reason for */
9200 /* all the values being passed in the setup message. If the user did */
9201 /* not specify any of the parameters, they will be passed as 0, which */
9202 /* will indicate to the remote that no changes beyond the system's */
9203 /* default should be used. Alignment is the exception, it will */
9204 /* default to 8, which will be no alignment alterations. */
9205
9206 netperf_request.content.request_type = DO_TCP_TRR;
9207 tcp_tran_rr_request->recv_buf_size = rsr_size_req;
9208 tcp_tran_rr_request->send_buf_size = rss_size_req;
9209 tcp_tran_rr_request->recv_alignment = remote_recv_align;
9210 tcp_tran_rr_request->recv_offset = remote_recv_offset;
9211 tcp_tran_rr_request->send_alignment = remote_send_align;
9212 tcp_tran_rr_request->send_offset = remote_send_offset;
9213 tcp_tran_rr_request->request_size = req_size;
9214 tcp_tran_rr_request->response_size = rsp_size;
9215 tcp_tran_rr_request->no_delay = rem_nodelay;
9216 tcp_tran_rr_request->measure_cpu = remote_cpu_usage;
9217 tcp_tran_rr_request->cpu_rate = remote_cpu_rate;
9218 tcp_tran_rr_request->so_rcvavoid = rem_rcvavoid;
9219 tcp_tran_rr_request->so_sndavoid = rem_sndavoid;
9220 if (test_time) {
9221 tcp_tran_rr_request->test_length = test_time;
9222 }
9223 else {
9224 tcp_tran_rr_request->test_length = test_trans * -1;
9225 }
9226 tcp_tran_rr_request->port = atoi(remote_data_port);
9227 tcp_tran_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
9228
9229 if (debug > 1) {
9230 fprintf(where,"netperf: send_tcp_tran_rr: requesting TCP_TRR test\n");
9231 }
9232
9233 send_request();
9234
9235 /* The response from the remote will contain all of the relevant */
9236 /* socket parameters for this test type. We will put them back into */
9237 /* the variables here so they can be displayed if desired. The */
9238 /* remote will have calibrated CPU if necessary, and will have done */
9239 /* all the needed set-up we will have calibrated the cpu locally */
9240 /* before sending the request, and will grab the counter value right */
9241 /* after the connect returns. The remote will grab the counter right */
9242 /* after the accept call. This saves the hassle of extra messages */
9243 /* being sent for the TCP tests. */
9244
9245 recv_response();
9246
9247 if (!netperf_response.content.serv_errno) {
9248 rsr_size = tcp_tran_rr_response->recv_buf_size;
9249 rss_size = tcp_tran_rr_response->send_buf_size;
9250 rem_nodelay = tcp_tran_rr_response->no_delay;
9251 remote_cpu_usage= tcp_tran_rr_response->measure_cpu;
9252 remote_cpu_rate = tcp_tran_rr_response->cpu_rate;
9253 /* make sure that port numbers are in network order */
9254 server.sin_port = tcp_tran_rr_response->data_port_number;
9255 server.sin_port = htons(server.sin_port);
9256 if (debug) {
9257 fprintf(where,"remote listen done.\n");
9258 fprintf(where,"remote port is %d\n",ntohs(server.sin_port));
9259 fflush(where);
9260 }
9261 }
9262 else {
9263 Set_errno(netperf_response.content.serv_errno);
9264 fprintf(where,
9265 "netperf: remote error %d",
9266 netperf_response.content.serv_errno);
9267 perror("");
9268 fflush(where);
9269 exit(1);
9270 }
9271
9272 /* pick a nice random spot between client_port_min and */
9273 /* client_port_max for our initial port number. if they are the */
9274 /* same, then just set to _min */
9275 if (client_port_max - client_port_min) {
9276 srand(getpid());
9277 myport = client_port_min +
9278 (rand() % (client_port_max - client_port_min));
9279 }
9280 else {
9281 myport = client_port_min;
9282 }
9283
9284 /* there will be a ++ before the first call to bind, so subtract one */
9285 myport--;
9286 myaddr->sin_port = htons((unsigned short)myport);
9287
9288 /* Set-up the test end conditions. For a request/response test, they */
9289 /* can be either time or transaction based. */
9290
9291 if (test_time) {
9292 /* The user wanted to end the test after a period of time. */
9293 times_up = 0;
9294 trans_remaining = 0;
9295 start_timer(test_time);
9296 }
9297 else {
9298 /* The tester wanted to send a number of bytes. */
9299 trans_remaining = test_bytes;
9300 times_up = 1;
9301 }
9302
9303 /* The cpu_start routine will grab the current time and possibly */
9304 /* value of the idle counter for later use in measuring cpu */
9305 /* utilization and/or service demand and thruput. */
9306
9307 cpu_start(local_cpu_usage);
9308
9309 /* We use an "OR" to control test execution. When the test is */
9310 /* controlled by time, the byte count check will always return false. */
9311 /* When the test is controlled by byte count, the time test will */
9312 /* always return false. When the test is finished, the whole */
9313 /* expression will go false and we will stop sending data. I think I */
9314 /* just arbitrarily decrement trans_remaining for the timed test, but */
9315 /* will not do that just yet... One other question is whether or not */
9316 /* the send buffer and the receive buffer should be the same buffer. */
9317
9318 while ((!times_up) || (trans_remaining > 0)) {
9319
9320 #ifdef WANT_HISTOGRAM
9321 if (verbosity > 1) {
9322 /* timestamp just before our call to create the socket, and then */
9323 /* again just after the receive raj 3/95 */
9324 HIST_timestamp(&time_one);
9325 }
9326 #endif /* WANT_HISTOGRAM */
9327
9328 /* set up the data socket - is this really necessary or can I just */
9329 /* re-use the same socket and move this cal out of the while loop. */
9330 /* it does introcudea *boatload* of system calls. I guess that it */
9331 /* all depends on "reality of programming." keeping it this way is */
9332 /* a bit more conservative I imagine - raj 3/95 */
9333 send_socket = create_data_socket(local_res);
9334
9335 if (send_socket == INVALID_SOCKET) {
9336 perror("netperf: send_tcp_tran_rr: tcp stream data socket");
9337 exit(1);
9338 }
9339
9340 /* we set SO_REUSEADDR on the premis that no unreserved port */
9341 /* number on the local system is going to be already connected to */
9342 /* the remote netserver's port number. One thing that I might */
9343 /* try later is to have the remote actually allocate a couple of */
9344 /* port numbers and cycle through those as well. depends on if we */
9345 /* can get through all the unreserved port numbers in less than */
9346 /* the length of the TIME_WAIT state raj 8/94 */
9347 one = 1;
9348 if(setsockopt(send_socket, SOL_SOCKET, SO_REUSEADDR,
9349 (char *)&one, sock_opt_len) == SOCKET_ERROR) {
9350 perror("netperf: send_tcp_tran_rr: so_reuseaddr");
9351 exit(1);
9352 }
9353
9354 newport:
9355 /* pick a new port number */
9356 myport = ntohs(myaddr->sin_port);
9357 myport++;
9358
9359 /* we do not want to use the port number that the server is */
9360 /* sitting at - this would cause us to fail in a loopback test. we */
9361 /* could just rely on the failure of the bind to get us past this, */
9362 /* but I'm guessing that in this one case at least, it is much */
9363 /* faster, given that we *know* that port number is already in use */
9364 /* (or rather would be in a loopback test) */
9365
9366 if (myport == ntohs(server.sin_port)) myport++;
9367
9368 /* wrap the port number when we get to 65535. NOTE, some broken */
9369 /* TCP's might treat the port number as a signed 16 bit quantity. */
9370 /* we aren't interested in testing such broken implementations :) */
9371 /* raj 8/94 */
9372 if (myport >= client_port_max) {
9373 myport = client_port_min;
9374 }
9375 myaddr->sin_port = htons((unsigned short)myport);
9376
9377 if (debug) {
9378 if ((nummessages % 100) == 0) {
9379 printf("port %d\n",myport);
9380 }
9381 }
9382
9383 /* we want to bind our socket to a particular port number. */
9384 if (bind(send_socket,
9385 (struct sockaddr *)myaddr,
9386 sizeof(struct sockaddr_storage)) == SOCKET_ERROR) {
9387 /* if the bind failed, someone else must have that port number */
9388 /* - perhaps in the listen state. since we can't use it, skip to */
9389 /* the next port number. we may have to do this again later, but */
9390 /* that's just too bad :) */
9391 if (debug > 1) {
9392 fprintf(where,
9393 "send_tcp_tran_rr: tried to bind to port %d errno %d\n",
9394 ntohs(myaddr->sin_port),
9395 errno);
9396 fflush(where);
9397 }
9398 /* yes, goto's are supposed to be evil, but they do have their */
9399 /* uses from time to time. the real world doesn't always have */
9400 /* to code to ge tthe A in CS 101 :) raj 3/95 */
9401 goto newport;
9402 }
9403
9404 /* Connect up to the remote port on the data socket. Since this is */
9405 /* a test for RFC_1644-style transactional TCP, we can use the */
9406 /* sendto() call instead of calling connect and then send() */
9407
9408 /* send the request */
9409 if((len=sendto(send_socket,
9410 send_ring->buffer_ptr,
9411 req_size,
9412 MSG_EOF,
9413 (struct sockaddr *)&server,
9414 sizeof(server))) != req_size) {
9415 if (SOCKET_EINTR(len))
9416 {
9417 /* we hit the end of a */
9418 /* timed test. */
9419 timed_out = 1;
9420 break;
9421 }
9422 perror("send_tcp_tran_rr: data send error");
9423 exit(1);
9424 }
9425 send_ring = send_ring->next;
9426
9427 /* receive the response */
9428 rsp_bytes_left = rsp_size;
9429 temp_message_ptr = recv_ring->buffer_ptr;
9430 while(rsp_bytes_left > 0) {
9431 if((rsp_bytes_recvd=recv(send_socket,
9432 temp_message_ptr,
9433 rsp_bytes_left,
9434 0)) == SOCKET_ERROR) {
9435 if (SOCKET_EINTR(rsp_bytes_recvd))
9436 {
9437 /* We hit the end of a timed test. */
9438 timed_out = 1;
9439 break;
9440 }
9441 perror("send_tcp_tran_rr: data recv error");
9442 exit(1);
9443 }
9444 rsp_bytes_left -= rsp_bytes_recvd;
9445 temp_message_ptr += rsp_bytes_recvd;
9446 }
9447 recv_ring = recv_ring->next;
9448
9449 if (timed_out) {
9450 /* we may have been in a nested while loop - we need */
9451 /* another call to break. */
9452 break;
9453 }
9454
9455 close(send_socket);
9456
9457 #ifdef WANT_HISTOGRAM
9458 if (verbosity > 1) {
9459 HIST_timestamp(&time_two);
9460 HIST_add(time_hist,delta_micro(&time_one,&time_two));
9461 }
9462 #endif /* WANT_HISTOGRAM */
9463
9464 nummessages++;
9465 if (trans_remaining) {
9466 trans_remaining--;
9467 }
9468
9469 if (debug > 3) {
9470 fprintf(where,
9471 "Transaction %d completed on local port %d\n",
9472 nummessages,
9473 ntohs(myaddr->sin_port));
9474 fflush(where);
9475 }
9476
9477
9478 }
9479
9480 /* this call will always give us the elapsed time for the test, and */
9481 /* will also store-away the necessaries for cpu utilization */
9482
9483 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
9484 /* how long did we really run? */
9485
9486 /* Get the statistics from the remote end. The remote will have */
9487 /* calculated service demand and all those interesting things. If it */
9488 /* wasn't supposed to care, it will return obvious values. */
9489
9490 recv_response();
9491 if (!netperf_response.content.serv_errno) {
9492 if (debug)
9493 fprintf(where,"remote results obtained\n");
9494 }
9495 else {
9496 Set_errno(netperf_response.content.serv_errno);
9497 fprintf(where,
9498 "netperf: remote error %d",
9499 netperf_response.content.serv_errno);
9500 perror("");
9501 fflush(where);
9502 exit(1);
9503 }
9504
9505 /* We now calculate what our thruput was for the test. In the future, */
9506 /* we may want to include a calculation of the thruput measured by */
9507 /* the remote, but it should be the case that for a TCP stream test, */
9508 /* that the two numbers should be *very* close... We calculate */
9509 /* bytes_sent regardless of the way the test length was controlled. */
9510 /* If it was time, we needed to, and if it was by bytes, the user may */
9511 /* have specified a number of bytes that wasn't a multiple of the */
9512 /* send_size, so we really didn't send what he asked for ;-) We use */
9513 /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
9514 /* 1024. A future enhancement *might* be to choose from a couple of */
9515 /* unit selections. */
9516
9517 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
9518 thruput = calc_thruput(bytes_xferd);
9519
9520 if (local_cpu_usage || remote_cpu_usage) {
9521 /* We must now do a little math for service demand and cpu */
9522 /* utilization for the system(s) */
9523 /* Of course, some of the information might be bogus because */
9524 /* there was no idle counter in the kernel(s). We need to make */
9525 /* a note of this for the user's benefit...*/
9526 if (local_cpu_usage) {
9527 if (local_cpu_rate == 0.0) {
9528 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
9529 fprintf(where,"Local CPU usage numbers based on process information only!\n");
9530 fflush(where);
9531 }
9532 local_cpu_utilization = calc_cpu_util(0.0);
9533 /* since calc_service demand is doing ms/Kunit we will */
9534 /* multiply the number of transaction by 1024 to get */
9535 /* "good" numbers */
9536 local_service_demand = calc_service_demand((double) nummessages*1024,
9537 0.0,
9538 0.0,
9539 0);
9540 }
9541 else {
9542 local_cpu_utilization = (float) -1.0;
9543 local_service_demand = (float) -1.0;
9544 }
9545
9546 if (remote_cpu_usage) {
9547 if (remote_cpu_rate == 0.0) {
9548 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
9549 fprintf(where,"Remote CPU usage numbers based on process information only!\n");
9550 fflush(where);
9551 }
9552 remote_cpu_utilization = tcp_tran_rr_result->cpu_util;
9553 /* since calc_service demand is doing ms/Kunit we will */
9554 /* multiply the number of transaction by 1024 to get */
9555 /* "good" numbers */
9556 remote_service_demand = calc_service_demand((double) nummessages*1024,
9557 0.0,
9558 remote_cpu_utilization,
9559 tcp_tran_rr_result->num_cpus);
9560 }
9561 else {
9562 remote_cpu_utilization = (float) -1.0;
9563 remote_service_demand = (float) -1.0;
9564 }
9565
9566 /* We are now ready to print all the information. If the user */
9567 /* has specified zero-level verbosity, we will just print the */
9568 /* local service demand, or the remote service demand. If the */
9569 /* user has requested verbosity level 1, he will get the basic */
9570 /* "streamperf" numbers. If the user has specified a verbosity */
9571 /* of greater than 1, we will display a veritable plethora of */
9572 /* background information from outside of this block as it it */
9573 /* not cpu_measurement specific... */
9574
9575 switch (verbosity) {
9576 case 0:
9577 if (local_cpu_usage) {
9578 fprintf(where,
9579 cpu_fmt_0,
9580 local_service_demand);
9581 }
9582 else {
9583 fprintf(where,
9584 cpu_fmt_0,
9585 remote_service_demand);
9586 }
9587 break;
9588 case 1:
9589 case 2:
9590
9591 if (print_headers) {
9592 fprintf(where,
9593 cpu_title,
9594 local_cpu_method,
9595 remote_cpu_method);
9596 }
9597
9598 fprintf(where,
9599 cpu_fmt_1_line_1, /* the format string */
9600 lss_size, /* local sendbuf size */
9601 lsr_size,
9602 req_size, /* how large were the requests */
9603 rsp_size, /* guess */
9604 elapsed_time, /* how long was the test */
9605 nummessages/elapsed_time,
9606 local_cpu_utilization, /* local cpu */
9607 remote_cpu_utilization, /* remote cpu */
9608 local_service_demand, /* local service demand */
9609 remote_service_demand); /* remote service demand */
9610 fprintf(where,
9611 cpu_fmt_1_line_2,
9612 rss_size,
9613 rsr_size);
9614 break;
9615 }
9616 }
9617 else {
9618 /* The tester did not wish to measure service demand. */
9619 switch (verbosity) {
9620 case 0:
9621 fprintf(where,
9622 tput_fmt_0,
9623 nummessages/elapsed_time);
9624 break;
9625 case 1:
9626 case 2:
9627 if (print_headers) {
9628 fprintf(where,tput_title,format_units());
9629 }
9630
9631 fprintf(where,
9632 tput_fmt_1_line_1, /* the format string */
9633 lss_size,
9634 lsr_size,
9635 req_size, /* how large were the requests */
9636 rsp_size, /* how large were the responses */
9637 elapsed_time, /* how long did it take */
9638 nummessages/elapsed_time);
9639 fprintf(where,
9640 tput_fmt_1_line_2,
9641 rss_size, /* remote recvbuf size */
9642 rsr_size);
9643
9644 break;
9645 }
9646 }
9647
9648 /* it would be a good thing to include information about some of the */
9649 /* other parameters that may have been set for this test, but at the */
9650 /* moment, I do not wish to figure-out all the formatting, so I will */
9651 /* just put this comment here to help remind me that it is something */
9652 /* that should be done at a later time. */
9653
9654 if (verbosity > 1) {
9655 /* The user wanted to know it all, so we will give it to him. */
9656 /* This information will include as much as we can find about */
9657 /* TCP statistics, the alignments of the sends and receives */
9658 /* and all that sort of rot... */
9659
9660 fprintf(where,
9661 ksink_fmt,
9662 local_send_align,
9663 remote_recv_offset,
9664 local_send_offset,
9665 remote_recv_offset);
9666
9667 #ifdef WANT_HISTOGRAM
9668 fprintf(where,"\nHistogram of request/response times\n");
9669 fflush(where);
9670 HIST_report(time_hist);
9671 #endif /* WANT_HISTOGRAM */
9672
9673 }
9674
9675 }
9676
9677
9678 int
recv_tcp_tran_rr()9679 recv_tcp_tran_rr()
9680 {
9681
9682 char *message;
9683 struct sockaddr_in myaddr_in,
9684 peeraddr_in;
9685 SOCKET s_listen,s_data;
9686 netperf_socklen_t addrlen;
9687 int NoPush = 1;
9688
9689 char *recv_message_ptr;
9690 char *send_message_ptr;
9691 char *temp_message_ptr;
9692 int trans_received;
9693 int trans_remaining;
9694 int bytes_sent;
9695 int request_bytes_recvd;
9696 int request_bytes_remaining;
9697 int timed_out = 0;
9698 float elapsed_time;
9699
9700 struct tcp_tran_rr_request_struct *tcp_tran_rr_request;
9701 struct tcp_tran_rr_response_struct *tcp_tran_rr_response;
9702 struct tcp_tran_rr_results_struct *tcp_tran_rr_results;
9703
9704 tcp_tran_rr_request =
9705 (struct tcp_tran_rr_request_struct *)netperf_request.content.test_specific_data;
9706 tcp_tran_rr_response =
9707 (struct tcp_tran_rr_response_struct *)netperf_response.content.test_specific_data;
9708 tcp_tran_rr_results =
9709 (struct tcp_tran_rr_results_struct *)netperf_response.content.test_specific_data;
9710
9711 if (debug) {
9712 fprintf(where,"netserver: recv_tcp_tran_rr: entered...\n");
9713 fflush(where);
9714 }
9715
9716 /* We want to set-up the listen socket with all the desired */
9717 /* parameters and then let the initiator know that all is ready. If */
9718 /* socket size defaults are to be used, then the initiator will have */
9719 /* sent us 0's. If the socket sizes cannot be changed, then we will */
9720 /* send-back what they are. If that information cannot be determined, */
9721 /* then we send-back -1's for the sizes. If things go wrong for any */
9722 /* reason, we will drop back ten yards and punt. */
9723
9724 /* If anything goes wrong, we want the remote to know about it. It */
9725 /* would be best if the error that the remote reports to the user is */
9726 /* the actual error we encountered, rather than some bogus unexpected */
9727 /* response type message. */
9728
9729 if (debug) {
9730 fprintf(where,"recv_tcp_tran_rr: setting the response type...\n");
9731 fflush(where);
9732 }
9733
9734 netperf_response.content.response_type = TCP_TRR_RESPONSE;
9735
9736 if (debug) {
9737 fprintf(where,"recv_tcp_tran_rr: the response type is set...\n");
9738 fflush(where);
9739 }
9740
9741 /* set-up the data buffer with the requested alignment and offset */
9742 message = (char *)malloc(DATABUFFERLEN);
9743 if (message == NULL) {
9744 printf("malloc(%d) failed!\n", DATABUFFERLEN);
9745 exit(1);
9746 }
9747
9748 /* We now alter the message_ptr variables to be at the desired */
9749 /* alignments with the desired offsets. */
9750
9751 if (debug) {
9752 fprintf(where,
9753 "recv_tcp_tran_rr: requested recv alignment of %d offset %d\n",
9754 tcp_tran_rr_request->recv_alignment,
9755 tcp_tran_rr_request->recv_offset);
9756 fprintf(where,
9757 "recv_tcp_tran_rr: requested send alignment of %d offset %d\n",
9758 tcp_tran_rr_request->send_alignment,
9759 tcp_tran_rr_request->send_offset);
9760 fflush(where);
9761 }
9762
9763 recv_message_ptr = ALIGN_BUFFER(message, tcp_tran_rr_request->recv_alignment, tcp_tran_rr_request->recv_offset);
9764
9765 send_message_ptr = ALIGN_BUFFER(message, tcp_tran_rr_request->send_alignment, tcp_tran_rr_request->send_offset);
9766
9767 if (debug) {
9768 fprintf(where,"recv_tcp_tran_rr: receive alignment and offset set...\n");
9769 fflush(where);
9770 }
9771
9772 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
9773 /* can put in OUR values !-) At some point, we may want to nail this */
9774 /* socket to a particular network-level address, but for now, */
9775 /* INADDR_ANY should be just fine. */
9776
9777 bzero((char *)&myaddr_in,
9778 sizeof(myaddr_in));
9779 myaddr_in.sin_family = AF_INET;
9780 myaddr_in.sin_addr.s_addr = INADDR_ANY;
9781 myaddr_in.sin_port = htons((unsigned short)tcp_tran_rr_request->port);
9782
9783 /* Grab a socket to listen on, and then listen on it. */
9784
9785 if (debug) {
9786 fprintf(where,"recv_tcp_tran_rr: grabbing a socket...\n");
9787 fflush(where);
9788 }
9789
9790 /* create_data_socket expects to find some things in the global */
9791 /* variables, so set the globals based on the values in the request. */
9792 /* once the socket has been created, we will set the response values */
9793 /* based on the updated value of those globals. raj 7/94 */
9794 lss_size_req = tcp_tran_rr_request->send_buf_size;
9795 lsr_size_req = tcp_tran_rr_request->recv_buf_size;
9796 loc_nodelay = tcp_tran_rr_request->no_delay;
9797 loc_rcvavoid = tcp_tran_rr_request->so_rcvavoid;
9798 loc_sndavoid = tcp_tran_rr_request->so_sndavoid;
9799
9800 set_hostname_and_port(local_name,
9801 port_buffer,
9802 nf_to_af(tcp_tran_rr_request->ipfamily),
9803 tcp_tran_rr_request->port);
9804
9805 local_res = complete_addrinfo(local_name,
9806 local_name,
9807 port_buffer,
9808 nf_to_af(tcp_tran_rr_request->ipfamily),
9809 SOCK_STREAM,
9810 IPPROTO_TCP,
9811 0);
9812
9813 s_listen = create_data_socket(local_res);
9814
9815 if (s_listen == INVALID_SOCKET) {
9816 netperf_response.content.serv_errno = errno;
9817 send_response();
9818 if (debug) {
9819 fprintf(where,"could not create data socket\n");
9820 fflush(where);
9821 }
9822 exit(1);
9823 }
9824
9825 #ifdef WIN32
9826 /* The test timer can fire during operations on the listening socket,
9827 so to make the start_timer below work we have to move
9828 it to close s_listen while we are blocked on accept. */
9829 win_kludge_socket2 = s_listen;
9830 #endif
9831
9832
9833 /* Let's get an address assigned to this socket so we can tell the */
9834 /* initiator how to reach the data socket. There may be a desire to */
9835 /* nail this socket to a specific IP address in a multi-homed, */
9836 /* multi-connection situation, but for now, we'll ignore the issue */
9837 /* and concentrate on single connection testing. */
9838
9839 if (bind(s_listen,
9840 (struct sockaddr *)&myaddr_in,
9841 sizeof(myaddr_in)) == SOCKET_ERROR) {
9842 netperf_response.content.serv_errno = errno;
9843 close(s_listen);
9844 send_response();
9845 if (debug) {
9846 fprintf(where,"could not bind\n");
9847 fflush(where);
9848 }
9849 exit(1);
9850 }
9851
9852 /* we want to disable the implicit PUSH on all sends. at some point, */
9853 /* this might want to be a parm to the test raj 3/95 */
9854 if (setsockopt(s_listen,
9855 IPPROTO_TCP,
9856 TCP_NOPUSH,
9857 (const char *)&NoPush,
9858 sizeof(int)) == SOCKET_ERROR) {
9859 fprintf(where,
9860 "recv_tcp_tran_rr: could not set TCP_NOPUSH errno %d\n",
9861 errno);
9862 fflush(where);
9863 netperf_response.content.serv_errno = errno;
9864 close(s_listen);
9865 send_response();
9866 }
9867
9868 /* Now, let's set-up the socket to listen for connections */
9869 if (listen(s_listen, 5) == SOCKET_ERROR) {
9870 netperf_response.content.serv_errno = errno;
9871 close(s_listen);
9872 send_response();
9873 if (debug) {
9874 fprintf(where,"could not listen\n");
9875 fflush(where);
9876 }
9877 exit(1);
9878 }
9879
9880 /* now get the port number assigned by the system */
9881 addrlen = sizeof(myaddr_in);
9882 if (getsockname(s_listen,
9883 (struct sockaddr *)&myaddr_in,
9884 &addrlen) == SOCKET_ERROR){
9885 netperf_response.content.serv_errno = errno;
9886 close(s_listen);
9887 send_response();
9888 if (debug) {
9889 fprintf(where,"could not geetsockname\n");
9890 fflush(where);
9891 }
9892 exit(1);
9893 }
9894
9895 /* Now myaddr_in contains the port and the internet address this is */
9896 /* returned to the sender also implicitly telling the sender that the */
9897 /* socket buffer sizing has been done. */
9898
9899 tcp_tran_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
9900 if (debug) {
9901 fprintf(where,"telling the remote to call me at %d\n",
9902 tcp_tran_rr_response->data_port_number);
9903 fflush(where);
9904 }
9905 netperf_response.content.serv_errno = 0;
9906
9907 /* But wait, there's more. If the initiator wanted cpu measurements, */
9908 /* then we must call the calibrate routine, which will return the max */
9909 /* rate back to the initiator. If the CPU was not to be measured, or */
9910 /* something went wrong with the calibration, we will return a 0.0 to */
9911 /* the initiator. */
9912
9913 tcp_tran_rr_response->cpu_rate = 0.0; /* assume no cpu */
9914 if (tcp_tran_rr_request->measure_cpu) {
9915 tcp_tran_rr_response->measure_cpu = 1;
9916 tcp_tran_rr_response->cpu_rate =
9917 calibrate_local_cpu(tcp_tran_rr_request->cpu_rate);
9918 }
9919
9920
9921
9922 /* before we send the response back to the initiator, pull some of */
9923 /* the socket parms from the globals */
9924 tcp_tran_rr_response->send_buf_size = lss_size;
9925 tcp_tran_rr_response->recv_buf_size = lsr_size;
9926 tcp_tran_rr_response->no_delay = loc_nodelay;
9927 tcp_tran_rr_response->so_rcvavoid = loc_rcvavoid;
9928 tcp_tran_rr_response->so_sndavoid = loc_sndavoid;
9929
9930 send_response();
9931
9932 addrlen = sizeof(peeraddr_in);
9933
9934 /* Now it's time to start receiving data on the connection. We will */
9935 /* first grab the apropriate counters and then start grabbing. */
9936
9937 cpu_start(tcp_tran_rr_request->measure_cpu);
9938
9939 /* The loop will exit when the sender does a shutdown, which will */
9940 /* return a length of zero */
9941
9942 if (tcp_tran_rr_request->test_length > 0) {
9943 times_up = 0;
9944 trans_remaining = 0;
9945 start_timer(tcp_tran_rr_request->test_length + PAD_TIME);
9946 }
9947 else {
9948 times_up = 1;
9949 trans_remaining = tcp_tran_rr_request->test_length * -1;
9950 }
9951
9952 trans_received = 0;
9953
9954 while ((!times_up) || (trans_remaining > 0)) {
9955
9956 /* accept a connection from the remote */
9957 if ((s_data=accept(s_listen,
9958 (struct sockaddr *)&peeraddr_in,
9959 &addrlen)) == INVALID_SOCKET) {
9960 if (errno == EINTR) {
9961 /* the timer popped */
9962 timed_out = 1;
9963 break;
9964 }
9965 fprintf(where,"recv_tcp_tran_rr: accept: errno = %d\n",errno);
9966 fflush(where);
9967 close(s_listen);
9968
9969 exit(1);
9970 }
9971
9972 if (debug) {
9973 fprintf(where,"recv_tcp_tran_rr: accepted data connection.\n");
9974 fflush(where);
9975 }
9976
9977 #ifdef WIN32
9978 /* this is used so the timer thread can close the socket out from */
9979 /* under us, which to date is the easiest/cleanest/least */
9980 /* Windows-specific way I can find to force the winsock calls to */
9981 /* return WSAEINTR with the test is over. anything that will run on */
9982 /* 95 and NT and is closer to what netperf expects from Unix signals */
9983 /* and such would be appreciated raj 1/96 */
9984 win_kludge_socket = s_data;
9985 #endif /* WIN32 */
9986
9987 #ifdef KLUDGE_SOCKET_OPTIONS
9988 /* this is for those systems which *INCORRECTLY* fail to pass */
9989 /* attributes across an accept() call. Including this goes against */
9990 /* my better judgement :( raj 11/95 */
9991
9992 kludge_socket_options(s_data);
9993
9994 #endif /* KLUDGE_SOCKET_OPTIONS */
9995
9996 temp_message_ptr = recv_message_ptr;
9997 request_bytes_remaining = tcp_tran_rr_request->request_size;
9998
9999 /* receive the request from the other side. we can just receive */
10000 /* until we get zero bytes, but that would be a slight structure */
10001 /* change in the code, with minimal perfomance effects. If */
10002 /* however, I has variable-length messages, I would want to do */
10003 /* this to avoid needing "double reads" - one for the message */
10004 /* length, and one for the rest of the message raj 3/95 */
10005 while(request_bytes_remaining > 0) {
10006 if((request_bytes_recvd=recv(s_data,
10007 temp_message_ptr,
10008 request_bytes_remaining,
10009 0)) == SOCKET_ERROR) {
10010 if ( SOCKET_EINTR(request_bytes_recvd) )
10011 {
10012 /* the timer popped */
10013 timed_out = 1;
10014 break;
10015 }
10016 netperf_response.content.serv_errno = errno;
10017 send_response();
10018 exit(1);
10019 }
10020 else {
10021 request_bytes_remaining -= request_bytes_recvd;
10022 temp_message_ptr += request_bytes_recvd;
10023 }
10024 }
10025
10026 if (timed_out) {
10027 /* we hit the end of the test based on time - lets */
10028 /* bail out of here now... */
10029 fprintf(where,"yo5\n");
10030 fflush(where);
10031 break;
10032 }
10033
10034 /* Now, send the response to the remote we can use sendto here to */
10035 /* help remind people that this is an rfc 1644 style of test */
10036 if((bytes_sent=sendto(s_data,
10037 send_message_ptr,
10038 tcp_tran_rr_request->response_size,
10039 MSG_EOF,
10040 (struct sockaddr *)&peeraddr_in,
10041 sizeof(struct sockaddr_storage))) == SOCKET_ERROR) {
10042 if (SOCKET_EINTR(bytes_sent)) {
10043 /* the test timer has popped */
10044 timed_out = 1;
10045 fprintf(where,"yo6\n");
10046 fflush(where);
10047 break;
10048 }
10049 netperf_response.content.serv_errno = 99;
10050 send_response();
10051 exit(1);
10052 }
10053
10054 trans_received++;
10055 if (trans_remaining) {
10056 trans_remaining--;
10057 }
10058
10059 if (debug) {
10060 fprintf(where,
10061 "recv_tcp_tran_rr: Transaction %d complete\n",
10062 trans_received);
10063 fflush(where);
10064 }
10065
10066 /* close the connection. since we have disable PUSH on sends, the */
10067 /* FIN should be tacked-onto our last send instead of being */
10068 /* standalone */
10069 close(s_data);
10070
10071 }
10072
10073
10074 /* The loop now exits due to timeout or transaction count being */
10075 /* reached */
10076
10077 cpu_stop(tcp_tran_rr_request->measure_cpu,&elapsed_time);
10078
10079 if (timed_out) {
10080 /* we ended the test by time, which was at least 2 seconds */
10081 /* longer than we wanted to run. so, we want to subtract */
10082 /* PAD_TIME from the elapsed_time. */
10083 elapsed_time -= PAD_TIME;
10084 }
10085 /* send the results to the sender */
10086
10087 if (debug) {
10088 fprintf(where,
10089 "recv_tcp_tran_rr: got %d transactions\n",
10090 trans_received);
10091 fflush(where);
10092 }
10093
10094 tcp_tran_rr_results->bytes_received = (trans_received *
10095 (tcp_tran_rr_request->request_size +
10096 tcp_tran_rr_request->response_size));
10097 tcp_tran_rr_results->trans_received = trans_received;
10098 tcp_tran_rr_results->elapsed_time = elapsed_time;
10099 if (tcp_tran_rr_request->measure_cpu) {
10100 tcp_tran_rr_results->cpu_util = calc_cpu_util(elapsed_time);
10101 }
10102
10103 if (debug) {
10104 fprintf(where,
10105 "recv_tcp_tran_rr: test complete, sending results.\n");
10106 fflush(where);
10107 }
10108
10109 send_response();
10110
10111 }
10112 #endif /* DO_1644 */
10113
10114 #ifdef DO_NBRR
10115 /* this routine implements the sending (netperf) side of the TCP_RR */
10116 /* test using POSIX-style non-blocking sockets. */
10117
10118 void
send_tcp_nbrr(char remote_host[])10119 send_tcp_nbrr(char remote_host[])
10120 {
10121
10122 char *tput_title = "\
10123 Local /Remote\n\
10124 Socket Size Request Resp. Elapsed Trans.\n\
10125 Send Recv Size Size Time Rate \n\
10126 bytes Bytes bytes bytes secs. per sec \n\n";
10127
10128 char *tput_fmt_0 =
10129 "%7.2f\n";
10130
10131 char *tput_fmt_1_line_1 = "\
10132 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
10133 char *tput_fmt_1_line_2 = "\
10134 %-6d %-6d\n";
10135
10136 char *cpu_title = "\
10137 Local /Remote\n\
10138 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
10139 Send Recv Size Size Time Rate local remote local remote\n\
10140 bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
10141
10142 char *cpu_fmt_0 =
10143 "%6.3f %c\n";
10144
10145 char *cpu_fmt_1_line_1 = "\
10146 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
10147
10148 char *cpu_fmt_1_line_2 = "\
10149 %-6d %-6d\n";
10150
10151 char *ksink_fmt = "\
10152 Alignment Offset\n\
10153 Local Remote Local Remote\n\
10154 Send Recv Send Recv\n\
10155 %5d %5d %5d %5d\n";
10156
10157
10158 int timed_out = 0;
10159 float elapsed_time;
10160
10161 int len;
10162 char *temp_message_ptr;
10163 int nummessages;
10164 SOCKET send_socket;
10165 int trans_remaining;
10166 double bytes_xferd;
10167
10168 struct ring_elt *send_ring;
10169 struct ring_elt *recv_ring;
10170
10171 int rsp_bytes_left;
10172 int rsp_bytes_recvd;
10173
10174 float local_cpu_utilization;
10175 float local_service_demand;
10176 float remote_cpu_utilization;
10177 float remote_service_demand;
10178 double thruput;
10179
10180 struct hostent *hp;
10181 struct sockaddr_storage server;
10182 unsigned int addr;
10183
10184 struct tcp_rr_request_struct *tcp_rr_request;
10185 struct tcp_rr_response_struct *tcp_rr_response;
10186 struct tcp_rr_results_struct *tcp_rr_result;
10187
10188 struct addrinfo *remote_res;
10189 struct addrinfo *local_res;
10190
10191 tcp_rr_request =
10192 (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
10193 tcp_rr_response=
10194 (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
10195 tcp_rr_result =
10196 (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
10197
10198 #ifdef WANT_HISTOGRAM
10199 if (verbosity > 1) {
10200 time_hist = HIST_new();
10201 }
10202 #endif /* WANT_HISTOGRAM */
10203
10204 /* since we are now disconnected from the code that established the */
10205 /* control socket, and since we want to be able to use different */
10206 /* protocols and such, we are passed the name of the remote host and */
10207 /* must turn that into the test specific addressing information. */
10208
10209 bzero((char *)&server,
10210 sizeof(server));
10211
10212 complete_addrinfos(&remote_res,
10213 &local_res,
10214 remote_host,
10215 SOCK_STREAM,
10216 IPPROTO_TCP,
10217 0);
10218
10219 if ( print_headers ) {
10220 print_top_test_header("TCP Non-Blocking REQUEST/RESPONSE TEST",local_res,remote_res);
10221 }
10222
10223 /* initialize a few counters */
10224
10225 send_ring = NULL;
10226 recv_ring = NULL;
10227 confidence_iteration = 1;
10228 init_stat();
10229
10230 /* we have a great-big while loop which controls the number of times */
10231 /* we run a particular test. this is for the calculation of a */
10232 /* confidence interval (I really should have stayed awake during */
10233 /* probstats :). If the user did not request confidence measurement */
10234 /* (no confidence is the default) then we will only go though the */
10235 /* loop once. the confidence stuff originates from the folks at IBM */
10236
10237 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
10238 (confidence_iteration <= iteration_min)) {
10239
10240 /* initialize a few counters. we have to remember that we might be */
10241 /* going through the loop more than once. */
10242
10243 nummessages = 0;
10244 bytes_xferd = 0.0;
10245 times_up = 0;
10246 timed_out = 0;
10247 trans_remaining = 0;
10248
10249 /* set-up the data buffers with the requested alignment and offset. */
10250 /* since this is a request/response test, default the send_width and */
10251 /* recv_width to 1 and not two raj 7/94 */
10252
10253 if (send_width == 0) send_width = 1;
10254 if (recv_width == 0) recv_width = 1;
10255
10256 if (send_ring == NULL) {
10257 send_ring = allocate_buffer_ring(send_width,
10258 req_size,
10259 local_send_align,
10260 local_send_offset);
10261 }
10262
10263 if (recv_ring == NULL) {
10264 recv_ring = allocate_buffer_ring(recv_width,
10265 rsp_size,
10266 local_recv_align,
10267 local_recv_offset);
10268 }
10269
10270 /*set up the data socket */
10271 send_socket = create_data_socket(local_res);
10272
10273 if (send_socket == INVALID_SOCKET){
10274 perror("netperf: send_tcp_nbrr: tcp stream data socket");
10275 exit(1);
10276 }
10277
10278 if (debug) {
10279 fprintf(where,"send_tcp_nbrr: send_socket obtained...\n");
10280 }
10281
10282 /* If the user has requested cpu utilization measurements, we must */
10283 /* calibrate the cpu(s). We will perform this task within the tests */
10284 /* themselves. If the user has specified the cpu rate, then */
10285 /* calibrate_local_cpu will return rather quickly as it will have */
10286 /* nothing to do. If local_cpu_rate is zero, then we will go through */
10287 /* all the "normal" calibration stuff and return the rate back.*/
10288
10289 if (local_cpu_usage) {
10290 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
10291 }
10292
10293 /* Tell the remote end to do a listen. The server alters the socket */
10294 /* paramters on the other side at this point, hence the reason for */
10295 /* all the values being passed in the setup message. If the user did */
10296 /* not specify any of the parameters, they will be passed as 0, which */
10297 /* will indicate to the remote that no changes beyond the system's */
10298 /* default should be used. Alignment is the exception, it will */
10299 /* default to 8, which will be no alignment alterations. */
10300
10301 netperf_request.content.request_type = DO_TCP_NBRR;
10302 tcp_rr_request->recv_buf_size = rsr_size_req;
10303 tcp_rr_request->send_buf_size = rss_size_req;
10304 tcp_rr_request->recv_alignment = remote_recv_align;
10305 tcp_rr_request->recv_offset = remote_recv_offset;
10306 tcp_rr_request->send_alignment = remote_send_align;
10307 tcp_rr_request->send_offset = remote_send_offset;
10308 tcp_rr_request->request_size = req_size;
10309 tcp_rr_request->response_size = rsp_size;
10310 tcp_rr_request->no_delay = rem_nodelay;
10311 tcp_rr_request->measure_cpu = remote_cpu_usage;
10312 tcp_rr_request->cpu_rate = remote_cpu_rate;
10313 tcp_rr_request->so_rcvavoid = rem_rcvavoid;
10314 tcp_rr_request->so_sndavoid = rem_sndavoid;
10315 if (test_time) {
10316 tcp_rr_request->test_length = test_time;
10317 }
10318 else {
10319 tcp_rr_request->test_length = test_trans * -1;
10320 }
10321
10322 if (debug > 1) {
10323 fprintf(where,"netperf: send_tcp_nbrr: requesting TCP rr test\n");
10324 }
10325
10326 send_request();
10327
10328 /* The response from the remote will contain all of the relevant */
10329 /* socket parameters for this test type. We will put them back into */
10330 /* the variables here so they can be displayed if desired. The */
10331 /* remote will have calibrated CPU if necessary, and will have done */
10332 /* all the needed set-up we will have calibrated the cpu locally */
10333 /* before sending the request, and will grab the counter value right*/
10334 /* after the connect returns. The remote will grab the counter right*/
10335 /* after the accept call. This saves the hassle of extra messages */
10336 /* being sent for the TCP tests. */
10337
10338 recv_response();
10339
10340 if (!netperf_response.content.serv_errno) {
10341 if (debug)
10342 fprintf(where,"remote listen done.\n");
10343 rsr_size = tcp_rr_response->recv_buf_size;
10344 rss_size = tcp_rr_response->send_buf_size;
10345 rem_nodelay = tcp_rr_response->no_delay;
10346 remote_cpu_usage = tcp_rr_response->measure_cpu;
10347 remote_cpu_rate = tcp_rr_response->cpu_rate;
10348 /* make sure that port numbers are in network order */
10349 server.sin_port = (unsigned short)tcp_rr_response->data_port_number;
10350 server.sin_port = htons(server.sin_port);
10351 }
10352 else {
10353 Set_errno(netperf_response.content.serv_errno);
10354 fprintf(where,
10355 "netperf: remote error %d",
10356 netperf_response.content.serv_errno);
10357 perror("");
10358 fflush(where);
10359 exit(1);
10360 }
10361
10362 /*Connect up to the remote port on the data socket */
10363 if (connect(send_socket,
10364 remote_res->ai_addr,
10365 remote_res->ai_addrlen) == INVALID_SOCKET){
10366 perror("netperf: data socket connect failed");
10367
10368 exit(1);
10369 }
10370
10371 /* now that we are connected, mark the socket as non-blocking */
10372 if (!set_nonblock(send_socket)) {
10373 perror("netperf: set_nonblock");
10374 exit(1);
10375 }
10376
10377 /* Data Socket set-up is finished. If there were problems, either the */
10378 /* connect would have failed, or the previous response would have */
10379 /* indicated a problem. I failed to see the value of the extra */
10380 /* message after the accept on the remote. If it failed, we'll see it */
10381 /* here. If it didn't, we might as well start pumping data. */
10382
10383 /* Set-up the test end conditions. For a request/response test, they */
10384 /* can be either time or transaction based. */
10385
10386 if (test_time) {
10387 /* The user wanted to end the test after a period of time. */
10388 times_up = 0;
10389 trans_remaining = 0;
10390 start_timer(test_time);
10391 }
10392 else {
10393 /* The tester wanted to send a number of bytes. */
10394 trans_remaining = test_bytes;
10395 times_up = 1;
10396 }
10397
10398 /* The cpu_start routine will grab the current time and possibly */
10399 /* value of the idle counter for later use in measuring cpu */
10400 /* utilization and/or service demand and thruput. */
10401
10402 cpu_start(local_cpu_usage);
10403
10404 #ifdef WANT_INTERVALS
10405 INTERVALS_INIT();
10406 #endif /* WANT_INTERVALS */
10407
10408 /* We use an "OR" to control test execution. When the test is */
10409 /* controlled by time, the byte count check will always return false. */
10410 /* When the test is controlled by byte count, the time test will */
10411 /* always return false. When the test is finished, the whole */
10412 /* expression will go false and we will stop sending data. I think I */
10413 /* just arbitrarily decrement trans_remaining for the timed test, but */
10414 /* will not do that just yet... One other question is whether or not */
10415 /* the send buffer and the receive buffer should be the same buffer. */
10416
10417 while ((!times_up) || (trans_remaining > 0)) {
10418 /* send the request. we assume that if we use a blocking socket, */
10419 /* the request will be sent at one shot. */
10420
10421 #ifdef WANT_HISTOGRAM
10422 if (verbosity > 1) {
10423 /* timestamp just before our call to send, and then again just */
10424 /* after the receive raj 8/94 */
10425 HIST_timestamp(&time_one);
10426 }
10427 #endif /* WANT_HISTOGRAM */
10428
10429 /* even though this is a non-blocking socket, we will assume for */
10430 /* the time being that we will be able to send an entire request */
10431 /* without getting an EAGAIN */
10432 if((len=send(send_socket,
10433 send_ring->buffer_ptr,
10434 req_size,
10435 0)) != req_size) {
10436 if (SOCKET_EINTR(len)) {
10437 /* we hit the end of a */
10438 /* timed test. */
10439 timed_out = 1;
10440 break;
10441 }
10442 perror("send_tcp_nbrr: data send error");
10443 exit(1);
10444 }
10445 send_ring = send_ring->next;
10446
10447 /* receive the response. since we are using non-blocking I/O, we */
10448 /* will "spin" on the recvs */
10449 rsp_bytes_left = rsp_size;
10450 temp_message_ptr = recv_ring->buffer_ptr;
10451 while(rsp_bytes_left > 0) {
10452 if((rsp_bytes_recvd=recv(send_socket,
10453 temp_message_ptr,
10454 rsp_bytes_left,
10455 0)) == SOCKET_ERROR) {
10456 if (SOCKET_EINTR(rsp_bytes_recvd))
10457 {
10458 /* We hit the end of a timed test. */
10459 timed_out = 1;
10460 break;
10461 }
10462 #ifndef WIN32 // But what does WinNT indicate in this situation...
10463 else if (errno == EAGAIN) {
10464 Set_errno(0);
10465 continue;
10466 }
10467 #endif
10468 else {
10469 perror("send_tcp_nbrr: data recv error");
10470 exit(1);
10471 }
10472 }
10473 rsp_bytes_left -= rsp_bytes_recvd;
10474 temp_message_ptr += rsp_bytes_recvd;
10475 }
10476 recv_ring = recv_ring->next;
10477
10478 if (timed_out) {
10479 /* we may have been in a nested while loop - we need */
10480 /* another call to break. */
10481 break;
10482 }
10483
10484 #ifdef WANT_HISTOGRAM
10485 if (verbosity > 1) {
10486 HIST_timestamp(&time_two);
10487 HIST_add(time_hist,delta_micro(&time_one,&time_two));
10488 }
10489 #endif /* WANT_HISTOGRAM */
10490 #ifdef WANT_INTERVALS
10491 INTERVALS_WAIT();
10492 #endif /* WANT_INTERVALS */
10493
10494 nummessages++;
10495 if (trans_remaining) {
10496 trans_remaining--;
10497 }
10498
10499 if (debug > 3) {
10500 if ((nummessages % 100) == 0) {
10501 fprintf(where,
10502 "Transaction %d completed\n",
10503 nummessages);
10504 fflush(where);
10505 }
10506 }
10507 }
10508
10509 /* At this point we used to call shutdown on the data socket to be */
10510 /* sure all the data was delivered, but this was not germane in a */
10511 /* request/response test, and it was causing the tests to "hang" when */
10512 /* they were being controlled by time. So, I have replaced this */
10513 /* shutdown call with a call to close that can be found later in the */
10514 /* procedure. */
10515
10516 /* this call will always give us the elapsed time for the test, and */
10517 /* will also store-away the necessaries for cpu utilization */
10518
10519 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
10520 /* measured? how long */
10521 /* did we really run? */
10522
10523 /* Get the statistics from the remote end. The remote will have */
10524 /* calculated service demand and all those interesting things. If it */
10525 /* wasn't supposed to care, it will return obvious values. */
10526
10527 recv_response();
10528 if (!netperf_response.content.serv_errno) {
10529 if (debug)
10530 fprintf(where,"remote results obtained\n");
10531 }
10532 else {
10533 Set_errno(netperf_response.content.serv_errno);
10534 fprintf(where,
10535 "netperf: remote error %d",
10536 netperf_response.content.serv_errno);
10537 perror("");
10538 fflush(where);
10539
10540 exit(1);
10541 }
10542
10543 /* We now calculate what our thruput was for the test. */
10544
10545 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
10546 thruput = nummessages/elapsed_time;
10547
10548 if (local_cpu_usage || remote_cpu_usage) {
10549 /* We must now do a little math for service demand and cpu */
10550 /* utilization for the system(s) */
10551 /* Of course, some of the information might be bogus because */
10552 /* there was no idle counter in the kernel(s). We need to make */
10553 /* a note of this for the user's benefit...*/
10554 if (local_cpu_usage) {
10555 local_cpu_utilization = calc_cpu_util(0.0);
10556 /* since calc_service demand is doing ms/Kunit we will */
10557 /* multiply the number of transaction by 1024 to get */
10558 /* "good" numbers */
10559 local_service_demand = calc_service_demand((double) nummessages*1024,
10560 0.0,
10561 0.0,
10562 0);
10563 }
10564 else {
10565 local_cpu_utilization = (float) -1.0;
10566 local_service_demand = (float) -1.0;
10567 }
10568
10569 if (remote_cpu_usage) {
10570 remote_cpu_utilization = tcp_rr_result->cpu_util;
10571 /* since calc_service demand is doing ms/Kunit we will */
10572 /* multiply the number of transaction by 1024 to get */
10573 /* "good" numbers */
10574 remote_service_demand = calc_service_demand((double) nummessages*1024,
10575 0.0,
10576 remote_cpu_utilization,
10577 tcp_rr_result->num_cpus);
10578 }
10579 else {
10580 remote_cpu_utilization = (float) -1.0;
10581 remote_service_demand = (float) -1.0;
10582 }
10583
10584 }
10585 else {
10586 /* we were not measuring cpu, for the confidence stuff, we */
10587 /* should make it -1.0 */
10588 local_cpu_utilization = (float) -1.0;
10589 local_service_demand = (float) -1.0;
10590 remote_cpu_utilization = (float) -1.0;
10591 remote_service_demand = (float) -1.0;
10592 }
10593
10594 /* at this point, we want to calculate the confidence information. */
10595 /* if debugging is on, calculate_confidence will print-out the */
10596 /* parameters we pass it */
10597
10598 calculate_confidence(confidence_iteration,
10599 elapsed_time,
10600 thruput,
10601 local_cpu_utilization,
10602 remote_cpu_utilization,
10603 local_service_demand,
10604 remote_service_demand);
10605
10606
10607 confidence_iteration++;
10608
10609 /* we are now done with the socket, so close it */
10610 close(send_socket);
10611
10612 }
10613
10614 retrieve_confident_values(&elapsed_time,
10615 &thruput,
10616 &local_cpu_utilization,
10617 &remote_cpu_utilization,
10618 &local_service_demand,
10619 &remote_service_demand);
10620
10621 /* We are now ready to print all the information. If the user */
10622 /* has specified zero-level verbosity, we will just print the */
10623 /* local service demand, or the remote service demand. If the */
10624 /* user has requested verbosity level 1, he will get the basic */
10625 /* "streamperf" numbers. If the user has specified a verbosity */
10626 /* of greater than 1, we will display a veritable plethora of */
10627 /* background information from outside of this block as it it */
10628 /* not cpu_measurement specific... */
10629
10630 if (confidence < 0) {
10631 /* we did not hit confidence, but were we asked to look for it? */
10632 if (iteration_max > 1) {
10633 display_confidence();
10634 }
10635 }
10636
10637 if (local_cpu_usage || remote_cpu_usage) {
10638 local_cpu_method = format_cpu_method(cpu_method);
10639 remote_cpu_method = format_cpu_method(tcp_rr_result->cpu_method);
10640
10641 switch (verbosity) {
10642 case 0:
10643 if (local_cpu_usage) {
10644 fprintf(where,
10645 cpu_fmt_0,
10646 local_service_demand,
10647 local_cpu_method);
10648 }
10649 else {
10650 fprintf(where,
10651 cpu_fmt_0,
10652 remote_service_demand,
10653 remote_cpu_method);
10654 }
10655 break;
10656 case 1:
10657 case 2:
10658 if (print_headers) {
10659 fprintf(where,
10660 cpu_title,
10661 local_cpu_method,
10662 remote_cpu_method);
10663 }
10664
10665 fprintf(where,
10666 cpu_fmt_1_line_1, /* the format string */
10667 lss_size, /* local sendbuf size */
10668 lsr_size,
10669 req_size, /* how large were the requests */
10670 rsp_size, /* guess */
10671 elapsed_time, /* how long was the test */
10672 thruput,
10673 local_cpu_utilization, /* local cpu */
10674 remote_cpu_utilization, /* remote cpu */
10675 local_service_demand, /* local service demand */
10676 remote_service_demand); /* remote service demand */
10677 fprintf(where,
10678 cpu_fmt_1_line_2,
10679 rss_size,
10680 rsr_size);
10681 break;
10682 }
10683 }
10684 else {
10685 /* The tester did not wish to measure service demand. */
10686
10687 switch (verbosity) {
10688 case 0:
10689 fprintf(where,
10690 tput_fmt_0,
10691 thruput);
10692 break;
10693 case 1:
10694 case 2:
10695 if (print_headers) {
10696 fprintf(where,tput_title,format_units());
10697 }
10698
10699 fprintf(where,
10700 tput_fmt_1_line_1, /* the format string */
10701 lss_size,
10702 lsr_size,
10703 req_size, /* how large were the requests */
10704 rsp_size, /* how large were the responses */
10705 elapsed_time, /* how long did it take */
10706 thruput);
10707 fprintf(where,
10708 tput_fmt_1_line_2,
10709 rss_size, /* remote recvbuf size */
10710 rsr_size);
10711
10712 break;
10713 }
10714 }
10715
10716 /* it would be a good thing to include information about some of the */
10717 /* other parameters that may have been set for this test, but at the */
10718 /* moment, I do not wish to figure-out all the formatting, so I will */
10719 /* just put this comment here to help remind me that it is something */
10720 /* that should be done at a later time. */
10721
10722 /* how to handle the verbose information in the presence of */
10723 /* confidence intervals is yet to be determined... raj 11/94 */
10724 if (verbosity > 1) {
10725 /* The user wanted to know it all, so we will give it to him. */
10726 /* This information will include as much as we can find about */
10727 /* TCP statistics, the alignments of the sends and receives */
10728 /* and all that sort of rot... */
10729
10730 fprintf(where,
10731 ksink_fmt,
10732 local_send_align,
10733 remote_recv_offset,
10734 local_send_offset,
10735 remote_recv_offset);
10736
10737 #ifdef WANT_HISTOGRAM
10738 fprintf(where,"\nHistogram of request/response times\n");
10739 fflush(where);
10740 HIST_report(time_hist);
10741 #endif /* WANT_HISTOGRAM */
10742
10743 }
10744
10745 }
10746
10747 /* this routine implements the receive (netserver) side of a TCP_RR */
10748 /* test */
10749 void
recv_tcp_nbrr()10750 recv_tcp_nbrr()
10751 {
10752
10753 struct ring_elt *send_ring;
10754 struct ring_elt *recv_ring;
10755
10756 struct sockaddr_in myaddr_in,
10757 peeraddr_in;
10758 SOCKET s_listen,s_data;
10759 netperf_socklen_t addrlen;
10760 char *temp_message_ptr;
10761 int trans_received;
10762 int trans_remaining;
10763 int bytes_sent;
10764 int request_bytes_recvd;
10765 int request_bytes_remaining;
10766 int timed_out = 0;
10767 float elapsed_time;
10768
10769 struct addrinfo *local_res;
10770 char local_name[BUFSIZ];
10771 char port_buffer[PORTBUFSIZE];
10772
10773 struct tcp_rr_request_struct *tcp_rr_request;
10774 struct tcp_rr_response_struct *tcp_rr_response;
10775 struct tcp_rr_results_struct *tcp_rr_results;
10776
10777 tcp_rr_request =
10778 (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
10779 tcp_rr_response =
10780 (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
10781 tcp_rr_results =
10782 (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
10783
10784 if (debug) {
10785 fprintf(where,"netserver: recv_tcp_nbrr: entered...\n");
10786 fflush(where);
10787 }
10788
10789 /* We want to set-up the listen socket with all the desired */
10790 /* parameters and then let the initiator know that all is ready. If */
10791 /* socket size defaults are to be used, then the initiator will have */
10792 /* sent us 0's. If the socket sizes cannot be changed, then we will */
10793 /* send-back what they are. If that information cannot be determined, */
10794 /* then we send-back -1's for the sizes. If things go wrong for any */
10795 /* reason, we will drop back ten yards and punt. */
10796
10797 /* If anything goes wrong, we want the remote to know about it. It */
10798 /* would be best if the error that the remote reports to the user is */
10799 /* the actual error we encountered, rather than some bogus unexpected */
10800 /* response type message. */
10801
10802 if (debug) {
10803 fprintf(where,"recv_tcp_nbrr: setting the response type...\n");
10804 fflush(where);
10805 }
10806
10807 netperf_response.content.response_type = TCP_RR_RESPONSE;
10808
10809 if (debug) {
10810 fprintf(where,"recv_tcp_nbrr: the response type is set...\n");
10811 fflush(where);
10812 }
10813
10814 /* allocate the recv and send rings with the requested alignments */
10815 /* and offsets. raj 7/94 */
10816 if (debug) {
10817 fprintf(where,"recv_tcp_nbrr: requested recv alignment of %d offset %d\n",
10818 tcp_rr_request->recv_alignment,
10819 tcp_rr_request->recv_offset);
10820 fprintf(where,"recv_tcp_nbrr: requested send alignment of %d offset %d\n",
10821 tcp_rr_request->send_alignment,
10822 tcp_rr_request->send_offset);
10823 fflush(where);
10824 }
10825
10826 /* at some point, these need to come to us from the remote system */
10827 if (send_width == 0) send_width = 1;
10828 if (recv_width == 0) recv_width = 1;
10829
10830 send_ring = allocate_buffer_ring(send_width,
10831 tcp_rr_request->response_size,
10832 tcp_rr_request->send_alignment,
10833 tcp_rr_request->send_offset);
10834
10835 recv_ring = allocate_buffer_ring(recv_width,
10836 tcp_rr_request->request_size,
10837 tcp_rr_request->recv_alignment,
10838 tcp_rr_request->recv_offset);
10839
10840
10841 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
10842 /* can put in OUR values !-) At some point, we may want to nail this */
10843 /* socket to a particular network-level address, but for now, */
10844 /* INADDR_ANY should be just fine. */
10845
10846 bzero((char *)&myaddr_in,
10847 sizeof(myaddr_in));
10848 myaddr_in.sin_family = AF_INET;
10849 myaddr_in.sin_addr.s_addr = INADDR_ANY;
10850 myaddr_in.sin_port = htons((unsigned short)tcp_rr_request->port);
10851
10852 /* Grab a socket to listen on, and then listen on it. */
10853
10854 if (debug) {
10855 fprintf(where,"recv_tcp_nbrr: grabbing a socket...\n");
10856 fflush(where);
10857 }
10858
10859 /* create_data_socket expects to find some things in the global */
10860 /* variables, so set the globals based on the values in the request. */
10861 /* once the socket has been created, we will set the response values */
10862 /* based on the updated value of those globals. raj 7/94 */
10863 lss_size_req = tcp_rr_request->send_buf_size;
10864 lsr_size_req = tcp_rr_request->recv_buf_size;
10865 loc_nodelay = tcp_rr_request->no_delay;
10866 loc_rcvavoid = tcp_rr_request->so_rcvavoid;
10867 loc_sndavoid = tcp_rr_request->so_sndavoid;
10868
10869 set_hostname_and_port(local_name,
10870 port_buffer,
10871 nf_to_af(tcp_rr_request->ipfamily),
10872 tcp_rr_request->port);
10873
10874 local_res = complete_addrinfo(local_name,
10875 local_name,
10876 port_buffer,
10877 nf_to_af(tcp_rr_request->ipfamily),
10878 SOCK_STREAM,
10879 IPPROTO_TCP,
10880 0);
10881
10882 s_listen = create_data_socket(local_res);
10883
10884 if (s_listen == INVALID_SOCKET) {
10885 netperf_response.content.serv_errno = errno;
10886 send_response();
10887
10888 exit(1);
10889 }
10890
10891 /* Let's get an address assigned to this socket so we can tell the */
10892 /* initiator how to reach the data socket. There may be a desire to */
10893 /* nail this socket to a specific IP address in a multi-homed, */
10894 /* multi-connection situation, but for now, we'll ignore the issue */
10895 /* and concentrate on single connection testing. */
10896
10897 if (bind(s_listen,
10898 (struct sockaddr *)&myaddr_in,
10899 sizeof(myaddr_in)) == SOCKET_ERROR) {
10900 netperf_response.content.serv_errno = errno;
10901 close(s_listen);
10902 send_response();
10903
10904 exit(1);
10905 }
10906
10907 /* Now, let's set-up the socket to listen for connections */
10908 if (listen(s_listen, 5) == SOCKET_ERROR) {
10909 netperf_response.content.serv_errno = errno;
10910 close(s_listen);
10911 send_response();
10912
10913 exit(1);
10914 }
10915
10916
10917 /* now get the port number assigned by the system */
10918 addrlen = sizeof(myaddr_in);
10919 if (getsockname(s_listen,
10920 (struct sockaddr *)&myaddr_in, &addrlen) == SOCKET_ERROR){
10921 netperf_response.content.serv_errno = errno;
10922 close(s_listen);
10923 send_response();
10924
10925 exit(1);
10926 }
10927
10928 /* Now myaddr_in contains the port and the internet address this is */
10929 /* returned to the sender also implicitly telling the sender that the */
10930 /* socket buffer sizing has been done. */
10931
10932 tcp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
10933 netperf_response.content.serv_errno = 0;
10934
10935 /* But wait, there's more. If the initiator wanted cpu measurements, */
10936 /* then we must call the calibrate routine, which will return the max */
10937 /* rate back to the initiator. If the CPU was not to be measured, or */
10938 /* something went wrong with the calibration, we will return a 0.0 to */
10939 /* the initiator. */
10940
10941 tcp_rr_response->cpu_rate = 0.0; /* assume no cpu */
10942 tcp_rr_response->measure_cpu = 0;
10943
10944 if (tcp_rr_request->measure_cpu) {
10945 tcp_rr_response->measure_cpu = 1;
10946 tcp_rr_response->cpu_rate = calibrate_local_cpu(tcp_rr_request->cpu_rate);
10947 }
10948
10949
10950 /* before we send the response back to the initiator, pull some of */
10951 /* the socket parms from the globals */
10952 tcp_rr_response->send_buf_size = lss_size;
10953 tcp_rr_response->recv_buf_size = lsr_size;
10954 tcp_rr_response->no_delay = loc_nodelay;
10955 tcp_rr_response->so_rcvavoid = loc_rcvavoid;
10956 tcp_rr_response->so_sndavoid = loc_sndavoid;
10957 tcp_rr_response->test_length = tcp_rr_request->test_length;
10958 send_response();
10959
10960 addrlen = sizeof(peeraddr_in);
10961
10962 if ((s_data = accept(s_listen,
10963 (struct sockaddr *)&peeraddr_in,
10964 &addrlen)) == INVALID_SOCKET) {
10965 /* Let's just punt. The remote will be given some information */
10966 close(s_listen);
10967 exit(1);
10968 }
10969
10970 if (debug) {
10971 fprintf(where,"recv_tcp_nbrr: accept completes on the data connection.\n");
10972 fflush(where);
10973 }
10974
10975 #ifdef KLUDGE_SOCKET_OPTIONS
10976 /* this is for those systems which *INCORRECTLY* fail to pass */
10977 /* attributes across an accept() call. Including this goes against */
10978 /* my better judgement :( raj 11/95 */
10979
10980 kludge_socket_options(s_data);
10981
10982 #endif /* KLUDGE_SOCKET_OPTIONS */
10983
10984 /* now that we are connected, mark the socket as non-blocking */
10985 if (!set_nonblock(s_data)) {
10986 close(s_data);
10987 exit(1);
10988 }
10989
10990
10991 /* Now it's time to start receiving data on the connection. We will */
10992 /* first grab the apropriate counters and then start grabbing. */
10993
10994 cpu_start(tcp_rr_request->measure_cpu);
10995
10996 #ifdef WIN32
10997 /* this is used so the timer thread can close the socket out from */
10998 /* under us, which to date is the easiest/cleanest/least */
10999 /* Windows-specific way I can find to force the winsock calls to */
11000 /* return WSAEINTR with the test is over. anything that will run on */
11001 /* 95 and NT and is closer to what netperf expects from Unix signals */
11002 /* and such would be appreciated raj 1/96 */
11003 win_kludge_socket = s_data;
11004 #endif /* WIN32 */
11005
11006 /* The loop will exit when the sender does a shutdown, which will */
11007 /* return a length of zero */
11008
11009 if (tcp_rr_request->test_length > 0) {
11010 times_up = 0;
11011 trans_remaining = 0;
11012 start_timer(tcp_rr_request->test_length + PAD_TIME);
11013 }
11014 else {
11015 times_up = 1;
11016 trans_remaining = tcp_rr_request->test_length * -1;
11017 }
11018
11019 trans_received = 0;
11020
11021 while ((!times_up) || (trans_remaining > 0)) {
11022 temp_message_ptr = recv_ring->buffer_ptr;
11023 request_bytes_remaining = tcp_rr_request->request_size;
11024 while(request_bytes_remaining > 0) {
11025 if((request_bytes_recvd=recv(s_data,
11026 temp_message_ptr,
11027 request_bytes_remaining,
11028 0)) == SOCKET_ERROR) {
11029 if ( SOCKET_EINTR(request_bytes_recvd))
11030 {
11031 /* the timer popped */
11032 timed_out = 1;
11033 break;
11034 }
11035 #ifndef WIN32 // But what does WinNT indicate in this situation...
11036 else if (errno == EAGAIN) {
11037 Set_errno(0);
11038 if (times_up) {
11039 timed_out = 1;
11040 break;
11041 }
11042 continue;
11043 }
11044 #endif
11045 else {
11046 netperf_response.content.serv_errno = errno;
11047 send_response();
11048 exit(1);
11049 }
11050 }
11051 else {
11052 request_bytes_remaining -= request_bytes_recvd;
11053 temp_message_ptr += request_bytes_recvd;
11054 }
11055 }
11056
11057 recv_ring = recv_ring->next;
11058
11059 if (timed_out) {
11060 /* we hit the end of the test based on time - lets */
11061 /* bail out of here now... */
11062 fprintf(where,"yo5\n");
11063 fflush(where);
11064 break;
11065 }
11066
11067 /* Now, send the response to the remote */
11068 if((bytes_sent=send(s_data,
11069 send_ring->buffer_ptr,
11070 tcp_rr_request->response_size,
11071 0)) == SOCKET_ERROR) {
11072 if (SOCKET_EINTR(bytes_sent)) {
11073 /* the test timer has popped */
11074 timed_out = 1;
11075 fprintf(where,"yo6\n");
11076 fflush(where);
11077 break;
11078 }
11079 netperf_response.content.serv_errno = 992;
11080 send_response();
11081 exit(1);
11082 }
11083
11084 send_ring = send_ring->next;
11085
11086 trans_received++;
11087 if (trans_remaining) {
11088 trans_remaining--;
11089 }
11090 }
11091
11092
11093 /* The loop now exits due to timeout or transaction count being */
11094 /* reached */
11095
11096 cpu_stop(tcp_rr_request->measure_cpu,&elapsed_time);
11097
11098 stop_timer();
11099
11100 if (timed_out) {
11101 /* we ended the test by time, which was at least 2 seconds */
11102 /* longer than we wanted to run. so, we want to subtract */
11103 /* PAD_TIME from the elapsed_time. */
11104 elapsed_time -= PAD_TIME;
11105 }
11106
11107 /* send the results to the sender */
11108
11109 if (debug) {
11110 fprintf(where,
11111 "recv_tcp_nbrr: got %d transactions\n",
11112 trans_received);
11113 fflush(where);
11114 }
11115
11116 tcp_rr_results->bytes_received = (trans_received *
11117 (tcp_rr_request->request_size +
11118 tcp_rr_request->response_size));
11119 tcp_rr_results->trans_received = trans_received;
11120 tcp_rr_results->elapsed_time = elapsed_time;
11121 tcp_rr_results->cpu_method = cpu_method;
11122 tcp_rr_results->num_cpus = lib_num_loc_cpus;
11123 if (tcp_rr_request->measure_cpu) {
11124 tcp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
11125 }
11126
11127 if (debug) {
11128 fprintf(where,
11129 "recv_tcp_nbrr: test complete, sending results.\n");
11130 fflush(where);
11131 }
11132
11133 /* we are done with the socket, free it */
11134 close(s_data);
11135
11136 send_response();
11137
11138 }
11139
11140 #endif /* DO_NBRR */
11141
11142
11143 /* this test is intended to test the performance of establishing a */
11144 /* connection, and then closing it again. this test is of somewhat */
11145 /* arcane interest since no packets are exchanged between the */
11146 /* user-space processes, but it will show the raw overhead of */
11147 /* establishing a TCP connection. that service demand could then be */
11148 /* compared with the sum of the service demands of a TCP_CRR and */
11149 /* TCP_RR test - presumeably, they would all relate */
11150
11151 void
send_tcp_cc(char remote_host[])11152 send_tcp_cc(char remote_host[])
11153 {
11154
11155 char *tput_title = "\
11156 Local /Remote\n\
11157 Socket Size Request Resp. Elapsed Trans.\n\
11158 Send Recv Size Size Time Rate \n\
11159 bytes Bytes bytes bytes secs. per sec \n\n";
11160
11161 char *tput_fmt_0 =
11162 "%7.2f\n";
11163
11164 char *tput_fmt_1_line_1 = "\
11165 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
11166 char *tput_fmt_1_line_2 = "\
11167 %-6d %-6d\n";
11168
11169 char *cpu_title = "\
11170 Local /Remote\n\
11171 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
11172 Send Recv Size Size Time Rate local remote local remote\n\
11173 bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
11174
11175 char *cpu_fmt_0 =
11176 "%6.3f\n";
11177
11178 char *cpu_fmt_1_line_1 = "\
11179 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
11180
11181 char *cpu_fmt_1_line_2 = "\
11182 %-6d %-6d\n";
11183
11184 char *ksink_fmt = "\n\
11185 Alignment Offset\n\
11186 Local Remote Local Remote\n\
11187 Send Recv Send Recv\n\
11188 %5d %5d %5d %5d\n";
11189
11190
11191 int timed_out = 0;
11192 float elapsed_time;
11193
11194 char temp_message_ptr[1];
11195 int nummessages;
11196 SOCKET send_socket;
11197 int trans_remaining;
11198 double bytes_xferd;
11199 int rsp_bytes_left = 1;
11200 int rsp_bytes_recvd;
11201
11202 float local_cpu_utilization;
11203 float local_service_demand;
11204 float remote_cpu_utilization;
11205 float remote_service_demand;
11206 double thruput;
11207
11208 struct addrinfo *local_res;
11209 struct addrinfo *remote_res;
11210
11211 int myport;
11212 int ret;
11213
11214 struct tcp_cc_request_struct *tcp_cc_request;
11215 struct tcp_cc_response_struct *tcp_cc_response;
11216 struct tcp_cc_results_struct *tcp_cc_result;
11217
11218 tcp_cc_request =
11219 (struct tcp_cc_request_struct *)netperf_request.content.test_specific_data;
11220 tcp_cc_response =
11221 (struct tcp_cc_response_struct *)netperf_response.content.test_specific_data;
11222 tcp_cc_result =
11223 (struct tcp_cc_results_struct *)netperf_response.content.test_specific_data;
11224
11225
11226 #ifdef WANT_HISTOGRAM
11227 if (verbosity > 1) {
11228 time_hist = HIST_new();
11229 }
11230 #endif /* WANT_HISTOGRAM */
11231
11232 /* since we are now disconnected from the code that established the */
11233 /* control socket, and since we want to be able to use different */
11234 /* protocols and such, we are passed the name of the remote host and */
11235 /* must turn that into the test specific addressing information. */
11236
11237 complete_addrinfos(&remote_res,
11238 &local_res,
11239 remote_host,
11240 SOCK_STREAM,
11241 IPPROTO_TCP,
11242 0);
11243
11244 if ( print_headers ) {
11245 print_top_test_header("TCP Connect/Close TEST",local_res,remote_res);
11246 }
11247
11248 /* initialize a few counters */
11249
11250 nummessages = 0;
11251 bytes_xferd = 0.0;
11252 times_up = 0;
11253
11254 /* since there are no data buffers in this test, we need no send or */
11255 /* recv rings */
11256
11257 if (debug) {
11258 fprintf(where,"send_tcp_cc: send_socket obtained...\n");
11259 }
11260
11261 /* If the user has requested cpu utilization measurements, we must */
11262 /* calibrate the cpu(s). We will perform this task within the tests */
11263 /* themselves. If the user has specified the cpu rate, then */
11264 /* calibrate_local_cpu will return rather quickly as it will have */
11265 /* nothing to do. If local_cpu_rate is zero, then we will go through */
11266 /* all the "normal" calibration stuff and return the rate back.*/
11267
11268 if (local_cpu_usage) {
11269 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
11270 }
11271
11272 /* Tell the remote end to do a listen. The server alters the socket */
11273 /* paramters on the other side at this point, hence the reason for */
11274 /* all the values being passed in the setup message. If the user did */
11275 /* not specify any of the parameters, they will be passed as 0, which */
11276 /* will indicate to the remote that no changes beyond the system's */
11277 /* default should be used. Alignment is the exception, it will */
11278 /* default to 8, which will be no alignment alterations. */
11279
11280 netperf_request.content.request_type = DO_TCP_CC;
11281 tcp_cc_request->recv_buf_size = rsr_size_req;
11282 tcp_cc_request->send_buf_size = rss_size_req;
11283 tcp_cc_request->recv_alignment = remote_recv_align;
11284 tcp_cc_request->recv_offset = remote_recv_offset;
11285 tcp_cc_request->send_alignment = remote_send_align;
11286 tcp_cc_request->send_offset = remote_send_offset;
11287 tcp_cc_request->request_size = req_size;
11288 tcp_cc_request->response_size = rsp_size;
11289 tcp_cc_request->no_delay = rem_nodelay;
11290 tcp_cc_request->measure_cpu = remote_cpu_usage;
11291 tcp_cc_request->cpu_rate = remote_cpu_rate;
11292 tcp_cc_request->so_rcvavoid = rem_rcvavoid;
11293 tcp_cc_request->so_sndavoid = rem_sndavoid;
11294 if (test_time) {
11295 tcp_cc_request->test_length = test_time;
11296 }
11297 else {
11298 tcp_cc_request->test_length = test_trans * -1;
11299 }
11300 tcp_cc_request->port = atoi(remote_data_port);
11301 tcp_cc_request->ipfamily = af_to_nf(remote_res->ai_family);
11302
11303 if (debug > 1) {
11304 fprintf(where,"netperf: send_tcp_cc: requesting TCP crr test\n");
11305 }
11306
11307 send_request();
11308
11309 /* The response from the remote will contain all of the relevant */
11310 /* socket parameters for this test type. We will put them back into */
11311 /* the variables here so they can be displayed if desired. The */
11312 /* remote will have calibrated CPU if necessary, and will have done */
11313 /* all the needed set-up we will have calibrated the cpu locally */
11314 /* before sending the request, and will grab the counter value right */
11315 /* after the connect returns. The remote will grab the counter right */
11316 /* after the accept call. This saves the hassle of extra messages */
11317 /* being sent for the TCP tests. */
11318
11319 recv_response();
11320
11321 if (!netperf_response.content.serv_errno) {
11322 rsr_size = tcp_cc_response->recv_buf_size;
11323 rss_size = tcp_cc_response->send_buf_size;
11324 rem_nodelay = tcp_cc_response->no_delay;
11325 remote_cpu_usage= tcp_cc_response->measure_cpu;
11326 remote_cpu_rate = tcp_cc_response->cpu_rate;
11327 /* make sure that port numbers are in network order */
11328 set_port_number(remote_res,(unsigned short)tcp_cc_response->data_port_number);
11329
11330 if (debug) {
11331 fprintf(where,"remote listen done.\n");
11332 fprintf(where,"remote port is %d\n",get_port_number(remote_res));
11333 fflush(where);
11334 }
11335 }
11336 else {
11337 Set_errno(netperf_response.content.serv_errno);
11338 fprintf(where,
11339 "netperf: remote error %d",
11340 netperf_response.content.serv_errno);
11341 perror("");
11342 fflush(where);
11343 exit(1);
11344 }
11345
11346 #ifdef WANT_DEMO
11347 DEMO_RR_SETUP(100)
11348 #endif
11349
11350 /* pick a nice random spot between client_port_min and */
11351 /* client_port_max for our initial port number */
11352 srand(getpid());
11353 if (client_port_max - client_port_min) {
11354 myport = client_port_min +
11355 (rand() % (client_port_max - client_port_min));
11356 }
11357 else {
11358 myport = client_port_min;
11359 }
11360 /* there will be a ++ before the first call to bind, so subtract one */
11361 myport--;
11362
11363 /* Set-up the test end conditions. For a request/response test, they */
11364 /* can be either time or transaction based. */
11365
11366 if (test_time) {
11367 /* The user wanted to end the test after a period of time. */
11368 times_up = 0;
11369 trans_remaining = 0;
11370 start_timer(test_time);
11371 }
11372 else {
11373 /* The tester wanted to send a number of bytes. */
11374 trans_remaining = test_bytes;
11375 times_up = 1;
11376 }
11377
11378 /* The cpu_start routine will grab the current time and possibly */
11379 /* value of the idle counter for later use in measuring cpu */
11380 /* utilization and/or service demand and thruput. */
11381
11382 cpu_start(local_cpu_usage);
11383
11384 #ifdef WANT_DEMO
11385 if (demo_mode) {
11386 HIST_timestamp(demo_one_ptr);
11387 }
11388 #endif
11389
11390 /* We use an "OR" to control test execution. When the test is */
11391 /* controlled by time, the byte count check will always return false. */
11392 /* When the test is controlled by byte count, the time test will */
11393 /* always return false. When the test is finished, the whole */
11394 /* expression will go false and we will stop sending data. I think I */
11395 /* just arbitrarily decrement trans_remaining for the timed test, but */
11396 /* will not do that just yet... One other question is whether or not */
11397 /* the send buffer and the receive buffer should be the same buffer. */
11398
11399 while ((!times_up) || (trans_remaining > 0)) {
11400
11401 #ifdef WANT_HISTOGRAM
11402 if (verbosity > 1) {
11403 /* timestamp just before our call to create the socket, and then */
11404 /* again just after the receive raj 3/95 */
11405 HIST_timestamp(&time_one);
11406 }
11407 #endif /* WANT_HISTOGRAM */
11408
11409 /* set up the data socket */
11410 /* newport: is this label really required any longer? */
11411 /* pick a new port number */
11412 myport++;
11413
11414 /* wrap the port number when we get to client_port_max. NOTE, some */
11415 /* broken TCP's might treat the port number as a signed 16 bit */
11416 /* quantity. we aren't interested in testing such broken */
11417 /* implementations :) so we won't make sure that it is below 32767 */
11418 /* raj 8/94 */
11419 if (myport >= client_port_max) {
11420 myport = client_port_min;
11421 }
11422
11423 /* we do not want to use the port number that the server is */
11424 /* sitting at - this would cause us to fail in a loopback test. we */
11425 /* could just rely on the failure of the bind to get us past this, */
11426 /* but I'm guessing that in this one case at least, it is much */
11427 /* faster, given that we *know* that port number is already in use */
11428 /* (or rather would be in a loopback test) */
11429
11430 if (myport == get_port_number(remote_res)) myport++;
11431
11432 if (debug) {
11433 if ((nummessages % 100) == 0) {
11434 printf("port %d\n",myport);
11435 }
11436 }
11437 set_port_number(local_res, (unsigned short)myport);
11438 send_socket = create_data_socket(local_res);
11439
11440 if (send_socket == INVALID_SOCKET) {
11441 perror("netperf: send_tcp_cc: tcp stream data socket");
11442 exit(1);
11443 }
11444
11445 /* we used to have a call to bind() here, but that is being
11446 taken care of by create_data_socket(). raj 2005-02-08 */
11447
11448 /* Connect up to the remote port on the data socket */
11449 if ((ret = connect(send_socket,
11450 remote_res->ai_addr,
11451 remote_res->ai_addrlen)) == INVALID_SOCKET){
11452 if (SOCKET_EINTR(ret))
11453 {
11454 /* we hit the end of a */
11455 /* timed test. */
11456 timed_out = 1;
11457 break;
11458 }
11459 perror("netperf: data socket connect failed");
11460 printf("\tattempted to connect on socket %d to port %d",
11461 send_socket,
11462 get_port_number(remote_res));
11463 printf(" from port %u \n",get_port_number(local_res));
11464 exit(1);
11465 }
11466
11467 /* we hang in a recv() to get the remote's close indication */
11468
11469 rsp_bytes_recvd=recv(send_socket,
11470 temp_message_ptr,
11471 rsp_bytes_left,
11472 0);
11473
11474
11475 if (rsp_bytes_recvd == 0) {
11476 /* connection close, call close. we assume that the requisite */
11477 /* number of bytes have been received */
11478
11479 #ifdef WANT_HISTOGRAM
11480 if (verbosity > 1) {
11481 HIST_timestamp(&time_two);
11482 HIST_add(time_hist,delta_micro(&time_one,&time_two));
11483 }
11484 #endif /* WANT_HISTOGRAM */
11485
11486 #ifdef WANT_DEMO
11487 DEMO_RR_INTERVAL(1)
11488 #endif
11489
11490 nummessages++;
11491 if (trans_remaining) {
11492 trans_remaining--;
11493 }
11494
11495 if (debug > 3) {
11496 fprintf(where,
11497 "Transaction %d completed on local port %u\n",
11498 nummessages,
11499 get_port_number(local_res));
11500 fflush(where);
11501 }
11502
11503 close(send_socket);
11504
11505 }
11506 else {
11507 /* it was less than zero - an error occured */
11508 if (SOCKET_EINTR(rsp_bytes_recvd))
11509 {
11510 /* We hit the end of a timed test. */
11511 timed_out = 1;
11512 break;
11513 }
11514 perror("send_tcp_cc: data recv error");
11515 exit(1);
11516 }
11517
11518 }
11519
11520
11521 /* this call will always give us the elapsed time for the test, and */
11522 /* will also store-away the necessaries for cpu utilization */
11523
11524 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
11525 /* how long did we really run? */
11526
11527 /* Get the statistics from the remote end. The remote will have */
11528 /* calculated service demand and all those interesting things. If it */
11529 /* wasn't supposed to care, it will return obvious values. */
11530
11531 recv_response();
11532 if (!netperf_response.content.serv_errno) {
11533 if (debug)
11534 fprintf(where,"remote results obtained\n");
11535 }
11536 else {
11537 Set_errno(netperf_response.content.serv_errno);
11538 fprintf(where,
11539 "netperf: remote error %d",
11540 netperf_response.content.serv_errno);
11541 perror("");
11542 fflush(where);
11543
11544 exit(1);
11545 }
11546
11547 /* We now calculate what our thruput was for the test. In the future, */
11548 /* we may want to include a calculation of the thruput measured by */
11549 /* the remote, but it should be the case that for a TCP stream test, */
11550 /* that the two numbers should be *very* close... We calculate */
11551 /* bytes_sent regardless of the way the test length was controlled. */
11552 /* If it was time, we needed to, and if it was by bytes, the user may */
11553 /* have specified a number of bytes that wasn't a multiple of the */
11554 /* send_size, so we really didn't send what he asked for ;-) We use */
11555 /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
11556 /* 1024. A future enhancement *might* be to choose from a couple of */
11557 /* unit selections. */
11558
11559 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
11560 thruput = calc_thruput(bytes_xferd);
11561
11562 if (local_cpu_usage || remote_cpu_usage) {
11563 /* We must now do a little math for service demand and cpu */
11564 /* utilization for the system(s) */
11565 /* Of course, some of the information might be bogus because */
11566 /* there was no idle counter in the kernel(s). We need to make */
11567 /* a note of this for the user's benefit...*/
11568 if (local_cpu_usage) {
11569 if (local_cpu_rate == 0.0) {
11570 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
11571 fprintf(where,"Local CPU usage numbers based on process information only!\n");
11572 fflush(where);
11573 }
11574 local_cpu_utilization = calc_cpu_util(0.0);
11575 /* since calc_service demand is doing ms/Kunit we will */
11576 /* multiply the number of transaction by 1024 to get */
11577 /* "good" numbers */
11578 local_service_demand = calc_service_demand((double) nummessages*1024,
11579 0.0,
11580 0.0,
11581 0);
11582 }
11583 else {
11584 local_cpu_utilization = (float) -1.0;
11585 local_service_demand = (float) -1.0;
11586 }
11587
11588 if (remote_cpu_usage) {
11589 if (remote_cpu_rate == 0.0) {
11590 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
11591 fprintf(where,"Remote CPU usage numbers based on process information only!\n");
11592 fflush(where);
11593 }
11594 remote_cpu_utilization = tcp_cc_result->cpu_util;
11595 /* since calc_service demand is doing ms/Kunit we will */
11596 /* multiply the number of transaction by 1024 to get */
11597 /* "good" numbers */
11598 remote_service_demand = calc_service_demand((double) nummessages*1024,
11599 0.0,
11600 remote_cpu_utilization,
11601 tcp_cc_result->num_cpus);
11602 }
11603 else {
11604 remote_cpu_utilization = (float) -1.0;
11605 remote_service_demand = (float) -1.0;
11606 }
11607
11608 /* We are now ready to print all the information. If the user */
11609 /* has specified zero-level verbosity, we will just print the */
11610 /* local service demand, or the remote service demand. If the */
11611 /* user has requested verbosity level 1, he will get the basic */
11612 /* "streamperf" numbers. If the user has specified a verbosity */
11613 /* of greater than 1, we will display a veritable plethora of */
11614 /* background information from outside of this block as it it */
11615 /* not cpu_measurement specific... */
11616
11617 switch (verbosity) {
11618 case 0:
11619 if (local_cpu_usage) {
11620 fprintf(where,
11621 cpu_fmt_0,
11622 local_service_demand);
11623 }
11624 else {
11625 fprintf(where,
11626 cpu_fmt_0,
11627 remote_service_demand);
11628 }
11629 break;
11630 case 1:
11631 case 2:
11632
11633 if (print_headers) {
11634 fprintf(where,
11635 cpu_title,
11636 local_cpu_method,
11637 remote_cpu_method);
11638 }
11639
11640 fprintf(where,
11641 cpu_fmt_1_line_1, /* the format string */
11642 lss_size, /* local sendbuf size */
11643 lsr_size,
11644 req_size, /* how large were the requests */
11645 rsp_size, /* guess */
11646 elapsed_time, /* how long was the test */
11647 nummessages/elapsed_time,
11648 local_cpu_utilization, /* local cpu */
11649 remote_cpu_utilization, /* remote cpu */
11650 local_service_demand, /* local service demand */
11651 remote_service_demand); /* remote service demand */
11652 fprintf(where,
11653 cpu_fmt_1_line_2,
11654 rss_size,
11655 rsr_size);
11656 break;
11657 }
11658 }
11659 else {
11660 /* The tester did not wish to measure service demand. */
11661 switch (verbosity) {
11662 case 0:
11663 fprintf(where,
11664 tput_fmt_0,
11665 nummessages/elapsed_time);
11666 break;
11667 case 1:
11668 case 2:
11669 if (print_headers) {
11670 fprintf(where,tput_title,format_units());
11671 }
11672
11673 fprintf(where,
11674 tput_fmt_1_line_1, /* the format string */
11675 lss_size,
11676 lsr_size,
11677 req_size, /* how large were the requests */
11678 rsp_size, /* how large were the responses */
11679 elapsed_time, /* how long did it take */
11680 nummessages/elapsed_time);
11681 fprintf(where,
11682 tput_fmt_1_line_2,
11683 rss_size, /* remote recvbuf size */
11684 rsr_size);
11685
11686 break;
11687 }
11688 }
11689
11690 /* it would be a good thing to include information about some of the */
11691 /* other parameters that may have been set for this test, but at the */
11692 /* moment, I do not wish to figure-out all the formatting, so I will */
11693 /* just put this comment here to help remind me that it is something */
11694 /* that should be done at a later time. */
11695
11696 if (verbosity > 1) {
11697 /* The user wanted to know it all, so we will give it to him. */
11698 /* This information will include as much as we can find about */
11699 /* TCP statistics, the alignments of the sends and receives */
11700 /* and all that sort of rot... */
11701
11702 fprintf(where,
11703 ksink_fmt,
11704 local_send_align,
11705 remote_recv_offset,
11706 local_send_offset,
11707 remote_recv_offset);
11708
11709 #ifdef WANT_HISTOGRAM
11710 fprintf(where,"\nHistogram of request/response times\n");
11711 fflush(where);
11712 HIST_report(time_hist);
11713 #endif /* WANT_HISTOGRAM */
11714
11715 }
11716
11717 }
11718
11719
11720 void
recv_tcp_cc()11721 recv_tcp_cc()
11722 {
11723
11724 char *message;
11725
11726 struct addrinfo *local_res;
11727 char local_name[BUFSIZ];
11728 char port_buffer[PORTBUFSIZE];
11729
11730 struct sockaddr_storage myaddr_in, peeraddr_in;
11731 SOCKET s_listen,s_data;
11732 netperf_socklen_t addrlen;
11733 char *recv_message_ptr;
11734 char *send_message_ptr;
11735 int trans_received;
11736 int trans_remaining;
11737 int timed_out = 0;
11738 float elapsed_time;
11739
11740 struct tcp_cc_request_struct *tcp_cc_request;
11741 struct tcp_cc_response_struct *tcp_cc_response;
11742 struct tcp_cc_results_struct *tcp_cc_results;
11743
11744 tcp_cc_request =
11745 (struct tcp_cc_request_struct *)netperf_request.content.test_specific_data;
11746 tcp_cc_response =
11747 (struct tcp_cc_response_struct *)netperf_response.content.test_specific_data;
11748 tcp_cc_results =
11749 (struct tcp_cc_results_struct *)netperf_response.content.test_specific_data;
11750
11751 if (debug) {
11752 fprintf(where,"netserver: recv_tcp_cc: entered...\n");
11753 fflush(where);
11754 }
11755
11756 /* We want to set-up the listen socket with all the desired */
11757 /* parameters and then let the initiator know that all is ready. If */
11758 /* socket size defaults are to be used, then the initiator will have */
11759 /* sent us 0's. If the socket sizes cannot be changed, then we will */
11760 /* send-back what they are. If that information cannot be determined, */
11761 /* then we send-back -1's for the sizes. If things go wrong for any */
11762 /* reason, we will drop back ten yards and punt. */
11763
11764 /* If anything goes wrong, we want the remote to know about it. It */
11765 /* would be best if the error that the remote reports to the user is */
11766 /* the actual error we encountered, rather than some bogus unexpected */
11767 /* response type message. */
11768
11769 if (debug) {
11770 fprintf(where,"recv_tcp_cc: setting the response type...\n");
11771 fflush(where);
11772 }
11773
11774 netperf_response.content.response_type = TCP_CC_RESPONSE;
11775
11776 if (debug) {
11777 fprintf(where,"recv_tcp_cc: the response type is set...\n");
11778 fflush(where);
11779 }
11780
11781 /* set-up the data buffer with the requested alignment and offset */
11782 message = (char *)malloc(DATABUFFERLEN);
11783 if (message == NULL) {
11784 printf("malloc(%d) failed!\n", DATABUFFERLEN);
11785 exit(1);
11786 }
11787
11788 /* We now alter the message_ptr variables to be at the desired */
11789 /* alignments with the desired offsets. */
11790
11791 if (debug) {
11792 fprintf(where,
11793 "recv_tcp_cc: requested recv alignment of %d offset %d\n",
11794 tcp_cc_request->recv_alignment,
11795 tcp_cc_request->recv_offset);
11796 fprintf(where,
11797 "recv_tcp_cc: requested send alignment of %d offset %d\n",
11798 tcp_cc_request->send_alignment,
11799 tcp_cc_request->send_offset);
11800 fflush(where);
11801 }
11802
11803 recv_message_ptr = ALIGN_BUFFER(message, tcp_cc_request->recv_alignment, tcp_cc_request->recv_offset);
11804
11805 send_message_ptr = ALIGN_BUFFER(message, tcp_cc_request->send_alignment, tcp_cc_request->send_offset);
11806
11807 if (debug) {
11808 fprintf(where,"recv_tcp_cc: receive alignment and offset set...\n");
11809 fflush(where);
11810 }
11811
11812 /* Grab a socket to listen on, and then listen on it. */
11813
11814 if (debug) {
11815 fprintf(where,"recv_tcp_cc: grabbing a socket...\n");
11816 fflush(where);
11817 }
11818
11819 /* create_data_socket expects to find some things in the global */
11820 /* variables, so set the globals based on the values in the request. */
11821 /* once the socket has been created, we will set the response values */
11822 /* based on the updated value of those globals. raj 7/94 */
11823 lss_size_req = tcp_cc_request->send_buf_size;
11824 lsr_size_req = tcp_cc_request->recv_buf_size;
11825 loc_nodelay = tcp_cc_request->no_delay;
11826 loc_rcvavoid = tcp_cc_request->so_rcvavoid;
11827 loc_sndavoid = tcp_cc_request->so_sndavoid;
11828
11829 set_hostname_and_port(local_name,
11830 port_buffer,
11831 nf_to_af(tcp_cc_request->ipfamily),
11832 tcp_cc_request->port);
11833
11834 local_res = complete_addrinfo(local_name,
11835 local_name,
11836 port_buffer,
11837 nf_to_af(tcp_cc_request->ipfamily),
11838 SOCK_STREAM,
11839 IPPROTO_TCP,
11840 0);
11841
11842 s_listen = create_data_socket(local_res);
11843
11844 if (s_listen == INVALID_SOCKET) {
11845 netperf_response.content.serv_errno = errno;
11846 send_response();
11847 if (debug) {
11848 fprintf(where,"could not create data socket\n");
11849 fflush(where);
11850 }
11851 exit(1);
11852 }
11853
11854 #ifdef WIN32
11855 /* The test timer can fire during operations on the listening socket,
11856 so to make the start_timer below work we have to move
11857 it to close s_listen while we are blocked on accept. */
11858 win_kludge_socket2 = s_listen;
11859 #endif
11860
11861
11862 /* Now, let's set-up the socket to listen for connections */
11863 if (listen(s_listen, 5) == SOCKET_ERROR) {
11864 netperf_response.content.serv_errno = errno;
11865 close(s_listen);
11866 send_response();
11867 if (debug) {
11868 fprintf(where,"could not listen\n");
11869 fflush(where);
11870 }
11871 exit(1);
11872 }
11873
11874 /* now get the port number assigned by the system */
11875 addrlen = sizeof(myaddr_in);
11876 if (getsockname(s_listen,
11877 (struct sockaddr *)&myaddr_in,
11878 &addrlen) == SOCKET_ERROR){
11879 netperf_response.content.serv_errno = errno;
11880 close(s_listen);
11881 send_response();
11882 if (debug) {
11883 fprintf(where,"could not geetsockname\n");
11884 fflush(where);
11885 }
11886 exit(1);
11887 }
11888
11889 /* Now myaddr_in contains the port and the internet address this is */
11890 /* returned to the sender also implicitly telling the sender that the */
11891 /* socket buffer sizing has been done. */
11892
11893 tcp_cc_response->data_port_number =
11894 (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
11895 if (debug) {
11896 fprintf(where,"telling the remote to call me at %d\n",
11897 tcp_cc_response->data_port_number);
11898 fflush(where);
11899 }
11900 netperf_response.content.serv_errno = 0;
11901
11902 /* But wait, there's more. If the initiator wanted cpu measurements, */
11903 /* then we must call the calibrate routine, which will return the max */
11904 /* rate back to the initiator. If the CPU was not to be measured, or */
11905 /* something went wrong with the calibration, we will return a 0.0 to */
11906 /* the initiator. */
11907
11908 tcp_cc_response->cpu_rate = (float)0.0; /* assume no cpu */
11909 if (tcp_cc_request->measure_cpu) {
11910 tcp_cc_response->measure_cpu = 1;
11911 tcp_cc_response->cpu_rate =
11912 calibrate_local_cpu(tcp_cc_request->cpu_rate);
11913 }
11914
11915
11916
11917 /* before we send the response back to the initiator, pull some of */
11918 /* the socket parms from the globals */
11919 tcp_cc_response->send_buf_size = lss_size;
11920 tcp_cc_response->recv_buf_size = lsr_size;
11921 tcp_cc_response->no_delay = loc_nodelay;
11922 tcp_cc_response->so_rcvavoid = loc_rcvavoid;
11923 tcp_cc_response->so_sndavoid = loc_sndavoid;
11924
11925 send_response();
11926
11927 addrlen = sizeof(peeraddr_in);
11928
11929 /* Now it's time to start receiving data on the connection. We will */
11930 /* first grab the apropriate counters and then start grabbing. */
11931
11932 cpu_start(tcp_cc_request->measure_cpu);
11933
11934 /* The loop will exit when the sender does a shutdown, which will */
11935 /* return a length of zero */
11936
11937 if (tcp_cc_request->test_length > 0) {
11938 times_up = 0;
11939 trans_remaining = 0;
11940 start_timer(tcp_cc_request->test_length + PAD_TIME);
11941 }
11942 else {
11943 times_up = 1;
11944 trans_remaining = tcp_cc_request->test_length * -1;
11945 }
11946
11947 trans_received = 0;
11948
11949 while ((!times_up) || (trans_remaining > 0)) {
11950 #ifdef WIN32
11951 /* The test timer will probably fire during this accept,
11952 so to make the start_timer above work we have to move
11953 it to close s_listen while we are blocked on accept. */
11954 win_kludge_socket = s_listen;
11955 #endif
11956 /* accept a connection from the remote */
11957 if ((s_data=accept(s_listen,
11958 (struct sockaddr *)&peeraddr_in,
11959 &addrlen)) == INVALID_SOCKET) {
11960 if (errno == EINTR) {
11961 /* the timer popped */
11962 timed_out = 1;
11963 break;
11964 }
11965 fprintf(where,"recv_tcp_cc: accept: errno = %d\n",errno);
11966 fflush(where);
11967 close(s_listen);
11968
11969 exit(1);
11970 }
11971
11972 #ifdef KLUDGE_SOCKET_OPTIONS
11973 /* this is for those systems which *INCORRECTLY* fail to pass */
11974 /* attributes across an accept() call. Including this goes against */
11975 /* my better judgement :( raj 11/95 */
11976
11977 kludge_socket_options(s_data);
11978
11979 #endif /* KLUDGE_SOCKET_OPTIONS */
11980
11981 #ifdef WIN32
11982 /* this is used so the timer thread can close the socket out from */
11983 /* under us, which to date is the easiest/cleanest/least */
11984 /* Windows-specific way I can find to force the winsock calls to */
11985 /* return WSAEINTR with the test is over. anything that will run on */
11986 /* 95 and NT and is closer to what netperf expects from Unix signals */
11987 /* and such would be appreciated raj 1/96 */
11988 win_kludge_socket = s_data;
11989 #endif /* WIN32 */
11990
11991 if (debug) {
11992 fprintf(where,"recv_tcp_cc: accepted data connection.\n");
11993 fflush(where);
11994 }
11995
11996
11997 /* close the connection. the server will likely do a graceful */
11998 /* close of the connection, insuring that all data has arrived at */
11999 /* the client. for this it will call shutdown(), and then recv() and */
12000 /* then close(). I'm reasonably confident that this is the */
12001 /* appropriate sequence of calls - I would like to hear of */
12002 /* examples in web servers to the contrary. raj 10/95*/
12003 close(s_data);
12004
12005 trans_received++;
12006 if (trans_remaining) {
12007 trans_remaining--;
12008 }
12009
12010 if (debug) {
12011 fprintf(where,
12012 "recv_tcp_cc: Transaction %d complete\n",
12013 trans_received);
12014 fflush(where);
12015 }
12016
12017 }
12018
12019
12020 /* The loop now exits due to timeout or transaction count being */
12021 /* reached */
12022
12023 cpu_stop(tcp_cc_request->measure_cpu,&elapsed_time);
12024
12025 if (timed_out) {
12026 /* we ended the test by time, which was at least 2 seconds */
12027 /* longer than we wanted to run. so, we want to subtract */
12028 /* PAD_TIME from the elapsed_time. */
12029 elapsed_time -= PAD_TIME;
12030 }
12031 /* send the results to the sender */
12032
12033 if (debug) {
12034 fprintf(where,
12035 "recv_tcp_cc: got %d transactions\n",
12036 trans_received);
12037 fflush(where);
12038 }
12039
12040 tcp_cc_results->bytes_received = (trans_received *
12041 (tcp_cc_request->request_size +
12042 tcp_cc_request->response_size));
12043 tcp_cc_results->trans_received = trans_received;
12044 tcp_cc_results->elapsed_time = elapsed_time;
12045 if (tcp_cc_request->measure_cpu) {
12046 tcp_cc_results->cpu_util = calc_cpu_util(elapsed_time);
12047 }
12048
12049 if (debug) {
12050 fprintf(where,
12051 "recv_tcp_cc: test complete, sending results.\n");
12052 fflush(where);
12053 }
12054
12055 send_response();
12056
12057 }
12058
12059 void
print_sockets_usage()12060 print_sockets_usage()
12061 {
12062
12063 fwrite(sockets_usage, sizeof(char), strlen(sockets_usage), stdout);
12064 exit(1);
12065
12066 }
12067
12068 void
scan_sockets_args(int argc,char * argv[])12069 scan_sockets_args(int argc, char *argv[])
12070
12071 {
12072
12073 #define SOCKETS_ARGS "b:CDnNhH:L:m:M:p:P:r:s:S:T:Vw:W:z46"
12074
12075 extern char *optarg; /* pointer to option string */
12076
12077 int c;
12078
12079 char
12080 arg1[BUFSIZ], /* argument holders */
12081 arg2[BUFSIZ];
12082
12083 if (debug) {
12084 int i;
12085 printf("%s called with the following argument vector\n",
12086 __func__);
12087 for (i = 0; i< argc; i++) {
12088 printf("%s ",argv[i]);
12089 }
12090 printf("\n");
12091 }
12092
12093 strncpy(local_data_port,"0",sizeof(local_data_port));
12094 strncpy(remote_data_port,"0",sizeof(remote_data_port));
12095
12096 /* Go through all the command line arguments and break them */
12097 /* out. For those options that take two parms, specifying only */
12098 /* the first will set both to that value. Specifying only the */
12099 /* second will leave the first untouched. To change only the */
12100 /* first, use the form "first," (see the routine break_args.. */
12101
12102 while ((c= getopt(argc, argv, SOCKETS_ARGS)) != EOF) {
12103 switch (c) {
12104 case '?':
12105 case '4':
12106 remote_data_family = AF_INET;
12107 local_data_family = AF_INET;
12108 break;
12109 case '6':
12110 #if defined(AF_INET6)
12111 remote_data_family = AF_INET6;
12112 local_data_family = AF_INET6;
12113 #else
12114 fprintf(stderr,
12115 "This netperf was not compiled on an IPv6 capable host!\n");
12116 fflush(stderr);
12117 exit(-1);
12118 #endif
12119 break;
12120 case 'h':
12121 print_sockets_usage();
12122 exit(1);
12123 case 'b':
12124 #ifdef WANT_FIRST_BURST
12125 first_burst_size = atoi(optarg);
12126 #else /* WANT_FIRST_BURST */
12127 printf("Initial request burst functionality not compiled-in!\n");
12128 #endif /* WANT_FIRST_BURST */
12129 break;
12130 case 'C':
12131 #ifdef TCP_CORK
12132 /* set TCP_CORK */
12133 loc_tcpcork = 1;
12134 rem_tcpcork = 1; /* however, at first, we ony have cork affect loc */
12135 #else
12136 printf("WARNING: TCP_CORK not available on this platform!\n");
12137 #endif /* TCP_CORK */
12138 break;
12139 case 'D':
12140 /* set the TCP nodelay flag */
12141 loc_nodelay = 1;
12142 rem_nodelay = 1;
12143 break;
12144 case 'H':
12145 break_args_explicit(optarg,arg1,arg2);
12146 if (arg1[0]) {
12147 /* make sure we leave room for the NULL termination boys and
12148 girls. raj 2005-02-82 */
12149 remote_data_address = malloc(strlen(arg1)+1);
12150 strncpy(remote_data_address,arg1,strlen(arg1));
12151 }
12152 if (arg2[0])
12153 remote_data_family = parse_address_family(arg2);
12154 break;
12155 case 'L':
12156 break_args_explicit(optarg,arg1,arg2);
12157 if (arg1[0]) {
12158 /* make sure we leave room for the NULL termination boys and
12159 girls. raj 2005-02-82 */
12160 local_data_address = malloc(strlen(arg1)+1);
12161 strncpy(local_data_address,arg1,strlen(arg1));
12162 }
12163 if (arg2[0])
12164 local_data_family = parse_address_family(arg2);
12165 break;
12166 case 's':
12167 /* set local socket sizes */
12168 break_args(optarg,arg1,arg2);
12169 if (arg1[0])
12170 lss_size_req = convert(arg1);
12171 if (arg2[0])
12172 lsr_size_req = convert(arg2);
12173 break;
12174 case 'S':
12175 /* set remote socket sizes */
12176 break_args(optarg,arg1,arg2);
12177 if (arg1[0])
12178 rss_size_req = convert(arg1);
12179 if (arg2[0])
12180 rsr_size_req = convert(arg2);
12181 break;
12182 case 'r':
12183 /* set the request/response sizes */
12184 break_args(optarg,arg1,arg2);
12185 if (arg1[0])
12186 req_size = convert(arg1);
12187 if (arg2[0])
12188 rsp_size = convert(arg2);
12189 break;
12190 case 'm':
12191 /* set the send size */
12192 send_size = convert(optarg);
12193 break;
12194 case 'M':
12195 /* set the recv size */
12196 recv_size = convert(optarg);
12197 break;
12198 case 'n':
12199 /* set the local socket type*/
12200 local_connected = 1;
12201 break;
12202 case 'N':
12203 /* set the remote socket type*/
12204 remote_connected = 1;
12205 break;
12206 case 'p':
12207 /* set the min and max port numbers for the TCP_CRR and TCP_TRR */
12208 /* tests. */
12209 break_args(optarg,arg1,arg2);
12210 if (arg1[0])
12211 client_port_min = atoi(arg1);
12212 if (arg2[0])
12213 client_port_max = atoi(arg2);
12214 break;
12215 case 'P':
12216 /* set the local and remote data port numbers for the tests to
12217 allow them to run through those blankety blank end-to-end
12218 breaking firewalls. raj 2004-06-15 */
12219 break_args(optarg,arg1,arg2);
12220 if (arg1[0])
12221 strncpy(local_data_port,arg1,sizeof(local_data_port));
12222 if (arg2[0])
12223 strncpy(remote_data_port,arg2,sizeof(remote_data_port));
12224 break;
12225 case 't':
12226 /* set the test name */
12227 strcpy(test_name,optarg);
12228 break;
12229 case 'W':
12230 /* set the "width" of the user space data */
12231 /* buffer. This will be the number of */
12232 /* send_size buffers malloc'd in the */
12233 /* *_STREAM test. It may be enhanced to set */
12234 /* both send and receive "widths" but for now */
12235 /* it is just the sending *_STREAM. */
12236 send_width = convert(optarg);
12237 break;
12238 case 'V' :
12239 /* we want to do copy avoidance and will set */
12240 /* it for everything, everywhere, if we really */
12241 /* can. of course, we don't know anything */
12242 /* about the remote... */
12243 #ifdef SO_SND_COPYAVOID
12244 loc_sndavoid = 1;
12245 #else
12246 loc_sndavoid = 0;
12247 printf("Local send copy avoidance not available.\n");
12248 #endif
12249 #ifdef SO_RCV_COPYAVOID
12250 loc_rcvavoid = 1;
12251 #else
12252 loc_rcvavoid = 0;
12253 printf("Local recv copy avoidance not available.\n");
12254 #endif
12255 rem_sndavoid = 1;
12256 rem_rcvavoid = 1;
12257 break;
12258 };
12259 }
12260
12261 #if defined(WANT_FIRST_BURST)
12262 #if defined(WANT_HISTOGRAM)
12263 /* if WANT_FIRST_BURST and WANT_HISTOGRAM are defined and the user
12264 indeed wants a non-zero first burst size, and we would emit a
12265 histogram, then we should emit a warning that the two are not
12266 compatible. raj 2006-01-31 */
12267 if ((first_burst_size > 0) && (verbosity >= 2)) {
12268 fprintf(stderr,
12269 "WARNING! Histograms and first bursts are incompatible!\n");
12270 fflush(stderr);
12271 }
12272 #endif
12273 #endif
12274
12275 /* we do not want to make remote_data_address non-NULL because if
12276 the user has not specified a remote adata address, we want to
12277 take it from the hostname in the -H global option. raj
12278 2005-02-08 */
12279
12280 /* so, if there is to be no control connection, we want to have some
12281 different settings for a few things */
12282
12283 if (no_control) {
12284
12285 if (strcmp(remote_data_port,"0") == 0) {
12286 /* we need to select either the discard port, echo port or
12287 chargen port dedepending on the test name. raj 2007-02-08 */
12288 if (strstr(test_name,"STREAM") ||
12289 strstr(test_name,"SENDFILE")) {
12290 strncpy(remote_data_port,"discard",sizeof(remote_data_port));
12291 }
12292 else if (strstr(test_name,"RR")) {
12293 strncpy(remote_data_port,"echo",sizeof(remote_data_port));
12294 }
12295 else if (strstr(test_name,"MAERTS")) {
12296 strncpy(remote_data_port,"chargen",sizeof(remote_data_port));
12297 }
12298 else {
12299 printf("No default port known for the %s test, please set one yourself\n",test_name);
12300 exit(-1);
12301 }
12302 }
12303 remote_data_port[sizeof(remote_data_port) - 1] = '\0';
12304
12305 /* I go back and forth on whether these should become -1 or if
12306 they should become 0 for a no_control test. what do you think?
12307 raj 2006-02-08 */
12308
12309 rem_rcvavoid = -1;
12310 rem_sndavoid = -1;
12311 rss_size_req = -1;
12312 rsr_size_req = -1;
12313 rem_nodelay = -1;
12314
12315 if (strstr(test_name,"STREAM") ||
12316 strstr(test_name,"SENDFILE")) {
12317 recv_size = -1;
12318 }
12319 else if (strstr(test_name,"RR")) {
12320 /* I am however _certain_ that for a no control RR test the
12321 response size must equal the request size since 99 times out
12322 of ten we will be speaking to the echo service somewhere */
12323 rsp_size = req_size;
12324 }
12325 else if (strstr(test_name,"MAERTS")) {
12326 send_size = -1;
12327 }
12328 else {
12329 printf("No default port known for the %s test, please set one yourself\n",test_name);
12330 exit(-1);
12331 }
12332 }
12333 }
12334