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 (c) 2013, Joyent, Inc. All rights reserved.
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 /* Return zero if a selector did match */
84 static int g_matched = 1;
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 g_jflg = B_TRUE;
142 break;
143 case 'l':
144 g_pflg = g_lflg = B_TRUE;
145 break;
146 case 'p':
147 g_pflg = B_TRUE;
148 break;
149 case 'T':
150 switch (*optarg) {
151 case 'd':
152 g_timestamp_fmt = DDATE;
153 break;
154 case 'u':
155 g_timestamp_fmt = UDATE;
156 break;
157 default:
158 errflg = B_TRUE;
159 }
160 break;
161 case 'm':
162 nselflg = B_TRUE;
163 nselector->ks_module.pstr =
164 (char *)ks_safe_strdup(optarg);
165 break;
166 case 'i':
167 nselflg = B_TRUE;
168 nselector->ks_instance.pstr =
169 (char *)ks_safe_strdup(optarg);
170 break;
171 case 'n':
172 nselflg = B_TRUE;
173 nselector->ks_name.pstr =
174 (char *)ks_safe_strdup(optarg);
175 break;
176 case 's':
177 nselflg = B_TRUE;
178 nselector->ks_statistic.pstr =
179 (char *)ks_safe_strdup(optarg);
180 break;
181 case 'c':
182 g_ks_class.pstr =
183 (char *)ks_safe_strdup(optarg);
184 break;
185 default:
186 errflg = B_TRUE;
187 break;
188 }
189
190 if (g_qflg && (g_jflg || g_pflg)) {
191 (void) fprintf(stderr, gettext(
192 "-q and -lpj are mutually exclusive\n"));
193 errflg = B_TRUE;
194 }
195
196 if (errflg) {
197 usage();
198 exit(2);
199 }
200
201 argc -= optind;
202 argv += optind;
203
204 /*
205 * Consume the rest of the command line. Parsing the
206 * unnamed command line arguments.
207 */
208 while (argc--) {
209 errno = 0;
210 tmp = strtoul(*argv, &q, 10);
211 if (tmp == ULONG_MAX && errno == ERANGE) {
212 if (n == 0) {
213 (void) fprintf(stderr, gettext(
214 "Interval is too large\n"));
215 } else if (n == 1) {
335 ks_sleep_until(&start_n, period_n, infinite_cycles,
336 &caught_cont);
337 (void) kstat_chain_update(kc);
338 (void) putchar('\n');
339 }
340 }
341
342 (void) kstat_close(kc);
343
344 return (g_matched);
345 }
346
347 /*
348 * Print usage.
349 */
350 static void
351 usage(void)
352 {
353 (void) fprintf(stderr, gettext(
354 "Usage:\n"
355 "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
356 " [ -m module ] [ -i instance ] [ -n name ] [ -s statistic ]\n"
357 " [ interval [ count ] ]\n"
358 "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
359 " [ module[:instance[:name[:statistic]]] ... ]\n"
360 " [ interval [ count ] ]\n"));
361 }
362
363 /*
364 * Sort compare function.
365 */
366 static int
367 compare_instances(ks_instance_t *l_arg, ks_instance_t *r_arg)
368 {
369 int rval;
370
371 rval = strcasecmp(l_arg->ks_module, r_arg->ks_module);
372 if (rval == 0) {
373 if (l_arg->ks_instance == r_arg->ks_instance) {
374 return (strcasecmp(l_arg->ks_name, r_arg->ks_name));
375 } else if (l_arg->ks_instance < r_arg->ks_instance) {
376 return (-1);
377 } else {
378 return (1);
691 break;
692 case KSTAT_TYPE_IO:
693 save_io(kp, ksi);
694 break;
695 case KSTAT_TYPE_TIMER:
696 save_timer(kp, ksi);
697 break;
698 default:
699 assert(B_FALSE); /* Invalid type */
700 break;
701 }
702 }
703 }
704
705 /*
706 * Print the value of a name-value pair.
707 */
708 static void
709 ks_value_print(ks_nvpair_t *nvpair)
710 {
711 switch (nvpair->data_type) {
712 case KSTAT_DATA_CHAR:
713 (void) fprintf(stdout, "%s", nvpair->value.c);
714 break;
715 case KSTAT_DATA_INT32:
716 (void) fprintf(stdout, "%d", nvpair->value.i32);
717 break;
718 case KSTAT_DATA_UINT32:
719 (void) fprintf(stdout, "%u", nvpair->value.ui32);
720 break;
721 case KSTAT_DATA_INT64:
722 (void) fprintf(stdout, "%lld", nvpair->value.i64);
723 break;
724 case KSTAT_DATA_UINT64:
725 (void) fprintf(stdout, "%llu", nvpair->value.ui64);
726 break;
727 case KSTAT_DATA_STRING:
728 (void) fprintf(stdout, "%s", KSTAT_NAMED_STR_PTR(nvpair));
729 break;
730 case KSTAT_DATA_HRTIME:
731 if (nvpair->value.ui64 == 0)
732 (void) fprintf(stdout, "0");
733 else
734 (void) fprintf(stdout, "%.9f",
735 nvpair->value.ui64 / 1000000000.0);
736 break;
737 default:
738 assert(B_FALSE);
739 }
740 }
741
742 /*
743 * Print a single instance.
744 */
745 static void
746 ks_instance_print(ks_instance_t *ksi, ks_nvpair_t *nvpair)
747 {
748 if (g_headerflg) {
749 if (!g_pflg) {
750 (void) fprintf(stdout, DFLT_FMT,
751 ksi->ks_module, ksi->ks_instance,
752 ksi->ks_name, ksi->ks_class);
753 }
754 g_headerflg = B_FALSE;
755 }
756
757 if (g_pflg) {
781 ksi->ks_module, ksi->ks_instance,
782 ksi->ks_name, ksi->ks_class,
783 ksi->ks_type);
784
785 if (ksi->ks_snaptime == 0)
786 (void) fprintf(stdout, "\t\"snaptime\": 0,\n");
787 else
788 (void) fprintf(stdout, "\t\"snaptime\": %.9f,\n",
789 ksi->ks_snaptime / 1000000000.0);
790
791 (void) fprintf(stdout, "\t\"data\": {\n");
792
793 g_headerflg = B_FALSE;
794 }
795
796 (void) fprintf(stdout, KS_JFMT, nvpair->name);
797 if (nvpair->data_type == KSTAT_DATA_STRING) {
798 (void) putchar('\"');
799 ks_value_print(nvpair);
800 (void) putchar('\"');
801 } else {
802 ks_value_print(nvpair);
803 }
804 if (nvpair != list_tail(&ksi->ks_nvlist))
805 (void) putchar(',');
806
807 (void) putchar('\n');
808 }
809
810 /*
811 * Print all instances.
812 */
813 static void
814 ks_instances_print(void)
815 {
816 ks_selector_t *selector;
817 ks_instance_t *ksi, *ktmp;
818 ks_nvpair_t *nvpair, *ntmp;
819 void (*ks_print_fn)(ks_instance_t *, ks_nvpair_t *);
820 char *ks_number;
1371 SAVE_INT32_X(ksi, name, fault->type);
1372 (void) snprintf(name, sizeof (name), "fclass_%d", i);
1373 SAVE_INT32_X(ksi, name, fault->fclass);
1374 (void) snprintf(name, sizeof (name), "create_time_%d", i);
1375 SAVE_HRTIME_X(ksi, name, fault->create_time);
1376 (void) snprintf(name, sizeof (name), "msg_%d", i);
1377 SAVE_STRING_X(ksi, name, fault->msg);
1378 }
1379 }
1380 #endif
1381
1382 static void
1383 save_named(kstat_t *kp, ks_instance_t *ksi)
1384 {
1385 kstat_named_t *knp;
1386 int n;
1387
1388 for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) {
1389 switch (knp->data_type) {
1390 case KSTAT_DATA_CHAR:
1391 nvpair_insert(ksi, knp->name,
1392 (ks_value_t *)&knp->value, KSTAT_DATA_CHAR);
1393 break;
1394 case KSTAT_DATA_INT32:
1395 nvpair_insert(ksi, knp->name,
1396 (ks_value_t *)&knp->value, KSTAT_DATA_INT32);
1397 break;
1398 case KSTAT_DATA_UINT32:
1399 nvpair_insert(ksi, knp->name,
1400 (ks_value_t *)&knp->value, KSTAT_DATA_UINT32);
1401 break;
1402 case KSTAT_DATA_INT64:
1403 nvpair_insert(ksi, knp->name,
1404 (ks_value_t *)&knp->value, KSTAT_DATA_INT64);
1405 break;
1406 case KSTAT_DATA_UINT64:
1407 nvpair_insert(ksi, knp->name,
1408 (ks_value_t *)&knp->value, KSTAT_DATA_UINT64);
1409 break;
1410 case KSTAT_DATA_STRING:
1411 SAVE_STRING_X(ksi, knp->name, KSTAT_NAMED_STR_PTR(knp));
1412 break;
1413 default:
1414 assert(B_FALSE); /* Invalid data type */
1415 break;
1416 }
1417 }
1418 }
1419
1420 static void
1421 save_intr(kstat_t *kp, ks_instance_t *ksi)
1422 {
1423 kstat_intr_t *intr = KSTAT_INTR_PTR(kp);
1424 char *intr_names[] = {"hard", "soft", "watchdog", "spurious",
1425 "multiple_service"};
1426 int n;
1427
1428 for (n = 0; n < KSTAT_NUM_INTRS; n++)
1429 SAVE_UINT32_X(ksi, intr_names[n], intr->intrs[n]);
1430 }
1431
1432 static void
1433 save_io(kstat_t *kp, ks_instance_t *ksi)
1434 {
1435 kstat_io_t *ksio = KSTAT_IO_PTR(kp);
1436
1437 SAVE_UINT64(ksi, ksio, nread);
1438 SAVE_UINT64(ksi, ksio, nwritten);
1439 SAVE_UINT32(ksi, ksio, reads);
1440 SAVE_UINT32(ksi, ksio, writes);
1441 SAVE_HRTIME(ksi, ksio, wtime);
1442 SAVE_HRTIME(ksi, ksio, wlentime);
1443 SAVE_HRTIME(ksi, ksio, wlastupdate);
1444 SAVE_HRTIME(ksi, ksio, rtime);
1445 SAVE_HRTIME(ksi, ksio, rlentime);
1446 SAVE_HRTIME(ksi, ksio, rlastupdate);
1447 SAVE_UINT32(ksi, ksio, wcnt);
1448 SAVE_UINT32(ksi, ksio, rcnt);
1449 }
1450
1451 static void
1452 save_timer(kstat_t *kp, ks_instance_t *ksi)
1453 {
1454 kstat_timer_t *ktimer = KSTAT_TIMER_PTR(kp);
1455
1456 SAVE_STRING(ksi, ktimer, name);
1457 SAVE_UINT64(ksi, ktimer, num_events);
1458 SAVE_HRTIME(ksi, ktimer, elapsed_time);
1459 SAVE_HRTIME(ksi, ktimer, min_time);
1460 SAVE_HRTIME(ksi, ktimer, max_time);
1461 SAVE_HRTIME(ksi, ktimer, start_time);
1462 SAVE_HRTIME(ksi, ktimer, stop_time);
1463 }
|
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 (c) 2013, Joyent, Inc. All rights reserved.
27 * Copyright 2016 Garrett D'Amore
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 * -H b display hrtime as seconds since boot
44 * -H d display hrtime as date
45 * -H u display hrtime as UNIX seconds (since epoch)
46 * -H I display hrtime as ISO-8601 local time
47 * -H Z display hrtime as ISO-8601 UTC
48 * -H n display hrtime as nanoseconds (since epoch)
49 */
50
51 #include <assert.h>
52 #include <ctype.h>
53 #include <errno.h>
54 #include <kstat.h>
55 #include <langinfo.h>
56 #include <libgen.h>
57 #include <limits.h>
58 #include <locale.h>
59 #include <signal.h>
60 #include <stddef.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <strings.h>
65 #include <time.h>
66 #include <unistd.h>
67 #include <sys/list.h>
68 #include <sys/time.h>
69 #include <sys/types.h>
70
71 #include "kstat.h"
72 #include "statcommon.h"
73
74 char *cmdname = "kstat"; /* Name of this command */
75 int caught_cont = 0; /* Have caught a SIGCONT */
76
77 static uint_t g_timestamp_fmt = NODATE;
78 static uint_t g_hrtime_fmt = KS_HRFMT_DEFAULT;
79
80 /* Helper flag - header was printed already? */
81 static boolean_t g_headerflg;
82
83 /* Saved command line options */
84 static boolean_t g_cflg = B_FALSE;
85 static boolean_t g_jflg = B_FALSE;
86 static boolean_t g_lflg = B_FALSE;
87 static boolean_t g_pflg = B_FALSE;
88 static boolean_t g_qflg = B_FALSE;
89 static ks_pattern_t g_ks_class = {"*", 0};
90
91 /* Return zero if a selector did match */
92 static int g_matched = 1;
93
94 /* Sorted list of kstat instances */
95 static list_t instances_list;
96 static list_t selector_list;
97
98 static hrtime_t hrtime_origin;
99
100 int
101 main(int argc, char **argv)
102 {
103 ks_selector_t *nselector;
104 ks_selector_t *uselector;
105 kstat_ctl_t *kc;
106 hrtime_t start_n;
107 hrtime_t period_n;
108 boolean_t errflg = B_FALSE;
109 boolean_t nselflg = B_FALSE;
110 boolean_t uselflg = B_FALSE;
111 char *q;
112 int count = 1;
113 int infinite_cycles = 0;
114 int interval = 0;
115 int n = 0;
116 int c, m, tmp;
117
118 (void) setlocale(LC_ALL, "");
119 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
120 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
121 #endif
122 (void) textdomain(TEXT_DOMAIN);
123
124 /*
125 * Create the selector list and a dummy default selector to match
126 * everything. While we process the cmdline options we will add
127 * selectors to this list.
128 */
129 list_create(&selector_list, sizeof (ks_selector_t),
130 offsetof(ks_selector_t, ks_next));
131
132 nselector = new_selector();
133
134 /*
135 * Parse named command line arguments.
136 */
137 while ((c = getopt(argc, argv, "h?CqjlpT:m:i:n:s:c:H:")) != EOF)
138 switch (c) {
139 case 'h':
140 case '?':
141 usage();
142 exit(0);
143 break;
144 case 'C':
145 g_pflg = g_cflg = B_TRUE;
146 break;
147 case 'q':
148 g_qflg = B_TRUE;
149 break;
150 case 'j':
151 g_jflg = B_TRUE;
152 break;
153 case 'l':
154 g_pflg = g_lflg = B_TRUE;
155 break;
156 case 'p':
157 g_pflg = B_TRUE;
158 break;
159 case 'T':
160 if (strlen(optarg) != 1) {
161 errflg = B_TRUE;
162 }
163 switch (*optarg) {
164 case 'd':
165 g_timestamp_fmt = DDATE;
166 break;
167 case 'u':
168 g_timestamp_fmt = UDATE;
169 break;
170 default:
171 errflg = B_TRUE;
172 }
173 break;
174 case 'm':
175 nselflg = B_TRUE;
176 nselector->ks_module.pstr =
177 (char *)ks_safe_strdup(optarg);
178 break;
179 case 'i':
180 nselflg = B_TRUE;
181 nselector->ks_instance.pstr =
182 (char *)ks_safe_strdup(optarg);
183 break;
184 case 'n':
185 nselflg = B_TRUE;
186 nselector->ks_name.pstr =
187 (char *)ks_safe_strdup(optarg);
188 break;
189 case 's':
190 nselflg = B_TRUE;
191 nselector->ks_statistic.pstr =
192 (char *)ks_safe_strdup(optarg);
193 break;
194 case 'c':
195 g_ks_class.pstr =
196 (char *)ks_safe_strdup(optarg);
197 break;
198 case 'H':
199 switch (*optarg) {
200 case 'o':
201 case 'b':
202 case 'n':
203 case 'I':
204 case 'Z':
205 case 'd':
206 case 'u':
207 if (strlen(optarg) != 1) {
208 errflg = B_TRUE;
209 }
210 g_hrtime_fmt = *optarg;
211 break;
212 default:
213 errflg = B_TRUE;
214 break;
215 }
216 break;
217 default:
218 errflg = B_TRUE;
219 break;
220 }
221
222 if (g_qflg && (g_jflg || g_pflg)) {
223 (void) fprintf(stderr, gettext(
224 "-q and -lpj are mutually exclusive\n"));
225 errflg = B_TRUE;
226 }
227
228 switch (g_hrtime_fmt) {
229 case KS_HRFMT_DEFAULT:
230 case KS_HRFMT_BOOT:
231 break;
232 default: {
233 struct timespec ts;
234 if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
235 perror("clock_gettime(CLOCK_REALTIME)");
236 exit(3);
237 }
238 hrtime_origin = ts.tv_sec;
239 hrtime_origin *= 1000000000;
240 hrtime_origin += ts.tv_nsec;
241 hrtime_origin -= gethrtime();
242 }
243 }
244
245 if (errflg) {
246 usage();
247 exit(2);
248 }
249
250 argc -= optind;
251 argv += optind;
252
253 /*
254 * Consume the rest of the command line. Parsing the
255 * unnamed command line arguments.
256 */
257 while (argc--) {
258 errno = 0;
259 tmp = strtoul(*argv, &q, 10);
260 if (tmp == ULONG_MAX && errno == ERANGE) {
261 if (n == 0) {
262 (void) fprintf(stderr, gettext(
263 "Interval is too large\n"));
264 } else if (n == 1) {
384 ks_sleep_until(&start_n, period_n, infinite_cycles,
385 &caught_cont);
386 (void) kstat_chain_update(kc);
387 (void) putchar('\n');
388 }
389 }
390
391 (void) kstat_close(kc);
392
393 return (g_matched);
394 }
395
396 /*
397 * Print usage.
398 */
399 static void
400 usage(void)
401 {
402 (void) fprintf(stderr, gettext(
403 "Usage:\n"
404 "kstat [ -Cjlpq ] [ -T d|u ] [ -H d|n|u|I|Z ] [ -c class ]\n"
405 " [ -m module ] [ -i instance ] [ -n name ] [ -s statistic ]\n"
406 " [ interval [ count ] ]\n"
407 "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ] [ -H d|n|u|I|Z ]\n"
408 " [ module[:instance[:name[:statistic]]] ... ]\n"
409 " [ interval [ count ] ]\n"));
410 }
411
412 /*
413 * Sort compare function.
414 */
415 static int
416 compare_instances(ks_instance_t *l_arg, ks_instance_t *r_arg)
417 {
418 int rval;
419
420 rval = strcasecmp(l_arg->ks_module, r_arg->ks_module);
421 if (rval == 0) {
422 if (l_arg->ks_instance == r_arg->ks_instance) {
423 return (strcasecmp(l_arg->ks_name, r_arg->ks_name));
424 } else if (l_arg->ks_instance < r_arg->ks_instance) {
425 return (-1);
426 } else {
427 return (1);
740 break;
741 case KSTAT_TYPE_IO:
742 save_io(kp, ksi);
743 break;
744 case KSTAT_TYPE_TIMER:
745 save_timer(kp, ksi);
746 break;
747 default:
748 assert(B_FALSE); /* Invalid type */
749 break;
750 }
751 }
752 }
753
754 /*
755 * Print the value of a name-value pair.
756 */
757 static void
758 ks_value_print(ks_nvpair_t *nvpair)
759 {
760 char dstr[64];
761 char zstr[8];
762 time_t t;
763
764 switch (nvpair->data_type) {
765 case KSTAT_DATA_CHAR:
766 (void) fprintf(stdout, "%s", nvpair->value.c);
767 break;
768 case KSTAT_DATA_INT32:
769 (void) fprintf(stdout, "%d", nvpair->value.i32);
770 break;
771 case KSTAT_DATA_UINT32:
772 (void) fprintf(stdout, "%u", nvpair->value.ui32);
773 break;
774 case KSTAT_DATA_INT64:
775 (void) fprintf(stdout, "%lld", nvpair->value.i64);
776 break;
777 case KSTAT_DATA_UINT64:
778 (void) fprintf(stdout, "%llu", nvpair->value.ui64);
779 break;
780 case KSTAT_DATA_STRING:
781 (void) fprintf(stdout, "%s", KSTAT_NAMED_STR_PTR(nvpair));
782 break;
783 case KSTAT_DATA_TIME:
784 switch (g_hrtime_fmt) {
785 case KS_HRFMT_UNIX:
786 (void) fprintf(stdout, "%.9f",
787 (nvpair->value.t + hrtime_origin) / 1000000000.0);
788 break;
789 case KS_HRFMT_NANO:
790 (void) fprintf(stdout, "%llu",
791 (nvpair->value.t + hrtime_origin));
792 break;
793 case KS_HRFMT_DATE:
794 t = (time_t)
795 ((nvpair->value.t + hrtime_origin) / 1000000000);
796 (void) strftime(dstr,
797 sizeof (dstr), "%+", localtime(&t));
798 (void) fprintf(stdout, "%s", dstr);
799 break;
800 case KS_HRFMT_ZISO:
801 t = (time_t)
802 ((nvpair->value.t + hrtime_origin) / 1000000000);
803 (void) strftime(dstr, sizeof (dstr), "%FT%T",
804 gmtime(&t));
805 (void) fprintf(stdout, "%s.%06uZ", dstr,
806 (unsigned)(nvpair->value.t % 1000000000)/1000);
807 break;
808 case KS_HRFMT_ISO:
809 t = (time_t)
810 ((nvpair->value.t + hrtime_origin) / 1000000000);
811 (void) strftime(dstr, sizeof (dstr), "%FT%T",
812 localtime(&t));
813 (void) strftime(zstr, sizeof (zstr), "%z",
814 localtime(&t));
815 (void) fprintf(stdout, "%s.%06u%s", dstr,
816 (unsigned)(nvpair->value.t % 1000000000)/1000,
817 zstr);
818 break;
819 case KS_HRFMT_DEFAULT:
820 case KS_HRFMT_BOOT:
821 if (nvpair->value.ui64 == 0)
822 (void) fprintf(stdout, "0");
823 else
824 (void) fprintf(stdout, "%.9f",
825 nvpair->value.ui64 / 1000000000.0);
826 break;
827 default:
828 abort();
829 }
830 break;
831 default:
832 assert(B_FALSE);
833 }
834 }
835
836 /*
837 * Print a single instance.
838 */
839 static void
840 ks_instance_print(ks_instance_t *ksi, ks_nvpair_t *nvpair)
841 {
842 if (g_headerflg) {
843 if (!g_pflg) {
844 (void) fprintf(stdout, DFLT_FMT,
845 ksi->ks_module, ksi->ks_instance,
846 ksi->ks_name, ksi->ks_class);
847 }
848 g_headerflg = B_FALSE;
849 }
850
851 if (g_pflg) {
875 ksi->ks_module, ksi->ks_instance,
876 ksi->ks_name, ksi->ks_class,
877 ksi->ks_type);
878
879 if (ksi->ks_snaptime == 0)
880 (void) fprintf(stdout, "\t\"snaptime\": 0,\n");
881 else
882 (void) fprintf(stdout, "\t\"snaptime\": %.9f,\n",
883 ksi->ks_snaptime / 1000000000.0);
884
885 (void) fprintf(stdout, "\t\"data\": {\n");
886
887 g_headerflg = B_FALSE;
888 }
889
890 (void) fprintf(stdout, KS_JFMT, nvpair->name);
891 if (nvpair->data_type == KSTAT_DATA_STRING) {
892 (void) putchar('\"');
893 ks_value_print(nvpair);
894 (void) putchar('\"');
895 } else if (nvpair->data_type == KSTAT_DATA_TIME) {
896 switch (g_hrtime_fmt) {
897 case KS_HRFMT_ISO:
898 case KS_HRFMT_ZISO:
899 case KS_HRFMT_DATE:
900 (void) putchar('\"');
901 ks_value_print(nvpair);
902 (void) putchar('\"');
903 break;
904 default:
905 ks_value_print(nvpair);
906 }
907 } else {
908 ks_value_print(nvpair);
909 }
910 if (nvpair != list_tail(&ksi->ks_nvlist))
911 (void) putchar(',');
912
913 (void) putchar('\n');
914 }
915
916 /*
917 * Print all instances.
918 */
919 static void
920 ks_instances_print(void)
921 {
922 ks_selector_t *selector;
923 ks_instance_t *ksi, *ktmp;
924 ks_nvpair_t *nvpair, *ntmp;
925 void (*ks_print_fn)(ks_instance_t *, ks_nvpair_t *);
926 char *ks_number;
1477 SAVE_INT32_X(ksi, name, fault->type);
1478 (void) snprintf(name, sizeof (name), "fclass_%d", i);
1479 SAVE_INT32_X(ksi, name, fault->fclass);
1480 (void) snprintf(name, sizeof (name), "create_time_%d", i);
1481 SAVE_HRTIME_X(ksi, name, fault->create_time);
1482 (void) snprintf(name, sizeof (name), "msg_%d", i);
1483 SAVE_STRING_X(ksi, name, fault->msg);
1484 }
1485 }
1486 #endif
1487
1488 static void
1489 save_named(kstat_t *kp, ks_instance_t *ksi)
1490 {
1491 kstat_named_t *knp;
1492 int n;
1493
1494 for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) {
1495 switch (knp->data_type) {
1496 case KSTAT_DATA_CHAR:
1497 case KSTAT_DATA_INT32:
1498 case KSTAT_DATA_UINT32:
1499 case KSTAT_DATA_INT64:
1500 case KSTAT_DATA_UINT64:
1501 case KSTAT_DATA_TIME:
1502 nvpair_insert(ksi, knp->name,
1503 (ks_value_t *)&knp->value, knp->data_type);
1504 break;
1505 case KSTAT_DATA_STRING:
1506 SAVE_STRING_X(ksi, knp->name, KSTAT_NAMED_STR_PTR(knp));
1507 break;
1508 default:
1509 assert(B_FALSE); /* Invalid data type */
1510 break;
1511 }
1512 }
1513 }
1514
1515 static void
1516 save_intr(kstat_t *kp, ks_instance_t *ksi)
1517 {
1518 kstat_intr_t *intr = KSTAT_INTR_PTR(kp);
1519 char *intr_names[] = {"hard", "soft", "watchdog", "spurious",
1520 "multiple_service"};
1521 int n;
1522
1523 for (n = 0; n < KSTAT_NUM_INTRS; n++)
1524 SAVE_UINT32_X(ksi, intr_names[n], intr->intrs[n]);
1525 }
1526
1527 static void
1528 save_io(kstat_t *kp, ks_instance_t *ksi)
1529 {
1530 kstat_io_t *ksio = KSTAT_IO_PTR(kp);
1531
1532 SAVE_UINT64(ksi, ksio, nread);
1533 SAVE_UINT64(ksi, ksio, nwritten);
1534 SAVE_UINT32(ksi, ksio, reads);
1535 SAVE_UINT32(ksi, ksio, writes);
1536 SAVE_UINT64(ksi, ksio, wtime);
1537 SAVE_UINT64(ksi, ksio, wlentime);
1538 SAVE_HRTIME(ksi, ksio, wlastupdate);
1539 SAVE_UINT64(ksi, ksio, rtime);
1540 SAVE_UINT64(ksi, ksio, rlentime);
1541 SAVE_HRTIME(ksi, ksio, rlastupdate);
1542 SAVE_UINT32(ksi, ksio, wcnt);
1543 SAVE_UINT32(ksi, ksio, rcnt);
1544 }
1545
1546 static void
1547 save_timer(kstat_t *kp, ks_instance_t *ksi)
1548 {
1549 kstat_timer_t *ktimer = KSTAT_TIMER_PTR(kp);
1550
1551 SAVE_STRING(ksi, ktimer, name);
1552 SAVE_UINT64(ksi, ktimer, num_events);
1553 SAVE_UINT64(ksi, ktimer, elapsed_time);
1554 SAVE_UINT64(ksi, ktimer, min_time);
1555 SAVE_UINT64(ksi, ktimer, max_time);
1556 SAVE_HRTIME(ksi, ktimer, start_time);
1557 SAVE_HRTIME(ksi, ktimer, stop_time);
1558 }
|