1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2013 David Hoeppner. All rights reserved. 25 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 26 * Copyright 2016 Joyent, Inc. 27 * Copyright 2020 Peter Tribble. 28 */ 29 30 /* 31 * Display kernel statistics 32 * 33 * This is a reimplementation of the perl kstat command originally found 34 * under usr/src/cmd/kstat/kstat.pl 35 * 36 * Incompatibilities: 37 * - perl regular expressions replaced with extended REs bracketed by '/' 38 * 39 * Flags added: 40 * -C similar to the -p option but value is separated by a colon 41 * -h display help 42 * -j json format 43 */ 44 45 #include <assert.h> 46 #include <ctype.h> 47 #include <errno.h> 48 #include <kstat.h> 49 #include <langinfo.h> 50 #include <libgen.h> 51 #include <limits.h> 52 #include <locale.h> 53 #include <signal.h> 54 #include <stddef.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <strings.h> 59 #include <time.h> 60 #include <unistd.h> 61 #include <sys/list.h> 62 #include <sys/time.h> 63 #include <sys/types.h> 64 65 #include "kstat.h" 66 #include "statcommon.h" 67 68 char *cmdname = "kstat"; /* Name of this command */ 69 int caught_cont = 0; /* Have caught a SIGCONT */ 70 71 static uint_t g_timestamp_fmt = NODATE; 72 73 /* Helper flag - header was printed already? */ 74 static boolean_t g_headerflg; 75 76 /* Saved command line options */ 77 static boolean_t g_cflg = B_FALSE; 78 static boolean_t g_jflg = B_FALSE; 79 static boolean_t g_lflg = B_FALSE; 80 static boolean_t g_pflg = B_FALSE; 81 static boolean_t g_qflg = B_FALSE; 82 static ks_pattern_t g_ks_class = {"*", 0}; 83 84 static boolean_t g_matched = B_FALSE; 85 86 /* Sorted list of kstat instances */ 87 static list_t instances_list; 88 static list_t selector_list; 89 90 int 91 main(int argc, char **argv) 92 { 93 ks_selector_t *nselector; 94 ks_selector_t *uselector; 95 kstat_ctl_t *kc; 96 hrtime_t start_n; 97 hrtime_t period_n; 98 boolean_t errflg = B_FALSE; 99 boolean_t nselflg = B_FALSE; 100 boolean_t uselflg = B_FALSE; 101 char *q; 102 int count = 1; 103 int infinite_cycles = 0; 104 int interval = 0; 105 int n = 0; 106 int c, m, tmp; 107 108 (void) setlocale(LC_ALL, ""); 109 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 110 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 111 #endif 112 (void) textdomain(TEXT_DOMAIN); 113 114 /* 115 * Create the selector list and a dummy default selector to match 116 * everything. While we process the cmdline options we will add 117 * selectors to this list. 118 */ 119 list_create(&selector_list, sizeof (ks_selector_t), 120 offsetof(ks_selector_t, ks_next)); 121 122 nselector = new_selector(); 123 124 /* 125 * Parse named command line arguments. 126 */ 127 while ((c = getopt(argc, argv, "h?CqjlpT:m:i:n:s:c:")) != EOF) 128 switch (c) { 129 case 'h': 130 case '?': 131 usage(); 132 exit(0); 133 break; 134 case 'C': 135 g_pflg = g_cflg = B_TRUE; 136 break; 137 case 'q': 138 g_qflg = B_TRUE; 139 break; 140 case 'j': 141 /* 142 * If we're printing JSON, we're going to force numeric 143 * representation to be in the C locale to assure that 144 * the decimal point is compliant with RFC 7159 (i.e., 145 * ASCII 0x2e). 146 */ 147 (void) setlocale(LC_NUMERIC, "C"); 148 g_jflg = B_TRUE; 149 break; 150 case 'l': 151 g_pflg = g_lflg = B_TRUE; 152 break; 153 case 'p': 154 g_pflg = B_TRUE; 155 break; 156 case 'T': 157 switch (*optarg) { 158 case 'd': 159 g_timestamp_fmt = DDATE; 160 break; 161 case 'u': 162 g_timestamp_fmt = UDATE; 163 break; 164 default: 165 errflg = B_TRUE; 166 } 167 break; 168 case 'm': 169 nselflg = B_TRUE; 170 nselector->ks_module.pstr = 171 (char *)ks_safe_strdup(optarg); 172 break; 173 case 'i': 174 nselflg = B_TRUE; 175 nselector->ks_instance.pstr = 176 (char *)ks_safe_strdup(optarg); 177 break; 178 case 'n': 179 nselflg = B_TRUE; 180 nselector->ks_name.pstr = 181 (char *)ks_safe_strdup(optarg); 182 break; 183 case 's': 184 nselflg = B_TRUE; 185 nselector->ks_statistic.pstr = 186 (char *)ks_safe_strdup(optarg); 187 break; 188 case 'c': 189 g_ks_class.pstr = 190 (char *)ks_safe_strdup(optarg); 191 break; 192 default: 193 errflg = B_TRUE; 194 break; 195 } 196 197 if (g_qflg && (g_jflg || g_pflg)) { 198 (void) fprintf(stderr, gettext( 199 "-q and -lpj are mutually exclusive\n")); 200 errflg = B_TRUE; 201 } 202 203 if (errflg) { 204 usage(); 205 exit(2); 206 } 207 208 argc -= optind; 209 argv += optind; 210 211 /* 212 * Consume the rest of the command line. Parsing the 213 * unnamed command line arguments. 214 */ 215 while (argc--) { 216 errno = 0; 217 tmp = strtoul(*argv, &q, 10); 218 if (tmp == ULONG_MAX && errno == ERANGE) { 219 if (n == 0) { 220 (void) fprintf(stderr, gettext( 221 "Interval is too large\n")); 222 } else if (n == 1) { 223 (void) fprintf(stderr, gettext( 224 "Count is too large\n")); 225 } 226 usage(); 227 exit(2); 228 } 229 230 if (errno != 0 || *q != '\0') { 231 m = 0; 232 uselector = new_selector(); 233 while ((q = (char *)strsep(argv, ":")) != NULL) { 234 m++; 235 if (m > 4) { 236 free(uselector); 237 usage(); 238 exit(2); 239 } 240 241 if (*q != '\0') { 242 switch (m) { 243 case 1: 244 uselector->ks_module.pstr = 245 (char *)ks_safe_strdup(q); 246 break; 247 case 2: 248 uselector->ks_instance.pstr = 249 (char *)ks_safe_strdup(q); 250 break; 251 case 3: 252 uselector->ks_name.pstr = 253 (char *)ks_safe_strdup(q); 254 break; 255 case 4: 256 uselector->ks_statistic.pstr = 257 (char *)ks_safe_strdup(q); 258 break; 259 default: 260 assert(B_FALSE); 261 } 262 } 263 } 264 265 uselflg = B_TRUE; 266 list_insert_tail(&selector_list, uselector); 267 } else { 268 if (tmp < 1) { 269 if (n == 0) { 270 (void) fprintf(stderr, gettext( 271 "Interval must be an " 272 "integer >= 1")); 273 } else if (n == 1) { 274 (void) fprintf(stderr, gettext( 275 "Count must be an integer >= 1")); 276 } 277 usage(); 278 exit(2); 279 } else { 280 if (n == 0) { 281 interval = tmp; 282 count = -1; 283 } else if (n == 1) { 284 count = tmp; 285 } else { 286 usage(); 287 exit(2); 288 } 289 } 290 n++; 291 } 292 argv++; 293 } 294 295 /* 296 * Check if we founded a named selector on the cmdline. 297 */ 298 if (uselflg) { 299 if (nselflg) { 300 (void) fprintf(stderr, gettext( 301 "[module[:instance[:name[:statistic]]]] and " 302 "-m -i -n -s are mutually exclusive")); 303 usage(); 304 exit(2); 305 } else { 306 free(nselector); 307 } 308 } else { 309 list_insert_tail(&selector_list, nselector); 310 } 311 312 assert(!list_is_empty(&selector_list)); 313 314 list_create(&instances_list, sizeof (ks_instance_t), 315 offsetof(ks_instance_t, ks_next)); 316 317 while ((kc = kstat_open()) == NULL) { 318 if (errno == EAGAIN) { 319 (void) poll(NULL, 0, 200); 320 } else { 321 perror("kstat_open"); 322 exit(3); 323 } 324 } 325 326 if (count > 1) { 327 if (signal(SIGCONT, cont_handler) == SIG_ERR) { 328 (void) fprintf(stderr, gettext( 329 "signal failed")); 330 exit(3); 331 } 332 } 333 334 period_n = (hrtime_t)interval * NANOSEC; 335 start_n = gethrtime(); 336 337 while (count == -1 || count-- > 0) { 338 ks_instances_read(kc); 339 ks_instances_print(); 340 341 if (interval && count) { 342 ks_sleep_until(&start_n, period_n, infinite_cycles, 343 &caught_cont); 344 (void) kstat_chain_update(kc); 345 (void) putchar('\n'); 346 } 347 } 348 349 (void) kstat_close(kc); 350 351 /* 352 * Return a non-zero exit code if we didn't match anything. 353 */ 354 return (g_matched ? 0 : 1); 355 } 356 357 /* 358 * Print usage. 359 */ 360 static void 361 usage(void) 362 { 363 (void) fprintf(stderr, gettext( 364 "Usage:\n" 365 "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n" 366 " [ -m module ] [ -i instance ] [ -n name ] [ -s statistic ]\n" 367 " [ interval [ count ] ]\n" 368 "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n" 369 " [ module[:instance[:name[:statistic]]] ... ]\n" 370 " [ interval [ count ] ]\n")); 371 } 372 373 /* 374 * Sort compare function. 375 */ 376 static int 377 compare_instances(ks_instance_t *l_arg, ks_instance_t *r_arg) 378 { 379 int rval; 380 381 rval = strcasecmp(l_arg->ks_module, r_arg->ks_module); 382 if (rval == 0) { 383 if (l_arg->ks_instance == r_arg->ks_instance) { 384 return (strcasecmp(l_arg->ks_name, r_arg->ks_name)); 385 } else if (l_arg->ks_instance < r_arg->ks_instance) { 386 return (-1); 387 } else { 388 return (1); 389 } 390 } else { 391 return (rval); 392 } 393 } 394 395 static char * 396 ks_safe_strdup(char *str) 397 { 398 char *ret; 399 400 if (str == NULL) { 401 return (NULL); 402 } 403 404 while ((ret = strdup(str)) == NULL) { 405 if (errno == EAGAIN) { 406 (void) poll(NULL, 0, 200); 407 } else { 408 perror("strdup"); 409 exit(3); 410 } 411 } 412 413 return (ret); 414 } 415 416 static void 417 ks_sleep_until(hrtime_t *wakeup, hrtime_t interval, int forever, 418 int *caught_cont) 419 { 420 hrtime_t now, pause, pause_left; 421 struct timespec pause_tv; 422 int status; 423 424 now = gethrtime(); 425 pause = *wakeup + interval - now; 426 427 if (pause <= 0 || pause < (interval / 4)) { 428 if (forever || *caught_cont) { 429 *wakeup = now + interval; 430 pause = interval; 431 } else { 432 pause = interval / 2; 433 *wakeup += interval; 434 } 435 } else { 436 *wakeup += interval; 437 } 438 439 if (pause < 1000) { 440 return; 441 } 442 443 pause_left = pause; 444 do { 445 pause_tv.tv_sec = pause_left / NANOSEC; 446 pause_tv.tv_nsec = pause_left % NANOSEC; 447 status = nanosleep(&pause_tv, (struct timespec *)NULL); 448 if (status < 0) { 449 if (errno == EINTR) { 450 now = gethrtime(); 451 pause_left = *wakeup - now; 452 if (pause_left < 1000) { 453 return; 454 } 455 } else { 456 perror("nanosleep"); 457 exit(3); 458 } 459 } 460 } while (status != 0); 461 } 462 463 /* 464 * Inserts an instance in the per selector list. 465 */ 466 static void 467 nvpair_insert(ks_instance_t *ksi, char *name, ks_value_t *value, 468 uchar_t data_type) 469 { 470 ks_nvpair_t *instance; 471 ks_nvpair_t *tmp; 472 473 instance = (ks_nvpair_t *)malloc(sizeof (ks_nvpair_t)); 474 if (instance == NULL) { 475 perror("malloc"); 476 exit(3); 477 } 478 479 (void) strlcpy(instance->name, name, KSTAT_STRLEN); 480 (void) memcpy(&instance->value, value, sizeof (ks_value_t)); 481 instance->data_type = data_type; 482 483 tmp = list_head(&ksi->ks_nvlist); 484 while (tmp != NULL && strcasecmp(instance->name, tmp->name) > 0) 485 tmp = list_next(&ksi->ks_nvlist, tmp); 486 487 list_insert_before(&ksi->ks_nvlist, tmp, instance); 488 } 489 490 /* 491 * Allocates a new all-matching selector. 492 */ 493 static ks_selector_t * 494 new_selector(void) 495 { 496 ks_selector_t *selector; 497 498 selector = (ks_selector_t *)malloc(sizeof (ks_selector_t)); 499 if (selector == NULL) { 500 perror("malloc"); 501 exit(3); 502 } 503 504 list_link_init(&selector->ks_next); 505 506 selector->ks_module.pstr = "*"; 507 selector->ks_instance.pstr = "*"; 508 selector->ks_name.pstr = "*"; 509 selector->ks_statistic.pstr = "*"; 510 511 return (selector); 512 } 513 514 /* 515 * This function was taken from the perl kstat module code - please 516 * see for further comments there. 517 */ 518 static kstat_raw_reader_t 519 lookup_raw_kstat_fn(char *module, char *name) 520 { 521 char key[KSTAT_STRLEN * 2]; 522 register char *f, *t; 523 int n = 0; 524 525 for (f = module, t = key; *f != '\0'; f++, t++) { 526 while (*f != '\0' && isdigit(*f)) 527 f++; 528 *t = *f; 529 } 530 *t++ = ':'; 531 532 for (f = name; *f != '\0'; f++, t++) { 533 while (*f != '\0' && isdigit(*f)) 534 f++; 535 *t = *f; 536 } 537 *t = '\0'; 538 539 while (ks_raw_lookup[n].fn != NULL) { 540 if (strncmp(ks_raw_lookup[n].name, key, strlen(key)) == 0) 541 return (ks_raw_lookup[n].fn); 542 n++; 543 } 544 545 return (0); 546 } 547 548 /* 549 * Match a string against a shell glob or extended regular expression. 550 */ 551 static boolean_t 552 ks_match(const char *str, ks_pattern_t *pattern) 553 { 554 int regcode; 555 char *regstr; 556 char *errbuf; 557 size_t bufsz; 558 559 if (pattern->pstr != NULL && gmatch(pattern->pstr, "/*/") != 0) { 560 /* All regex patterns are strdup'd copies */ 561 regstr = pattern->pstr + 1; 562 *(strrchr(regstr, '/')) = '\0'; 563 564 regcode = regcomp(&pattern->preg, regstr, 565 REG_EXTENDED | REG_NOSUB); 566 if (regcode != 0) { 567 bufsz = regerror(regcode, NULL, NULL, 0); 568 if (bufsz != 0) { 569 errbuf = malloc(bufsz); 570 if (errbuf == NULL) { 571 perror("malloc"); 572 exit(3); 573 } 574 (void) regerror(regcode, NULL, errbuf, bufsz); 575 (void) fprintf(stderr, "kstat: %s\n", errbuf); 576 } 577 usage(); 578 exit(2); 579 } 580 581 pattern->pstr = NULL; 582 } 583 584 if (pattern->pstr == NULL) { 585 return (regexec(&pattern->preg, str, 0, NULL, 0) == 0); 586 } 587 588 return ((gmatch(str, pattern->pstr) != 0)); 589 } 590 591 /* 592 * Iterate over all kernel statistics and save matches. 593 */ 594 static void 595 ks_instances_read(kstat_ctl_t *kc) 596 { 597 kstat_raw_reader_t save_raw = NULL; 598 kid_t id; 599 ks_selector_t *selector; 600 ks_instance_t *ksi; 601 ks_instance_t *tmp; 602 kstat_t *kp; 603 boolean_t skip; 604 605 for (kp = kc->kc_chain; kp != NULL; kp = kp->ks_next) { 606 /* Don't bother storing the kstat headers */ 607 if (strncmp(kp->ks_name, "kstat_", 6) == 0) { 608 continue; 609 } 610 611 /* Don't bother storing raw stats we don't understand */ 612 if (kp->ks_type == KSTAT_TYPE_RAW) { 613 save_raw = lookup_raw_kstat_fn(kp->ks_module, 614 kp->ks_name); 615 if (save_raw == NULL) { 616 #ifdef REPORT_UNKNOWN 617 (void) fprintf(stderr, 618 "Unknown kstat type %s:%d:%s - " 619 "%d of size %d\n", kp->ks_module, 620 kp->ks_instance, kp->ks_name, 621 kp->ks_ndata, kp->ks_data_size); 622 #endif 623 continue; 624 } 625 } 626 627 /* 628 * Iterate over the list of selectors and skip 629 * instances we dont want. We filter for statistics 630 * later, as we dont know them yet. 631 */ 632 skip = B_TRUE; 633 selector = list_head(&selector_list); 634 while (selector != NULL) { 635 if (ks_match(kp->ks_module, &selector->ks_module) && 636 ks_match(kp->ks_name, &selector->ks_name)) { 637 skip = B_FALSE; 638 break; 639 } 640 selector = list_next(&selector_list, selector); 641 } 642 643 if (skip) { 644 continue; 645 } 646 647 /* 648 * Allocate a new instance and fill in the values 649 * we know so far. 650 */ 651 ksi = (ks_instance_t *)malloc(sizeof (ks_instance_t)); 652 if (ksi == NULL) { 653 perror("malloc"); 654 exit(3); 655 } 656 657 list_link_init(&ksi->ks_next); 658 659 (void) strlcpy(ksi->ks_module, kp->ks_module, KSTAT_STRLEN); 660 (void) strlcpy(ksi->ks_name, kp->ks_name, KSTAT_STRLEN); 661 (void) strlcpy(ksi->ks_class, kp->ks_class, KSTAT_STRLEN); 662 663 ksi->ks_instance = kp->ks_instance; 664 ksi->ks_snaptime = kp->ks_snaptime; 665 ksi->ks_type = kp->ks_type; 666 667 list_create(&ksi->ks_nvlist, sizeof (ks_nvpair_t), 668 offsetof(ks_nvpair_t, nv_next)); 669 670 SAVE_HRTIME_X(ksi, "crtime", kp->ks_crtime); 671 if (g_pflg) { 672 SAVE_STRING_X(ksi, "class", kp->ks_class); 673 } 674 675 /* Insert this instance into a sorted list */ 676 tmp = list_head(&instances_list); 677 while (tmp != NULL && compare_instances(ksi, tmp) > 0) 678 tmp = list_next(&instances_list, tmp); 679 680 list_insert_before(&instances_list, tmp, ksi); 681 682 /* Read the actual statistics */ 683 id = kstat_read(kc, kp, NULL); 684 if (id == -1) { 685 #ifdef REPORT_UNKNOWN 686 perror("kstat_read"); 687 #endif 688 continue; 689 } 690 691 SAVE_HRTIME_X(ksi, "snaptime", kp->ks_snaptime); 692 693 switch (kp->ks_type) { 694 case KSTAT_TYPE_RAW: 695 save_raw(kp, ksi); 696 break; 697 case KSTAT_TYPE_NAMED: 698 save_named(kp, ksi); 699 break; 700 case KSTAT_TYPE_INTR: 701 save_intr(kp, ksi); 702 break; 703 case KSTAT_TYPE_IO: 704 save_io(kp, ksi); 705 break; 706 case KSTAT_TYPE_TIMER: 707 save_timer(kp, ksi); 708 break; 709 default: 710 assert(B_FALSE); /* Invalid type */ 711 break; 712 } 713 } 714 } 715 716 /* 717 * Print the value of a name-value pair. 718 */ 719 static void 720 ks_value_print(ks_nvpair_t *nvpair) 721 { 722 switch (nvpair->data_type) { 723 case KSTAT_DATA_CHAR: 724 (void) fprintf(stdout, "%s", nvpair->value.c); 725 break; 726 case KSTAT_DATA_INT32: 727 (void) fprintf(stdout, "%d", nvpair->value.i32); 728 break; 729 case KSTAT_DATA_UINT32: 730 (void) fprintf(stdout, "%u", nvpair->value.ui32); 731 break; 732 case KSTAT_DATA_INT64: 733 (void) fprintf(stdout, "%lld", nvpair->value.i64); 734 break; 735 case KSTAT_DATA_UINT64: 736 (void) fprintf(stdout, "%llu", nvpair->value.ui64); 737 break; 738 case KSTAT_DATA_STRING: 739 (void) fprintf(stdout, "%s", KSTAT_NAMED_STR_PTR(nvpair)); 740 break; 741 case KSTAT_DATA_HRTIME: 742 if (nvpair->value.ui64 == 0) 743 (void) fprintf(stdout, "0"); 744 else 745 (void) fprintf(stdout, "%.9f", 746 nvpair->value.ui64 / 1000000000.0); 747 break; 748 default: 749 assert(B_FALSE); 750 } 751 } 752 753 /* 754 * Print a single instance. 755 */ 756 /*ARGSUSED*/ 757 static void 758 ks_instance_print(ks_instance_t *ksi, ks_nvpair_t *nvpair, boolean_t last) 759 { 760 if (g_headerflg) { 761 if (!g_pflg) { 762 (void) fprintf(stdout, DFLT_FMT, 763 ksi->ks_module, ksi->ks_instance, 764 ksi->ks_name, ksi->ks_class); 765 } 766 g_headerflg = B_FALSE; 767 } 768 769 if (g_pflg) { 770 (void) fprintf(stdout, KS_PFMT, 771 ksi->ks_module, ksi->ks_instance, 772 ksi->ks_name, nvpair->name); 773 if (!g_lflg) { 774 (void) putchar(g_cflg ? ':': '\t'); 775 ks_value_print(nvpair); 776 } 777 } else { 778 (void) fprintf(stdout, KS_DFMT, nvpair->name); 779 ks_value_print(nvpair); 780 } 781 782 (void) putchar('\n'); 783 } 784 785 /* 786 * Print a C string as a JSON string. 787 */ 788 static void 789 ks_print_json_string(const char *str) 790 { 791 char c; 792 793 (void) putchar('"'); 794 795 while ((c = *str++) != '\0') { 796 /* 797 * For readability, we use the allowed alternate escape 798 * sequence for quote, question mark, reverse solidus (look 799 * it up!), newline and tab -- and use the universal escape 800 * sequence for all other control characters. 801 */ 802 switch (c) { 803 case '"': 804 case '?': 805 case '\\': 806 (void) fprintf(stdout, "\\%c", c); 807 break; 808 809 case '\n': 810 (void) fprintf(stdout, "\\n"); 811 break; 812 813 case '\t': 814 (void) fprintf(stdout, "\\t"); 815 break; 816 817 default: 818 /* 819 * By escaping those characters for which isprint(3C) 820 * is false, we escape both the RFC 7159 mandated 821 * escaped range of 0x01 through 0x1f as well as DEL 822 * (0x7f -- the control character that RFC 7159 forgot) 823 * and then everything else that's unprintable for 824 * good measure. 825 */ 826 if (!isprint(c)) { 827 (void) fprintf(stdout, "\\u%04hhx", (uint8_t)c); 828 break; 829 } 830 831 (void) putchar(c); 832 break; 833 } 834 } 835 836 (void) putchar('"'); 837 } 838 839 /* 840 * Print a single instance in JSON format. 841 */ 842 static void 843 ks_instance_print_json(ks_instance_t *ksi, ks_nvpair_t *nvpair, boolean_t last) 844 { 845 static int headers; 846 847 if (g_headerflg) { 848 if (headers++ > 0) 849 (void) fprintf(stdout, ", "); 850 851 (void) fprintf(stdout, "{\n\t\"module\": "); 852 ks_print_json_string(ksi->ks_module); 853 854 (void) fprintf(stdout, 855 ",\n\t\"instance\": %d,\n\t\"name\": ", ksi->ks_instance); 856 ks_print_json_string(ksi->ks_name); 857 858 (void) fprintf(stdout, ",\n\t\"class\": "); 859 ks_print_json_string(ksi->ks_class); 860 861 (void) fprintf(stdout, ",\n\t\"type\": %d,\n", ksi->ks_type); 862 863 if (ksi->ks_snaptime == 0) 864 (void) fprintf(stdout, "\t\"snaptime\": 0,\n"); 865 else 866 (void) fprintf(stdout, "\t\"snaptime\": %.9f,\n", 867 ksi->ks_snaptime / 1000000000.0); 868 869 (void) fprintf(stdout, "\t\"data\": {\n"); 870 871 g_headerflg = B_FALSE; 872 } 873 874 (void) fprintf(stdout, "\t\t"); 875 ks_print_json_string(nvpair->name); 876 (void) fprintf(stdout, ": "); 877 878 switch (nvpair->data_type) { 879 case KSTAT_DATA_CHAR: 880 ks_print_json_string(nvpair->value.c); 881 break; 882 883 case KSTAT_DATA_STRING: 884 ks_print_json_string(KSTAT_NAMED_STR_PTR(nvpair)); 885 break; 886 887 default: 888 ks_value_print(nvpair); 889 break; 890 } 891 892 if (!last) 893 (void) putchar(','); 894 895 (void) putchar('\n'); 896 } 897 898 /* 899 * Print all instances. 900 */ 901 static void 902 ks_instances_print(void) 903 { 904 ks_selector_t *selector; 905 ks_instance_t *ksi, *ktmp; 906 ks_nvpair_t *nvpair, *ntmp, *next; 907 void (*ks_print_fn)(ks_instance_t *, ks_nvpair_t *, boolean_t); 908 char *ks_number; 909 910 if (g_timestamp_fmt != NODATE) 911 print_timestamp(g_timestamp_fmt); 912 913 if (g_jflg) { 914 ks_print_fn = &ks_instance_print_json; 915 (void) putchar('['); 916 } else { 917 ks_print_fn = &ks_instance_print; 918 } 919 920 /* Iterate over each selector */ 921 selector = list_head(&selector_list); 922 while (selector != NULL) { 923 924 /* Iterate over each instance */ 925 for (ksi = list_head(&instances_list); ksi != NULL; 926 ksi = list_next(&instances_list, ksi)) { 927 928 (void) asprintf(&ks_number, "%d", ksi->ks_instance); 929 if (!(ks_match(ksi->ks_module, &selector->ks_module) && 930 ks_match(ksi->ks_name, &selector->ks_name) && 931 ks_match(ks_number, &selector->ks_instance) && 932 ks_match(ksi->ks_class, &g_ks_class))) { 933 free(ks_number); 934 continue; 935 } 936 937 free(ks_number); 938 939 g_headerflg = B_TRUE; 940 941 /* 942 * Find our first statistic to print. 943 */ 944 for (nvpair = list_head(&ksi->ks_nvlist); 945 nvpair != NULL; 946 nvpair = list_next(&ksi->ks_nvlist, nvpair)) { 947 if (ks_match(nvpair->name, 948 &selector->ks_statistic)) 949 break; 950 } 951 952 while (nvpair != NULL) { 953 boolean_t last; 954 955 /* 956 * Find the next statistic to print so we can 957 * indicate to the print function if this 958 * statistic is the last to be printed for 959 * this instance. 960 */ 961 for (next = list_next(&ksi->ks_nvlist, nvpair); 962 next != NULL; 963 next = list_next(&ksi->ks_nvlist, next)) { 964 if (ks_match(next->name, 965 &selector->ks_statistic)) 966 break; 967 } 968 969 g_matched = B_TRUE; 970 last = next == NULL ? B_TRUE : B_FALSE; 971 972 if (!g_qflg) 973 (*ks_print_fn)(ksi, nvpair, last); 974 975 nvpair = next; 976 } 977 978 if (!g_headerflg) { 979 if (g_jflg) { 980 (void) fprintf(stdout, "\t}\n}"); 981 } else if (!g_pflg) { 982 (void) putchar('\n'); 983 } 984 } 985 } 986 987 selector = list_next(&selector_list, selector); 988 } 989 990 if (g_jflg) 991 (void) fprintf(stdout, "]\n"); 992 993 (void) fflush(stdout); 994 995 /* Free the instances list */ 996 ksi = list_head(&instances_list); 997 while (ksi != NULL) { 998 nvpair = list_head(&ksi->ks_nvlist); 999 while (nvpair != NULL) { 1000 ntmp = nvpair; 1001 nvpair = list_next(&ksi->ks_nvlist, nvpair); 1002 list_remove(&ksi->ks_nvlist, ntmp); 1003 if (ntmp->data_type == KSTAT_DATA_STRING) 1004 free(ntmp->value.str.addr.ptr); 1005 free(ntmp); 1006 } 1007 1008 ktmp = ksi; 1009 ksi = list_next(&instances_list, ksi); 1010 list_remove(&instances_list, ktmp); 1011 list_destroy(&ktmp->ks_nvlist); 1012 free(ktmp); 1013 } 1014 } 1015 1016 static void 1017 save_cpu_stat(kstat_t *kp, ks_instance_t *ksi) 1018 { 1019 cpu_stat_t *stat; 1020 cpu_sysinfo_t *sysinfo; 1021 cpu_syswait_t *syswait; 1022 cpu_vminfo_t *vminfo; 1023 1024 stat = (cpu_stat_t *)(kp->ks_data); 1025 sysinfo = &stat->cpu_sysinfo; 1026 syswait = &stat->cpu_syswait; 1027 vminfo = &stat->cpu_vminfo; 1028 1029 SAVE_UINT32_X(ksi, "idle", sysinfo->cpu[CPU_IDLE]); 1030 SAVE_UINT32_X(ksi, "user", sysinfo->cpu[CPU_USER]); 1031 SAVE_UINT32_X(ksi, "kernel", sysinfo->cpu[CPU_KERNEL]); 1032 SAVE_UINT32_X(ksi, "wait", sysinfo->cpu[CPU_WAIT]); 1033 SAVE_UINT32_X(ksi, "wait_io", sysinfo->wait[W_IO]); 1034 SAVE_UINT32_X(ksi, "wait_swap", sysinfo->wait[W_SWAP]); 1035 SAVE_UINT32_X(ksi, "wait_pio", sysinfo->wait[W_PIO]); 1036 SAVE_UINT32(ksi, sysinfo, bread); 1037 SAVE_UINT32(ksi, sysinfo, bwrite); 1038 SAVE_UINT32(ksi, sysinfo, lread); 1039 SAVE_UINT32(ksi, sysinfo, lwrite); 1040 SAVE_UINT32(ksi, sysinfo, phread); 1041 SAVE_UINT32(ksi, sysinfo, phwrite); 1042 SAVE_UINT32(ksi, sysinfo, pswitch); 1043 SAVE_UINT32(ksi, sysinfo, trap); 1044 SAVE_UINT32(ksi, sysinfo, intr); 1045 SAVE_UINT32(ksi, sysinfo, syscall); 1046 SAVE_UINT32(ksi, sysinfo, sysread); 1047 SAVE_UINT32(ksi, sysinfo, syswrite); 1048 SAVE_UINT32(ksi, sysinfo, sysfork); 1049 SAVE_UINT32(ksi, sysinfo, sysvfork); 1050 SAVE_UINT32(ksi, sysinfo, sysexec); 1051 SAVE_UINT32(ksi, sysinfo, readch); 1052 SAVE_UINT32(ksi, sysinfo, writech); 1053 SAVE_UINT32(ksi, sysinfo, rcvint); 1054 SAVE_UINT32(ksi, sysinfo, xmtint); 1055 SAVE_UINT32(ksi, sysinfo, mdmint); 1056 SAVE_UINT32(ksi, sysinfo, rawch); 1057 SAVE_UINT32(ksi, sysinfo, canch); 1058 SAVE_UINT32(ksi, sysinfo, outch); 1059 SAVE_UINT32(ksi, sysinfo, msg); 1060 SAVE_UINT32(ksi, sysinfo, sema); 1061 SAVE_UINT32(ksi, sysinfo, namei); 1062 SAVE_UINT32(ksi, sysinfo, ufsiget); 1063 SAVE_UINT32(ksi, sysinfo, ufsdirblk); 1064 SAVE_UINT32(ksi, sysinfo, ufsipage); 1065 SAVE_UINT32(ksi, sysinfo, ufsinopage); 1066 SAVE_UINT32(ksi, sysinfo, inodeovf); 1067 SAVE_UINT32(ksi, sysinfo, fileovf); 1068 SAVE_UINT32(ksi, sysinfo, procovf); 1069 SAVE_UINT32(ksi, sysinfo, intrthread); 1070 SAVE_UINT32(ksi, sysinfo, intrblk); 1071 SAVE_UINT32(ksi, sysinfo, idlethread); 1072 SAVE_UINT32(ksi, sysinfo, inv_swtch); 1073 SAVE_UINT32(ksi, sysinfo, nthreads); 1074 SAVE_UINT32(ksi, sysinfo, cpumigrate); 1075 SAVE_UINT32(ksi, sysinfo, xcalls); 1076 SAVE_UINT32(ksi, sysinfo, mutex_adenters); 1077 SAVE_UINT32(ksi, sysinfo, rw_rdfails); 1078 SAVE_UINT32(ksi, sysinfo, rw_wrfails); 1079 SAVE_UINT32(ksi, sysinfo, modload); 1080 SAVE_UINT32(ksi, sysinfo, modunload); 1081 SAVE_UINT32(ksi, sysinfo, bawrite); 1082 #ifdef STATISTICS /* see header file */ 1083 SAVE_UINT32(ksi, sysinfo, rw_enters); 1084 SAVE_UINT32(ksi, sysinfo, win_uo_cnt); 1085 SAVE_UINT32(ksi, sysinfo, win_uu_cnt); 1086 SAVE_UINT32(ksi, sysinfo, win_so_cnt); 1087 SAVE_UINT32(ksi, sysinfo, win_su_cnt); 1088 SAVE_UINT32(ksi, sysinfo, win_suo_cnt); 1089 #endif 1090 1091 SAVE_INT32(ksi, syswait, iowait); 1092 SAVE_INT32(ksi, syswait, swap); 1093 SAVE_INT32(ksi, syswait, physio); 1094 1095 SAVE_UINT32(ksi, vminfo, pgrec); 1096 SAVE_UINT32(ksi, vminfo, pgfrec); 1097 SAVE_UINT32(ksi, vminfo, pgin); 1098 SAVE_UINT32(ksi, vminfo, pgpgin); 1099 SAVE_UINT32(ksi, vminfo, pgout); 1100 SAVE_UINT32(ksi, vminfo, pgpgout); 1101 SAVE_UINT32(ksi, vminfo, swapin); 1102 SAVE_UINT32(ksi, vminfo, pgswapin); 1103 SAVE_UINT32(ksi, vminfo, swapout); 1104 SAVE_UINT32(ksi, vminfo, pgswapout); 1105 SAVE_UINT32(ksi, vminfo, zfod); 1106 SAVE_UINT32(ksi, vminfo, dfree); 1107 SAVE_UINT32(ksi, vminfo, scan); 1108 SAVE_UINT32(ksi, vminfo, rev); 1109 SAVE_UINT32(ksi, vminfo, hat_fault); 1110 SAVE_UINT32(ksi, vminfo, as_fault); 1111 SAVE_UINT32(ksi, vminfo, maj_fault); 1112 SAVE_UINT32(ksi, vminfo, cow_fault); 1113 SAVE_UINT32(ksi, vminfo, prot_fault); 1114 SAVE_UINT32(ksi, vminfo, softlock); 1115 SAVE_UINT32(ksi, vminfo, kernel_asflt); 1116 SAVE_UINT32(ksi, vminfo, pgrrun); 1117 SAVE_UINT32(ksi, vminfo, execpgin); 1118 SAVE_UINT32(ksi, vminfo, execpgout); 1119 SAVE_UINT32(ksi, vminfo, execfree); 1120 SAVE_UINT32(ksi, vminfo, anonpgin); 1121 SAVE_UINT32(ksi, vminfo, anonpgout); 1122 SAVE_UINT32(ksi, vminfo, anonfree); 1123 SAVE_UINT32(ksi, vminfo, fspgin); 1124 SAVE_UINT32(ksi, vminfo, fspgout); 1125 SAVE_UINT32(ksi, vminfo, fsfree); 1126 } 1127 1128 static void 1129 save_var(kstat_t *kp, ks_instance_t *ksi) 1130 { 1131 struct var *var = (struct var *)(kp->ks_data); 1132 1133 assert(kp->ks_data_size == sizeof (struct var)); 1134 1135 SAVE_INT32(ksi, var, v_buf); 1136 SAVE_INT32(ksi, var, v_call); 1137 SAVE_INT32(ksi, var, v_proc); 1138 SAVE_INT32(ksi, var, v_maxupttl); 1139 SAVE_INT32(ksi, var, v_nglobpris); 1140 SAVE_INT32(ksi, var, v_maxsyspri); 1141 SAVE_INT32(ksi, var, v_clist); 1142 SAVE_INT32(ksi, var, v_maxup); 1143 SAVE_INT32(ksi, var, v_hbuf); 1144 SAVE_INT32(ksi, var, v_hmask); 1145 SAVE_INT32(ksi, var, v_pbuf); 1146 SAVE_INT32(ksi, var, v_sptmap); 1147 SAVE_INT32(ksi, var, v_maxpmem); 1148 SAVE_INT32(ksi, var, v_autoup); 1149 SAVE_INT32(ksi, var, v_bufhwm); 1150 } 1151 1152 static void 1153 save_ncstats(kstat_t *kp, ks_instance_t *ksi) 1154 { 1155 struct ncstats *ncstats = (struct ncstats *)(kp->ks_data); 1156 1157 assert(kp->ks_data_size == sizeof (struct ncstats)); 1158 1159 SAVE_INT32(ksi, ncstats, hits); 1160 SAVE_INT32(ksi, ncstats, misses); 1161 SAVE_INT32(ksi, ncstats, enters); 1162 SAVE_INT32(ksi, ncstats, dbl_enters); 1163 SAVE_INT32(ksi, ncstats, long_enter); 1164 SAVE_INT32(ksi, ncstats, long_look); 1165 SAVE_INT32(ksi, ncstats, move_to_front); 1166 SAVE_INT32(ksi, ncstats, purges); 1167 } 1168 1169 static void 1170 save_sysinfo(kstat_t *kp, ks_instance_t *ksi) 1171 { 1172 sysinfo_t *sysinfo = (sysinfo_t *)(kp->ks_data); 1173 1174 assert(kp->ks_data_size == sizeof (sysinfo_t)); 1175 1176 SAVE_UINT32(ksi, sysinfo, updates); 1177 SAVE_UINT32(ksi, sysinfo, runque); 1178 SAVE_UINT32(ksi, sysinfo, runocc); 1179 SAVE_UINT32(ksi, sysinfo, swpque); 1180 SAVE_UINT32(ksi, sysinfo, swpocc); 1181 SAVE_UINT32(ksi, sysinfo, waiting); 1182 } 1183 1184 static void 1185 save_vminfo(kstat_t *kp, ks_instance_t *ksi) 1186 { 1187 vminfo_t *vminfo = (vminfo_t *)(kp->ks_data); 1188 1189 assert(kp->ks_data_size == sizeof (vminfo_t)); 1190 1191 SAVE_UINT64(ksi, vminfo, freemem); 1192 SAVE_UINT64(ksi, vminfo, swap_resv); 1193 SAVE_UINT64(ksi, vminfo, swap_alloc); 1194 SAVE_UINT64(ksi, vminfo, swap_avail); 1195 SAVE_UINT64(ksi, vminfo, swap_free); 1196 SAVE_UINT64(ksi, vminfo, updates); 1197 } 1198 1199 static void 1200 save_nfs(kstat_t *kp, ks_instance_t *ksi) 1201 { 1202 struct mntinfo_kstat *mntinfo = (struct mntinfo_kstat *)(kp->ks_data); 1203 1204 assert(kp->ks_data_size == sizeof (struct mntinfo_kstat)); 1205 1206 SAVE_STRING(ksi, mntinfo, mik_proto); 1207 SAVE_UINT32(ksi, mntinfo, mik_vers); 1208 SAVE_UINT32(ksi, mntinfo, mik_flags); 1209 SAVE_UINT32(ksi, mntinfo, mik_secmod); 1210 SAVE_UINT32(ksi, mntinfo, mik_curread); 1211 SAVE_UINT32(ksi, mntinfo, mik_curwrite); 1212 SAVE_INT32(ksi, mntinfo, mik_timeo); 1213 SAVE_INT32(ksi, mntinfo, mik_retrans); 1214 SAVE_UINT32(ksi, mntinfo, mik_acregmin); 1215 SAVE_UINT32(ksi, mntinfo, mik_acregmax); 1216 SAVE_UINT32(ksi, mntinfo, mik_acdirmin); 1217 SAVE_UINT32(ksi, mntinfo, mik_acdirmax); 1218 SAVE_UINT32_X(ksi, "lookup_srtt", mntinfo->mik_timers[0].srtt); 1219 SAVE_UINT32_X(ksi, "lookup_deviate", mntinfo->mik_timers[0].deviate); 1220 SAVE_UINT32_X(ksi, "lookup_rtxcur", mntinfo->mik_timers[0].rtxcur); 1221 SAVE_UINT32_X(ksi, "read_srtt", mntinfo->mik_timers[1].srtt); 1222 SAVE_UINT32_X(ksi, "read_deviate", mntinfo->mik_timers[1].deviate); 1223 SAVE_UINT32_X(ksi, "read_rtxcur", mntinfo->mik_timers[1].rtxcur); 1224 SAVE_UINT32_X(ksi, "write_srtt", mntinfo->mik_timers[2].srtt); 1225 SAVE_UINT32_X(ksi, "write_deviate", mntinfo->mik_timers[2].deviate); 1226 SAVE_UINT32_X(ksi, "write_rtxcur", mntinfo->mik_timers[2].rtxcur); 1227 SAVE_UINT32(ksi, mntinfo, mik_noresponse); 1228 SAVE_UINT32(ksi, mntinfo, mik_failover); 1229 SAVE_UINT32(ksi, mntinfo, mik_remap); 1230 SAVE_STRING(ksi, mntinfo, mik_curserver); 1231 } 1232 1233 #ifdef __sparc 1234 static void 1235 save_sfmmu_global_stat(kstat_t *kp, ks_instance_t *ksi) 1236 { 1237 struct sfmmu_global_stat *sfmmug = 1238 (struct sfmmu_global_stat *)(kp->ks_data); 1239 1240 assert(kp->ks_data_size == sizeof (struct sfmmu_global_stat)); 1241 1242 SAVE_INT32(ksi, sfmmug, sf_tsb_exceptions); 1243 SAVE_INT32(ksi, sfmmug, sf_tsb_raise_exception); 1244 SAVE_INT32(ksi, sfmmug, sf_pagefaults); 1245 SAVE_INT32(ksi, sfmmug, sf_uhash_searches); 1246 SAVE_INT32(ksi, sfmmug, sf_uhash_links); 1247 SAVE_INT32(ksi, sfmmug, sf_khash_searches); 1248 SAVE_INT32(ksi, sfmmug, sf_khash_links); 1249 SAVE_INT32(ksi, sfmmug, sf_swapout); 1250 SAVE_INT32(ksi, sfmmug, sf_tsb_alloc); 1251 SAVE_INT32(ksi, sfmmug, sf_tsb_allocfail); 1252 SAVE_INT32(ksi, sfmmug, sf_tsb_sectsb_create); 1253 SAVE_INT32(ksi, sfmmug, sf_scd_1sttsb_alloc); 1254 SAVE_INT32(ksi, sfmmug, sf_scd_2ndtsb_alloc); 1255 SAVE_INT32(ksi, sfmmug, sf_scd_1sttsb_allocfail); 1256 SAVE_INT32(ksi, sfmmug, sf_scd_2ndtsb_allocfail); 1257 SAVE_INT32(ksi, sfmmug, sf_tteload8k); 1258 SAVE_INT32(ksi, sfmmug, sf_tteload64k); 1259 SAVE_INT32(ksi, sfmmug, sf_tteload512k); 1260 SAVE_INT32(ksi, sfmmug, sf_tteload4m); 1261 SAVE_INT32(ksi, sfmmug, sf_tteload32m); 1262 SAVE_INT32(ksi, sfmmug, sf_tteload256m); 1263 SAVE_INT32(ksi, sfmmug, sf_tsb_load8k); 1264 SAVE_INT32(ksi, sfmmug, sf_tsb_load4m); 1265 SAVE_INT32(ksi, sfmmug, sf_hblk_hit); 1266 SAVE_INT32(ksi, sfmmug, sf_hblk8_ncreate); 1267 SAVE_INT32(ksi, sfmmug, sf_hblk8_nalloc); 1268 SAVE_INT32(ksi, sfmmug, sf_hblk1_ncreate); 1269 SAVE_INT32(ksi, sfmmug, sf_hblk1_nalloc); 1270 SAVE_INT32(ksi, sfmmug, sf_hblk_slab_cnt); 1271 SAVE_INT32(ksi, sfmmug, sf_hblk_reserve_cnt); 1272 SAVE_INT32(ksi, sfmmug, sf_hblk_recurse_cnt); 1273 SAVE_INT32(ksi, sfmmug, sf_hblk_reserve_hit); 1274 SAVE_INT32(ksi, sfmmug, sf_get_free_success); 1275 SAVE_INT32(ksi, sfmmug, sf_get_free_throttle); 1276 SAVE_INT32(ksi, sfmmug, sf_get_free_fail); 1277 SAVE_INT32(ksi, sfmmug, sf_put_free_success); 1278 SAVE_INT32(ksi, sfmmug, sf_put_free_fail); 1279 SAVE_INT32(ksi, sfmmug, sf_pgcolor_conflict); 1280 SAVE_INT32(ksi, sfmmug, sf_uncache_conflict); 1281 SAVE_INT32(ksi, sfmmug, sf_unload_conflict); 1282 SAVE_INT32(ksi, sfmmug, sf_ism_uncache); 1283 SAVE_INT32(ksi, sfmmug, sf_ism_recache); 1284 SAVE_INT32(ksi, sfmmug, sf_recache); 1285 SAVE_INT32(ksi, sfmmug, sf_steal_count); 1286 SAVE_INT32(ksi, sfmmug, sf_pagesync); 1287 SAVE_INT32(ksi, sfmmug, sf_clrwrt); 1288 SAVE_INT32(ksi, sfmmug, sf_pagesync_invalid); 1289 SAVE_INT32(ksi, sfmmug, sf_kernel_xcalls); 1290 SAVE_INT32(ksi, sfmmug, sf_user_xcalls); 1291 SAVE_INT32(ksi, sfmmug, sf_tsb_grow); 1292 SAVE_INT32(ksi, sfmmug, sf_tsb_shrink); 1293 SAVE_INT32(ksi, sfmmug, sf_tsb_resize_failures); 1294 SAVE_INT32(ksi, sfmmug, sf_tsb_reloc); 1295 SAVE_INT32(ksi, sfmmug, sf_user_vtop); 1296 SAVE_INT32(ksi, sfmmug, sf_ctx_inv); 1297 SAVE_INT32(ksi, sfmmug, sf_tlb_reprog_pgsz); 1298 SAVE_INT32(ksi, sfmmug, sf_region_remap_demap); 1299 SAVE_INT32(ksi, sfmmug, sf_create_scd); 1300 SAVE_INT32(ksi, sfmmug, sf_join_scd); 1301 SAVE_INT32(ksi, sfmmug, sf_leave_scd); 1302 SAVE_INT32(ksi, sfmmug, sf_destroy_scd); 1303 } 1304 #endif 1305 1306 #ifdef __sparc 1307 static void 1308 save_sfmmu_tsbsize_stat(kstat_t *kp, ks_instance_t *ksi) 1309 { 1310 struct sfmmu_tsbsize_stat *sfmmut; 1311 1312 assert(kp->ks_data_size == sizeof (struct sfmmu_tsbsize_stat)); 1313 sfmmut = (struct sfmmu_tsbsize_stat *)(kp->ks_data); 1314 1315 SAVE_INT32(ksi, sfmmut, sf_tsbsz_8k); 1316 SAVE_INT32(ksi, sfmmut, sf_tsbsz_16k); 1317 SAVE_INT32(ksi, sfmmut, sf_tsbsz_32k); 1318 SAVE_INT32(ksi, sfmmut, sf_tsbsz_64k); 1319 SAVE_INT32(ksi, sfmmut, sf_tsbsz_128k); 1320 SAVE_INT32(ksi, sfmmut, sf_tsbsz_256k); 1321 SAVE_INT32(ksi, sfmmut, sf_tsbsz_512k); 1322 SAVE_INT32(ksi, sfmmut, sf_tsbsz_1m); 1323 SAVE_INT32(ksi, sfmmut, sf_tsbsz_2m); 1324 SAVE_INT32(ksi, sfmmut, sf_tsbsz_4m); 1325 } 1326 #endif 1327 1328 static void 1329 save_named(kstat_t *kp, ks_instance_t *ksi) 1330 { 1331 kstat_named_t *knp; 1332 int n; 1333 1334 for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) { 1335 /* 1336 * Annoyingly, some drivers have kstats with uninitialized 1337 * members (which kstat_install(9F) is sadly powerless to 1338 * prevent, and kstat_read(3KSTAT) unfortunately does nothing 1339 * to stop). To prevent these from confusing us to be 1340 * KSTAT_DATA_CHAR statistics, we skip over them. 1341 */ 1342 if (knp->name[0] == '\0') 1343 continue; 1344 1345 switch (knp->data_type) { 1346 case KSTAT_DATA_CHAR: 1347 nvpair_insert(ksi, knp->name, 1348 (ks_value_t *)&knp->value, KSTAT_DATA_CHAR); 1349 break; 1350 case KSTAT_DATA_INT32: 1351 nvpair_insert(ksi, knp->name, 1352 (ks_value_t *)&knp->value, KSTAT_DATA_INT32); 1353 break; 1354 case KSTAT_DATA_UINT32: 1355 nvpair_insert(ksi, knp->name, 1356 (ks_value_t *)&knp->value, KSTAT_DATA_UINT32); 1357 break; 1358 case KSTAT_DATA_INT64: 1359 nvpair_insert(ksi, knp->name, 1360 (ks_value_t *)&knp->value, KSTAT_DATA_INT64); 1361 break; 1362 case KSTAT_DATA_UINT64: 1363 nvpair_insert(ksi, knp->name, 1364 (ks_value_t *)&knp->value, KSTAT_DATA_UINT64); 1365 break; 1366 case KSTAT_DATA_STRING: 1367 SAVE_STRING_X(ksi, knp->name, KSTAT_NAMED_STR_PTR(knp)); 1368 break; 1369 default: 1370 assert(B_FALSE); /* Invalid data type */ 1371 break; 1372 } 1373 } 1374 } 1375 1376 static void 1377 save_intr(kstat_t *kp, ks_instance_t *ksi) 1378 { 1379 kstat_intr_t *intr = KSTAT_INTR_PTR(kp); 1380 char *intr_names[] = {"hard", "soft", "watchdog", "spurious", 1381 "multiple_service"}; 1382 int n; 1383 1384 for (n = 0; n < KSTAT_NUM_INTRS; n++) 1385 SAVE_UINT32_X(ksi, intr_names[n], intr->intrs[n]); 1386 } 1387 1388 static void 1389 save_io(kstat_t *kp, ks_instance_t *ksi) 1390 { 1391 kstat_io_t *ksio = KSTAT_IO_PTR(kp); 1392 1393 SAVE_UINT64(ksi, ksio, nread); 1394 SAVE_UINT64(ksi, ksio, nwritten); 1395 SAVE_UINT32(ksi, ksio, reads); 1396 SAVE_UINT32(ksi, ksio, writes); 1397 SAVE_HRTIME(ksi, ksio, wtime); 1398 SAVE_HRTIME(ksi, ksio, wlentime); 1399 SAVE_HRTIME(ksi, ksio, wlastupdate); 1400 SAVE_HRTIME(ksi, ksio, rtime); 1401 SAVE_HRTIME(ksi, ksio, rlentime); 1402 SAVE_HRTIME(ksi, ksio, rlastupdate); 1403 SAVE_UINT32(ksi, ksio, wcnt); 1404 SAVE_UINT32(ksi, ksio, rcnt); 1405 } 1406 1407 static void 1408 save_timer(kstat_t *kp, ks_instance_t *ksi) 1409 { 1410 kstat_timer_t *ktimer = KSTAT_TIMER_PTR(kp); 1411 1412 SAVE_STRING(ksi, ktimer, name); 1413 SAVE_UINT64(ksi, ktimer, num_events); 1414 SAVE_HRTIME(ksi, ktimer, elapsed_time); 1415 SAVE_HRTIME(ksi, ktimer, min_time); 1416 SAVE_HRTIME(ksi, ktimer, max_time); 1417 SAVE_HRTIME(ksi, ktimer, start_time); 1418 SAVE_HRTIME(ksi, ktimer, stop_time); 1419 } 1420