1/* 2 * Slabinfo: Tool to get reports about slabs 3 * 4 * (C) 2007 sgi, Christoph Lameter <clameter@sgi.com> 5 * 6 * Compile by: 7 * 8 * gcc -o slabinfo slabinfo.c 9 */ 10#include <stdio.h> 11#include <stdlib.h> 12#include <sys/types.h> 13#include <dirent.h> 14#include <string.h> 15#include <unistd.h> 16#include <stdarg.h> 17#include <getopt.h> 18#include <regex.h> 19#include <errno.h> 20 21#define MAX_SLABS 500 22#define MAX_ALIASES 500 23#define MAX_NODES 1024 24 25struct slabinfo { 26 char *name; 27 int alias; 28 int refs; 29 int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu; 30 int hwcache_align, object_size, objs_per_slab; 31 int sanity_checks, slab_size, store_user, trace; 32 int order, poison, reclaim_account, red_zone; 33 unsigned long partial, objects, slabs; 34 int numa[MAX_NODES]; 35 int numa_partial[MAX_NODES]; 36} slabinfo[MAX_SLABS]; 37 38struct aliasinfo { 39 char *name; 40 char *ref; 41 struct slabinfo *slab; 42} aliasinfo[MAX_ALIASES]; 43 44int slabs = 0; 45int actual_slabs = 0; 46int aliases = 0; 47int alias_targets = 0; 48int highest_node = 0; 49 50char buffer[4096]; 51 52int show_empty = 0; 53int show_report = 0; 54int show_alias = 0; 55int show_slab = 0; 56int skip_zero = 1; 57int show_numa = 0; 58int show_track = 0; 59int show_first_alias = 0; 60int validate = 0; 61int shrink = 0; 62int show_inverted = 0; 63int show_single_ref = 0; 64int show_totals = 0; 65int sort_size = 0; 66int set_debug = 0; 67int show_ops = 0; 68 69/* Debug options */ 70int sanity = 0; 71int redzone = 0; 72int poison = 0; 73int tracking = 0; 74int tracing = 0; 75 76int page_size; 77 78regex_t pattern; 79 80void fatal(const char *x, ...) 81{ 82 va_list ap; 83 84 va_start(ap, x); 85 vfprintf(stderr, x, ap); 86 va_end(ap); 87 exit(1); 88} 89 90void usage(void) 91{ 92 printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n" 93 "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n" 94 "-a|--aliases Show aliases\n" 95 "-d<options>|--debug=<options> Set/Clear Debug options\n" 96 "-e|--empty Show empty slabs\n" 97 "-f|--first-alias Show first alias\n" 98 "-h|--help Show usage information\n" 99 "-i|--inverted Inverted list\n" 100 "-l|--slabs Show slabs\n" 101 "-n|--numa Show NUMA information\n" 102 "-o|--ops Show kmem_cache_ops\n" 103 "-s|--shrink Shrink slabs\n" 104 "-r|--report Detailed report on single slabs\n" 105 "-S|--Size Sort by size\n" 106 "-t|--tracking Show alloc/free information\n" 107 "-T|--Totals Show summary information\n" 108 "-v|--validate Validate slabs\n" 109 "-z|--zero Include empty slabs\n" 110 "-1|--1ref Single reference\n" 111 "\nValid debug options (FZPUT may be combined)\n" 112 "a / A Switch on all debug options (=FZUP)\n" 113 "- Switch off all debug options\n" 114 "f / F Sanity Checks (SLAB_DEBUG_FREE)\n" 115 "z / Z Redzoning\n" 116 "p / P Poisoning\n" 117 "u / U Tracking\n" 118 "t / T Tracing\n" 119 ); 120} 121 122unsigned long read_obj(char *name) 123{ 124 FILE *f = fopen(name, "r"); 125 126 if (!f) 127 buffer[0] = 0; 128 else { 129 if (!fgets(buffer,sizeof(buffer), f)) 130 buffer[0] = 0; 131 fclose(f); 132 if (buffer[strlen(buffer)] == '\n') 133 buffer[strlen(buffer)] = 0; 134 } 135 return strlen(buffer); 136} 137 138 139/* 140 * Get the contents of an attribute 141 */ 142unsigned long get_obj(char *name) 143{ 144 if (!read_obj(name)) 145 return 0; 146 147 return atol(buffer); 148} 149 150unsigned long get_obj_and_str(char *name, char **x) 151{ 152 unsigned long result = 0; 153 char *p; 154 155 *x = NULL; 156 157 if (!read_obj(name)) { 158 x = NULL; 159 return 0; 160 } 161 result = strtoul(buffer, &p, 10); 162 while (*p == ' ') 163 p++; 164 if (*p) 165 *x = strdup(p); 166 return result; 167} 168 169void set_obj(struct slabinfo *s, char *name, int n) 170{ 171 char x[100]; 172 FILE *f; 173 174 sprintf(x, "%s/%s", s->name, name); 175 f = fopen(x, "w"); 176 if (!f) 177 fatal("Cannot write to %s\n", x); 178 179 fprintf(f, "%d\n", n); 180 fclose(f); 181} 182 183unsigned long read_slab_obj(struct slabinfo *s, char *name) 184{ 185 char x[100]; 186 FILE *f; 187 int l; 188 189 sprintf(x, "%s/%s", s->name, name); 190 f = fopen(x, "r"); 191 if (!f) { 192 buffer[0] = 0; 193 l = 0; 194 } else { 195 l = fread(buffer, 1, sizeof(buffer), f); 196 buffer[l] = 0; 197 fclose(f); 198 } 199 return l; 200} 201 202 203/* 204 * Put a size string together 205 */ 206int store_size(char *buffer, unsigned long value) 207{ 208 unsigned long divisor = 1; 209 char trailer = 0; 210 int n; 211 212 if (value > 1000000000UL) { 213 divisor = 100000000UL; 214 trailer = 'G'; 215 } else if (value > 1000000UL) { 216 divisor = 100000UL; 217 trailer = 'M'; 218 } else if (value > 1000UL) { 219 divisor = 100; 220 trailer = 'K'; 221 } 222 223 value /= divisor; 224 n = sprintf(buffer, "%ld",value); 225 if (trailer) { 226 buffer[n] = trailer; 227 n++; 228 buffer[n] = 0; 229 } 230 if (divisor != 1) { 231 memmove(buffer + n - 2, buffer + n - 3, 4); 232 buffer[n-2] = '.'; 233 n++; 234 } 235 return n; 236} 237 238void decode_numa_list(int *numa, char *t) 239{ 240 int node; 241 int nr; 242 243 memset(numa, 0, MAX_NODES * sizeof(int)); 244 245 if (!t) 246 return; 247 248 while (*t == 'N') { 249 t++; 250 node = strtoul(t, &t, 10); 251 if (*t == '=') { 252 t++; 253 nr = strtoul(t, &t, 10); 254 numa[node] = nr; 255 if (node > highest_node) 256 highest_node = node; 257 } 258 while (*t == ' ') 259 t++; 260 } 261} 262 263void slab_validate(struct slabinfo *s) 264{ 265 if (strcmp(s->name, "*") == 0) 266 return; 267 268 set_obj(s, "validate", 1); 269} 270 271void slab_shrink(struct slabinfo *s) 272{ 273 if (strcmp(s->name, "*") == 0) 274 return; 275 276 set_obj(s, "shrink", 1); 277} 278 279int line = 0; 280 281void first_line(void) 282{ 283 printf("Name Objects Objsize Space " 284 "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); 285} 286 287/* 288 * Find the shortest alias of a slab 289 */ 290struct aliasinfo *find_one_alias(struct slabinfo *find) 291{ 292 struct aliasinfo *a; 293 struct aliasinfo *best = NULL; 294 295 for(a = aliasinfo;a < aliasinfo + aliases; a++) { 296 if (a->slab == find && 297 (!best || strlen(best->name) < strlen(a->name))) { 298 best = a; 299 if (strncmp(a->name,"kmall", 5) == 0) 300 return best; 301 } 302 } 303 return best; 304} 305 306unsigned long slab_size(struct slabinfo *s) 307{ 308 return s->slabs * (page_size << s->order); 309} 310 311void slab_numa(struct slabinfo *s, int mode) 312{ 313 int node; 314 315 if (strcmp(s->name, "*") == 0) 316 return; 317 318 if (!highest_node) { 319 printf("\n%s: No NUMA information available.\n", s->name); 320 return; 321 } 322 323 if (skip_zero && !s->slabs) 324 return; 325 326 if (!line) { 327 printf("\n%-21s:", mode ? "NUMA nodes" : "Slab"); 328 for(node = 0; node <= highest_node; node++) 329 printf(" %4d", node); 330 printf("\n----------------------"); 331 for(node = 0; node <= highest_node; node++) 332 printf("-----"); 333 printf("\n"); 334 } 335 printf("%-21s ", mode ? "All slabs" : s->name); 336 for(node = 0; node <= highest_node; node++) { 337 char b[20]; 338 339 store_size(b, s->numa[node]); 340 printf(" %4s", b); 341 } 342 printf("\n"); 343 if (mode) { 344 printf("%-21s ", "Partial slabs"); 345 for(node = 0; node <= highest_node; node++) { 346 char b[20]; 347 348 store_size(b, s->numa_partial[node]); 349 printf(" %4s", b); 350 } 351 printf("\n"); 352 } 353 line++; 354} 355 356void show_tracking(struct slabinfo *s) 357{ 358 printf("\n%s: Kernel object allocation\n", s->name); 359 printf("-----------------------------------------------------------------------\n"); 360 if (read_slab_obj(s, "alloc_calls")) 361 printf(buffer); 362 else 363 printf("No Data\n"); 364 365 printf("\n%s: Kernel object freeing\n", s->name); 366 printf("------------------------------------------------------------------------\n"); 367 if (read_slab_obj(s, "free_calls")) 368 printf(buffer); 369 else 370 printf("No Data\n"); 371 372} 373 374void ops(struct slabinfo *s) 375{ 376 if (strcmp(s->name, "*") == 0) 377 return; 378 379 if (read_slab_obj(s, "ops")) { 380 printf("\n%s: kmem_cache operations\n", s->name); 381 printf("--------------------------------------------\n"); 382 printf(buffer); 383 } else 384 printf("\n%s has no kmem_cache operations\n", s->name); 385} 386 387const char *onoff(int x) 388{ 389 if (x) 390 return "On "; 391 return "Off"; 392} 393 394void report(struct slabinfo *s) 395{ 396 if (strcmp(s->name, "*") == 0) 397 return; 398 399 printf("\nSlabcache: %-20s Aliases: %2d Order : %2d Objects: %d\n", 400 s->name, s->aliases, s->order, s->objects); 401 if (s->hwcache_align) 402 printf("** Hardware cacheline aligned\n"); 403 if (s->cache_dma) 404 printf("** Memory is allocated in a special DMA zone\n"); 405 if (s->destroy_by_rcu) 406 printf("** Slabs are destroyed via RCU\n"); 407 if (s->reclaim_account) 408 printf("** Reclaim accounting active\n"); 409 410 printf("\nSizes (bytes) Slabs Debug Memory\n"); 411 printf("------------------------------------------------------------------------\n"); 412 printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n", 413 s->object_size, s->slabs, onoff(s->sanity_checks), 414 s->slabs * (page_size << s->order)); 415 printf("SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld\n", 416 s->slab_size, s->slabs - s->partial - s->cpu_slabs, 417 onoff(s->red_zone), s->objects * s->object_size); 418 printf("SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld\n", 419 page_size << s->order, s->partial, onoff(s->poison), 420 s->slabs * (page_size << s->order) - s->objects * s->object_size); 421 printf("Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld\n", 422 s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user), 423 (s->slab_size - s->object_size) * s->objects); 424 printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n", 425 s->align, s->objs_per_slab, onoff(s->trace), 426 ((page_size << s->order) - s->objs_per_slab * s->slab_size) * 427 s->slabs); 428 429 ops(s); 430 show_tracking(s); 431 slab_numa(s, 1); 432} 433 434void slabcache(struct slabinfo *s) 435{ 436 char size_str[20]; 437 char dist_str[40]; 438 char flags[20]; 439 char *p = flags; 440 441 if (strcmp(s->name, "*") == 0) 442 return; 443 444 if (actual_slabs == 1) { 445 report(s); 446 return; 447 } 448 449 if (skip_zero && !show_empty && !s->slabs) 450 return; 451 452 if (show_empty && s->slabs) 453 return; 454 455 store_size(size_str, slab_size(s)); 456 sprintf(dist_str,"%lu/%lu/%d", s->slabs, s->partial, s->cpu_slabs); 457 458 if (!line++) 459 first_line(); 460 461 if (s->aliases) 462 *p++ = '*'; 463 if (s->cache_dma) 464 *p++ = 'd'; 465 if (s->hwcache_align) 466 *p++ = 'A'; 467 if (s->poison) 468 *p++ = 'P'; 469 if (s->reclaim_account) 470 *p++ = 'a'; 471 if (s->red_zone) 472 *p++ = 'Z'; 473 if (s->sanity_checks) 474 *p++ = 'F'; 475 if (s->store_user) 476 *p++ = 'U'; 477 if (s->trace) 478 *p++ = 'T'; 479 480 *p = 0; 481 printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n", 482 s->name, s->objects, s->object_size, size_str, dist_str, 483 s->objs_per_slab, s->order, 484 s->slabs ? (s->partial * 100) / s->slabs : 100, 485 s->slabs ? (s->objects * s->object_size * 100) / 486 (s->slabs * (page_size << s->order)) : 100, 487 flags); 488} 489 490/* 491 * Analyze debug options. Return false if something is amiss. 492 */ 493int debug_opt_scan(char *opt) 494{ 495 if (!opt || !opt[0] || strcmp(opt, "-") == 0) 496 return 1; 497 498 if (strcasecmp(opt, "a") == 0) { 499 sanity = 1; 500 poison = 1; 501 redzone = 1; 502 tracking = 1; 503 return 1; 504 } 505 506 for ( ; *opt; opt++) 507 switch (*opt) { 508 case 'F' : case 'f': 509 if (sanity) 510 return 0; 511 sanity = 1; 512 break; 513 case 'P' : case 'p': 514 if (poison) 515 return 0; 516 poison = 1; 517 break; 518 519 case 'Z' : case 'z': 520 if (redzone) 521 return 0; 522 redzone = 1; 523 break; 524 525 case 'U' : case 'u': 526 if (tracking) 527 return 0; 528 tracking = 1; 529 break; 530 531 case 'T' : case 't': 532 if (tracing) 533 return 0; 534 tracing = 1; 535 break; 536 default: 537 return 0; 538 } 539 return 1; 540} 541 542int slab_empty(struct slabinfo *s) 543{ 544 if (s->objects > 0) 545 return 0; 546 547 /* 548 * We may still have slabs even if there are no objects. Shrinking will 549 * remove them. 550 */ 551 if (s->slabs != 0) 552 set_obj(s, "shrink", 1); 553 554 return 1; 555} 556 557void slab_debug(struct slabinfo *s) 558{ 559 if (strcmp(s->name, "*") == 0) 560 return; 561 562 if (sanity && !s->sanity_checks) { 563 set_obj(s, "sanity", 1); 564 } 565 if (!sanity && s->sanity_checks) { 566 if (slab_empty(s)) 567 set_obj(s, "sanity", 0); 568 else 569 fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name); 570 } 571 if (redzone && !s->red_zone) { 572 if (slab_empty(s)) 573 set_obj(s, "red_zone", 1); 574 else 575 fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name); 576 } 577 if (!redzone && s->red_zone) { 578 if (slab_empty(s)) 579 set_obj(s, "red_zone", 0); 580 else 581 fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name); 582 } 583 if (poison && !s->poison) { 584 if (slab_empty(s)) 585 set_obj(s, "poison", 1); 586 else 587 fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name); 588 } 589 if (!poison && s->poison) { 590 if (slab_empty(s)) 591 set_obj(s, "poison", 0); 592 else 593 fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name); 594 } 595 if (tracking && !s->store_user) { 596 if (slab_empty(s)) 597 set_obj(s, "store_user", 1); 598 else 599 fprintf(stderr, "%s not empty cannot enable tracking\n", s->name); 600 } 601 if (!tracking && s->store_user) { 602 if (slab_empty(s)) 603 set_obj(s, "store_user", 0); 604 else 605 fprintf(stderr, "%s not empty cannot disable tracking\n", s->name); 606 } 607 if (tracing && !s->trace) { 608 if (slabs == 1) 609 set_obj(s, "trace", 1); 610 else 611 fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name); 612 } 613 if (!tracing && s->trace) 614 set_obj(s, "trace", 1); 615} 616 617void totals(void) 618{ 619 struct slabinfo *s; 620 621 int used_slabs = 0; 622 char b1[20], b2[20], b3[20], b4[20]; 623 unsigned long long max = 1ULL << 63; 624 625 /* Object size */ 626 unsigned long long min_objsize = max, max_objsize = 0, avg_objsize; 627 628 /* Number of partial slabs in a slabcache */ 629 unsigned long long min_partial = max, max_partial = 0, 630 avg_partial, total_partial = 0; 631 632 /* Number of slabs in a slab cache */ 633 unsigned long long min_slabs = max, max_slabs = 0, 634 avg_slabs, total_slabs = 0; 635 636 /* Size of the whole slab */ 637 unsigned long long min_size = max, max_size = 0, 638 avg_size, total_size = 0; 639 640 /* Bytes used for object storage in a slab */ 641 unsigned long long min_used = max, max_used = 0, 642 avg_used, total_used = 0; 643 644 /* Waste: Bytes used for alignment and padding */ 645 unsigned long long min_waste = max, max_waste = 0, 646 avg_waste, total_waste = 0; 647 /* Number of objects in a slab */ 648 unsigned long long min_objects = max, max_objects = 0, 649 avg_objects, total_objects = 0; 650 /* Waste per object */ 651 unsigned long long min_objwaste = max, 652 max_objwaste = 0, avg_objwaste, 653 total_objwaste = 0; 654 655 /* Memory per object */ 656 unsigned long long min_memobj = max, 657 max_memobj = 0, avg_memobj, 658 total_objsize = 0; 659 660 /* Percentage of partial slabs per slab */ 661 unsigned long min_ppart = 100, max_ppart = 0, 662 avg_ppart, total_ppart = 0; 663 664 /* Number of objects in partial slabs */ 665 unsigned long min_partobj = max, max_partobj = 0, 666 avg_partobj, total_partobj = 0; 667 668 /* Percentage of partial objects of all objects in a slab */ 669 unsigned long min_ppartobj = 100, max_ppartobj = 0, 670 avg_ppartobj, total_ppartobj = 0; 671 672 673 for (s = slabinfo; s < slabinfo + slabs; s++) { 674 unsigned long long size; 675 unsigned long used; 676 unsigned long long wasted; 677 unsigned long long objwaste; 678 long long objects_in_partial_slabs; 679 unsigned long percentage_partial_slabs; 680 unsigned long percentage_partial_objs; 681 682 if (!s->slabs || !s->objects) 683 continue; 684 685 used_slabs++; 686 687 size = slab_size(s); 688 used = s->objects * s->object_size; 689 wasted = size - used; 690 objwaste = s->slab_size - s->object_size; 691 692 objects_in_partial_slabs = s->objects - 693 (s->slabs - s->partial - s ->cpu_slabs) * 694 s->objs_per_slab; 695 696 if (objects_in_partial_slabs < 0) 697 objects_in_partial_slabs = 0; 698 699 percentage_partial_slabs = s->partial * 100 / s->slabs; 700 if (percentage_partial_slabs > 100) 701 percentage_partial_slabs = 100; 702 703 percentage_partial_objs = objects_in_partial_slabs * 100 704 / s->objects; 705 706 if (percentage_partial_objs > 100) 707 percentage_partial_objs = 100; 708 709 if (s->object_size < min_objsize) 710 min_objsize = s->object_size; 711 if (s->partial < min_partial) 712 min_partial = s->partial; 713 if (s->slabs < min_slabs) 714 min_slabs = s->slabs; 715 if (size < min_size) 716 min_size = size; 717 if (wasted < min_waste) 718 min_waste = wasted; 719 if (objwaste < min_objwaste) 720 min_objwaste = objwaste; 721 if (s->objects < min_objects) 722 min_objects = s->objects; 723 if (used < min_used) 724 min_used = used; 725 if (objects_in_partial_slabs < min_partobj) 726 min_partobj = objects_in_partial_slabs; 727 if (percentage_partial_slabs < min_ppart) 728 min_ppart = percentage_partial_slabs; 729 if (percentage_partial_objs < min_ppartobj) 730 min_ppartobj = percentage_partial_objs; 731 if (s->slab_size < min_memobj) 732 min_memobj = s->slab_size; 733 734 if (s->object_size > max_objsize) 735 max_objsize = s->object_size; 736 if (s->partial > max_partial) 737 max_partial = s->partial; 738 if (s->slabs > max_slabs) 739 max_slabs = s->slabs; 740 if (size > max_size) 741 max_size = size; 742 if (wasted > max_waste) 743 max_waste = wasted; 744 if (objwaste > max_objwaste) 745 max_objwaste = objwaste; 746 if (s->objects > max_objects) 747 max_objects = s->objects; 748 if (used > max_used) 749 max_used = used; 750 if (objects_in_partial_slabs > max_partobj) 751 max_partobj = objects_in_partial_slabs; 752 if (percentage_partial_slabs > max_ppart) 753 max_ppart = percentage_partial_slabs; 754 if (percentage_partial_objs > max_ppartobj) 755 max_ppartobj = percentage_partial_objs; 756 if (s->slab_size > max_memobj) 757 max_memobj = s->slab_size; 758 759 total_partial += s->partial; 760 total_slabs += s->slabs; 761 total_size += size; 762 total_waste += wasted; 763 764 total_objects += s->objects; 765 total_used += used; 766 total_partobj += objects_in_partial_slabs; 767 total_ppart += percentage_partial_slabs; 768 total_ppartobj += percentage_partial_objs; 769 770 total_objwaste += s->objects * objwaste; 771 total_objsize += s->objects * s->slab_size; 772 } 773 774 if (!total_objects) { 775 printf("No objects\n"); 776 return; 777 } 778 if (!used_slabs) { 779 printf("No slabs\n"); 780 return; 781 } 782 783 /* Per slab averages */ 784 avg_partial = total_partial / used_slabs; 785 avg_slabs = total_slabs / used_slabs; 786 avg_size = total_size / used_slabs; 787 avg_waste = total_waste / used_slabs; 788 789 avg_objects = total_objects / used_slabs; 790 avg_used = total_used / used_slabs; 791 avg_partobj = total_partobj / used_slabs; 792 avg_ppart = total_ppart / used_slabs; 793 avg_ppartobj = total_ppartobj / used_slabs; 794 795 /* Per object object sizes */ 796 avg_objsize = total_used / total_objects; 797 avg_objwaste = total_objwaste / total_objects; 798 avg_partobj = total_partobj * 100 / total_objects; 799 avg_memobj = total_objsize / total_objects; 800 801 printf("Slabcache Totals\n"); 802 printf("----------------\n"); 803 printf("Slabcaches : %3d Aliases : %3d->%-3d Active: %3d\n", 804 slabs, aliases, alias_targets, used_slabs); 805 806 store_size(b1, total_size);store_size(b2, total_waste); 807 store_size(b3, total_waste * 100 / total_used); 808 printf("Memory used: %6s # Loss : %6s MRatio:%6s%%\n", b1, b2, b3); 809 810 store_size(b1, total_objects);store_size(b2, total_partobj); 811 store_size(b3, total_partobj * 100 / total_objects); 812 printf("# Objects : %6s # PartObj: %6s ORatio:%6s%%\n", b1, b2, b3); 813 814 printf("\n"); 815 printf("Per Cache Average Min Max Total\n"); 816 printf("---------------------------------------------------------\n"); 817 818 store_size(b1, avg_objects);store_size(b2, min_objects); 819 store_size(b3, max_objects);store_size(b4, total_objects); 820 printf("#Objects %10s %10s %10s %10s\n", 821 b1, b2, b3, b4); 822 823 store_size(b1, avg_slabs);store_size(b2, min_slabs); 824 store_size(b3, max_slabs);store_size(b4, total_slabs); 825 printf("#Slabs %10s %10s %10s %10s\n", 826 b1, b2, b3, b4); 827 828 store_size(b1, avg_partial);store_size(b2, min_partial); 829 store_size(b3, max_partial);store_size(b4, total_partial); 830 printf("#PartSlab %10s %10s %10s %10s\n", 831 b1, b2, b3, b4); 832 store_size(b1, avg_ppart);store_size(b2, min_ppart); 833 store_size(b3, max_ppart); 834 store_size(b4, total_partial * 100 / total_slabs); 835 printf("%%PartSlab%10s%% %10s%% %10s%% %10s%%\n", 836 b1, b2, b3, b4); 837 838 store_size(b1, avg_partobj);store_size(b2, min_partobj); 839 store_size(b3, max_partobj); 840 store_size(b4, total_partobj); 841 printf("PartObjs %10s %10s %10s %10s\n", 842 b1, b2, b3, b4); 843 844 store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj); 845 store_size(b3, max_ppartobj); 846 store_size(b4, total_partobj * 100 / total_objects); 847 printf("%% PartObj%10s%% %10s%% %10s%% %10s%%\n", 848 b1, b2, b3, b4); 849 850 store_size(b1, avg_size);store_size(b2, min_size); 851 store_size(b3, max_size);store_size(b4, total_size); 852 printf("Memory %10s %10s %10s %10s\n", 853 b1, b2, b3, b4); 854 855 store_size(b1, avg_used);store_size(b2, min_used); 856 store_size(b3, max_used);store_size(b4, total_used); 857 printf("Used %10s %10s %10s %10s\n", 858 b1, b2, b3, b4); 859 860 store_size(b1, avg_waste);store_size(b2, min_waste); 861 store_size(b3, max_waste);store_size(b4, total_waste); 862 printf("Loss %10s %10s %10s %10s\n", 863 b1, b2, b3, b4); 864 865 printf("\n"); 866 printf("Per Object Average Min Max\n"); 867 printf("---------------------------------------------\n"); 868 869 store_size(b1, avg_memobj);store_size(b2, min_memobj); 870 store_size(b3, max_memobj); 871 printf("Memory %10s %10s %10s\n", 872 b1, b2, b3); 873 store_size(b1, avg_objsize);store_size(b2, min_objsize); 874 store_size(b3, max_objsize); 875 printf("User %10s %10s %10s\n", 876 b1, b2, b3); 877 878 store_size(b1, avg_objwaste);store_size(b2, min_objwaste); 879 store_size(b3, max_objwaste); 880 printf("Loss %10s %10s %10s\n", 881 b1, b2, b3); 882} 883 884void sort_slabs(void) 885{ 886 struct slabinfo *s1,*s2; 887 888 for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) { 889 for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) { 890 int result; 891 892 if (sort_size) 893 result = slab_size(s1) < slab_size(s2); 894 else 895 result = strcasecmp(s1->name, s2->name); 896 897 if (show_inverted) 898 result = -result; 899 900 if (result > 0) { 901 struct slabinfo t; 902 903 memcpy(&t, s1, sizeof(struct slabinfo)); 904 memcpy(s1, s2, sizeof(struct slabinfo)); 905 memcpy(s2, &t, sizeof(struct slabinfo)); 906 } 907 } 908 } 909} 910 911void sort_aliases(void) 912{ 913 struct aliasinfo *a1,*a2; 914 915 for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) { 916 for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) { 917 char *n1, *n2; 918 919 n1 = a1->name; 920 n2 = a2->name; 921 if (show_alias && !show_inverted) { 922 n1 = a1->ref; 923 n2 = a2->ref; 924 } 925 if (strcasecmp(n1, n2) > 0) { 926 struct aliasinfo t; 927 928 memcpy(&t, a1, sizeof(struct aliasinfo)); 929 memcpy(a1, a2, sizeof(struct aliasinfo)); 930 memcpy(a2, &t, sizeof(struct aliasinfo)); 931 } 932 } 933 } 934} 935 936void link_slabs(void) 937{ 938 struct aliasinfo *a; 939 struct slabinfo *s; 940 941 for (a = aliasinfo; a < aliasinfo + aliases; a++) { 942 943 for (s = slabinfo; s < slabinfo + slabs; s++) 944 if (strcmp(a->ref, s->name) == 0) { 945 a->slab = s; 946 s->refs++; 947 break; 948 } 949 if (s == slabinfo + slabs) 950 fatal("Unresolved alias %s\n", a->ref); 951 } 952} 953 954void alias(void) 955{ 956 struct aliasinfo *a; 957 char *active = NULL; 958 959 sort_aliases(); 960 link_slabs(); 961 962 for(a = aliasinfo; a < aliasinfo + aliases; a++) { 963 964 if (!show_single_ref && a->slab->refs == 1) 965 continue; 966 967 if (!show_inverted) { 968 if (active) { 969 if (strcmp(a->slab->name, active) == 0) { 970 printf(" %s", a->name); 971 continue; 972 } 973 } 974 printf("\n%-12s <- %s", a->slab->name, a->name); 975 active = a->slab->name; 976 } 977 else 978 printf("%-20s -> %s\n", a->name, a->slab->name); 979 } 980 if (active) 981 printf("\n"); 982} 983 984 985void rename_slabs(void) 986{ 987 struct slabinfo *s; 988 struct aliasinfo *a; 989 990 for (s = slabinfo; s < slabinfo + slabs; s++) { 991 if (*s->name != ':') 992 continue; 993 994 if (s->refs > 1 && !show_first_alias) 995 continue; 996 997 a = find_one_alias(s); 998 999 if (a) 1000 s->name = a->name; 1001 else { 1002 s->name = "*"; 1003 actual_slabs--; 1004 } 1005 } 1006} 1007 1008int slab_mismatch(char *slab) 1009{ 1010 return regexec(&pattern, slab, 0, NULL, 0); 1011} 1012 1013void read_slab_dir(void) 1014{ 1015 DIR *dir; 1016 struct dirent *de; 1017 struct slabinfo *slab = slabinfo; 1018 struct aliasinfo *alias = aliasinfo; 1019 char *p; 1020 char *t; 1021 int count; 1022 1023 if (chdir("/sys/slab")) 1024 fatal("SYSFS support for SLUB not active\n"); 1025 1026 dir = opendir("."); 1027 while ((de = readdir(dir))) { 1028 if (de->d_name[0] == '.' || 1029 (de->d_name[0] != ':' && slab_mismatch(de->d_name))) 1030 continue; 1031 switch (de->d_type) { 1032 case DT_LNK: 1033 alias->name = strdup(de->d_name); 1034 count = readlink(de->d_name, buffer, sizeof(buffer)); 1035 1036 if (count < 0) 1037 fatal("Cannot read symlink %s\n", de->d_name); 1038 1039 buffer[count] = 0; 1040 p = buffer + count; 1041 while (p > buffer && p[-1] != '/') 1042 p--; 1043 alias->ref = strdup(p); 1044 alias++; 1045 break; 1046 case DT_DIR: 1047 if (chdir(de->d_name)) 1048 fatal("Unable to access slab %s\n", slab->name); 1049 slab->name = strdup(de->d_name); 1050 slab->alias = 0; 1051 slab->refs = 0; 1052 slab->aliases = get_obj("aliases"); 1053 slab->align = get_obj("align"); 1054 slab->cache_dma = get_obj("cache_dma"); 1055 slab->cpu_slabs = get_obj("cpu_slabs"); 1056 slab->destroy_by_rcu = get_obj("destroy_by_rcu"); 1057 slab->hwcache_align = get_obj("hwcache_align"); 1058 slab->object_size = get_obj("object_size"); 1059 slab->objects = get_obj("objects"); 1060 slab->objs_per_slab = get_obj("objs_per_slab"); 1061 slab->order = get_obj("order"); 1062 slab->partial = get_obj("partial"); 1063 slab->partial = get_obj_and_str("partial", &t); 1064 decode_numa_list(slab->numa_partial, t); 1065 slab->poison = get_obj("poison"); 1066 slab->reclaim_account = get_obj("reclaim_account"); 1067 slab->red_zone = get_obj("red_zone"); 1068 slab->sanity_checks = get_obj("sanity_checks"); 1069 slab->slab_size = get_obj("slab_size"); 1070 slab->slabs = get_obj_and_str("slabs", &t); 1071 decode_numa_list(slab->numa, t); 1072 slab->store_user = get_obj("store_user"); 1073 slab->trace = get_obj("trace"); 1074 chdir(".."); 1075 if (slab->name[0] == ':') 1076 alias_targets++; 1077 slab++; 1078 break; 1079 default : 1080 fatal("Unknown file type %lx\n", de->d_type); 1081 } 1082 } 1083 closedir(dir); 1084 slabs = slab - slabinfo; 1085 actual_slabs = slabs; 1086 aliases = alias - aliasinfo; 1087 if (slabs > MAX_SLABS) 1088 fatal("Too many slabs\n"); 1089 if (aliases > MAX_ALIASES) 1090 fatal("Too many aliases\n"); 1091} 1092 1093void output_slabs(void) 1094{ 1095 struct slabinfo *slab; 1096 1097 for (slab = slabinfo; slab < slabinfo + slabs; slab++) { 1098 1099 if (slab->alias) 1100 continue; 1101 1102 1103 if (show_numa) 1104 slab_numa(slab, 0); 1105 else if (show_track) 1106 show_tracking(slab); 1107 else if (validate) 1108 slab_validate(slab); 1109 else if (shrink) 1110 slab_shrink(slab); 1111 else if (set_debug) 1112 slab_debug(slab); 1113 else if (show_ops) 1114 ops(slab); 1115 else if (show_slab) 1116 slabcache(slab); 1117 else if (show_report) 1118 report(slab); 1119 } 1120} 1121 1122struct option opts[] = { 1123 { "aliases", 0, NULL, 'a' }, 1124 { "debug", 2, NULL, 'd' }, 1125 { "empty", 0, NULL, 'e' }, 1126 { "first-alias", 0, NULL, 'f' }, 1127 { "help", 0, NULL, 'h' }, 1128 { "inverted", 0, NULL, 'i'}, 1129 { "numa", 0, NULL, 'n' }, 1130 { "ops", 0, NULL, 'o' }, 1131 { "report", 0, NULL, 'r' }, 1132 { "shrink", 0, NULL, 's' }, 1133 { "slabs", 0, NULL, 'l' }, 1134 { "track", 0, NULL, 't'}, 1135 { "validate", 0, NULL, 'v' }, 1136 { "zero", 0, NULL, 'z' }, 1137 { "1ref", 0, NULL, '1'}, 1138 { NULL, 0, NULL, 0 } 1139}; 1140 1141int main(int argc, char *argv[]) 1142{ 1143 int c; 1144 int err; 1145 char *pattern_source; 1146 1147 page_size = getpagesize(); 1148 1149 while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS", 1150 opts, NULL)) != -1) 1151 switch(c) { 1152 case '1': 1153 show_single_ref = 1; 1154 break; 1155 case 'a': 1156 show_alias = 1; 1157 break; 1158 case 'd': 1159 set_debug = 1; 1160 if (!debug_opt_scan(optarg)) 1161 fatal("Invalid debug option '%s'\n", optarg); 1162 break; 1163 case 'e': 1164 show_empty = 1; 1165 break; 1166 case 'f': 1167 show_first_alias = 1; 1168 break; 1169 case 'h': 1170 usage(); 1171 return 0; 1172 case 'i': 1173 show_inverted = 1; 1174 break; 1175 case 'n': 1176 show_numa = 1; 1177 break; 1178 case 'o': 1179 show_ops = 1; 1180 break; 1181 case 'r': 1182 show_report = 1; 1183 break; 1184 case 's': 1185 shrink = 1; 1186 break; 1187 case 'l': 1188 show_slab = 1; 1189 break; 1190 case 't': 1191 show_track = 1; 1192 break; 1193 case 'v': 1194 validate = 1; 1195 break; 1196 case 'z': 1197 skip_zero = 0; 1198 break; 1199 case 'T': 1200 show_totals = 1; 1201 break; 1202 case 'S': 1203 sort_size = 1; 1204 break; 1205 1206 default: 1207 fatal("%s: Invalid option '%c'\n", argv[0], optopt); 1208 1209 } 1210 1211 if (!show_slab && !show_alias && !show_track && !show_report 1212 && !validate && !shrink && !set_debug && !show_ops) 1213 show_slab = 1; 1214 1215 if (argc > optind) 1216 pattern_source = argv[optind]; 1217 else 1218 pattern_source = ".*"; 1219 1220 err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB); 1221 if (err) 1222 fatal("%s: Invalid pattern '%s' code %d\n", 1223 argv[0], pattern_source, err); 1224 read_slab_dir(); 1225 if (show_alias) 1226 alias(); 1227 else 1228 if (show_totals) 1229 totals(); 1230 else { 1231 link_slabs(); 1232 rename_slabs(); 1233 sort_slabs(); 1234 output_slabs(); 1235 } 1236 return 0; 1237} 1238