1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2014 David Hoeppner. All rights reserved.
14 */
15
16 /*
17 * Display ZFS ARC statistics.
18 *
19 * Based on work by Neelakanth Nadgir and Mike Harsch.
20 */
21 #include <sys/list.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <kstat.h>
25 #include <libintl.h>
26 #include <limits.h>
27 #include <locale.h>
28 #include <poll.h>
29 #include <stddef.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <strings.h>
33
34 #include "statcommon.h"
35
36 char *cmdname = "arcstat"; /* Name of this command */
37 int caught_cont = 0; /* Have caught a SIGCONT */
38
39 /* Saved command line options */
40 static boolean_t g_fflg = B_FALSE; /* custom header fields */
41 static boolean_t g_oflg = B_FALSE; /* write output file */
42 static boolean_t g_rflg = B_FALSE; /* raw output */
43 static boolean_t g_vflg = B_FALSE; /* verbose help */
44 static boolean_t g_xflg = B_FALSE; /* extended header */
45
46 /* Time in seconds between snapshots */
47 int interval = 1;
48
49 static list_t fields_list;
50 static char *separator = " ";
51 static char *output_file = NULL;
52 static char *hdr;
53
54 typedef struct _arcstat_delta {
55 int64_t ad_hits;
56 int64_t ad_miss;
57 int64_t ad_read;
58 int64_t ad_hit_percent;
59 int64_t ad_miss_percent;
60 int64_t ad_dhit;
61 int64_t ad_dmis;
62 int64_t ad_dread;
63 int64_t ad_dh_percent;
64 int64_t ad_dm_percent;
65 int64_t ad_phit;
66 int64_t ad_pmis;
67 int64_t ad_pread;
68 int64_t ad_ph_percent;
69 int64_t ad_pm_percent;
70 int64_t ad_mhit;
71 int64_t ad_mmis;
72 int64_t ad_mread;
73 int64_t ad_mh_percent;
74 int64_t ad_mm_percent;
75 int64_t ad_arcsz;
76 int64_t ad_c;
77 int64_t ad_mfu;
78 int64_t ad_mru;
79 int64_t ad_mfug;
80 int64_t ad_mrug;
81 int64_t ad_eskip;
82 int64_t ad_rmiss;
83 int64_t ad_mtxmis;
84 } arcstat_delta_t;
85
86 typedef struct arcstat_snapshot {
87 kstat_t as_arcstats;
88 uint64_t as_hits;
89 uint64_t as_misses;
90 uint64_t as_demand_data_hits;
91 uint64_t as_demand_data_misses;
92 uint64_t as_demand_metadata_hits;
93 uint64_t as_demand_metadata_misses;
94 uint64_t as_prefetch_data_hits;
95 uint64_t as_prefetch_data_misses;
96 uint64_t as_prefetch_metadata_hits;
97 uint64_t as_prefetch_metadata_misses;
98 uint64_t as_size;
99 uint64_t as_c;
100 uint64_t as_mfu_hits;
101 uint64_t as_mru_hits;
102 uint64_t as_mru_ghost_hits;
103 uint64_t as_mfu_ghost_hits;
104 uint64_t as_evict_skip;
105 uint64_t as_recycle_miss;
106 uint64_t as_mutex_miss;
107 uint64_t as_l2_hits;
108 uint64_t as_l2_misses;
109 uint64_t as_l2_size;
110 uint64_t as_l2_read_bytes;
111 } arcstat_snapshot_t;
112
113 typedef struct arcstat_hdr_field {
114 list_node_t ahf_next;
115 char *ahf_name;
116 struct arcstat_field *ahf_desc;
117 } arcstat_hdr_field_t;
118
119 typedef enum field_type {
120 as_time,
121 as_hits,
122 as_miss,
123 as_read,
124 as_hit_percent,
125 as_miss_percent,
126 as_dhit,
127 as_dmis,
128 as_dread,
129 as_dh_percent,
130 as_dm_percent,
131 as_phit,
132 as_pmis,
133 as_pread,
134 as_ph_percent,
135 as_pm_percent,
136 as_mhit,
137 as_mmis,
138 as_mread,
139 as_mh_percent,
140 as_mm_percent,
141 as_arcsz,
142 as_c,
143 } field_type_t;
144
145 /* XXX */
146 struct arcstat_field {
147 char *af_name;
148 char *af_description;
149 int af_length;
150 int af_interval;
151 field_type_t af_type;
152 } arcstat_fields[] = {
153 { "time", "Time", 8, -1, as_time },
154 { "hits", "ARC reads per second", 4, 1000, as_hits },
155 { "miss", "ARC misses per second", 4, 1000, as_miss },
156 { "read", "Total ARC accesses per second", 4, 1000, as_read },
157 { "hit%", "ARC Hit percentage", 4, 100, as_hit_percent },
158 { "miss%", "ARC miss percentage", 5, 100, as_miss_percent },
159 { "dhit", "Demand Data hits per second", 4, 1000, as_dhit },
160 { "dmis", "Demand Data misses per second", 4, 1000, as_dmis },
161 { "dread", "Demand data accesses per second", 5, 1000, as_dread },
162 { "dh%", "Demand Data hit percentage", 3, 100, as_dh_percent },
163 { "dm%", "Demand Data miss percentage", 3, 100, as_dm_percent },
164 { "phit", "Prefetch hits per second", 4, 1000, as_phit },
165 { "pmis", "Prefetch misses per second", 4, 1000, as_pmis },
166 { "ph%", "Prefetch hits percentage", 3, 100, as_ph_percent },
167 { "pm%", "Prefetch miss percentage", 3, 100, as_pm_percent },
168 { "mhit", "Metadata hits per second", 4, 1000, as_mhit },
169 { "mmis", "Metadata misses per second", 4, 1000, as_mmis },
170 { "mread", "Metadata accesses per second", 4, 1000, as_mread },
171 { "mh%", "Metadata hit percentage", 3, 100, as_mh_percent },
172 { "mm%", "Metadata miss percentage", 3, 100, as_mm_percent },
173 { "arcsz", "ARC Size", 5, 1024, as_arcsz },
174 { "c", "ARC Target Size", 4, 1024, as_c },
175 { "mfu", "MFU List hits per second", 4, 1000 },
176 { "mru", "MRU List hits per second", 4, 1000 },
177 { "mfug", "MFU Ghost List hits per second", 4, 1000 },
178 { "mrug", "MRU Ghost List hits per second", 4, 1000 },
179 { "eskip", "evict_skip per second", 5, 1000 },
180 { "mtxmis", "mutex_miss per second", 6, 1000 },
181 { "rmis", "recycle_miss per second", 4, 1000 },
182 { "pread", "Prefetch accesses per second", 5, 1000 },
183 { "l2hits", "L2ARC hits per second", 6, 1000 },
184 { "l2miss", "L2ARC misses per second", 6, 1000 },
185 { "l2read", "Total L2ARC accesses per second", 6, 1000 },
186 { "l2hit%", "L2ARC access hit percentage", 6, 100 },
187 { "l2miss%", "L2ARC access miss percentage", 7, 100 },
188 { "l2size", "Size of the L2ARC", 6, 1024 },
189 { "l2bytes", "bytes read per second from the L2ARC", 7, 1024 },
190 { NULL, NULL, -1, -1 },
191 };
192
193 /*
194 * Print usage.
195 */
196 static void
197 usage(void)
198 {
199 (void) fprintf(stderr, gettext(
200 "Usage: arcstat [-hvxr] [-f fields] [-o file] [-s string] "
201 "[interval [count]]\n\n"));
202
203 if (g_vflg) {
204 int i = 0;
205
206 (void) fprintf(stderr, gettext(
207 "Field definitions are as follows:\n"));
208
209 for (;arcstat_fields[i].af_name != NULL; i++) {
210 (void) fprintf(stderr, "%11s : ",
211 arcstat_fields[i].af_name);
212 (void) fprintf(stderr, "%s\n", gettext(
213 arcstat_fields[i].af_description));
214 }
215 }
216 }
217
218 /*
219 * Print header.
220 */
221 static void
222 printhdr(int sig)
223 {
224 arcstat_hdr_field_t *hdr_field;
225
226 /*
227 * Reenable the signal.
228 */
229 if (sig)
230 (void) signal(SIGCONT, printhdr);
231 if (sig == SIGCONT)
232 caught_cont = 1;
233
234 /*
235 * Print fields in fields list for this header.
236 */
237 hdr_field = list_head(&fields_list);
238 while (hdr_field != NULL) {
239 if (g_rflg) {
240 printf("%s%s", hdr_field->ahf_name, separator);
241 } else {
242 printf("%*s%s", hdr_field->ahf_desc->af_length,
243 hdr_field->ahf_name, separator);
244 }
245
246 hdr_field = list_next(&fields_list, hdr_field);
247 }
248
249 (void) putchar('\n');
250 }
251
252 /*
253 * Pretty print values.
254 */
255 static void
256 printvals(arcstat_delta_t *delta)
257 {
258 arcstat_hdr_field_t *hdr_field;
259
260 #define ARCSTAT_PRINT_VALUE(field, delta, value) \
261 (void) printf("%*llu%s", field->ahf_desc->af_length, delta->ad_##value, separator);
262
263 /*
264 * Print values for fields.
265 */
266 hdr_field = list_head(&fields_list);
267 while (hdr_field != NULL) {
268 switch (hdr_field->ahf_desc->af_type) {
269 case as_time: {
270 time_t t = time(NULL);
271 char dstr[64];
272 char *fmt = "%H:%M:%S";
273 int len;
274
275 len = strftime(dstr, sizeof (dstr), fmt, localtime(&t));
276 if (len > 0)
277 (void) printf("%s%s", dstr, separator);
278 break;
279 };
280 case as_miss:
281 ARCSTAT_PRINT_VALUE(hdr_field, delta, miss);
282 break;
283 case as_read:
284 (void) printf("%*llu%s", hdr_field->ahf_desc->af_length, delta->ad_miss, separator);
285 break;
286 case as_hit_percent:
287 ARCSTAT_PRINT_VALUE(hdr_field, delta, hit_percent);
288 break;
289 case as_miss_percent:
290 ARCSTAT_PRINT_VALUE(hdr_field, delta, miss_percent);
291 break;
292 case as_dhit:
293 ARCSTAT_PRINT_VALUE(hdr_field, delta, dhit);
294 break;
295 case as_dmis:
296 ARCSTAT_PRINT_VALUE(hdr_field, delta, dmis);
297 break;
298 case as_dread:
299 ARCSTAT_PRINT_VALUE(hdr_field, delta, dread);
300 break;
301 case as_dh_percent:
302 ARCSTAT_PRINT_VALUE(hdr_field, delta, dh_percent);
303 break;
304 case as_dm_percent:
305 ARCSTAT_PRINT_VALUE(hdr_field, delta, dm_percent);
306 break;
307 case as_phit:
308 ARCSTAT_PRINT_VALUE(hdr_field, delta, phit);
309 break;
310 case as_pmis:
311 ARCSTAT_PRINT_VALUE(hdr_field, delta, pmis);
312 break;
313 case as_pread:
314 ARCSTAT_PRINT_VALUE(hdr_field, delta, pread);
315 break;
316 case as_ph_percent:
317 ARCSTAT_PRINT_VALUE(hdr_field, delta, ph_percent);
318 break;
319 case as_pm_percent:
320 ARCSTAT_PRINT_VALUE(hdr_field, delta, pm_percent);
321 break;
322 case as_mhit:
323 ARCSTAT_PRINT_VALUE(hdr_field, delta, mhit);
324 break;
325 case as_mmis:
326 ARCSTAT_PRINT_VALUE(hdr_field, delta, mmis);
327 break;
328 case as_mread:
329 ARCSTAT_PRINT_VALUE(hdr_field, delta, mread);
330 break;
331 case as_mh_percent:
332 ARCSTAT_PRINT_VALUE(hdr_field, delta, mh_percent);
333 break;
334 case as_mm_percent:
335 ARCSTAT_PRINT_VALUE(hdr_field, delta, mm_percent);
336 break;
337 case as_arcsz:
338 ARCSTAT_PRINT_VALUE(hdr_field, delta, arcsz);
339 break;
340 case as_c:
341 ARCSTAT_PRINT_VALUE(hdr_field, delta, c);
342 break;
343 default:
344 break;
345 }
346
347 // number_to_scaled_string
348
349 hdr_field = list_next(&fields_list, hdr_field);
350 }
351
352 (void) putchar('\n');
353 }
354
355 arcstat_snapshot_t *
356 arcstat_acquire_snapshot(kstat_ctl_t *kc)
357 {
358 arcstat_snapshot_t *snapshot;
359 kstat_named_t *knp;
360 kstat_t *ksp;
361
362 if ((ksp = kstat_lookup(kc, "zfs", 0, "arcstats")) == NULL)
363 return (NULL);
364
365 if (kstat_read(kc, ksp, NULL) == -1)
366 return (NULL);
367
368 snapshot = safe_alloc(sizeof (arcstat_snapshot_t));
369
370 /* XXX snapshot */
371 #define ARC_KSTAT_DATA_LOOKUP(name) \
372 knp = (kstat_named_t *)kstat_data_lookup(ksp, #name); \
373 if (knp == NULL) \
374 return (NULL); \
375 snapshot->as_##name = knp->value.ui64;
376
377 ARC_KSTAT_DATA_LOOKUP(hits);
378 ARC_KSTAT_DATA_LOOKUP(misses);
379 ARC_KSTAT_DATA_LOOKUP(demand_data_hits);
380 ARC_KSTAT_DATA_LOOKUP(demand_data_misses);
381 ARC_KSTAT_DATA_LOOKUP(demand_metadata_hits);
382 ARC_KSTAT_DATA_LOOKUP(demand_metadata_misses);
383 ARC_KSTAT_DATA_LOOKUP(prefetch_data_hits);
384 ARC_KSTAT_DATA_LOOKUP(prefetch_data_misses);
385 ARC_KSTAT_DATA_LOOKUP(prefetch_metadata_hits);
386 ARC_KSTAT_DATA_LOOKUP(prefetch_metadata_misses);
387 ARC_KSTAT_DATA_LOOKUP(size);
388 ARC_KSTAT_DATA_LOOKUP(c);
389 ARC_KSTAT_DATA_LOOKUP(mfu_hits);
390 ARC_KSTAT_DATA_LOOKUP(mru_hits);
391 ARC_KSTAT_DATA_LOOKUP(mru_ghost_hits);
392 ARC_KSTAT_DATA_LOOKUP(mfu_ghost_hits);
393 ARC_KSTAT_DATA_LOOKUP(evict_skip);
394 ARC_KSTAT_DATA_LOOKUP(recycle_miss);
395 ARC_KSTAT_DATA_LOOKUP(mutex_miss);
396 ARC_KSTAT_DATA_LOOKUP(l2_hits);
397 ARC_KSTAT_DATA_LOOKUP(l2_misses);
398 ARC_KSTAT_DATA_LOOKUP(l2_size);
399 ARC_KSTAT_DATA_LOOKUP(l2_read_bytes);
400
401 return (snapshot);
402 }
403
404 static void
405 arcstat_free_snapshot(arcstat_snapshot_t *old)
406 {
407 }
408
409 static void
410 arcstat_chain_update(kstat_ctl_t *kc)
411 {
412 int ret;
413
414 ret = kstat_chain_update(kc);
415 if (ret != 0) {
416 (void) printf("<State Changed>\n");
417 }
418 }
419
420 static void
421 free_field_list(list_t list)
422 {
423 arcstat_hdr_field_t *hdr_field;
424
425 hdr_field = list_head(&list);
426 while (hdr_field != NULL) {
427
428 hdr_field = list_next(&list, hdr_field);
429 }
430 }
431
432 static arcstat_delta_t *
433 arcstat_calculate_delta(arcstat_snapshot_t *old, arcstat_snapshot_t *new)
434 {
435 arcstat_delta_t *delta;
436
437 assert(old != NULL && new != NULL);
438
439 delta = safe_alloc(sizeof (arcstat_delta_t));
440
441 (void) memset(delta, 0, sizeof (arcstat_delta_t));
442
443 #define ARC_SNAPSHOT_DIFF(O, N, S) \
444 (N->as_##S - O->as_##S)
445
446 delta->ad_hits = ARC_SNAPSHOT_DIFF(old, new, hits) / interval;
447 delta->ad_miss = ARC_SNAPSHOT_DIFF(old, new, misses) / interval;
448
449 delta->ad_read = delta->ad_hits + delta->ad_miss;
450 if (delta->ad_read > 0) {
451 delta->ad_hit_percent = 100 * (delta->ad_hits / delta->ad_read);
452 delta->ad_miss_percent = 100 - delta->ad_hit_percent;
453 }
454
455 delta->ad_dhit = (ARC_SNAPSHOT_DIFF(old, new, demand_data_hits) +
456 ARC_SNAPSHOT_DIFF(old, new, demand_metadata_hits)) / interval;
457 delta->ad_dmis = (ARC_SNAPSHOT_DIFF(old, new, demand_data_misses) +
458 ARC_SNAPSHOT_DIFF(old, new, demand_metadata_misses)) / interval;
459
460 delta->ad_dread = delta->ad_dhit + delta->ad_dmis;
461 if (delta->ad_dread > 0) {
462 delta->ad_dh_percent = 100 * (delta->ad_dhit / delta->ad_dread);
463 delta->ad_dm_percent = 100 - delta->ad_dh_percent;
464 }
465
466 delta->ad_phit = (ARC_SNAPSHOT_DIFF(old, new, prefetch_data_hits) +
467 ARC_SNAPSHOT_DIFF(old, new, prefetch_metadata_hits)) / interval;
468 delta->ad_pmis = (ARC_SNAPSHOT_DIFF(old, new, prefetch_data_misses) +
469 ARC_SNAPSHOT_DIFF(old, new, prefetch_metadata_misses)) / interval;
470
471 delta->ad_pread = delta->ad_phit + delta->ad_pmis;
472 if (delta->ad_pread > 0) {
473 delta->ad_ph_percent = 100 * (delta->ad_phit / delta->ad_pread);
474 delta->ad_pm_percent = 100 - delta->ad_ph_percent;
475 }
476
477 delta->ad_mhit = (ARC_SNAPSHOT_DIFF(old, new, prefetch_metadata_hits) +
478 ARC_SNAPSHOT_DIFF(old, new, demand_metadata_hits)) / interval;
479 delta->ad_mmis = (ARC_SNAPSHOT_DIFF(old, new,
480 prefetch_metadata_misses) + ARC_SNAPSHOT_DIFF(old, new,
481 demand_metadata_misses)) / interval;
482
483 delta->ad_mread = delta->ad_mhit + delta->ad_mmis;
484 if (delta->ad_mread > 0) {
485 delta->ad_mh_percent = 100 * (delta->ad_mhit / delta->ad_mread);
486 delta->ad_mm_percent = 100 - delta->ad_mh_percent;
487 }
488
489 delta->ad_arcsz = new->as_size;
490 delta->ad_c = new->as_c;
491 delta->ad_mfu = ARC_SNAPSHOT_DIFF(old, new, mfu_hits) / interval;
492 delta->ad_mru = ARC_SNAPSHOT_DIFF(old, new, mru_hits) / interval;
493 delta->ad_mfug = ARC_SNAPSHOT_DIFF(old, new, mfu_ghost_hits) /
494 interval;
495 delta->ad_mrug = ARC_SNAPSHOT_DIFF(old, new, mru_ghost_hits) /
496 interval;
497 delta->ad_eskip = ARC_SNAPSHOT_DIFF(old, new, evict_skip) / interval;
498 delta->ad_rmiss = ARC_SNAPSHOT_DIFF(old, new, recycle_miss) / interval;
499 delta->ad_mtxmis = ARC_SNAPSHOT_DIFF(old, new, mutex_miss) / interval;
500
501 /* XXX L2 cache */
502
503 return (delta);
504 }
505
506 int
507 main(int argc, char **argv)
508 {
509 int c;
510 int i = 0;
511 int iter = 1;
512 char *endptr;
513 int infinite_cycles = 0;
514 kstat_ctl_t *kc;
515 hrtime_t start_n;
516 hrtime_t period_n;
517 list_t invalid_list;
518 list_t incompt_list;
519 boolean_t l2exist = B_FALSE;
520 arcstat_hdr_field_t *hdr_field;
521 arcstat_snapshot_t *old = NULL;
522 arcstat_snapshot_t *new = NULL;
523
524
525 (void) setlocale(LC_ALL, "");
526 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
527 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
528 #endif
529 (void) textdomain(TEXT_DOMAIN);
530
531 /*
532 * Parse command line arguments.
533 */
534 while ((c = getopt(argc, argv, "h?f:o:rs:vx")) != EOF) {
535 switch (c) {
536 case 'h':
537 case '?':
538 usage();
539 exit(0);
540 break;
541 case 'f':
542 g_fflg = B_TRUE;
543 hdr = safe_strdup(optarg);
544 break;
545 case 'o':
546 g_oflg = B_TRUE;
547 output_file = (char *)optarg;
548 case 'r':
549 g_rflg = B_TRUE;
550 break;
551 case 's':
552 separator = (char *)optarg;
553 break;
554 case 'v':
555 g_vflg = B_TRUE;
556 usage();
557 exit(0);
558 break;
559 case 'x':
560 g_xflg = B_TRUE;
561 break;
562 default:
563 break;
564 }
565 }
566
567 /*
568 * Select the standard, extended or user supplied header fields.
569 */
570 if (!g_fflg) {
571 if (g_xflg) {
572 hdr = safe_strdup("time,mfu,mru,mfug,mrug,eskip,mtxmis,rmis,dread,pread,read");
573 } else {
574 hdr = safe_strdup("time,read,miss,miss%,dmis,dm%,pmis,pm%,mmis,mm%,arcsz,c");
575 }
576 }
577
578 /*
579 * Interval and count.
580 */
581 if (argc > optind) {
582 interval = (int)strtol(argv[optind], &endptr, 10);
583 if (*endptr != NULL)
584 usage();
585 period_n = (hrtime_t)interval * NANOSEC;
586 if (argc > optind + 1) {
587 iter = (unsigned int)strtoul
588 (argv[optind + 1], &endptr, 10);
589 if (*endptr != NULL || iter < 0)
590 usage();
591 if (iter == 0)
592 return (0); /* XXX */
593 } else {
594 infinite_cycles = 1;
595 }
596 }
597
598 /*
599 * Need to know if there is a L2 cache.
600 */
601 kc = open_kstat();
602
603 /* XXX L2 cache */
604
605 /* Valid field names */
606 list_create(&fields_list, sizeof (arcstat_hdr_field_t),
607 offsetof(arcstat_hdr_field_t, ahf_next));
608
609 /* Invalid field names */
610 list_create(&invalid_list, sizeof (arcstat_hdr_field_t),
611 offsetof(arcstat_hdr_field_t, ahf_next));
612
613 /* Invalid field names if no L2 ARC */
614 list_create(&incompt_list, sizeof (arcstat_hdr_field_t),
615 offsetof(arcstat_hdr_field_t, ahf_next));
616
617 while ((endptr = (char *)strsep(&hdr, ",")) != NULL) {
618 boolean_t found_field = B_FALSE;
619 int i = 0;
620
621 for (; arcstat_fields[i].af_name != NULL; i++) {
622 if (strcmp(arcstat_fields[i].af_name, endptr) == 0) {
623 found_field = B_TRUE;
624 break;
625 }
626 }
627
628 /*
629 * Allocate a new header field and link it to the fields table.
630 */
631 hdr_field = safe_alloc(sizeof (arcstat_hdr_field_t));
632 hdr_field->ahf_name = safe_strdup(endptr);
633 hdr_field->ahf_desc = &arcstat_fields[i];
634
635 list_link_init(&hdr_field->ahf_next);
636
637 /*
638 * Add valid fields to fields_list or to the list of invalid fields.
639 */
640 if (found_field) {
641 list_insert_tail(&fields_list, hdr_field);
642 } else {
643 list_insert_tail(&invalid_list, hdr_field);
644 }
645 }
646
647 /*
648 * User supplied an invalid field per cmdline.
649 */
650 if (!list_is_empty(&invalid_list)) {
651 (void) fprintf(stderr, "%s -- ", gettext(
652 "Invalid column definition!"));
653
654 hdr_field = list_head(&invalid_list);
655 while (hdr_field != NULL) {
656 (void) fprintf(stderr, "%s ", hdr_field->ahf_name);
657
658 hdr_field = list_next(&invalid_list, hdr_field);
659 }
660
661 (void) fprintf(stderr, "\n\n");
662
663 //free_field_list(invalid_list);
664
665 usage();
666 exit(2);
667 }
668
669 /*
670 * User supplied an L2 cache field, but we have no L2 cache.
671 */
672 if (!list_is_empty(&incompt_list)) {
673 (void) fprintf(stderr, "%s -- ", gettext(
674 "Incompatible field specified!"));
675
676 hdr_field = list_head(&incompt_list);
677 while (hdr_field != NULL) {
678 (void) fprintf(stderr, "%s ", hdr_field->ahf_name);
679
680 hdr_field = list_next(&incompt_list, hdr_field);
681 }
682
683 (void) fprintf(stderr, "\n\n");
684
685 usage();
686 exit(2);
687 }
688
689 /* We should have at least one valid field */
690 assert(!list_is_empty(&fields_list));
691
692 /*
693 * If we need write to a file, try to open it.
694 */
695 if (g_oflg) {
696
697 }
698
699 // (void) sigset(SIGCONT, printhdr);
700 /* Set up handler for SIGCONT */
701 if (signal(SIGCONT, cont_handler) == SIG_ERR)
702 fail(1, "signal failed");
703
704 start_n = gethrtime();
705
706 new = arcstat_acquire_snapshot(kc);
707 while (infinite_cycles || iter > 0) {
708 arcstat_delta_t *delta;
709
710 arcstat_free_snapshot(old);
711 old = new;
712 new = arcstat_acquire_snapshot(kc);
713
714 arcstat_chain_update(kc);
715
716 /* XXX */
717 if (i % 20 == 0)
718 printhdr(0);
719 i++;
720
721 delta = arcstat_calculate_delta(old, new);
722 printvals(delta);
723
724 if (!infinite_cycles && --iter < 1)
725 break;
726
727 sleep_until(&start_n, period_n, infinite_cycles, &caught_cont);
728 }
729
730 (void) kstat_close(kc);
731
732 arcstat_free_snapshot(old);
733 arcstat_free_snapshot(new);
734
735 free(hdr);
736
737 return (0);
738 }
739
740 #define NUMBER_WIDTH 64
741 typedef char numbuf_t[NUMBER_WIDTH];
742
743 /* Copied from du.c */
744 static char *
745 number_to_scaled_string(
746 numbuf_t buf, /* put the result here */
747 unsigned long long number, /* convert this number */
748 unsigned long long unit_from, /* number of byes per input unit */
749 unsigned long long scale) /* 1024 (-h) or 1000 (-H) */
750 {
751 unsigned long long save = 0;
752 char *M = "KMGTPE"; /* Measurement: kilo, mega, giga, tera, peta, exa */
753 char *uom = M; /* unit of measurement, initially 'K' (=M[0]) */
754
755 if ((long long)number == (long long) -1) {
756 (void) strcpy(buf, "-1");
757 return (buf);
758 }
759
760 /*
761 * Convert number from unit_from to given scale (1024 or 1000)
762 * This means multiply number with unit_from and divide by scale.
763 * if number is large enough, we first divide and then multiply
764 * to avoid an overflow (large enough here means 100 (rather arbitrary
765 * value) times scale in order to reduce rounding errors)
766 * otherwise, we first multiply and then divide to avoid an underflow.
767 */
768 if (number >= 100L * scale) {
769 number = number / scale;
770 number = number * unit_from;
771 } else {
772 number = number * unit_from;
773 number = number / scale;
774 }
775
776 /*
777 * Now we have number as a count of scale units.
778 * Stop scaling when we reached exa bytes, then something is
779 * probably wrong with our number.
780 */
781 while ((number >= scale) && (*uom != 'E')) {
782 uom++; /* Next unit of measurement */
783 save = number;
784 number = (number + (scale / 2)) / scale;
785 }
786
787 /* Check if we should output a decimal place after the point */
788 if (save && ((save / scale) < 10)) {
789 /* sprintf() will round for us */
790 float fnum = (float)save / scale;
791 (void) sprintf(buf, "%.1f%c", fnum, *uom);
792 } else {
793 (void) sprintf(buf, "%llu%c", number, *uom);
794 }
795 return (buf);
796 }