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