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