blob: 9d27f25439b4d147e5e6d0992f698ec140b8d432 [file] [log] [blame]
The Android Open Source Project02fb0ac2009-03-03 19:30:07 -08001#ifdef HAVE_CONFIG_H
2#include <config.h>
3#endif
4
5#ifdef WANT_XTI
6#ifndef lint
7char nettest_xti_id[]="\
8@(#)nettest_xti.c (c) Copyright 1995-2007 Hewlett-Packard Co. Version 2.4.3";
9#else
10#define DIRTY
11#define WANT_HISTOGRAM
12#define WANT_INTERVALS
13#endif /* lint */
14/****************************************************************/
15/* */
16/* nettest_xti.c */
17/* */
18/* the XTI args parsing routine... */
19/* */
20/* scan_xti_args() */
21/* */
22/* the actual test routines... */
23/* */
24/* send_xti_tcp_stream() perform a tcp stream test */
25/* recv_xti_tcp_stream() */
26/* send_xti_tcp_rr() perform a tcp request/response */
27/* recv_xti_tcp_rr() */
28/* send_xti_tcp_conn_rr() an RR test including connect */
29/* recv_xti_tcp_conn_rr() */
30/* send_xti_udp_stream() perform a udp stream test */
31/* recv_xti_udp_stream() */
32/* send_xti_udp_rr() perform a udp request/response */
33/* recv_xti_udp_rr() */
34/* */
35/****************************************************************/
36
37#ifdef HAVE_CONFIG_H
38#include <config.h>
39#endif
40
41#include <sys/types.h>
42#include <fcntl.h>
43#ifndef WIN32
44#include <sys/ipc.h>
45#include <sys/socket.h>
46#include <netinet/in.h>
47#include <netdb.h>
48#include <errno.h>
49#include <signal.h>
50#else /* WIN32 */
51#include <process.h>
52#include <winsock2.h>
53#include <windows.h>
54#endif /* WIN32 */
55#include <stdio.h>
56#include <time.h>
57#include <malloc.h>
58 /* xti.h should be included *after* in.h because there are name */
59 /* conflicts!( Silly standards people... raj 2/95 fortuenately, the */
60 /* confilcts are on IP_TOP and IP_TTL, whcih netperf does not yet use */
61#include <xti.h>
62
63#include "netlib.h"
64#include "netsh.h"
65#include "nettest_xti.h"
66
67#ifdef WANT_HISTOGRAM
68#ifdef __sgi
69#include <sys/time.h>
70#endif /* __sgi */
71#include "hist.h"
72#endif /* WANT_HISTOGRAM */
73
74
75
76 /* these variables are specific to the XTI sockets tests. declare */
77 /* them static to make them global only to this file. */
78
79static int
80 rss_size, /* remote socket send buffer size */
81 rsr_size, /* remote socket recv buffer size */
82 lss_size, /* local socket send buffer size */
83 lsr_size, /* local socket recv buffer size */
84 req_size = 1, /* request size */
85 rsp_size = 1, /* response size */
86 send_size, /* how big are individual sends */
87 recv_size; /* how big are individual receives */
88
89static int confidence_iteration;
90static char local_cpu_method;
91static char remote_cpu_method;
92
93 /* different options for the xti */
94
95static int
96 loc_nodelay, /* don't/do use NODELAY locally */
97 rem_nodelay, /* don't/do use NODELAY remotely */
98 loc_sndavoid, /* avoid send copies locally */
99 loc_rcvavoid, /* avoid recv copies locally */
100 rem_sndavoid, /* avoid send copies remotely */
101 rem_rcvavoid; /* avoid recv_copies remotely */
102
103static struct t_info info_struct;
104
105#ifdef WANT_HISTOGRAM
106#ifdef HAVE_GETHRTIME
107hrtime_t time_one;
108hrtime_t time_two;
109#else
110static struct timeval time_one;
111static struct timeval time_two;
112#endif /* HAVE_GETHRTIME */
113static HIST time_hist;
114#endif /* WANT_HISTOGRAM */
115
116static char loc_xti_device[32] = "/dev/tcp";
117static char rem_xti_device[32] = "/dev/tcp";
118
119static int xti_flags = 0;
120
121char xti_usage[] = "\n\
122Usage: netperf [global options] -- [test options] \n\
123\n\
124TCP/UDP XTI API Test Options:\n\
125 -D [L][,R] Set XTI_TCP_NODELAY locally and/or remotely (XTI_TCP_*)\n\
126 -h Display this text\n\
127 -m bytes Set the send size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\
128 -M bytes Set the recv size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\
129 -r bytes Set request size (XTI_TCP_RR, XTI_UDP_RR)\n\
130 -R bytes Set response size (XTI_TCP_RR, XTI_UDP_RR)\n\
131 -s send[,recv] Set local socket send/recv buffer sizes\n\
132 -S send[,recv] Set remote socket send/recv buffer sizes\n\
133 -X dev[,dev] Set the local/remote XTI device file name\n\
134\n\
135For those options taking two parms, at least one must be specified;\n\
136specifying one value without a comma will set both parms to that\n\
137value, specifying a value with a leading comma will set just the second\n\
138parm, a value with a trailing comma will set just the first. To set\n\
139each parm to unique values, specify both and separate them with a\n\
140comma.\n";
141
142
143 /* This routine is intended to retrieve interesting aspects of tcp */
144 /* for the data connection. at first, it attempts to retrieve the */
145 /* maximum segment size. later, it might be modified to retrieve */
146 /* other information, but it must be information that can be */
147 /* retrieved quickly as it is called during the timing of the test. */
148 /* for that reason, a second routine may be created that can be */
149 /* called outside of the timing loop */
150void
151get_xti_info(socket, info_struct)
152 int socket;
153 struct t_info *info_struct;
154{
155
156}
157
158
159 /* This routine will create a data (listen) socket with the apropriate */
160 /* options set and return it to the caller. this replaces all the */
161 /* duplicate code in each of the test routines and should help make */
162 /* things a little easier to understand. since this routine can be */
163 /* called by either the netperf or netserver programs, all output */
164 /* should be directed towards "where." family is generally AF_INET, */
165 /* and type will be either SOCK_STREAM or SOCK_DGRAM */
166SOCKET
167create_xti_endpoint(char *name)
168{
169
170 SOCKET temp_socket;
171
172 struct t_optmgmt *opt_req; /* we request an option */
173 struct t_optmgmt *opt_ret; /* it tells us what we got */
174
175 /* we use this to pass-in BSD-like socket options through t_optmgmt. */
176 /* it ends up being about as clear as mud. raj 2/95 */
177 struct sock_option {
178 struct t_opthdr myopthdr;
179 long value;
180 } *sock_option;
181
182 if (debug) {
183 fprintf(where,"create_xti_endpoint: attempting to open %s\n",
184 name);
185 fflush(where);
186 }
187
188 /*set up the data socket */
189 temp_socket = t_open(name,O_RDWR,NULL);
190
191 if (temp_socket == INVALID_SOCKET){
192 fprintf(where,
193 "netperf: create_xti_endpoint: t_open %s: errno %d t_errno %d\n",
194 name,
195 errno,
196 t_errno);
197 fflush(where);
198 exit(1);
199 }
200
201 if (debug) {
202 fprintf(where,"create_xti_endpoint: socket %d obtained...\n",temp_socket);
203 fflush(where);
204 }
205
206 /* allocate what we need for option mgmt */
207 if ((opt_req = (struct t_optmgmt *)t_alloc(temp_socket,T_OPTMGMT,T_ALL)) ==
208 NULL) {
209 fprintf(where,
210 "netperf: create_xti_endpoint: t_alloc: opt_req errno %d\n",
211 errno);
212 fflush(where);
213 exit(1);
214 }
215
216 if (debug) {
217 fprintf(where,
218 "create_xti_endpoint: opt_req->opt.buf %x maxlen %d len %d\n",
219 opt_req->opt.buf,
220 opt_req->opt.maxlen,
221 opt_req->opt.len);
222
223 fflush(where);
224 }
225
226 if ((opt_ret = (struct t_optmgmt *) t_alloc(temp_socket,T_OPTMGMT,T_ALL)) ==
227 NULL) {
228 fprintf(where,
229 "netperf: create_xti_endpoint: t_alloc: opt_ret errno %d\n",
230 errno);
231 fflush(where);
232 exit(1);
233 }
234
235 if (debug) {
236 fprintf(where,
237 "create_xti_endpoint: opt_ret->opt.buf %x maxlen %d len %d\n",
238 opt_ret->opt.buf,
239 opt_ret->opt.maxlen,
240 opt_ret->opt.len);
241 fflush(where);
242 }
243
244 /* Modify the local socket size. The reason we alter the send buffer */
245 /* size here rather than when the connection is made is to take care */
246 /* of decreases in buffer size. Decreasing the window size after */
247 /* connection establishment is a TCP no-no. Also, by setting the */
248 /* buffer (window) size before the connection is established, we can */
249 /* control the TCP MSS (segment size). The MSS is never more that 1/2 */
250 /* the minimum receive buffer size at each half of the connection. */
251 /* This is why we are altering the receive buffer size on the sending */
252 /* size of a unidirectional transfer. If the user has not requested */
253 /* that the socket buffers be altered, we will try to find-out what */
254 /* their values are. If we cannot touch the socket buffer in any way, */
255 /* we will set the values to -1 to indicate that. */
256
257#ifdef XTI_SNDBUF
258 if (lss_size > 0) {
259 /* we want to "negotiate" the option */
260 opt_req->flags = T_NEGOTIATE;
261 }
262 else {
263 /* we want to accept the default, and know what it is. I assume */
264 /* that when nothing has been changed, that T_CURRENT will return */
265 /* the same as T_DEFAULT raj 3/95 */
266 opt_req->flags = T_CURRENT;
267 }
268
269 /* the first part is for the netbuf that holds the option we want */
270 /* to negotiate or check */
271 /* the buffer of the netbuf points at the socket options structure */
272
273 /* we assume that the t_alloc call allocated a buffer that started */
274 /* on a proper alignment */
275 sock_option = (struct sock_option *)opt_req->opt.buf;
276
277 /* and next, set the fields in the sock_option structure */
278 sock_option->myopthdr.level = XTI_GENERIC;
279 sock_option->myopthdr.name = XTI_SNDBUF;
280 sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long);
281 sock_option->value = lss_size;
282
283 opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long);
284
285 /* now, set-up the stuff to return the value in the end */
286 /* we assume that the t_alloc call allocated a buffer that started */
287 /* on a proper alignment */
288 sock_option = (struct sock_option *)opt_ret->opt.buf;
289
290 /* finally, call t_optmgmt. clear as mud. */
291 if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
292 fprintf(where,
293 "netperf: create_xti_endpoint: XTI_SNDBUF option: t_errno %d\n",
294 t_errno);
295 fflush(where);
296 exit(1);
297 }
298
299 if (sock_option->myopthdr.status == T_SUCCESS) {
300 lss_size = sock_option->value;
301 }
302 else {
303 fprintf(where,"create_xti_endpoint: XTI_SNDBUF option status 0x%.4x",
304 sock_option->myopthdr.status);
305 fprintf(where," value %d\n",
306 sock_option->value);
307 fflush(where);
308 lss_size = -1;
309 }
310
311 if (lsr_size > 0) {
312 /* we want to "negotiate" the option */
313 opt_req->flags = T_NEGOTIATE;
314 }
315 else {
316 /* we want to accept the default, and know what it is. I assume */
317 /* that when nothing has been changed, that T_CURRENT will return */
318 /* the same as T_DEFAULT raj 3/95 */
319 opt_req->flags = T_CURRENT;
320 }
321
322 /* the first part is for the netbuf that holds the option we want */
323 /* to negotiate or check */
324 /* the buffer of the netbuf points at the socket options structure */
325
326 /* we assume that the t_alloc call allocated a buffer that started */
327 /* on a proper alignment */
328 sock_option = (struct sock_option *)opt_req->opt.buf;
329
330 /* and next, set the fields in the sock_option structure */
331 sock_option->myopthdr.level = XTI_GENERIC;
332 sock_option->myopthdr.name = XTI_RCVBUF;
333 sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long);
334 sock_option->value = lsr_size;
335
336 opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long);
337
338 /* now, set-up the stuff to return the value in the end */
339 /* we assume that the t_alloc call allocated a buffer that started */
340 /* on a proper alignment */
341 sock_option = (struct sock_option *)opt_ret->opt.buf;
342
343 /* finally, call t_optmgmt. clear as mud. */
344 if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
345 fprintf(where,
346 "netperf: create_xti_endpoint: XTI_RCVBUF option: t_errno %d\n",
347 t_errno);
348 fflush(where);
349 exit(1);
350 }
351 lsr_size = sock_option->value;
352
353 /* this needs code */
354
355 if (debug) {
356 fprintf(where,"netperf: create_xti_endpoint: socket sizes determined...\n");
357 fprintf(where," send: %d recv: %d\n",
358 lss_size,lsr_size);
359 fflush(where);
360 }
361
362#else /* XTI_SNDBUF */
363
364 lss_size = -1;
365 lsr_size = -1;
366
367#endif /* XTI_SNDBUF */
368
369 /* now, we may wish to enable the copy avoidance features on the */
370 /* local system. of course, this may not be possible... */
371
372 if (loc_rcvavoid) {
373 fprintf(where,
374 "netperf: create_xti_endpoint: Could not enable receive copy avoidance");
375 fflush(where);
376 loc_rcvavoid = 0;
377 }
378
379 if (loc_sndavoid) {
380 fprintf(where,
381 "netperf: create_xti_endpoint: Could not enable send copy avoidance");
382 fflush(where);
383 loc_sndavoid = 0;
384 }
385
386 /* Now, we will see about setting the TCP_NODELAY flag on the local */
387 /* socket. We will only do this for those systems that actually */
388 /* support the option. If it fails, note the fact, but keep going. */
389 /* If the user tries to enable TCP_NODELAY on a UDP socket, this */
390 /* will cause an error to be displayed */
391
392#ifdef TCP_NODELAY
393 if ((strcmp(test_name,"XTI_TCP_STREAM") == 0) ||
394 (strcmp(test_name,"XTI_TCP_RR") == 0) ||
395 (strcmp(test_name,"XTI_TCP_CRR") == 0)) {
396 if (loc_nodelay) {
397 /* we want to "negotiate" the option */
398 opt_req->flags = T_NEGOTIATE;
399 }
400 else {
401 /* we want to accept the default, and know what it is. I assume */
402 /* that when nothing has been changed, that T_CURRENT will return */
403 /* the same as T_DEFAULT raj 3/95 */
404 opt_req->flags = T_CURRENT;
405 }
406
407 /* the first part is for the netbuf that holds the option we want */
408 /* to negotiate or check the buffer of the netbuf points at the */
409 /* socket options structure */
410
411 /* we assume that the t_alloc call allocated a buffer that started */
412 /* on a proper alignment */
413 sock_option = (struct sock_option *)opt_req->opt.buf;
414
415 /* and next, set the fields in the sock_option structure */
416 sock_option->myopthdr.level = INET_TCP;
417 sock_option->myopthdr.name = TCP_NODELAY;
418 sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long);
419 sock_option->value = T_YES;
420
421 opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long);
422
423 /* now, set-up the stuff to return the value in the end */
424 /* we assume that the t_alloc call allocated a buffer that started */
425 /* on a proper alignment */
426 sock_option = (struct sock_option *)opt_ret->opt.buf;
427
428 /* finally, call t_optmgmt. clear as mud. */
429 if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
430 fprintf(where,
431 "create_xti_endpoint: TCP_NODELAY option: errno %d t_errno %d\n",
432 errno,
433 t_errno);
434 fflush(where);
435 exit(1);
436 }
437 loc_nodelay = sock_option->value;
438 }
439#else /* TCP_NODELAY */
440
441 loc_nodelay = 0;
442
443#endif /* TCP_NODELAY */
444
445 return(temp_socket);
446
447}
448
449
450/* This routine implements the TCP unidirectional data transfer test */
451/* (a.k.a. stream) for the xti interface. It receives its */
452/* parameters via global variables from the shell and writes its */
453/* output to the standard output. */
454
455
456void
457send_xti_tcp_stream(char remote_host[])
458{
459
460 char *tput_title = "\
461Recv Send Send \n\
462Socket Socket Message Elapsed \n\
463Size Size Size Time Throughput \n\
464bytes bytes bytes secs. %s/sec \n\n";
465
466 char *tput_fmt_0 =
467 "%7.2f\n";
468
469 char *tput_fmt_1 =
470 "%6d %6d %6d %-6.2f %7.2f \n";
471
472 char *cpu_title = "\
473Recv Send Send Utilization Service Demand\n\
474Socket Socket Message Elapsed Send Recv Send Recv\n\
475Size Size Size Time Throughput local remote local remote\n\
476bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
477
478 char *cpu_fmt_0 =
479 "%6.3f %c\n";
480
481 char *cpu_fmt_1 =
482 "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
483
484 char *ksink_fmt = "\n\
485Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
486Local Remote Local Remote Xfered Per Per\n\
487Send Recv Send Recv Send (avg) Recv (avg)\n\
488%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
489
490 char *ksink_fmt2 = "\n\
491Maximum\n\
492Segment\n\
493Size (bytes)\n\
494%6d\n";
495
496
497 float elapsed_time;
498
499#ifdef WANT_INTERVALS
500 int interval_count;
501 sigset_t signal_set;
502#endif
503
504 /* what we want is to have a buffer space that is at least one */
505 /* send-size greater than our send window. this will insure that we */
506 /* are never trying to re-use a buffer that may still be in the hands */
507 /* of the transport. This buffer will be malloc'd after we have found */
508 /* the size of the local senc socket buffer. We will want to deal */
509 /* with alignment and offset concerns as well. */
510
511 int *message_int_ptr;
512
513 struct ring_elt *send_ring;
514
515 int len;
516 unsigned int nummessages;
517 SOCKET send_socket;
518 int bytes_remaining;
519 int tcp_mss = -1; /* possibly uninitialized on printf far below */
520
521 /* with links like fddi, one can send > 32 bits worth of bytes */
522 /* during a test... ;-) at some point, this should probably become a */
523 /* 64bit integral type, but those are not entirely common yet */
524
525 double bytes_sent;
526
527 float local_cpu_utilization;
528 float local_service_demand;
529 float remote_cpu_utilization;
530 float remote_service_demand;
531
532 double thruput;
533
534 /* some addressing information */
535 struct hostent *hp;
536 struct sockaddr_in server;
537 unsigned int addr;
538
539 struct t_call server_call;
540
541 struct xti_tcp_stream_request_struct *xti_tcp_stream_request;
542 struct xti_tcp_stream_response_struct *xti_tcp_stream_response;
543 struct xti_tcp_stream_results_struct *xti_tcp_stream_result;
544
545 xti_tcp_stream_request =
546 (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data;
547 xti_tcp_stream_response =
548 (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data;
549 xti_tcp_stream_result =
550 (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data;
551
552#ifdef WANT_HISTOGRAM
553 time_hist = HIST_new();
554#endif /* WANT_HISTOGRAM */
555 /* since we are now disconnected from the code that established the */
556 /* control socket, and since we want to be able to use different */
557 /* protocols and such, we are passed the name of the remote host and */
558 /* must turn that into the test specific addressing information. */
559
560 bzero((char *)&server,
561 sizeof(server));
562
563 /* it would seem that while HP-UX will allow an IP address (as a */
564 /* string) in a call to gethostbyname, other, less enlightened */
565 /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
566 /* order changed to check for IP address first. raj 7/96 */
567
568 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
569 /* it was not an IP address, try it as a name */
570 if ((hp = gethostbyname(remote_host)) == NULL) {
571 /* we have no idea what it is */
572 fprintf(where,
573 "establish_control: could not resolve the destination %s\n",
574 remote_host);
575 fflush(where);
576 exit(1);
577 }
578 else {
579 /* it was a valid remote_host */
580 bcopy(hp->h_addr,
581 (char *)&server.sin_addr,
582 hp->h_length);
583 server.sin_family = hp->h_addrtype;
584 }
585 }
586 else {
587 /* it was a valid IP address */
588 server.sin_addr.s_addr = addr;
589 server.sin_family = AF_INET;
590 }
591
592 if ( print_headers ) {
593 /* we want to have some additional, interesting information in */
594 /* the headers. we know some of it here, but not all, so we will */
595 /* only print the test title here and will print the results */
596 /* titles after the test is finished */
597 fprintf(where,"XTI TCP STREAM TEST");
598 fprintf(where," to %s", remote_host);
599 if (iteration_max > 1) {
600 fprintf(where,
601 " : +/-%3.1f%% @ %2d%% conf.",
602 interval/0.02,
603 confidence_level);
604 }
605 if (loc_nodelay || rem_nodelay) {
606 fprintf(where," : nodelay");
607 }
608 if (loc_sndavoid ||
609 loc_rcvavoid ||
610 rem_sndavoid ||
611 rem_rcvavoid) {
612 fprintf(where," : copy avoidance");
613 }
614#ifdef WANT_HISTOGRAM
615 fprintf(where," : histogram");
616#endif /* WANT_HISTOGRAM */
617#ifdef WANT_INTERVALS
618 fprintf(where," : interval");
619#endif /* WANT_INTERVALS */
620#ifdef DIRTY
621 fprintf(where," : dirty data");
622#endif /* DIRTY */
623 fprintf(where,"\n");
624 }
625
626 send_ring = NULL;
627 confidence_iteration = 1;
628 init_stat();
629
630 /* we have a great-big while loop which controls the number of times */
631 /* we run a particular test. this is for the calculation of a */
632 /* confidence interval (I really should have stayed awake during */
633 /* probstats :). If the user did not request confidence measurement */
634 /* (no confidence is the default) then we will only go though the */
635 /* loop once. the confidence stuff originates from the folks at IBM */
636
637 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
638 (confidence_iteration <= iteration_min)) {
639
640 /* initialize a few counters. we have to remember that we might be */
641 /* going through the loop more than once. */
642
643 nummessages = 0;
644 bytes_sent = 0.0;
645 times_up = 0;
646
647 /*set up the data socket */
648 send_socket = create_xti_endpoint(loc_xti_device);
649
650 if (send_socket == INVALID_SOCKET) {
651 perror("netperf: send_xti_tcp_stream: tcp stream data socket");
652 exit(1);
653 }
654
655 if (debug) {
656 fprintf(where,"send_xti_tcp_stream: send_socket obtained...\n");
657 }
658
659 /* it would seem that with XTI, there is no implicit bind on a */
660 /* connect, so we have to make a call to t_bind. this is not */
661 /* terribly convenient, but I suppose that "standard is better */
662 /* than better" :) raj 2/95 */
663
664 if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
665 t_error("send_xti_tcp_stream: t_bind");
666 exit(1);
667 }
668
669 /* at this point, we have either retrieved the socket buffer sizes, */
670 /* or have tried to set them, so now, we may want to set the send */
671 /* size based on that (because the user either did not use a -m */
672 /* option, or used one with an argument of 0). If the socket buffer */
673 /* size is not available, we will set the send size to 4KB - no */
674 /* particular reason, just arbitrary... */
675 if (send_size == 0) {
676 if (lss_size > 0) {
677 send_size = lss_size;
678 }
679 else {
680 send_size = 4096;
681 }
682 }
683
684 /* set-up the data buffer ring with the requested alignment and offset. */
685 /* note also that we have allocated a quantity */
686 /* of memory that is at least one send-size greater than our socket */
687 /* buffer size. We want to be sure that there are at least two */
688 /* buffers allocated - this can be a bit of a problem when the */
689 /* send_size is bigger than the socket size, so we must check... the */
690 /* user may have wanted to explicitly set the "width" of our send */
691 /* buffers, we should respect that wish... */
692
693 if (send_width == 0) {
694 send_width = (lss_size/send_size) + 1;
695 if (send_width == 1) send_width++;
696 }
697
698 if (send_ring == NULL) {
699 /* only allocate the send ring once. this is a networking test, */
700 /* not a memory allocation test. this way, we do not need a */
701 /* deallocate_buffer_ring() routine, and I don't feel like */
702 /* writing one anyway :) raj 11/94 */
703 send_ring = allocate_buffer_ring(send_width,
704 send_size,
705 local_send_align,
706 local_send_offset);
707 }
708
709 /* If the user has requested cpu utilization measurements, we must */
710 /* calibrate the cpu(s). We will perform this task within the tests */
711 /* themselves. If the user has specified the cpu rate, then */
712 /* calibrate_local_cpu will return rather quickly as it will have */
713 /* nothing to do. If local_cpu_rate is zero, then we will go through */
714 /* all the "normal" calibration stuff and return the rate back. */
715
716 if (local_cpu_usage) {
717 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
718 }
719
720 /* Tell the remote end to do a listen. The server alters the socket */
721 /* paramters on the other side at this point, hence the reason for */
722 /* all the values being passed in the setup message. If the user did */
723 /* not specify any of the parameters, they will be passed as 0, which */
724 /* will indicate to the remote that no changes beyond the system's */
725 /* default should be used. Alignment is the exception, it will */
726 /* default to 1, which will be no alignment alterations. */
727
728 netperf_request.content.request_type = DO_XTI_TCP_STREAM;
729 xti_tcp_stream_request->send_buf_size = rss_size;
730 xti_tcp_stream_request->recv_buf_size = rsr_size;
731 xti_tcp_stream_request->receive_size = recv_size;
732 xti_tcp_stream_request->no_delay = rem_nodelay;
733 xti_tcp_stream_request->recv_alignment = remote_recv_align;
734 xti_tcp_stream_request->recv_offset = remote_recv_offset;
735 xti_tcp_stream_request->measure_cpu = remote_cpu_usage;
736 xti_tcp_stream_request->cpu_rate = remote_cpu_rate;
737 if (test_time) {
738 xti_tcp_stream_request->test_length = test_time;
739 }
740 else {
741 xti_tcp_stream_request->test_length = test_bytes;
742 }
743 xti_tcp_stream_request->so_rcvavoid = rem_rcvavoid;
744 xti_tcp_stream_request->so_sndavoid = rem_sndavoid;
745
746 strcpy(xti_tcp_stream_request->xti_device, rem_xti_device);
747
748#ifdef __alpha
749
750 /* ok - even on a DEC box, strings are strings. I didn't really want */
751 /* to ntohl the words of a string. since I don't want to teach the */
752 /* send_ and recv_ _request and _response routines about the types, */
753 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
754 /* solution would be to use XDR, but I am still leary of being able */
755 /* to find XDR libs on all platforms I want running netperf. raj */
756 {
757 int *charword;
758 int *initword;
759 int *lastword;
760
761 initword = (int *) xti_tcp_stream_request->xti_device;
762 lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
763
764 for (charword = initword;
765 charword < lastword;
766 charword++) {
767
768 *charword = ntohl(*charword);
769 }
770 }
771#endif /* __alpha */
772
773#ifdef DIRTY
774 xti_tcp_stream_request->dirty_count = rem_dirty_count;
775 xti_tcp_stream_request->clean_count = rem_clean_count;
776#endif /* DIRTY */
777
778
779 if (debug > 1) {
780 fprintf(where,
781 "netperf: send_xti_tcp_stream: requesting TCP stream test\n");
782 }
783
784 send_request();
785
786 /* The response from the remote will contain all of the relevant */
787 /* socket parameters for this test type. We will put them back into */
788 /* the variables here so they can be displayed if desired. The */
789 /* remote will have calibrated CPU if necessary, and will have done */
790 /* all the needed set-up we will have calibrated the cpu locally */
791 /* before sending the request, and will grab the counter value right*/
792 /* after the connect returns. The remote will grab the counter right*/
793 /* after the accept call. This saves the hassle of extra messages */
794 /* being sent for the TCP tests. */
795
796 recv_response();
797
798 if (!netperf_response.content.serv_errno) {
799 if (debug)
800 fprintf(where,"remote listen done.\n");
801 rsr_size = xti_tcp_stream_response->recv_buf_size;
802 rss_size = xti_tcp_stream_response->send_buf_size;
803 rem_nodelay = xti_tcp_stream_response->no_delay;
804 remote_cpu_usage = xti_tcp_stream_response->measure_cpu;
805 remote_cpu_rate = xti_tcp_stream_response->cpu_rate;
806
807 /* we have to make sure that the server port number is in */
808 /* network order */
809 server.sin_port = (short)xti_tcp_stream_response->data_port_number;
810 server.sin_port = htons(server.sin_port);
811 rem_rcvavoid = xti_tcp_stream_response->so_rcvavoid;
812 rem_sndavoid = xti_tcp_stream_response->so_sndavoid;
813 }
814 else {
815 Set_errno(netperf_response.content.serv_errno);
816 perror("netperf: remote error");
817
818 exit(1);
819 }
820
821 /*Connect up to the remote port on the data socket */
822 memset (&server_call, 0, sizeof(server_call));
823 server_call.addr.maxlen = sizeof(struct sockaddr_in);
824 server_call.addr.len = sizeof(struct sockaddr_in);
825 server_call.addr.buf = (char *)&server;
826
827 if (t_connect(send_socket,
828 &server_call,
829 NULL) == INVALID_SOCKET){
830 t_error("netperf: send_xti_tcp_stream: data socket connect failed");
831 printf(" port: %d\n",ntohs(server.sin_port));
832 exit(1);
833 }
834
835 /* Data Socket set-up is finished. If there were problems, either */
836 /* the connect would have failed, or the previous response would */
837 /* have indicated a problem. I failed to see the value of the */
838 /* extra message after the accept on the remote. If it failed, */
839 /* we'll see it here. If it didn't, we might as well start pumping */
840 /* data. */
841
842 /* Set-up the test end conditions. For a stream test, they can be */
843 /* either time or byte-count based. */
844
845 if (test_time) {
846 /* The user wanted to end the test after a period of time. */
847 times_up = 0;
848 bytes_remaining = 0;
849 /* in previous revisions, we had the same code repeated throught */
850 /* all the test suites. this was unnecessary, and meant more */
851 /* work for me when I wanted to switch to POSIX signals, so I */
852 /* have abstracted this out into a routine in netlib.c. if you */
853 /* are experiencing signal problems, you might want to look */
854 /* there. raj 11/94 */
855 start_timer(test_time);
856 }
857 else {
858 /* The tester wanted to send a number of bytes. */
859 bytes_remaining = test_bytes;
860 times_up = 1;
861 }
862
863 /* The cpu_start routine will grab the current time and possibly */
864 /* value of the idle counter for later use in measuring cpu */
865 /* utilization and/or service demand and thruput. */
866
867 cpu_start(local_cpu_usage);
868
869#ifdef WANT_INTERVALS
870 if ((interval_burst) || (demo_mode)) {
871 /* zero means that we never pause, so we never should need the */
872 /* interval timer, unless we are in demo_mode */
873 start_itimer(interval_wate);
874 }
875 interval_count = interval_burst;
876 /* get the signal set for the call to sigsuspend */
877 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
878 fprintf(where,
879 "send_xti_tcp_stream: unable to get sigmask errno %d\n",
880 errno);
881 fflush(where);
882 exit(1);
883 }
884#endif /* WANT_INTERVALS */
885
886 /* before we start, initialize a few variables */
887
888 /* We use an "OR" to control test execution. When the test is */
889 /* controlled by time, the byte count check will always return false. */
890 /* When the test is controlled by byte count, the time test will */
891 /* always return false. When the test is finished, the whole */
892 /* expression will go false and we will stop sending data. */
893
894 while ((!times_up) || (bytes_remaining > 0)) {
895
896#ifdef DIRTY
897 /* we want to dirty some number of consecutive integers in the buffer */
898 /* we are about to send. we may also want to bring some number of */
899 /* them cleanly into the cache. The clean ones will follow any dirty */
900 /* ones into the cache. at some point, we might want to replace */
901 /* the rand() call with something from a table to reduce our call */
902 /* overhead during the test, but it is not a high priority item. */
903 access_buffer(send_ring->buffer_ptr,
904 send_size,
905 loc_dirty_count,
906 loc_clean_count);
907#endif /* DIRTY */
908
909#ifdef WANT_HISTOGRAM
910 /* timestamp just before we go into send and then again just after */
911 /* we come out raj 8/94 */
912 HIST_timestamp(&time_one);
913#endif /* WANT_HISTOGRAM */
914
915 if((len=t_snd(send_socket,
916 send_ring->buffer_ptr,
917 send_size,
918 0)) != send_size) {
919 if ((len >=0) || (errno == EINTR)) {
920 /* the test was interrupted, must be the end of test */
921 break;
922 }
923 fprintf(where,
924 "send_xti_tcp_stream: t_snd: errno %d t_errno %d t_look 0x%.4x\n",
925 errno,
926 t_errno,
927 t_look(send_socket));
928 fflush(where);
929 exit(1);
930 }
931
932#ifdef WANT_HISTOGRAM
933 /* timestamp the exit from the send call and update the histogram */
934 HIST_timestamp(&time_two);
935 HIST_add(time_hist,delta_micro(&time_one,&time_two));
936#endif /* WANT_HISTOGRAM */
937
938#ifdef WANT_INTERVALS
939 if (demo_mode) {
940 units_this_tick += send_size;
941 }
942 /* in this case, the interval count is the count-down couter */
943 /* to decide to sleep for a little bit */
944 if ((interval_burst) && (--interval_count == 0)) {
945 /* call sigsuspend and wait for the interval timer to get us */
946 /* out */
947 if (debug) {
948 fprintf(where,"about to suspend\n");
949 fflush(where);
950 }
951 if (sigsuspend(&signal_set) == EFAULT) {
952 fprintf(where,
953 "send_xti_tcp_stream: fault with signal set!\n");
954 fflush(where);
955 exit(1);
956 }
957 interval_count = interval_burst;
958 }
959#endif /* WANT_INTERVALS */
960
961 /* now we want to move our pointer to the next position in the */
962 /* data buffer...we may also want to wrap back to the "beginning" */
963 /* of the bufferspace, so we will mod the number of messages sent */
964 /* by the send width, and use that to calculate the offset to add */
965 /* to the base pointer. */
966 nummessages++;
967 send_ring = send_ring->next;
968 if (bytes_remaining) {
969 bytes_remaining -= send_size;
970 }
971 }
972
973 /* The test is over. Flush the buffers to the remote end. We do a */
974 /* graceful release to insure that all data has been taken by the */
975 /* remote. */
976
977 /* but first, if the verbosity is greater than 1, find-out what */
978 /* the TCP maximum segment_size was (if possible) */
979 if (verbosity > 1) {
980 tcp_mss = -1;
981 get_xti_info(send_socket,info_struct);
982 }
983
984 if (t_sndrel(send_socket) == -1) {
985 t_error("netperf: cannot shutdown tcp stream socket");
986 exit(1);
987 }
988
989 /* hang a t_rcvrel() off the socket to block until the remote has */
990 /* brought all the data up into the application. it will do a */
991 /* t_sedrel to cause a FIN to be sent our way. We will assume that */
992 /* any exit from the t_rcvrel() call is good... raj 2/95 */
993
994 if (debug > 1) {
995 fprintf(where,"about to hang a receive for graceful release.\n");
996 fflush(where);
997 }
998
999 t_rcvrel(send_socket);
1000
1001 /* this call will always give us the elapsed time for the test, and */
1002 /* will also store-away the necessaries for cpu utilization */
1003
1004 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
1005 /* measured and how */
1006 /* long did we really */
1007 /* run? */
1008
1009 /* Get the statistics from the remote end. The remote will have */
1010 /* calculated service demand and all those interesting things. If it */
1011 /* wasn't supposed to care, it will return obvious values. */
1012
1013 recv_response();
1014 if (!netperf_response.content.serv_errno) {
1015 if (debug)
1016 fprintf(where,"remote results obtained\n");
1017 }
1018 else {
1019 Set_errno(netperf_response.content.serv_errno);
1020 perror("netperf: remote error");
1021
1022 exit(1);
1023 }
1024
1025 /* We now calculate what our thruput was for the test. In the future, */
1026 /* we may want to include a calculation of the thruput measured by */
1027 /* the remote, but it should be the case that for a TCP stream test, */
1028 /* that the two numbers should be *very* close... We calculate */
1029 /* bytes_sent regardless of the way the test length was controlled. */
1030 /* If it was time, we needed to, and if it was by bytes, the user may */
1031 /* have specified a number of bytes that wasn't a multiple of the */
1032 /* send_size, so we really didn't send what he asked for ;-) */
1033
1034 bytes_sent = xti_tcp_stream_result->bytes_received;
1035
1036 thruput = calc_thruput(bytes_sent);
1037
1038 if (local_cpu_usage || remote_cpu_usage) {
1039 /* We must now do a little math for service demand and cpu */
1040 /* utilization for the system(s) */
1041 /* Of course, some of the information might be bogus because */
1042 /* there was no idle counter in the kernel(s). We need to make */
1043 /* a note of this for the user's benefit...*/
1044 if (local_cpu_usage) {
1045
1046 local_cpu_utilization = calc_cpu_util(0.0);
1047 local_service_demand = calc_service_demand(bytes_sent,
1048 0.0,
1049 0.0,
1050 0);
1051 }
1052 else {
1053 local_cpu_utilization = -1.0;
1054 local_service_demand = -1.0;
1055 }
1056
1057 if (remote_cpu_usage) {
1058
1059 remote_cpu_utilization = xti_tcp_stream_result->cpu_util;
1060 remote_service_demand = calc_service_demand(bytes_sent,
1061 0.0,
1062 remote_cpu_utilization,
1063 xti_tcp_stream_result->num_cpus);
1064 }
1065 else {
1066 remote_cpu_utilization = -1.0;
1067 remote_service_demand = -1.0;
1068 }
1069 }
1070 else {
1071 /* we were not measuring cpu, for the confidence stuff, we */
1072 /* should make it -1.0 */
1073 local_cpu_utilization = -1.0;
1074 local_service_demand = -1.0;
1075 remote_cpu_utilization = -1.0;
1076 remote_service_demand = -1.0;
1077 }
1078
1079 /* at this point, we want to calculate the confidence information. */
1080 /* if debugging is on, calculate_confidence will print-out the */
1081 /* parameters we pass it */
1082
1083 calculate_confidence(confidence_iteration,
1084 elapsed_time,
1085 thruput,
1086 local_cpu_utilization,
1087 remote_cpu_utilization,
1088 local_service_demand,
1089 remote_service_demand);
1090
1091
1092 confidence_iteration++;
1093 }
1094
1095 /* at this point, we have finished making all the runs that we */
1096 /* will be making. so, we should extract what the calcuated values */
1097 /* are for all the confidence stuff. we could make the values */
1098 /* global, but that seemed a little messy, and it did not seem worth */
1099 /* all the mucking with header files. so, we create a routine much */
1100 /* like calcualte_confidence, which just returns the mean values. */
1101 /* raj 11/94 */
1102
1103 retrieve_confident_values(&elapsed_time,
1104 &thruput,
1105 &local_cpu_utilization,
1106 &remote_cpu_utilization,
1107 &local_service_demand,
1108 &remote_service_demand);
1109
1110 /* We are now ready to print all the information. If the user */
1111 /* has specified zero-level verbosity, we will just print the */
1112 /* local service demand, or the remote service demand. If the */
1113 /* user has requested verbosity level 1, he will get the basic */
1114 /* "streamperf" numbers. If the user has specified a verbosity */
1115 /* of greater than 1, we will display a veritable plethora of */
1116 /* background information from outside of this block as it it */
1117 /* not cpu_measurement specific... */
1118
1119 if (confidence < 0) {
1120 /* we did not hit confidence, but were we asked to look for it? */
1121 if (iteration_max > 1) {
1122 display_confidence();
1123 }
1124 }
1125
1126 if (local_cpu_usage || remote_cpu_usage) {
1127 local_cpu_method = format_cpu_method(cpu_method);
1128 remote_cpu_method = format_cpu_method(xti_tcp_stream_result->cpu_method);
1129
1130 switch (verbosity) {
1131 case 0:
1132 if (local_cpu_usage) {
1133 fprintf(where,
1134 cpu_fmt_0,
1135 local_service_demand,
1136 local_cpu_method);
1137 }
1138 else {
1139 fprintf(where,
1140 cpu_fmt_0,
1141 remote_service_demand,
1142 remote_cpu_method);
1143 }
1144 break;
1145 case 1:
1146 case 2:
1147 if (print_headers) {
1148 fprintf(where,
1149 cpu_title,
1150 format_units(),
1151 local_cpu_method,
1152 remote_cpu_method);
1153 }
1154
1155 fprintf(where,
1156 cpu_fmt_1, /* the format string */
1157 rsr_size, /* remote recvbuf size */
1158 lss_size, /* local sendbuf size */
1159 send_size, /* how large were the sends */
1160 elapsed_time, /* how long was the test */
1161 thruput, /* what was the xfer rate */
1162 local_cpu_utilization, /* local cpu */
1163 remote_cpu_utilization, /* remote cpu */
1164 local_service_demand, /* local service demand */
1165 remote_service_demand); /* remote service demand */
1166 break;
1167 }
1168 }
1169 else {
1170 /* The tester did not wish to measure service demand. */
1171
1172 switch (verbosity) {
1173 case 0:
1174 fprintf(where,
1175 tput_fmt_0,
1176 thruput);
1177 break;
1178 case 1:
1179 case 2:
1180 if (print_headers) {
1181 fprintf(where,tput_title,format_units());
1182 }
1183 fprintf(where,
1184 tput_fmt_1, /* the format string */
1185 rsr_size, /* remote recvbuf size */
1186 lss_size, /* local sendbuf size */
1187 send_size, /* how large were the sends */
1188 elapsed_time, /* how long did it take */
1189 thruput);/* how fast did it go */
1190 break;
1191 }
1192 }
1193
1194 /* it would be a good thing to include information about some of the */
1195 /* other parameters that may have been set for this test, but at the */
1196 /* moment, I do not wish to figure-out all the formatting, so I will */
1197 /* just put this comment here to help remind me that it is something */
1198 /* that should be done at a later time. */
1199
1200 if (verbosity > 1) {
1201 /* The user wanted to know it all, so we will give it to him. */
1202 /* This information will include as much as we can find about */
1203 /* TCP statistics, the alignments of the sends and receives */
1204 /* and all that sort of rot... */
1205
1206 /* this stuff needs to be worked-out in the presence of confidence */
1207 /* intervals and multiple iterations of the test... raj 11/94 */
1208
1209 fprintf(where,
1210 ksink_fmt,
1211 "Bytes",
1212 "Bytes",
1213 "Bytes",
1214 local_send_align,
1215 remote_recv_align,
1216 local_send_offset,
1217 remote_recv_offset,
1218 bytes_sent,
1219 bytes_sent / (double)nummessages,
1220 nummessages,
1221 bytes_sent / (double)xti_tcp_stream_result->recv_calls,
1222 xti_tcp_stream_result->recv_calls);
1223 fprintf(where,
1224 ksink_fmt2,
1225 tcp_mss);
1226 fflush(where);
1227#ifdef WANT_HISTOGRAM
1228 fprintf(where,"\n\nHistogram of time spent in send() call.\n");
1229 fflush(where);
1230 HIST_report(time_hist);
1231#endif /* WANT_HISTOGRAM */
1232 }
1233
1234}
1235
1236
1237/* This is the server-side routine for the tcp stream test. It is */
1238/* implemented as one routine. I could break things-out somewhat, but */
1239/* didn't feel it was necessary. */
1240
1241void
1242recv_xti_tcp_stream()
1243{
1244
1245 struct sockaddr_in myaddr_in, peeraddr_in;
1246 struct t_bind bind_req, bind_resp;
1247 struct t_call call_req;
1248
1249 SOCKET s_listen,s_data;
1250 int addrlen;
1251 int len;
1252 unsigned int receive_calls;
1253 float elapsed_time;
1254 double bytes_received;
1255
1256 struct ring_elt *recv_ring;
1257
1258 int *message_int_ptr;
1259 int i;
1260
1261 struct xti_tcp_stream_request_struct *xti_tcp_stream_request;
1262 struct xti_tcp_stream_response_struct *xti_tcp_stream_response;
1263 struct xti_tcp_stream_results_struct *xti_tcp_stream_results;
1264
1265 xti_tcp_stream_request =
1266 (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data;
1267 xti_tcp_stream_response =
1268 (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data;
1269 xti_tcp_stream_results =
1270 (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data;
1271
1272 if (debug) {
1273 fprintf(where,"netserver: recv_xti_tcp_stream: entered...\n");
1274 fflush(where);
1275 }
1276
1277 /* We want to set-up the listen socket with all the desired */
1278 /* parameters and then let the initiator know that all is ready. If */
1279 /* socket size defaults are to be used, then the initiator will have */
1280 /* sent us 0's. If the socket sizes cannot be changed, then we will */
1281 /* send-back what they are. If that information cannot be determined, */
1282 /* then we send-back -1's for the sizes. If things go wrong for any */
1283 /* reason, we will drop back ten yards and punt. */
1284
1285 /* If anything goes wrong, we want the remote to know about it. It */
1286 /* would be best if the error that the remote reports to the user is */
1287 /* the actual error we encountered, rather than some bogus unexpected */
1288 /* response type message. */
1289
1290 if (debug) {
1291 fprintf(where,"recv_xti_tcp_stream: setting the response type...\n");
1292 fflush(where);
1293 }
1294
1295 netperf_response.content.response_type = XTI_TCP_STREAM_RESPONSE;
1296
1297 if (debug) {
1298 fprintf(where,"recv_xti_tcp_stream: the response type is set...\n");
1299 fflush(where);
1300 }
1301
1302 /* We now alter the message_ptr variable to be at the desired */
1303 /* alignment with the desired offset. */
1304
1305 if (debug) {
1306 fprintf(where,"recv_xti_tcp_stream: requested alignment of %d\n",
1307 xti_tcp_stream_request->recv_alignment);
1308 fflush(where);
1309 }
1310
1311 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
1312 /* can put in OUR values !-) At some point, we may want to nail this */
1313 /* socket to a particular network-level address, but for now, */
1314 /* INADDR_ANY should be just fine. */
1315
1316 bzero((char *)&myaddr_in,
1317 sizeof(myaddr_in));
1318 myaddr_in.sin_family = AF_INET;
1319 myaddr_in.sin_addr.s_addr = INADDR_ANY;
1320 myaddr_in.sin_port = 0;
1321
1322 /* Grab a socket to listen on, and then listen on it. */
1323
1324 if (debug) {
1325 fprintf(where,"recv_xti_tcp_stream: grabbing a socket...\n");
1326 fflush(where);
1327 }
1328
1329 /* create_xti_endpoint expects to find some things in the global */
1330 /* variables, so set the globals based on the values in the request. */
1331 /* once the socket has been created, we will set the response values */
1332 /* based on the updated value of those globals. raj 7/94 */
1333 lss_size = xti_tcp_stream_request->send_buf_size;
1334 lsr_size = xti_tcp_stream_request->recv_buf_size;
1335 loc_nodelay = xti_tcp_stream_request->no_delay;
1336 loc_rcvavoid = xti_tcp_stream_request->so_rcvavoid;
1337 loc_sndavoid = xti_tcp_stream_request->so_sndavoid;
1338
1339#ifdef __alpha
1340
1341 /* ok - even on a DEC box, strings are strings. I din't really want */
1342 /* to ntohl the words of a string. since I don't want to teach the */
1343 /* send_ and recv_ _request and _response routines about the types, */
1344 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
1345 /* solution would be to use XDR, but I am still leary of being able */
1346 /* to find XDR libs on all platforms I want running netperf. raj */
1347 {
1348 int *charword;
1349 int *initword;
1350 int *lastword;
1351
1352 initword = (int *) xti_tcp_stream_request->xti_device;
1353 lastword = initword + ((xti_tcp_stream_request->dev_name_len + 3) / 4);
1354
1355 for (charword = initword;
1356 charword < lastword;
1357 charword++) {
1358
1359 *charword = htonl(*charword);
1360 }
1361 }
1362
1363#endif /* __alpha */
1364
1365 s_listen = create_xti_endpoint(xti_tcp_stream_request->xti_device);
1366
1367 if (s_listen == INVALID_SOCKET) {
1368 netperf_response.content.serv_errno = errno;
1369 send_response();
1370 exit(1);
1371 }
1372
1373 /* Let's get an address assigned to this socket so we can tell the */
1374 /* initiator how to reach the data socket. There may be a desire to */
1375 /* nail this socket to a specific IP address in a multi-homed, */
1376 /* multi-connection situation, but for now, we'll ignore the issue */
1377 /* and concentrate on single connection testing. */
1378
1379 bind_req.addr.maxlen = sizeof(struct sockaddr_in);
1380 bind_req.addr.len = sizeof(struct sockaddr_in);
1381 bind_req.addr.buf = (char *)&myaddr_in;
1382 bind_req.qlen = 1;
1383
1384 bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
1385 bind_resp.addr.len = sizeof(struct sockaddr_in);
1386 bind_resp.addr.buf = (char *)&myaddr_in;
1387 bind_resp.qlen = 1;
1388
1389 if (t_bind(s_listen,
1390 &bind_req,
1391 &bind_resp) == SOCKET_ERROR) {
1392 netperf_response.content.serv_errno = t_errno;
1393 close(s_listen);
1394 send_response();
1395
1396 exit(1);
1397 }
1398
1399 if (debug) {
1400 fprintf(where,
1401 "recv_xti_tcp_stream: t_bind complete port %d\n",
1402 ntohs(myaddr_in.sin_port));
1403 fflush(where);
1404 }
1405
1406 /* what sort of sizes did we end-up with? */
1407 if (xti_tcp_stream_request->receive_size == 0) {
1408 if (lsr_size > 0) {
1409 recv_size = lsr_size;
1410 }
1411 else {
1412 recv_size = 4096;
1413 }
1414 }
1415 else {
1416 recv_size = xti_tcp_stream_request->receive_size;
1417 }
1418
1419 /* we want to set-up our recv_ring in a manner analagous to what we */
1420 /* do on the sending side. this is more for the sake of symmetry */
1421 /* than for the needs of say copy avoidance, but it might also be */
1422 /* more realistic - this way one could conceivably go with a */
1423 /* double-buffering scheme when taking the data an putting it into */
1424 /* the filesystem or something like that. raj 7/94 */
1425
1426 if (recv_width == 0) {
1427 recv_width = (lsr_size/recv_size) + 1;
1428 if (recv_width == 1) recv_width++;
1429 }
1430
1431 recv_ring = allocate_buffer_ring(recv_width,
1432 recv_size,
1433 xti_tcp_stream_request->recv_alignment,
1434 xti_tcp_stream_request->recv_offset);
1435
1436 if (debug) {
1437 fprintf(where,"recv_xti_tcp_stream: recv alignment and offset set...\n");
1438 fflush(where);
1439 }
1440
1441 /* Now myaddr_in contains the port and the internet address this is */
1442 /* returned to the sender also implicitly telling the sender that the */
1443 /* socket buffer sizing has been done. */
1444
1445 xti_tcp_stream_response->data_port_number =
1446 (int) ntohs(myaddr_in.sin_port);
1447 netperf_response.content.serv_errno = 0;
1448
1449 /* But wait, there's more. If the initiator wanted cpu measurements, */
1450 /* then we must call the calibrate routine, which will return the max */
1451 /* rate back to the initiator. If the CPU was not to be measured, or */
1452 /* something went wrong with the calibration, we will return a -1 to */
1453 /* the initiator. */
1454
1455 xti_tcp_stream_response->cpu_rate = 0.0; /* assume no cpu */
1456 if (xti_tcp_stream_request->measure_cpu) {
1457 xti_tcp_stream_response->measure_cpu = 1;
1458 xti_tcp_stream_response->cpu_rate =
1459 calibrate_local_cpu(xti_tcp_stream_request->cpu_rate);
1460 }
1461 else {
1462 xti_tcp_stream_response->measure_cpu = 0;
1463 }
1464
1465 /* before we send the response back to the initiator, pull some of */
1466 /* the socket parms from the globals */
1467 xti_tcp_stream_response->send_buf_size = lss_size;
1468 xti_tcp_stream_response->recv_buf_size = lsr_size;
1469 xti_tcp_stream_response->no_delay = loc_nodelay;
1470 xti_tcp_stream_response->so_rcvavoid = loc_rcvavoid;
1471 xti_tcp_stream_response->so_sndavoid = loc_sndavoid;
1472 xti_tcp_stream_response->receive_size = recv_size;
1473
1474 send_response();
1475
1476 /* Now, let's set-up the socket to listen for connections. for xti, */
1477 /* the t_listen call is blocking by default - this is different */
1478 /* semantics from BSD - probably has to do with being able to reject */
1479 /* a call before an accept */
1480 call_req.addr.maxlen = sizeof(struct sockaddr_in);
1481 call_req.addr.len = sizeof(struct sockaddr_in);
1482 call_req.addr.buf = (char *)&peeraddr_in;
1483 call_req.opt.maxlen = 0;
1484 call_req.opt.len = 0;
1485 call_req.opt.buf = NULL;
1486 call_req.udata.maxlen= 0;
1487 call_req.udata.len = 0;
1488 call_req.udata.buf = 0;
1489
1490 if (t_listen(s_listen, &call_req) == -1) {
1491 fprintf(where,
1492 "recv_xti_tcp_stream: t_listen: errno %d t_errno %d\n",
1493 errno,
1494 t_errno);
1495 fflush(where);
1496 netperf_response.content.serv_errno = t_errno;
1497 close(s_listen);
1498 send_response();
1499 exit(1);
1500 }
1501
1502 if (debug) {
1503 fprintf(where,
1504 "recv_xti_tcp_stream: t_listen complete t_look 0x%.4x\n",
1505 t_look(s_listen));
1506 fflush(where);
1507 }
1508
1509 /* now just rubber stamp the thing. we want to use the same fd? so */
1510 /* we will just equate s_data with s_listen. this seems a little */
1511 /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */
1512 s_data = s_listen;
1513 if (t_accept(s_listen,
1514 s_data,
1515 &call_req) == -1) {
1516 fprintf(where,
1517 "recv_xti_tcp_stream: t_accept: errno %d t_errno %d\n",
1518 errno,
1519 t_errno);
1520 fflush(where);
1521 close(s_listen);
1522 exit(1);
1523 }
1524
1525 if (debug) {
1526 fprintf(where,
1527 "recv_xti_tcp_stream: t_accept complete t_look 0x%.4x\n",
1528 t_look(s_data));
1529 fprintf(where,
1530 " remote is %s port %d\n",
1531 inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr),
1532 ntohs(peeraddr_in.sin_port));
1533 fflush(where);
1534 }
1535
1536 /* Now it's time to start receiving data on the connection. We will */
1537 /* first grab the apropriate counters and then start grabbing. */
1538
1539 cpu_start(xti_tcp_stream_request->measure_cpu);
1540
1541 /* The loop will exit when the sender does a t_sndrel, which will */
1542 /* return T_LOOK error from the t_recv */
1543
1544#ifdef DIRTY
1545 /* we want to dirty some number of consecutive integers in the buffer */
1546 /* we are about to recv. we may also want to bring some number of */
1547 /* them cleanly into the cache. The clean ones will follow any dirty */
1548 /* ones into the cache. */
1549
1550 access_buffer(recv_ring->buffer_ptr,
1551 recv_size,
1552 xti_tcp_stream_request->dirty_count,
1553 xti_tcp_stream_request->clean_count);
1554
1555#endif /* DIRTY */
1556
1557 bytes_received = 0;
1558 receive_calls = 0;
1559
1560 while ((len = t_rcv(s_data,
1561 recv_ring->buffer_ptr,
1562 recv_size,
1563 &xti_flags)) != -1) {
1564 bytes_received += len;
1565 receive_calls++;
1566
1567 /* more to the next buffer in the recv_ring */
1568 recv_ring = recv_ring->next;
1569
1570#ifdef DIRTY
1571
1572 access_buffer(recv_ring->buffer_ptr,
1573 recv_size,
1574 xti_tcp_stream_request->dirty_count,
1575 xti_tcp_stream_request->clean_count);
1576
1577#endif /* DIRTY */
1578 }
1579
1580 if (t_look(s_data) == T_ORDREL) {
1581 /* this is a normal exit path */
1582 if (debug) {
1583 fprintf(where,
1584 "recv_xti_tcp_stream: t_rcv T_ORDREL indicated\n");
1585 fflush(where);
1586 }
1587 }
1588 else {
1589 /* something went wrong */
1590 fprintf(where,
1591 "recv_xti_tcp_stream: t_rcv: errno %d t_errno %d len %d",
1592 errno,
1593 t_errno,
1594 len);
1595 fprintf(where,
1596 " t_look 0x%.4x",
1597 t_look(s_data));
1598 fflush(where);
1599 netperf_response.content.serv_errno = t_errno;
1600 send_response();
1601 exit(1);
1602 }
1603
1604 /* receive the release and let the initiator know that we have */
1605 /* received all the data. raj 3/95 */
1606
1607 if (t_rcvrel(s_data) == -1) {
1608 netperf_response.content.serv_errno = errno;
1609 send_response();
1610 exit(1);
1611 }
1612
1613 if (debug) {
1614 fprintf(where,
1615 "recv_xti_tcp_stream: t_rcvrel complete\n");
1616 fflush(where);
1617 }
1618
1619 if (t_sndrel(s_data) == -1) {
1620 netperf_response.content.serv_errno = errno;
1621 send_response();
1622 exit(1);
1623 }
1624
1625 if (debug) {
1626 fprintf(where,
1627 "recv_xti_tcp_stream: t_sndrel complete\n");
1628 fflush(where);
1629 }
1630
1631 cpu_stop(xti_tcp_stream_request->measure_cpu,&elapsed_time);
1632
1633 /* send the results to the sender */
1634
1635 if (debug) {
1636 fprintf(where,
1637 "recv_xti_tcp_stream: got %g bytes\n",
1638 bytes_received);
1639 fprintf(where,
1640 "recv_xti_tcp_stream: got %d recvs\n",
1641 receive_calls);
1642 fflush(where);
1643 }
1644
1645 xti_tcp_stream_results->bytes_received = bytes_received;
1646 xti_tcp_stream_results->elapsed_time = elapsed_time;
1647 xti_tcp_stream_results->recv_calls = receive_calls;
1648
1649 if (xti_tcp_stream_request->measure_cpu) {
1650 xti_tcp_stream_results->cpu_util = calc_cpu_util(0.0);
1651 };
1652
1653 if (debug) {
1654 fprintf(where,
1655 "recv_xti_tcp_stream: test complete, sending results.\n");
1656 fprintf(where,
1657 " bytes_received %g receive_calls %d\n",
1658 bytes_received,
1659 receive_calls);
1660 fprintf(where,
1661 " len %d\n",
1662 len);
1663 fflush(where);
1664 }
1665
1666 xti_tcp_stream_results->cpu_method = cpu_method;
1667 send_response();
1668
1669 /* we are now done with the socket */
1670 t_close(s_data);
1671
1672}
1673
1674
1675 /* this routine implements the sending (netperf) side of the XTI_TCP_RR */
1676 /* test. */
1677
1678void
1679send_xti_tcp_rr(char remote_host[])
1680{
1681
1682 char *tput_title = "\
1683Local /Remote\n\
1684Socket Size Request Resp. Elapsed Trans.\n\
1685Send Recv Size Size Time Rate \n\
1686bytes Bytes bytes bytes secs. per sec \n\n";
1687
1688 char *tput_fmt_0 =
1689 "%7.2f\n";
1690
1691 char *tput_fmt_1_line_1 = "\
1692%-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
1693 char *tput_fmt_1_line_2 = "\
1694%-6d %-6d\n";
1695
1696 char *cpu_title = "\
1697Local /Remote\n\
1698Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
1699Send Recv Size Size Time Rate local remote local remote\n\
1700bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
1701
1702 char *cpu_fmt_0 =
1703 "%6.3f %c\n";
1704
1705 char *cpu_fmt_1_line_1 = "\
1706%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
1707
1708 char *cpu_fmt_1_line_2 = "\
1709%-6d %-6d\n";
1710
1711 char *ksink_fmt = "\
1712Alignment Offset\n\
1713Local Remote Local Remote\n\
1714Send Recv Send Recv\n\
1715%5d %5d %5d %5d\n";
1716
1717
1718 int timed_out = 0;
1719 float elapsed_time;
1720
1721 int len;
1722 char *temp_message_ptr;
1723 int nummessages;
1724 SOCKET send_socket;
1725 int trans_remaining;
1726 double bytes_xferd;
1727
1728 struct ring_elt *send_ring;
1729 struct ring_elt *recv_ring;
1730
1731 int rsp_bytes_left;
1732 int rsp_bytes_recvd;
1733
1734 float local_cpu_utilization;
1735 float local_service_demand;
1736 float remote_cpu_utilization;
1737 float remote_service_demand;
1738 double thruput;
1739
1740 struct hostent *hp;
1741 struct sockaddr_in server;
1742 unsigned int addr;
1743
1744 struct t_call server_call;
1745
1746 struct xti_tcp_rr_request_struct *xti_tcp_rr_request;
1747 struct xti_tcp_rr_response_struct *xti_tcp_rr_response;
1748 struct xti_tcp_rr_results_struct *xti_tcp_rr_result;
1749
1750#ifdef WANT_INTERVALS
1751 int interval_count;
1752 sigset_t signal_set;
1753#endif /* WANT_INTERVALS */
1754
1755 xti_tcp_rr_request =
1756 (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data;
1757 xti_tcp_rr_response=
1758 (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data;
1759 xti_tcp_rr_result =
1760 (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data;
1761
1762#ifdef WANT_HISTOGRAM
1763 time_hist = HIST_new();
1764#endif /* WANT_HISTOGRAM */
1765
1766 /* since we are now disconnected from the code that established the */
1767 /* control socket, and since we want to be able to use different */
1768 /* protocols and such, we are passed the name of the remote host and */
1769 /* must turn that into the test specific addressing information. */
1770
1771 bzero((char *)&server,
1772 sizeof(server));
1773
1774 /* it would seem that while HP-UX will allow an IP address (as a */
1775 /* string) in a call to gethostbyname, other, less enlightened */
1776 /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
1777 /* order changed to check for IP address first. raj 7/96 */
1778
1779 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
1780 /* it was not an IP address, try it as a name */
1781 if ((hp = gethostbyname(remote_host)) == NULL) {
1782 /* we have no idea what it is */
1783 fprintf(where,
1784 "establish_control: could not resolve the destination %s\n",
1785 remote_host);
1786 fflush(where);
1787 exit(1);
1788 }
1789 else {
1790 /* it was a valid remote_host */
1791 bcopy(hp->h_addr,
1792 (char *)&server.sin_addr,
1793 hp->h_length);
1794 server.sin_family = hp->h_addrtype;
1795 }
1796 }
1797 else {
1798 /* it was a valid IP address */
1799 server.sin_addr.s_addr = addr;
1800 server.sin_family = AF_INET;
1801 }
1802
1803 if ( print_headers ) {
1804 fprintf(where,"XTI TCP REQUEST/RESPONSE TEST");
1805 fprintf(where," to %s", remote_host);
1806 if (iteration_max > 1) {
1807 fprintf(where,
1808 " : +/-%3.1f%% @ %2d%% conf.",
1809 interval/0.02,
1810 confidence_level);
1811 }
1812 if (loc_nodelay || rem_nodelay) {
1813 fprintf(where," : nodelay");
1814 }
1815 if (loc_sndavoid ||
1816 loc_rcvavoid ||
1817 rem_sndavoid ||
1818 rem_rcvavoid) {
1819 fprintf(where," : copy avoidance");
1820 }
1821#ifdef WANT_HISTOGRAM
1822 fprintf(where," : histogram");
1823#endif /* WANT_HISTOGRAM */
1824#ifdef WANT_INTERVALS
1825 fprintf(where," : interval");
1826#endif /* WANT_INTERVALS */
1827#ifdef DIRTY
1828 fprintf(where," : dirty data");
1829#endif /* DIRTY */
1830 fprintf(where,"\n");
1831 }
1832
1833 /* initialize a few counters */
1834
1835 send_ring = NULL;
1836 recv_ring = NULL;
1837 confidence_iteration = 1;
1838 init_stat();
1839
1840 /* we have a great-big while loop which controls the number of times */
1841 /* we run a particular test. this is for the calculation of a */
1842 /* confidence interval (I really should have stayed awake during */
1843 /* probstats :). If the user did not request confidence measurement */
1844 /* (no confidence is the default) then we will only go though the */
1845 /* loop once. the confidence stuff originates from the folks at IBM */
1846
1847 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
1848 (confidence_iteration <= iteration_min)) {
1849
1850 /* initialize a few counters. we have to remember that we might be */
1851 /* going through the loop more than once. */
1852
1853 nummessages = 0;
1854 bytes_xferd = 0.0;
1855 times_up = 0;
1856 timed_out = 0;
1857 trans_remaining = 0;
1858
1859 /* set-up the data buffers with the requested alignment and offset. */
1860 /* since this is a request/response test, default the send_width and */
1861 /* recv_width to 1 and not two raj 7/94 */
1862
1863 if (send_width == 0) send_width = 1;
1864 if (recv_width == 0) recv_width = 1;
1865
1866 if (send_ring == NULL) {
1867 send_ring = allocate_buffer_ring(send_width,
1868 req_size,
1869 local_send_align,
1870 local_send_offset);
1871 }
1872
1873 if (recv_ring == NULL) {
1874 recv_ring = allocate_buffer_ring(recv_width,
1875 rsp_size,
1876 local_recv_align,
1877 local_recv_offset);
1878 }
1879
1880 /*set up the data socket */
1881 send_socket = create_xti_endpoint(loc_xti_device);
1882
1883 if (send_socket == INVALID_SOCKET){
1884 perror("netperf: send_xti_tcp_rr: tcp stream data socket");
1885 exit(1);
1886 }
1887
1888 if (debug) {
1889 fprintf(where,"send_xti_tcp_rr: send_socket obtained...\n");
1890 }
1891
1892 /* it would seem that with XTI, there is no implicit bind on a */
1893 /* connect, so we have to make a call to t_bind. this is not */
1894 /* terribly convenient, but I suppose that "standard is better */
1895 /* than better" :) raj 2/95 */
1896
1897 if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
1898 t_error("send_xti_tcp_stream: t_bind");
1899 exit(1);
1900 }
1901
1902 /* If the user has requested cpu utilization measurements, we must */
1903 /* calibrate the cpu(s). We will perform this task within the tests */
1904 /* themselves. If the user has specified the cpu rate, then */
1905 /* calibrate_local_cpu will return rather quickly as it will have */
1906 /* nothing to do. If local_cpu_rate is zero, then we will go through */
1907 /* all the "normal" calibration stuff and return the rate back.*/
1908
1909 if (local_cpu_usage) {
1910 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1911 }
1912
1913 /* Tell the remote end to do a listen. The server alters the socket */
1914 /* paramters on the other side at this point, hence the reason for */
1915 /* all the values being passed in the setup message. If the user did */
1916 /* not specify any of the parameters, they will be passed as 0, which */
1917 /* will indicate to the remote that no changes beyond the system's */
1918 /* default should be used. Alignment is the exception, it will */
1919 /* default to 8, which will be no alignment alterations. */
1920
1921 netperf_request.content.request_type = DO_XTI_TCP_RR;
1922 xti_tcp_rr_request->recv_buf_size = rsr_size;
1923 xti_tcp_rr_request->send_buf_size = rss_size;
1924 xti_tcp_rr_request->recv_alignment = remote_recv_align;
1925 xti_tcp_rr_request->recv_offset = remote_recv_offset;
1926 xti_tcp_rr_request->send_alignment = remote_send_align;
1927 xti_tcp_rr_request->send_offset = remote_send_offset;
1928 xti_tcp_rr_request->request_size = req_size;
1929 xti_tcp_rr_request->response_size = rsp_size;
1930 xti_tcp_rr_request->no_delay = rem_nodelay;
1931 xti_tcp_rr_request->measure_cpu = remote_cpu_usage;
1932 xti_tcp_rr_request->cpu_rate = remote_cpu_rate;
1933 xti_tcp_rr_request->so_rcvavoid = rem_rcvavoid;
1934 xti_tcp_rr_request->so_sndavoid = rem_sndavoid;
1935 if (test_time) {
1936 xti_tcp_rr_request->test_length = test_time;
1937 }
1938 else {
1939 xti_tcp_rr_request->test_length = test_trans * -1;
1940 }
1941
1942 strcpy(xti_tcp_rr_request->xti_device, rem_xti_device);
1943
1944#ifdef __alpha
1945
1946 /* ok - even on a DEC box, strings are strings. I didn't really want */
1947 /* to ntohl the words of a string. since I don't want to teach the */
1948 /* send_ and recv_ _request and _response routines about the types, */
1949 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
1950 /* solution would be to use XDR, but I am still leary of being able */
1951 /* to find XDR libs on all platforms I want running netperf. raj */
1952 {
1953 int *charword;
1954 int *initword;
1955 int *lastword;
1956
1957 initword = (int *) xti_tcp_rr_request->xti_device;
1958 lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
1959
1960 for (charword = initword;
1961 charword < lastword;
1962 charword++) {
1963
1964 *charword = ntohl(*charword);
1965 }
1966 }
1967#endif /* __alpha */
1968
1969 if (debug > 1) {
1970 fprintf(where,"netperf: send_xti_tcp_rr: requesting TCP rr test\n");
1971 }
1972
1973 send_request();
1974
1975 /* The response from the remote will contain all of the relevant */
1976 /* socket parameters for this test type. We will put them back into */
1977 /* the variables here so they can be displayed if desired. The */
1978 /* remote will have calibrated CPU if necessary, and will have done */
1979 /* all the needed set-up we will have calibrated the cpu locally */
1980 /* before sending the request, and will grab the counter value right*/
1981 /* after the connect returns. The remote will grab the counter right*/
1982 /* after the accept call. This saves the hassle of extra messages */
1983 /* being sent for the TCP tests. */
1984
1985 recv_response();
1986
1987 if (!netperf_response.content.serv_errno) {
1988 if (debug)
1989 fprintf(where,"remote listen done.\n");
1990 rsr_size = xti_tcp_rr_response->recv_buf_size;
1991 rss_size = xti_tcp_rr_response->send_buf_size;
1992 rem_nodelay = xti_tcp_rr_response->no_delay;
1993 remote_cpu_usage = xti_tcp_rr_response->measure_cpu;
1994 remote_cpu_rate = xti_tcp_rr_response->cpu_rate;
1995 /* make sure that port numbers are in network order */
1996 server.sin_port = (short)xti_tcp_rr_response->data_port_number;
1997 server.sin_port = htons(server.sin_port);
1998 }
1999 else {
2000 Set_errno(netperf_response.content.serv_errno);
2001 perror("netperf: remote error");
2002
2003 exit(1);
2004 }
2005
2006 /*Connect up to the remote port on the data socket */
2007 memset (&server_call, 0, sizeof(server_call));
2008 server_call.addr.maxlen = sizeof(struct sockaddr_in);
2009 server_call.addr.len = sizeof(struct sockaddr_in);
2010 server_call.addr.buf = (char *)&server;
2011
2012 if (t_connect(send_socket,
2013 &server_call,
2014 NULL) == INVALID_SOCKET){
2015 t_error("netperf: send_xti_tcp_rr: data socket connect failed");
2016 printf(" port: %d\n",ntohs(server.sin_port));
2017 exit(1);
2018 }
2019
2020 /* Data Socket set-up is finished. If there were problems, either the */
2021 /* connect would have failed, or the previous response would have */
2022 /* indicated a problem. I failed to see the value of the extra */
2023 /* message after the accept on the remote. If it failed, we'll see it */
2024 /* here. If it didn't, we might as well start pumping data. */
2025
2026 /* Set-up the test end conditions. For a request/response test, they */
2027 /* can be either time or transaction based. */
2028
2029 if (test_time) {
2030 /* The user wanted to end the test after a period of time. */
2031 times_up = 0;
2032 trans_remaining = 0;
2033 start_timer(test_time);
2034 }
2035 else {
2036 /* The tester wanted to send a number of bytes. */
2037 trans_remaining = test_bytes;
2038 times_up = 1;
2039 }
2040
2041 /* The cpu_start routine will grab the current time and possibly */
2042 /* value of the idle counter for later use in measuring cpu */
2043 /* utilization and/or service demand and thruput. */
2044
2045 cpu_start(local_cpu_usage);
2046
2047#ifdef WANT_INTERVALS
2048 if ((interval_burst) || (demo_mode)) {
2049 /* zero means that we never pause, so we never should need the */
2050 /* interval timer, unless we are in demo_mode */
2051 start_itimer(interval_wate);
2052 }
2053 interval_count = interval_burst;
2054 /* get the signal set for the call to sigsuspend */
2055 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
2056 fprintf(where,
2057 "send_xti_tcp_rr: unable to get sigmask errno %d\n",
2058 errno);
2059 fflush(where);
2060 exit(1);
2061 }
2062#endif /* WANT_INTERVALS */
2063
2064 /* We use an "OR" to control test execution. When the test is */
2065 /* controlled by time, the byte count check will always return false. */
2066 /* When the test is controlled by byte count, the time test will */
2067 /* always return false. When the test is finished, the whole */
2068 /* expression will go false and we will stop sending data. I think I */
2069 /* just arbitrarily decrement trans_remaining for the timed test, but */
2070 /* will not do that just yet... One other question is whether or not */
2071 /* the send buffer and the receive buffer should be the same buffer. */
2072
2073 while ((!times_up) || (trans_remaining > 0)) {
2074 /* send the request. we assume that if we use a blocking socket, */
2075 /* the request will be sent at one shot. */
2076
2077#ifdef WANT_HISTOGRAM
2078 /* timestamp just before our call to send, and then again just */
2079 /* after the receive raj 8/94 */
2080 HIST_timestamp(&time_one);
2081#endif /* WANT_HISTOGRAM */
2082
2083 if((len=t_snd(send_socket,
2084 send_ring->buffer_ptr,
2085 req_size,
2086 0)) != req_size) {
2087 if ((errno == EINTR) || (errno == 0)) {
2088 /* we hit the end of a */
2089 /* timed test. */
2090 timed_out = 1;
2091 break;
2092 }
2093 fprintf(where,
2094 "send_xti_tcp_rr: t_snd: errno %d t_errno %d t_look 0x%.4x\n",
2095 errno,
2096 t_errno,
2097 t_look(send_socket));
2098 fflush(where);
2099 exit(1);
2100 }
2101 send_ring = send_ring->next;
2102
2103 /* receive the response */
2104 rsp_bytes_left = rsp_size;
2105 temp_message_ptr = recv_ring->buffer_ptr;
2106 while(rsp_bytes_left > 0) {
2107 if((rsp_bytes_recvd=t_rcv(send_socket,
2108 temp_message_ptr,
2109 rsp_bytes_left,
2110 &xti_flags)) == SOCKET_ERROR) {
2111 if (errno == EINTR) {
2112 /* We hit the end of a timed test. */
2113 timed_out = 1;
2114 break;
2115 }
2116 fprintf(where,
2117 "send_xti_tcp_rr: t_rcv: errno %d t_errno %d t_look 0x%x\n",
2118 errno,
2119 t_errno,
2120 t_look(send_socket));
2121 fflush(where);
2122 exit(1);
2123 }
2124 rsp_bytes_left -= rsp_bytes_recvd;
2125 temp_message_ptr += rsp_bytes_recvd;
2126 }
2127 recv_ring = recv_ring->next;
2128
2129 if (timed_out) {
2130 /* we may have been in a nested while loop - we need */
2131 /* another call to break. */
2132 break;
2133 }
2134
2135#ifdef WANT_HISTOGRAM
2136 HIST_timestamp(&time_two);
2137 HIST_add(time_hist,delta_micro(&time_one,&time_two));
2138#endif /* WANT_HISTOGRAM */
2139#ifdef WANT_INTERVALS
2140 if (demo_mode) {
2141 units_this_tick += 1;
2142 }
2143 /* in this case, the interval count is the count-down couter */
2144 /* to decide to sleep for a little bit */
2145 if ((interval_burst) && (--interval_count == 0)) {
2146 /* call sigsuspend and wait for the interval timer to get us */
2147 /* out */
2148 if (debug) {
2149 fprintf(where,"about to suspend\n");
2150 fflush(where);
2151 }
2152 if (sigsuspend(&signal_set) == EFAULT) {
2153 fprintf(where,
2154 "send_xti_udp_rr: fault with signal set!\n");
2155 fflush(where);
2156 exit(1);
2157 }
2158 interval_count = interval_burst;
2159 }
2160#endif /* WANT_INTERVALS */
2161
2162 nummessages++;
2163 if (trans_remaining) {
2164 trans_remaining--;
2165 }
2166
2167 if (debug > 3) {
2168 if ((nummessages % 100) == 0) {
2169 fprintf(where,
2170 "Transaction %d completed\n",
2171 nummessages);
2172 fflush(where);
2173 }
2174 }
2175 }
2176
2177
2178 /* this call will always give us the elapsed time for the test, and */
2179 /* will also store-away the necessaries for cpu utilization */
2180
2181 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
2182 /* measured? how long */
2183 /* did we really run? */
2184
2185 /* Get the statistics from the remote end. The remote will have */
2186 /* calculated service demand and all those interesting things. If it */
2187 /* wasn't supposed to care, it will return obvious values. */
2188
2189 recv_response();
2190 if (!netperf_response.content.serv_errno) {
2191 if (debug)
2192 fprintf(where,"remote results obtained\n");
2193 }
2194 else {
2195 Set_errno(netperf_response.content.serv_errno);
2196 perror("netperf: remote error");
2197
2198 exit(1);
2199 }
2200
2201 /* We now calculate what our thruput was for the test. */
2202
2203 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
2204 thruput = nummessages/elapsed_time;
2205
2206 if (local_cpu_usage || remote_cpu_usage) {
2207 /* We must now do a little math for service demand and cpu */
2208 /* utilization for the system(s) */
2209 /* Of course, some of the information might be bogus because */
2210 /* there was no idle counter in the kernel(s). We need to make */
2211 /* a note of this for the user's benefit...*/
2212 if (local_cpu_usage) {
2213 local_cpu_utilization = calc_cpu_util(0.0);
2214 /* since calc_service demand is doing ms/Kunit we will */
2215 /* multiply the number of transaction by 1024 to get */
2216 /* "good" numbers */
2217 local_service_demand = calc_service_demand((double) nummessages*1024,
2218 0.0,
2219 0.0,
2220 0);
2221 }
2222 else {
2223 local_cpu_utilization = -1.0;
2224 local_service_demand = -1.0;
2225 }
2226
2227 if (remote_cpu_usage) {
2228 remote_cpu_utilization = xti_tcp_rr_result->cpu_util;
2229 /* since calc_service demand is doing ms/Kunit we will */
2230 /* multiply the number of transaction by 1024 to get */
2231 /* "good" numbers */
2232 remote_service_demand = calc_service_demand((double) nummessages*1024,
2233 0.0,
2234 remote_cpu_utilization,
2235 xti_tcp_rr_result->num_cpus);
2236 }
2237 else {
2238 remote_cpu_utilization = -1.0;
2239 remote_service_demand = -1.0;
2240 }
2241
2242 }
2243 else {
2244 /* we were not measuring cpu, for the confidence stuff, we */
2245 /* should make it -1.0 */
2246 local_cpu_utilization = -1.0;
2247 local_service_demand = -1.0;
2248 remote_cpu_utilization = -1.0;
2249 remote_service_demand = -1.0;
2250 }
2251
2252 /* at this point, we want to calculate the confidence information. */
2253 /* if debugging is on, calculate_confidence will print-out the */
2254 /* parameters we pass it */
2255
2256 calculate_confidence(confidence_iteration,
2257 elapsed_time,
2258 thruput,
2259 local_cpu_utilization,
2260 remote_cpu_utilization,
2261 local_service_demand,
2262 remote_service_demand);
2263
2264
2265 confidence_iteration++;
2266
2267 /* we are now done with the socket, so close it */
2268 t_close(send_socket);
2269
2270 }
2271
2272 retrieve_confident_values(&elapsed_time,
2273 &thruput,
2274 &local_cpu_utilization,
2275 &remote_cpu_utilization,
2276 &local_service_demand,
2277 &remote_service_demand);
2278
2279 /* We are now ready to print all the information. If the user */
2280 /* has specified zero-level verbosity, we will just print the */
2281 /* local service demand, or the remote service demand. If the */
2282 /* user has requested verbosity level 1, he will get the basic */
2283 /* "streamperf" numbers. If the user has specified a verbosity */
2284 /* of greater than 1, we will display a veritable plethora of */
2285 /* background information from outside of this block as it it */
2286 /* not cpu_measurement specific... */
2287
2288 if (confidence < 0) {
2289 /* we did not hit confidence, but were we asked to look for it? */
2290 if (iteration_max > 1) {
2291 display_confidence();
2292 }
2293 }
2294
2295 if (local_cpu_usage || remote_cpu_usage) {
2296 local_cpu_method = format_cpu_method(cpu_method);
2297 remote_cpu_method = format_cpu_method(xti_tcp_rr_result->cpu_method);
2298
2299 switch (verbosity) {
2300 case 0:
2301 if (local_cpu_usage) {
2302 fprintf(where,
2303 cpu_fmt_0,
2304 local_service_demand,
2305 local_cpu_method);
2306 }
2307 else {
2308 fprintf(where,
2309 cpu_fmt_0,
2310 remote_service_demand,
2311 remote_cpu_method);
2312 }
2313 break;
2314 case 1:
2315 case 2:
2316 if (print_headers) {
2317 fprintf(where,
2318 cpu_title,
2319 local_cpu_method,
2320 remote_cpu_method);
2321 }
2322
2323 fprintf(where,
2324 cpu_fmt_1_line_1, /* the format string */
2325 lss_size, /* local sendbuf size */
2326 lsr_size,
2327 req_size, /* how large were the requests */
2328 rsp_size, /* guess */
2329 elapsed_time, /* how long was the test */
2330 thruput,
2331 local_cpu_utilization, /* local cpu */
2332 remote_cpu_utilization, /* remote cpu */
2333 local_service_demand, /* local service demand */
2334 remote_service_demand); /* remote service demand */
2335 fprintf(where,
2336 cpu_fmt_1_line_2,
2337 rss_size,
2338 rsr_size);
2339 break;
2340 }
2341 }
2342 else {
2343 /* The tester did not wish to measure service demand. */
2344
2345 switch (verbosity) {
2346 case 0:
2347 fprintf(where,
2348 tput_fmt_0,
2349 thruput);
2350 break;
2351 case 1:
2352 case 2:
2353 if (print_headers) {
2354 fprintf(where,tput_title,format_units());
2355 }
2356
2357 fprintf(where,
2358 tput_fmt_1_line_1, /* the format string */
2359 lss_size,
2360 lsr_size,
2361 req_size, /* how large were the requests */
2362 rsp_size, /* how large were the responses */
2363 elapsed_time, /* how long did it take */
2364 thruput);
2365 fprintf(where,
2366 tput_fmt_1_line_2,
2367 rss_size, /* remote recvbuf size */
2368 rsr_size);
2369
2370 break;
2371 }
2372 }
2373
2374 /* it would be a good thing to include information about some of the */
2375 /* other parameters that may have been set for this test, but at the */
2376 /* moment, I do not wish to figure-out all the formatting, so I will */
2377 /* just put this comment here to help remind me that it is something */
2378 /* that should be done at a later time. */
2379
2380 /* how to handle the verbose information in the presence of */
2381 /* confidence intervals is yet to be determined... raj 11/94 */
2382 if (verbosity > 1) {
2383 /* The user wanted to know it all, so we will give it to him. */
2384 /* This information will include as much as we can find about */
2385 /* TCP statistics, the alignments of the sends and receives */
2386 /* and all that sort of rot... */
2387
2388 fprintf(where,
2389 ksink_fmt,
2390 local_send_align,
2391 remote_recv_offset,
2392 local_send_offset,
2393 remote_recv_offset);
2394
2395#ifdef WANT_HISTOGRAM
2396 fprintf(where,"\nHistogram of request/response times\n");
2397 fflush(where);
2398 HIST_report(time_hist);
2399#endif /* WANT_HISTOGRAM */
2400
2401 }
2402
2403}
2404
2405void
2406send_xti_udp_stream(char remote_host[])
2407{
2408 /**********************************************************************/
2409 /* */
2410 /* UDP Unidirectional Send Test */
2411 /* */
2412 /**********************************************************************/
2413 char *tput_title = "\
2414Socket Message Elapsed Messages \n\
2415Size Size Time Okay Errors Throughput\n\
2416bytes bytes secs # # %s/sec\n\n";
2417
2418 char *tput_fmt_0 =
2419 "%7.2f\n";
2420
2421 char *tput_fmt_1 = "\
2422%6d %6d %-7.2f %7d %6d %7.2f\n\
2423%6d %-7.2f %7d %7.2f\n\n";
2424
2425
2426 char *cpu_title = "\
2427Socket Message Elapsed Messages CPU Service\n\
2428Size Size Time Okay Errors Throughput Util Demand\n\
2429bytes bytes secs # # %s/sec %% %c%c us/KB\n\n";
2430
2431 char *cpu_fmt_0 =
2432 "%6.2f %c\n";
2433
2434 char *cpu_fmt_1 = "\
2435%6d %6d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\
2436%6d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n";
2437
2438 unsigned int messages_recvd;
2439 unsigned int messages_sent;
2440 unsigned int failed_sends;
2441
2442 float elapsed_time,
2443 recv_elapsed,
2444 local_cpu_utilization,
2445 remote_cpu_utilization;
2446
2447 float local_service_demand, remote_service_demand;
2448 double local_thruput, remote_thruput;
2449 double bytes_sent;
2450 double bytes_recvd;
2451
2452
2453 int len;
2454 int *message_int_ptr;
2455 struct ring_elt *send_ring;
2456 SOCKET data_socket;
2457
2458 unsigned int sum_messages_sent;
2459 unsigned int sum_messages_recvd;
2460 unsigned int sum_failed_sends;
2461 double sum_local_thruput;
2462
2463#ifdef WANT_INTERVALS
2464 int interval_count;
2465 sigset_t signal_set;
2466#endif /* WANT_INTERVALS */
2467
2468 struct hostent *hp;
2469 struct sockaddr_in server;
2470 unsigned int addr;
2471
2472 struct t_unitdata unitdata;
2473
2474 struct xti_udp_stream_request_struct *xti_udp_stream_request;
2475 struct xti_udp_stream_response_struct *xti_udp_stream_response;
2476 struct xti_udp_stream_results_struct *xti_udp_stream_results;
2477
2478 xti_udp_stream_request =
2479 (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data;
2480 xti_udp_stream_response =
2481 (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data;
2482 xti_udp_stream_results =
2483 (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data;
2484
2485#ifdef WANT_HISTOGRAM
2486 time_hist = HIST_new();
2487#endif /* WANT_HISTOGRAM */
2488
2489 /* since we are now disconnected from the code that established the */
2490 /* control socket, and since we want to be able to use different */
2491 /* protocols and such, we are passed the name of the remote host and */
2492 /* must turn that into the test specific addressing information. */
2493
2494 bzero((char *)&server,
2495 sizeof(server));
2496
2497 /* it would seem that while HP-UX will allow an IP address (as a */
2498 /* string) in a call to gethostbyname, other, less enlightened */
2499 /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
2500 /* order changed to check for IP address first. raj 7/96 */
2501
2502 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
2503 /* it was not an IP address, try it as a name */
2504 if ((hp = gethostbyname(remote_host)) == NULL) {
2505 /* we have no idea what it is */
2506 fprintf(where,
2507 "establish_control: could not resolve the destination %s\n",
2508 remote_host);
2509 fflush(where);
2510 exit(1);
2511 }
2512 else {
2513 /* it was a valid remote_host */
2514 bcopy(hp->h_addr,
2515 (char *)&server.sin_addr,
2516 hp->h_length);
2517 server.sin_family = hp->h_addrtype;
2518 }
2519 }
2520 else {
2521 /* it was a valid IP address */
2522 server.sin_addr.s_addr = addr;
2523 server.sin_family = AF_INET;
2524 }
2525
2526 if ( print_headers ) {
2527 fprintf(where,"UDP UNIDIRECTIONAL SEND TEST");
2528 fprintf(where," to %s", remote_host);
2529 if (iteration_max > 1) {
2530 fprintf(where,
2531 " : +/-%3.1f%% @ %2d%% conf.",
2532 interval/0.02,
2533 confidence_level);
2534 }
2535 if (loc_sndavoid ||
2536 loc_rcvavoid ||
2537 rem_sndavoid ||
2538 rem_rcvavoid) {
2539 fprintf(where," : copy avoidance");
2540 }
2541#ifdef WANT_HISTOGRAM
2542 fprintf(where," : histogram");
2543#endif /* WANT_HISTOGRAM */
2544#ifdef WANT_INTERVALS
2545 fprintf(where," : interval");
2546#endif /* WANT_INTERVALS */
2547#ifdef DIRTY
2548 fprintf(where," : dirty data");
2549#endif /* DIRTY */
2550 fprintf(where,"\n");
2551 }
2552
2553 send_ring = NULL;
2554 confidence_iteration = 1;
2555 init_stat();
2556 sum_messages_sent = 0;
2557 sum_messages_recvd = 0;
2558 sum_failed_sends = 0;
2559 sum_local_thruput = 0.0;
2560
2561 /* we have a great-big while loop which controls the number of times */
2562 /* we run a particular test. this is for the calculation of a */
2563 /* confidence interval (I really should have stayed awake during */
2564 /* probstats :). If the user did not request confidence measurement */
2565 /* (no confidence is the default) then we will only go though the */
2566 /* loop once. the confidence stuff originates from the folks at IBM */
2567
2568 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
2569 (confidence_iteration <= iteration_min)) {
2570
2571 /* initialize a few counters. we have to remember that we might be */
2572 /* going through the loop more than once. */
2573 messages_sent = 0;
2574 messages_recvd = 0;
2575 failed_sends = 0;
2576 times_up = 0;
2577
2578 /*set up the data socket */
2579 data_socket = create_xti_endpoint(loc_xti_device);
2580
2581 if (data_socket == INVALID_SOCKET) {
2582 perror("send_xti_udp_stream: create_xti_endpoint");
2583 exit(1);
2584 }
2585
2586 if (t_bind(data_socket, NULL, NULL) == SOCKET_ERROR) {
2587 t_error("send_xti_udp_stream: t_bind");
2588 exit(1);
2589 }
2590
2591 /* now, we want to see if we need to set the send_size */
2592 if (send_size == 0) {
2593 if (lss_size > 0) {
2594 send_size = lss_size;
2595 }
2596 else {
2597 send_size = 4096;
2598 }
2599 }
2600
2601 /* set-up the data buffer with the requested alignment and offset, */
2602 /* most of the numbers here are just a hack to pick something nice */
2603 /* and big in an attempt to never try to send a buffer a second time */
2604 /* before it leaves the node...unless the user set the width */
2605 /* explicitly. */
2606 if (send_width == 0) send_width = 32;
2607
2608 if (send_ring == NULL ) {
2609 send_ring = allocate_buffer_ring(send_width,
2610 send_size,
2611 local_send_align,
2612 local_send_offset);
2613 }
2614
2615
2616 /* if the user supplied a cpu rate, this call will complete rather */
2617 /* quickly, otherwise, the cpu rate will be retured to us for */
2618 /* possible display. The Library will keep it's own copy of this data */
2619 /* for use elsewhere. We will only display it. (Does that make it */
2620 /* "opaque" to us?) */
2621
2622 if (local_cpu_usage)
2623 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
2624
2625 /* Tell the remote end to set up the data connection. The server */
2626 /* sends back the port number and alters the socket parameters there. */
2627 /* Of course this is a datagram service so no connection is actually */
2628 /* set up, the server just sets up the socket and binds it. */
2629
2630 netperf_request.content.request_type = DO_XTI_UDP_STREAM;
2631 xti_udp_stream_request->recv_buf_size = rsr_size;
2632 xti_udp_stream_request->message_size = send_size;
2633 xti_udp_stream_request->recv_alignment = remote_recv_align;
2634 xti_udp_stream_request->recv_offset = remote_recv_offset;
2635 xti_udp_stream_request->measure_cpu = remote_cpu_usage;
2636 xti_udp_stream_request->cpu_rate = remote_cpu_rate;
2637 xti_udp_stream_request->test_length = test_time;
2638 xti_udp_stream_request->so_rcvavoid = rem_rcvavoid;
2639 xti_udp_stream_request->so_sndavoid = rem_sndavoid;
2640
2641 strcpy(xti_udp_stream_request->xti_device, rem_xti_device);
2642
2643#ifdef __alpha
2644
2645 /* ok - even on a DEC box, strings are strings. I didn't really want */
2646 /* to ntohl the words of a string. since I don't want to teach the */
2647 /* send_ and recv_ _request and _response routines about the types, */
2648 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
2649 /* solution would be to use XDR, but I am still leary of being able */
2650 /* to find XDR libs on all platforms I want running netperf. raj */
2651 {
2652 int *charword;
2653 int *initword;
2654 int *lastword;
2655
2656 initword = (int *) xti_udp_stream_request->xti_device;
2657 lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
2658
2659 for (charword = initword;
2660 charword < lastword;
2661 charword++) {
2662
2663 *charword = ntohl(*charword);
2664 }
2665 }
2666#endif /* __alpha */
2667
2668 send_request();
2669
2670 recv_response();
2671
2672 if (!netperf_response.content.serv_errno) {
2673 if (debug)
2674 fprintf(where,"send_xti_udp_stream: remote data connection done.\n");
2675 }
2676 else {
2677 Set_errno(netperf_response.content.serv_errno);
2678 perror("send_xti_udp_stream: error on remote");
2679 exit(1);
2680 }
2681
2682 /* Place the port number returned by the remote into the sockaddr */
2683 /* structure so our sends can be sent to the correct place. Also get */
2684 /* some of the returned socket buffer information for user display. */
2685
2686 /* make sure that port numbers are in the proper order */
2687 server.sin_port = (short)xti_udp_stream_response->data_port_number;
2688 server.sin_port = htons(server.sin_port);
2689 rsr_size = xti_udp_stream_response->recv_buf_size;
2690 rss_size = xti_udp_stream_response->send_buf_size;
2691 remote_cpu_rate = xti_udp_stream_response->cpu_rate;
2692
2693 /* it would seem that XTI does not allow the expedient of */
2694 /* "connecting" a UDP end-point the way BSD does. so, we will do */
2695 /* everything with t_sndudata and t_rcvudata. Our "virtual" */
2696 /* connect here will be to assign the destination portion of the */
2697 /* t_unitdata struct here, where we would have otherwise called */
2698 /* t_connect() raj 3/95 */
2699
2700 memset (&unitdata, 0, sizeof(unitdata));
2701 unitdata.addr.maxlen = sizeof(struct sockaddr_in);
2702 unitdata.addr.len = sizeof(struct sockaddr_in);
2703 unitdata.addr.buf = (char *)&server;
2704
2705 /* we don't use any options, so might as well set that part here */
2706 /* too */
2707
2708 unitdata.opt.maxlen = 0;
2709 unitdata.opt.len = 0;
2710 unitdata.opt.buf = NULL;
2711
2712 /* we need to initialize the send buffer for the first time as */
2713 /* well since we move to the next pointer after the send call. */
2714
2715 unitdata.udata.maxlen = send_size;
2716 unitdata.udata.len = send_size;
2717 unitdata.udata.buf = send_ring->buffer_ptr;
2718
2719 /* set up the timer to call us after test_time. one of these days, */
2720 /* it might be nice to figure-out a nice reliable way to have the */
2721 /* test controlled by a byte count as well, but since UDP is not */
2722 /* reliable, that could prove difficult. so, in the meantime, we */
2723 /* only allow a XTI_UDP_STREAM test to be a timed test. */
2724
2725 if (test_time) {
2726 times_up = 0;
2727 start_timer(test_time);
2728 }
2729 else {
2730 fprintf(where,"Sorry, XTI_UDP_STREAM tests must be timed.\n");
2731 fflush(where);
2732 exit(1);
2733 }
2734
2735 /* Get the start count for the idle counter and the start time */
2736
2737 cpu_start(local_cpu_usage);
2738
2739#ifdef WANT_INTERVALS
2740 if ((interval_burst) || (demo_mode)) {
2741 /* zero means that we never pause, so we never should need the */
2742 /* interval timer, unless we are in demo_mode */
2743 start_itimer(interval_wate);
2744 }
2745 interval_count = interval_burst;
2746 /* get the signal set for the call to sigsuspend */
2747 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
2748 fprintf(where,
2749 "send_xti_udp_stream: unable to get sigmask errno %d\n",
2750 errno);
2751 fflush(where);
2752 exit(1);
2753 }
2754#endif /* WANT_INTERVALS */
2755
2756 /* Send datagrams like there was no tomorrow. at somepoint it might */
2757 /* be nice to set this up so that a quantity of bytes could be sent, */
2758 /* but we still need some sort of end of test trigger on the receive */
2759 /* side. that could be a select with a one second timeout, but then */
2760 /* if there is a test where none of the data arrives for awile and */
2761 /* then starts again, we would end the test too soon. something to */
2762 /* think about... */
2763 while (!times_up) {
2764
2765#ifdef DIRTY
2766 /* we want to dirty some number of consecutive integers in the buffer */
2767 /* we are about to send. we may also want to bring some number of */
2768 /* them cleanly into the cache. The clean ones will follow any dirty */
2769 /* ones into the cache. */
2770
2771 access_buffer(send_ring->buffer_ptr,
2772 send_size,
2773 loc_dirty_count,
2774 loc_clean_count);
2775
2776#endif /* DIRTY */
2777
2778#ifdef WANT_HISTOGRAM
2779 HIST_timestamp(&time_one);
2780#endif /* WANT_HISTOGRAM */
2781
2782 if ((t_sndudata(data_socket,
2783 &unitdata)) != 0) {
2784 if (errno == EINTR)
2785 break;
2786 if (errno == ENOBUFS) {
2787 failed_sends++;
2788 continue;
2789 }
2790 perror("xti_udp_send: data send error");
2791 t_error("xti_udp_send: data send error");
2792 exit(1);
2793 }
2794 messages_sent++;
2795
2796 /* now we want to move our pointer to the next position in the */
2797 /* data buffer...and update the unitdata structure */
2798
2799 send_ring = send_ring->next;
2800 unitdata.udata.buf = send_ring->buffer_ptr;
2801
2802#ifdef WANT_HISTOGRAM
2803 /* get the second timestamp */
2804 HIST_timestamp(&time_two);
2805 HIST_add(time_hist,delta_micro(&time_one,&time_two));
2806#endif /* WANT_HISTOGRAM */
2807#ifdef WANT_INTERVALS
2808 if (demo_mode) {
2809 units_this_tick += send_size;
2810 }
2811 /* in this case, the interval count is the count-down couter */
2812 /* to decide to sleep for a little bit */
2813 if ((interval_burst) && (--interval_count == 0)) {
2814 /* call sigsuspend and wait for the interval timer to get us */
2815 /* out */
2816 if (debug) {
2817 fprintf(where,"about to suspend\n");
2818 fflush(where);
2819 }
2820 if (sigsuspend(&signal_set) == EFAULT) {
2821 fprintf(where,
2822 "send_xti_udp_stream: fault with signal set!\n");
2823 fflush(where);
2824 exit(1);
2825 }
2826 interval_count = interval_burst;
2827 }
2828#endif /* WANT_INTERVALS */
2829
2830 }
2831
2832 /* This is a timed test, so the remote will be returning to us after */
2833 /* a time. We should not need to send any "strange" messages to tell */
2834 /* the remote that the test is completed, unless we decide to add a */
2835 /* number of messages to the test. */
2836
2837 /* the test is over, so get stats and stuff */
2838 cpu_stop(local_cpu_usage,
2839 &elapsed_time);
2840
2841 /* Get the statistics from the remote end */
2842 recv_response();
2843 if (!netperf_response.content.serv_errno) {
2844 if (debug)
2845 fprintf(where,"send_xti_udp_stream: remote results obtained\n");
2846 }
2847 else {
2848 Set_errno(netperf_response.content.serv_errno);
2849 perror("send_xti_udp_stream: error on remote");
2850 exit(1);
2851 }
2852
2853 bytes_sent = (double) send_size * (double) messages_sent;
2854 local_thruput = calc_thruput(bytes_sent);
2855
2856 messages_recvd = xti_udp_stream_results->messages_recvd;
2857 bytes_recvd = (double) send_size * (double) messages_recvd;
2858
2859 /* we asume that the remote ran for as long as we did */
2860
2861 remote_thruput = calc_thruput(bytes_recvd);
2862
2863 /* print the results for this socket and message size */
2864
2865 if (local_cpu_usage || remote_cpu_usage) {
2866 /* We must now do a little math for service demand and cpu */
2867 /* utilization for the system(s) We pass zeros for the local */
2868 /* cpu utilization and elapsed time to tell the routine to use */
2869 /* the libraries own values for those. */
2870 if (local_cpu_usage) {
2871 local_cpu_utilization = calc_cpu_util(0.0);
2872 /* shouldn't this really be based on bytes_recvd, since that is */
2873 /* the effective throughput of the test? I think that it should, */
2874 /* so will make the change raj 11/94 */
2875 local_service_demand = calc_service_demand(bytes_recvd,
2876 0.0,
2877 0.0,
2878 0);
2879 }
2880 else {
2881 local_cpu_utilization = -1.0;
2882 local_service_demand = -1.0;
2883 }
2884
2885 /* The local calculations could use variables being kept by */
2886 /* the local netlib routines. The remote calcuations need to */
2887 /* have a few things passed to them. */
2888 if (remote_cpu_usage) {
2889 remote_cpu_utilization = xti_udp_stream_results->cpu_util;
2890 remote_service_demand = calc_service_demand(bytes_recvd,
2891 0.0,
2892 remote_cpu_utilization,
2893 xti_udp_stream_results->num_cpus);
2894 }
2895 else {
2896 remote_cpu_utilization = -1.0;
2897 remote_service_demand = -1.0;
2898 }
2899 }
2900 else {
2901 /* we were not measuring cpu, for the confidence stuff, we */
2902 /* should make it -1.0 */
2903 local_cpu_utilization = -1.0;
2904 local_service_demand = -1.0;
2905 remote_cpu_utilization = -1.0;
2906 remote_service_demand = -1.0;
2907 }
2908
2909 /* at this point, we want to calculate the confidence information. */
2910 /* if debugging is on, calculate_confidence will print-out the */
2911 /* parameters we pass it */
2912
2913 calculate_confidence(confidence_iteration,
2914 elapsed_time,
2915 remote_thruput,
2916 local_cpu_utilization,
2917 remote_cpu_utilization,
2918 local_service_demand,
2919 remote_service_demand);
2920
2921 /* since the routine calculate_confidence is rather generic, and */
2922 /* we have a few other parms of interest, we will do a little work */
2923 /* here to caclulate their average. */
2924 sum_messages_sent += messages_sent;
2925 sum_messages_recvd += messages_recvd;
2926 sum_failed_sends += failed_sends;
2927 sum_local_thruput += local_thruput;
2928
2929 confidence_iteration++;
2930
2931 /* this datapoint is done, so we don't need the socket any longer */
2932 close(data_socket);
2933
2934 }
2935
2936 /* we should reach this point once the test is finished */
2937
2938 retrieve_confident_values(&elapsed_time,
2939 &remote_thruput,
2940 &local_cpu_utilization,
2941 &remote_cpu_utilization,
2942 &local_service_demand,
2943 &remote_service_demand);
2944
2945 /* some of the interesting values aren't covered by the generic */
2946 /* confidence routine */
2947 messages_sent = sum_messages_sent / (confidence_iteration -1);
2948 messages_recvd = sum_messages_recvd / (confidence_iteration -1);
2949 failed_sends = sum_failed_sends / (confidence_iteration -1);
2950 local_thruput = sum_local_thruput / (confidence_iteration -1);
2951
2952 /* We are now ready to print all the information. If the user */
2953 /* has specified zero-level verbosity, we will just print the */
2954 /* local service demand, or the remote service demand. If the */
2955 /* user has requested verbosity level 1, he will get the basic */
2956 /* "streamperf" numbers. If the user has specified a verbosity */
2957 /* of greater than 1, we will display a veritable plethora of */
2958 /* background information from outside of this block as it it */
2959 /* not cpu_measurement specific... */
2960
2961
2962 if (confidence < 0) {
2963 /* we did not hit confidence, but were we asked to look for it? */
2964 if (iteration_max > 1) {
2965 display_confidence();
2966 }
2967 }
2968
2969 if (local_cpu_usage || remote_cpu_usage) {
2970 local_cpu_method = format_cpu_method(cpu_method);
2971 remote_cpu_method = format_cpu_method(xti_udp_stream_results->cpu_method);
2972
2973 switch (verbosity) {
2974 case 0:
2975 if (local_cpu_usage) {
2976 fprintf(where,
2977 cpu_fmt_0,
2978 local_service_demand,
2979 local_cpu_method);
2980 }
2981 else {
2982 fprintf(where,
2983 cpu_fmt_0,
2984 remote_service_demand,
2985 local_cpu_method);
2986 }
2987 break;
2988 case 1:
2989 case 2:
2990 if (print_headers) {
2991 fprintf(where,
2992 cpu_title,
2993 format_units(),
2994 local_cpu_method,
2995 remote_cpu_method);
2996 }
2997
2998 fprintf(where,
2999 cpu_fmt_1, /* the format string */
3000 lss_size, /* local sendbuf size */
3001 send_size, /* how large were the sends */
3002 elapsed_time, /* how long was the test */
3003 messages_sent,
3004 failed_sends,
3005 local_thruput, /* what was the xfer rate */
3006 local_cpu_utilization, /* local cpu */
3007 local_service_demand, /* local service demand */
3008 rsr_size,
3009 elapsed_time,
3010 messages_recvd,
3011 remote_thruput,
3012 remote_cpu_utilization, /* remote cpu */
3013 remote_service_demand); /* remote service demand */
3014 break;
3015 }
3016 }
3017 else {
3018 /* The tester did not wish to measure service demand. */
3019 switch (verbosity) {
3020 case 0:
3021 fprintf(where,
3022 tput_fmt_0,
3023 local_thruput);
3024 break;
3025 case 1:
3026 case 2:
3027 if (print_headers) {
3028 fprintf(where,tput_title,format_units());
3029 }
3030 fprintf(where,
3031 tput_fmt_1, /* the format string */
3032 lss_size, /* local sendbuf size */
3033 send_size, /* how large were the sends */
3034 elapsed_time, /* how long did it take */
3035 messages_sent,
3036 failed_sends,
3037 local_thruput,
3038 rsr_size, /* remote recvbuf size */
3039 elapsed_time,
3040 messages_recvd,
3041 remote_thruput);
3042 break;
3043 }
3044 }
3045
3046 fflush(where);
3047#ifdef WANT_HISTOGRAM
3048 if (verbosity > 1) {
3049 fprintf(where,"\nHistogram of time spent in send() call\n");
3050 fflush(where);
3051 HIST_report(time_hist);
3052 }
3053#endif /* WANT_HISTOGRAM */
3054
3055}
3056
3057
3058 /* this routine implements the receive side (netserver) of the */
3059 /* XTI_UDP_STREAM performance test. */
3060
3061void
3062recv_xti_udp_stream()
3063{
3064 struct ring_elt *recv_ring;
3065
3066 struct t_bind bind_req, bind_resp;
3067 struct t_unitdata unitdata;
3068 int flags = 0;
3069
3070 struct sockaddr_in myaddr_in;
3071 struct sockaddr_in fromaddr_in;
3072
3073 SOCKET s_data;
3074 int addrlen;
3075 unsigned int bytes_received = 0;
3076 float elapsed_time;
3077
3078 unsigned int message_size;
3079 unsigned int messages_recvd = 0;
3080
3081 struct xti_udp_stream_request_struct *xti_udp_stream_request;
3082 struct xti_udp_stream_response_struct *xti_udp_stream_response;
3083 struct xti_udp_stream_results_struct *xti_udp_stream_results;
3084
3085 xti_udp_stream_request =
3086 (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data;
3087 xti_udp_stream_response =
3088 (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data;
3089 xti_udp_stream_results =
3090 (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data;
3091
3092 if (debug) {
3093 fprintf(where,"netserver: recv_xti_udp_stream: entered...\n");
3094 fflush(where);
3095 }
3096
3097 /* We want to set-up the listen socket with all the desired */
3098 /* parameters and then let the initiator know that all is ready. If */
3099 /* socket size defaults are to be used, then the initiator will have */
3100 /* sent us 0's. If the socket sizes cannot be changed, then we will */
3101 /* send-back what they are. If that information cannot be determined, */
3102 /* then we send-back -1's for the sizes. If things go wrong for any */
3103 /* reason, we will drop back ten yards and punt. */
3104
3105 /* If anything goes wrong, we want the remote to know about it. It */
3106 /* would be best if the error that the remote reports to the user is */
3107 /* the actual error we encountered, rather than some bogus unexpected */
3108 /* response type message. */
3109
3110 if (debug > 1) {
3111 fprintf(where,"recv_xti_udp_stream: setting the response type...\n");
3112 fflush(where);
3113 }
3114
3115 netperf_response.content.response_type = XTI_UDP_STREAM_RESPONSE;
3116
3117 if (debug > 2) {
3118 fprintf(where,"recv_xti_udp_stream: the response type is set...\n");
3119 fflush(where);
3120 }
3121
3122 /* We now alter the message_ptr variable to be at the desired */
3123 /* alignment with the desired offset. */
3124
3125 if (debug > 1) {
3126 fprintf(where,"recv_xti_udp_stream: requested alignment of %d\n",
3127 xti_udp_stream_request->recv_alignment);
3128 fflush(where);
3129 }
3130
3131 if (recv_width == 0) recv_width = 1;
3132
3133 recv_ring = allocate_buffer_ring(recv_width,
3134 xti_udp_stream_request->message_size,
3135 xti_udp_stream_request->recv_alignment,
3136 xti_udp_stream_request->recv_offset);
3137
3138 if (debug > 1) {
3139 fprintf(where,"recv_xti_udp_stream: receive alignment and offset set...\n");
3140 fflush(where);
3141 }
3142
3143 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
3144 /* can put in OUR values !-) At some point, we may want to nail this */
3145 /* socket to a particular network-level address, but for now, */
3146 /* INADDR_ANY should be just fine. */
3147
3148 bzero((char *)&myaddr_in,
3149 sizeof(myaddr_in));
3150 myaddr_in.sin_family = AF_INET;
3151 myaddr_in.sin_addr.s_addr = INADDR_ANY;
3152 myaddr_in.sin_port = 0;
3153
3154 /* Grab a socket to listen on, and then listen on it. */
3155
3156 if (debug > 1) {
3157 fprintf(where,"recv_xti_udp_stream: grabbing a socket...\n");
3158 fflush(where);
3159 }
3160
3161 /* create_xti_endpoint expects to find some things in the global */
3162 /* variables, so set the globals based on the values in the request. */
3163 /* once the socket has been created, we will set the response values */
3164 /* based on the updated value of those globals. raj 7/94 */
3165 lsr_size = xti_udp_stream_request->recv_buf_size;
3166 loc_rcvavoid = xti_udp_stream_request->so_rcvavoid;
3167 loc_sndavoid = xti_udp_stream_request->so_sndavoid;
3168
3169#ifdef __alpha
3170
3171 /* ok - even on a DEC box, strings are strings. I din't really want */
3172 /* to ntohl the words of a string. since I don't want to teach the */
3173 /* send_ and recv_ _request and _response routines about the types, */
3174 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
3175 /* solution would be to use XDR, but I am still leary of being able */
3176 /* to find XDR libs on all platforms I want running netperf. raj */
3177 {
3178 int *charword;
3179 int *initword;
3180 int *lastword;
3181
3182 initword = (int *) xti_udp_stream_request->xti_device;
3183 lastword = initword + ((xti_udp_stream_request->dev_name_len + 3) / 4);
3184
3185 for (charword = initword;
3186 charword < lastword;
3187 charword++) {
3188
3189 *charword = htonl(*charword);
3190 }
3191 }
3192
3193#endif /* __alpha */
3194
3195 s_data = create_xti_endpoint(xti_udp_stream_request->xti_device);
3196
3197 if (s_data == INVALID_SOCKET) {
3198 netperf_response.content.serv_errno = errno;
3199 send_response();
3200 exit(1);
3201 }
3202
3203 /* Let's get an address assigned to this socket so we can tell the */
3204 /* initiator how to reach the data socket. There may be a desire to */
3205 /* nail this socket to a specific IP address in a multi-homed, */
3206 /* multi-connection situation, but for now, we'll ignore the issue */
3207 /* and concentrate on single connection testing. */
3208
3209 bind_req.addr.maxlen = sizeof(struct sockaddr_in);
3210 bind_req.addr.len = sizeof(struct sockaddr_in);
3211 bind_req.addr.buf = (char *)&myaddr_in;
3212 bind_req.qlen = 1;
3213
3214 bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
3215 bind_resp.addr.len = sizeof(struct sockaddr_in);
3216 bind_resp.addr.buf = (char *)&myaddr_in;
3217 bind_resp.qlen = 1;
3218
3219 if (t_bind(s_data,
3220 &bind_req,
3221 &bind_resp) == SOCKET_ERROR) {
3222 netperf_response.content.serv_errno = t_errno;
3223 send_response();
3224
3225 exit(1);
3226 }
3227
3228 xti_udp_stream_response->test_length =
3229 xti_udp_stream_request->test_length;
3230
3231 /* Now myaddr_in contains the port and the internet address this is */
3232 /* returned to the sender also implicitly telling the sender that the */
3233 /* socket buffer sizing has been done. */
3234
3235 xti_udp_stream_response->data_port_number =
3236 (int) ntohs(myaddr_in.sin_port);
3237 netperf_response.content.serv_errno = 0;
3238
3239 /* But wait, there's more. If the initiator wanted cpu measurements, */
3240 /* then we must call the calibrate routine, which will return the max */
3241 /* rate back to the initiator. If the CPU was not to be measured, or */
3242 /* something went wrong with the calibration, we will return a -1 to */
3243 /* the initiator. */
3244
3245 xti_udp_stream_response->cpu_rate = 0.0; /* assume no cpu */
3246 xti_udp_stream_response->measure_cpu = 0;
3247 if (xti_udp_stream_request->measure_cpu) {
3248 /* We will pass the rate into the calibration routine. If the */
3249 /* user did not specify one, it will be 0.0, and we will do a */
3250 /* "real" calibration. Otherwise, all it will really do is */
3251 /* store it away... */
3252 xti_udp_stream_response->measure_cpu = 1;
3253 xti_udp_stream_response->cpu_rate =
3254 calibrate_local_cpu(xti_udp_stream_request->cpu_rate);
3255 }
3256
3257 message_size = xti_udp_stream_request->message_size;
3258 test_time = xti_udp_stream_request->test_length;
3259
3260 /* before we send the response back to the initiator, pull some of */
3261 /* the socket parms from the globals */
3262 xti_udp_stream_response->send_buf_size = lss_size;
3263 xti_udp_stream_response->recv_buf_size = lsr_size;
3264 xti_udp_stream_response->so_rcvavoid = loc_rcvavoid;
3265 xti_udp_stream_response->so_sndavoid = loc_sndavoid;
3266
3267 /* since we are going to call t_rcvudata() instead of t_rcv() we */
3268 /* need to init the unitdata structure raj 3/95 */
3269
3270 unitdata.addr.maxlen = sizeof(fromaddr_in);
3271 unitdata.addr.len = sizeof(fromaddr_in);
3272 unitdata.addr.buf = (char *)&fromaddr_in;
3273
3274 unitdata.opt.maxlen = 0;
3275 unitdata.opt.len = 0;
3276 unitdata.opt.buf = NULL;
3277
3278 unitdata.udata.maxlen = xti_udp_stream_request->message_size;
3279 unitdata.udata.len = xti_udp_stream_request->message_size;
3280 unitdata.udata.buf = recv_ring->buffer_ptr;
3281
3282 send_response();
3283
3284 /* Now it's time to start receiving data on the connection. We will */
3285 /* first grab the apropriate counters and then start grabbing. */
3286
3287 cpu_start(xti_udp_stream_request->measure_cpu);
3288
3289 /* The loop will exit when the timer pops, or if we happen to recv a */
3290 /* message of less than send_size bytes... */
3291
3292 times_up = 0;
3293 start_timer(test_time + PAD_TIME);
3294
3295 if (debug) {
3296 fprintf(where,"recv_xti_udp_stream: about to enter inner sanctum.\n");
3297 fflush(where);
3298 }
3299
3300 while (!times_up) {
3301#ifdef RAJ_DEBUG
3302 if (debug) {
3303 fprintf(where,"t_rcvudata, errno %d, t_errno %d",
3304 errno,
3305 t_errno);
3306 fprintf(where," after %d messages\n",messages_recvd);
3307 fprintf(where,"addrmax %d addrlen %d addrbuf %x\n",
3308 unitdata.addr.maxlen,
3309 unitdata.addr.len,
3310 unitdata.addr.buf);
3311 fprintf(where,"optmax %d optlen %d optbuf %x\n",
3312 unitdata.opt.maxlen,
3313 unitdata.opt.len,
3314 unitdata.opt.buf);
3315 fprintf(where,"udatamax %d udatalen %d udatabuf %x\n",
3316 unitdata.udata.maxlen,
3317 unitdata.udata.len,
3318 unitdata.udata.buf);
3319 fflush(where);
3320 }
3321#endif /* RAJ_DEBUG */
3322 if (t_rcvudata(s_data,
3323 &unitdata,
3324 &flags) != 0) {
3325 if (errno == TNODATA) {
3326 continue;
3327 }
3328 if (errno != EINTR) {
3329 netperf_response.content.serv_errno = t_errno;
3330 send_response();
3331 exit(1);
3332 }
3333 break;
3334 }
3335 messages_recvd++;
3336 recv_ring = recv_ring->next;
3337 unitdata.udata.buf = recv_ring->buffer_ptr;
3338 }
3339
3340 if (debug) {
3341 fprintf(where,"recv_xti_udp_stream: got %d messages.\n",messages_recvd);
3342 fflush(where);
3343 }
3344
3345
3346 /* The loop now exits due timer or < send_size bytes received. */
3347
3348 cpu_stop(xti_udp_stream_request->measure_cpu,&elapsed_time);
3349
3350 if (times_up) {
3351 /* we ended on a timer, subtract the PAD_TIME */
3352 elapsed_time -= (float)PAD_TIME;
3353 }
3354 else {
3355 stop_timer();
3356 }
3357
3358 if (debug) {
3359 fprintf(where,"recv_xti_udp_stream: test ended in %f seconds.\n",elapsed_time);
3360 fflush(where);
3361 }
3362
3363 bytes_received = (messages_recvd * message_size);
3364
3365 /* send the results to the sender */
3366
3367 if (debug) {
3368 fprintf(where,
3369 "recv_xti_udp_stream: got %d bytes\n",
3370 bytes_received);
3371 fflush(where);
3372 }
3373
3374 netperf_response.content.response_type = XTI_UDP_STREAM_RESULTS;
3375 xti_udp_stream_results->bytes_received = bytes_received;
3376 xti_udp_stream_results->messages_recvd = messages_recvd;
3377 xti_udp_stream_results->elapsed_time = elapsed_time;
3378 xti_udp_stream_results->cpu_method = cpu_method;
3379 if (xti_udp_stream_request->measure_cpu) {
3380 xti_udp_stream_results->cpu_util = calc_cpu_util(elapsed_time);
3381 }
3382 else {
3383 xti_udp_stream_results->cpu_util = -1.0;
3384 }
3385
3386 if (debug > 1) {
3387 fprintf(where,
3388 "recv_xti_udp_stream: test complete, sending results.\n");
3389 fflush(where);
3390 }
3391
3392 send_response();
3393
3394}
3395
3396void send_xti_udp_rr(char remote_host[])
3397{
3398
3399 char *tput_title = "\
3400Local /Remote\n\
3401Socket Size Request Resp. Elapsed Trans.\n\
3402Send Recv Size Size Time Rate \n\
3403bytes Bytes bytes bytes secs. per sec \n\n";
3404
3405 char *tput_fmt_0 =
3406 "%7.2f\n";
3407
3408 char *tput_fmt_1_line_1 = "\
3409%-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
3410 char *tput_fmt_1_line_2 = "\
3411%-6d %-6d\n";
3412
3413 char *cpu_title = "\
3414Local /Remote\n\
3415Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
3416Send Recv Size Size Time Rate local remote local remote\n\
3417bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
3418
3419 char *cpu_fmt_0 =
3420 "%6.3f %c\n";
3421
3422 char *cpu_fmt_1_line_1 = "\
3423%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
3424
3425 char *cpu_fmt_1_line_2 = "\
3426%-6d %-6d\n";
3427
3428 char *ksink_fmt = "\
3429Alignment Offset\n\
3430Local Remote Local Remote\n\
3431Send Recv Send Recv\n\
3432%5d %5d %5d %5d\n";
3433
3434
3435 float elapsed_time;
3436
3437 struct ring_elt *send_ring;
3438 struct ring_elt *recv_ring;
3439
3440 struct t_bind bind_req, bind_resp;
3441 struct t_unitdata unitdata;
3442 struct t_unitdata send_unitdata;
3443 struct t_unitdata recv_unitdata;
3444 int flags = 0;
3445
3446 int len;
3447 int nummessages;
3448 SOCKET send_socket;
3449 int trans_remaining;
3450 int bytes_xferd;
3451
3452 int rsp_bytes_recvd;
3453
3454 float local_cpu_utilization;
3455 float local_service_demand;
3456 float remote_cpu_utilization;
3457 float remote_service_demand;
3458 double thruput;
3459
3460 struct hostent *hp;
3461 struct sockaddr_in server, myaddr_in;
3462 unsigned int addr;
3463 int addrlen;
3464
3465 struct xti_udp_rr_request_struct *xti_udp_rr_request;
3466 struct xti_udp_rr_response_struct *xti_udp_rr_response;
3467 struct xti_udp_rr_results_struct *xti_udp_rr_result;
3468
3469#ifdef WANT_INTERVALS
3470 int interval_count;
3471 sigset_t signal_set;
3472#endif /* WANT_INTERVALS */
3473
3474 xti_udp_rr_request =
3475 (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data;
3476 xti_udp_rr_response =
3477 (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data;
3478 xti_udp_rr_result =
3479 (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data;
3480
3481#ifdef WANT_HISTOGRAM
3482 time_hist = HIST_new();
3483#endif
3484
3485 /* since we are now disconnected from the code that established the */
3486 /* control socket, and since we want to be able to use different */
3487 /* protocols and such, we are passed the name of the remote host and */
3488 /* must turn that into the test specific addressing information. */
3489
3490 bzero((char *)&server,
3491 sizeof(server));
3492
3493 /* it would seem that while HP-UX will allow an IP address (as a */
3494 /* string) in a call to gethostbyname, other, less enlightened */
3495 /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
3496 /* order changed to check for IP address first. raj 7/96 */
3497
3498 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
3499 /* it was not an IP address, try it as a name */
3500 if ((hp = gethostbyname(remote_host)) == NULL) {
3501 /* we have no idea what it is */
3502 fprintf(where,
3503 "establish_control: could not resolve the destination %s\n",
3504 remote_host);
3505 fflush(where);
3506 exit(1);
3507 }
3508 else {
3509 /* it was a valid remote_host */
3510 bcopy(hp->h_addr,
3511 (char *)&server.sin_addr,
3512 hp->h_length);
3513 server.sin_family = hp->h_addrtype;
3514 }
3515 }
3516 else {
3517 /* it was a valid IP address */
3518 server.sin_addr.s_addr = addr;
3519 server.sin_family = AF_INET;
3520 }
3521
3522 if ( print_headers ) {
3523 fprintf(where,"XTI UDP REQUEST/RESPONSE TEST");
3524 fprintf(where," to %s", remote_host);
3525 if (iteration_max > 1) {
3526 fprintf(where,
3527 " : +/-%3.1f%% @ %2d%% conf.",
3528 interval/0.02,
3529 confidence_level);
3530 }
3531 if (loc_sndavoid ||
3532 loc_rcvavoid ||
3533 rem_sndavoid ||
3534 rem_rcvavoid) {
3535 fprintf(where," : copy avoidance");
3536 }
3537#ifdef WANT_HISTOGRAM
3538 fprintf(where," : histogram");
3539#endif /* WANT_HISTOGRAM */
3540#ifdef WANT_INTERVALS
3541 fprintf(where," : interval");
3542#endif /* WANT_INTERVALS */
3543#ifdef DIRTY
3544 fprintf(where," : dirty data");
3545#endif /* DIRTY */
3546 fprintf(where,"\n");
3547 }
3548
3549 /* initialize a few counters */
3550
3551 send_ring = NULL;
3552 recv_ring = NULL;
3553 nummessages = 0;
3554 bytes_xferd = 0;
3555 times_up = 0;
3556 confidence_iteration = 1;
3557 init_stat();
3558
3559
3560 /* we have a great-big while loop which controls the number of times */
3561 /* we run a particular test. this is for the calculation of a */
3562 /* confidence interval (I really should have stayed awake during */
3563 /* probstats :). If the user did not request confidence measurement */
3564 /* (no confidence is the default) then we will only go though the */
3565 /* loop once. the confidence stuff originates from the folks at IBM */
3566
3567 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
3568 (confidence_iteration <= iteration_min)) {
3569
3570 nummessages = 0;
3571 bytes_xferd = 0.0;
3572 times_up = 0;
3573 trans_remaining = 0;
3574
3575 /* set-up the data buffers with the requested alignment and offset */
3576
3577 if (send_width == 0) send_width = 1;
3578 if (recv_width == 0) recv_width = 1;
3579
3580 if (send_ring == NULL) {
3581 send_ring = allocate_buffer_ring(send_width,
3582 req_size,
3583 local_send_align,
3584 local_send_offset);
3585 }
3586
3587 if (recv_ring == NULL) {
3588 recv_ring = allocate_buffer_ring(recv_width,
3589 rsp_size,
3590 local_recv_align,
3591 local_recv_offset);
3592 }
3593
3594 /* since we are going to call t_rcvudata() instead of t_rcv() we */
3595 /* need to init the unitdata structure raj 8/95 */
3596
3597 memset (&recv_unitdata, 0, sizeof(recv_unitdata));
3598 recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
3599 recv_unitdata.addr.len = sizeof(struct sockaddr_in);
3600 recv_unitdata.addr.buf = (char *)&server;
3601
3602 recv_unitdata.opt.maxlen = 0;
3603 recv_unitdata.opt.len = 0;
3604 recv_unitdata.opt.buf = NULL;
3605
3606 recv_unitdata.udata.maxlen = rsp_size;
3607 recv_unitdata.udata.len = rsp_size;
3608 recv_unitdata.udata.buf = recv_ring->buffer_ptr;
3609
3610 /* since we are going to call t_sndudata() instead of t_snd() we */
3611 /* need to init the unitdata structure raj 8/95 */
3612
3613 memset (&send_unitdata, 0, sizeof(send_unitdata));
3614 send_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
3615 send_unitdata.addr.len = sizeof(struct sockaddr_in);
3616 send_unitdata.addr.buf = (char *)&server;
3617
3618 send_unitdata.opt.maxlen = 0;
3619 send_unitdata.opt.len = 0;
3620 send_unitdata.opt.buf = NULL;
3621
3622 send_unitdata.udata.maxlen = req_size;
3623 send_unitdata.udata.len = req_size;
3624 send_unitdata.udata.buf = send_ring->buffer_ptr;
3625
3626 /*set up the data socket */
3627 send_socket = create_xti_endpoint(loc_xti_device);
3628
3629 if (send_socket == INVALID_SOCKET){
3630 perror("netperf: send_xti_udp_rr: udp rr data socket");
3631 exit(1);
3632 }
3633
3634 if (debug) {
3635 fprintf(where,"send_xti_udp_rr: send_socket obtained...\n");
3636 }
3637
3638 /* it would seem that with XTI, there is no implicit bind */
3639 /* so we have to make a call to t_bind. this is not */
3640 /* terribly convenient, but I suppose that "standard is better */
3641 /* than better" :) raj 2/95 */
3642
3643 if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
3644 t_error("send_xti_tcp_stream: t_bind");
3645 exit(1);
3646 }
3647
3648 /* If the user has requested cpu utilization measurements, we must */
3649 /* calibrate the cpu(s). We will perform this task within the tests */
3650 /* themselves. If the user has specified the cpu rate, then */
3651 /* calibrate_local_cpu will return rather quickly as it will have */
3652 /* nothing to do. If local_cpu_rate is zero, then we will go through */
3653 /* all the "normal" calibration stuff and return the rate back. If */
3654 /* there is no idle counter in the kernel idle loop, the */
3655 /* local_cpu_rate will be set to -1. */
3656
3657 if (local_cpu_usage) {
3658 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
3659 }
3660
3661 /* Tell the remote end to do a listen. The server alters the socket */
3662 /* paramters on the other side at this point, hence the reason for */
3663 /* all the values being passed in the setup message. If the user did */
3664 /* not specify any of the parameters, they will be passed as 0, which */
3665 /* will indicate to the remote that no changes beyond the system's */
3666 /* default should be used. Alignment is the exception, it will */
3667 /* default to 8, which will be no alignment alterations. */
3668
3669 netperf_request.content.request_type = DO_XTI_UDP_RR;
3670 xti_udp_rr_request->recv_buf_size = rsr_size;
3671 xti_udp_rr_request->send_buf_size = rss_size;
3672 xti_udp_rr_request->recv_alignment = remote_recv_align;
3673 xti_udp_rr_request->recv_offset = remote_recv_offset;
3674 xti_udp_rr_request->send_alignment = remote_send_align;
3675 xti_udp_rr_request->send_offset = remote_send_offset;
3676 xti_udp_rr_request->request_size = req_size;
3677 xti_udp_rr_request->response_size = rsp_size;
3678 xti_udp_rr_request->measure_cpu = remote_cpu_usage;
3679 xti_udp_rr_request->cpu_rate = remote_cpu_rate;
3680 xti_udp_rr_request->so_rcvavoid = rem_rcvavoid;
3681 xti_udp_rr_request->so_sndavoid = rem_sndavoid;
3682 if (test_time) {
3683 xti_udp_rr_request->test_length = test_time;
3684 }
3685 else {
3686 xti_udp_rr_request->test_length = test_trans * -1;
3687 }
3688
3689 strcpy(xti_udp_rr_request->xti_device, rem_xti_device);
3690
3691#ifdef __alpha
3692
3693 /* ok - even on a DEC box, strings are strings. I didn't really want */
3694 /* to ntohl the words of a string. since I don't want to teach the */
3695 /* send_ and recv_ _request and _response routines about the types, */
3696 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
3697 /* solution would be to use XDR, but I am still leary of being able */
3698 /* to find XDR libs on all platforms I want running netperf. raj */
3699 {
3700 int *charword;
3701 int *initword;
3702 int *lastword;
3703
3704 initword = (int *) xti_udp_rr_request->xti_device;
3705 lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
3706
3707 for (charword = initword;
3708 charword < lastword;
3709 charword++) {
3710
3711 *charword = ntohl(*charword);
3712 }
3713 }
3714#endif /* __alpha */
3715
3716 if (debug > 1) {
3717 fprintf(where,"netperf: send_xti_udp_rr: requesting UDP r/r test\n");
3718 }
3719
3720 send_request();
3721
3722 /* The response from the remote will contain all of the relevant */
3723 /* socket parameters for this test type. We will put them back into */
3724 /* the variables here so they can be displayed if desired. The */
3725 /* remote will have calibrated CPU if necessary, and will have done */
3726 /* all the needed set-up we will have calibrated the cpu locally */
3727 /* before sending the request, and will grab the counter value right*/
3728 /* after the connect returns. The remote will grab the counter right*/
3729 /* after the accept call. This saves the hassle of extra messages */
3730 /* being sent for the UDP tests. */
3731
3732 recv_response();
3733
3734 if (!netperf_response.content.serv_errno) {
3735 if (debug)
3736 fprintf(where,"remote listen done.\n");
3737 rsr_size = xti_udp_rr_response->recv_buf_size;
3738 rss_size = xti_udp_rr_response->send_buf_size;
3739 remote_cpu_usage = xti_udp_rr_response->measure_cpu;
3740 remote_cpu_rate = xti_udp_rr_response->cpu_rate;
3741 /* port numbers in proper order */
3742 server.sin_port = (short)xti_udp_rr_response->data_port_number;
3743 server.sin_port = htons(server.sin_port);
3744 }
3745 else {
3746 Set_errno(netperf_response.content.serv_errno);
3747 perror("netperf: remote error");
3748
3749 exit(1);
3750 }
3751
3752 /* Data Socket set-up is finished. If there were problems, either the */
3753 /* connect would have failed, or the previous response would have */
3754 /* indicated a problem. I failed to see the value of the extra */
3755 /* message after the accept on the remote. If it failed, we'll see it */
3756 /* here. If it didn't, we might as well start pumping data. */
3757
3758 /* Set-up the test end conditions. For a request/response test, they */
3759 /* can be either time or transaction based. */
3760
3761 if (test_time) {
3762 /* The user wanted to end the test after a period of time. */
3763 times_up = 0;
3764 trans_remaining = 0;
3765 start_timer(test_time);
3766 }
3767 else {
3768 /* The tester wanted to send a number of bytes. */
3769 trans_remaining = test_bytes;
3770 times_up = 1;
3771 }
3772
3773 /* The cpu_start routine will grab the current time and possibly */
3774 /* value of the idle counter for later use in measuring cpu */
3775 /* utilization and/or service demand and thruput. */
3776
3777 cpu_start(local_cpu_usage);
3778
3779#ifdef WANT_INTERVALS
3780 if ((interval_burst) || (demo_mode)) {
3781 /* zero means that we never pause, so we never should need the */
3782 /* interval timer, unless we are in demo_mode */
3783 start_itimer(interval_wate);
3784 }
3785 interval_count = interval_burst;
3786 /* get the signal set for the call to sigsuspend */
3787 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
3788 fprintf(where,
3789 "send_xti_udp_rr: unable to get sigmask errno %d\n",
3790 errno);
3791 fflush(where);
3792 exit(1);
3793 }
3794#endif /* WANT_INTERVALS */
3795
3796 /* We use an "OR" to control test execution. When the test is */
3797 /* controlled by time, the byte count check will always return */
3798 /* false. When the test is controlled by byte count, the time test */
3799 /* will always return false. When the test is finished, the whole */
3800 /* expression will go false and we will stop sending data. I think */
3801 /* I just arbitrarily decrement trans_remaining for the timed */
3802 /* test, but will not do that just yet... One other question is */
3803 /* whether or not the send buffer and the receive buffer should be */
3804 /* the same buffer. */
3805
3806 while ((!times_up) || (trans_remaining > 0)) {
3807 /* send the request */
3808#ifdef WANT_HISTOGRAM
3809 HIST_timestamp(&time_one);
3810#endif
3811 if((t_sndudata(send_socket,
3812 &send_unitdata)) != 0) {
3813 if (errno == EINTR) {
3814 /* We likely hit */
3815 /* test-end time. */
3816 break;
3817 }
3818 fprintf(where,
3819 "send_xti_udp_rr: t_sndudata: errno %d t_errno %d t_look 0x%.4x\n",
3820 errno,
3821 t_errno,
3822 t_look(send_socket));
3823 fflush(where);
3824 exit(1);
3825 }
3826 send_ring = send_ring->next;
3827
3828 /* receive the response. with UDP we will get it all, or nothing */
3829
3830 if((t_rcvudata(send_socket,
3831 &recv_unitdata,
3832 &flags)) != 0) {
3833 if (errno == TNODATA) {
3834 continue;
3835 }
3836 if (errno == EINTR) {
3837 /* Again, we have likely hit test-end time */
3838 break;
3839 }
3840 fprintf(where,
3841 "send_xti_udp_rr: t_rcvudata: errno %d t_errno %d t_look 0x%x\n",
3842 errno,
3843 t_errno,
3844 t_look(send_socket));
3845 fprintf(where,
3846 "recv_unitdata.udata.buf %x\n",recv_unitdata.udata.buf);
3847 fprintf(where,
3848 "recv_unitdata.udata.maxlen %x\n",recv_unitdata.udata.maxlen);
3849 fprintf(where,
3850 "recv_unitdata.udata.len %x\n",recv_unitdata.udata.len);
3851 fprintf(where,
3852 "recv_unitdata.addr.buf %x\n",recv_unitdata.addr.buf);
3853 fprintf(where,
3854 "recv_unitdata.addr.maxlen %x\n",recv_unitdata.addr.maxlen);
3855 fprintf(where,
3856 "recv_unitdata.addr.len %x\n",recv_unitdata.addr.len);
3857 fflush(where);
3858 exit(1);
3859 }
3860 recv_ring = recv_ring->next;
3861
3862#ifdef WANT_HISTOGRAM
3863 HIST_timestamp(&time_two);
3864 HIST_add(time_hist,delta_micro(&time_one,&time_two));
3865
3866 /* at this point, we may wish to sleep for some period of */
3867 /* time, so we see how long that last transaction just took, */
3868 /* and sleep for the difference of that and the interval. We */
3869 /* will not sleep if the time would be less than a */
3870 /* millisecond. */
3871#endif
3872#ifdef WANT_INTERVALS
3873 if (demo_mode) {
3874 units_this_tick += 1;
3875 }
3876 /* in this case, the interval count is the count-down couter */
3877 /* to decide to sleep for a little bit */
3878 if ((interval_burst) && (--interval_count == 0)) {
3879 /* call sigsuspend and wait for the interval timer to get us */
3880 /* out */
3881 if (debug) {
3882 fprintf(where,"about to suspend\n");
3883 fflush(where);
3884 }
3885 if (sigsuspend(&signal_set) == EFAULT) {
3886 fprintf(where,
3887 "send_xti_udp_rr: fault with signal set!\n");
3888 fflush(where);
3889 exit(1);
3890 }
3891 interval_count = interval_burst;
3892 }
3893#endif /* WANT_INTERVALS */
3894
3895 nummessages++;
3896 if (trans_remaining) {
3897 trans_remaining--;
3898 }
3899
3900 if (debug > 3) {
3901 if ((nummessages % 100) == 0) {
3902 fprintf(where,"Transaction %d completed\n",nummessages);
3903 fflush(where);
3904 }
3905 }
3906
3907 }
3908
3909 /* this call will always give us the elapsed time for the test, and */
3910 /* will also store-away the necessaries for cpu utilization */
3911
3912 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
3913 /* measured? how long */
3914 /* did we really run? */
3915
3916 /* Get the statistics from the remote end. The remote will have */
3917 /* calculated service demand and all those interesting things. If */
3918 /* it wasn't supposed to care, it will return obvious values. */
3919
3920 recv_response();
3921 if (!netperf_response.content.serv_errno) {
3922 if (debug)
3923 fprintf(where,"remote results obtained\n");
3924 }
3925 else {
3926 Set_errno(netperf_response.content.serv_errno);
3927 perror("netperf: remote error");
3928
3929 exit(1);
3930 }
3931
3932 /* We now calculate what our thruput was for the test. In the */
3933 /* future, we may want to include a calculation of the thruput */
3934 /* measured by the remote, but it should be the case that for a */
3935 /* UDP rr test, that the two numbers should be *very* close... */
3936 /* We calculate bytes_sent regardless of the way the test length */
3937 /* was controlled. */
3938
3939 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
3940 thruput = nummessages / elapsed_time;
3941
3942 if (local_cpu_usage || remote_cpu_usage) {
3943
3944 /* We must now do a little math for service demand and cpu */
3945 /* utilization for the system(s) Of course, some of the */
3946 /* information might be bogus because there was no idle counter */
3947 /* in the kernel(s). We need to make a note of this for the */
3948 /* user's benefit by placing a code for the metod used in the */
3949 /* test banner */
3950
3951 if (local_cpu_usage) {
3952 local_cpu_utilization = calc_cpu_util(0.0);
3953
3954 /* since calc_service demand is doing ms/Kunit we will */
3955 /* multiply the number of transaction by 1024 to get */
3956 /* "good" numbers */
3957
3958 local_service_demand = calc_service_demand((double) nummessages*1024,
3959 0.0,
3960 0.0,
3961 0);
3962 }
3963 else {
3964 local_cpu_utilization = -1.0;
3965 local_service_demand = -1.0;
3966 }
3967
3968 if (remote_cpu_usage) {
3969 remote_cpu_utilization = xti_udp_rr_result->cpu_util;
3970
3971 /* since calc_service demand is doing ms/Kunit we will */
3972 /* multiply the number of transaction by 1024 to get */
3973 /* "good" numbers */
3974
3975 remote_service_demand = calc_service_demand((double) nummessages*1024,
3976 0.0,
3977 remote_cpu_utilization,
3978 xti_udp_rr_result->num_cpus);
3979 }
3980 else {
3981 remote_cpu_utilization = -1.0;
3982 remote_service_demand = -1.0;
3983 }
3984 }
3985 else {
3986 /* we were not measuring cpu, for the confidence stuff, we */
3987 /* should make it -1.0 */
3988 local_cpu_utilization = -1.0;
3989 local_service_demand = -1.0;
3990 remote_cpu_utilization = -1.0;
3991 remote_service_demand = -1.0;
3992 }
3993
3994 /* at this point, we want to calculate the confidence information. */
3995 /* if debugging is on, calculate_confidence will print-out the */
3996 /* parameters we pass it */
3997
3998 calculate_confidence(confidence_iteration,
3999 elapsed_time,
4000 thruput,
4001 local_cpu_utilization,
4002 remote_cpu_utilization,
4003 local_service_demand,
4004 remote_service_demand);
4005
4006
4007 confidence_iteration++;
4008
4009 /* we are done with the socket */
4010 t_close(send_socket);
4011 }
4012
4013 /* at this point, we have made all the iterations we are going to */
4014 /* make. */
4015 retrieve_confident_values(&elapsed_time,
4016 &thruput,
4017 &local_cpu_utilization,
4018 &remote_cpu_utilization,
4019 &local_service_demand,
4020 &remote_service_demand);
4021
4022 /* We are now ready to print all the information. If the user */
4023 /* has specified zero-level verbosity, we will just print the */
4024 /* local service demand, or the remote service demand. If the */
4025 /* user has requested verbosity level 1, he will get the basic */
4026 /* "streamperf" numbers. If the user has specified a verbosity */
4027 /* of greater than 1, we will display a veritable plethora of */
4028 /* background information from outside of this block as it it */
4029 /* not cpu_measurement specific... */
4030
4031 if (confidence < 0) {
4032 /* we did not hit confidence, but were we asked to look for it? */
4033 if (iteration_max > 1) {
4034 display_confidence();
4035 }
4036 }
4037
4038 if (local_cpu_usage || remote_cpu_usage) {
4039 local_cpu_method = format_cpu_method(cpu_method);
4040 remote_cpu_method = format_cpu_method(xti_udp_rr_result->cpu_method);
4041
4042 switch (verbosity) {
4043 case 0:
4044 if (local_cpu_usage) {
4045 fprintf(where,
4046 cpu_fmt_0,
4047 local_service_demand,
4048 local_cpu_method);
4049 }
4050 else {
4051 fprintf(where,
4052 cpu_fmt_0,
4053 remote_service_demand,
4054 remote_cpu_method);
4055 }
4056 break;
4057 case 1:
4058 case 2:
4059 if (print_headers) {
4060 fprintf(where,
4061 cpu_title,
4062 local_cpu_method,
4063 remote_cpu_method);
4064 }
4065
4066 fprintf(where,
4067 cpu_fmt_1_line_1, /* the format string */
4068 lss_size, /* local sendbuf size */
4069 lsr_size,
4070 req_size, /* how large were the requests */
4071 rsp_size, /* guess */
4072 elapsed_time, /* how long was the test */
4073 nummessages/elapsed_time,
4074 local_cpu_utilization, /* local cpu */
4075 remote_cpu_utilization, /* remote cpu */
4076 local_service_demand, /* local service demand */
4077 remote_service_demand); /* remote service demand */
4078 fprintf(where,
4079 cpu_fmt_1_line_2,
4080 rss_size,
4081 rsr_size);
4082 break;
4083 }
4084 }
4085 else {
4086 /* The tester did not wish to measure service demand. */
4087 switch (verbosity) {
4088 case 0:
4089 fprintf(where,
4090 tput_fmt_0,
4091 nummessages/elapsed_time);
4092 break;
4093 case 1:
4094 case 2:
4095 if (print_headers) {
4096 fprintf(where,tput_title,format_units());
4097 }
4098
4099 fprintf(where,
4100 tput_fmt_1_line_1, /* the format string */
4101 lss_size,
4102 lsr_size,
4103 req_size, /* how large were the requests */
4104 rsp_size, /* how large were the responses */
4105 elapsed_time, /* how long did it take */
4106 nummessages/elapsed_time);
4107 fprintf(where,
4108 tput_fmt_1_line_2,
4109 rss_size, /* remote recvbuf size */
4110 rsr_size);
4111
4112 break;
4113 }
4114 }
4115 fflush(where);
4116
4117 /* it would be a good thing to include information about some of the */
4118 /* other parameters that may have been set for this test, but at the */
4119 /* moment, I do not wish to figure-out all the formatting, so I will */
4120 /* just put this comment here to help remind me that it is something */
4121 /* that should be done at a later time. */
4122
4123 /* how to handle the verbose information in the presence of */
4124 /* confidence intervals is yet to be determined... raj 11/94 */
4125
4126 if (verbosity > 1) {
4127 /* The user wanted to know it all, so we will give it to him. */
4128 /* This information will include as much as we can find about */
4129 /* UDP statistics, the alignments of the sends and receives */
4130 /* and all that sort of rot... */
4131
4132#ifdef WANT_HISTOGRAM
4133 fprintf(where,"\nHistogram of request/reponse times.\n");
4134 fflush(where);
4135 HIST_report(time_hist);
4136#endif /* WANT_HISTOGRAM */
4137 }
4138}
4139
4140 /* this routine implements the receive side (netserver) of a XTI_UDP_RR */
4141 /* test. */
4142void
4143 recv_xti_udp_rr()
4144{
4145
4146 struct ring_elt *recv_ring;
4147 struct ring_elt *send_ring;
4148
4149 struct t_bind bind_req, bind_resp;
4150 struct t_unitdata send_unitdata;
4151 struct t_unitdata recv_unitdata;
4152 int flags = 0;
4153
4154 struct sockaddr_in myaddr_in, peeraddr_in;
4155 SOCKET s_data;
4156 int addrlen;
4157 int trans_received;
4158 int trans_remaining;
4159 float elapsed_time;
4160
4161 struct xti_udp_rr_request_struct *xti_udp_rr_request;
4162 struct xti_udp_rr_response_struct *xti_udp_rr_response;
4163 struct xti_udp_rr_results_struct *xti_udp_rr_results;
4164
4165
4166 /* a little variable initialization */
4167 memset (&myaddr_in, 0, sizeof(struct sockaddr_in));
4168 myaddr_in.sin_family = AF_INET;
4169 myaddr_in.sin_addr.s_addr = INADDR_ANY;
4170 myaddr_in.sin_port = 0;
4171 memset (&peeraddr_in, 0, sizeof(struct sockaddr_in));
4172
4173 /* and some not so paranoid :) */
4174 xti_udp_rr_request =
4175 (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data;
4176 xti_udp_rr_response =
4177 (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data;
4178 xti_udp_rr_results =
4179 (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data;
4180
4181 if (debug) {
4182 fprintf(where,"netserver: recv_xti_udp_rr: entered...\n");
4183 fflush(where);
4184 }
4185
4186 /* We want to set-up the listen socket with all the desired */
4187 /* parameters and then let the initiator know that all is ready. If */
4188 /* socket size defaults are to be used, then the initiator will have */
4189 /* sent us 0's. If the socket sizes cannot be changed, then we will */
4190 /* send-back what they are. If that information cannot be determined, */
4191 /* then we send-back -1's for the sizes. If things go wrong for any */
4192 /* reason, we will drop back ten yards and punt. */
4193
4194 /* If anything goes wrong, we want the remote to know about it. It */
4195 /* would be best if the error that the remote reports to the user is */
4196 /* the actual error we encountered, rather than some bogus unexpected */
4197 /* response type message. */
4198
4199 if (debug) {
4200 fprintf(where,"recv_xti_udp_rr: setting the response type...\n");
4201 fflush(where);
4202 }
4203
4204 netperf_response.content.response_type = XTI_UDP_RR_RESPONSE;
4205
4206 if (debug) {
4207 fprintf(where,"recv_xti_udp_rr: the response type is set...\n");
4208 fflush(where);
4209 }
4210
4211 /* We now alter the message_ptr variables to be at the desired */
4212 /* alignments with the desired offsets. */
4213
4214 if (debug) {
4215 fprintf(where,"recv_xti_udp_rr: requested recv alignment of %d offset %d\n",
4216 xti_udp_rr_request->recv_alignment,
4217 xti_udp_rr_request->recv_offset);
4218 fprintf(where,"recv_xti_udp_rr: requested send alignment of %d offset %d\n",
4219 xti_udp_rr_request->send_alignment,
4220 xti_udp_rr_request->send_offset);
4221 fflush(where);
4222 }
4223
4224 if (send_width == 0) send_width = 1;
4225 if (recv_width == 0) recv_width = 1;
4226
4227 recv_ring = allocate_buffer_ring(recv_width,
4228 xti_udp_rr_request->request_size,
4229 xti_udp_rr_request->recv_alignment,
4230 xti_udp_rr_request->recv_offset);
4231
4232 send_ring = allocate_buffer_ring(send_width,
4233 xti_udp_rr_request->response_size,
4234 xti_udp_rr_request->send_alignment,
4235 xti_udp_rr_request->send_offset);
4236
4237 if (debug) {
4238 fprintf(where,"recv_xti_udp_rr: receive alignment and offset set...\n");
4239 fflush(where);
4240 }
4241
4242 /* create_xti_endpoint expects to find some things in the global */
4243 /* variables, so set the globals based on the values in the request. */
4244 /* once the socket has been created, we will set the response values */
4245 /* based on the updated value of those globals. raj 7/94 */
4246 lss_size = xti_udp_rr_request->send_buf_size;
4247 lsr_size = xti_udp_rr_request->recv_buf_size;
4248 loc_rcvavoid = xti_udp_rr_request->so_rcvavoid;
4249 loc_sndavoid = xti_udp_rr_request->so_sndavoid;
4250
4251#ifdef __alpha
4252
4253 /* ok - even on a DEC box, strings are strings. I din't really want */
4254 /* to ntohl the words of a string. since I don't want to teach the */
4255 /* send_ and recv_ _request and _response routines about the types, */
4256 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
4257 /* solution would be to use XDR, but I am still leary of being able */
4258 /* to find XDR libs on all platforms I want running netperf. raj */
4259 {
4260 int *charword;
4261 int *initword;
4262 int *lastword;
4263
4264 initword = (int *) xti_udp_rr_request->xti_device;
4265 lastword = initword + ((xti_udp_rr_request->dev_name_len + 3) / 4);
4266
4267 for (charword = initword;
4268 charword < lastword;
4269 charword++) {
4270
4271 *charword = htonl(*charword);
4272 }
4273 }
4274
4275#endif /* __alpha */
4276
4277 s_data = create_xti_endpoint(xti_udp_rr_request->xti_device);
4278
4279 if (s_data == INVALID_SOCKET) {
4280 netperf_response.content.serv_errno = errno;
4281 send_response();
4282 exit(1);
4283 }
4284
4285 if (debug) {
4286 fprintf(where,"recv_xti_udp_rr: endpoint created...\n");
4287 fflush(where);
4288 }
4289
4290 /* Let's get an address assigned to this socket so we can tell the */
4291 /* initiator how to reach the data socket. There may be a desire to */
4292 /* nail this socket to a specific IP address in a multi-homed, */
4293 /* multi-connection situation, but for now, we'll ignore the issue */
4294 /* and concentrate on single connection testing. */
4295
4296 bind_req.addr.maxlen = sizeof(struct sockaddr_in);
4297 bind_req.addr.len = sizeof(struct sockaddr_in);
4298 bind_req.addr.buf = (char *)&myaddr_in;
4299 bind_req.qlen = 1;
4300
4301 bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
4302 bind_resp.addr.len = sizeof(struct sockaddr_in);
4303 bind_resp.addr.buf = (char *)&myaddr_in;
4304 bind_resp.qlen = 1;
4305
4306 if (t_bind(s_data,
4307 &bind_req,
4308 &bind_resp) == SOCKET_ERROR) {
4309 if (debug) {
4310 fprintf(where,
4311 "recv_xti_udp_rr: t_bind failed, t_errno %d errno %d\n",
4312 t_errno,
4313 errno);
4314 fflush(where);
4315 }
4316
4317 netperf_response.content.serv_errno = t_errno;
4318 send_response();
4319
4320 exit(1);
4321 }
4322
4323 if (debug) {
4324 fprintf(where,
4325 "recv_xti_udp_rr: endpoint bound to port %d...\n",
4326 ntohs(myaddr_in.sin_port));
4327 fflush(where);
4328 }
4329
4330 xti_udp_rr_response->test_length =
4331 xti_udp_rr_request->test_length;
4332
4333
4334 /* Now myaddr_in contains the port and the internet address this is */
4335 /* returned to the sender also implicitly telling the sender that the */
4336 /* socket buffer sizing has been done. */
4337
4338 xti_udp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
4339 netperf_response.content.serv_errno = 0;
4340
4341 fprintf(where,"recv port number %d\n",myaddr_in.sin_port);
4342 fflush(where);
4343
4344 /* But wait, there's more. If the initiator wanted cpu measurements, */
4345 /* then we must call the calibrate routine, which will return the max */
4346 /* rate back to the initiator. If the CPU was not to be measured, or */
4347 /* something went wrong with the calibration, we will return a 0.0 to */
4348 /* the initiator. */
4349
4350 xti_udp_rr_response->cpu_rate = 0.0; /* assume no cpu */
4351 xti_udp_rr_response->measure_cpu = 0;
4352 if (xti_udp_rr_request->measure_cpu) {
4353 xti_udp_rr_response->measure_cpu = 1;
4354 xti_udp_rr_response->cpu_rate =
4355 calibrate_local_cpu(xti_udp_rr_request->cpu_rate);
4356 }
4357
4358 /* before we send the response back to the initiator, pull some of */
4359 /* the socket parms from the globals */
4360 xti_udp_rr_response->send_buf_size = lss_size;
4361 xti_udp_rr_response->recv_buf_size = lsr_size;
4362 xti_udp_rr_response->so_rcvavoid = loc_rcvavoid;
4363 xti_udp_rr_response->so_sndavoid = loc_sndavoid;
4364
4365 /* since we are going to call t_rcvudata() instead of t_rcv() we */
4366 /* need to init the unitdata structure raj 3/95 */
4367
4368 memset (&recv_unitdata, 0, sizeof(recv_unitdata));
4369 recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
4370 recv_unitdata.addr.len = sizeof(struct sockaddr_in);
4371 recv_unitdata.addr.buf = (char *)&peeraddr_in;
4372
4373 recv_unitdata.opt.maxlen = 0;
4374 recv_unitdata.opt.len = 0;
4375 recv_unitdata.opt.buf = NULL;
4376
4377 recv_unitdata.udata.maxlen = xti_udp_rr_request->request_size;
4378 recv_unitdata.udata.len = xti_udp_rr_request->request_size;
4379 recv_unitdata.udata.buf = recv_ring->buffer_ptr;
4380
4381 /* since we are going to call t_sndudata() instead of t_snd() we */
4382 /* need to init the unitdata structure raj 8/95 */
4383
4384 memset (&send_unitdata, 0, sizeof(send_unitdata));
4385 send_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
4386 send_unitdata.addr.len = sizeof(struct sockaddr_in);
4387 send_unitdata.addr.buf = (char *)&peeraddr_in;
4388
4389 send_unitdata.opt.maxlen = 0;
4390 send_unitdata.opt.len = 0;
4391 send_unitdata.opt.buf = NULL;
4392
4393 send_unitdata.udata.maxlen = xti_udp_rr_request->response_size;
4394 send_unitdata.udata.len = xti_udp_rr_request->response_size;
4395 send_unitdata.udata.buf = send_ring->buffer_ptr;
4396
4397 send_response();
4398
4399
4400 /* Now it's time to start receiving data on the connection. We will */
4401 /* first grab the apropriate counters and then start grabbing. */
4402
4403 cpu_start(xti_udp_rr_request->measure_cpu);
4404
4405 if (xti_udp_rr_request->test_length > 0) {
4406 times_up = 0;
4407 trans_remaining = 0;
4408 start_timer(xti_udp_rr_request->test_length + PAD_TIME);
4409 }
4410 else {
4411 times_up = 1;
4412 trans_remaining = xti_udp_rr_request->test_length * -1;
4413 }
4414
4415 addrlen = sizeof(peeraddr_in);
4416 bzero((char *)&peeraddr_in, addrlen);
4417
4418 trans_received = 0;
4419
4420 while ((!times_up) || (trans_remaining > 0)) {
4421
4422 /* receive the request from the other side */
4423 if (t_rcvudata(s_data,
4424 &recv_unitdata,
4425 &flags) != 0) {
4426 if (errno == TNODATA) {
4427 continue;
4428 }
4429 if (errno == EINTR) {
4430 /* we must have hit the end of test time. */
4431 break;
4432 }
4433 if (debug) {
4434 fprintf(where,
4435 "recv_xti_udp_rr: t_rcvudata failed, t_errno %d errno %d\n",
4436 t_errno,
4437 errno);
4438 fflush(where);
4439 }
4440 netperf_response.content.serv_errno = t_errno;
4441 send_response();
4442 exit(1);
4443 }
4444 recv_ring = recv_ring->next;
4445 recv_unitdata.udata.buf = recv_ring->buffer_ptr;
4446
4447 /* Now, send the response to the remote */
4448 if (t_sndudata(s_data,
4449 &send_unitdata) != 0) {
4450 if (errno == EINTR) {
4451 /* we have hit end of test time. */
4452 break;
4453 }
4454 if (debug) {
4455 fprintf(where,
4456 "recv_xti_udp_rr: t_sndudata failed, t_errno %d errno %d\n",
4457 t_errno,
4458 errno);
4459 fflush(where);
4460 }
4461 netperf_response.content.serv_errno = errno;
4462 send_response();
4463 exit(1);
4464 }
4465 send_ring = send_ring->next;
4466 send_unitdata.udata.buf = send_ring->buffer_ptr;
4467
4468 trans_received++;
4469 if (trans_remaining) {
4470 trans_remaining--;
4471 }
4472
4473 if (debug) {
4474 fprintf(where,
4475 "recv_xti_udp_rr: Transaction %d complete.\n",
4476 trans_received);
4477 fflush(where);
4478 }
4479
4480 }
4481
4482
4483 /* The loop now exits due to timeout or transaction count being */
4484 /* reached */
4485
4486 cpu_stop(xti_udp_rr_request->measure_cpu,&elapsed_time);
4487
4488 if (times_up) {
4489 /* we ended the test by time, which was at least 2 seconds */
4490 /* longer than we wanted to run. so, we want to subtract */
4491 /* PAD_TIME from the elapsed_time. */
4492 elapsed_time -= PAD_TIME;
4493 }
4494 /* send the results to the sender */
4495
4496 if (debug) {
4497 fprintf(where,
4498 "recv_xti_udp_rr: got %d transactions\n",
4499 trans_received);
4500 fflush(where);
4501 }
4502
4503 xti_udp_rr_results->bytes_received = (trans_received *
4504 (xti_udp_rr_request->request_size +
4505 xti_udp_rr_request->response_size));
4506 xti_udp_rr_results->trans_received = trans_received;
4507 xti_udp_rr_results->elapsed_time = elapsed_time;
4508 xti_udp_rr_results->cpu_method = cpu_method;
4509 if (xti_udp_rr_request->measure_cpu) {
4510 xti_udp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
4511 }
4512
4513 if (debug) {
4514 fprintf(where,
4515 "recv_xti_udp_rr: test complete, sending results.\n");
4516 fflush(where);
4517 }
4518
4519 send_response();
4520
4521 /* we are done with the socket now */
4522 close(s_data);
4523
4524}
4525
4526 /* this routine implements the receive (netserver) side of a XTI_TCP_RR */
4527 /* test */
4528void
4529recv_xti_tcp_rr()
4530{
4531
4532 struct ring_elt *send_ring;
4533 struct ring_elt *recv_ring;
4534
4535 struct sockaddr_in myaddr_in, peeraddr_in;
4536 struct t_bind bind_req, bind_resp;
4537 struct t_call call_req;
4538
4539 SOCKET s_listen,s_data;
4540 int addrlen;
4541 char *temp_message_ptr;
4542 int trans_received;
4543 int trans_remaining;
4544 int bytes_sent;
4545 int request_bytes_recvd;
4546 int request_bytes_remaining;
4547 int timed_out = 0;
4548 float elapsed_time;
4549
4550 struct xti_tcp_rr_request_struct *xti_tcp_rr_request;
4551 struct xti_tcp_rr_response_struct *xti_tcp_rr_response;
4552 struct xti_tcp_rr_results_struct *xti_tcp_rr_results;
4553
4554 xti_tcp_rr_request =
4555 (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data;
4556 xti_tcp_rr_response =
4557 (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data;
4558 xti_tcp_rr_results =
4559 (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data;
4560
4561 if (debug) {
4562 fprintf(where,"netserver: recv_xti_tcp_rr: entered...\n");
4563 fflush(where);
4564 }
4565
4566 /* We want to set-up the listen socket with all the desired */
4567 /* parameters and then let the initiator know that all is ready. If */
4568 /* socket size defaults are to be used, then the initiator will have */
4569 /* sent us 0's. If the socket sizes cannot be changed, then we will */
4570 /* send-back what they are. If that information cannot be determined, */
4571 /* then we send-back -1's for the sizes. If things go wrong for any */
4572 /* reason, we will drop back ten yards and punt. */
4573
4574 /* If anything goes wrong, we want the remote to know about it. It */
4575 /* would be best if the error that the remote reports to the user is */
4576 /* the actual error we encountered, rather than some bogus unexpected */
4577 /* response type message. */
4578
4579 if (debug) {
4580 fprintf(where,"recv_xti_tcp_rr: setting the response type...\n");
4581 fflush(where);
4582 }
4583
4584 netperf_response.content.response_type = XTI_TCP_RR_RESPONSE;
4585
4586 if (debug) {
4587 fprintf(where,"recv_xti_tcp_rr: the response type is set...\n");
4588 fflush(where);
4589 }
4590
4591 /* allocate the recv and send rings with the requested alignments */
4592 /* and offsets. raj 7/94 */
4593 if (debug) {
4594 fprintf(where,"recv_xti_tcp_rr: requested recv alignment of %d offset %d\n",
4595 xti_tcp_rr_request->recv_alignment,
4596 xti_tcp_rr_request->recv_offset);
4597 fprintf(where,"recv_xti_tcp_rr: requested send alignment of %d offset %d\n",
4598 xti_tcp_rr_request->send_alignment,
4599 xti_tcp_rr_request->send_offset);
4600 fflush(where);
4601 }
4602
4603 /* at some point, these need to come to us from the remote system */
4604 if (send_width == 0) send_width = 1;
4605 if (recv_width == 0) recv_width = 1;
4606
4607 send_ring = allocate_buffer_ring(send_width,
4608 xti_tcp_rr_request->response_size,
4609 xti_tcp_rr_request->send_alignment,
4610 xti_tcp_rr_request->send_offset);
4611
4612 recv_ring = allocate_buffer_ring(recv_width,
4613 xti_tcp_rr_request->request_size,
4614 xti_tcp_rr_request->recv_alignment,
4615 xti_tcp_rr_request->recv_offset);
4616
4617
4618 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
4619 /* can put in OUR values !-) At some point, we may want to nail this */
4620 /* socket to a particular network-level address, but for now, */
4621 /* INADDR_ANY should be just fine. */
4622
4623 bzero((char *)&myaddr_in,
4624 sizeof(myaddr_in));
4625 myaddr_in.sin_family = AF_INET;
4626 myaddr_in.sin_addr.s_addr = INADDR_ANY;
4627 myaddr_in.sin_port = 0;
4628
4629 /* Grab a socket to listen on, and then listen on it. */
4630
4631 if (debug) {
4632 fprintf(where,"recv_xti_tcp_rr: grabbing a socket...\n");
4633 fflush(where);
4634 }
4635
4636 /* create_xti_endpoint expects to find some things in the global */
4637 /* variables, so set the globals based on the values in the request. */
4638 /* once the socket has been created, we will set the response values */
4639 /* based on the updated value of those globals. raj 7/94 */
4640 lss_size = xti_tcp_rr_request->send_buf_size;
4641 lsr_size = xti_tcp_rr_request->recv_buf_size;
4642 loc_nodelay = xti_tcp_rr_request->no_delay;
4643 loc_rcvavoid = xti_tcp_rr_request->so_rcvavoid;
4644 loc_sndavoid = xti_tcp_rr_request->so_sndavoid;
4645
4646#ifdef __alpha
4647
4648 /* ok - even on a DEC box, strings are strings. I din't really want */
4649 /* to ntohl the words of a string. since I don't want to teach the */
4650 /* send_ and recv_ _request and _response routines about the types, */
4651 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
4652 /* solution would be to use XDR, but I am still leary of being able */
4653 /* to find XDR libs on all platforms I want running netperf. raj */
4654 {
4655 int *charword;
4656 int *initword;
4657 int *lastword;
4658
4659 initword = (int *) xti_tcp_rr_request->xti_device;
4660 lastword = initword + ((xti_tcp_rr_request->dev_name_len + 3) / 4);
4661
4662 for (charword = initword;
4663 charword < lastword;
4664 charword++) {
4665
4666 *charword = htonl(*charword);
4667 }
4668 }
4669
4670#endif /* __alpha */
4671
4672 s_listen = create_xti_endpoint(xti_tcp_rr_request->xti_device);
4673
4674 if (s_listen == INVALID_SOCKET) {
4675 netperf_response.content.serv_errno = errno;
4676 send_response();
4677
4678 exit(1);
4679 }
4680
4681 /* Let's get an address assigned to this socket so we can tell the */
4682 /* initiator how to reach the data socket. There may be a desire to */
4683 /* nail this socket to a specific IP address in a multi-homed, */
4684 /* multi-connection situation, but for now, we'll ignore the issue */
4685 /* and concentrate on single connection testing. */
4686
4687 bind_req.addr.maxlen = sizeof(struct sockaddr_in);
4688 bind_req.addr.len = sizeof(struct sockaddr_in);
4689 bind_req.addr.buf = (char *)&myaddr_in;
4690 bind_req.qlen = 1;
4691
4692 bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
4693 bind_resp.addr.len = sizeof(struct sockaddr_in);
4694 bind_resp.addr.buf = (char *)&myaddr_in;
4695 bind_resp.qlen = 1;
4696
4697 if (t_bind(s_listen,
4698 &bind_req,
4699 &bind_resp) == SOCKET_ERROR) {
4700 netperf_response.content.serv_errno = t_errno;
4701 close(s_listen);
4702 send_response();
4703
4704 exit(1);
4705 }
4706
4707 if (debug) {
4708 fprintf(where,
4709 "recv_xti_tcp_rr: t_bind complete port %d\n",
4710 ntohs(myaddr_in.sin_port));
4711 fflush(where);
4712 }
4713
4714 /* Now myaddr_in contains the port and the internet address this is */
4715 /* returned to the sender also implicitly telling the sender that the */
4716 /* socket buffer sizing has been done. */
4717
4718 xti_tcp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
4719 netperf_response.content.serv_errno = 0;
4720
4721 /* But wait, there's more. If the initiator wanted cpu measurements, */
4722 /* then we must call the calibrate routine, which will return the max */
4723 /* rate back to the initiator. If the CPU was not to be measured, or */
4724 /* something went wrong with the calibration, we will return a 0.0 to */
4725 /* the initiator. */
4726
4727 xti_tcp_rr_response->cpu_rate = 0.0; /* assume no cpu */
4728 xti_tcp_rr_response->measure_cpu = 0;
4729
4730 if (xti_tcp_rr_request->measure_cpu) {
4731 xti_tcp_rr_response->measure_cpu = 1;
4732 xti_tcp_rr_response->cpu_rate = calibrate_local_cpu(xti_tcp_rr_request->cpu_rate);
4733 }
4734
4735
4736 /* before we send the response back to the initiator, pull some of */
4737 /* the socket parms from the globals */
4738 xti_tcp_rr_response->send_buf_size = lss_size;
4739 xti_tcp_rr_response->recv_buf_size = lsr_size;
4740 xti_tcp_rr_response->no_delay = loc_nodelay;
4741 xti_tcp_rr_response->so_rcvavoid = loc_rcvavoid;
4742 xti_tcp_rr_response->so_sndavoid = loc_sndavoid;
4743 xti_tcp_rr_response->test_length = xti_tcp_rr_request->test_length;
4744 send_response();
4745
4746 /* Now, let's set-up the socket to listen for connections. for xti, */
4747 /* the t_listen call is blocking by default - this is different */
4748 /* semantics from BSD - probably has to do with being able to reject */
4749 /* a call before an accept */
4750 call_req.addr.maxlen = sizeof(struct sockaddr_in);
4751 call_req.addr.len = sizeof(struct sockaddr_in);
4752 call_req.addr.buf = (char *)&peeraddr_in;
4753 call_req.opt.maxlen = 0;
4754 call_req.opt.len = 0;
4755 call_req.opt.buf = NULL;
4756 call_req.udata.maxlen= 0;
4757 call_req.udata.len = 0;
4758 call_req.udata.buf = 0;
4759
4760 if (t_listen(s_listen, &call_req) == -1) {
4761 fprintf(where,
4762 "recv_xti_tcp_rr: t_listen: errno %d t_errno %d\n",
4763 errno,
4764 t_errno);
4765 fflush(where);
4766 netperf_response.content.serv_errno = t_errno;
4767 close(s_listen);
4768 send_response();
4769 exit(1);
4770 }
4771
4772 if (debug) {
4773 fprintf(where,
4774 "recv_xti_tcp_rr: t_listen complete t_look 0x%.4x\n",
4775 t_look(s_listen));
4776 fflush(where);
4777 }
4778
4779 /* now just rubber stamp the thing. we want to use the same fd? so */
4780 /* we will just equate s_data with s_listen. this seems a little */
4781 /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */
4782 s_data = s_listen;
4783 if (t_accept(s_listen,
4784 s_data,
4785 &call_req) == -1) {
4786 fprintf(where,
4787 "recv_xti_tcp_rr: t_accept: errno %d t_errno %d\n",
4788 errno,
4789 t_errno);
4790 fflush(where);
4791 close(s_listen);
4792 exit(1);
4793 }
4794
4795 if (debug) {
4796 fprintf(where,
4797 "recv_xti_tcp_rr: t_accept complete t_look 0x%.4x",
4798 t_look(s_data));
4799 fprintf(where,
4800 " remote is %s port %d\n",
4801 inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr),
4802 ntohs(peeraddr_in.sin_port));
4803 fflush(where);
4804 }
4805
4806 /* Now it's time to start receiving data on the connection. We will */
4807 /* first grab the apropriate counters and then start grabbing. */
4808
4809 cpu_start(xti_tcp_rr_request->measure_cpu);
4810
4811 if (xti_tcp_rr_request->test_length > 0) {
4812 times_up = 0;
4813 trans_remaining = 0;
4814 start_timer(xti_tcp_rr_request->test_length + PAD_TIME);
4815 }
4816 else {
4817 times_up = 1;
4818 trans_remaining = xti_tcp_rr_request->test_length * -1;
4819 }
4820
4821 trans_received = 0;
4822
4823 while ((!times_up) || (trans_remaining > 0)) {
4824 temp_message_ptr = recv_ring->buffer_ptr;
4825 request_bytes_remaining = xti_tcp_rr_request->request_size;
4826 while(request_bytes_remaining > 0) {
4827 if((request_bytes_recvd=t_rcv(s_data,
4828 temp_message_ptr,
4829 request_bytes_remaining,
4830 &xti_flags)) == SOCKET_ERROR) {
4831 if (errno == EINTR) {
4832 /* the timer popped */
4833 timed_out = 1;
4834 break;
4835 }
4836 fprintf(where,
4837 "recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d",
4838 errno,
4839 t_errno,
4840 request_bytes_recvd);
4841 fprintf(where,
4842 " t_look 0x%x",
4843 t_look(s_data));
4844 fflush(where);
4845 netperf_response.content.serv_errno = t_errno;
4846 send_response();
4847 exit(1);
4848 }
4849 else {
4850 request_bytes_remaining -= request_bytes_recvd;
4851 temp_message_ptr += request_bytes_recvd;
4852 }
4853 }
4854
4855 recv_ring = recv_ring->next;
4856
4857 if (timed_out) {
4858 /* we hit the end of the test based on time - lets */
4859 /* bail out of here now... */
4860 if (debug) {
4861 fprintf(where,"yo5\n");
4862 fflush(where);
4863 }
4864 break;
4865 }
4866
4867 /* Now, send the response to the remote */
4868 if((bytes_sent=t_snd(s_data,
4869 send_ring->buffer_ptr,
4870 xti_tcp_rr_request->response_size,
4871 0)) == -1) {
4872 if (errno == EINTR) {
4873 /* the test timer has popped */
4874 timed_out = 1;
4875 if (debug) {
4876 fprintf(where,"yo6\n");
4877 fflush(where);
4878 }
4879 break;
4880 }
4881 fprintf(where,
4882 "recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d",
4883 errno,
4884 t_errno,
4885 bytes_sent);
4886 fprintf(where,
4887 " t_look 0x%x",
4888 t_look(s_data));
4889 fflush(where);
4890 netperf_response.content.serv_errno = t_errno;
4891 send_response();
4892 exit(1);
4893 }
4894
4895 send_ring = send_ring->next;
4896
4897 trans_received++;
4898 if (trans_remaining) {
4899 trans_remaining--;
4900 }
4901 }
4902
4903
4904 /* The loop now exits due to timeout or transaction count being */
4905 /* reached */
4906
4907 cpu_stop(xti_tcp_rr_request->measure_cpu,&elapsed_time);
4908
4909 stop_timer(); /* this is probably unnecessary, but it shouldn't hurt */
4910
4911 if (timed_out) {
4912 /* we ended the test by time, which was at least 2 seconds */
4913 /* longer than we wanted to run. so, we want to subtract */
4914 /* PAD_TIME from the elapsed_time. */
4915 elapsed_time -= PAD_TIME;
4916 }
4917
4918 /* send the results to the sender */
4919
4920 if (debug) {
4921 fprintf(where,
4922 "recv_xti_tcp_rr: got %d transactions\n",
4923 trans_received);
4924 fflush(where);
4925 }
4926
4927 xti_tcp_rr_results->bytes_received = (trans_received *
4928 (xti_tcp_rr_request->request_size +
4929 xti_tcp_rr_request->response_size));
4930 xti_tcp_rr_results->trans_received = trans_received;
4931 xti_tcp_rr_results->elapsed_time = elapsed_time;
4932 xti_tcp_rr_results->cpu_method = cpu_method;
4933 if (xti_tcp_rr_request->measure_cpu) {
4934 xti_tcp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
4935 }
4936
4937 if (debug) {
4938 fprintf(where,
4939 "recv_xti_tcp_rr: test complete, sending results.\n");
4940 fflush(where);
4941 }
4942
4943 /* we are done with the socket, free it */
4944 t_close(s_data);
4945
4946 send_response();
4947
4948}
4949
4950
4951
4952 /* this test is intended to test the performance of establishing a */
4953 /* connection, exchanging a request/response pair, and repeating. it */
4954 /* is expected that this would be a good starting-point for */
4955 /* comparision of T/TCP with classic TCP for transactional workloads. */
4956 /* it will also look (can look) much like the communication pattern */
4957 /* of http for www access. */
4958
4959void
4960send_xti_tcp_conn_rr(char remote_host[])
4961{
4962
4963 char *tput_title = "\
4964Local /Remote\n\
4965Socket Size Request Resp. Elapsed Trans.\n\
4966Send Recv Size Size Time Rate \n\
4967bytes Bytes bytes bytes secs. per sec \n\n";
4968
4969 char *tput_fmt_0 =
4970 "%7.2f\n";
4971
4972 char *tput_fmt_1_line_1 = "\
4973%-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
4974 char *tput_fmt_1_line_2 = "\
4975%-6d %-6d\n";
4976
4977 char *cpu_title = "\
4978Local /Remote\n\
4979Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
4980Send Recv Size Size Time Rate local remote local remote\n\
4981bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
4982
4983 char *cpu_fmt_0 =
4984 "%6.3f\n";
4985
4986 char *cpu_fmt_1_line_1 = "\
4987%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
4988
4989 char *cpu_fmt_1_line_2 = "\
4990%-6d %-6d\n";
4991
4992 char *ksink_fmt = "\
4993Alignment Offset\n\
4994Local Remote Local Remote\n\
4995Send Recv Send Recv\n\
4996%5d %5d %5d %5d\n";
4997
4998
4999 int one = 1;
5000 int timed_out = 0;
5001 float elapsed_time;
5002
5003 int len;
5004 struct ring_elt *send_ring;
5005 struct ring_elt *recv_ring;
5006 char *temp_message_ptr;
5007 int nummessages;
5008 SOCKET send_socket;
5009 int trans_remaining;
5010 double bytes_xferd;
5011 int sock_opt_len = sizeof(int);
5012 int rsp_bytes_left;
5013 int rsp_bytes_recvd;
5014
5015 float local_cpu_utilization;
5016 float local_service_demand;
5017 float remote_cpu_utilization;
5018 float remote_service_demand;
5019 double thruput;
5020
5021 struct hostent *hp;
5022 struct sockaddr_in server;
5023 struct sockaddr_in *myaddr;
5024 unsigned int addr;
5025 int myport;
5026
5027 struct xti_tcp_conn_rr_request_struct *xti_tcp_conn_rr_request;
5028 struct xti_tcp_conn_rr_response_struct *xti_tcp_conn_rr_response;
5029 struct xti_tcp_conn_rr_results_struct *xti_tcp_conn_rr_result;
5030
5031 xti_tcp_conn_rr_request =
5032 (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
5033 xti_tcp_conn_rr_response =
5034 (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
5035 xti_tcp_conn_rr_result =
5036 (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
5037
5038 /* since we are now disconnected from the code that established the */
5039 /* control socket, and since we want to be able to use different */
5040 /* protocols and such, we are passed the name of the remote host and */
5041 /* must turn that into the test specific addressing information. */
5042
5043 myaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
5044 if (myaddr == NULL) {
5045 printf("malloc(%d) failed!\n", sizeof(struct sockaddr_in));
5046 exit(1);
5047 }
5048
5049 bzero((char *)&server,
5050 sizeof(server));
5051 bzero((char *)myaddr,
5052 sizeof(struct sockaddr_in));
5053 myaddr->sin_family = AF_INET;
5054
5055 /* it would seem that while HP-UX will allow an IP address (as a */
5056 /* string) in a call to gethostbyname, other, less enlightened */
5057 /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
5058 /* order changed to check for IP address first. raj 7/96 */
5059
5060 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
5061 /* it was not an IP address, try it as a name */
5062 if ((hp = gethostbyname(remote_host)) == NULL) {
5063 /* we have no idea what it is */
5064 fprintf(where,
5065 "establish_control: could not resolve the destination %s\n",
5066 remote_host);
5067 fflush(where);
5068 exit(1);
5069 }
5070 else {
5071 /* it was a valid remote_host */
5072 bcopy(hp->h_addr,
5073 (char *)&server.sin_addr,
5074 hp->h_length);
5075 server.sin_family = hp->h_addrtype;
5076 }
5077 }
5078 else {
5079 /* it was a valid IP address */
5080 server.sin_addr.s_addr = addr;
5081 server.sin_family = AF_INET;
5082 }
5083
5084 if ( print_headers ) {
5085 fprintf(where,"TCP Connect/Request/Response Test\n");
5086 if (local_cpu_usage || remote_cpu_usage)
5087 fprintf(where,cpu_title,format_units());
5088 else
5089 fprintf(where,tput_title,format_units());
5090 }
5091
5092 /* initialize a few counters */
5093
5094 nummessages = 0;
5095 bytes_xferd = 0.0;
5096 times_up = 0;
5097
5098 /* set-up the data buffers with the requested alignment and offset */
5099 if (send_width == 0) send_width = 1;
5100 if (recv_width == 0) recv_width = 1;
5101
5102 send_ring = allocate_buffer_ring(send_width,
5103 req_size,
5104 local_send_align,
5105 local_send_offset);
5106
5107 recv_ring = allocate_buffer_ring(recv_width,
5108 rsp_size,
5109 local_recv_align,
5110 local_recv_offset);
5111
5112
5113 if (debug) {
5114 fprintf(where,"send_xti_tcp_conn_rr: send_socket obtained...\n");
5115 }
5116
5117 /* If the user has requested cpu utilization measurements, we must */
5118 /* calibrate the cpu(s). We will perform this task within the tests */
5119 /* themselves. If the user has specified the cpu rate, then */
5120 /* calibrate_local_cpu will return rather quickly as it will have */
5121 /* nothing to do. If local_cpu_rate is zero, then we will go through */
5122 /* all the "normal" calibration stuff and return the rate back.*/
5123
5124 if (local_cpu_usage) {
5125 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
5126 }
5127
5128 /* Tell the remote end to do a listen. The server alters the socket */
5129 /* paramters on the other side at this point, hence the reason for */
5130 /* all the values being passed in the setup message. If the user did */
5131 /* not specify any of the parameters, they will be passed as 0, which */
5132 /* will indicate to the remote that no changes beyond the system's */
5133 /* default should be used. Alignment is the exception, it will */
5134 /* default to 8, which will be no alignment alterations. */
5135
5136 netperf_request.content.request_type = DO_XTI_TCP_CRR;
5137 xti_tcp_conn_rr_request->recv_buf_size = rsr_size;
5138 xti_tcp_conn_rr_request->send_buf_size = rss_size;
5139 xti_tcp_conn_rr_request->recv_alignment = remote_recv_align;
5140 xti_tcp_conn_rr_request->recv_offset = remote_recv_offset;
5141 xti_tcp_conn_rr_request->send_alignment = remote_send_align;
5142 xti_tcp_conn_rr_request->send_offset = remote_send_offset;
5143 xti_tcp_conn_rr_request->request_size = req_size;
5144 xti_tcp_conn_rr_request->response_size = rsp_size;
5145 xti_tcp_conn_rr_request->no_delay = rem_nodelay;
5146 xti_tcp_conn_rr_request->measure_cpu = remote_cpu_usage;
5147 xti_tcp_conn_rr_request->cpu_rate = remote_cpu_rate;
5148 xti_tcp_conn_rr_request->so_rcvavoid = rem_rcvavoid;
5149 xti_tcp_conn_rr_request->so_sndavoid = rem_sndavoid;
5150 if (test_time) {
5151 xti_tcp_conn_rr_request->test_length = test_time;
5152 }
5153 else {
5154 xti_tcp_conn_rr_request->test_length = test_trans * -1;
5155 }
5156
5157 if (debug > 1) {
5158 fprintf(where,"netperf: send_xti_tcp_conn_rr: requesting TCP crr test\n");
5159 }
5160
5161 send_request();
5162
5163 /* The response from the remote will contain all of the relevant */
5164 /* socket parameters for this test type. We will put them back into */
5165 /* the variables here so they can be displayed if desired. The */
5166 /* remote will have calibrated CPU if necessary, and will have done */
5167 /* all the needed set-up we will have calibrated the cpu locally */
5168 /* before sending the request, and will grab the counter value right */
5169 /* after the connect returns. The remote will grab the counter right */
5170 /* after the accept call. This saves the hassle of extra messages */
5171 /* being sent for the TCP tests. */
5172
5173 recv_response();
5174
5175 if (!netperf_response.content.serv_errno) {
5176 rsr_size = xti_tcp_conn_rr_response->recv_buf_size;
5177 rss_size = xti_tcp_conn_rr_response->send_buf_size;
5178 rem_nodelay = xti_tcp_conn_rr_response->no_delay;
5179 remote_cpu_usage= xti_tcp_conn_rr_response->measure_cpu;
5180 remote_cpu_rate = xti_tcp_conn_rr_response->cpu_rate;
5181 /* make sure that port numbers are in network order */
5182 server.sin_port = (short)xti_tcp_conn_rr_response->data_port_number;
5183 server.sin_port = htons(server.sin_port);
5184 if (debug) {
5185 fprintf(where,"remote listen done.\n");
5186 fprintf(where,"remote port is %d\n",ntohs(server.sin_port));
5187 fflush(where);
5188 }
5189 }
5190 else {
5191 Set_errno(netperf_response.content.serv_errno);
5192 perror("netperf: remote error");
5193
5194 exit(1);
5195 }
5196
5197 /* Set-up the test end conditions. For a request/response test, they */
5198 /* can be either time or transaction based. */
5199
5200 if (test_time) {
5201 /* The user wanted to end the test after a period of time. */
5202 times_up = 0;
5203 trans_remaining = 0;
5204 start_timer(test_time);
5205 }
5206 else {
5207 /* The tester wanted to send a number of bytes. */
5208 trans_remaining = test_bytes;
5209 times_up = 1;
5210 }
5211
5212 /* The cpu_start routine will grab the current time and possibly */
5213 /* value of the idle counter for later use in measuring cpu */
5214 /* utilization and/or service demand and thruput. */
5215
5216 cpu_start(local_cpu_usage);
5217
5218 /* We use an "OR" to control test execution. When the test is */
5219 /* controlled by time, the byte count check will always return false. */
5220 /* When the test is controlled by byte count, the time test will */
5221 /* always return false. When the test is finished, the whole */
5222 /* expression will go false and we will stop sending data. I think I */
5223 /* just arbitrarily decrement trans_remaining for the timed test, but */
5224 /* will not do that just yet... One other question is whether or not */
5225 /* the send buffer and the receive buffer should be the same buffer. */
5226
5227 /* just for grins, start the port numbers at 65530. this should */
5228 /* quickly flush-out those broken implementations of TCP which treat */
5229 /* the port number as a signed 16 bit quantity. */
5230 myport = 65530;
5231 myaddr->sin_port = htons(myport);
5232
5233 while ((!times_up) || (trans_remaining > 0)) {
5234
5235 /* set up the data socket */
5236 send_socket = create_xti_endpoint(loc_xti_device);
5237
5238 if (send_socket == INVALID_SOCKET) {
5239 perror("netperf: send_xti_tcp_conn_rr: tcp stream data socket");
5240 exit(1);
5241 }
5242
5243 /* we set SO_REUSEADDR on the premis that no unreserved port */
5244 /* number on the local system is going to be already connected to */
5245 /* the remote netserver's port number. we might still have a */
5246 /* problem if there is a port in the unconnected state. In that */
5247 /* case, we might want to throw-in a goto to the point where we */
5248 /* increment the port number by one and try again. of course, this */
5249 /* could lead to a big load of spinning. one thing that I might */
5250 /* try later is to have the remote actually allocate a couple of */
5251 /* port numbers and cycle through those as well. depends on if we */
5252 /* can get through all the unreserved port numbers in less than */
5253 /* the length of the TIME_WAIT state raj 8/94 */
5254 one = 1;
5255 if(setsockopt(send_socket, SOL_SOCKET, SO_REUSEADDR,
5256 (char *)&one, sock_opt_len) == SOCKET_ERROR) {
5257 perror("netperf: send_xti_tcp_conn_rr: so_reuseaddr");
5258 exit(1);
5259 }
5260
5261 /* we want to bind our socket to a particular port number. */
5262 if (bind(send_socket,
5263 (struct sockaddr *)myaddr,
5264 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
5265 printf("netperf: send_xti_tcp_conn_rr: tried to bind to port %d\n",
5266 ntohs(myaddr->sin_port));
5267 perror("netperf: send_xti_tcp_conn_rr: bind");
5268 exit(1);
5269 }
5270
5271 /* Connect up to the remote port on the data socket */
5272 if (connect(send_socket,
5273 (struct sockaddr *)&server,
5274 sizeof(server)) == INVALID_SOCKET){
5275 if (errno == EINTR) {
5276 /* we hit the end of a */
5277 /* timed test. */
5278 timed_out = 1;
5279 break;
5280 }
5281 perror("netperf: data socket connect failed");
5282 printf("\tattempted to connect on socket %d to port %d",
5283 send_socket,
5284 ntohs(server.sin_port));
5285 printf(" from port %d \n",ntohs(myaddr->sin_port));
5286 exit(1);
5287 }
5288
5289 /* send the request */
5290 if((len=send(send_socket,
5291 send_ring->buffer_ptr,
5292 req_size,
5293 0)) != req_size) {
5294 if (errno == EINTR) {
5295 /* we hit the end of a */
5296 /* timed test. */
5297 timed_out = 1;
5298 break;
5299 }
5300 perror("send_xti_tcp_conn_rr: data send error");
5301 exit(1);
5302 }
5303 send_ring = send_ring->next;
5304
5305 /* receive the response */
5306 rsp_bytes_left = rsp_size;
5307 temp_message_ptr = recv_ring->buffer_ptr;
5308 while(rsp_bytes_left > 0) {
5309 if((rsp_bytes_recvd=recv(send_socket,
5310 temp_message_ptr,
5311 rsp_bytes_left,
5312 0)) == SOCKET_ERROR) {
5313 if (errno == EINTR) {
5314 /* We hit the end of a timed test. */
5315 timed_out = 1;
5316 break;
5317 }
5318 perror("send_xti_tcp_conn_rr: data recv error");
5319 exit(1);
5320 }
5321 rsp_bytes_left -= rsp_bytes_recvd;
5322 temp_message_ptr += rsp_bytes_recvd;
5323 }
5324 recv_ring = recv_ring->next;
5325
5326 if (timed_out) {
5327 /* we may have been in a nested while loop - we need */
5328 /* another call to break. */
5329 break;
5330 }
5331
5332 close(send_socket);
5333
5334 nummessages++;
5335 if (trans_remaining) {
5336 trans_remaining--;
5337 }
5338
5339 if (debug > 3) {
5340 fprintf(where,
5341 "Transaction %d completed on local port %d\n",
5342 nummessages,
5343 ntohs(myaddr->sin_port));
5344 fflush(where);
5345 }
5346
5347newport:
5348 /* pick a new port number */
5349 myport = ntohs(myaddr->sin_port);
5350 myport++;
5351 /* we do not want to use the port number that the server is */
5352 /* sitting at - this would cause us to fail in a loopback test */
5353
5354 if (myport == ntohs(server.sin_port)) myport++;
5355
5356 /* wrap the port number when we get to 65535. NOTE, some broken */
5357 /* TCP's might treat the port number as a signed 16 bit quantity. */
5358 /* we aren't interested in testing such broekn implementations :) */
5359 /* raj 8/94 */
5360 if (myport == 65535) {
5361 myport = 5000;
5362 }
5363 myaddr->sin_port = htons(myport);
5364
5365 if (debug) {
5366 if ((myport % 1000) == 0) {
5367 printf("port %d\n",myport);
5368 }
5369 }
5370
5371 }
5372
5373 /* this call will always give us the elapsed time for the test, and */
5374 /* will also store-away the necessaries for cpu utilization */
5375
5376 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
5377 /* how long did we really run? */
5378
5379 /* Get the statistics from the remote end. The remote will have */
5380 /* calculated service demand and all those interesting things. If it */
5381 /* wasn't supposed to care, it will return obvious values. */
5382
5383 recv_response();
5384 if (!netperf_response.content.serv_errno) {
5385 if (debug)
5386 fprintf(where,"remote results obtained\n");
5387 }
5388 else {
5389 Set_errno(netperf_response.content.serv_errno);
5390 perror("netperf: remote error");
5391
5392 exit(1);
5393 }
5394
5395 /* We now calculate what our thruput was for the test. In the future, */
5396 /* we may want to include a calculation of the thruput measured by */
5397 /* the remote, but it should be the case that for a TCP stream test, */
5398 /* that the two numbers should be *very* close... We calculate */
5399 /* bytes_sent regardless of the way the test length was controlled. */
5400 /* If it was time, we needed to, and if it was by bytes, the user may */
5401 /* have specified a number of bytes that wasn't a multiple of the */
5402 /* send_size, so we really didn't send what he asked for ;-) We use */
5403 /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
5404 /* 1024. A future enhancement *might* be to choose from a couple of */
5405 /* unit selections. */
5406
5407 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
5408 thruput = calc_thruput(bytes_xferd);
5409
5410 if (local_cpu_usage || remote_cpu_usage) {
5411 /* We must now do a little math for service demand and cpu */
5412 /* utilization for the system(s) */
5413 /* Of course, some of the information might be bogus because */
5414 /* there was no idle counter in the kernel(s). We need to make */
5415 /* a note of this for the user's benefit...*/
5416 if (local_cpu_usage) {
5417 if (local_cpu_rate == 0.0) {
5418 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
5419 fprintf(where,"Local CPU usage numbers based on process information only!\n");
5420 fflush(where);
5421 }
5422 local_cpu_utilization = calc_cpu_util(0.0);
5423 /* since calc_service demand is doing ms/Kunit we will */
5424 /* multiply the number of transaction by 1024 to get */
5425 /* "good" numbers */
5426 local_service_demand = calc_service_demand((double) nummessages*1024,
5427 0.0,
5428 0.0,
5429 0);
5430 }
5431 else {
5432 local_cpu_utilization = -1.0;
5433 local_service_demand = -1.0;
5434 }
5435
5436 if (remote_cpu_usage) {
5437 if (remote_cpu_rate == 0.0) {
5438 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
5439 fprintf(where,"Remote CPU usage numbers based on process information only!\n");
5440 fflush(where);
5441 }
5442 remote_cpu_utilization = xti_tcp_conn_rr_result->cpu_util;
5443 /* since calc_service demand is doing ms/Kunit we will */
5444 /* multiply the number of transaction by 1024 to get */
5445 /* "good" numbers */
5446 remote_service_demand = calc_service_demand((double) nummessages*1024,
5447 0.0,
5448 remote_cpu_utilization,
5449 xti_tcp_conn_rr_result->num_cpus);
5450 }
5451 else {
5452 remote_cpu_utilization = -1.0;
5453 remote_service_demand = -1.0;
5454 }
5455
5456 /* We are now ready to print all the information. If the user */
5457 /* has specified zero-level verbosity, we will just print the */
5458 /* local service demand, or the remote service demand. If the */
5459 /* user has requested verbosity level 1, he will get the basic */
5460 /* "streamperf" numbers. If the user has specified a verbosity */
5461 /* of greater than 1, we will display a veritable plethora of */
5462 /* background information from outside of this block as it it */
5463 /* not cpu_measurement specific... */
5464
5465 switch (verbosity) {
5466 case 0:
5467 if (local_cpu_usage) {
5468 fprintf(where,
5469 cpu_fmt_0,
5470 local_service_demand);
5471 }
5472 else {
5473 fprintf(where,
5474 cpu_fmt_0,
5475 remote_service_demand);
5476 }
5477 break;
5478 case 1:
5479 fprintf(where,
5480 cpu_fmt_1_line_1, /* the format string */
5481 lss_size, /* local sendbuf size */
5482 lsr_size,
5483 req_size, /* how large were the requests */
5484 rsp_size, /* guess */
5485 elapsed_time, /* how long was the test */
5486 nummessages/elapsed_time,
5487 local_cpu_utilization, /* local cpu */
5488 remote_cpu_utilization, /* remote cpu */
5489 local_service_demand, /* local service demand */
5490 remote_service_demand); /* remote service demand */
5491 fprintf(where,
5492 cpu_fmt_1_line_2,
5493 rss_size,
5494 rsr_size);
5495 break;
5496 }
5497 }
5498 else {
5499 /* The tester did not wish to measure service demand. */
5500 switch (verbosity) {
5501 case 0:
5502 fprintf(where,
5503 tput_fmt_0,
5504 nummessages/elapsed_time);
5505 break;
5506 case 1:
5507 fprintf(where,
5508 tput_fmt_1_line_1, /* the format string */
5509 lss_size,
5510 lsr_size,
5511 req_size, /* how large were the requests */
5512 rsp_size, /* how large were the responses */
5513 elapsed_time, /* how long did it take */
5514 nummessages/elapsed_time);
5515 fprintf(where,
5516 tput_fmt_1_line_2,
5517 rss_size, /* remote recvbuf size */
5518 rsr_size);
5519
5520 break;
5521 }
5522 }
5523
5524 /* it would be a good thing to include information about some of the */
5525 /* other parameters that may have been set for this test, but at the */
5526 /* moment, I do not wish to figure-out all the formatting, so I will */
5527 /* just put this comment here to help remind me that it is something */
5528 /* that should be done at a later time. */
5529
5530 if (verbosity > 1) {
5531 /* The user wanted to know it all, so we will give it to him. */
5532 /* This information will include as much as we can find about */
5533 /* TCP statistics, the alignments of the sends and receives */
5534 /* and all that sort of rot... */
5535
5536 fprintf(where,
5537 ksink_fmt);
5538 }
5539
5540}
5541
5542
5543void
5544recv_xti_tcp_conn_rr()
5545{
5546
5547 char *message;
5548 struct sockaddr_in myaddr_in,
5549 peeraddr_in;
5550 SOCKET s_listen,s_data;
5551 int addrlen;
5552 char *recv_message_ptr;
5553 char *send_message_ptr;
5554 char *temp_message_ptr;
5555 int trans_received;
5556 int trans_remaining;
5557 int bytes_sent;
5558 int request_bytes_recvd;
5559 int request_bytes_remaining;
5560 int timed_out = 0;
5561 float elapsed_time;
5562
5563 struct xti_tcp_conn_rr_request_struct *xti_tcp_conn_rr_request;
5564 struct xti_tcp_conn_rr_response_struct *xti_tcp_conn_rr_response;
5565 struct xti_tcp_conn_rr_results_struct *xti_tcp_conn_rr_results;
5566
5567 xti_tcp_conn_rr_request =
5568 (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
5569 xti_tcp_conn_rr_response =
5570 (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
5571 xti_tcp_conn_rr_results =
5572 (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
5573
5574 if (debug) {
5575 fprintf(where,"netserver: recv_xti_tcp_conn_rr: entered...\n");
5576 fflush(where);
5577 }
5578
5579 /* We want to set-up the listen socket with all the desired */
5580 /* parameters and then let the initiator know that all is ready. If */
5581 /* socket size defaults are to be used, then the initiator will have */
5582 /* sent us 0's. If the socket sizes cannot be changed, then we will */
5583 /* send-back what they are. If that information cannot be determined, */
5584 /* then we send-back -1's for the sizes. If things go wrong for any */
5585 /* reason, we will drop back ten yards and punt. */
5586
5587 /* If anything goes wrong, we want the remote to know about it. It */
5588 /* would be best if the error that the remote reports to the user is */
5589 /* the actual error we encountered, rather than some bogus unexpected */
5590 /* response type message. */
5591
5592 if (debug) {
5593 fprintf(where,"recv_xti_tcp_conn_rr: setting the response type...\n");
5594 fflush(where);
5595 }
5596
5597 netperf_response.content.response_type = XTI_TCP_CRR_RESPONSE;
5598
5599 if (debug) {
5600 fprintf(where,"recv_xti_tcp_conn_rr: the response type is set...\n");
5601 fflush(where);
5602 }
5603
5604 /* set-up the data buffer with the requested alignment and offset */
5605 message = (char *)malloc(DATABUFFERLEN);
5606 if (message == NULL) {
5607 printf("malloc(%d) failed!\n", DATABUFFERLEN);
5608 exit(1);
5609 }
5610
5611 /* We now alter the message_ptr variables to be at the desired */
5612 /* alignments with the desired offsets. */
5613
5614 if (debug) {
5615 fprintf(where,
5616 "recv_xti_tcp_conn_rr: requested recv alignment of %d offset %d\n",
5617 xti_tcp_conn_rr_request->recv_alignment,
5618 xti_tcp_conn_rr_request->recv_offset);
5619 fprintf(where,
5620 "recv_xti_tcp_conn_rr: requested send alignment of %d offset %d\n",
5621 xti_tcp_conn_rr_request->send_alignment,
5622 xti_tcp_conn_rr_request->send_offset);
5623 fflush(where);
5624 }
5625
5626 recv_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->recv_alignment, xti_tcp_conn_rr_request->recv_offset);
5627
5628 send_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->send_alignment, xti_tcp_conn_rr_request->send_offset);
5629
5630 if (debug) {
5631 fprintf(where,"recv_xti_tcp_conn_rr: receive alignment and offset set...\n");
5632 fflush(where);
5633 }
5634
5635 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
5636 /* can put in OUR values !-) At some point, we may want to nail this */
5637 /* socket to a particular network-level address, but for now, */
5638 /* INADDR_ANY should be just fine. */
5639
5640 bzero((char *)&myaddr_in,
5641 sizeof(myaddr_in));
5642 myaddr_in.sin_family = AF_INET;
5643 myaddr_in.sin_addr.s_addr = INADDR_ANY;
5644 myaddr_in.sin_port = 0;
5645
5646 /* Grab a socket to listen on, and then listen on it. */
5647
5648 if (debug) {
5649 fprintf(where,"recv_xti_tcp_conn_rr: grabbing a socket...\n");
5650 fflush(where);
5651 }
5652
5653 /* create_xti_endpoint expects to find some things in the global */
5654 /* variables, so set the globals based on the values in the request. */
5655 /* once the socket has been created, we will set the response values */
5656 /* based on the updated value of those globals. raj 7/94 */
5657 lss_size = xti_tcp_conn_rr_request->send_buf_size;
5658 lsr_size = xti_tcp_conn_rr_request->recv_buf_size;
5659 loc_nodelay = xti_tcp_conn_rr_request->no_delay;
5660 loc_rcvavoid = xti_tcp_conn_rr_request->so_rcvavoid;
5661 loc_sndavoid = xti_tcp_conn_rr_request->so_sndavoid;
5662
5663 s_listen = create_xti_endpoint(loc_xti_device);
5664
5665 if (s_listen == INVALID_SOCKET) {
5666 netperf_response.content.serv_errno = errno;
5667 send_response();
5668 if (debug) {
5669 fprintf(where,"could not create data socket\n");
5670 fflush(where);
5671 }
5672 exit(1);
5673 }
5674
5675 /* Let's get an address assigned to this socket so we can tell the */
5676 /* initiator how to reach the data socket. There may be a desire to */
5677 /* nail this socket to a specific IP address in a multi-homed, */
5678 /* multi-connection situation, but for now, we'll ignore the issue */
5679 /* and concentrate on single connection testing. */
5680
5681 if (bind(s_listen,
5682 (struct sockaddr *)&myaddr_in,
5683 sizeof(myaddr_in)) == SOCKET_ERROR) {
5684 netperf_response.content.serv_errno = errno;
5685 close(s_listen);
5686 send_response();
5687 if (debug) {
5688 fprintf(where,"could not bind\n");
5689 fflush(where);
5690 }
5691 exit(1);
5692 }
5693
5694 /* Now, let's set-up the socket to listen for connections */
5695 if (listen(s_listen, 5) == SOCKET_ERROR) {
5696 netperf_response.content.serv_errno = errno;
5697 close(s_listen);
5698 send_response();
5699 if (debug) {
5700 fprintf(where,"could not listen\n");
5701 fflush(where);
5702 }
5703 exit(1);
5704 }
5705
5706 /* now get the port number assigned by the system */
5707 addrlen = sizeof(myaddr_in);
5708 if (getsockname(s_listen,
5709 (struct sockaddr *)&myaddr_in,
5710 &addrlen) == SOCKET_ERROR){
5711 netperf_response.content.serv_errno = errno;
5712 close(s_listen);
5713 send_response();
5714 if (debug) {
5715 fprintf(where,"could not geetsockname\n");
5716 fflush(where);
5717 }
5718 exit(1);
5719 }
5720
5721 /* Now myaddr_in contains the port and the internet address this is */
5722 /* returned to the sender also implicitly telling the sender that the */
5723 /* socket buffer sizing has been done. */
5724
5725 xti_tcp_conn_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
5726 if (debug) {
5727 fprintf(where,"telling the remote to call me at %d\n",
5728 xti_tcp_conn_rr_response->data_port_number);
5729 fflush(where);
5730 }
5731 netperf_response.content.serv_errno = 0;
5732
5733 /* But wait, there's more. If the initiator wanted cpu measurements, */
5734 /* then we must call the calibrate routine, which will return the max */
5735 /* rate back to the initiator. If the CPU was not to be measured, or */
5736 /* something went wrong with the calibration, we will return a 0.0 to */
5737 /* the initiator. */
5738
5739 xti_tcp_conn_rr_response->cpu_rate = 0.0; /* assume no cpu */
5740 if (xti_tcp_conn_rr_request->measure_cpu) {
5741 xti_tcp_conn_rr_response->measure_cpu = 1;
5742 xti_tcp_conn_rr_response->cpu_rate =
5743 calibrate_local_cpu(xti_tcp_conn_rr_request->cpu_rate);
5744 }
5745
5746
5747
5748 /* before we send the response back to the initiator, pull some of */
5749 /* the socket parms from the globals */
5750 xti_tcp_conn_rr_response->send_buf_size = lss_size;
5751 xti_tcp_conn_rr_response->recv_buf_size = lsr_size;
5752 xti_tcp_conn_rr_response->no_delay = loc_nodelay;
5753 xti_tcp_conn_rr_response->so_rcvavoid = loc_rcvavoid;
5754 xti_tcp_conn_rr_response->so_sndavoid = loc_sndavoid;
5755
5756 send_response();
5757
5758 addrlen = sizeof(peeraddr_in);
5759
5760 /* Now it's time to start receiving data on the connection. We will */
5761 /* first grab the apropriate counters and then start grabbing. */
5762
5763 cpu_start(xti_tcp_conn_rr_request->measure_cpu);
5764
5765 /* The loop will exit when the sender does a shutdown, which will */
5766 /* return a length of zero */
5767
5768 if (xti_tcp_conn_rr_request->test_length > 0) {
5769 times_up = 0;
5770 trans_remaining = 0;
5771 start_timer(xti_tcp_conn_rr_request->test_length + PAD_TIME);
5772 }
5773 else {
5774 times_up = 1;
5775 trans_remaining = xti_tcp_conn_rr_request->test_length * -1;
5776 }
5777
5778 trans_received = 0;
5779
5780 while ((!times_up) || (trans_remaining > 0)) {
5781
5782 /* accept a connection from the remote */
5783 if ((s_data=accept(s_listen,
5784 (struct sockaddr *)&peeraddr_in,
5785 &addrlen)) == INVALID_SOCKET) {
5786 if (errno == EINTR) {
5787 /* the timer popped */
5788 timed_out = 1;
5789 break;
5790 }
5791 fprintf(where,"recv_xti_tcp_conn_rr: accept: errno = %d\n",errno);
5792 fflush(where);
5793 close(s_listen);
5794
5795 exit(1);
5796 }
5797
5798 if (debug) {
5799 fprintf(where,"recv_xti_tcp_conn_rr: accepted data connection.\n");
5800 fflush(where);
5801 }
5802
5803 temp_message_ptr = recv_message_ptr;
5804 request_bytes_remaining = xti_tcp_conn_rr_request->request_size;
5805
5806 /* receive the request from the other side */
5807 while(request_bytes_remaining > 0) {
5808 if((request_bytes_recvd=recv(s_data,
5809 temp_message_ptr,
5810 request_bytes_remaining,
5811 0)) == SOCKET_ERROR) {
5812 if (errno == EINTR) {
5813 /* the timer popped */
5814 timed_out = 1;
5815 break;
5816 }
5817 netperf_response.content.serv_errno = errno;
5818 send_response();
5819 exit(1);
5820 }
5821 else {
5822 request_bytes_remaining -= request_bytes_recvd;
5823 temp_message_ptr += request_bytes_recvd;
5824 }
5825 }
5826
5827 if (timed_out) {
5828 /* we hit the end of the test based on time - lets */
5829 /* bail out of here now... */
5830 fprintf(where,"yo5\n");
5831 fflush(where);
5832 break;
5833 }
5834
5835 /* Now, send the response to the remote */
5836 if((bytes_sent=send(s_data,
5837 send_message_ptr,
5838 xti_tcp_conn_rr_request->response_size,
5839 0)) == SOCKET_ERROR) {
5840 if (errno == EINTR) {
5841 /* the test timer has popped */
5842 timed_out = 1;
5843 fprintf(where,"yo6\n");
5844 fflush(where);
5845 break;
5846 }
5847 netperf_response.content.serv_errno = 99;
5848 send_response();
5849 exit(1);
5850 }
5851
5852 trans_received++;
5853 if (trans_remaining) {
5854 trans_remaining--;
5855 }
5856
5857 if (debug) {
5858 fprintf(where,
5859 "recv_xti_tcp_conn_rr: Transaction %d complete\n",
5860 trans_received);
5861 fflush(where);
5862 }
5863
5864 /* close the connection */
5865 close(s_data);
5866
5867 }
5868
5869
5870 /* The loop now exits due to timeout or transaction count being */
5871 /* reached */
5872
5873 cpu_stop(xti_tcp_conn_rr_request->measure_cpu,&elapsed_time);
5874
5875 if (timed_out) {
5876 /* we ended the test by time, which was at least 2 seconds */
5877 /* longer than we wanted to run. so, we want to subtract */
5878 /* PAD_TIME from the elapsed_time. */
5879 elapsed_time -= PAD_TIME;
5880 }
5881 /* send the results to the sender */
5882
5883 if (debug) {
5884 fprintf(where,
5885 "recv_xti_tcp_conn_rr: got %d transactions\n",
5886 trans_received);
5887 fflush(where);
5888 }
5889
5890 xti_tcp_conn_rr_results->bytes_received = (trans_received *
5891 (xti_tcp_conn_rr_request->request_size +
5892 xti_tcp_conn_rr_request->response_size));
5893 xti_tcp_conn_rr_results->trans_received = trans_received;
5894 xti_tcp_conn_rr_results->elapsed_time = elapsed_time;
5895 if (xti_tcp_conn_rr_request->measure_cpu) {
5896 xti_tcp_conn_rr_results->cpu_util = calc_cpu_util(elapsed_time);
5897 }
5898
5899 if (debug) {
5900 fprintf(where,
5901 "recv_xti_tcp_conn_rr: test complete, sending results.\n");
5902 fflush(where);
5903 }
5904
5905 send_response();
5906
5907}
5908
5909void
5910print_xti_usage()
5911{
5912
5913 fwrite(xti_usage, sizeof(char), strlen(xti_usage), stdout);
5914 exit(1);
5915
5916}
5917
5918void
5919scan_xti_args(int argc, char *argv[])
5920{
5921#define XTI_ARGS "Dhm:M:r:s:S:Vw:W:X:"
5922 extern int optind, opterrs; /* index of first unused arg */
5923 extern char *optarg; /* pointer to option string */
5924
5925 int c;
5926
5927 char
5928 arg1[BUFSIZ], /* argument holders */
5929 arg2[BUFSIZ];
5930
5931 if (no_control) {
5932 fprintf(where,
5933 "The XTI tests do not know how to run with no control connection\n");
5934 exit(-1);
5935 }
5936
5937 /* Go through all the command line arguments and break them */
5938 /* out. For those options that take two parms, specifying only */
5939 /* the first will set both to that value. Specifying only the */
5940 /* second will leave the first untouched. To change only the */
5941 /* first, use the form "first," (see the routine break_args.. */
5942
5943 while ((c= getopt(argc, argv, XTI_ARGS)) != EOF) {
5944 switch (c) {
5945 case '?':
5946 case 'h':
5947 print_xti_usage();
5948 exit(1);
5949 case 'D':
5950 /* set the TCP nodelay flag */
5951 loc_nodelay = 1;
5952 rem_nodelay = 1;
5953 break;
5954 case 's':
5955 /* set local socket sizes */
5956 break_args(optarg,arg1,arg2);
5957 if (arg1[0])
5958 lss_size = convert(arg1);
5959 if (arg2[0])
5960 lsr_size = convert(arg2);
5961 break;
5962 case 'S':
5963 /* set remote socket sizes */
5964 break_args(optarg,arg1,arg2);
5965 if (arg1[0])
5966 rss_size = convert(arg1);
5967 if (arg2[0])
5968 rsr_size = convert(arg2);
5969 break;
5970 case 'r':
5971 /* set the request/response sizes */
5972 break_args(optarg,arg1,arg2);
5973 if (arg1[0])
5974 req_size = convert(arg1);
5975 if (arg2[0])
5976 rsp_size = convert(arg2);
5977 break;
5978 case 'm':
5979 /* set the send size */
5980 send_size = convert(optarg);
5981 break;
5982 case 'M':
5983 /* set the recv size */
5984 recv_size = convert(optarg);
5985 break;
5986 case 'W':
5987 /* set the "width" of the user space data */
5988 /* buffer. This will be the number of */
5989 /* send_size buffers malloc'd in the */
5990 /* *_STREAM test. It may be enhanced to set */
5991 /* both send and receive "widths" but for now */
5992 /* it is just the sending *_STREAM. */
5993 send_width = convert(optarg);
5994 break;
5995 case 'V' :
5996 /* we want to do copy avoidance and will set */
5997 /* it for everything, everywhere, if we really */
5998 /* can. of course, we don't know anything */
5999 /* about the remote... */
6000#ifdef SO_SND_COPYAVOID
6001 loc_sndavoid = 1;
6002#else
6003 loc_sndavoid = 0;
6004 printf("Local send copy avoidance not available.\n");
6005#endif
6006#ifdef SO_RCV_COPYAVOID
6007 loc_rcvavoid = 1;
6008#else
6009 loc_rcvavoid = 0;
6010 printf("Local recv copy avoidance not available.\n");
6011#endif
6012 rem_sndavoid = 1;
6013 rem_rcvavoid = 1;
6014 break;
6015 case 'X':
6016 /* set the xti device file name(s) */
6017 break_args(optarg,arg1,arg2);
6018 if (arg1[0])
6019 strcpy(loc_xti_device,arg1);
6020 if (arg2[0])
6021 strcpy(rem_xti_device,arg2);
6022 break;
6023 };
6024 }
6025}
6026#endif /* WANT_XTI */