blob: e4716a40fb0fb78cd14011439277229992903790 [file] [log] [blame]
The Android Open Source Project02fb0ac2009-03-03 19:30:07 -08001#ifdef lint
2#define WANT_UNIX
3#define DIRTY
4#define WANT_INTERVALS
5#endif /* lint */
6
7#ifdef HAVE_CONFIG_H
8#include <config.h>
9#endif
10
11#ifdef WANT_UNIX
12char nettest_unix_id[]="\
13@(#)nettest_unix.c (c) Copyright 1994-2007 Hewlett-Packard Co. Version 2.4.3";
14
15/****************************************************************/
16/* */
17/* nettest_bsd.c */
18/* */
19/* the BSD sockets parsing routine... */
20/* */
21/* scan_unix_args() */
22/* */
23/* the actual test routines... */
24/* */
25/* send_stream_stream() perform a stream stream test */
26/* recv_stream_stream() */
27/* send_stream_rr() perform a stream request/response */
28/* recv_stream_rr() */
29/* send_dg_stream() perform a dg stream test */
30/* recv_dg_stream() */
31/* send_dg_rr() perform a dg request/response */
32/* recv_dg_rr() */
33/* loc_cpu_rate() determine the local cpu maxrate */
34/* rem_cpu_rate() find the remote cpu maxrate */
35/* */
36/****************************************************************/
37
38 /* at some point, I might want to go-in and see if I really need all */
39 /* these includes, but for the moment, we'll let them all just sit */
40 /* there. raj 8/94 */
41#include <sys/types.h>
42#include <fcntl.h>
43#include <stdio.h>
44#include <stdlib.h>
45#ifndef WIN32
46#include <sys/ipc.h>
47#include <sys/socket.h>
48#include <errno.h>
49#include <signal.h>
50#include <sys/un.h>
51#include <unistd.h>
52#else /* WIN32 */
53#include <process.h>
54#include <winsock2.h>
55#include <windows.h>
56#endif /* WIN32 */
57#include <string.h>
58#include <time.h>
59#include <sys/time.h>
60
61#ifdef NOSTDLIBH
62#include <malloc.h>
63#else /* NOSTDLIBH */
64#include <stdlib.h>
65#endif /* NOSTDLIBH */
66
67#include <sys/stat.h>
68
69
70#include "netlib.h"
71#include "netsh.h"
72#include "nettest_unix.h"
73
74
75
76 /* these variables are specific to the UNIX sockets tests. declare */
77 /* them static to make them global only to this file. */
78
79#define UNIX_PRFX "netperf."
80#define UNIX_LENGTH_MAX 0xFFFF - 28
81
82static char
83 path_prefix[32];
84
85static int
86 rss_size, /* remote socket send buffer size */
87 rsr_size, /* remote socket recv buffer size */
88 lss_size_req, /* requested local socket send buffer size */
89 lsr_size_req, /* requested local socket recv buffer size */
90 lss_size, /* local socket send buffer size */
91 lsr_size, /* local socket recv buffer size */
92 req_size = 1, /* request size */
93 rsp_size = 1, /* response size */
94 send_size, /* how big are individual sends */
95 recv_size; /* how big are individual receives */
96
97 /* different options for the sockets */
98
99
100char unix_usage[] = "\n\
101Usage: netperf [global options] -- [test options] \n\
102\n\
103STREAM/DG UNIX Sockets Test Options:\n\
104 -h Display this text\n\
105 -m bytes Set the send size (STREAM_STREAM, DG_STREAM)\n\
106 -M bytes Set the recv size (STREAM_STREAM, DG_STREAM)\n\
107 -p dir Set the directory where pipes are created\n\
108 -r req,res Set request,response size (STREAM_RR, DG_RR)\n\
109 -s send[,recv] Set local socket send/recv buffer sizes\n\
110 -S send[,recv] Set remote socket send/recv buffer sizes\n\
111\n\
112For those options taking two parms, at least one must be specified;\n\
113specifying one value without a comma will set both parms to that\n\
114value, specifying a value with a leading comma will set just the second\n\
115parm, a value with a trailing comma will set just the first. To set\n\
116each parm to unique values, specify both and separate them with a\n\
117comma.\n";
118
119 /* this routing initializes all the test specific variables */
120
121static void
122init_test_vars()
123{
124 rss_size = 0;
125 rsr_size = 0;
126 lss_size_req = 0;
127 lsr_size_req = 0;
128 lss_size = 0;
129 lsr_size = 0;
130 req_size = 1;
131 rsp_size = 1;
132 send_size = 0;
133 recv_size = 0;
134
135 strcpy(path_prefix,"/tmp");
136
137}
138
139 /* This routine will create a data (listen) socket with the apropriate */
140 /* options set and return it to the caller. this replaces all the */
141 /* duplicate code in each of the test routines and should help make */
142 /* things a little easier to understand. since this routine can be */
143 /* called by either the netperf or netserver programs, all output */
144 /* should be directed towards "where." family is generally AF_UNIX, */
145 /* and type will be either SOCK_STREAM or SOCK_DGRAM */
146SOCKET
147create_unix_socket(int family, int type)
148{
149
150 SOCKET temp_socket;
151 int sock_opt_len;
152
153 /*set up the data socket */
154 temp_socket = socket(family,
155 type,
156 0);
157
158 if (temp_socket == INVALID_SOCKET){
159 fprintf(where,
160 "netperf: create_unix_socket: socket: %d\n",
161 errno);
162 fflush(where);
163 exit(1);
164 }
165
166 if (debug) {
167 fprintf(where,"create_unix_socket: socket %d obtained...\n",temp_socket);
168 fflush(where);
169 }
170
171 /* Modify the local socket size. The reason we alter the send buffer */
172 /* size here rather than when the connection is made is to take care */
173 /* of decreases in buffer size. Decreasing the window size after */
174 /* connection establishment is a STREAM no-no. Also, by setting the */
175 /* buffer (window) size before the connection is established, we can */
176 /* control the STREAM MSS (segment size). The MSS is never more that 1/2 */
177 /* the minimum receive buffer size at each half of the connection. */
178 /* This is why we are altering the receive buffer size on the sending */
179 /* size of a unidirectional transfer. If the user has not requested */
180 /* that the socket buffers be altered, we will try to find-out what */
181 /* their values are. If we cannot touch the socket buffer in any way, */
182 /* we will set the values to -1 to indicate that. */
183
184 set_sock_buffer(temp_socket, SEND_BUFFER, lss_size_req, &lss_size);
185 set_sock_buffer(temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size);
186
187 return(temp_socket);
188
189}
190
191
192/* This routine implements the STREAM unidirectional data transfer test */
193/* (a.k.a. stream) for the sockets interface. It receives its */
194/* parameters via global variables from the shell and writes its */
195/* output to the standard output. */
196
197
198void
199send_stream_stream(char remote_host[])
200{
201
202 char *tput_title = "\
203Recv Send Send \n\
204Socket Socket Message Elapsed \n\
205Size Size Size Time Throughput \n\
206bytes bytes bytes secs. %s/sec \n\n";
207
208 char *tput_fmt_0 =
209 "%7.2f\n";
210
211 char *tput_fmt_1 =
212 "%5d %5d %6d %-6.2f %7.2f \n";
213
214 char *cpu_title = "\
215Recv Send Send Utilization Service Demand\n\
216Socket Socket Message Elapsed Send Recv Send Recv\n\
217Size Size Size Time Throughput local remote local remote\n\
218bytes bytes bytes secs. %-8.8s/s %% %% us/KB us/KB\n\n";
219
220 char *cpu_fmt_0 =
221 "%6.3f\n";
222
223 char *cpu_fmt_1 =
224 "%5d %5d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
225
226 char *ksink_fmt = "\n\
227Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
228Local Remote Local Remote Xfered Per Per\n\
229Send Recv Send Recv Send (avg) Recv (avg)\n\
230%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
231
232
233 float elapsed_time;
234
235#ifdef WANT_INTERVALS
236 int interval_count;
237#endif
238
239 /* what we want is to have a buffer space that is at least one */
240 /* send-size greater than our send window. this will insure that we */
241 /* are never trying to re-use a buffer that may still be in the hands */
242 /* of the transport. This buffer will be malloc'd after we have found */
243 /* the size of the local senc socket buffer. We will want to deal */
244 /* with alignment and offset concerns as well. */
245
246#ifdef DIRTY
247 int *message_int_ptr;
248#endif
249#include <sys/stat.h>
250
251 struct ring_elt *send_ring;
252
253 int len = 0;
254 int nummessages;
255 SOCKET send_socket;
256 int bytes_remaining;
257 /* with links like fddi, one can send > 32 bits worth of bytes */
258 /* during a test... ;-) */
259 double bytes_sent;
260
261#ifdef DIRTY
262 int i;
263#endif /* DIRTY */
264
265 float local_cpu_utilization;
266 float local_service_demand;
267 float remote_cpu_utilization;
268 float remote_service_demand;
269 double thruput;
270
271 struct sockaddr_un server;
272
273 struct stream_stream_request_struct *stream_stream_request;
274 struct stream_stream_response_struct *stream_stream_response;
275 struct stream_stream_results_struct *stream_stream_result;
276
277 stream_stream_request =
278 (struct stream_stream_request_struct *)netperf_request.content.test_specific_data;
279 stream_stream_response =
280 (struct stream_stream_response_struct *)netperf_response.content.test_specific_data;
281 stream_stream_result =
282 (struct stream_stream_results_struct *)netperf_response.content.test_specific_data;
283
284 /* since we are now disconnected from the code that established the */
285 /* control socket, and since we want to be able to use different */
286 /* protocols and such, we are passed the name of the remote host and */
287 /* must turn that into the test specific addressing information. */
288
289 bzero((char *)&server,
290 sizeof(server));
291 server.sun_family = AF_UNIX;
292
293
294 if ( print_headers ) {
295 fprintf(where,"STREAM STREAM TEST\n");
296 if (local_cpu_usage || remote_cpu_usage)
297 fprintf(where,cpu_title,format_units());
298 else
299 fprintf(where,tput_title,format_units());
300 }
301
302 /* initialize a few counters */
303
304 nummessages = 0;
305 bytes_sent = 0.0;
306 times_up = 0;
307
308 /*set up the data socket */
309 send_socket = create_unix_socket(AF_UNIX,
310 SOCK_STREAM);
311
312 if (send_socket == INVALID_SOCKET){
313 perror("netperf: send_stream_stream: stream stream data socket");
314 exit(1);
315 }
316
317 if (debug) {
318 fprintf(where,"send_stream_stream: send_socket obtained...\n");
319 }
320
321 /* at this point, we have either retrieved the socket buffer sizes, */
322 /* or have tried to set them, so now, we may want to set the send */
323 /* size based on that (because the user either did not use a -m */
324 /* option, or used one with an argument of 0). If the socket buffer */
325 /* size is not available, we will set the send size to 4KB - no */
326 /* particular reason, just arbitrary... */
327 if (send_size == 0) {
328 if (lss_size > 0) {
329 send_size = lss_size;
330 }
331 else {
332 send_size = 4096;
333 }
334 }
335
336 /* set-up the data buffer ring with the requested alignment and offset. */
337 /* note also that we have allocated a quantity */
338 /* of memory that is at least one send-size greater than our socket */
339 /* buffer size. We want to be sure that there are at least two */
340 /* buffers allocated - this can be a bit of a problem when the */
341 /* send_size is bigger than the socket size, so we must check... the */
342 /* user may have wanted to explicitly set the "width" of our send */
343 /* buffers, we should respect that wish... */
344 if (send_width == 0) {
345 send_width = (lss_size/send_size) + 1;
346 if (send_width == 1) send_width++;
347 }
348
349 send_ring = allocate_buffer_ring(send_width,
350 send_size,
351 local_send_align,
352 local_send_offset);
353
354 /* If the user has requested cpu utilization measurements, we must */
355 /* calibrate the cpu(s). We will perform this task within the tests */
356 /* themselves. If the user has specified the cpu rate, then */
357 /* calibrate_local_cpu will return rather quickly as it will have */
358 /* nothing to do. If local_cpu_rate is zero, then we will go through */
359 /* all the "normal" calibration stuff and return the rate back.*/
360
361 if (local_cpu_usage) {
362 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
363 }
364
365 /* Tell the remote end to do a listen. The server alters the socket */
366 /* paramters on the other side at this point, hence the reason for */
367 /* all the values being passed in the setup message. If the user did */
368 /* not specify any of the parameters, they will be passed as 0, which */
369 /* will indicate to the remote that no changes beyond the system's */
370 /* default should be used. Alignment is the exception, it will */
371 /* default to 1, which will be no alignment alterations. */
372
373 netperf_request.content.request_type = DO_STREAM_STREAM;
374 stream_stream_request->send_buf_size = rss_size;
375 stream_stream_request->recv_buf_size = rsr_size;
376 stream_stream_request->receive_size = recv_size;
377 stream_stream_request->recv_alignment = remote_recv_align;
378 stream_stream_request->recv_offset = remote_recv_offset;
379 stream_stream_request->measure_cpu = remote_cpu_usage;
380 stream_stream_request->cpu_rate = remote_cpu_rate;
381 if (test_time) {
382 stream_stream_request->test_length = test_time;
383 }
384 else {
385 stream_stream_request->test_length = test_bytes;
386 }
387#ifdef DIRTY
388 stream_stream_request->dirty_count = rem_dirty_count;
389 stream_stream_request->clean_count = rem_clean_count;
390#endif /* DIRTY */
391
392
393 if (debug > 1) {
394 fprintf(where,
395 "netperf: send_stream_stream: requesting STREAM stream test\n");
396 }
397
398 send_request();
399
400 /* The response from the remote will contain all of the relevant */
401 /* socket parameters for this test type. We will put them back into */
402 /* the variables here so they can be displayed if desired. The */
403 /* remote will have calibrated CPU if necessary, and will have done */
404 /* all the needed set-up we will have calibrated the cpu locally */
405 /* before sending the request, and will grab the counter value right */
406 /* after the connect returns. The remote will grab the counter right */
407 /* after the accept call. This saves the hassle of extra messages */
408 /* being sent for the STREAM tests. */
409
410 recv_response();
411
412 if (!netperf_response.content.serv_errno) {
413 if (debug)
414 fprintf(where,"remote listen done.\n");
415 rsr_size = stream_stream_response->recv_buf_size;
416 rss_size = stream_stream_response->send_buf_size;
417 remote_cpu_usage = stream_stream_response->measure_cpu;
418 remote_cpu_rate = stream_stream_response->cpu_rate;
419 strcpy(server.sun_path,stream_stream_response->unix_path);
420 }
421 else {
422 Set_errno(netperf_response.content.serv_errno);
423 perror("netperf: send_stream_stream: remote error");
424 exit(1);
425 }
426
427 /*Connect up to the remote port on the data socket */
428 if (connect(send_socket,
429 (struct sockaddr *)&server,
430 sizeof(server)) == INVALID_SOCKET){
431 perror("netperf: send_stream_stream: data socket connect failed");
432 printf(" path: %s\n",server.sun_path);
433 exit(1);
434 }
435
436 /* Data Socket set-up is finished. If there were problems, either the */
437 /* connect would have failed, or the previous response would have */
438 /* indicated a problem. I failed to see the value of the extra */
439 /* message after the accept on the remote. If it failed, we'll see it */
440 /* here. If it didn't, we might as well start pumping data. */
441
442 /* Set-up the test end conditions. For a stream test, they can be */
443 /* either time or byte-count based. */
444
445 if (test_time) {
446 /* The user wanted to end the test after a period of time. */
447 times_up = 0;
448 bytes_remaining = 0;
449 start_timer(test_time);
450 }
451 else {
452 /* The tester wanted to send a number of bytes. */
453 bytes_remaining = test_bytes;
454 times_up = 1;
455 }
456
457 /* The cpu_start routine will grab the current time and possibly */
458 /* value of the idle counter for later use in measuring cpu */
459 /* utilization and/or service demand and thruput. */
460
461 cpu_start(local_cpu_usage);
462
463 /* We use an "OR" to control test execution. When the test is */
464 /* controlled by time, the byte count check will always return false. */
465 /* When the test is controlled by byte count, the time test will */
466 /* always return false. When the test is finished, the whole */
467 /* expression will go false and we will stop sending data. */
468
469#ifdef DIRTY
470 /* initialize the random number generator for putting dirty stuff */
471 /* into the send buffer. raj */
472 srand((int) getpid());
473#endif
474
475 while ((!times_up) || (bytes_remaining > 0)) {
476
477#ifdef DIRTY
478 /* we want to dirty some number of consecutive integers in the buffer */
479 /* we are about to send. we may also want to bring some number of */
480 /* them cleanly into the cache. The clean ones will follow any dirty */
481 /* ones into the cache. at some point, we might want to replace */
482 /* the rand() call with something from a table to reduce our call */
483 /* overhead during the test, but it is not a high priority item. */
484 message_int_ptr = (int *)(send_ring->buffer_ptr);
485 for (i = 0; i < loc_dirty_count; i++) {
486 *message_int_ptr = rand();
487 message_int_ptr++;
488 }
489 for (i = 0; i < loc_clean_count; i++) {
490 loc_dirty_count = *message_int_ptr;
491 message_int_ptr++;
492 }
493#endif /* DIRTY */
494
495 if((len=send(send_socket,
496 send_ring->buffer_ptr,
497 send_size,
498 0)) != send_size) {
499 if ((len >=0) || (errno == EINTR)) {
500 /* the test was interrupted, must be the end of test */
501 break;
502 }
503 perror("netperf: data send error");
504 printf("len was %d\n",len);
505 exit(1);
506 }
507#ifdef WANT_INTERVALS
508 for (interval_count = 0;
509 interval_count < interval_wate;
510 interval_count++);
511#endif
512
513 /* now we want to move our pointer to the next position in the */
514 /* data buffer...we may also want to wrap back to the "beginning" */
515 /* of the bufferspace, so we will mod the number of messages sent */
516 /* by the send width, and use that to calculate the offset to add */
517 /* to the base pointer. */
518 nummessages++;
519 send_ring = send_ring->next;
520 if (bytes_remaining) {
521 bytes_remaining -= send_size;
522 }
523 }
524
525 /* The test is over. Flush the buffers to the remote end. We do a */
526 /* graceful release to insure that all data has been taken by the */
527 /* remote. */
528
529 if (close(send_socket) == -1) {
530 perror("netperf: send_stream_stream: cannot close socket");
531 exit(1);
532 }
533
534 /* this call will always give us the elapsed time for the test, and */
535 /* will also store-away the necessaries for cpu utilization */
536
537 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
538 /* measured and how */
539 /* long did we really */
540 /* run? */
541
542 /* Get the statistics from the remote end. The remote will have */
543 /* calculated service demand and all those interesting things. If it */
544 /* wasn't supposed to care, it will return obvious values. */
545
546 recv_response();
547 if (!netperf_response.content.serv_errno) {
548 if (debug)
549 fprintf(where,"remote results obtained\n");
550 }
551 else {
552 Set_errno(netperf_response.content.serv_errno);
553 perror("netperf: remote error");
554
555 exit(1);
556 }
557
558 /* We now calculate what our thruput was for the test. In the future, */
559 /* we may want to include a calculation of the thruput measured by */
560 /* the remote, but it should be the case that for a STREAM stream test, */
561 /* that the two numbers should be *very* close... We calculate */
562 /* bytes_sent regardless of the way the test length was controlled. */
563 /* If it was time, we needed to, and if it was by bytes, the user may */
564 /* have specified a number of bytes that wasn't a multiple of the */
565 /* send_size, so we really didn't send what he asked for ;-) */
566
567 bytes_sent = ((double) send_size * (double) nummessages) + len;
568 thruput = calc_thruput(bytes_sent);
569
570 if (local_cpu_usage || remote_cpu_usage) {
571 /* We must now do a little math for service demand and cpu */
572 /* utilization for the system(s) */
573 /* Of course, some of the information might be bogus because */
574 /* there was no idle counter in the kernel(s). We need to make */
575 /* a note of this for the user's benefit...*/
576 if (local_cpu_usage) {
577 if (local_cpu_rate == 0.0) {
578 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
579 fprintf(where,"Local CPU usage numbers based on process information only!\n");
580 fflush(where);
581 }
582 local_cpu_utilization = calc_cpu_util(0.0);
583 local_service_demand = calc_service_demand(bytes_sent,
584 0.0,
585 0.0,
586 0);
587 }
588 else {
589 local_cpu_utilization = -1.0;
590 local_service_demand = -1.0;
591 }
592
593 if (remote_cpu_usage) {
594 if (remote_cpu_rate == 0.0) {
595 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
596 fprintf(where,"Remote CPU usage numbers based on process information only!\n");
597 fflush(where);
598 }
599 remote_cpu_utilization = stream_stream_result->cpu_util;
600 remote_service_demand = calc_service_demand(bytes_sent,
601 0.0,
602 remote_cpu_utilization,
603 stream_stream_result->num_cpus);
604 }
605 else {
606 remote_cpu_utilization = -1.0;
607 remote_service_demand = -1.0;
608 }
609
610 /* We are now ready to print all the information. If the user */
611 /* has specified zero-level verbosity, we will just print the */
612 /* local service demand, or the remote service demand. If the */
613 /* user has requested verbosity level 1, he will get the basic */
614 /* "streamperf" numbers. If the user has specified a verbosity */
615 /* of greater than 1, we will display a veritable plethora of */
616 /* background information from outside of this block as it it */
617 /* not cpu_measurement specific... */
618
619 switch (verbosity) {
620 case 0:
621 if (local_cpu_usage) {
622 fprintf(where,
623 cpu_fmt_0,
624 local_service_demand);
625 }
626 else {
627 fprintf(where,
628 cpu_fmt_0,
629 remote_service_demand);
630 }
631 break;
632 case 1:
633 case 2:
634 fprintf(where,
635 cpu_fmt_1, /* the format string */
636 rsr_size, /* remote recvbuf size */
637 lss_size, /* local sendbuf size */
638 send_size, /* how large were the sends */
639 elapsed_time, /* how long was the test */
640 thruput, /* what was the xfer rate */
641 local_cpu_utilization, /* local cpu */
642 remote_cpu_utilization, /* remote cpu */
643 local_service_demand, /* local service demand */
644 remote_service_demand); /* remote service demand */
645 break;
646 }
647 }
648 else {
649 /* The tester did not wish to measure service demand. */
650 switch (verbosity) {
651 case 0:
652 fprintf(where,
653 tput_fmt_0,
654 thruput);
655 break;
656 case 1:
657 case 2:
658 fprintf(where,
659 tput_fmt_1, /* the format string */
660 rsr_size, /* remote recvbuf size */
661 lss_size, /* local sendbuf size */
662 send_size, /* how large were the sends */
663 elapsed_time, /* how long did it take */
664 thruput);/* how fast did it go */
665 break;
666 }
667 }
668
669 /* it would be a good thing to include information about some of the */
670 /* other parameters that may have been set for this test, but at the */
671 /* moment, I do not wish to figure-out all the formatting, so I will */
672 /* just put this comment here to help remind me that it is something */
673 /* that should be done at a later time. */
674
675 if (verbosity > 1) {
676 /* The user wanted to know it all, so we will give it to him. */
677 /* This information will include as much as we can find about */
678 /* STREAM statistics, the alignments of the sends and receives */
679 /* and all that sort of rot... */
680
681 fprintf(where,
682 ksink_fmt,
683 "Bytes",
684 "Bytes",
685 "Bytes",
686 local_send_align,
687 remote_recv_align,
688 local_send_offset,
689 remote_recv_offset,
690 bytes_sent,
691 bytes_sent / (double)nummessages,
692 nummessages,
693 bytes_sent / (double)stream_stream_result->recv_calls,
694 stream_stream_result->recv_calls);
695 }
696
697}
698
699
700/* This is the server-side routine for the stream stream test. It is */
701/* implemented as one routine. I could break things-out somewhat, but */
702/* didn't feel it was necessary. */
703
704void
705recv_stream_stream()
706{
707
708 struct sockaddr_un myaddr_un, peeraddr_un;
709 SOCKET s_listen,s_data;
710 int addrlen;
711 int len;
712 int receive_calls = 0;
713 float elapsed_time;
714 int bytes_received;
715
716 struct ring_elt *recv_ring;
717
718#ifdef DIRTY
719 char *message_ptr;
720 int *message_int_ptr;
721 int dirty_count;
722 int clean_count;
723 int i;
724#endif
725
726 struct stream_stream_request_struct *stream_stream_request;
727 struct stream_stream_response_struct *stream_stream_response;
728 struct stream_stream_results_struct *stream_stream_results;
729
730 stream_stream_request =
731 (struct stream_stream_request_struct *)netperf_request.content.test_specific_data;
732 stream_stream_response =
733 (struct stream_stream_response_struct *)netperf_response.content.test_specific_data;
734 stream_stream_results =
735 (struct stream_stream_results_struct *)netperf_response.content.test_specific_data;
736
737 if (debug) {
738 fprintf(where,"netserver: recv_stream_stream: entered...\n");
739 fflush(where);
740 }
741
742 /* We want to set-up the listen socket with all the desired */
743 /* parameters and then let the initiator know that all is ready. If */
744 /* socket size defaults are to be used, then the initiator will have */
745 /* sent us 0's. If the socket sizes cannot be changed, then we will */
746 /* send-back what they are. If that information cannot be determined, */
747 /* then we send-back -1's for the sizes. If things go wrong for any */
748 /* reason, we will drop back ten yards and punt. */
749
750 /* If anything goes wrong, we want the remote to know about it. It */
751 /* would be best if the error that the remote reports to the user is */
752 /* the actual error we encountered, rather than some bogus unexpected */
753 /* response type message. */
754
755 if (debug) {
756 fprintf(where,"recv_stream_stream: setting the response type...\n");
757 fflush(where);
758 }
759
760 netperf_response.content.response_type = STREAM_STREAM_RESPONSE;
761
762 if (debug) {
763 fprintf(where,"recv_stream_stream: the response type is set...\n");
764 fflush(where);
765 }
766
767 /* We now alter the message_ptr variable to be at the desired */
768 /* alignment with the desired offset. */
769
770 if (debug) {
771 fprintf(where,"recv_stream_stream: requested alignment of %d\n",
772 stream_stream_request->recv_alignment);
773 fflush(where);
774 }
775
776 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
777 /* can put in OUR values !-) At some point, we may want to nail this */
778 /* socket to a particular network-level address, but for now, */
779 /* INADDR_ANY should be just fine. */
780
781 bzero((char *)&myaddr_un,
782 sizeof(myaddr_un));
783 myaddr_un.sun_family = AF_UNIX;
784
785 /* Grab a socket to listen on, and then listen on it. */
786
787 if (debug) {
788 fprintf(where,"recv_stream_stream: grabbing a socket...\n");
789 fflush(where);
790 }
791
792 /* create_unix_socket expects to find some things in the global */
793 /* variables, so set the globals based on the values in the request. */
794 /* once the socket has been created, we will set the response values */
795 /* based on the updated value of those globals. raj 7/94 */
796 lss_size_req = stream_stream_request->send_buf_size;
797 lsr_size_req = stream_stream_request->recv_buf_size;
798
799 s_listen = create_unix_socket(AF_UNIX,
800 SOCK_STREAM);
801
802 if (s_listen == INVALID_SOCKET) {
803 netperf_response.content.serv_errno = errno;
804 send_response();
805 exit(1);
806 }
807
808 /* Let's get an address assigned to this socket so we can tell the */
809 /* initiator how to reach the data socket. There may be a desire to */
810 /* nail this socket to a specific IP address in a multi-homed, */
811 /* multi-connection situation, but for now, we'll ignore the issue */
812 /* and concentrate on single connection testing. */
813
814 strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf."));
815 if (debug) {
816 fprintf(where,"selected a path of %s\n",myaddr_un.sun_path);
817 fflush(where);
818 }
819 if (bind(s_listen,
820 (struct sockaddr *)&myaddr_un,
821 sizeof(myaddr_un)) == SOCKET_ERROR) {
822 netperf_response.content.serv_errno = errno;
823 fprintf(where,"could not bind to path\n");
824 close(s_listen);
825 send_response();
826
827 exit(1);
828 }
829
830 chmod(myaddr_un.sun_path, 0666);
831
832 /* what sort of sizes did we end-up with? */
833 if (stream_stream_request->receive_size == 0) {
834 if (lsr_size > 0) {
835 recv_size = lsr_size;
836 }
837 else {
838 recv_size = 4096;
839 }
840 }
841 else {
842 recv_size = stream_stream_request->receive_size;
843 }
844
845 /* we want to set-up our recv_ring in a manner analagous to what we */
846 /* do on the sending side. this is more for the sake of symmetry */
847 /* than for the needs of say copy avoidance, but it might also be */
848 /* more realistic - this way one could conceivably go with a */
849 /* double-buffering scheme when taking the data an putting it into */
850 /* the filesystem or something like that. raj 7/94 */
851
852 if (recv_width == 0) {
853 recv_width = (lsr_size/recv_size) + 1;
854 if (recv_width == 1) recv_width++;
855 }
856
857 recv_ring = allocate_buffer_ring(recv_width,
858 recv_size,
859 stream_stream_request->recv_alignment,
860 stream_stream_request->recv_offset);
861
862 if (debug) {
863 fprintf(where,"recv_stream_stream: receive alignment and offset set...\n");
864 fflush(where);
865 }
866
867 /* Now, let's set-up the socket to listen for connections */
868 if (listen(s_listen, 5) == SOCKET_ERROR) {
869 netperf_response.content.serv_errno = errno;
870 close(s_listen);
871 send_response();
872
873 exit(1);
874 }
875
876 /* now get the port number assigned by the system */
877 addrlen = sizeof(myaddr_un);
878 if (getsockname(s_listen,
879 (struct sockaddr *)&myaddr_un,
880 &addrlen) == SOCKET_ERROR){
881 netperf_response.content.serv_errno = errno;
882 close(s_listen);
883 send_response();
884
885 exit(1);
886 }
887
888 /* Now myaddr_un contains the path */
889 /* returned to the sender also implicitly telling the sender that the */
890 /* socket buffer sizing has been done. */
891 strcpy(stream_stream_response->unix_path,myaddr_un.sun_path);
892 netperf_response.content.serv_errno = 0;
893
894 /* But wait, there's more. If the initiator wanted cpu measurements, */
895 /* then we must call the calibrate routine, which will return the max */
896 /* rate back to the initiator. If the CPU was not to be measured, or */
897 /* something went wrong with the calibration, we will return a -1 to */
898 /* the initiator. */
899
900 stream_stream_response->cpu_rate = 0.0; /* assume no cpu */
901 if (stream_stream_request->measure_cpu) {
902 stream_stream_response->measure_cpu = 1;
903 stream_stream_response->cpu_rate =
904 calibrate_local_cpu(stream_stream_request->cpu_rate);
905 }
906
907 /* before we send the response back to the initiator, pull some of */
908 /* the socket parms from the globals */
909 stream_stream_response->send_buf_size = lss_size;
910 stream_stream_response->recv_buf_size = lsr_size;
911 stream_stream_response->receive_size = recv_size;
912
913 send_response();
914
915 addrlen = sizeof(peeraddr_un);
916
917 if ((s_data=accept(s_listen,
918 (struct sockaddr *)&peeraddr_un,
919 &addrlen)) == INVALID_SOCKET) {
920 /* Let's just punt. The remote will be given some information */
921 close(s_listen);
922 exit(1);
923 }
924
925 /* Now it's time to start receiving data on the connection. We will */
926 /* first grab the apropriate counters and then start grabbing. */
927
928 cpu_start(stream_stream_request->measure_cpu);
929
930 /* The loop will exit when the sender does a shutdown, which will */
931 /* return a length of zero */
932
933#ifdef DIRTY
934 /* we want to dirty some number of consecutive integers in the buffer */
935 /* we are about to recv. we may also want to bring some number of */
936 /* them cleanly into the cache. The clean ones will follow any dirty */
937 /* ones into the cache. */
938
939 dirty_count = stream_stream_request->dirty_count;
940 clean_count = stream_stream_request->clean_count;
941 message_int_ptr = (int *)recv_ring->buffer_ptr;
942 for (i = 0; i < dirty_count; i++) {
943 *message_int_ptr = rand();
944 message_int_ptr++;
945 }
946 for (i = 0; i < clean_count; i++) {
947 dirty_count = *message_int_ptr;
948 message_int_ptr++;
949 }
950#endif /* DIRTY */
951 bytes_received = 0;
952
953 while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) {
954 if (len == SOCKET_ERROR) {
955 netperf_response.content.serv_errno = errno;
956 send_response();
957 exit(1);
958 }
959 bytes_received += len;
960 receive_calls++;
961
962 /* more to the next buffer in the recv_ring */
963 recv_ring = recv_ring->next;
964
965#ifdef DIRTY
966 message_int_ptr = (int *)(recv_ring->buffer_ptr);
967 for (i = 0; i < dirty_count; i++) {
968 *message_int_ptr = rand();
969 message_int_ptr++;
970 }
971 for (i = 0; i < clean_count; i++) {
972 dirty_count = *message_int_ptr;
973 message_int_ptr++;
974 }
975#endif /* DIRTY */
976 }
977
978 /* The loop now exits due to zero bytes received. we will have */
979 /* counted one too many messages received, so decrement the */
980 /* receive_calls counter by one. raj 7/94 */
981 receive_calls--;
982
983 /* perform a shutdown to signal the sender that */
984 /* we have received all the data sent. raj 4/93 */
985
986 if (shutdown(s_data,1) == SOCKET_ERROR) {
987 netperf_response.content.serv_errno = errno;
988 send_response();
989 exit(1);
990 }
991
992 cpu_stop(stream_stream_request->measure_cpu,&elapsed_time);
993
994 /* send the results to the sender */
995
996 if (debug) {
997 fprintf(where,
998 "recv_stream_stream: got %d bytes\n",
999 bytes_received);
1000 fprintf(where,
1001 "recv_stream_stream: got %d recvs\n",
1002 receive_calls);
1003 fflush(where);
1004 }
1005
1006 stream_stream_results->bytes_received = bytes_received;
1007 stream_stream_results->elapsed_time = elapsed_time;
1008 stream_stream_results->recv_calls = receive_calls;
1009
1010 if (stream_stream_request->measure_cpu) {
1011 stream_stream_results->cpu_util = calc_cpu_util(0.0);
1012 };
1013
1014 if (debug > 1) {
1015 fprintf(where,
1016 "recv_stream_stream: test complete, sending results.\n");
1017 fflush(where);
1018 }
1019
1020 send_response();
1021 unlink(myaddr_un.sun_path);
1022}
1023
1024
1025 /* this routine implements the sending (netperf) side of the STREAM_RR */
1026 /* test. */
1027
1028void
1029send_stream_rr(char remote_host[])
1030{
1031
1032 char *tput_title = "\
1033Local /Remote\n\
1034Socket Size Request Resp. Elapsed Trans.\n\
1035Send Recv Size Size Time Rate \n\
1036bytes Bytes bytes bytes secs. per sec \n\n";
1037
1038 char *tput_fmt_0 =
1039 "%7.2f\n";
1040
1041 char *tput_fmt_1_line_1 = "\
1042%-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
1043 char *tput_fmt_1_line_2 = "\
1044%-6d %-6d\n";
1045
1046 char *cpu_title = "\
1047Local /Remote\n\
1048Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
1049Send Recv Size Size Time Rate local remote local remote\n\
1050bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
1051
1052 char *cpu_fmt_0 =
1053 "%6.3f\n";
1054
1055 char *cpu_fmt_1_line_1 = "\
1056%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
1057
1058 char *cpu_fmt_1_line_2 = "\
1059%-6d %-6d\n";
1060
1061 char *ksink_fmt = "\
1062Alignment Offset\n\
1063Local Remote Local Remote\n\
1064Send Recv Send Recv\n\
1065%5d %5d %5d %5d\n";
1066
1067
1068 int timed_out = 0;
1069 float elapsed_time;
1070
1071 int len;
1072 char *temp_message_ptr;
1073 int nummessages;
1074 SOCKET send_socket;
1075 int trans_remaining;
1076 double bytes_xferd;
1077
1078 struct ring_elt *send_ring;
1079 struct ring_elt *recv_ring;
1080
1081 int rsp_bytes_left;
1082 int rsp_bytes_recvd;
1083
1084 float local_cpu_utilization;
1085 float local_service_demand;
1086 float remote_cpu_utilization;
1087 float remote_service_demand;
1088 double thruput;
1089
1090 struct sockaddr_un server;
1091
1092 struct stream_rr_request_struct *stream_rr_request;
1093 struct stream_rr_response_struct *stream_rr_response;
1094 struct stream_rr_results_struct *stream_rr_result;
1095
1096 stream_rr_request =
1097 (struct stream_rr_request_struct *)netperf_request.content.test_specific_data;
1098 stream_rr_response=
1099 (struct stream_rr_response_struct *)netperf_response.content.test_specific_data;
1100 stream_rr_result =
1101 (struct stream_rr_results_struct *)netperf_response.content.test_specific_data;
1102
1103 /* since we are now disconnected from the code that established the */
1104 /* control socket, and since we want to be able to use different */
1105 /* protocols and such, we are passed the name of the remote host and */
1106 /* must turn that into the test specific addressing information. */
1107
1108 bzero((char *)&server,
1109 sizeof(server));
1110
1111 server.sun_family = AF_UNIX;
1112
1113
1114 if ( print_headers ) {
1115 fprintf(where,"STREAM REQUEST/RESPONSE TEST\n");
1116 if (local_cpu_usage || remote_cpu_usage)
1117 fprintf(where,cpu_title,format_units());
1118 else
1119 fprintf(where,tput_title,format_units());
1120 }
1121
1122 /* initialize a few counters */
1123
1124 nummessages = 0;
1125 bytes_xferd = 0.0;
1126 times_up = 0;
1127
1128 /* set-up the data buffers with the requested alignment and offset. */
1129 /* since this is a request/response test, default the send_width and */
1130 /* recv_width to 1 and not two raj 7/94 */
1131
1132 if (send_width == 0) send_width = 1;
1133 if (recv_width == 0) recv_width = 1;
1134
1135 send_ring = allocate_buffer_ring(send_width,
1136 req_size,
1137 local_send_align,
1138 local_send_offset);
1139
1140 recv_ring = allocate_buffer_ring(recv_width,
1141 rsp_size,
1142 local_recv_align,
1143 local_recv_offset);
1144
1145 /*set up the data socket */
1146 send_socket = create_unix_socket(AF_UNIX,
1147 SOCK_STREAM);
1148
1149 if (send_socket == INVALID_SOCKET){
1150 perror("netperf: send_stream_rr: stream stream data socket");
1151 exit(1);
1152 }
1153
1154 if (debug) {
1155 fprintf(where,"send_stream_rr: send_socket obtained...\n");
1156 }
1157
1158 /* If the user has requested cpu utilization measurements, we must */
1159 /* calibrate the cpu(s). We will perform this task within the tests */
1160 /* themselves. If the user has specified the cpu rate, then */
1161 /* calibrate_local_cpu will return rather quickly as it will have */
1162 /* nothing to do. If local_cpu_rate is zero, then we will go through */
1163 /* all the "normal" calibration stuff and return the rate back.*/
1164
1165 if (local_cpu_usage) {
1166 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1167 }
1168
1169 /* Tell the remote end to do a listen. The server alters the socket */
1170 /* paramters on the other side at this point, hence the reason for */
1171 /* all the values being passed in the setup message. If the user did */
1172 /* not specify any of the parameters, they will be passed as 0, which */
1173 /* will indicate to the remote that no changes beyond the system's */
1174 /* default should be used. Alignment is the exception, it will */
1175 /* default to 8, which will be no alignment alterations. */
1176
1177 netperf_request.content.request_type = DO_STREAM_RR;
1178 stream_rr_request->recv_buf_size = rsr_size;
1179 stream_rr_request->send_buf_size = rss_size;
1180 stream_rr_request->recv_alignment= remote_recv_align;
1181 stream_rr_request->recv_offset = remote_recv_offset;
1182 stream_rr_request->send_alignment= remote_send_align;
1183 stream_rr_request->send_offset = remote_send_offset;
1184 stream_rr_request->request_size = req_size;
1185 stream_rr_request->response_size = rsp_size;
1186 stream_rr_request->measure_cpu = remote_cpu_usage;
1187 stream_rr_request->cpu_rate = remote_cpu_rate;
1188 if (test_time) {
1189 stream_rr_request->test_length = test_time;
1190 }
1191 else {
1192 stream_rr_request->test_length = test_trans * -1;
1193 }
1194
1195 if (debug > 1) {
1196 fprintf(where,"netperf: send_stream_rr: requesting STREAM rr test\n");
1197 }
1198
1199 send_request();
1200
1201 /* The response from the remote will contain all of the relevant */
1202 /* socket parameters for this test type. We will put them back into */
1203 /* the variables here so they can be displayed if desired. The */
1204 /* remote will have calibrated CPU if necessary, and will have done */
1205 /* all the needed set-up we will have calibrated the cpu locally */
1206 /* before sending the request, and will grab the counter value right */
1207 /* after the connect returns. The remote will grab the counter right */
1208 /* after the accept call. This saves the hassle of extra messages */
1209 /* being sent for the STREAM tests. */
1210
1211 recv_response();
1212
1213 if (!netperf_response.content.serv_errno) {
1214 if (debug)
1215 fprintf(where,"remote listen done.\n");
1216 rsr_size = stream_rr_response->recv_buf_size;
1217 rss_size = stream_rr_response->send_buf_size;
1218 remote_cpu_usage= stream_rr_response->measure_cpu;
1219 remote_cpu_rate = stream_rr_response->cpu_rate;
1220 /* make sure that port numbers are in network order */
1221 strcpy(server.sun_path,stream_rr_response->unix_path);
1222 }
1223 else {
1224 Set_errno(netperf_response.content.serv_errno);
1225 perror("netperf: remote error");
1226
1227 exit(1);
1228 }
1229
1230 /*Connect up to the remote port on the data socket */
1231 if (connect(send_socket,
1232 (struct sockaddr *)&server,
1233 sizeof(server)) == INVALID_SOCKET){
1234 perror("netperf: data socket connect failed");
1235
1236 exit(1);
1237 }
1238
1239 /* Data Socket set-up is finished. If there were problems, either the */
1240 /* connect would have failed, or the previous response would have */
1241 /* indicated a problem. I failed to see the value of the extra */
1242 /* message after the accept on the remote. If it failed, we'll see it */
1243 /* here. If it didn't, we might as well start pumping data. */
1244
1245 /* Set-up the test end conditions. For a request/response test, they */
1246 /* can be either time or transaction based. */
1247
1248 if (test_time) {
1249 /* The user wanted to end the test after a period of time. */
1250 times_up = 0;
1251 trans_remaining = 0;
1252 start_timer(test_time);
1253 }
1254 else {
1255 /* The tester wanted to send a number of bytes. */
1256 trans_remaining = test_bytes;
1257 times_up = 1;
1258 }
1259
1260 /* The cpu_start routine will grab the current time and possibly */
1261 /* value of the idle counter for later use in measuring cpu */
1262 /* utilization and/or service demand and thruput. */
1263
1264 cpu_start(local_cpu_usage);
1265
1266 /* We use an "OR" to control test execution. When the test is */
1267 /* controlled by time, the byte count check will always return false. */
1268 /* When the test is controlled by byte count, the time test will */
1269 /* always return false. When the test is finished, the whole */
1270 /* expression will go false and we will stop sending data. I think I */
1271 /* just arbitrarily decrement trans_remaining for the timed test, but */
1272 /* will not do that just yet... One other question is whether or not */
1273 /* the send buffer and the receive buffer should be the same buffer. */
1274
1275 while ((!times_up) || (trans_remaining > 0)) {
1276 /* send the request. we assume that if we use a blocking socket, */
1277 /* the request will be sent at one shot. */
1278 if((len=send(send_socket,
1279 send_ring->buffer_ptr,
1280 req_size,
1281 0)) != req_size) {
1282 if (errno == EINTR) {
1283 /* we hit the end of a */
1284 /* timed test. */
1285 timed_out = 1;
1286 break;
1287 }
1288 perror("send_stream_rr: data send error");
1289 exit(1);
1290 }
1291 send_ring = send_ring->next;
1292
1293 /* receive the response */
1294 rsp_bytes_left = rsp_size;
1295 temp_message_ptr = recv_ring->buffer_ptr;
1296 while(rsp_bytes_left > 0) {
1297 if((rsp_bytes_recvd=recv(send_socket,
1298 temp_message_ptr,
1299 rsp_bytes_left,
1300 0)) == SOCKET_ERROR) {
1301 if (errno == EINTR) {
1302 /* We hit the end of a timed test. */
1303 timed_out = 1;
1304 break;
1305 }
1306 perror("send_stream_rr: data recv error");
1307 exit(1);
1308 }
1309 rsp_bytes_left -= rsp_bytes_recvd;
1310 temp_message_ptr += rsp_bytes_recvd;
1311 }
1312 recv_ring = recv_ring->next;
1313
1314 if (timed_out) {
1315 /* we may have been in a nested while loop - we need */
1316 /* another call to break. */
1317 break;
1318 }
1319
1320 nummessages++;
1321 if (trans_remaining) {
1322 trans_remaining--;
1323 }
1324
1325 if (debug > 3) {
1326 fprintf(where,
1327 "Transaction %d completed\n",
1328 nummessages);
1329 fflush(where);
1330 }
1331 }
1332
1333 /* At this point we used to call shutdown on the data socket to be */
1334 /* sure all the data was delivered, but this was not germane in a */
1335 /* request/response test, and it was causing the tests to "hang" when */
1336 /* they were being controlled by time. So, I have replaced this */
1337 /* shutdown call with a call to close that can be found later in the */
1338 /* procedure. */
1339
1340 /* this call will always give us the elapsed time for the test, and */
1341 /* will also store-away the necessaries for cpu utilization */
1342
1343 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
1344 /* how long did we really run? */
1345
1346 /* Get the statistics from the remote end. The remote will have */
1347 /* calculated service demand and all those interesting things. If it */
1348 /* wasn't supposed to care, it will return obvious values. */
1349
1350 recv_response();
1351 if (!netperf_response.content.serv_errno) {
1352 if (debug)
1353 fprintf(where,"remote results obtained\n");
1354 }
1355 else {
1356 Set_errno(netperf_response.content.serv_errno);
1357 perror("netperf: remote error");
1358
1359 exit(1);
1360 }
1361
1362 /* We now calculate what our thruput was for the test. In the future, */
1363 /* we may want to include a calculation of the thruput measured by */
1364 /* the remote, but it should be the case that for a STREAM stream test, */
1365 /* that the two numbers should be *very* close... We calculate */
1366 /* bytes_sent regardless of the way the test length was controlled. */
1367 /* If it was time, we needed to, and if it was by bytes, the user may */
1368 /* have specified a number of bytes that wasn't a multiple of the */
1369 /* send_size, so we really didn't send what he asked for ;-) We use */
1370 /* Kbytes/s as the units of thruput for a STREAM stream test, where K = */
1371 /* 1024. A future enhancement *might* be to choose from a couple of */
1372 /* unit selections. */
1373
1374 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
1375 thruput = calc_thruput(bytes_xferd);
1376
1377 if (local_cpu_usage || remote_cpu_usage) {
1378 /* We must now do a little math for service demand and cpu */
1379 /* utilization for the system(s) */
1380 /* Of course, some of the information might be bogus because */
1381 /* there was no idle counter in the kernel(s). We need to make */
1382 /* a note of this for the user's benefit...*/
1383 if (local_cpu_usage) {
1384 if (local_cpu_rate == 0.0) {
1385 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
1386 fprintf(where,"Local CPU usage numbers based on process information only!\n");
1387 fflush(where);
1388 }
1389 local_cpu_utilization = calc_cpu_util(0.0);
1390 /* since calc_service demand is doing ms/Kunit we will */
1391 /* multiply the number of transaction by 1024 to get */
1392 /* "good" numbers */
1393 local_service_demand = calc_service_demand((double) nummessages*1024,
1394 0.0,
1395 0.0,
1396 0);
1397 }
1398 else {
1399 local_cpu_utilization = -1.0;
1400 local_service_demand = -1.0;
1401 }
1402
1403 if (remote_cpu_usage) {
1404 if (remote_cpu_rate == 0.0) {
1405 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
1406 fprintf(where,"Remote CPU usage numbers based on process information only!\n");
1407 fflush(where);
1408 }
1409 remote_cpu_utilization = stream_rr_result->cpu_util;
1410 /* since calc_service demand is doing ms/Kunit we will */
1411 /* multiply the number of transaction by 1024 to get */
1412 /* "good" numbers */
1413 remote_service_demand = calc_service_demand((double) nummessages*1024,
1414 0.0,
1415 remote_cpu_utilization,
1416 stream_rr_result->num_cpus);
1417 }
1418 else {
1419 remote_cpu_utilization = -1.0;
1420 remote_service_demand = -1.0;
1421 }
1422
1423 /* We are now ready to print all the information. If the user */
1424 /* has specified zero-level verbosity, we will just print the */
1425 /* local service demand, or the remote service demand. If the */
1426 /* user has requested verbosity level 1, he will get the basic */
1427 /* "streamperf" numbers. If the user has specified a verbosity */
1428 /* of greater than 1, we will display a veritable plethora of */
1429 /* background information from outside of this block as it it */
1430 /* not cpu_measurement specific... */
1431
1432 switch (verbosity) {
1433 case 0:
1434 if (local_cpu_usage) {
1435 fprintf(where,
1436 cpu_fmt_0,
1437 local_service_demand);
1438 }
1439 else {
1440 fprintf(where,
1441 cpu_fmt_0,
1442 remote_service_demand);
1443 }
1444 break;
1445 case 1:
1446 fprintf(where,
1447 cpu_fmt_1_line_1, /* the format string */
1448 lss_size, /* local sendbuf size */
1449 lsr_size,
1450 req_size, /* how large were the requests */
1451 rsp_size, /* guess */
1452 elapsed_time, /* how long was the test */
1453 nummessages/elapsed_time,
1454 local_cpu_utilization, /* local cpu */
1455 remote_cpu_utilization, /* remote cpu */
1456 local_service_demand, /* local service demand */
1457 remote_service_demand); /* remote service demand */
1458 fprintf(where,
1459 cpu_fmt_1_line_2,
1460 rss_size,
1461 rsr_size);
1462 break;
1463 }
1464 }
1465 else {
1466 /* The tester did not wish to measure service demand. */
1467 switch (verbosity) {
1468 case 0:
1469 fprintf(where,
1470 tput_fmt_0,
1471 nummessages/elapsed_time);
1472 break;
1473 case 1:
1474 fprintf(where,
1475 tput_fmt_1_line_1, /* the format string */
1476 lss_size,
1477 lsr_size,
1478 req_size, /* how large were the requests */
1479 rsp_size, /* how large were the responses */
1480 elapsed_time, /* how long did it take */
1481 nummessages/elapsed_time);
1482 fprintf(where,
1483 tput_fmt_1_line_2,
1484 rss_size, /* remote recvbuf size */
1485 rsr_size);
1486
1487 break;
1488 }
1489 }
1490
1491 /* it would be a good thing to include information about some of the */
1492 /* other parameters that may have been set for this test, but at the */
1493 /* moment, I do not wish to figure-out all the formatting, so I will */
1494 /* just put this comment here to help remind me that it is something */
1495 /* that should be done at a later time. */
1496
1497 if (verbosity > 1) {
1498 /* The user wanted to know it all, so we will give it to him. */
1499 /* This information will include as much as we can find about */
1500 /* STREAM statistics, the alignments of the sends and receives */
1501 /* and all that sort of rot... */
1502
1503 fprintf(where,
1504 ksink_fmt);
1505 }
1506 /* The test is over. Kill the data socket */
1507
1508 if (close(send_socket) == -1) {
1509 perror("send_stream_rr: cannot shutdown stream stream socket");
1510 }
1511
1512}
1513
1514void
1515send_dg_stream(char remote_host[])
1516{
1517 /************************************************************************/
1518 /* */
1519 /* DG Unidirectional Send Test */
1520 /* */
1521 /************************************************************************/
1522 char *tput_title =
1523 "Socket Message Elapsed Messages \n\
1524Size Size Time Okay Errors Throughput\n\
1525bytes bytes secs # # %s/sec\n\n";
1526
1527 char *tput_fmt_0 =
1528 "%7.2f\n";
1529
1530 char *tput_fmt_1 =
1531 "%5d %5d %-7.2f %7d %6d %7.2f\n\
1532%5d %-7.2f %7d %7.2f\n\n";
1533
1534
1535 char *cpu_title =
1536 "Socket Message Elapsed Messages CPU Service\n\
1537Size Size Time Okay Errors Throughput Util Demand\n\
1538bytes bytes secs # # %s/sec %% us/KB\n\n";
1539
1540 char *cpu_fmt_0 =
1541 "%6.2f\n";
1542
1543 char *cpu_fmt_1 =
1544 "%5d %5d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\
1545%5d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n";
1546
1547 int messages_recvd;
1548 float elapsed_time,
1549 local_cpu_utilization,
1550 remote_cpu_utilization;
1551
1552 float local_service_demand, remote_service_demand;
1553 double local_thruput, remote_thruput;
1554 double bytes_sent;
1555 double bytes_recvd;
1556
1557
1558 int len;
1559 struct ring_elt *send_ring;
1560 int failed_sends;
1561 int failed_cows;
1562 int messages_sent;
1563 SOCKET data_socket;
1564
1565
1566#ifdef WANT_INTERVALS
1567 int interval_count;
1568#endif /* WANT_INTERVALS */
1569#ifdef DIRTY
1570 int *message_int_ptr;
1571 int i;
1572#endif /* DIRTY */
1573
1574 struct sockaddr_un server;
1575
1576 struct dg_stream_request_struct *dg_stream_request;
1577 struct dg_stream_response_struct *dg_stream_response;
1578 struct dg_stream_results_struct *dg_stream_results;
1579
1580 dg_stream_request = (struct dg_stream_request_struct *)netperf_request.content.test_specific_data;
1581 dg_stream_response = (struct dg_stream_response_struct *)netperf_response.content.test_specific_data;
1582 dg_stream_results = (struct dg_stream_results_struct *)netperf_response.content.test_specific_data;
1583
1584 /* since we are now disconnected from the code that established the */
1585 /* control socket, and since we want to be able to use different */
1586 /* protocols and such, we are passed the name of the remote host and */
1587 /* must turn that into the test specific addressing information. */
1588
1589 bzero((char *)&server,
1590 sizeof(server));
1591
1592 server.sun_family = AF_UNIX;
1593
1594 if ( print_headers ) {
1595 printf("DG UNIDIRECTIONAL SEND TEST\n");
1596 if (local_cpu_usage || remote_cpu_usage)
1597 printf(cpu_title,format_units());
1598 else
1599 printf(tput_title,format_units());
1600 }
1601
1602 failed_sends = 0;
1603 failed_cows = 0;
1604 messages_sent = 0;
1605 times_up = 0;
1606
1607 /*set up the data socket */
1608 data_socket = create_unix_socket(AF_UNIX,
1609 SOCK_DGRAM);
1610
1611 if (data_socket == INVALID_SOCKET){
1612 perror("dg_send: data socket");
1613 exit(1);
1614 }
1615
1616 /* now, we want to see if we need to set the send_size */
1617 if (send_size == 0) {
1618 if (lss_size > 0) {
1619 send_size = (lss_size < UNIX_LENGTH_MAX ? lss_size : UNIX_LENGTH_MAX);
1620 }
1621 else {
1622 send_size = 4096;
1623 }
1624 }
1625
1626
1627 /* set-up the data buffer with the requested alignment and offset, */
1628 /* most of the numbers here are just a hack to pick something nice */
1629 /* and big in an attempt to never try to send a buffer a second time */
1630 /* before it leaves the node...unless the user set the width */
1631 /* explicitly. */
1632 if (send_width == 0) send_width = 32;
1633
1634 send_ring = allocate_buffer_ring(send_width,
1635 send_size,
1636 local_send_align,
1637 local_send_offset);
1638
1639 /* At this point, we want to do things like disable DG checksumming */
1640 /* and measure the cpu rate and all that so we are ready to go */
1641 /* immediately after the test response message is delivered. */
1642
1643 /* if the user supplied a cpu rate, this call will complete rather */
1644 /* quickly, otherwise, the cpu rate will be retured to us for */
1645 /* possible display. The Library will keep it's own copy of this data */
1646 /* for use elsewhere. We will only display it. (Does that make it */
1647 /* "opaque" to us?) */
1648
1649 if (local_cpu_usage)
1650 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1651
1652 /* Tell the remote end to set up the data connection. The server */
1653 /* sends back the port number and alters the socket parameters there. */
1654 /* Of course this is a datagram service so no connection is actually */
1655 /* set up, the server just sets up the socket and binds it. */
1656
1657 netperf_request.content.request_type = DO_DG_STREAM;
1658 dg_stream_request->recv_buf_size = rsr_size;
1659 dg_stream_request->message_size = send_size;
1660 dg_stream_request->recv_alignment = remote_recv_align;
1661 dg_stream_request->recv_offset = remote_recv_offset;
1662 dg_stream_request->measure_cpu = remote_cpu_usage;
1663 dg_stream_request->cpu_rate = remote_cpu_rate;
1664 dg_stream_request->test_length = test_time;
1665
1666 send_request();
1667
1668 recv_response();
1669
1670 if (!netperf_response.content.serv_errno) {
1671 if (debug)
1672 fprintf(where,"send_dg_stream: remote data connection done.\n");
1673 }
1674 else {
1675 Set_errno(netperf_response.content.serv_errno);
1676 perror("send_dg_stream: error on remote");
1677 exit(1);
1678 }
1679
1680 /* Place the port number returned by the remote into the sockaddr */
1681 /* structure so our sends can be sent to the correct place. Also get */
1682 /* some of the returned socket buffer information for user display. */
1683
1684 /* make sure that port numbers are in the proper order */
1685 strcpy(server.sun_path,dg_stream_response->unix_path);
1686 rsr_size = dg_stream_response->recv_buf_size;
1687 rss_size = dg_stream_response->send_buf_size;
1688 remote_cpu_rate = dg_stream_response->cpu_rate;
1689
1690 /* We "connect" up to the remote post to allow is to use the send */
1691 /* call instead of the sendto call. Presumeably, this is a little */
1692 /* simpler, and a little more efficient. I think that it also means */
1693 /* that we can be informed of certain things, but am not sure yet... */
1694
1695 if (connect(data_socket,
1696 (struct sockaddr *)&server,
1697 sizeof(server)) == INVALID_SOCKET){
1698 perror("send_dg_stream: data socket connect failed");
1699 exit(1);
1700 }
1701
1702 /* set up the timer to call us after test_time */
1703 start_timer(test_time);
1704
1705 /* Get the start count for the idle counter and the start time */
1706
1707 cpu_start(local_cpu_usage);
1708
1709#ifdef WANT_INTERVALS
1710 interval_count = interval_burst;
1711#endif
1712
1713 /* Send datagrams like there was no tomorrow. at somepoint it might */
1714 /* be nice to set this up so that a quantity of bytes could be sent, */
1715 /* but we still need some sort of end of test trigger on the receive */
1716 /* side. that could be a select with a one second timeout, but then */
1717 /* if there is a test where none of the data arrives for awile and */
1718 /* then starts again, we would end the test too soon. something to */
1719 /* think about... */
1720 while (!times_up) {
1721
1722#ifdef DIRTY
1723 /* we want to dirty some number of consecutive integers in the buffer */
1724 /* we are about to send. we may also want to bring some number of */
1725 /* them cleanly into the cache. The clean ones will follow any dirty */
1726 /* ones into the cache. */
1727 message_int_ptr = (int *)(send_ring->buffer_ptr);
1728 for (i = 0; i < loc_dirty_count; i++) {
1729 *message_int_ptr = 4;
1730 message_int_ptr++;
1731 }
1732 for (i = 0; i < loc_clean_count; i++) {
1733 loc_dirty_count = *message_int_ptr;
1734 message_int_ptr++;
1735 }
1736#endif /* DIRTY */
1737
1738 if ((len=send(data_socket,
1739 send_ring->buffer_ptr,
1740 send_size,
1741 0)) != send_size) {
1742 if ((len >= 0) || (errno == EINTR))
1743 break;
1744 if (errno == ENOBUFS) {
1745 failed_sends++;
1746 continue;
1747 }
1748 perror("dg_send: data send error");
1749 exit(1);
1750 }
1751 messages_sent++;
1752
1753 /* now we want to move our pointer to the next position in the */
1754 /* data buffer... */
1755
1756 send_ring = send_ring->next;
1757
1758
1759#ifdef WANT_INTERVALS
1760 /* in this case, the interval count is the count-down couter */
1761 /* to decide to sleep for a little bit */
1762 if ((interval_burst) && (--interval_count == 0)) {
1763 /* call the sleep routine for some milliseconds, if our */
1764 /* timer popped while we were in there, we want to */
1765 /* break out of the loop. */
1766 if (msec_sleep(interval_wate)) {
1767 break;
1768 }
1769 interval_count = interval_burst;
1770 }
1771
1772#endif
1773
1774 }
1775
1776 /* This is a timed test, so the remote will be returning to us after */
1777 /* a time. We should not need to send any "strange" messages to tell */
1778 /* the remote that the test is completed, unless we decide to add a */
1779 /* number of messages to the test. */
1780
1781 /* the test is over, so get stats and stuff */
1782 cpu_stop(local_cpu_usage,
1783 &elapsed_time);
1784
1785 /* Get the statistics from the remote end */
1786 recv_response();
1787 if (!netperf_response.content.serv_errno) {
1788 if (debug)
1789 fprintf(where,"send_dg_stream: remote results obtained\n");
1790 }
1791 else {
1792 Set_errno(netperf_response.content.serv_errno);
1793 perror("send_dg_stream: error on remote");
1794 exit(1);
1795 }
1796
1797 bytes_sent = send_size * messages_sent;
1798 local_thruput = calc_thruput(bytes_sent);
1799
1800 messages_recvd = dg_stream_results->messages_recvd;
1801 bytes_recvd = send_size * messages_recvd;
1802
1803 /* we asume that the remote ran for as long as we did */
1804
1805 remote_thruput = calc_thruput(bytes_recvd);
1806
1807 /* print the results for this socket and message size */
1808
1809 if (local_cpu_usage || remote_cpu_usage) {
1810 /* We must now do a little math for service demand and cpu */
1811 /* utilization for the system(s) We pass zeros for the local */
1812 /* cpu utilization and elapsed time to tell the routine to use */
1813 /* the libraries own values for those. */
1814 if (local_cpu_usage) {
1815 if (local_cpu_rate == 0.0) {
1816 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
1817 fprintf(where,"Local CPU usage numbers based on process information only!\n");
1818 fflush(where);
1819 }
1820
1821 local_cpu_utilization = calc_cpu_util(0.0);
1822 local_service_demand = calc_service_demand(bytes_sent,
1823 0.0,
1824 0.0,
1825 0);
1826 }
1827 else {
1828 local_cpu_utilization = -1.0;
1829 local_service_demand = -1.0;
1830 }
1831
1832 /* The local calculations could use variables being kept by */
1833 /* the local netlib routines. The remote calcuations need to */
1834 /* have a few things passed to them. */
1835 if (remote_cpu_usage) {
1836 if (remote_cpu_rate == 0.0) {
1837 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
1838 fprintf(where,"REMOTE CPU usage numbers based on process information only!\n");
1839 fflush(where);
1840 }
1841
1842 remote_cpu_utilization = dg_stream_results->cpu_util;
1843 remote_service_demand = calc_service_demand(bytes_recvd,
1844 0.0,
1845 remote_cpu_utilization,
1846 dg_stream_results->num_cpus);
1847 }
1848 else {
1849 remote_cpu_utilization = -1.0;
1850 remote_service_demand = -1.0;
1851 }
1852
1853 /* We are now ready to print all the information. If the user */
1854 /* has specified zero-level verbosity, we will just print the */
1855 /* local service demand, or the remote service demand. If the */
1856 /* user has requested verbosity level 1, he will get the basic */
1857 /* "streamperf" numbers. If the user has specified a verbosity */
1858 /* of greater than 1, we will display a veritable plethora of */
1859 /* background information from outside of this block as it it */
1860 /* not cpu_measurement specific... */
1861
1862 switch (verbosity) {
1863 case 0:
1864 if (local_cpu_usage) {
1865 fprintf(where,
1866 cpu_fmt_0,
1867 local_service_demand);
1868 }
1869 else {
1870 fprintf(where,
1871 cpu_fmt_0,
1872 remote_service_demand);
1873 }
1874 break;
1875 case 1:
1876 fprintf(where,
1877 cpu_fmt_1, /* the format string */
1878 lss_size, /* local sendbuf size */
1879 send_size, /* how large were the sends */
1880 elapsed_time, /* how long was the test */
1881 messages_sent,
1882 failed_sends,
1883 local_thruput, /* what was the xfer rate */
1884 local_cpu_utilization, /* local cpu */
1885 local_service_demand, /* local service demand */
1886 rsr_size,
1887 elapsed_time,
1888 messages_recvd,
1889 remote_thruput,
1890 remote_cpu_utilization, /* remote cpu */
1891 remote_service_demand); /* remote service demand */
1892 break;
1893 }
1894 }
1895 else {
1896 /* The tester did not wish to measure service demand. */
1897 switch (verbosity) {
1898 case 0:
1899 fprintf(where,
1900 tput_fmt_0,
1901 local_thruput);
1902 break;
1903 case 1:
1904 fprintf(where,
1905 tput_fmt_1, /* the format string */
1906 lss_size, /* local sendbuf size */
1907 send_size, /* how large were the sends */
1908 elapsed_time, /* how long did it take */
1909 messages_sent,
1910 failed_sends,
1911 local_thruput,
1912 rsr_size, /* remote recvbuf size */
1913 elapsed_time,
1914 messages_recvd,
1915 remote_thruput
1916 );
1917 break;
1918 }
1919 }
1920}
1921
1922
1923 /* this routine implements the receive side (netserver) of the */
1924 /* DG_STREAM performance test. */
1925
1926void
1927recv_dg_stream()
1928{
1929 struct ring_elt *recv_ring;
1930
1931 struct sockaddr_un myaddr_un;
1932 SOCKET s_data;
1933 int len = 0;
1934 int bytes_received = 0;
1935 float elapsed_time;
1936
1937 int message_size;
1938 int messages_recvd = 0;
1939
1940 struct dg_stream_request_struct *dg_stream_request;
1941 struct dg_stream_response_struct *dg_stream_response;
1942 struct dg_stream_results_struct *dg_stream_results;
1943
1944 dg_stream_request =
1945 (struct dg_stream_request_struct *)netperf_request.content.test_specific_data;
1946 dg_stream_response =
1947 (struct dg_stream_response_struct *)netperf_response.content.test_specific_data;
1948 dg_stream_results =
1949 (struct dg_stream_results_struct *)netperf_response.content.test_specific_data;
1950
1951 if (debug) {
1952 fprintf(where,"netserver: recv_dg_stream: entered...\n");
1953 fflush(where);
1954 }
1955
1956 /* We want to set-up the listen socket with all the desired */
1957 /* parameters and then let the initiator know that all is ready. If */
1958 /* socket size defaults are to be used, then the initiator will have */
1959 /* sent us 0's. If the socket sizes cannot be changed, then we will */
1960 /* send-back what they are. If that information cannot be determined, */
1961 /* then we send-back -1's for the sizes. If things go wrong for any */
1962 /* reason, we will drop back ten yards and punt. */
1963
1964 /* If anything goes wrong, we want the remote to know about it. It */
1965 /* would be best if the error that the remote reports to the user is */
1966 /* the actual error we encountered, rather than some bogus unexpected */
1967 /* response type message. */
1968
1969 if (debug > 1) {
1970 fprintf(where,"recv_dg_stream: setting the response type...\n");
1971 fflush(where);
1972 }
1973
1974 netperf_response.content.response_type = DG_STREAM_RESPONSE;
1975
1976 if (debug > 2) {
1977 fprintf(where,"recv_dg_stream: the response type is set...\n");
1978 fflush(where);
1979 }
1980
1981 /* We now alter the message_ptr variable to be at the desired */
1982 /* alignment with the desired offset. */
1983
1984 if (debug > 1) {
1985 fprintf(where,"recv_dg_stream: requested alignment of %d\n",
1986 dg_stream_request->recv_alignment);
1987 fflush(where);
1988 }
1989
1990 if (recv_width == 0) recv_width = 1;
1991
1992 recv_ring = allocate_buffer_ring(recv_width,
1993 dg_stream_request->message_size,
1994 dg_stream_request->recv_alignment,
1995 dg_stream_request->recv_offset);
1996
1997 if (debug > 1) {
1998 fprintf(where,"recv_dg_stream: receive alignment and offset set...\n");
1999 fflush(where);
2000 }
2001
2002 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
2003 /* can put in OUR values !-) At some point, we may want to nail this */
2004 /* socket to a particular network-level address, but for now, */
2005 /* INADDR_ANY should be just fine. */
2006
2007 bzero((char *)&myaddr_un,
2008 sizeof(myaddr_un));
2009 myaddr_un.sun_family = AF_UNIX;
2010
2011 /* Grab a socket to listen on, and then listen on it. */
2012
2013 if (debug > 1) {
2014 fprintf(where,"recv_dg_stream: grabbing a socket...\n");
2015 fflush(where);
2016 }
2017
2018 /* create_unix_socket expects to find some things in the global */
2019 /* variables, so set the globals based on the values in the request. */
2020 /* once the socket has been created, we will set the response values */
2021 /* based on the updated value of those globals. raj 7/94 */
2022 lsr_size = dg_stream_request->recv_buf_size;
2023
2024 s_data = create_unix_socket(AF_UNIX,
2025 SOCK_DGRAM);
2026
2027 if (s_data == INVALID_SOCKET) {
2028 netperf_response.content.serv_errno = errno;
2029 send_response();
2030 exit(1);
2031 }
2032
2033 /* Let's get an address assigned to this socket so we can tell the */
2034 /* initiator how to reach the data socket. There may be a desire to */
2035 /* nail this socket to a specific IP address in a multi-homed, */
2036 /* multi-connection situation, but for now, we'll ignore the issue */
2037 /* and concentrate on single connection testing. */
2038
2039 strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf."));
2040 if (bind(s_data,
2041 (struct sockaddr *)&myaddr_un,
2042 sizeof(myaddr_un)) == SOCKET_ERROR) {
2043 netperf_response.content.serv_errno = errno;
2044 send_response();
2045 exit(1);
2046 }
2047
2048 chmod(myaddr_un.sun_path, 0666);
2049
2050 dg_stream_response->test_length = dg_stream_request->test_length;
2051
2052 /* Now myaddr_un contains the port and the internet address this is */
2053 /* returned to the sender also implicitly telling the sender that the */
2054 /* socket buffer sizing has been done. */
2055
2056 strcpy(dg_stream_response->unix_path,myaddr_un.sun_path);
2057 netperf_response.content.serv_errno = 0;
2058
2059 /* But wait, there's more. If the initiator wanted cpu measurements, */
2060 /* then we must call the calibrate routine, which will return the max */
2061 /* rate back to the initiator. If the CPU was not to be measured, or */
2062 /* something went wrong with the calibration, we will return a -1 to */
2063 /* the initiator. */
2064
2065 dg_stream_response->cpu_rate = 0.0; /* assume no cpu */
2066 if (dg_stream_request->measure_cpu) {
2067 /* We will pass the rate into the calibration routine. If the */
2068 /* user did not specify one, it will be 0.0, and we will do a */
2069 /* "real" calibration. Otherwise, all it will really do is */
2070 /* store it away... */
2071 dg_stream_response->measure_cpu = 1;
2072 dg_stream_response->cpu_rate =
2073 calibrate_local_cpu(dg_stream_request->cpu_rate);
2074 }
2075
2076 message_size = dg_stream_request->message_size;
2077 test_time = dg_stream_request->test_length;
2078
2079 /* before we send the response back to the initiator, pull some of */
2080 /* the socket parms from the globals */
2081 dg_stream_response->send_buf_size = lss_size;
2082 dg_stream_response->recv_buf_size = lsr_size;
2083
2084 send_response();
2085
2086 /* Now it's time to start receiving data on the connection. We will */
2087 /* first grab the apropriate counters and then start grabbing. */
2088
2089 cpu_start(dg_stream_request->measure_cpu);
2090
2091 /* The loop will exit when the timer pops, or if we happen to recv a */
2092 /* message of less than send_size bytes... */
2093
2094 times_up = 0;
2095 start_timer(test_time + PAD_TIME);
2096
2097 if (debug) {
2098 fprintf(where,"recv_dg_stream: about to enter inner sanctum.\n");
2099 fflush(where);
2100 }
2101
2102 while (!times_up) {
2103 if ((len = recv(s_data,
2104 recv_ring->buffer_ptr,
2105 message_size,
2106 0)) != message_size) {
2107 if ((len == SOCKET_ERROR) && (errno != EINTR)) {
2108 netperf_response.content.serv_errno = errno;
2109 send_response();
2110 exit(1);
2111 }
2112 break;
2113 }
2114 messages_recvd++;
2115 recv_ring = recv_ring->next;
2116 }
2117
2118 if (debug) {
2119 fprintf(where,"recv_dg_stream: got %d messages.\n",messages_recvd);
2120 fflush(where);
2121 }
2122
2123
2124 /* The loop now exits due timer or < send_size bytes received. */
2125
2126 cpu_stop(dg_stream_request->measure_cpu,&elapsed_time);
2127
2128 if (times_up) {
2129 /* we ended on a timer, subtract the PAD_TIME */
2130 elapsed_time -= (float)PAD_TIME;
2131 }
2132 else {
2133 stop_timer();
2134 }
2135
2136 if (debug) {
2137 fprintf(where,"recv_dg_stream: test ended in %f seconds.\n",elapsed_time);
2138 fflush(where);
2139 }
2140
2141
2142 /* We will count the "off" message that got us out of the loop */
2143 bytes_received = (messages_recvd * message_size) + len;
2144
2145 /* send the results to the sender */
2146
2147 if (debug) {
2148 fprintf(where,
2149 "recv_dg_stream: got %d bytes\n",
2150 bytes_received);
2151 fflush(where);
2152 }
2153
2154 netperf_response.content.response_type = DG_STREAM_RESULTS;
2155 dg_stream_results->bytes_received = bytes_received;
2156 dg_stream_results->messages_recvd = messages_recvd;
2157 dg_stream_results->elapsed_time = elapsed_time;
2158 if (dg_stream_request->measure_cpu) {
2159 dg_stream_results->cpu_util = calc_cpu_util(elapsed_time);
2160 }
2161 else {
2162 dg_stream_results->cpu_util = -1.0;
2163 }
2164
2165 if (debug > 1) {
2166 fprintf(where,
2167 "recv_dg_stream: test complete, sending results.\n");
2168 fflush(where);
2169 }
2170
2171 send_response();
2172
2173}
2174
2175void
2176send_dg_rr(char remote_host[])
2177{
2178
2179 char *tput_title = "\
2180Local /Remote\n\
2181Socket Size Request Resp. Elapsed Trans.\n\
2182Send Recv Size Size Time Rate \n\
2183bytes Bytes bytes bytes secs. per sec \n\n";
2184
2185 char *tput_fmt_0 =
2186 "%7.2f\n";
2187
2188 char *tput_fmt_1_line_1 = "\
2189%-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
2190 char *tput_fmt_1_line_2 = "\
2191%-6d %-6d\n";
2192
2193 char *cpu_title = "\
2194Local /Remote\n\
2195Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
2196Send Recv Size Size Time Rate local remote local remote\n\
2197bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
2198
2199 char *cpu_fmt_0 =
2200 "%6.3f\n";
2201
2202 char *cpu_fmt_1_line_1 = "\
2203%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
2204
2205 char *cpu_fmt_1_line_2 = "\
2206%-6d %-6d\n";
2207
2208 float elapsed_time;
2209
2210 /* we add MAXALIGNMENT and MAXOFFSET to insure that there is enough */
2211 /* space for a maximally aligned, maximally sized message. At some */
2212 /* point, we may want to actually make this even larger and cycle */
2213 /* through the thing one piece at a time.*/
2214
2215 int len;
2216 char *send_message_ptr;
2217 char *recv_message_ptr;
2218 char *temp_message_ptr;
2219 int nummessages;
2220 SOCKET send_socket;
2221 int trans_remaining;
2222 int bytes_xferd;
2223
2224 int rsp_bytes_recvd;
2225
2226 float local_cpu_utilization;
2227 float local_service_demand;
2228 float remote_cpu_utilization;
2229 float remote_service_demand;
2230 double thruput;
2231
2232#ifdef WANT_INTERVALS
2233 /* timing stuff */
2234#define MAX_KEPT_TIMES 1024
2235 int time_index = 0;
2236 int unused_buckets;
2237 int kept_times[MAX_KEPT_TIMES];
2238 int sleep_usecs;
2239 unsigned int total_times=0;
2240 struct timezone dummy_zone;
2241 struct timeval send_time;
2242 struct timeval recv_time;
2243 struct timeval sleep_timeval;
2244#endif
2245
2246 struct sockaddr_un server, myaddr_un;
2247
2248 struct dg_rr_request_struct *dg_rr_request;
2249 struct dg_rr_response_struct *dg_rr_response;
2250 struct dg_rr_results_struct *dg_rr_result;
2251
2252 dg_rr_request =
2253 (struct dg_rr_request_struct *)netperf_request.content.test_specific_data;
2254 dg_rr_response=
2255 (struct dg_rr_response_struct *)netperf_response.content.test_specific_data;
2256 dg_rr_result =
2257 (struct dg_rr_results_struct *)netperf_response.content.test_specific_data;
2258
2259 /* we want to zero out the times, so we can detect unused entries. */
2260#ifdef WANT_INTERVALS
2261 time_index = 0;
2262 while (time_index < MAX_KEPT_TIMES) {
2263 kept_times[time_index] = 0;
2264 time_index += 1;
2265 }
2266 time_index = 0;
2267#endif
2268
2269 /* since we are now disconnected from the code that established the */
2270 /* control socket, and since we want to be able to use different */
2271 /* protocols and such, we are passed the name of the remote host and */
2272 /* must turn that into the test specific addressing information. */
2273
2274 bzero((char *)&server,
2275 sizeof(server));
2276 server.sun_family = AF_UNIX;
2277
2278 bzero((char *)&myaddr_un,
2279 sizeof(myaddr_un));
2280 myaddr_un.sun_family = AF_UNIX;
2281
2282 strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf."));
2283
2284 if ( print_headers ) {
2285 fprintf(where,"DG REQUEST/RESPONSE TEST\n");
2286 if (local_cpu_usage || remote_cpu_usage)
2287 fprintf(where,cpu_title,format_units());
2288 else
2289 fprintf(where,tput_title,format_units());
2290 }
2291
2292 /* initialize a few counters */
2293
2294 nummessages = 0;
2295 bytes_xferd = 0;
2296 times_up = 0;
2297
2298 /* set-up the data buffer with the requested alignment and offset */
2299 temp_message_ptr = (char *)malloc(DATABUFFERLEN);
2300 if (temp_message_ptr == NULL) {
2301 printf("malloc(%d) failed!\n", DATABUFFERLEN);
2302 exit(1);
2303 }
2304 send_message_ptr = (char *)(( (long)temp_message_ptr +
2305 (long) local_send_align - 1) &
2306 ~((long) local_send_align - 1));
2307 send_message_ptr = send_message_ptr + local_send_offset;
2308 temp_message_ptr = (char *)malloc(DATABUFFERLEN);
2309 if (temp_message_ptr == NULL) {
2310 printf("malloc(%d) failed!\n", DATABUFFERLEN);
2311 exit(1);
2312 }
2313 recv_message_ptr = (char *)(( (long)temp_message_ptr +
2314 (long) local_recv_align - 1) &
2315 ~((long) local_recv_align - 1));
2316 recv_message_ptr = recv_message_ptr + local_recv_offset;
2317
2318 /*set up the data socket */
2319 send_socket = create_unix_socket(AF_UNIX,
2320 SOCK_DGRAM);
2321
2322 if (send_socket == INVALID_SOCKET){
2323 perror("netperf: send_dg_rr: dg rr data socket");
2324 exit(1);
2325 }
2326
2327 if (debug) {
2328 fprintf(where,"send_dg_rr: send_socket obtained...\n");
2329 }
2330
2331
2332 /* If the user has requested cpu utilization measurements, we must */
2333 /* calibrate the cpu(s). We will perform this task within the tests */
2334 /* themselves. If the user has specified the cpu rate, then */
2335 /* calibrate_local_cpu will return rather quickly as it will have */
2336 /* nothing to do. If local_cpu_rate is zero, then we will go through */
2337 /* all the "normal" calibration stuff and return the rate back. If */
2338 /* there is no idle counter in the kernel idle loop, the */
2339 /* local_cpu_rate will be set to -1. */
2340
2341 if (local_cpu_usage) {
2342 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
2343 }
2344
2345 /* Tell the remote end to do a listen. The server alters the socket */
2346 /* paramters on the other side at this point, hence the reason for */
2347 /* all the values being passed in the setup message. If the user did */
2348 /* not specify any of the parameters, they will be passed as 0, which */
2349 /* will indicate to the remote that no changes beyond the system's */
2350 /* default should be used. Alignment is the exception, it will */
2351 /* default to 8, which will be no alignment alterations. */
2352
2353 netperf_request.content.request_type = DO_DG_RR;
2354 dg_rr_request->recv_buf_size = rsr_size;
2355 dg_rr_request->send_buf_size = rss_size;
2356 dg_rr_request->recv_alignment = remote_recv_align;
2357 dg_rr_request->recv_offset = remote_recv_offset;
2358 dg_rr_request->send_alignment = remote_send_align;
2359 dg_rr_request->send_offset = remote_send_offset;
2360 dg_rr_request->request_size = req_size;
2361 dg_rr_request->response_size = rsp_size;
2362 dg_rr_request->measure_cpu = remote_cpu_usage;
2363 dg_rr_request->cpu_rate = remote_cpu_rate;
2364 if (test_time) {
2365 dg_rr_request->test_length = test_time;
2366 }
2367 else {
2368 dg_rr_request->test_length = test_trans * -1;
2369 }
2370
2371 if (debug > 1) {
2372 fprintf(where,"netperf: send_dg_rr: requesting DG request/response test\n");
2373 }
2374
2375 send_request();
2376
2377 /* The response from the remote will contain all of the relevant */
2378 /* socket parameters for this test type. We will put them back into */
2379 /* the variables here so they can be displayed if desired. The */
2380 /* remote will have calibrated CPU if necessary, and will have done */
2381 /* all the needed set-up we will have calibrated the cpu locally */
2382 /* before sending the request, and will grab the counter value right */
2383 /* after the connect returns. The remote will grab the counter right */
2384 /* after the accept call. This saves the hassle of extra messages */
2385 /* being sent for the DG tests. */
2386
2387 recv_response();
2388
2389 if (!netperf_response.content.serv_errno) {
2390 if (debug)
2391 fprintf(where,"remote listen done.\n");
2392 rsr_size = dg_rr_response->recv_buf_size;
2393 rss_size = dg_rr_response->send_buf_size;
2394 remote_cpu_usage= dg_rr_response->measure_cpu;
2395 remote_cpu_rate = dg_rr_response->cpu_rate;
2396 /* port numbers in proper order */
2397 strcpy(server.sun_path,dg_rr_response->unix_path);
2398 }
2399 else {
2400 Set_errno(netperf_response.content.serv_errno);
2401 perror("netperf: remote error");
2402
2403 exit(1);
2404 }
2405
2406 /* Connect up to the remote port on the data socket. This will set */
2407 /* the default destination address on this socket. we need to bind */
2408 /* out socket so that the remote gets something from a recvfrom */
2409 if (bind(send_socket,
2410 (struct sockaddr *)&myaddr_un,
2411 sizeof(myaddr_un)) == SOCKET_ERROR) {
2412 perror("netperf: send_dg_rr");
2413 unlink(myaddr_un.sun_path);
2414 close(send_socket);
2415 exit(1);
2416 }
2417
2418 if (connect(send_socket,
2419 (struct sockaddr *)&server,
2420 sizeof(server)) == INVALID_SOCKET ) {
2421 perror("netperf: data socket connect failed");
2422 exit(1);
2423 }
2424
2425 /* Data Socket set-up is finished. If there were problems, either the */
2426 /* connect would have failed, or the previous response would have */
2427 /* indicated a problem. I failed to see the value of the extra */
2428 /* message after the accept on the remote. If it failed, we'll see it */
2429 /* here. If it didn't, we might as well start pumping data. */
2430
2431 /* Set-up the test end conditions. For a request/response test, they */
2432 /* can be either time or transaction based. */
2433
2434 if (test_time) {
2435 /* The user wanted to end the test after a period of time. */
2436 times_up = 0;
2437 trans_remaining = 0;
2438 start_timer(test_time);
2439 }
2440 else {
2441 /* The tester wanted to send a number of bytes. */
2442 trans_remaining = test_bytes;
2443 times_up = 1;
2444 }
2445
2446 /* The cpu_start routine will grab the current time and possibly */
2447 /* value of the idle counter for later use in measuring cpu */
2448 /* utilization and/or service demand and thruput. */
2449
2450 cpu_start(local_cpu_usage);
2451
2452 /* We use an "OR" to control test execution. When the test is */
2453 /* controlled by time, the byte count check will always return false. */
2454 /* When the test is controlled by byte count, the time test will */
2455 /* always return false. When the test is finished, the whole */
2456 /* expression will go false and we will stop sending data. I think I */
2457 /* just arbitrarily decrement trans_remaining for the timed test, but */
2458 /* will not do that just yet... One other question is whether or not */
2459 /* the send buffer and the receive buffer should be the same buffer. */
2460 while ((!times_up) || (trans_remaining > 0)) {
2461 /* send the request */
2462#ifdef WANT_INTERVALS
2463 gettimeofday(&send_time,&dummy_zone);
2464#endif
2465 if((len=send(send_socket,
2466 send_message_ptr,
2467 req_size,
2468 0)) != req_size) {
2469 if (errno == EINTR) {
2470 /* We likely hit */
2471 /* test-end time. */
2472 break;
2473 }
2474 perror("send_dg_rr: data send error");
2475 exit(1);
2476 }
2477
2478 /* receive the response. with DG we will get it all, or nothing */
2479
2480 if((rsp_bytes_recvd=recv(send_socket,
2481 recv_message_ptr,
2482 rsp_size,
2483 0)) != rsp_size) {
2484 if (errno == EINTR) {
2485 /* Again, we have likely hit test-end time */
2486 break;
2487 }
2488 perror("send_dg_rr: data recv error");
2489 exit(1);
2490 }
2491#ifdef WANT_INTERVALS
2492 gettimeofday(&recv_time,&dummy_zone);
2493
2494 /* now we do some arithmatic on the two timevals */
2495 if (recv_time.tv_usec < send_time.tv_usec) {
2496 /* we wrapped around a second */
2497 recv_time.tv_usec += 1000000;
2498 recv_time.tv_sec -= 1;
2499 }
2500
2501 /* and store it away */
2502 kept_times[time_index] = (recv_time.tv_sec - send_time.tv_sec) * 1000000;
2503 kept_times[time_index] += (recv_time.tv_usec - send_time.tv_usec);
2504
2505 /* at this point, we may wish to sleep for some period of */
2506 /* time, so we see how long that last transaction just took, */
2507 /* and sleep for the difference of that and the interval. We */
2508 /* will not sleep if the time would be less than a */
2509 /* millisecond. */
2510 if (interval_usecs > 0) {
2511 sleep_usecs = interval_usecs - kept_times[time_index];
2512 if (sleep_usecs > 1000) {
2513 /* we sleep */
2514 sleep_timeval.tv_sec = sleep_usecs / 1000000;
2515 sleep_timeval.tv_usec = sleep_usecs % 1000000;
2516 select(0,
2517 0,
2518 0,
2519 0,
2520 &sleep_timeval);
2521 }
2522 }
2523
2524 /* now up the time index */
2525 time_index = (time_index +1)%MAX_KEPT_TIMES;
2526#endif
2527 nummessages++;
2528 if (trans_remaining) {
2529 trans_remaining--;
2530 }
2531
2532 if (debug > 3) {
2533 fprintf(where,"Transaction %d completed\n",nummessages);
2534 fflush(where);
2535 }
2536
2537 }
2538
2539 /* The test is over. Flush the buffers to the remote end. We do a */
2540 /* graceful release to insure that all data has been taken by the */
2541 /* remote. Of course, since this was a request/response test, there */
2542 /* should be no data outstanding on the socket ;-) */
2543
2544 if (shutdown(send_socket,1) == SOCKET_ERROR) {
2545 perror("netperf: cannot shutdown dg stream socket");
2546
2547 exit(1);
2548 }
2549
2550 /* this call will always give us the elapsed time for the test, and */
2551 /* will also store-away the necessaries for cpu utilization */
2552
2553 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
2554 /* how long did we really run? */
2555
2556 /* Get the statistics from the remote end. The remote will have */
2557 /* calculated service demand and all those interesting things. If it */
2558 /* wasn't supposed to care, it will return obvious values. */
2559
2560 recv_response();
2561 if (!netperf_response.content.serv_errno) {
2562 if (debug)
2563 fprintf(where,"remote results obtained\n");
2564 }
2565 else {
2566 Set_errno(netperf_response.content.serv_errno);
2567 perror("netperf: remote error");
2568
2569 exit(1);
2570 }
2571
2572 /* We now calculate what our thruput was for the test. In the future, */
2573 /* we may want to include a calculation of the thruput measured by */
2574 /* the remote, but it should be the case that for a DG stream test, */
2575 /* that the two numbers should be *very* close... We calculate */
2576 /* bytes_sent regardless of the way the test length was controlled. */
2577 /* If it was time, we needed to, and if it was by bytes, the user may */
2578 /* have specified a number of bytes that wasn't a multiple of the */
2579 /* send_size, so we really didn't send what he asked for ;-) We use */
2580
2581 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
2582 thruput = calc_thruput(bytes_xferd);
2583
2584 if (local_cpu_usage || remote_cpu_usage) {
2585 /* We must now do a little math for service demand and cpu */
2586 /* utilization for the system(s) */
2587 /* Of course, some of the information might be bogus because */
2588 /* there was no idle counter in the kernel(s). We need to make */
2589 /* a note of this for the user's benefit...*/
2590 if (local_cpu_usage) {
2591 if (local_cpu_rate == 0.0) {
2592 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
2593 fprintf(where,"Local CPU usage numbers based on process information only!\n");
2594 fflush(where);
2595 }
2596 local_cpu_utilization = calc_cpu_util(0.0);
2597 /* since calc_service demand is doing ms/Kunit we will */
2598 /* multiply the number of transaction by 1024 to get */
2599 /* "good" numbers */
2600 local_service_demand = calc_service_demand((double) nummessages*1024,
2601 0.0,
2602 0.0,
2603 0);
2604 }
2605 else {
2606 local_cpu_utilization = -1.0;
2607 local_service_demand = -1.0;
2608 }
2609
2610 if (remote_cpu_usage) {
2611 if (remote_cpu_rate == 0.0) {
2612 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
2613 fprintf(where,"Remote CPU usage numbers based on process information only!\n");
2614 fflush(where);
2615 }
2616 remote_cpu_utilization = dg_rr_result->cpu_util;
2617 /* since calc_service demand is doing ms/Kunit we will */
2618 /* multiply the number of transaction by 1024 to get */
2619 /* "good" numbers */
2620 remote_service_demand = calc_service_demand((double) nummessages*1024,
2621 0.0,
2622 remote_cpu_utilization,
2623 dg_rr_result->num_cpus);
2624 }
2625 else {
2626 remote_cpu_utilization = -1.0;
2627 remote_service_demand = -1.0;
2628 }
2629
2630 /* We are now ready to print all the information. If the user */
2631 /* has specified zero-level verbosity, we will just print the */
2632 /* local service demand, or the remote service demand. If the */
2633 /* user has requested verbosity level 1, he will get the basic */
2634 /* "streamperf" numbers. If the user has specified a verbosity */
2635 /* of greater than 1, we will display a veritable plethora of */
2636 /* background information from outside of this block as it it */
2637 /* not cpu_measurement specific... */
2638
2639 switch (verbosity) {
2640 case 0:
2641 if (local_cpu_usage) {
2642 fprintf(where,
2643 cpu_fmt_0,
2644 local_service_demand);
2645 }
2646 else {
2647 fprintf(where,
2648 cpu_fmt_0,
2649 remote_service_demand);
2650 }
2651 break;
2652 case 1:
2653 case 2:
2654 fprintf(where,
2655 cpu_fmt_1_line_1, /* the format string */
2656 lss_size, /* local sendbuf size */
2657 lsr_size,
2658 req_size, /* how large were the requests */
2659 rsp_size, /* guess */
2660 elapsed_time, /* how long was the test */
2661 nummessages/elapsed_time,
2662 local_cpu_utilization, /* local cpu */
2663 remote_cpu_utilization, /* remote cpu */
2664 local_service_demand, /* local service demand */
2665 remote_service_demand); /* remote service demand */
2666 fprintf(where,
2667 cpu_fmt_1_line_2,
2668 rss_size,
2669 rsr_size);
2670 break;
2671 }
2672 }
2673 else {
2674 /* The tester did not wish to measure service demand. */
2675 switch (verbosity) {
2676 case 0:
2677 fprintf(where,
2678 tput_fmt_0,
2679 nummessages/elapsed_time);
2680 break;
2681 case 1:
2682 case 2:
2683 fprintf(where,
2684 tput_fmt_1_line_1, /* the format string */
2685 lss_size,
2686 lsr_size,
2687 req_size, /* how large were the requests */
2688 rsp_size, /* how large were the responses */
2689 elapsed_time, /* how long did it take */
2690 nummessages/elapsed_time);
2691 fprintf(where,
2692 tput_fmt_1_line_2,
2693 rss_size, /* remote recvbuf size */
2694 rsr_size);
2695
2696 break;
2697 }
2698 }
2699
2700 /* it would be a good thing to include information about some of the */
2701 /* other parameters that may have been set for this test, but at the */
2702 /* moment, I do not wish to figure-out all the formatting, so I will */
2703 /* just put this comment here to help remind me that it is something */
2704 /* that should be done at a later time. */
2705
2706 if (verbosity > 1) {
2707 /* The user wanted to know it all, so we will give it to him. */
2708 /* This information will include as much as we can find about */
2709 /* DG statistics, the alignments of the sends and receives */
2710 /* and all that sort of rot... */
2711
2712#ifdef WANT_INTERVALS
2713 kept_times[MAX_KEPT_TIMES] = 0;
2714 time_index = 0;
2715 while (time_index < MAX_KEPT_TIMES) {
2716 if (kept_times[time_index] > 0) {
2717 total_times += kept_times[time_index];
2718 }
2719 else
2720 unused_buckets++;
2721 time_index += 1;
2722 }
2723 total_times /= (MAX_KEPT_TIMES-unused_buckets);
2724 fprintf(where,
2725 "Average response time %d usecs\n",
2726 total_times);
2727#endif
2728 }
2729 unlink(myaddr_un.sun_path);
2730}
2731
2732 /* this routine implements the receive side (netserver) of a DG_RR */
2733 /* test. */
2734void
2735recv_dg_rr()
2736{
2737
2738 struct ring_elt *recv_ring;
2739 struct ring_elt *send_ring;
2740
2741 struct sockaddr_un myaddr_un,
2742 peeraddr_un;
2743 SOCKET s_data;
2744 int addrlen;
2745 int trans_received = 0;
2746 int trans_remaining;
2747 float elapsed_time;
2748
2749 struct dg_rr_request_struct *dg_rr_request;
2750 struct dg_rr_response_struct *dg_rr_response;
2751 struct dg_rr_results_struct *dg_rr_results;
2752
2753 dg_rr_request =
2754 (struct dg_rr_request_struct *)netperf_request.content.test_specific_data;
2755 dg_rr_response =
2756 (struct dg_rr_response_struct *)netperf_response.content.test_specific_data;
2757 dg_rr_results =
2758 (struct dg_rr_results_struct *)netperf_response.content.test_specific_data;
2759
2760 if (debug) {
2761 fprintf(where,"netserver: recv_dg_rr: entered...\n");
2762 fflush(where);
2763 }
2764
2765 /* We want to set-up the listen socket with all the desired */
2766 /* parameters and then let the initiator know that all is ready. If */
2767 /* socket size defaults are to be used, then the initiator will have */
2768 /* sent us 0's. If the socket sizes cannot be changed, then we will */
2769 /* send-back what they are. If that information cannot be determined, */
2770 /* then we send-back -1's for the sizes. If things go wrong for any */
2771 /* reason, we will drop back ten yards and punt. */
2772
2773 /* If anything goes wrong, we want the remote to know about it. It */
2774 /* would be best if the error that the remote reports to the user is */
2775 /* the actual error we encountered, rather than some bogus unexpected */
2776 /* response type message. */
2777
2778 if (debug) {
2779 fprintf(where,"recv_dg_rr: setting the response type...\n");
2780 fflush(where);
2781 }
2782
2783 netperf_response.content.response_type = DG_RR_RESPONSE;
2784
2785 if (debug) {
2786 fprintf(where,"recv_dg_rr: the response type is set...\n");
2787 fflush(where);
2788 }
2789
2790 /* We now alter the message_ptr variables to be at the desired */
2791 /* alignments with the desired offsets. */
2792
2793 if (debug) {
2794 fprintf(where,"recv_dg_rr: requested recv alignment of %d offset %d\n",
2795 dg_rr_request->recv_alignment,
2796 dg_rr_request->recv_offset);
2797 fprintf(where,"recv_dg_rr: requested send alignment of %d offset %d\n",
2798 dg_rr_request->send_alignment,
2799 dg_rr_request->send_offset);
2800 fflush(where);
2801 }
2802
2803 if (send_width == 0) send_width = 1;
2804 if (recv_width == 0) recv_width = 1;
2805
2806 recv_ring = allocate_buffer_ring(recv_width,
2807 dg_rr_request->request_size,
2808 dg_rr_request->recv_alignment,
2809 dg_rr_request->recv_offset);
2810
2811 send_ring = allocate_buffer_ring(send_width,
2812 dg_rr_request->response_size,
2813 dg_rr_request->send_alignment,
2814 dg_rr_request->send_offset);
2815
2816 if (debug) {
2817 fprintf(where,"recv_dg_rr: receive alignment and offset set...\n");
2818 fflush(where);
2819 }
2820
2821 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
2822 /* can put in OUR values !-) At some point, we may want to nail this */
2823 /* socket to a particular network-level address, but for now, */
2824 /* INADDR_ANY should be just fine. */
2825
2826 bzero((char *)&myaddr_un,
2827 sizeof(myaddr_un));
2828 myaddr_un.sun_family = AF_UNIX;
2829
2830 /* Grab a socket to listen on, and then listen on it. */
2831
2832 if (debug) {
2833 fprintf(where,"recv_dg_rr: grabbing a socket...\n");
2834 fflush(where);
2835 }
2836
2837
2838 /* create_unix_socket expects to find some things in the global */
2839 /* variables, so set the globals based on the values in the request. */
2840 /* once the socket has been created, we will set the response values */
2841 /* based on the updated value of those globals. raj 7/94 */
2842 lss_size_req = dg_rr_request->send_buf_size;
2843 lsr_size_req = dg_rr_request->recv_buf_size;
2844
2845 s_data = create_unix_socket(AF_UNIX,
2846 SOCK_DGRAM);
2847
2848 if (s_data == INVALID_SOCKET) {
2849 netperf_response.content.serv_errno = errno;
2850 send_response();
2851
2852 exit(1);
2853 }
2854
2855 /* Let's get an address assigned to this socket so we can tell the */
2856 /* initiator how to reach the data socket. There may be a desire to */
2857 /* nail this socket to a specific IP address in a multi-homed, */
2858 /* multi-connection situation, but for now, we'll ignore the issue */
2859 /* and concentrate on single connection testing. */
2860
2861 strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf."));
2862 if (bind(s_data,
2863 (struct sockaddr *)&myaddr_un,
2864 sizeof(myaddr_un)) == SOCKET_ERROR) {
2865 netperf_response.content.serv_errno = errno;
2866 unlink(myaddr_un.sun_path);
2867 close(s_data);
2868 send_response();
2869
2870 exit(1);
2871 }
2872
2873 /* Now myaddr_un contains the port and the internet address this is */
2874 /* returned to the sender also implicitly telling the sender that the */
2875 /* socket buffer sizing has been done. */
2876
2877 strcpy(dg_rr_response->unix_path,myaddr_un.sun_path);
2878 netperf_response.content.serv_errno = 0;
2879
2880 /* But wait, there's more. If the initiator wanted cpu measurements, */
2881 /* then we must call the calibrate routine, which will return the max */
2882 /* rate back to the initiator. If the CPU was not to be measured, or */
2883 /* something went wrong with the calibration, we will return a 0.0 to */
2884 /* the initiator. */
2885
2886 dg_rr_response->cpu_rate = 0.0; /* assume no cpu */
2887 if (dg_rr_request->measure_cpu) {
2888 dg_rr_response->measure_cpu = 1;
2889 dg_rr_response->cpu_rate = calibrate_local_cpu(dg_rr_request->cpu_rate);
2890 }
2891
2892 /* before we send the response back to the initiator, pull some of */
2893 /* the socket parms from the globals */
2894 dg_rr_response->send_buf_size = lss_size;
2895 dg_rr_response->recv_buf_size = lsr_size;
2896
2897 send_response();
2898
2899
2900 /* Now it's time to start receiving data on the connection. We will */
2901 /* first grab the apropriate counters and then start grabbing. */
2902
2903 cpu_start(dg_rr_request->measure_cpu);
2904
2905 if (dg_rr_request->test_length > 0) {
2906 times_up = 0;
2907 trans_remaining = 0;
2908 start_timer(dg_rr_request->test_length + PAD_TIME);
2909 }
2910 else {
2911 times_up = 1;
2912 trans_remaining = dg_rr_request->test_length * -1;
2913 }
2914
2915 addrlen = sizeof(peeraddr_un);
2916 bzero((char *)&peeraddr_un, addrlen);
2917
2918 while ((!times_up) || (trans_remaining > 0)) {
2919
2920 /* receive the request from the other side */
2921 fprintf(where,"socket %d ptr %p size %d\n",
2922 s_data,
2923 recv_ring->buffer_ptr,
2924 dg_rr_request->request_size);
2925 fflush(where);
2926 if (recvfrom(s_data,
2927 recv_ring->buffer_ptr,
2928 dg_rr_request->request_size,
2929 0,
2930 (struct sockaddr *)&peeraddr_un,
2931 &addrlen) != dg_rr_request->request_size) {
2932 if (errno == EINTR) {
2933 /* we must have hit the end of test time. */
2934 break;
2935 }
2936 netperf_response.content.serv_errno = errno;
2937 fprintf(where,"error on recvfrom errno %d\n",errno);
2938 fflush(where);
2939 send_response();
2940 unlink(myaddr_un.sun_path);
2941 exit(1);
2942 }
2943 recv_ring = recv_ring->next;
2944
2945 /* Now, send the response to the remote */
2946 if (sendto(s_data,
2947 send_ring->buffer_ptr,
2948 dg_rr_request->response_size,
2949 0,
2950 (struct sockaddr *)&peeraddr_un,
2951 addrlen) != dg_rr_request->response_size) {
2952 if (errno == EINTR) {
2953 /* we have hit end of test time. */
2954 break;
2955 }
2956 netperf_response.content.serv_errno = errno;
2957 fprintf(where,"error on recvfrom errno %d\n",errno);
2958 fflush(where);
2959 unlink(myaddr_un.sun_path);
2960 send_response();
2961 exit(1);
2962 }
2963 send_ring = send_ring->next;
2964
2965 trans_received++;
2966 if (trans_remaining) {
2967 trans_remaining--;
2968 }
2969
2970 if (debug) {
2971 fprintf(where,
2972 "recv_dg_rr: Transaction %d complete.\n",
2973 trans_received);
2974 fflush(where);
2975 }
2976
2977 }
2978
2979
2980 /* The loop now exits due to timeout or transaction count being */
2981 /* reached */
2982
2983 cpu_stop(dg_rr_request->measure_cpu,&elapsed_time);
2984
2985 if (times_up) {
2986 /* we ended the test by time, which was at least 2 seconds */
2987 /* longer than we wanted to run. so, we want to subtract */
2988 /* PAD_TIME from the elapsed_time. */
2989 elapsed_time -= PAD_TIME;
2990 }
2991 /* send the results to the sender */
2992
2993 if (debug) {
2994 fprintf(where,
2995 "recv_dg_rr: got %d transactions\n",
2996 trans_received);
2997 fflush(where);
2998 }
2999
3000 dg_rr_results->bytes_received = (trans_received *
3001 (dg_rr_request->request_size +
3002 dg_rr_request->response_size));
3003 dg_rr_results->trans_received = trans_received;
3004 dg_rr_results->elapsed_time = elapsed_time;
3005 if (dg_rr_request->measure_cpu) {
3006 dg_rr_results->cpu_util = calc_cpu_util(elapsed_time);
3007 }
3008
3009 if (debug) {
3010 fprintf(where,
3011 "recv_dg_rr: test complete, sending results.\n");
3012 fflush(where);
3013 }
3014
3015 send_response();
3016 unlink(myaddr_un.sun_path);
3017
3018}
3019 /* this routine implements the receive (netserver) side of a STREAM_RR */
3020 /* test */
3021
3022void
3023recv_stream_rr()
3024{
3025
3026 struct ring_elt *send_ring;
3027 struct ring_elt *recv_ring;
3028
3029 struct sockaddr_un myaddr_un,
3030 peeraddr_un;
3031 SOCKET s_listen,s_data;
3032 int addrlen;
3033 char *temp_message_ptr;
3034 int trans_received = 0;
3035 int trans_remaining;
3036 int bytes_sent;
3037 int request_bytes_recvd;
3038 int request_bytes_remaining;
3039 int timed_out = 0;
3040 float elapsed_time;
3041
3042 struct stream_rr_request_struct *stream_rr_request;
3043 struct stream_rr_response_struct *stream_rr_response;
3044 struct stream_rr_results_struct *stream_rr_results;
3045
3046 stream_rr_request =
3047 (struct stream_rr_request_struct *)netperf_request.content.test_specific_data;
3048 stream_rr_response =
3049 (struct stream_rr_response_struct *)netperf_response.content.test_specific_data;
3050 stream_rr_results =
3051 (struct stream_rr_results_struct *)netperf_response.content.test_specific_data;
3052
3053 if (debug) {
3054 fprintf(where,"netserver: recv_stream_rr: entered...\n");
3055 fflush(where);
3056 }
3057
3058 /* We want to set-up the listen socket with all the desired */
3059 /* parameters and then let the initiator know that all is ready. If */
3060 /* socket size defaults are to be used, then the initiator will have */
3061 /* sent us 0's. If the socket sizes cannot be changed, then we will */
3062 /* send-back what they are. If that information cannot be determined, */
3063 /* then we send-back -1's for the sizes. If things go wrong for any */
3064 /* reason, we will drop back ten yards and punt. */
3065
3066 /* If anything goes wrong, we want the remote to know about it. It */
3067 /* would be best if the error that the remote reports to the user is */
3068 /* the actual error we encountered, rather than some bogus unexpected */
3069 /* response type message. */
3070
3071 if (debug) {
3072 fprintf(where,"recv_stream_rr: setting the response type...\n");
3073 fflush(where);
3074 }
3075
3076 netperf_response.content.response_type = STREAM_RR_RESPONSE;
3077
3078 if (debug) {
3079 fprintf(where,"recv_stream_rr: the response type is set...\n");
3080 fflush(where);
3081 }
3082
3083 /* allocate the recv and send rings with the requested alignments */
3084 /* and offsets. raj 7/94 */
3085 if (debug) {
3086 fprintf(where,"recv_stream_rr: requested recv alignment of %d offset %d\n",
3087 stream_rr_request->recv_alignment,
3088 stream_rr_request->recv_offset);
3089 fprintf(where,"recv_stream_rr: requested send alignment of %d offset %d\n",
3090 stream_rr_request->send_alignment,
3091 stream_rr_request->send_offset);
3092 fflush(where);
3093 }
3094
3095 /* at some point, these need to come to us from the remote system */
3096 if (send_width == 0) send_width = 1;
3097 if (recv_width == 0) recv_width = 1;
3098
3099 send_ring = allocate_buffer_ring(send_width,
3100 stream_rr_request->response_size,
3101 stream_rr_request->send_alignment,
3102 stream_rr_request->send_offset);
3103
3104 recv_ring = allocate_buffer_ring(recv_width,
3105 stream_rr_request->request_size,
3106 stream_rr_request->recv_alignment,
3107 stream_rr_request->recv_offset);
3108
3109
3110 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
3111 /* can put in OUR values !-) At some point, we may want to nail this */
3112 /* socket to a particular network-level address, but for now, */
3113 /* INADDR_ANY should be just fine. */
3114
3115 bzero((char *)&myaddr_un,
3116 sizeof(myaddr_un));
3117 myaddr_un.sun_family = AF_UNIX;
3118
3119 /* Grab a socket to listen on, and then listen on it. */
3120
3121 if (debug) {
3122 fprintf(where,"recv_stream_rr: grabbing a socket...\n");
3123 fflush(where);
3124 }
3125
3126 /* create_unix_socket expects to find some things in the global */
3127 /* variables, so set the globals based on the values in the request. */
3128 /* once the socket has been created, we will set the response values */
3129 /* based on the updated value of those globals. raj 7/94 */
3130 lss_size_req = stream_rr_request->send_buf_size;
3131 lsr_size_req = stream_rr_request->recv_buf_size;
3132
3133 s_listen = create_unix_socket(AF_UNIX,
3134 SOCK_STREAM);
3135
3136 if (s_listen == INVALID_SOCKET) {
3137 netperf_response.content.serv_errno = errno;
3138 send_response();
3139
3140 exit(1);
3141 }
3142
3143 /* Let's get an address assigned to this socket so we can tell the */
3144 /* initiator how to reach the data socket. There may be a desire to */
3145 /* nail this socket to a specific IP address in a multi-homed, */
3146 /* multi-connection situation, but for now, we'll ignore the issue */
3147 /* and concentrate on single connection testing. */
3148
3149 strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf."));
3150 if (bind(s_listen,
3151 (struct sockaddr *)&myaddr_un,
3152 sizeof(myaddr_un)) == SOCKET_ERROR) {
3153 netperf_response.content.serv_errno = errno;
3154 unlink(myaddr_un.sun_path);
3155 close(s_listen);
3156 send_response();
3157
3158 exit(1);
3159 }
3160
3161 /* Now, let's set-up the socket to listen for connections */
3162 if (listen(s_listen, 5) == SOCKET_ERROR) {
3163 netperf_response.content.serv_errno = errno;
3164 close(s_listen);
3165 send_response();
3166
3167 exit(1);
3168 }
3169
3170 /* Now myaddr_un contains the port and the internet address this is */
3171 /* returned to the sender also implicitly telling the sender that the */
3172 /* socket buffer sizing has been done. */
3173
3174 strcpy(stream_rr_response->unix_path,myaddr_un.sun_path);
3175 netperf_response.content.serv_errno = 0;
3176
3177 /* But wait, there's more. If the initiator wanted cpu measurements, */
3178 /* then we must call the calibrate routine, which will return the max */
3179 /* rate back to the initiator. If the CPU was not to be measured, or */
3180 /* something went wrong with the calibration, we will return a 0.0 to */
3181 /* the initiator. */
3182
3183 stream_rr_response->cpu_rate = 0.0; /* assume no cpu */
3184 if (stream_rr_request->measure_cpu) {
3185 stream_rr_response->measure_cpu = 1;
3186 stream_rr_response->cpu_rate = calibrate_local_cpu(stream_rr_request->cpu_rate);
3187 }
3188
3189
3190 /* before we send the response back to the initiator, pull some of */
3191 /* the socket parms from the globals */
3192 stream_rr_response->send_buf_size = lss_size;
3193 stream_rr_response->recv_buf_size = lsr_size;
3194
3195 send_response();
3196
3197 addrlen = sizeof(peeraddr_un);
3198
3199 if ((s_data = accept(s_listen,
3200 (struct sockaddr *)&peeraddr_un,
3201 &addrlen)) == INVALID_SOCKET) {
3202 /* Let's just punt. The remote will be given some information */
3203 close(s_listen);
3204
3205 exit(1);
3206 }
3207
3208 if (debug) {
3209 fprintf(where,"recv_stream_rr: accept completes on the data connection.\n");
3210 fflush(where);
3211 }
3212
3213 /* Now it's time to start receiving data on the connection. We will */
3214 /* first grab the apropriate counters and then start grabbing. */
3215
3216 cpu_start(stream_rr_request->measure_cpu);
3217
3218 /* The loop will exit when the sender does a shutdown, which will */
3219 /* return a length of zero */
3220
3221 if (stream_rr_request->test_length > 0) {
3222 times_up = 0;
3223 trans_remaining = 0;
3224 start_timer(stream_rr_request->test_length + PAD_TIME);
3225 }
3226 else {
3227 times_up = 1;
3228 trans_remaining = stream_rr_request->test_length * -1;
3229 }
3230
3231 while ((!times_up) || (trans_remaining > 0)) {
3232 temp_message_ptr = recv_ring->buffer_ptr;
3233 request_bytes_remaining = stream_rr_request->request_size;
3234
3235 /* receive the request from the other side */
3236 if (debug) {
3237 fprintf(where,"about to receive for trans %d\n",trans_received);
3238 fprintf(where,"temp_message_ptr is %p\n",temp_message_ptr);
3239 fflush(where);
3240 }
3241 while(request_bytes_remaining > 0) {
3242 if((request_bytes_recvd=recv(s_data,
3243 temp_message_ptr,
3244 request_bytes_remaining,
3245 0)) == SOCKET_ERROR) {
3246 if (errno == EINTR) {
3247 /* the timer popped */
3248 timed_out = 1;
3249 break;
3250 }
3251 netperf_response.content.serv_errno = errno;
3252 send_response();
3253 exit(1);
3254 }
3255 else {
3256 request_bytes_remaining -= request_bytes_recvd;
3257 temp_message_ptr += request_bytes_recvd;
3258 }
3259 if (debug) {
3260 fprintf(where,"just received for trans %d\n",trans_received);
3261 fflush(where);
3262 }
3263 }
3264
3265 recv_ring = recv_ring->next;
3266
3267 if (timed_out) {
3268 /* we hit the end of the test based on time - lets */
3269 /* bail out of here now... */
3270 fprintf(where,"yo5\n");
3271 fflush(where);
3272 break;
3273 }
3274
3275 /* Now, send the response to the remote */
3276 if (debug) {
3277 fprintf(where,"about to send for trans %d\n",trans_received);
3278 fflush(where);
3279 }
3280 if((bytes_sent=send(s_data,
3281 send_ring->buffer_ptr,
3282 stream_rr_request->response_size,
3283 0)) == SOCKET_ERROR) {
3284 if (errno == EINTR) {
3285 /* the test timer has popped */
3286 timed_out = 1;
3287 fprintf(where,"yo6\n");
3288 fflush(where);
3289 break;
3290 }
3291 netperf_response.content.serv_errno = 997;
3292 send_response();
3293 exit(1);
3294 }
3295
3296 send_ring = send_ring->next;
3297
3298 trans_received++;
3299 if (trans_remaining) {
3300 trans_remaining--;
3301 }
3302
3303 if (debug) {
3304 fprintf(where,
3305 "recv_stream_rr: Transaction %d complete\n",
3306 trans_received);
3307 fflush(where);
3308 }
3309 }
3310
3311
3312 /* The loop now exits due to timeout or transaction count being */
3313 /* reached */
3314
3315 cpu_stop(stream_rr_request->measure_cpu,&elapsed_time);
3316
3317 if (timed_out) {
3318 /* we ended the test by time, which was at least 2 seconds */
3319 /* longer than we wanted to run. so, we want to subtract */
3320 /* PAD_TIME from the elapsed_time. */
3321 elapsed_time -= PAD_TIME;
3322 }
3323 /* send the results to the sender */
3324
3325 if (debug) {
3326 fprintf(where,
3327 "recv_stream_rr: got %d transactions\n",
3328 trans_received);
3329 fflush(where);
3330 }
3331
3332 stream_rr_results->bytes_received = (trans_received *
3333 (stream_rr_request->request_size +
3334 stream_rr_request->response_size));
3335 stream_rr_results->trans_received = trans_received;
3336 stream_rr_results->elapsed_time = elapsed_time;
3337 if (stream_rr_request->measure_cpu) {
3338 stream_rr_results->cpu_util = calc_cpu_util(elapsed_time);
3339 }
3340
3341 if (debug) {
3342 fprintf(where,
3343 "recv_stream_rr: test complete, sending results.\n");
3344 fflush(where);
3345 }
3346
3347 send_response();
3348 unlink(myaddr_un.sun_path);
3349}
3350
3351void
3352print_unix_usage()
3353{
3354
3355 fwrite(unix_usage, sizeof(char), strlen(unix_usage), stdout);
3356 exit(1);
3357
3358}
3359void
3360scan_unix_args(int argc, char *argv[])
3361{
3362#define UNIX_ARGS "hm:M:p:r:s:S:"
3363 extern char *optarg; /* pointer to option string */
3364
3365 int c;
3366
3367 char
3368 arg1[BUFSIZ], /* argument holders */
3369 arg2[BUFSIZ];
3370
3371 init_test_vars();
3372
3373 if (no_control) {
3374 fprintf(where,
3375 "The UNIX tests do not know how to run with no control connection\n");
3376 exit(-1);
3377 }
3378
3379 /* Go through all the command line arguments and break them */
3380 /* out. For those options that take two parms, specifying only */
3381 /* the first will set both to that value. Specifying only the */
3382 /* second will leave the first untouched. To change only the */
3383 /* first, use the form "first," (see the routine break_args.. */
3384
3385 while ((c= getopt(argc, argv, UNIX_ARGS)) != EOF) {
3386 switch (c) {
3387 case '?':
3388 case 'h':
3389 print_unix_usage();
3390 exit(1);
3391 case 'p':
3392 /* set the path prefix (directory) that should be used for the */
3393 /* pipes. at some point, there should be some error checking. */
3394 strcpy(path_prefix,optarg);
3395 break;
3396 case 's':
3397 /* set local socket sizes */
3398 break_args(optarg,arg1,arg2);
3399 if (arg1[0])
3400 lss_size_req = atoi(arg1);
3401 if (arg2[0])
3402 lsr_size_req = atoi(arg2);
3403 break;
3404 case 'S':
3405 /* set remote socket sizes */
3406 break_args(optarg,arg1,arg2);
3407 if (arg1[0])
3408 rss_size = atoi(arg1);
3409 if (arg2[0])
3410 rsr_size = atoi(arg2);
3411 break;
3412 case 'r':
3413 /* set the request/response sizes */
3414 break_args(optarg,arg1,arg2);
3415 if (arg1[0])
3416 req_size = atoi(arg1);
3417 if (arg2[0])
3418 rsp_size = atoi(arg2);
3419 break;
3420 case 'm':
3421 /* set the send size */
3422 send_size = atoi(optarg);
3423 break;
3424 case 'M':
3425 /* set the recv size */
3426 recv_size = atoi(optarg);
3427 break;
3428 };
3429 }
3430}
3431#endif /* WANT_UNIX */