1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Slabinfo: Tool to get reports about slabs 4 * 5 * (C) 2007 sgi, Christoph Lameter 6 * (C) 2011 Linux Foundation, Christoph Lameter 7 * 8 * Compile with: 9 * 10 * gcc -o slabinfo slabinfo.c 11 */ 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <sys/types.h> 15 #include <dirent.h> 16 #include <strings.h> 17 #include <string.h> 18 #include <unistd.h> 19 #include <stdarg.h> 20 #include <getopt.h> 21 #include <regex.h> 22 #include <errno.h> 23 24 #define MAX_SLABS 2000 25 #define MAX_ALIASES 500 26 #define MAX_NODES 1024 27 28 struct slabinfo { 29 char *name; 30 int alias; 31 int refs; 32 int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu; 33 unsigned int hwcache_align, object_size, objs_per_slab; 34 unsigned int sanity_checks, slab_size, store_user, trace; 35 int order, poison, reclaim_account, red_zone; 36 unsigned long partial, objects, slabs, objects_partial, objects_total; 37 unsigned long alloc_fastpath, alloc_slowpath; 38 unsigned long free_fastpath, free_slowpath; 39 unsigned long free_frozen, free_add_partial, free_remove_partial; 40 unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill; 41 unsigned long cpuslab_flush, deactivate_full, deactivate_empty; 42 unsigned long deactivate_to_head, deactivate_to_tail; 43 unsigned long deactivate_remote_frees, order_fallback; 44 unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail; 45 unsigned long alloc_node_mismatch, deactivate_bypass; 46 unsigned long cpu_partial_alloc, cpu_partial_free; 47 int numa[MAX_NODES]; 48 int numa_partial[MAX_NODES]; 49 } slabinfo[MAX_SLABS]; 50 51 struct aliasinfo { 52 char *name; 53 char *ref; 54 struct slabinfo *slab; 55 } aliasinfo[MAX_ALIASES]; 56 57 int slabs; 58 int actual_slabs; 59 int aliases; 60 int alias_targets; 61 int highest_node; 62 63 char buffer[4096]; 64 65 int show_empty; 66 int show_report; 67 int show_alias; 68 int show_slab; 69 int skip_zero = 1; 70 int show_numa; 71 int show_track; 72 int show_first_alias; 73 int validate; 74 int shrink; 75 int show_inverted; 76 int show_single_ref; 77 int show_totals; 78 int sort_size; 79 int sort_active; 80 int set_debug; 81 int show_ops; 82 int sort_partial; 83 int show_activity; 84 int output_lines = -1; 85 int sort_loss; 86 int extended_totals; 87 int show_bytes; 88 int unreclaim_only; 89 90 /* Debug options */ 91 int sanity; 92 int redzone; 93 int poison; 94 int tracking; 95 int tracing; 96 97 int page_size; 98 99 regex_t pattern; 100 101 static void fatal(const char *x, ...) 102 { 103 va_list ap; 104 105 va_start(ap, x); 106 vfprintf(stderr, x, ap); 107 va_end(ap); 108 exit(EXIT_FAILURE); 109 } 110 111 static void usage(void) 112 { 113 printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n" 114 "slabinfo [-aABDefhilLnoPrsStTUvXz1] [N=K] [-dafzput] [slab-regexp]\n" 115 "-a|--aliases Show aliases\n" 116 "-A|--activity Most active slabs first\n" 117 "-B|--Bytes Show size in bytes\n" 118 "-D|--display-active Switch line format to activity\n" 119 "-e|--empty Show empty slabs\n" 120 "-f|--first-alias Show first alias\n" 121 "-h|--help Show usage information\n" 122 "-i|--inverted Inverted list\n" 123 "-l|--slabs Show slabs\n" 124 "-L|--Loss Sort by loss\n" 125 "-n|--numa Show NUMA information\n" 126 "-N|--lines=K Show the first K slabs\n" 127 "-o|--ops Show kmem_cache_ops\n" 128 "-P|--partial Sort by number of partial slabs\n" 129 "-r|--report Detailed report on single slabs\n" 130 "-s|--shrink Shrink slabs\n" 131 "-S|--Size Sort by size\n" 132 "-t|--tracking Show alloc/free information\n" 133 "-T|--Totals Show summary information\n" 134 "-U|--Unreclaim Show unreclaimable slabs only\n" 135 "-v|--validate Validate slabs\n" 136 "-X|--Xtotals Show extended summary information\n" 137 "-z|--zero Include empty slabs\n" 138 "-1|--1ref Single reference\n" 139 140 "\n" 141 "-d | --debug Switch off all debug options\n" 142 "-da | --debug=a Switch on all debug options (--debug=FZPU)\n" 143 144 "\n" 145 "-d[afzput] | --debug=[afzput]\n" 146 " f | F Sanity Checks (SLAB_CONSISTENCY_CHECKS)\n" 147 " z | Z Redzoning\n" 148 " p | P Poisoning\n" 149 " u | U Tracking\n" 150 " t | T Tracing\n" 151 152 "\nSorting options (--Loss, --Size, --Partial) are mutually exclusive\n" 153 ); 154 } 155 156 static unsigned long read_obj(const char *name) 157 { 158 size_t len; 159 FILE *f = fopen(name, "r"); 160 161 if (!f) { 162 buffer[0] = 0; 163 if (errno == EACCES) 164 fatal("%s, Try using superuser\n", strerror(errno)); 165 } else { 166 if (!fgets(buffer, sizeof(buffer), f)) 167 buffer[0] = 0; 168 fclose(f); 169 len = strlen(buffer); 170 171 if (len > 0 && buffer[len - 1] == '\n') 172 buffer[len - 1] = 0; 173 } 174 return strlen(buffer); 175 } 176 177 178 /* 179 * Get the contents of an attribute 180 */ 181 static unsigned long get_obj(const char *name) 182 { 183 if (!read_obj(name)) 184 return 0; 185 186 return atol(buffer); 187 } 188 189 static unsigned long get_obj_and_str(const char *name, char **x) 190 { 191 unsigned long result = 0; 192 char *p; 193 194 *x = NULL; 195 196 if (!read_obj(name)) { 197 x = NULL; 198 return 0; 199 } 200 result = strtoul(buffer, &p, 10); 201 while (*p == ' ') 202 p++; 203 if (*p) 204 *x = strdup(p); 205 return result; 206 } 207 208 static void set_obj(struct slabinfo *s, const char *name, int n) 209 { 210 char x[100]; 211 FILE *f; 212 213 snprintf(x, 100, "%s/%s", s->name, name); 214 f = fopen(x, "w"); 215 if (!f) 216 fatal("Cannot write to %s\n", x); 217 218 fprintf(f, "%d\n", n); 219 fclose(f); 220 } 221 222 static unsigned long read_slab_obj(struct slabinfo *s, const char *name) 223 { 224 char x[100]; 225 FILE *f; 226 size_t l; 227 228 snprintf(x, 100, "%s/%s", s->name, name); 229 f = fopen(x, "r"); 230 if (!f) { 231 buffer[0] = 0; 232 l = 0; 233 } else { 234 l = fread(buffer, 1, sizeof(buffer), f); 235 buffer[l] = 0; 236 fclose(f); 237 } 238 return l; 239 } 240 241 static unsigned long read_debug_slab_obj(struct slabinfo *s, const char *name) 242 { 243 char x[128]; 244 FILE *f; 245 size_t l; 246 247 snprintf(x, 128, "/sys/kernel/debug/slab/%s/%s", s->name, name); 248 f = fopen(x, "r"); 249 if (!f) { 250 buffer[0] = 0; 251 l = 0; 252 } else { 253 l = fread(buffer, 1, sizeof(buffer), f); 254 buffer[l] = 0; 255 fclose(f); 256 } 257 return l; 258 } 259 260 /* 261 * Put a size string together 262 */ 263 static int store_size(char *buffer, unsigned long value) 264 { 265 unsigned long divisor = 1; 266 char trailer = 0; 267 int n; 268 269 if (!show_bytes) { 270 if (value > 1000000000UL) { 271 divisor = 100000000UL; 272 trailer = 'G'; 273 } else if (value > 1000000UL) { 274 divisor = 100000UL; 275 trailer = 'M'; 276 } else if (value > 1000UL) { 277 divisor = 100; 278 trailer = 'K'; 279 } 280 } 281 282 value /= divisor; 283 n = sprintf(buffer, "%ld",value); 284 if (trailer) { 285 buffer[n] = trailer; 286 n++; 287 buffer[n] = 0; 288 } 289 if (divisor != 1) { 290 memmove(buffer + n - 2, buffer + n - 3, 4); 291 buffer[n-2] = '.'; 292 n++; 293 } 294 return n; 295 } 296 297 static void decode_numa_list(int *numa, char *t) 298 { 299 int node; 300 int nr; 301 302 memset(numa, 0, MAX_NODES * sizeof(int)); 303 304 if (!t) 305 return; 306 307 while (*t == 'N') { 308 t++; 309 node = strtoul(t, &t, 10); 310 if (*t == '=') { 311 t++; 312 nr = strtoul(t, &t, 10); 313 numa[node] = nr; 314 if (node > highest_node) 315 highest_node = node; 316 } 317 while (*t == ' ') 318 t++; 319 } 320 } 321 322 static void slab_validate(struct slabinfo *s) 323 { 324 if (strcmp(s->name, "*") == 0) 325 return; 326 327 set_obj(s, "validate", 1); 328 } 329 330 static void slab_shrink(struct slabinfo *s) 331 { 332 if (strcmp(s->name, "*") == 0) 333 return; 334 335 set_obj(s, "shrink", 1); 336 } 337 338 int line = 0; 339 340 static void first_line(void) 341 { 342 if (show_activity) 343 printf("Name Objects Alloc Free" 344 " %%Fast Fallb O CmpX UL\n"); 345 else 346 printf("Name Objects Objsize %s " 347 "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n", 348 sort_loss ? " Loss" : "Space"); 349 } 350 351 /* 352 * Find the shortest alias of a slab 353 */ 354 static struct aliasinfo *find_one_alias(struct slabinfo *find) 355 { 356 struct aliasinfo *a; 357 struct aliasinfo *best = NULL; 358 359 for(a = aliasinfo;a < aliasinfo + aliases; a++) { 360 if (a->slab == find && 361 (!best || strlen(best->name) < strlen(a->name))) { 362 best = a; 363 if (strncmp(a->name,"kmall", 5) == 0) 364 return best; 365 } 366 } 367 return best; 368 } 369 370 static unsigned long slab_size(struct slabinfo *s) 371 { 372 return s->slabs * (page_size << s->order); 373 } 374 375 static unsigned long slab_activity(struct slabinfo *s) 376 { 377 return s->alloc_fastpath + s->free_fastpath + 378 s->alloc_slowpath + s->free_slowpath; 379 } 380 381 static unsigned long slab_waste(struct slabinfo *s) 382 { 383 return slab_size(s) - s->objects * s->object_size; 384 } 385 386 static void slab_numa(struct slabinfo *s, int mode) 387 { 388 int node; 389 390 if (strcmp(s->name, "*") == 0) 391 return; 392 393 if (!highest_node) { 394 printf("\n%s: No NUMA information available.\n", s->name); 395 return; 396 } 397 398 if (skip_zero && !s->slabs) 399 return; 400 401 if (!line) { 402 printf("\n%-21s:", mode ? "NUMA nodes" : "Slab"); 403 for(node = 0; node <= highest_node; node++) 404 printf(" %4d", node); 405 printf("\n----------------------"); 406 for(node = 0; node <= highest_node; node++) 407 printf("-----"); 408 printf("\n"); 409 } 410 printf("%-21s ", mode ? "All slabs" : s->name); 411 for(node = 0; node <= highest_node; node++) { 412 char b[20]; 413 414 store_size(b, s->numa[node]); 415 printf(" %4s", b); 416 } 417 printf("\n"); 418 if (mode) { 419 printf("%-21s ", "Partial slabs"); 420 for(node = 0; node <= highest_node; node++) { 421 char b[20]; 422 423 store_size(b, s->numa_partial[node]); 424 printf(" %4s", b); 425 } 426 printf("\n"); 427 } 428 line++; 429 } 430 431 static void show_tracking(struct slabinfo *s) 432 { 433 printf("\n%s: Kernel object allocation\n", s->name); 434 printf("-----------------------------------------------------------------------\n"); 435 if (read_debug_slab_obj(s, "alloc_traces")) 436 printf("%s", buffer); 437 else if (read_slab_obj(s, "alloc_calls")) 438 printf("%s", buffer); 439 else 440 printf("No Data\n"); 441 442 printf("\n%s: Kernel object freeing\n", s->name); 443 printf("------------------------------------------------------------------------\n"); 444 if (read_debug_slab_obj(s, "free_traces")) 445 printf("%s", buffer); 446 else if (read_slab_obj(s, "free_calls")) 447 printf("%s", buffer); 448 else 449 printf("No Data\n"); 450 451 } 452 453 static void ops(struct slabinfo *s) 454 { 455 if (strcmp(s->name, "*") == 0) 456 return; 457 458 if (read_slab_obj(s, "ops")) { 459 printf("\n%s: kmem_cache operations\n", s->name); 460 printf("--------------------------------------------\n"); 461 printf("%s", buffer); 462 } else 463 printf("\n%s has no kmem_cache operations\n", s->name); 464 } 465 466 static const char *onoff(int x) 467 { 468 if (x) 469 return "On "; 470 return "Off"; 471 } 472 473 static void slab_stats(struct slabinfo *s) 474 { 475 unsigned long total_alloc; 476 unsigned long total_free; 477 unsigned long total; 478 479 if (!s->alloc_slab) 480 return; 481 482 total_alloc = s->alloc_fastpath + s->alloc_slowpath; 483 total_free = s->free_fastpath + s->free_slowpath; 484 485 if (!total_alloc) 486 return; 487 488 printf("\n"); 489 printf("Slab Perf Counter Alloc Free %%Al %%Fr\n"); 490 printf("--------------------------------------------------\n"); 491 printf("Fastpath %8lu %8lu %3lu %3lu\n", 492 s->alloc_fastpath, s->free_fastpath, 493 s->alloc_fastpath * 100 / total_alloc, 494 total_free ? s->free_fastpath * 100 / total_free : 0); 495 printf("Slowpath %8lu %8lu %3lu %3lu\n", 496 total_alloc - s->alloc_fastpath, s->free_slowpath, 497 (total_alloc - s->alloc_fastpath) * 100 / total_alloc, 498 total_free ? s->free_slowpath * 100 / total_free : 0); 499 printf("Page Alloc %8lu %8lu %3lu %3lu\n", 500 s->alloc_slab, s->free_slab, 501 s->alloc_slab * 100 / total_alloc, 502 total_free ? s->free_slab * 100 / total_free : 0); 503 printf("Add partial %8lu %8lu %3lu %3lu\n", 504 s->deactivate_to_head + s->deactivate_to_tail, 505 s->free_add_partial, 506 (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc, 507 total_free ? s->free_add_partial * 100 / total_free : 0); 508 printf("Remove partial %8lu %8lu %3lu %3lu\n", 509 s->alloc_from_partial, s->free_remove_partial, 510 s->alloc_from_partial * 100 / total_alloc, 511 total_free ? s->free_remove_partial * 100 / total_free : 0); 512 513 printf("Cpu partial list %8lu %8lu %3lu %3lu\n", 514 s->cpu_partial_alloc, s->cpu_partial_free, 515 s->cpu_partial_alloc * 100 / total_alloc, 516 total_free ? s->cpu_partial_free * 100 / total_free : 0); 517 518 printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n", 519 s->deactivate_remote_frees, s->free_frozen, 520 s->deactivate_remote_frees * 100 / total_alloc, 521 total_free ? s->free_frozen * 100 / total_free : 0); 522 523 printf("Total %8lu %8lu\n\n", total_alloc, total_free); 524 525 if (s->cpuslab_flush) 526 printf("Flushes %8lu\n", s->cpuslab_flush); 527 528 total = s->deactivate_full + s->deactivate_empty + 529 s->deactivate_to_head + s->deactivate_to_tail + s->deactivate_bypass; 530 531 if (total) { 532 printf("\nSlab Deactivation Occurrences %%\n"); 533 printf("-------------------------------------------------\n"); 534 printf("Slab full %7lu %3lu%%\n", 535 s->deactivate_full, (s->deactivate_full * 100) / total); 536 printf("Slab empty %7lu %3lu%%\n", 537 s->deactivate_empty, (s->deactivate_empty * 100) / total); 538 printf("Moved to head of partial list %7lu %3lu%%\n", 539 s->deactivate_to_head, (s->deactivate_to_head * 100) / total); 540 printf("Moved to tail of partial list %7lu %3lu%%\n", 541 s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total); 542 printf("Deactivation bypass %7lu %3lu%%\n", 543 s->deactivate_bypass, (s->deactivate_bypass * 100) / total); 544 printf("Refilled from foreign frees %7lu %3lu%%\n", 545 s->alloc_refill, (s->alloc_refill * 100) / total); 546 printf("Node mismatch %7lu %3lu%%\n", 547 s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total); 548 } 549 550 if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail) { 551 printf("\nCmpxchg_double Looping\n------------------------\n"); 552 printf("Locked Cmpxchg Double redos %lu\nUnlocked Cmpxchg Double redos %lu\n", 553 s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail); 554 } 555 } 556 557 static void report(struct slabinfo *s) 558 { 559 if (strcmp(s->name, "*") == 0) 560 return; 561 562 printf("\nSlabcache: %-15s Aliases: %2d Order : %2d Objects: %lu\n", 563 s->name, s->aliases, s->order, s->objects); 564 if (s->hwcache_align) 565 printf("** Hardware cacheline aligned\n"); 566 if (s->cache_dma) 567 printf("** Memory is allocated in a special DMA zone\n"); 568 if (s->destroy_by_rcu) 569 printf("** Slabs are destroyed via RCU\n"); 570 if (s->reclaim_account) 571 printf("** Reclaim accounting active\n"); 572 573 printf("\nSizes (bytes) Slabs Debug Memory\n"); 574 printf("------------------------------------------------------------------------\n"); 575 printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n", 576 s->object_size, s->slabs, onoff(s->sanity_checks), 577 s->slabs * (page_size << s->order)); 578 printf("SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld\n", 579 s->slab_size, s->slabs - s->partial - s->cpu_slabs, 580 onoff(s->red_zone), s->objects * s->object_size); 581 printf("SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld\n", 582 page_size << s->order, s->partial, onoff(s->poison), 583 s->slabs * (page_size << s->order) - s->objects * s->object_size); 584 printf("Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld\n", 585 s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user), 586 (s->slab_size - s->object_size) * s->objects); 587 printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n", 588 s->align, s->objs_per_slab, onoff(s->trace), 589 ((page_size << s->order) - s->objs_per_slab * s->slab_size) * 590 s->slabs); 591 592 ops(s); 593 show_tracking(s); 594 slab_numa(s, 1); 595 slab_stats(s); 596 } 597 598 static void slabcache(struct slabinfo *s) 599 { 600 char size_str[20]; 601 char dist_str[40]; 602 char flags[20]; 603 char *p = flags; 604 605 if (strcmp(s->name, "*") == 0) 606 return; 607 608 if (unreclaim_only && s->reclaim_account) 609 return; 610 611 if (actual_slabs == 1) { 612 report(s); 613 return; 614 } 615 616 if (skip_zero && !show_empty && !s->slabs) 617 return; 618 619 if (show_empty && s->slabs) 620 return; 621 622 if (sort_loss == 0) 623 store_size(size_str, slab_size(s)); 624 else 625 store_size(size_str, slab_waste(s)); 626 snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs, 627 s->partial, s->cpu_slabs); 628 629 if (!line++) 630 first_line(); 631 632 if (s->aliases) 633 *p++ = '*'; 634 if (s->cache_dma) 635 *p++ = 'd'; 636 if (s->hwcache_align) 637 *p++ = 'A'; 638 if (s->poison) 639 *p++ = 'P'; 640 if (s->reclaim_account) 641 *p++ = 'a'; 642 if (s->red_zone) 643 *p++ = 'Z'; 644 if (s->sanity_checks) 645 *p++ = 'F'; 646 if (s->store_user) 647 *p++ = 'U'; 648 if (s->trace) 649 *p++ = 'T'; 650 651 *p = 0; 652 if (show_activity) { 653 unsigned long total_alloc; 654 unsigned long total_free; 655 656 total_alloc = s->alloc_fastpath + s->alloc_slowpath; 657 total_free = s->free_fastpath + s->free_slowpath; 658 659 printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d %4ld %4ld\n", 660 s->name, s->objects, 661 total_alloc, total_free, 662 total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0, 663 total_free ? (s->free_fastpath * 100 / total_free) : 0, 664 s->order_fallback, s->order, s->cmpxchg_double_fail, 665 s->cmpxchg_double_cpu_fail); 666 } else { 667 printf("%-21s %8ld %7d %15s %14s %4d %1d %3ld %3ld %s\n", 668 s->name, s->objects, s->object_size, size_str, dist_str, 669 s->objs_per_slab, s->order, 670 s->slabs ? (s->partial * 100) / s->slabs : 100, 671 s->slabs ? (s->objects * s->object_size * 100) / 672 (s->slabs * (page_size << s->order)) : 100, 673 flags); 674 } 675 } 676 677 /* 678 * Analyze debug options. Return false if something is amiss. 679 */ 680 static int debug_opt_scan(char *opt) 681 { 682 if (!opt || !opt[0] || strcmp(opt, "-") == 0) 683 return 1; 684 685 if (strcasecmp(opt, "a") == 0) { 686 sanity = 1; 687 poison = 1; 688 redzone = 1; 689 tracking = 1; 690 return 1; 691 } 692 693 for ( ; *opt; opt++) 694 switch (*opt) { 695 case 'F' : case 'f': 696 if (sanity) 697 return 0; 698 sanity = 1; 699 break; 700 case 'P' : case 'p': 701 if (poison) 702 return 0; 703 poison = 1; 704 break; 705 706 case 'Z' : case 'z': 707 if (redzone) 708 return 0; 709 redzone = 1; 710 break; 711 712 case 'U' : case 'u': 713 if (tracking) 714 return 0; 715 tracking = 1; 716 break; 717 718 case 'T' : case 't': 719 if (tracing) 720 return 0; 721 tracing = 1; 722 break; 723 default: 724 return 0; 725 } 726 return 1; 727 } 728 729 static int slab_empty(struct slabinfo *s) 730 { 731 if (s->objects > 0) 732 return 0; 733 734 /* 735 * We may still have slabs even if there are no objects. Shrinking will 736 * remove them. 737 */ 738 if (s->slabs != 0) 739 set_obj(s, "shrink", 1); 740 741 return 1; 742 } 743 744 static void slab_debug(struct slabinfo *s) 745 { 746 if (strcmp(s->name, "*") == 0) 747 return; 748 749 if (sanity && !s->sanity_checks) { 750 set_obj(s, "sanity_checks", 1); 751 } 752 if (!sanity && s->sanity_checks) { 753 if (slab_empty(s)) 754 set_obj(s, "sanity_checks", 0); 755 else 756 fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name); 757 } 758 if (redzone && !s->red_zone) { 759 if (slab_empty(s)) 760 set_obj(s, "red_zone", 1); 761 else 762 fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name); 763 } 764 if (!redzone && s->red_zone) { 765 if (slab_empty(s)) 766 set_obj(s, "red_zone", 0); 767 else 768 fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name); 769 } 770 if (poison && !s->poison) { 771 if (slab_empty(s)) 772 set_obj(s, "poison", 1); 773 else 774 fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name); 775 } 776 if (!poison && s->poison) { 777 if (slab_empty(s)) 778 set_obj(s, "poison", 0); 779 else 780 fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name); 781 } 782 if (tracking && !s->store_user) { 783 if (slab_empty(s)) 784 set_obj(s, "store_user", 1); 785 else 786 fprintf(stderr, "%s not empty cannot enable tracking\n", s->name); 787 } 788 if (!tracking && s->store_user) { 789 if (slab_empty(s)) 790 set_obj(s, "store_user", 0); 791 else 792 fprintf(stderr, "%s not empty cannot disable tracking\n", s->name); 793 } 794 if (tracing && !s->trace) { 795 if (slabs == 1) 796 set_obj(s, "trace", 1); 797 else 798 fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name); 799 } 800 if (!tracing && s->trace) 801 set_obj(s, "trace", 1); 802 } 803 804 static void totals(void) 805 { 806 struct slabinfo *s; 807 808 int used_slabs = 0; 809 char b1[20], b2[20], b3[20], b4[20]; 810 unsigned long long max = 1ULL << 63; 811 812 /* Object size */ 813 unsigned long long min_objsize = max, max_objsize = 0, avg_objsize; 814 815 /* Number of partial slabs in a slabcache */ 816 unsigned long long min_partial = max, max_partial = 0, 817 avg_partial, total_partial = 0; 818 819 /* Number of slabs in a slab cache */ 820 unsigned long long min_slabs = max, max_slabs = 0, 821 avg_slabs, total_slabs = 0; 822 823 /* Size of the whole slab */ 824 unsigned long long min_size = max, max_size = 0, 825 avg_size, total_size = 0; 826 827 /* Bytes used for object storage in a slab */ 828 unsigned long long min_used = max, max_used = 0, 829 avg_used, total_used = 0; 830 831 /* Waste: Bytes used for alignment and padding */ 832 unsigned long long min_waste = max, max_waste = 0, 833 avg_waste, total_waste = 0; 834 /* Number of objects in a slab */ 835 unsigned long long min_objects = max, max_objects = 0, 836 avg_objects, total_objects = 0; 837 /* Waste per object */ 838 unsigned long long min_objwaste = max, 839 max_objwaste = 0, avg_objwaste, 840 total_objwaste = 0; 841 842 /* Memory per object */ 843 unsigned long long min_memobj = max, 844 max_memobj = 0, avg_memobj, 845 total_objsize = 0; 846 847 /* Percentage of partial slabs per slab */ 848 unsigned long min_ppart = 100, max_ppart = 0, 849 avg_ppart, total_ppart = 0; 850 851 /* Number of objects in partial slabs */ 852 unsigned long min_partobj = max, max_partobj = 0, 853 avg_partobj, total_partobj = 0; 854 855 /* Percentage of partial objects of all objects in a slab */ 856 unsigned long min_ppartobj = 100, max_ppartobj = 0, 857 avg_ppartobj, total_ppartobj = 0; 858 859 860 for (s = slabinfo; s < slabinfo + slabs; s++) { 861 unsigned long long size; 862 unsigned long used; 863 unsigned long long wasted; 864 unsigned long long objwaste; 865 unsigned long percentage_partial_slabs; 866 unsigned long percentage_partial_objs; 867 868 if (!s->slabs || !s->objects) 869 continue; 870 871 used_slabs++; 872 873 size = slab_size(s); 874 used = s->objects * s->object_size; 875 wasted = size - used; 876 objwaste = s->slab_size - s->object_size; 877 878 percentage_partial_slabs = s->partial * 100 / s->slabs; 879 if (percentage_partial_slabs > 100) 880 percentage_partial_slabs = 100; 881 882 percentage_partial_objs = s->objects_partial * 100 883 / s->objects; 884 885 if (percentage_partial_objs > 100) 886 percentage_partial_objs = 100; 887 888 if (s->object_size < min_objsize) 889 min_objsize = s->object_size; 890 if (s->partial < min_partial) 891 min_partial = s->partial; 892 if (s->slabs < min_slabs) 893 min_slabs = s->slabs; 894 if (size < min_size) 895 min_size = size; 896 if (wasted < min_waste) 897 min_waste = wasted; 898 if (objwaste < min_objwaste) 899 min_objwaste = objwaste; 900 if (s->objects < min_objects) 901 min_objects = s->objects; 902 if (used < min_used) 903 min_used = used; 904 if (s->objects_partial < min_partobj) 905 min_partobj = s->objects_partial; 906 if (percentage_partial_slabs < min_ppart) 907 min_ppart = percentage_partial_slabs; 908 if (percentage_partial_objs < min_ppartobj) 909 min_ppartobj = percentage_partial_objs; 910 if (s->slab_size < min_memobj) 911 min_memobj = s->slab_size; 912 913 if (s->object_size > max_objsize) 914 max_objsize = s->object_size; 915 if (s->partial > max_partial) 916 max_partial = s->partial; 917 if (s->slabs > max_slabs) 918 max_slabs = s->slabs; 919 if (size > max_size) 920 max_size = size; 921 if (wasted > max_waste) 922 max_waste = wasted; 923 if (objwaste > max_objwaste) 924 max_objwaste = objwaste; 925 if (s->objects > max_objects) 926 max_objects = s->objects; 927 if (used > max_used) 928 max_used = used; 929 if (s->objects_partial > max_partobj) 930 max_partobj = s->objects_partial; 931 if (percentage_partial_slabs > max_ppart) 932 max_ppart = percentage_partial_slabs; 933 if (percentage_partial_objs > max_ppartobj) 934 max_ppartobj = percentage_partial_objs; 935 if (s->slab_size > max_memobj) 936 max_memobj = s->slab_size; 937 938 total_partial += s->partial; 939 total_slabs += s->slabs; 940 total_size += size; 941 total_waste += wasted; 942 943 total_objects += s->objects; 944 total_used += used; 945 total_partobj += s->objects_partial; 946 total_ppart += percentage_partial_slabs; 947 total_ppartobj += percentage_partial_objs; 948 949 total_objwaste += s->objects * objwaste; 950 total_objsize += s->objects * s->slab_size; 951 } 952 953 if (!total_objects) { 954 printf("No objects\n"); 955 return; 956 } 957 if (!used_slabs) { 958 printf("No slabs\n"); 959 return; 960 } 961 962 /* Per slab averages */ 963 avg_partial = total_partial / used_slabs; 964 avg_slabs = total_slabs / used_slabs; 965 avg_size = total_size / used_slabs; 966 avg_waste = total_waste / used_slabs; 967 968 avg_objects = total_objects / used_slabs; 969 avg_used = total_used / used_slabs; 970 avg_partobj = total_partobj / used_slabs; 971 avg_ppart = total_ppart / used_slabs; 972 avg_ppartobj = total_ppartobj / used_slabs; 973 974 /* Per object object sizes */ 975 avg_objsize = total_used / total_objects; 976 avg_objwaste = total_objwaste / total_objects; 977 avg_partobj = total_partobj * 100 / total_objects; 978 avg_memobj = total_objsize / total_objects; 979 980 printf("Slabcache Totals\n"); 981 printf("----------------\n"); 982 printf("Slabcaches : %15d Aliases : %11d->%-3d Active: %3d\n", 983 slabs, aliases, alias_targets, used_slabs); 984 985 store_size(b1, total_size);store_size(b2, total_waste); 986 store_size(b3, total_waste * 100 / total_used); 987 printf("Memory used: %15s # Loss : %15s MRatio:%6s%%\n", b1, b2, b3); 988 989 store_size(b1, total_objects);store_size(b2, total_partobj); 990 store_size(b3, total_partobj * 100 / total_objects); 991 printf("# Objects : %15s # PartObj: %15s ORatio:%6s%%\n", b1, b2, b3); 992 993 printf("\n"); 994 printf("Per Cache Average " 995 "Min Max Total\n"); 996 printf("---------------------------------------" 997 "-------------------------------------\n"); 998 999 store_size(b1, avg_objects);store_size(b2, min_objects); 1000 store_size(b3, max_objects);store_size(b4, total_objects); 1001 printf("#Objects %15s %15s %15s %15s\n", 1002 b1, b2, b3, b4); 1003 1004 store_size(b1, avg_slabs);store_size(b2, min_slabs); 1005 store_size(b3, max_slabs);store_size(b4, total_slabs); 1006 printf("#Slabs %15s %15s %15s %15s\n", 1007 b1, b2, b3, b4); 1008 1009 store_size(b1, avg_partial);store_size(b2, min_partial); 1010 store_size(b3, max_partial);store_size(b4, total_partial); 1011 printf("#PartSlab %15s %15s %15s %15s\n", 1012 b1, b2, b3, b4); 1013 store_size(b1, avg_ppart);store_size(b2, min_ppart); 1014 store_size(b3, max_ppart); 1015 store_size(b4, total_partial * 100 / total_slabs); 1016 printf("%%PartSlab%15s%% %15s%% %15s%% %15s%%\n", 1017 b1, b2, b3, b4); 1018 1019 store_size(b1, avg_partobj);store_size(b2, min_partobj); 1020 store_size(b3, max_partobj); 1021 store_size(b4, total_partobj); 1022 printf("PartObjs %15s %15s %15s %15s\n", 1023 b1, b2, b3, b4); 1024 1025 store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj); 1026 store_size(b3, max_ppartobj); 1027 store_size(b4, total_partobj * 100 / total_objects); 1028 printf("%% PartObj%15s%% %15s%% %15s%% %15s%%\n", 1029 b1, b2, b3, b4); 1030 1031 store_size(b1, avg_size);store_size(b2, min_size); 1032 store_size(b3, max_size);store_size(b4, total_size); 1033 printf("Memory %15s %15s %15s %15s\n", 1034 b1, b2, b3, b4); 1035 1036 store_size(b1, avg_used);store_size(b2, min_used); 1037 store_size(b3, max_used);store_size(b4, total_used); 1038 printf("Used %15s %15s %15s %15s\n", 1039 b1, b2, b3, b4); 1040 1041 store_size(b1, avg_waste);store_size(b2, min_waste); 1042 store_size(b3, max_waste);store_size(b4, total_waste); 1043 printf("Loss %15s %15s %15s %15s\n", 1044 b1, b2, b3, b4); 1045 1046 printf("\n"); 1047 printf("Per Object Average " 1048 "Min Max\n"); 1049 printf("---------------------------------------" 1050 "--------------------\n"); 1051 1052 store_size(b1, avg_memobj);store_size(b2, min_memobj); 1053 store_size(b3, max_memobj); 1054 printf("Memory %15s %15s %15s\n", 1055 b1, b2, b3); 1056 store_size(b1, avg_objsize);store_size(b2, min_objsize); 1057 store_size(b3, max_objsize); 1058 printf("User %15s %15s %15s\n", 1059 b1, b2, b3); 1060 1061 store_size(b1, avg_objwaste);store_size(b2, min_objwaste); 1062 store_size(b3, max_objwaste); 1063 printf("Loss %15s %15s %15s\n", 1064 b1, b2, b3); 1065 } 1066 1067 static void sort_slabs(void) 1068 { 1069 struct slabinfo *s1,*s2; 1070 1071 for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) { 1072 for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) { 1073 int result; 1074 1075 if (sort_size) { 1076 if (slab_size(s1) == slab_size(s2)) 1077 result = strcasecmp(s1->name, s2->name); 1078 else 1079 result = slab_size(s1) < slab_size(s2); 1080 } else if (sort_active) { 1081 if (slab_activity(s1) == slab_activity(s2)) 1082 result = strcasecmp(s1->name, s2->name); 1083 else 1084 result = slab_activity(s1) < slab_activity(s2); 1085 } else if (sort_loss) { 1086 if (slab_waste(s1) == slab_waste(s2)) 1087 result = strcasecmp(s1->name, s2->name); 1088 else 1089 result = slab_waste(s1) < slab_waste(s2); 1090 } else if (sort_partial) { 1091 if (s1->partial == s2->partial) 1092 result = strcasecmp(s1->name, s2->name); 1093 else 1094 result = s1->partial < s2->partial; 1095 } else 1096 result = strcasecmp(s1->name, s2->name); 1097 1098 if (show_inverted) 1099 result = -result; 1100 1101 if (result > 0) { 1102 struct slabinfo t; 1103 1104 memcpy(&t, s1, sizeof(struct slabinfo)); 1105 memcpy(s1, s2, sizeof(struct slabinfo)); 1106 memcpy(s2, &t, sizeof(struct slabinfo)); 1107 } 1108 } 1109 } 1110 } 1111 1112 static void sort_aliases(void) 1113 { 1114 struct aliasinfo *a1,*a2; 1115 1116 for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) { 1117 for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) { 1118 char *n1, *n2; 1119 1120 n1 = a1->name; 1121 n2 = a2->name; 1122 if (show_alias && !show_inverted) { 1123 n1 = a1->ref; 1124 n2 = a2->ref; 1125 } 1126 if (strcasecmp(n1, n2) > 0) { 1127 struct aliasinfo t; 1128 1129 memcpy(&t, a1, sizeof(struct aliasinfo)); 1130 memcpy(a1, a2, sizeof(struct aliasinfo)); 1131 memcpy(a2, &t, sizeof(struct aliasinfo)); 1132 } 1133 } 1134 } 1135 } 1136 1137 static void link_slabs(void) 1138 { 1139 struct aliasinfo *a; 1140 struct slabinfo *s; 1141 1142 for (a = aliasinfo; a < aliasinfo + aliases; a++) { 1143 1144 for (s = slabinfo; s < slabinfo + slabs; s++) 1145 if (strcmp(a->ref, s->name) == 0) { 1146 a->slab = s; 1147 s->refs++; 1148 break; 1149 } 1150 if (s == slabinfo + slabs) 1151 fatal("Unresolved alias %s\n", a->ref); 1152 } 1153 } 1154 1155 static void alias(void) 1156 { 1157 struct aliasinfo *a; 1158 char *active = NULL; 1159 1160 sort_aliases(); 1161 link_slabs(); 1162 1163 for(a = aliasinfo; a < aliasinfo + aliases; a++) { 1164 1165 if (!show_single_ref && a->slab->refs == 1) 1166 continue; 1167 1168 if (!show_inverted) { 1169 if (active) { 1170 if (strcmp(a->slab->name, active) == 0) { 1171 printf(" %s", a->name); 1172 continue; 1173 } 1174 } 1175 printf("\n%-12s <- %s", a->slab->name, a->name); 1176 active = a->slab->name; 1177 } 1178 else 1179 printf("%-15s -> %s\n", a->name, a->slab->name); 1180 } 1181 if (active) 1182 printf("\n"); 1183 } 1184 1185 1186 static void rename_slabs(void) 1187 { 1188 struct slabinfo *s; 1189 struct aliasinfo *a; 1190 1191 for (s = slabinfo; s < slabinfo + slabs; s++) { 1192 if (*s->name != ':') 1193 continue; 1194 1195 if (s->refs > 1 && !show_first_alias) 1196 continue; 1197 1198 a = find_one_alias(s); 1199 1200 if (a) 1201 s->name = a->name; 1202 else { 1203 s->name = "*"; 1204 actual_slabs--; 1205 } 1206 } 1207 } 1208 1209 static int slab_mismatch(char *slab) 1210 { 1211 return regexec(&pattern, slab, 0, NULL, 0); 1212 } 1213 1214 static void read_slab_dir(void) 1215 { 1216 DIR *dir; 1217 struct dirent *de; 1218 struct slabinfo *slab = slabinfo; 1219 struct aliasinfo *alias = aliasinfo; 1220 char *p; 1221 char *t; 1222 int count; 1223 1224 if (chdir("/sys/kernel/slab") && chdir("/sys/slab")) 1225 fatal("SYSFS support for SLUB not active\n"); 1226 1227 dir = opendir("."); 1228 while ((de = readdir(dir))) { 1229 if (de->d_name[0] == '.' || 1230 (de->d_name[0] != ':' && slab_mismatch(de->d_name))) 1231 continue; 1232 switch (de->d_type) { 1233 case DT_LNK: 1234 if (alias - aliasinfo == MAX_ALIASES) 1235 fatal("Too many aliases\n"); 1236 alias->name = strdup(de->d_name); 1237 count = readlink(de->d_name, buffer, sizeof(buffer)-1); 1238 1239 if (count < 0) 1240 fatal("Cannot read symlink %s\n", de->d_name); 1241 1242 buffer[count] = 0; 1243 p = buffer + count; 1244 while (p > buffer && p[-1] != '/') 1245 p--; 1246 alias->ref = strdup(p); 1247 alias++; 1248 break; 1249 case DT_DIR: 1250 if (slab - slabinfo == MAX_SLABS) 1251 fatal("Too many slabs\n"); 1252 if (chdir(de->d_name)) 1253 fatal("Unable to access slab %s\n", slab->name); 1254 slab->name = strdup(de->d_name); 1255 slab->alias = 0; 1256 slab->refs = 0; 1257 slab->aliases = get_obj("aliases"); 1258 slab->align = get_obj("align"); 1259 slab->cache_dma = get_obj("cache_dma"); 1260 slab->cpu_slabs = get_obj("cpu_slabs"); 1261 slab->destroy_by_rcu = get_obj("destroy_by_rcu"); 1262 slab->hwcache_align = get_obj("hwcache_align"); 1263 slab->object_size = get_obj("object_size"); 1264 slab->objects = get_obj("objects"); 1265 slab->objects_partial = get_obj("objects_partial"); 1266 slab->objects_total = get_obj("objects_total"); 1267 slab->objs_per_slab = get_obj("objs_per_slab"); 1268 slab->order = get_obj("order"); 1269 slab->partial = get_obj("partial"); 1270 slab->partial = get_obj_and_str("partial", &t); 1271 decode_numa_list(slab->numa_partial, t); 1272 free(t); 1273 slab->poison = get_obj("poison"); 1274 slab->reclaim_account = get_obj("reclaim_account"); 1275 slab->red_zone = get_obj("red_zone"); 1276 slab->sanity_checks = get_obj("sanity_checks"); 1277 slab->slab_size = get_obj("slab_size"); 1278 slab->slabs = get_obj_and_str("slabs", &t); 1279 decode_numa_list(slab->numa, t); 1280 free(t); 1281 slab->store_user = get_obj("store_user"); 1282 slab->trace = get_obj("trace"); 1283 slab->alloc_fastpath = get_obj("alloc_fastpath"); 1284 slab->alloc_slowpath = get_obj("alloc_slowpath"); 1285 slab->free_fastpath = get_obj("free_fastpath"); 1286 slab->free_slowpath = get_obj("free_slowpath"); 1287 slab->free_frozen= get_obj("free_frozen"); 1288 slab->free_add_partial = get_obj("free_add_partial"); 1289 slab->free_remove_partial = get_obj("free_remove_partial"); 1290 slab->alloc_from_partial = get_obj("alloc_from_partial"); 1291 slab->alloc_slab = get_obj("alloc_slab"); 1292 slab->alloc_refill = get_obj("alloc_refill"); 1293 slab->free_slab = get_obj("free_slab"); 1294 slab->cpuslab_flush = get_obj("cpuslab_flush"); 1295 slab->deactivate_full = get_obj("deactivate_full"); 1296 slab->deactivate_empty = get_obj("deactivate_empty"); 1297 slab->deactivate_to_head = get_obj("deactivate_to_head"); 1298 slab->deactivate_to_tail = get_obj("deactivate_to_tail"); 1299 slab->deactivate_remote_frees = get_obj("deactivate_remote_frees"); 1300 slab->order_fallback = get_obj("order_fallback"); 1301 slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail"); 1302 slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail"); 1303 slab->cpu_partial_alloc = get_obj("cpu_partial_alloc"); 1304 slab->cpu_partial_free = get_obj("cpu_partial_free"); 1305 slab->alloc_node_mismatch = get_obj("alloc_node_mismatch"); 1306 slab->deactivate_bypass = get_obj("deactivate_bypass"); 1307 if (chdir("..")) 1308 fatal("Unable to chdir from slab ../%s\n", 1309 slab->name); 1310 if (slab->name[0] == ':') 1311 alias_targets++; 1312 slab++; 1313 break; 1314 default : 1315 fatal("Unknown file type %lx\n", de->d_type); 1316 } 1317 } 1318 closedir(dir); 1319 slabs = slab - slabinfo; 1320 actual_slabs = slabs; 1321 aliases = alias - aliasinfo; 1322 } 1323 1324 static void output_slabs(void) 1325 { 1326 struct slabinfo *slab; 1327 int lines = output_lines; 1328 1329 for (slab = slabinfo; (slab < slabinfo + slabs) && 1330 lines != 0; slab++) { 1331 1332 if (slab->alias) 1333 continue; 1334 1335 if (lines != -1) 1336 lines--; 1337 1338 if (show_numa) 1339 slab_numa(slab, 0); 1340 else if (show_track) 1341 show_tracking(slab); 1342 else if (validate) 1343 slab_validate(slab); 1344 else if (shrink) 1345 slab_shrink(slab); 1346 else if (set_debug) 1347 slab_debug(slab); 1348 else if (show_ops) 1349 ops(slab); 1350 else if (show_slab) 1351 slabcache(slab); 1352 else if (show_report) 1353 report(slab); 1354 } 1355 } 1356 1357 static void _xtotals(char *heading, char *underline, 1358 int loss, int size, int partial) 1359 { 1360 printf("%s%s", heading, underline); 1361 line = 0; 1362 sort_loss = loss; 1363 sort_size = size; 1364 sort_partial = partial; 1365 sort_slabs(); 1366 output_slabs(); 1367 } 1368 1369 static void xtotals(void) 1370 { 1371 char *heading, *underline; 1372 1373 totals(); 1374 1375 link_slabs(); 1376 rename_slabs(); 1377 1378 heading = "\nSlabs sorted by size\n"; 1379 underline = "--------------------\n"; 1380 _xtotals(heading, underline, 0, 1, 0); 1381 1382 heading = "\nSlabs sorted by loss\n"; 1383 underline = "--------------------\n"; 1384 _xtotals(heading, underline, 1, 0, 0); 1385 1386 heading = "\nSlabs sorted by number of partial slabs\n"; 1387 underline = "---------------------------------------\n"; 1388 _xtotals(heading, underline, 0, 0, 1); 1389 1390 printf("\n"); 1391 } 1392 1393 struct option opts[] = { 1394 { "aliases", no_argument, NULL, 'a' }, 1395 { "activity", no_argument, NULL, 'A' }, 1396 { "Bytes", no_argument, NULL, 'B'}, 1397 { "debug", optional_argument, NULL, 'd' }, 1398 { "display-activity", no_argument, NULL, 'D' }, 1399 { "empty", no_argument, NULL, 'e' }, 1400 { "first-alias", no_argument, NULL, 'f' }, 1401 { "help", no_argument, NULL, 'h' }, 1402 { "inverted", no_argument, NULL, 'i'}, 1403 { "slabs", no_argument, NULL, 'l' }, 1404 { "Loss", no_argument, NULL, 'L'}, 1405 { "numa", no_argument, NULL, 'n' }, 1406 { "lines", required_argument, NULL, 'N'}, 1407 { "ops", no_argument, NULL, 'o' }, 1408 { "partial", no_argument, NULL, 'p'}, 1409 { "report", no_argument, NULL, 'r' }, 1410 { "shrink", no_argument, NULL, 's' }, 1411 { "Size", no_argument, NULL, 'S'}, 1412 { "tracking", no_argument, NULL, 't'}, 1413 { "Totals", no_argument, NULL, 'T'}, 1414 { "Unreclaim", no_argument, NULL, 'U'}, 1415 { "validate", no_argument, NULL, 'v' }, 1416 { "Xtotals", no_argument, NULL, 'X'}, 1417 { "zero", no_argument, NULL, 'z' }, 1418 { "1ref", no_argument, NULL, '1'}, 1419 { NULL, 0, NULL, 0 } 1420 }; 1421 1422 int main(int argc, char *argv[]) 1423 { 1424 int c; 1425 int err; 1426 char *pattern_source; 1427 1428 page_size = getpagesize(); 1429 1430 while ((c = getopt_long(argc, argv, "aABd::DefhilLnN:oPrsStTUvXz1", 1431 opts, NULL)) != -1) 1432 switch (c) { 1433 case 'a': 1434 show_alias = 1; 1435 break; 1436 case 'A': 1437 sort_active = 1; 1438 break; 1439 case 'B': 1440 show_bytes = 1; 1441 break; 1442 case 'd': 1443 set_debug = 1; 1444 if (!debug_opt_scan(optarg)) 1445 fatal("Invalid debug option '%s'\n", optarg); 1446 break; 1447 case 'D': 1448 show_activity = 1; 1449 break; 1450 case 'e': 1451 show_empty = 1; 1452 break; 1453 case 'f': 1454 show_first_alias = 1; 1455 break; 1456 case 'h': 1457 usage(); 1458 return 0; 1459 case 'i': 1460 show_inverted = 1; 1461 break; 1462 case 'l': 1463 show_slab = 1; 1464 break; 1465 case 'L': 1466 sort_loss = 1; 1467 break; 1468 case 'n': 1469 show_numa = 1; 1470 break; 1471 case 'N': 1472 if (optarg) { 1473 output_lines = atoi(optarg); 1474 if (output_lines < 1) 1475 output_lines = 1; 1476 } 1477 break; 1478 case 'o': 1479 show_ops = 1; 1480 break; 1481 case 'r': 1482 show_report = 1; 1483 break; 1484 case 'P': 1485 sort_partial = 1; 1486 break; 1487 case 's': 1488 shrink = 1; 1489 break; 1490 case 'S': 1491 sort_size = 1; 1492 break; 1493 case 't': 1494 show_track = 1; 1495 break; 1496 case 'T': 1497 show_totals = 1; 1498 break; 1499 case 'U': 1500 unreclaim_only = 1; 1501 break; 1502 case 'v': 1503 validate = 1; 1504 break; 1505 case 'X': 1506 if (output_lines == -1) 1507 output_lines = 1; 1508 extended_totals = 1; 1509 show_bytes = 1; 1510 break; 1511 case 'z': 1512 skip_zero = 0; 1513 break; 1514 case '1': 1515 show_single_ref = 1; 1516 break; 1517 default: 1518 fatal("%s: Invalid option '%c'\n", argv[0], optopt); 1519 1520 } 1521 1522 if (!show_slab && !show_alias && !show_track && !show_report 1523 && !validate && !shrink && !set_debug && !show_ops) 1524 show_slab = 1; 1525 1526 if (argc > optind) 1527 pattern_source = argv[optind]; 1528 else 1529 pattern_source = ".*"; 1530 1531 err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB); 1532 if (err) 1533 fatal("%s: Invalid pattern '%s' code %d\n", 1534 argv[0], pattern_source, err); 1535 read_slab_dir(); 1536 if (show_alias) { 1537 alias(); 1538 } else if (extended_totals) { 1539 xtotals(); 1540 } else if (show_totals) { 1541 totals(); 1542 } else { 1543 link_slabs(); 1544 rename_slabs(); 1545 sort_slabs(); 1546 output_slabs(); 1547 } 1548 return 0; 1549 } 1550