1 /* 2 * Copyright (c) 1997, 1998 Kenneth D. Merry. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/types.h> 32 #include <sys/sysctl.h> 33 #include <sys/errno.h> 34 #include <sys/dkstat.h> 35 #include <sys/queue.h> 36 37 #include <ctype.h> 38 #include <err.h> 39 #include <fcntl.h> 40 #include <limits.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <stdarg.h> 45 #include <kvm.h> 46 47 #include "devstat.h" 48 49 typedef enum { 50 DEVSTAT_ARG_NOTYPE, 51 DEVSTAT_ARG_UINT64, 52 DEVSTAT_ARG_LD 53 } devstat_arg_type; 54 55 char devstat_errbuf[DEVSTAT_ERRBUF_SIZE]; 56 57 /* 58 * Table to match descriptive strings with device types. These are in 59 * order from most common to least common to speed search time. 60 */ 61 struct devstat_match_table match_table[] = { 62 {"da", DEVSTAT_TYPE_DIRECT, DEVSTAT_MATCH_TYPE}, 63 {"cd", DEVSTAT_TYPE_CDROM, DEVSTAT_MATCH_TYPE}, 64 {"scsi", DEVSTAT_TYPE_IF_SCSI, DEVSTAT_MATCH_IF}, 65 {"ide", DEVSTAT_TYPE_IF_IDE, DEVSTAT_MATCH_IF}, 66 {"other", DEVSTAT_TYPE_IF_OTHER, DEVSTAT_MATCH_IF}, 67 {"worm", DEVSTAT_TYPE_WORM, DEVSTAT_MATCH_TYPE}, 68 {"sa", DEVSTAT_TYPE_SEQUENTIAL,DEVSTAT_MATCH_TYPE}, 69 {"pass", DEVSTAT_TYPE_PASS, DEVSTAT_MATCH_PASS}, 70 {"optical", DEVSTAT_TYPE_OPTICAL, DEVSTAT_MATCH_TYPE}, 71 {"array", DEVSTAT_TYPE_STORARRAY, DEVSTAT_MATCH_TYPE}, 72 {"changer", DEVSTAT_TYPE_CHANGER, DEVSTAT_MATCH_TYPE}, 73 {"scanner", DEVSTAT_TYPE_SCANNER, DEVSTAT_MATCH_TYPE}, 74 {"printer", DEVSTAT_TYPE_PRINTER, DEVSTAT_MATCH_TYPE}, 75 {"floppy", DEVSTAT_TYPE_FLOPPY, DEVSTAT_MATCH_TYPE}, 76 {"proc", DEVSTAT_TYPE_PROCESSOR, DEVSTAT_MATCH_TYPE}, 77 {"comm", DEVSTAT_TYPE_COMM, DEVSTAT_MATCH_TYPE}, 78 {"enclosure", DEVSTAT_TYPE_ENCLOSURE, DEVSTAT_MATCH_TYPE}, 79 {NULL, 0, 0} 80 }; 81 82 struct devstat_args { 83 devstat_metric metric; 84 devstat_arg_type argtype; 85 } devstat_arg_list[] = { 86 { DSM_NONE, DEVSTAT_ARG_NOTYPE }, 87 { DSM_TOTAL_BYTES, DEVSTAT_ARG_UINT64 }, 88 { DSM_TOTAL_BYTES_READ, DEVSTAT_ARG_UINT64 }, 89 { DSM_TOTAL_BYTES_WRITE, DEVSTAT_ARG_UINT64 }, 90 { DSM_TOTAL_TRANSFERS, DEVSTAT_ARG_UINT64 }, 91 { DSM_TOTAL_TRANSFERS_READ, DEVSTAT_ARG_UINT64 }, 92 { DSM_TOTAL_TRANSFERS_WRITE, DEVSTAT_ARG_UINT64 }, 93 { DSM_TOTAL_TRANSFERS_OTHER, DEVSTAT_ARG_UINT64 }, 94 { DSM_TOTAL_BLOCKS, DEVSTAT_ARG_UINT64 }, 95 { DSM_TOTAL_BLOCKS_READ, DEVSTAT_ARG_UINT64 }, 96 { DSM_TOTAL_BLOCKS_WRITE, DEVSTAT_ARG_UINT64 }, 97 { DSM_KB_PER_TRANSFER, DEVSTAT_ARG_LD }, 98 { DSM_KB_PER_TRANSFER_READ, DEVSTAT_ARG_LD }, 99 { DSM_KB_PER_TRANSFER_WRITE, DEVSTAT_ARG_LD }, 100 { DSM_TRANSFERS_PER_SECOND, DEVSTAT_ARG_LD }, 101 { DSM_TRANSFERS_PER_SECOND_READ, DEVSTAT_ARG_LD }, 102 { DSM_TRANSFERS_PER_SECOND_WRITE, DEVSTAT_ARG_LD }, 103 { DSM_TRANSFERS_PER_SECOND_OTHER, DEVSTAT_ARG_LD }, 104 { DSM_MB_PER_SECOND, DEVSTAT_ARG_LD }, 105 { DSM_MB_PER_SECOND_READ, DEVSTAT_ARG_LD }, 106 { DSM_MB_PER_SECOND_WRITE, DEVSTAT_ARG_LD }, 107 { DSM_BLOCKS_PER_SECOND, DEVSTAT_ARG_LD }, 108 { DSM_BLOCKS_PER_SECOND_READ, DEVSTAT_ARG_LD }, 109 { DSM_BLOCKS_PER_SECOND_WRITE, DEVSTAT_ARG_LD }, 110 { DSM_MS_PER_TRANSACTION, DEVSTAT_ARG_LD }, 111 { DSM_MS_PER_TRANSACTION_READ, DEVSTAT_ARG_LD }, 112 { DSM_MS_PER_TRANSACTION_WRITE, DEVSTAT_ARG_LD } 113 }; 114 115 static char *namelist[] = { 116 #define X_NUMDEVS 0 117 "_devstat_num_devs", 118 #define X_GENERATION 1 119 "_devstat_generation", 120 #define X_VERSION 2 121 "_devstat_version", 122 #define X_DEVICE_STATQ 3 123 "_device_statq", 124 #define X_END 4 125 }; 126 127 /* 128 * Local function declarations. 129 */ 130 static int compare_select(const void *arg1, const void *arg2); 131 static int readkmem(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes); 132 static int readkmem_nl(kvm_t *kd, char *name, void *buf, size_t nbytes); 133 static char *get_devstat_kvm(kvm_t *kd); 134 135 #define KREADNL(kd, var, val) \ 136 readkmem_nl(kd, namelist[var], &val, sizeof(val)) 137 138 int 139 devstat_getnumdevs(kvm_t *kd) 140 { 141 size_t numdevsize; 142 int numdevs; 143 char *func_name = "devstat_getnumdevs"; 144 145 numdevsize = sizeof(int); 146 147 /* 148 * Find out how many devices we have in the system. 149 */ 150 if (kd == NULL) { 151 if (sysctlbyname("kern.devstat.numdevs", &numdevs, 152 &numdevsize, NULL, 0) == -1) { 153 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 154 "%s: error getting number of devices\n" 155 "%s: %s", func_name, func_name, 156 strerror(errno)); 157 return(-1); 158 } else 159 return(numdevs); 160 } else { 161 if (KREADNL(kd, X_NUMDEVS, numdevs) == -1) 162 return(-1); 163 else 164 return(numdevs); 165 } 166 } 167 168 /* 169 * This is an easy way to get the generation number, but the generation is 170 * supplied in a more atmoic manner by the kern.devstat.all sysctl. 171 * Because this generation sysctl is separate from the statistics sysctl, 172 * the device list and the generation could change between the time that 173 * this function is called and the device list is retreived. 174 */ 175 long 176 devstat_getgeneration(kvm_t *kd) 177 { 178 size_t gensize; 179 long generation; 180 char *func_name = "devstat_getgeneration"; 181 182 gensize = sizeof(long); 183 184 /* 185 * Get the current generation number. 186 */ 187 if (kd == NULL) { 188 if (sysctlbyname("kern.devstat.generation", &generation, 189 &gensize, NULL, 0) == -1) { 190 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 191 "%s: error getting devstat generation\n%s: %s", 192 func_name, func_name, strerror(errno)); 193 return(-1); 194 } else 195 return(generation); 196 } else { 197 if (KREADNL(kd, X_GENERATION, generation) == -1) 198 return(-1); 199 else 200 return(generation); 201 } 202 } 203 204 /* 205 * Get the current devstat version. The return value of this function 206 * should be compared with DEVSTAT_VERSION, which is defined in 207 * sys/devicestat.h. This will enable userland programs to determine 208 * whether they are out of sync with the kernel. 209 */ 210 int 211 devstat_getversion(kvm_t *kd) 212 { 213 size_t versize; 214 int version; 215 char *func_name = "devstat_getversion"; 216 217 versize = sizeof(int); 218 219 /* 220 * Get the current devstat version. 221 */ 222 if (kd == NULL) { 223 if (sysctlbyname("kern.devstat.version", &version, &versize, 224 NULL, 0) == -1) { 225 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 226 "%s: error getting devstat version\n%s: %s", 227 func_name, func_name, strerror(errno)); 228 return(-1); 229 } else 230 return(version); 231 } else { 232 if (KREADNL(kd, X_VERSION, version) == -1) 233 return(-1); 234 else 235 return(version); 236 } 237 } 238 239 /* 240 * Check the devstat version we know about against the devstat version the 241 * kernel knows about. If they don't match, print an error into the 242 * devstat error buffer, and return -1. If they match, return 0. 243 */ 244 int 245 devstat_checkversion(kvm_t *kd) 246 { 247 int retval = 0; 248 int errlen = 0; 249 char *func_name = "devstat_checkversion"; 250 int version; 251 252 version = devstat_getversion(kd); 253 254 if (version != DEVSTAT_VERSION) { 255 int buflen = 0; 256 char tmpstr[256]; 257 258 /* 259 * This is really pretty silly, but basically the idea is 260 * that if getversion() returns an error (i.e. -1), then it 261 * has printed an error message in the buffer. Therefore, 262 * we need to add a \n to the end of that message before we 263 * print our own message in the buffer. 264 */ 265 if (version == -1) { 266 buflen = strlen(devstat_errbuf); 267 errlen = snprintf(tmpstr, sizeof(tmpstr), "\n"); 268 strncat(devstat_errbuf, tmpstr, 269 DEVSTAT_ERRBUF_SIZE - buflen - 1); 270 buflen += errlen; 271 } 272 273 errlen = snprintf(tmpstr, sizeof(tmpstr), 274 "%s: userland devstat version %d is not " 275 "the same as the kernel\n%s: devstat " 276 "version %d\n", func_name, DEVSTAT_VERSION, 277 func_name, version); 278 279 if (version == -1) { 280 strncat(devstat_errbuf, tmpstr, 281 DEVSTAT_ERRBUF_SIZE - buflen - 1); 282 buflen += errlen; 283 } else { 284 strncpy(devstat_errbuf, tmpstr, DEVSTAT_ERRBUF_SIZE); 285 devstat_errbuf[DEVSTAT_ERRBUF_SIZE - 1] = '\0'; 286 } 287 288 if (version < DEVSTAT_VERSION) 289 snprintf(tmpstr, sizeof(tmpstr), 290 "%s: libdevstat newer than kernel\n", 291 func_name); 292 else 293 snprintf(tmpstr, sizeof(tmpstr), 294 "%s: kernel newer than libdevstat\n", 295 func_name); 296 297 strncat(devstat_errbuf, tmpstr, 298 DEVSTAT_ERRBUF_SIZE - buflen - 1); 299 300 retval = -1; 301 } 302 303 return(retval); 304 } 305 306 /* 307 * Get the current list of devices and statistics, and the current 308 * generation number. 309 * 310 * Return values: 311 * -1 -- error 312 * 0 -- device list is unchanged 313 * 1 -- device list has changed 314 */ 315 int 316 devstat_getdevs(kvm_t *kd, struct statinfo *stats) 317 { 318 int error; 319 size_t dssize; 320 int oldnumdevs; 321 long oldgeneration; 322 int retval = 0; 323 struct devinfo *dinfo; 324 char *func_name = "devstat_getdevs"; 325 326 dinfo = stats->dinfo; 327 328 if (dinfo == NULL) { 329 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 330 "%s: stats->dinfo was NULL", func_name); 331 return(-1); 332 } 333 334 oldnumdevs = dinfo->numdevs; 335 oldgeneration = dinfo->generation; 336 337 /* Get the current time when we get the stats */ 338 gettimeofday(&stats->busy_time, NULL); 339 340 if (kd == NULL) { 341 /* If this is our first time through, mem_ptr will be null. */ 342 if (dinfo->mem_ptr == NULL) { 343 /* 344 * Get the number of devices. If it's negative, it's an 345 * error. Don't bother setting the error string, since 346 * getnumdevs() has already done that for us. 347 */ 348 if ((dinfo->numdevs = getnumdevs()) < 0) 349 return(-1); 350 351 /* 352 * The kern.devstat.all sysctl returns the current 353 * generation number, as well as all the devices. 354 * So we need four bytes more. 355 */ 356 dssize = (dinfo->numdevs * sizeof(struct devstat)) + 357 sizeof(long); 358 dinfo->mem_ptr = (u_int8_t *)malloc(dssize); 359 } else 360 dssize = (dinfo->numdevs * sizeof(struct devstat)) + 361 sizeof(long); 362 363 /* 364 * Request all of the devices. We only really allow for one 365 * ENOMEM failure. It would, of course, be possible to just go 366 * in a loop and keep reallocing the device structure until we 367 * don't get ENOMEM back. I'm not sure it's worth it, though. 368 * If devices are being added to the system that quickly, maybe 369 * the user can just wait until all devices are added. 370 */ 371 if ((error = sysctlbyname("kern.devstat.all", dinfo->mem_ptr, 372 &dssize, NULL, 0)) == -1) { 373 /* 374 * If we get ENOMEM back, that means that there are 375 * more devices now, so we need to allocate more 376 * space for the device array. 377 */ 378 if (errno == ENOMEM) { 379 /* 380 * No need to set the error string here, 381 * getnumdevs() will do that if it fails. 382 */ 383 if ((dinfo->numdevs = getnumdevs()) < 0) 384 return(-1); 385 386 dssize = (dinfo->numdevs * 387 sizeof(struct devstat)) + sizeof(long); 388 dinfo->mem_ptr = (u_int8_t *) 389 realloc(dinfo->mem_ptr, dssize); 390 if ((error = sysctlbyname("kern.devstat.all", 391 dinfo->mem_ptr, &dssize, NULL, 0)) == -1) { 392 snprintf(devstat_errbuf, 393 sizeof(devstat_errbuf), 394 "%s: error getting device " 395 "stats\n%s: %s", func_name, 396 func_name, strerror(errno)); 397 return(-1); 398 } 399 } else { 400 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 401 "%s: error getting device stats\n" 402 "%s: %s", func_name, func_name, 403 strerror(errno)); 404 return(-1); 405 } 406 } 407 408 } else { 409 /* 410 * This is of course non-atomic, but since we are working 411 * on a core dump, the generation is unlikely to change 412 */ 413 if ((dinfo->numdevs = getnumdevs()) == -1) 414 return(-1); 415 if ((dinfo->mem_ptr = get_devstat_kvm(kd)) == NULL) 416 return(-1); 417 } 418 /* 419 * The sysctl spits out the generation as the first four bytes, 420 * then all of the device statistics structures. 421 */ 422 dinfo->generation = *(long *)dinfo->mem_ptr; 423 424 /* 425 * If the generation has changed, and if the current number of 426 * devices is not the same as the number of devices recorded in the 427 * devinfo structure, it is likely that the device list has shrunk. 428 * The reason that it is likely that the device list has shrunk in 429 * this case is that if the device list has grown, the sysctl above 430 * will return an ENOMEM error, and we will reset the number of 431 * devices and reallocate the device array. If the second sysctl 432 * fails, we will return an error and therefore never get to this 433 * point. If the device list has shrunk, the sysctl will not 434 * return an error since we have more space allocated than is 435 * necessary. So, in the shrinkage case, we catch it here and 436 * reallocate the array so that we don't use any more space than is 437 * necessary. 438 */ 439 if (oldgeneration != dinfo->generation) { 440 if (getnumdevs() != dinfo->numdevs) { 441 if ((dinfo->numdevs = getnumdevs()) < 0) 442 return(-1); 443 dssize = (dinfo->numdevs * sizeof(struct devstat)) + 444 sizeof(long); 445 dinfo->mem_ptr = (u_int8_t *)realloc(dinfo->mem_ptr, 446 dssize); 447 } 448 retval = 1; 449 } 450 451 dinfo->devices = (struct devstat *)(dinfo->mem_ptr + sizeof(long)); 452 453 return(retval); 454 } 455 456 /* 457 * selectdevs(): 458 * 459 * Devices are selected/deselected based upon the following criteria: 460 * - devices specified by the user on the command line 461 * - devices matching any device type expressions given on the command line 462 * - devices with the highest I/O, if 'top' mode is enabled 463 * - the first n unselected devices in the device list, if maxshowdevs 464 * devices haven't already been selected and if the user has not 465 * specified any devices on the command line and if we're in "add" mode. 466 * 467 * Input parameters: 468 * - device selection list (dev_select) 469 * - current number of devices selected (num_selected) 470 * - total number of devices in the selection list (num_selections) 471 * - devstat generation as of the last time selectdevs() was called 472 * (select_generation) 473 * - current devstat generation (current_generation) 474 * - current list of devices and statistics (devices) 475 * - number of devices in the current device list (numdevs) 476 * - compiled version of the command line device type arguments (matches) 477 * - This is optional. If the number of devices is 0, this will be ignored. 478 * - The matching code pays attention to the current selection mode. So 479 * if you pass in a matching expression, it will be evaluated based 480 * upon the selection mode that is passed in. See below for details. 481 * - number of device type matching expressions (num_matches) 482 * - Set to 0 to disable the matching code. 483 * - list of devices specified on the command line by the user (dev_selections) 484 * - number of devices selected on the command line by the user 485 * (num_dev_selections) 486 * - Our selection mode. There are four different selection modes: 487 * - add mode. (DS_SELECT_ADD) Any devices matching devices explicitly 488 * selected by the user or devices matching a pattern given by the 489 * user will be selected in addition to devices that are already 490 * selected. Additional devices will be selected, up to maxshowdevs 491 * number of devices. 492 * - only mode. (DS_SELECT_ONLY) Only devices matching devices 493 * explicitly given by the user or devices matching a pattern 494 * given by the user will be selected. No other devices will be 495 * selected. 496 * - addonly mode. (DS_SELECT_ADDONLY) This is similar to add and 497 * only. Basically, this will not de-select any devices that are 498 * current selected, as only mode would, but it will also not 499 * gratuitously select up to maxshowdevs devices as add mode would. 500 * - remove mode. (DS_SELECT_REMOVE) Any devices matching devices 501 * explicitly selected by the user or devices matching a pattern 502 * given by the user will be de-selected. 503 * - maximum number of devices we can select (maxshowdevs) 504 * - flag indicating whether or not we're in 'top' mode (perf_select) 505 * 506 * Output data: 507 * - the device selection list may be modified and passed back out 508 * - the number of devices selected and the total number of items in the 509 * device selection list may be changed 510 * - the selection generation may be changed to match the current generation 511 * 512 * Return values: 513 * -1 -- error 514 * 0 -- selected devices are unchanged 515 * 1 -- selected devices changed 516 */ 517 int 518 devstat_selectdevs(struct device_selection **dev_select, int *num_selected, 519 int *num_selections, long *select_generation, 520 long current_generation, struct devstat *devices, 521 int numdevs, struct devstat_match *matches, int num_matches, 522 char **dev_selections, int num_dev_selections, 523 devstat_select_mode select_mode, int maxshowdevs, 524 int perf_select) 525 { 526 register int i, j, k; 527 int init_selections = 0, init_selected_var = 0; 528 struct device_selection *old_dev_select = NULL; 529 int old_num_selections = 0, old_num_selected; 530 int selection_number = 0; 531 int changed = 0, found = 0; 532 533 if ((dev_select == NULL) || (devices == NULL) || (numdevs <= 0)) 534 return(-1); 535 536 /* 537 * We always want to make sure that we have as many dev_select 538 * entries as there are devices. 539 */ 540 /* 541 * In this case, we haven't selected devices before. 542 */ 543 if (*dev_select == NULL) { 544 *dev_select = (struct device_selection *)malloc(numdevs * 545 sizeof(struct device_selection)); 546 *select_generation = current_generation; 547 init_selections = 1; 548 changed = 1; 549 /* 550 * In this case, we have selected devices before, but the device 551 * list has changed since we last selected devices, so we need to 552 * either enlarge or reduce the size of the device selection list. 553 */ 554 } else if (*num_selections != numdevs) { 555 *dev_select = (struct device_selection *)realloc(*dev_select, 556 numdevs * sizeof(struct device_selection)); 557 *select_generation = current_generation; 558 init_selections = 1; 559 /* 560 * In this case, we've selected devices before, and the selection 561 * list is the same size as it was the last time, but the device 562 * list has changed. 563 */ 564 } else if (*select_generation < current_generation) { 565 *select_generation = current_generation; 566 init_selections = 1; 567 } 568 569 /* 570 * If we're in "only" mode, we want to clear out the selected 571 * variable since we're going to select exactly what the user wants 572 * this time through. 573 */ 574 if (select_mode == DS_SELECT_ONLY) 575 init_selected_var = 1; 576 577 /* 578 * In all cases, we want to back up the number of selected devices. 579 * It is a quick and accurate way to determine whether the selected 580 * devices have changed. 581 */ 582 old_num_selected = *num_selected; 583 584 /* 585 * We want to make a backup of the current selection list if 586 * the list of devices has changed, or if we're in performance 587 * selection mode. In both cases, we don't want to make a backup 588 * if we already know for sure that the list will be different. 589 * This is certainly the case if this is our first time through the 590 * selection code. 591 */ 592 if (((init_selected_var != 0) || (init_selections != 0) 593 || (perf_select != 0)) && (changed == 0)){ 594 old_dev_select = (struct device_selection *)malloc( 595 *num_selections * sizeof(struct device_selection)); 596 old_num_selections = *num_selections; 597 bcopy(*dev_select, old_dev_select, 598 sizeof(struct device_selection) * *num_selections); 599 } 600 601 if (init_selections != 0) { 602 bzero(*dev_select, sizeof(struct device_selection) * numdevs); 603 604 for (i = 0; i < numdevs; i++) { 605 (*dev_select)[i].device_number = 606 devices[i].device_number; 607 strncpy((*dev_select)[i].device_name, 608 devices[i].device_name, 609 DEVSTAT_NAME_LEN); 610 (*dev_select)[i].device_name[DEVSTAT_NAME_LEN - 1]='\0'; 611 (*dev_select)[i].unit_number = devices[i].unit_number; 612 (*dev_select)[i].position = i; 613 } 614 *num_selections = numdevs; 615 } else if (init_selected_var != 0) { 616 for (i = 0; i < numdevs; i++) 617 (*dev_select)[i].selected = 0; 618 } 619 620 /* we haven't gotten around to selecting anything yet.. */ 621 if ((select_mode == DS_SELECT_ONLY) || (init_selections != 0) 622 || (init_selected_var != 0)) 623 *num_selected = 0; 624 625 /* 626 * Look through any devices the user specified on the command line 627 * and see if they match known devices. If so, select them. 628 */ 629 for (i = 0; (i < *num_selections) && (num_dev_selections > 0); i++) { 630 char tmpstr[80]; 631 632 snprintf(tmpstr, sizeof(tmpstr), "%s%d", 633 (*dev_select)[i].device_name, 634 (*dev_select)[i].unit_number); 635 for (j = 0; j < num_dev_selections; j++) { 636 if (strcmp(tmpstr, dev_selections[j]) == 0) { 637 /* 638 * Here we do different things based on the 639 * mode we're in. If we're in add or 640 * addonly mode, we only select this device 641 * if it hasn't already been selected. 642 * Otherwise, we would be unnecessarily 643 * changing the selection order and 644 * incrementing the selection count. If 645 * we're in only mode, we unconditionally 646 * select this device, since in only mode 647 * any previous selections are erased and 648 * manually specified devices are the first 649 * ones to be selected. If we're in remove 650 * mode, we de-select the specified device and 651 * decrement the selection count. 652 */ 653 switch(select_mode) { 654 case DS_SELECT_ADD: 655 case DS_SELECT_ADDONLY: 656 if ((*dev_select)[i].selected) 657 break; 658 /* FALLTHROUGH */ 659 case DS_SELECT_ONLY: 660 (*dev_select)[i].selected = 661 ++selection_number; 662 (*num_selected)++; 663 break; 664 case DS_SELECT_REMOVE: 665 (*dev_select)[i].selected = 0; 666 (*num_selected)--; 667 /* 668 * This isn't passed back out, we 669 * just use it to keep track of 670 * how many devices we've removed. 671 */ 672 num_dev_selections--; 673 break; 674 } 675 break; 676 } 677 } 678 } 679 680 /* 681 * Go through the user's device type expressions and select devices 682 * accordingly. We only do this if the number of devices already 683 * selected is less than the maximum number we can show. 684 */ 685 for (i = 0; (i < num_matches) && (*num_selected < maxshowdevs); i++) { 686 /* We should probably indicate some error here */ 687 if ((matches[i].match_fields == DEVSTAT_MATCH_NONE) 688 || (matches[i].num_match_categories <= 0)) 689 continue; 690 691 for (j = 0; j < numdevs; j++) { 692 int num_match_categories; 693 694 num_match_categories = matches[i].num_match_categories; 695 696 /* 697 * Determine whether or not the current device 698 * matches the given matching expression. This if 699 * statement consists of three components: 700 * - the device type check 701 * - the device interface check 702 * - the passthrough check 703 * If a the matching test is successful, it 704 * decrements the number of matching categories, 705 * and if we've reached the last element that 706 * needed to be matched, the if statement succeeds. 707 * 708 */ 709 if ((((matches[i].match_fields & DEVSTAT_MATCH_TYPE)!=0) 710 && ((devices[j].device_type & DEVSTAT_TYPE_MASK) == 711 (matches[i].device_type & DEVSTAT_TYPE_MASK)) 712 &&(((matches[i].match_fields & DEVSTAT_MATCH_PASS)!=0) 713 || (((matches[i].match_fields & 714 DEVSTAT_MATCH_PASS) == 0) 715 && ((devices[j].device_type & 716 DEVSTAT_TYPE_PASS) == 0))) 717 && (--num_match_categories == 0)) 718 || (((matches[i].match_fields & DEVSTAT_MATCH_IF) != 0) 719 && ((devices[j].device_type & DEVSTAT_TYPE_IF_MASK) == 720 (matches[i].device_type & DEVSTAT_TYPE_IF_MASK)) 721 &&(((matches[i].match_fields & DEVSTAT_MATCH_PASS)!=0) 722 || (((matches[i].match_fields & 723 DEVSTAT_MATCH_PASS) == 0) 724 && ((devices[j].device_type & 725 DEVSTAT_TYPE_PASS) == 0))) 726 && (--num_match_categories == 0)) 727 || (((matches[i].match_fields & DEVSTAT_MATCH_PASS)!=0) 728 && ((devices[j].device_type & DEVSTAT_TYPE_PASS) != 0) 729 && (--num_match_categories == 0))) { 730 731 /* 732 * This is probably a non-optimal solution 733 * to the problem that the devices in the 734 * device list will not be in the same 735 * order as the devices in the selection 736 * array. 737 */ 738 for (k = 0; k < numdevs; k++) { 739 if ((*dev_select)[k].position == j) { 740 found = 1; 741 break; 742 } 743 } 744 745 /* 746 * There shouldn't be a case where a device 747 * in the device list is not in the 748 * selection list...but it could happen. 749 */ 750 if (found != 1) { 751 fprintf(stderr, "selectdevs: couldn't" 752 " find %s%d in selection " 753 "list\n", 754 devices[j].device_name, 755 devices[j].unit_number); 756 break; 757 } 758 759 /* 760 * We do different things based upon the 761 * mode we're in. If we're in add or only 762 * mode, we go ahead and select this device 763 * if it hasn't already been selected. If 764 * it has already been selected, we leave 765 * it alone so we don't mess up the 766 * selection ordering. Manually specified 767 * devices have already been selected, and 768 * they have higher priority than pattern 769 * matched devices. If we're in remove 770 * mode, we de-select the given device and 771 * decrement the selected count. 772 */ 773 switch(select_mode) { 774 case DS_SELECT_ADD: 775 case DS_SELECT_ADDONLY: 776 case DS_SELECT_ONLY: 777 if ((*dev_select)[k].selected != 0) 778 break; 779 (*dev_select)[k].selected = 780 ++selection_number; 781 (*num_selected)++; 782 break; 783 case DS_SELECT_REMOVE: 784 (*dev_select)[k].selected = 0; 785 (*num_selected)--; 786 break; 787 } 788 } 789 } 790 } 791 792 /* 793 * Here we implement "top" mode. Devices are sorted in the 794 * selection array based on two criteria: whether or not they are 795 * selected (not selection number, just the fact that they are 796 * selected!) and the number of bytes in the "bytes" field of the 797 * selection structure. The bytes field generally must be kept up 798 * by the user. In the future, it may be maintained by library 799 * functions, but for now the user has to do the work. 800 * 801 * At first glance, it may seem wrong that we don't go through and 802 * select every device in the case where the user hasn't specified 803 * any devices or patterns. In fact, though, it won't make any 804 * difference in the device sorting. In that particular case (i.e. 805 * when we're in "add" or "only" mode, and the user hasn't 806 * specified anything) the first time through no devices will be 807 * selected, so the only criterion used to sort them will be their 808 * performance. The second time through, and every time thereafter, 809 * all devices will be selected, so again selection won't matter. 810 */ 811 if (perf_select != 0) { 812 813 /* Sort the device array by throughput */ 814 qsort(*dev_select, *num_selections, 815 sizeof(struct device_selection), 816 compare_select); 817 818 if (*num_selected == 0) { 819 /* 820 * Here we select every device in the array, if it 821 * isn't already selected. Because the 'selected' 822 * variable in the selection array entries contains 823 * the selection order, the devstats routine can show 824 * the devices that were selected first. 825 */ 826 for (i = 0; i < *num_selections; i++) { 827 if ((*dev_select)[i].selected == 0) { 828 (*dev_select)[i].selected = 829 ++selection_number; 830 (*num_selected)++; 831 } 832 } 833 } else { 834 selection_number = 0; 835 for (i = 0; i < *num_selections; i++) { 836 if ((*dev_select)[i].selected != 0) { 837 (*dev_select)[i].selected = 838 ++selection_number; 839 } 840 } 841 } 842 } 843 844 /* 845 * If we're in the "add" selection mode and if we haven't already 846 * selected maxshowdevs number of devices, go through the array and 847 * select any unselected devices. If we're in "only" mode, we 848 * obviously don't want to select anything other than what the user 849 * specifies. If we're in "remove" mode, it probably isn't a good 850 * idea to go through and select any more devices, since we might 851 * end up selecting something that the user wants removed. Through 852 * more complicated logic, we could actually figure this out, but 853 * that would probably require combining this loop with the various 854 * selections loops above. 855 */ 856 if ((select_mode == DS_SELECT_ADD) && (*num_selected < maxshowdevs)) { 857 for (i = 0; i < *num_selections; i++) 858 if ((*dev_select)[i].selected == 0) { 859 (*dev_select)[i].selected = ++selection_number; 860 (*num_selected)++; 861 } 862 } 863 864 /* 865 * Look at the number of devices that have been selected. If it 866 * has changed, set the changed variable. Otherwise, if we've 867 * made a backup of the selection list, compare it to the current 868 * selection list to see if the selected devices have changed. 869 */ 870 if ((changed == 0) && (old_num_selected != *num_selected)) 871 changed = 1; 872 else if ((changed == 0) && (old_dev_select != NULL)) { 873 /* 874 * Now we go through the selection list and we look at 875 * it three different ways. 876 */ 877 for (i = 0; (i < *num_selections) && (changed == 0) && 878 (i < old_num_selections); i++) { 879 /* 880 * If the device at index i in both the new and old 881 * selection arrays has the same device number and 882 * selection status, it hasn't changed. We 883 * continue on to the next index. 884 */ 885 if (((*dev_select)[i].device_number == 886 old_dev_select[i].device_number) 887 && ((*dev_select)[i].selected == 888 old_dev_select[i].selected)) 889 continue; 890 891 /* 892 * Now, if we're still going through the if 893 * statement, the above test wasn't true. So we 894 * check here to see if the device at index i in 895 * the current array is the same as the device at 896 * index i in the old array. If it is, that means 897 * that its selection number has changed. Set 898 * changed to 1 and exit the loop. 899 */ 900 else if ((*dev_select)[i].device_number == 901 old_dev_select[i].device_number) { 902 changed = 1; 903 break; 904 } 905 /* 906 * If we get here, then the device at index i in 907 * the current array isn't the same device as the 908 * device at index i in the old array. 909 */ 910 else { 911 int found = 0; 912 913 /* 914 * Search through the old selection array 915 * looking for a device with the same 916 * device number as the device at index i 917 * in the current array. If the selection 918 * status is the same, then we mark it as 919 * found. If the selection status isn't 920 * the same, we break out of the loop. 921 * Since found isn't set, changed will be 922 * set to 1 below. 923 */ 924 for (j = 0; j < old_num_selections; j++) { 925 if (((*dev_select)[i].device_number == 926 old_dev_select[j].device_number) 927 && ((*dev_select)[i].selected == 928 old_dev_select[j].selected)){ 929 found = 1; 930 break; 931 } 932 else if ((*dev_select)[i].device_number 933 == old_dev_select[j].device_number) 934 break; 935 } 936 if (found == 0) 937 changed = 1; 938 } 939 } 940 } 941 if (old_dev_select != NULL) 942 free(old_dev_select); 943 944 return(changed); 945 } 946 947 /* 948 * Comparison routine for qsort() above. Note that the comparison here is 949 * backwards -- generally, it should return a value to indicate whether 950 * arg1 is <, =, or > arg2. Instead, it returns the opposite. The reason 951 * it returns the opposite is so that the selection array will be sorted in 952 * order of decreasing performance. We sort on two parameters. The first 953 * sort key is whether or not one or the other of the devices in question 954 * has been selected. If one of them has, and the other one has not, the 955 * selected device is automatically more important than the unselected 956 * device. If neither device is selected, we judge the devices based upon 957 * performance. 958 */ 959 static int 960 compare_select(const void *arg1, const void *arg2) 961 { 962 if ((((struct device_selection *)arg1)->selected) 963 && (((struct device_selection *)arg2)->selected == 0)) 964 return(-1); 965 else if ((((struct device_selection *)arg1)->selected == 0) 966 && (((struct device_selection *)arg2)->selected)) 967 return(1); 968 else if (((struct device_selection *)arg2)->bytes < 969 ((struct device_selection *)arg1)->bytes) 970 return(-1); 971 else if (((struct device_selection *)arg2)->bytes > 972 ((struct device_selection *)arg1)->bytes) 973 return(1); 974 else 975 return(0); 976 } 977 978 /* 979 * Take a string with the general format "arg1,arg2,arg3", and build a 980 * device matching expression from it. 981 */ 982 int 983 devstat_buildmatch(char *match_str, struct devstat_match **matches, 984 int *num_matches) 985 { 986 char *tstr[5]; 987 char **tempstr; 988 int num_args; 989 register int i, j; 990 char *func_name = "devstat_buildmatch"; 991 992 /* We can't do much without a string to parse */ 993 if (match_str == NULL) { 994 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 995 "%s: no match expression", func_name); 996 return(-1); 997 } 998 999 /* 1000 * Break the (comma delimited) input string out into separate strings. 1001 */ 1002 for (tempstr = tstr, num_args = 0; 1003 (*tempstr = strsep(&match_str, ",")) != NULL && (num_args < 5); 1004 num_args++) 1005 if (**tempstr != '\0') 1006 if (++tempstr >= &tstr[5]) 1007 break; 1008 1009 /* The user gave us too many type arguments */ 1010 if (num_args > 3) { 1011 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1012 "%s: too many type arguments", func_name); 1013 return(-1); 1014 } 1015 1016 /* 1017 * Since you can't realloc a pointer that hasn't been malloced 1018 * first, we malloc first and then realloc. 1019 */ 1020 if (*num_matches == 0) 1021 *matches = (struct devstat_match *)malloc( 1022 sizeof(struct devstat_match)); 1023 else 1024 *matches = (struct devstat_match *)realloc(*matches, 1025 sizeof(struct devstat_match) * (*num_matches + 1)); 1026 1027 /* Make sure the current entry is clear */ 1028 bzero(&matches[0][*num_matches], sizeof(struct devstat_match)); 1029 1030 /* 1031 * Step through the arguments the user gave us and build a device 1032 * matching expression from them. 1033 */ 1034 for (i = 0; i < num_args; i++) { 1035 char *tempstr2, *tempstr3; 1036 1037 /* 1038 * Get rid of leading white space. 1039 */ 1040 tempstr2 = tstr[i]; 1041 while (isspace(*tempstr2) && (*tempstr2 != '\0')) 1042 tempstr2++; 1043 1044 /* 1045 * Get rid of trailing white space. 1046 */ 1047 tempstr3 = &tempstr2[strlen(tempstr2) - 1]; 1048 1049 while ((*tempstr3 != '\0') && (tempstr3 > tempstr2) 1050 && (isspace(*tempstr3))) { 1051 *tempstr3 = '\0'; 1052 tempstr3--; 1053 } 1054 1055 /* 1056 * Go through the match table comparing the user's 1057 * arguments to known device types, interfaces, etc. 1058 */ 1059 for (j = 0; match_table[j].match_str != NULL; j++) { 1060 /* 1061 * We do case-insensitive matching, in case someone 1062 * wants to enter "SCSI" instead of "scsi" or 1063 * something like that. Only compare as many 1064 * characters as are in the string in the match 1065 * table. This should help if someone tries to use 1066 * a super-long match expression. 1067 */ 1068 if (strncasecmp(tempstr2, match_table[j].match_str, 1069 strlen(match_table[j].match_str)) == 0) { 1070 /* 1071 * Make sure the user hasn't specified two 1072 * items of the same type, like "da" and 1073 * "cd". One device cannot be both. 1074 */ 1075 if (((*matches)[*num_matches].match_fields & 1076 match_table[j].match_field) != 0) { 1077 snprintf(devstat_errbuf, 1078 sizeof(devstat_errbuf), 1079 "%s: cannot have more than " 1080 "one match item in a single " 1081 "category", func_name); 1082 return(-1); 1083 } 1084 /* 1085 * If we've gotten this far, we have a 1086 * winner. Set the appropriate fields in 1087 * the match entry. 1088 */ 1089 (*matches)[*num_matches].match_fields |= 1090 match_table[j].match_field; 1091 (*matches)[*num_matches].device_type |= 1092 match_table[j].type; 1093 (*matches)[*num_matches].num_match_categories++; 1094 break; 1095 } 1096 } 1097 /* 1098 * We should have found a match in the above for loop. If 1099 * not, that means the user entered an invalid device type 1100 * or interface. 1101 */ 1102 if ((*matches)[*num_matches].num_match_categories != (i + 1)) { 1103 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1104 "%s: unknown match item \"%s\"", func_name, 1105 tstr[i]); 1106 return(-1); 1107 } 1108 } 1109 1110 (*num_matches)++; 1111 1112 return(0); 1113 } 1114 1115 /* 1116 * Compute a number of device statistics. Only one field is mandatory, and 1117 * that is "current". Everything else is optional. The caller passes in 1118 * pointers to variables to hold the various statistics he desires. If he 1119 * doesn't want a particular staistic, he should pass in a NULL pointer. 1120 * Return values: 1121 * 0 -- success 1122 * -1 -- failure 1123 */ 1124 int 1125 compute_stats(struct devstat *current, struct devstat *previous, 1126 long double etime, u_int64_t *total_bytes, 1127 u_int64_t *total_transfers, u_int64_t *total_blocks, 1128 long double *kb_per_transfer, long double *transfers_per_second, 1129 long double *mb_per_second, long double *blocks_per_second, 1130 long double *ms_per_transaction) 1131 { 1132 u_int64_t totalbytes, totaltransfers, totalblocks; 1133 char *func_name = "compute_stats"; 1134 1135 /* 1136 * current is the only mandatory field. 1137 */ 1138 if (current == NULL) { 1139 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1140 "%s: current stats structure was NULL", 1141 func_name); 1142 return(-1); 1143 } 1144 1145 totalbytes = (current->bytes_written + current->bytes_read) - 1146 ((previous) ? (previous->bytes_written + 1147 previous->bytes_read) : 0); 1148 1149 if (total_bytes) 1150 *total_bytes = totalbytes; 1151 1152 totaltransfers = (current->num_reads + 1153 current->num_writes + 1154 current->num_other) - 1155 ((previous) ? 1156 (previous->num_reads + 1157 previous->num_writes + 1158 previous->num_other) : 0); 1159 if (total_transfers) 1160 *total_transfers = totaltransfers; 1161 1162 if (transfers_per_second) { 1163 if (etime > 0.0) { 1164 *transfers_per_second = totaltransfers; 1165 *transfers_per_second /= etime; 1166 } else 1167 *transfers_per_second = 0.0; 1168 } 1169 1170 if (kb_per_transfer) { 1171 *kb_per_transfer = totalbytes; 1172 *kb_per_transfer /= 1024; 1173 if (totaltransfers > 0) 1174 *kb_per_transfer /= totaltransfers; 1175 else 1176 *kb_per_transfer = 0.0; 1177 } 1178 1179 if (mb_per_second) { 1180 *mb_per_second = totalbytes; 1181 *mb_per_second /= 1024 * 1024; 1182 if (etime > 0.0) 1183 *mb_per_second /= etime; 1184 else 1185 *mb_per_second = 0.0; 1186 } 1187 1188 totalblocks = totalbytes; 1189 if (current->block_size > 0) 1190 totalblocks /= current->block_size; 1191 else 1192 totalblocks /= 512; 1193 1194 if (total_blocks) 1195 *total_blocks = totalblocks; 1196 1197 if (blocks_per_second) { 1198 *blocks_per_second = totalblocks; 1199 if (etime > 0.0) 1200 *blocks_per_second /= etime; 1201 else 1202 *blocks_per_second = 0.0; 1203 } 1204 1205 if (ms_per_transaction) { 1206 if (totaltransfers > 0) { 1207 *ms_per_transaction = etime; 1208 *ms_per_transaction /= totaltransfers; 1209 *ms_per_transaction *= 1000; 1210 } else 1211 *ms_per_transaction = 0.0; 1212 } 1213 1214 return(0); 1215 } 1216 1217 long double 1218 devstat_compute_etime(struct timeval cur_time, struct timeval prev_time) 1219 { 1220 struct timeval busy_time; 1221 u_int64_t busy_usec; 1222 long double etime; 1223 1224 timersub(&cur_time, &prev_time, &busy_time); 1225 1226 busy_usec = busy_time.tv_sec; 1227 busy_usec *= 1000000; 1228 busy_usec += busy_time.tv_usec; 1229 etime = busy_usec; 1230 etime /= 1000000; 1231 1232 return(etime); 1233 } 1234 1235 int 1236 devstat_compute_statistics(struct devstat *current, struct devstat *previous, 1237 long double etime, ...) 1238 { 1239 char *func_name = "devstat_compute_statistics"; 1240 u_int64_t totalbytes, totalbytesread, totalbyteswrite; 1241 u_int64_t totaltransfers, totaltransfersread, totaltransferswrite; 1242 u_int64_t totaltransfersother, totalblocks, totalblocksread; 1243 u_int64_t totalblockswrite; 1244 va_list ap; 1245 devstat_metric metric; 1246 u_int64_t *destu64; 1247 long double *destld; 1248 int retval; 1249 1250 retval = 0; 1251 1252 /* 1253 * current is the only mandatory field. 1254 */ 1255 if (current == NULL) { 1256 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1257 "%s: current stats structure was NULL", func_name); 1258 return(-1); 1259 } 1260 1261 totalbytesread = current->bytes_read - 1262 ((previous) ? previous->bytes_read : 0); 1263 totalbyteswrite = current->bytes_written - 1264 ((previous) ? previous->bytes_written : 0); 1265 1266 totalbytes = totalbytesread + totalbyteswrite; 1267 1268 totaltransfersread = current->num_reads - 1269 ((previous) ? previous->num_reads : 0); 1270 1271 totaltransferswrite = current->num_writes - 1272 ((previous) ? previous->num_writes : 0); 1273 1274 totaltransfersother = current->num_other - 1275 ((previous) ? previous->num_other : 0); 1276 1277 totaltransfers = totaltransfersread + totaltransferswrite + 1278 totaltransfersother; 1279 1280 totalblocks = totalbytes; 1281 totalblocksread = totalbytesread; 1282 totalblockswrite = totalbyteswrite; 1283 1284 if (current->block_size > 0) { 1285 totalblocks /= current->block_size; 1286 totalblocksread /= current->block_size; 1287 totalblockswrite /= current->block_size; 1288 } else { 1289 totalblocks /= 512; 1290 totalblocksread /= 512; 1291 totalblockswrite /= 512; 1292 } 1293 1294 va_start(ap, etime); 1295 1296 while ((metric = (devstat_metric)va_arg(ap, devstat_metric)) != 0) { 1297 1298 if (metric == DSM_NONE) 1299 break; 1300 1301 if (metric >= DSM_MAX) { 1302 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1303 "%s: metric %d is out of range", func_name, 1304 metric); 1305 retval = -1; 1306 goto bailout; 1307 } 1308 1309 switch (devstat_arg_list[metric].argtype) { 1310 case DEVSTAT_ARG_UINT64: 1311 destu64 = (u_int64_t *)va_arg(ap, u_int64_t *); 1312 if (destu64 == NULL) { 1313 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1314 "%s: argument type not u_int64_t * or " 1315 "argument type missing", func_name); 1316 retval = -1; 1317 goto bailout; 1318 break; /* NOTREACHED */ 1319 } 1320 break; 1321 case DEVSTAT_ARG_LD: 1322 destld = (long double *)va_arg(ap, long double *); 1323 if (destld == NULL) { 1324 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1325 "%s: argument type not long double * " 1326 "or argument type missing", func_name); 1327 retval = -1; 1328 goto bailout; 1329 break; /* NOTREACHED */ 1330 } 1331 break; 1332 default: 1333 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1334 "%s: unknown argument type %d", func_name, 1335 devstat_arg_list[metric].argtype); 1336 retval = -1; 1337 goto bailout; 1338 break; /* NOTREACHED */ 1339 } 1340 1341 switch (metric) { 1342 case DSM_TOTAL_BYTES: 1343 *destu64 = totalbytes; 1344 break; 1345 case DSM_TOTAL_BYTES_READ: 1346 *destu64 = totalbytesread; 1347 break; 1348 case DSM_TOTAL_BYTES_WRITE: 1349 *destu64 = totalbyteswrite; 1350 break; 1351 case DSM_TOTAL_TRANSFERS: 1352 *destu64 = totaltransfers; 1353 break; 1354 case DSM_TOTAL_TRANSFERS_READ: 1355 *destu64 = totaltransfersread; 1356 break; 1357 case DSM_TOTAL_TRANSFERS_WRITE: 1358 *destu64 = totaltransferswrite; 1359 break; 1360 case DSM_TOTAL_TRANSFERS_OTHER: 1361 *destu64 = totaltransfersother; 1362 break; 1363 case DSM_TOTAL_BLOCKS: 1364 *destu64 = totalblocks; 1365 break; 1366 case DSM_TOTAL_BLOCKS_READ: 1367 *destu64 = totalblocksread; 1368 break; 1369 case DSM_TOTAL_BLOCKS_WRITE: 1370 *destu64 = totalblockswrite; 1371 break; 1372 case DSM_KB_PER_TRANSFER: 1373 *destld = totalbytes; 1374 *destld /= 1024; 1375 if (totaltransfers > 0) 1376 *destld /= totaltransfers; 1377 else 1378 *destld = 0.0; 1379 break; 1380 case DSM_KB_PER_TRANSFER_READ: 1381 *destld = totalbytesread; 1382 *destld /= 1024; 1383 if (totaltransfersread > 0) 1384 *destld /= totaltransfersread; 1385 else 1386 *destld = 0.0; 1387 break; 1388 case DSM_KB_PER_TRANSFER_WRITE: 1389 *destld = totalbyteswrite; 1390 *destld /= 1024; 1391 if (totaltransferswrite > 0) 1392 *destld /= totaltransferswrite; 1393 else 1394 *destld = 0.0; 1395 break; 1396 case DSM_TRANSFERS_PER_SECOND: 1397 if (etime > 0.0) { 1398 *destld = totaltransfers; 1399 *destld /= etime; 1400 } else 1401 *destld = 0.0; 1402 break; 1403 case DSM_TRANSFERS_PER_SECOND_READ: 1404 if (etime > 0.0) { 1405 *destld = totaltransfersread; 1406 *destld /= etime; 1407 } else 1408 *destld = 0.0; 1409 break; 1410 case DSM_TRANSFERS_PER_SECOND_WRITE: 1411 if (etime > 0.0) { 1412 *destld = totaltransferswrite; 1413 *destld /= etime; 1414 } else 1415 *destld = 0.0; 1416 break; 1417 case DSM_TRANSFERS_PER_SECOND_OTHER: 1418 if (etime > 0.0) { 1419 *destld = totaltransfersother; 1420 *destld /= etime; 1421 } else 1422 *destld = 0.0; 1423 break; 1424 case DSM_MB_PER_SECOND: 1425 *destld = totalbytes; 1426 *destld /= 1024 * 1024; 1427 if (etime > 0.0) 1428 *destld /= etime; 1429 else 1430 *destld = 0.0; 1431 break; 1432 case DSM_MB_PER_SECOND_READ: 1433 *destld = totalbytesread; 1434 *destld /= 1024 * 1024; 1435 if (etime > 0.0) 1436 *destld /= etime; 1437 else 1438 *destld = 0.0; 1439 break; 1440 case DSM_MB_PER_SECOND_WRITE: 1441 *destld = totalbyteswrite; 1442 *destld /= 1024 * 1024; 1443 if (etime > 0.0) 1444 *destld /= etime; 1445 else 1446 *destld = 0.0; 1447 break; 1448 case DSM_BLOCKS_PER_SECOND: 1449 *destld = totalblocks; 1450 if (etime > 0.0) 1451 *destld /= etime; 1452 else 1453 *destld = 0.0; 1454 break; 1455 case DSM_BLOCKS_PER_SECOND_READ: 1456 *destld = totalblocksread; 1457 if (etime > 0.0) 1458 *destld /= etime; 1459 else 1460 *destld = 0.0; 1461 break; 1462 case DSM_BLOCKS_PER_SECOND_WRITE: 1463 *destld = totalblockswrite; 1464 if (etime > 0.0) 1465 *destld /= etime; 1466 else 1467 *destld = 0.0; 1468 break; 1469 /* 1470 * This calculation is somewhat bogus. It simply divides 1471 * the elapsed time by the total number of transactions 1472 * completed. While that does give the caller a good 1473 * picture of the average rate of transaction completion, 1474 * it doesn't necessarily give the caller a good view of 1475 * how long transactions took to complete on average. 1476 * Those two numbers will be different for a device that 1477 * can handle more than one transaction at a time. e.g. 1478 * SCSI disks doing tagged queueing. 1479 * 1480 * The only way to accurately determine the real average 1481 * time per transaction would be to compute and store the 1482 * time on a per-transaction basis. That currently isn't 1483 * done in the kernel, and would only be desireable if it 1484 * could be implemented in a somewhat non-intrusive and high 1485 * performance way. 1486 */ 1487 case DSM_MS_PER_TRANSACTION: 1488 if (totaltransfers > 0) { 1489 *destld = etime; 1490 *destld /= totaltransfers; 1491 *destld *= 1000; 1492 } else 1493 *destld = 0.0; 1494 break; 1495 /* 1496 * As above, these next two really only give the average 1497 * rate of completion for read and write transactions, not 1498 * the average time the transaction took to complete. 1499 */ 1500 case DSM_MS_PER_TRANSACTION_READ: 1501 if (totaltransfersread > 0) { 1502 *destld = etime; 1503 *destld /= totaltransfersread; 1504 *destld *= 1000; 1505 } else 1506 *destld = 0.0; 1507 break; 1508 case DSM_MS_PER_TRANSACTION_WRITE: 1509 if (totaltransferswrite > 0) { 1510 *destld = etime; 1511 *destld /= totaltransferswrite; 1512 *destld *= 1000; 1513 } else 1514 *destld = 0.0; 1515 break; 1516 default: 1517 /* 1518 * This shouldn't happen, since we should have 1519 * caught any out of range metrics at the top of 1520 * the loop. 1521 */ 1522 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1523 "%s: unknown metric %d", func_name, metric); 1524 retval = -1; 1525 goto bailout; 1526 break; /* NOTREACHED */ 1527 } 1528 } 1529 1530 bailout: 1531 1532 va_end(ap); 1533 return(retval); 1534 } 1535 1536 static int 1537 readkmem(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes) 1538 { 1539 char *func_name = "readkmem"; 1540 1541 if (kvm_read(kd, addr, buf, nbytes) == -1) { 1542 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1543 "%s: error reading value (kvm_read): %s", func_name, 1544 kvm_geterr(kd)); 1545 return(-1); 1546 } 1547 return(0); 1548 } 1549 1550 static int 1551 readkmem_nl(kvm_t *kd, char *name, void *buf, size_t nbytes) 1552 { 1553 char *func_name = "readkmem_nl"; 1554 struct nlist nl[2] = { { name }, { NULL } }; 1555 1556 if (kvm_nlist(kd, nl) == -1) { 1557 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1558 "%s: error getting name list (kvm_nlist): %s", 1559 func_name, kvm_geterr(kd)); 1560 return(-1); 1561 } 1562 return(readkmem(kd, nl[0].n_value, buf, nbytes)); 1563 } 1564 1565 /* 1566 * This duplicates the functionality of the kernel sysctl handler for poking 1567 * through crash dumps. 1568 */ 1569 static char * 1570 get_devstat_kvm(kvm_t *kd) 1571 { 1572 int error, i, wp; 1573 long gen; 1574 struct devstat *nds; 1575 struct devstat ds; 1576 struct devstatlist dhead; 1577 int num_devs; 1578 char *rv = NULL; 1579 char *func_name = "get_devstat_kvm"; 1580 1581 if ((num_devs = getnumdevs()) <= 0) 1582 return(NULL); 1583 error = 0; 1584 if (KREADNL(kd, X_DEVICE_STATQ, dhead) == -1) 1585 return(NULL); 1586 1587 nds = STAILQ_FIRST(&dhead); 1588 1589 if ((rv = malloc(sizeof(gen))) == NULL) { 1590 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1591 "%s: out of memory (initial malloc failed)", 1592 func_name); 1593 return(NULL); 1594 } 1595 gen = getgeneration(); 1596 memcpy(rv, &gen, sizeof(gen)); 1597 wp = sizeof(gen); 1598 /* 1599 * Now push out all the devices. 1600 */ 1601 for (i = 0; (nds != NULL) && (i < num_devs); 1602 nds = STAILQ_NEXT(nds, dev_links), i++) { 1603 if (readkmem(kd, (long)nds, &ds, sizeof(ds)) == -1) { 1604 free(rv); 1605 return(NULL); 1606 } 1607 nds = &ds; 1608 rv = (char *)reallocf(rv, sizeof(gen) + 1609 sizeof(ds) * (i + 1)); 1610 if (rv == NULL) { 1611 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1612 "%s: out of memory (malloc failed)", 1613 func_name); 1614 return(NULL); 1615 } 1616 memcpy(rv + wp, &ds, sizeof(ds)); 1617 wp += sizeof(ds); 1618 } 1619 return(rv); 1620 } 1621 1622 /* 1623 * Compatability functions for libdevstat 2. These are deprecated and may 1624 * eventually be removed. 1625 */ 1626 int 1627 getnumdevs(void) 1628 { 1629 return(devstat_getnumdevs(NULL)); 1630 } 1631 1632 long 1633 getgeneration(void) 1634 { 1635 return(devstat_getgeneration(NULL)); 1636 } 1637 1638 int 1639 getversion(void) 1640 { 1641 return(devstat_getversion(NULL)); 1642 } 1643 1644 int 1645 checkversion(void) 1646 { 1647 return(devstat_checkversion(NULL)); 1648 } 1649 1650 int 1651 getdevs(struct statinfo *stats) 1652 { 1653 return(devstat_getdevs(NULL, stats)); 1654 } 1655 1656 int 1657 selectdevs(struct device_selection **dev_select, int *num_selected, 1658 int *num_selections, long *select_generation, 1659 long current_generation, struct devstat *devices, int numdevs, 1660 struct devstat_match *matches, int num_matches, 1661 char **dev_selections, int num_dev_selections, 1662 devstat_select_mode select_mode, int maxshowdevs, 1663 int perf_select) 1664 { 1665 1666 return(devstat_selectdevs(dev_select, num_selected, num_selections, 1667 select_generation, current_generation, devices, numdevs, 1668 matches, num_matches, dev_selections, num_dev_selections, 1669 select_mode, maxshowdevs, perf_select)); 1670 } 1671 1672 int 1673 buildmatch(char *match_str, struct devstat_match **matches, 1674 int *num_matches) 1675 { 1676 return(devstat_buildmatch(match_str, matches, num_matches)); 1677 } 1678 1679 long double 1680 compute_etime(struct timeval cur_time, struct timeval prev_time) 1681 { 1682 return(devstat_compute_etime(cur_time, prev_time)); 1683 } 1684