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