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