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