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 }