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