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