Commit a87615b8f9e2349f6d3770af3d72fd6a41ab4239

Authored by Christoph Lameter
Committed by Linus Torvalds
1 parent be7b3fbcef

SLUB: slabinfo upgrade

-e Show empty slabs
-d Modification of slab debug options at runtime
-o Operations. Display of ctor / dtor etc.
-r Report: Display all available information about a slabcache.

Cleanup tracking display and make it work right.

Signed-off-by: Christoph Lameter <clameter@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 352 additions and 74 deletions Side-by-side Diff

Documentation/vm/slabinfo.c
... ... @@ -16,6 +16,7 @@
16 16 #include <stdarg.h>
17 17 #include <getopt.h>
18 18 #include <regex.h>
  19 +#include <errno.h>
19 20  
20 21 #define MAX_SLABS 500
21 22 #define MAX_ALIASES 500
22 23  
... ... @@ -41,12 +42,15 @@
41 42 } aliasinfo[MAX_ALIASES];
42 43  
43 44 int slabs = 0;
  45 +int actual_slabs = 0;
44 46 int aliases = 0;
45 47 int alias_targets = 0;
46 48 int highest_node = 0;
47 49  
48 50 char buffer[4096];
49 51  
  52 +int show_empty = 0;
  53 +int show_report = 0;
50 54 int show_alias = 0;
51 55 int show_slab = 0;
52 56 int skip_zero = 1;
53 57  
... ... @@ -59,7 +63,16 @@
59 63 int show_single_ref = 0;
60 64 int show_totals = 0;
61 65 int sort_size = 0;
  66 +int set_debug = 0;
  67 +int show_ops = 0;
62 68  
  69 +/* Debug options */
  70 +int sanity = 0;
  71 +int redzone = 0;
  72 +int poison = 0;
  73 +int tracking = 0;
  74 +int tracing = 0;
  75 +
63 76 int page_size;
64 77  
65 78 regex_t pattern;
66 79  
67 80  
68 81  
69 82  
70 83  
71 84  
72 85  
... ... @@ -76,20 +89,33 @@
76 89  
77 90 void usage(void)
78 91 {
79   - printf("slabinfo [-ahnpvtsz] [slab-regexp]\n"
  92 + printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n"
  93 + "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
80 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"
81 98 "-h|--help Show usage information\n"
  99 + "-i|--inverted Inverted list\n"
  100 + "-l|--slabs Show slabs\n"
82 101 "-n|--numa Show NUMA information\n"
  102 + "-o|--ops Show kmem_cache_ops\n"
83 103 "-s|--shrink Shrink slabs\n"
84   - "-v|--validate Validate slabs\n"
  104 + "-r|--report Detailed report on single slabs\n"
  105 + "-S|--Size Sort by size\n"
85 106 "-t|--tracking Show alloc/free information\n"
86 107 "-T|--Totals Show summary information\n"
87   - "-l|--slabs Show slabs\n"
88   - "-S|--Size Sort by size\n"
  108 + "-v|--validate Validate slabs\n"
89 109 "-z|--zero Include empty slabs\n"
90   - "-f|--first-alias Show first alias\n"
91   - "-i|--inverted Inverted list\n"
92 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"
93 119 );
94 120 }
95 121  
96 122  
... ... @@ -143,11 +169,10 @@
143 169 void set_obj(struct slabinfo *s, char *name, int n)
144 170 {
145 171 char x[100];
  172 + FILE *f;
146 173  
147 174 sprintf(x, "%s/%s", s->name, name);
148   -
149   - FILE *f = fopen(x, "w");
150   -
  175 + f = fopen(x, "w");
151 176 if (!f)
152 177 fatal("Cannot write to %s\n", x);
153 178  
... ... @@ -155,6 +180,26 @@
155 180 fclose(f);
156 181 }
157 182  
  183 +unsigned 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 +
158 203 /*
159 204 * Put a size string together
160 205 */
... ... @@ -226,7 +271,7 @@
226 271  
227 272 void first_line(void)
228 273 {
229   - printf("Name Objects Objsize Space "
  274 + printf("Name Objects Objsize Space "
230 275 "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
231 276 }
232 277  
... ... @@ -246,10 +291,7 @@
246 291 return best;
247 292 }
248 293 }
249   - if (best)
250   - return best;
251   - fatal("Cannot find alias for %s\n", find->name);
252   - return NULL;
  294 + return best;
253 295 }
254 296  
255 297 unsigned long slab_size(struct slabinfo *s)
256 298  
... ... @@ -257,7 +299,127 @@
257 299 return s->slabs * (page_size << s->order);
258 300 }
259 301  
  302 +void slab_numa(struct slabinfo *s, int mode)
  303 +{
  304 + int node;
260 305  
  306 + if (strcmp(s->name, "*") == 0)
  307 + return;
  308 +
  309 + if (!highest_node) {
  310 + printf("\n%s: No NUMA information available.\n", s->name);
  311 + return;
  312 + }
  313 +
  314 + if (skip_zero && !s->slabs)
  315 + return;
  316 +
  317 + if (!line) {
  318 + printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
  319 + for(node = 0; node <= highest_node; node++)
  320 + printf(" %4d", node);
  321 + printf("\n----------------------");
  322 + for(node = 0; node <= highest_node; node++)
  323 + printf("-----");
  324 + printf("\n");
  325 + }
  326 + printf("%-21s ", mode ? "All slabs" : s->name);
  327 + for(node = 0; node <= highest_node; node++) {
  328 + char b[20];
  329 +
  330 + store_size(b, s->numa[node]);
  331 + printf(" %4s", b);
  332 + }
  333 + printf("\n");
  334 + if (mode) {
  335 + printf("%-21s ", "Partial slabs");
  336 + for(node = 0; node <= highest_node; node++) {
  337 + char b[20];
  338 +
  339 + store_size(b, s->numa_partial[node]);
  340 + printf(" %4s", b);
  341 + }
  342 + printf("\n");
  343 + }
  344 + line++;
  345 +}
  346 +
  347 +void show_tracking(struct slabinfo *s)
  348 +{
  349 + printf("\n%s: Kernel object allocation\n", s->name);
  350 + printf("-----------------------------------------------------------------------\n");
  351 + if (read_slab_obj(s, "alloc_calls"))
  352 + printf(buffer);
  353 + else
  354 + printf("No Data\n");
  355 +
  356 + printf("\n%s: Kernel object freeing\n", s->name);
  357 + printf("------------------------------------------------------------------------\n");
  358 + if (read_slab_obj(s, "free_calls"))
  359 + printf(buffer);
  360 + else
  361 + printf("No Data\n");
  362 +
  363 +}
  364 +
  365 +void ops(struct slabinfo *s)
  366 +{
  367 + if (strcmp(s->name, "*") == 0)
  368 + return;
  369 +
  370 + if (read_slab_obj(s, "ops")) {
  371 + printf("\n%s: kmem_cache operations\n", s->name);
  372 + printf("--------------------------------------------\n");
  373 + printf(buffer);
  374 + } else
  375 + printf("\n%s has no kmem_cache operations\n", s->name);
  376 +}
  377 +
  378 +const char *onoff(int x)
  379 +{
  380 + if (x)
  381 + return "On ";
  382 + return "Off";
  383 +}
  384 +
  385 +void report(struct slabinfo *s)
  386 +{
  387 + if (strcmp(s->name, "*") == 0)
  388 + return;
  389 + printf("\nSlabcache: %-20s Aliases: %2d Order : %2d\n", s->name, s->aliases, s->order);
  390 + if (s->hwcache_align)
  391 + printf("** Hardware cacheline aligned\n");
  392 + if (s->cache_dma)
  393 + printf("** Memory is allocated in a special DMA zone\n");
  394 + if (s->destroy_by_rcu)
  395 + printf("** Slabs are destroyed via RCU\n");
  396 + if (s->reclaim_account)
  397 + printf("** Reclaim accounting active\n");
  398 +
  399 + printf("\nSizes (bytes) Slabs Debug Memory\n");
  400 + printf("------------------------------------------------------------------------\n");
  401 + printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n",
  402 + s->object_size, s->slabs, onoff(s->sanity_checks),
  403 + s->slabs * (page_size << s->order));
  404 + printf("SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld\n",
  405 + s->slab_size, s->slabs - s->partial - s->cpu_slabs,
  406 + onoff(s->red_zone), s->objects * s->object_size);
  407 + printf("SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld\n",
  408 + page_size << s->order, s->partial, onoff(s->poison),
  409 + s->slabs * (page_size << s->order) - s->objects * s->object_size);
  410 + printf("Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld\n",
  411 + s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
  412 + (s->slab_size - s->object_size) * s->objects);
  413 + printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n",
  414 + s->align, s->objs_per_slab, onoff(s->trace),
  415 + ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
  416 + s->slabs);
  417 +
  418 + ops(s);
  419 + show_tracking(s);
  420 + slab_numa(s, 1);
  421 +}
  422 +
261 423 void slabcache(struct slabinfo *s)
262 424 {
263 425 char size_str[20];
264 426  
... ... @@ -265,9 +427,20 @@
265 427 char flags[20];
266 428 char *p = flags;
267 429  
268   - if (skip_zero && !s->slabs)
  430 + if (strcmp(s->name, "*") == 0)
269 431 return;
270 432  
  433 + if (actual_slabs == 1) {
  434 + report(s);
  435 + return;
  436 + }
  437 +
  438 + if (skip_zero && !show_empty && !s->slabs)
  439 + return;
  440 +
  441 + if (show_empty && s->slabs)
  442 + return;
  443 +
271 444 store_size(size_str, slab_size(s));
272 445 sprintf(dist_str,"%lu/%lu/%d", s->slabs, s->partial, s->cpu_slabs);
273 446  
274 447  
275 448  
276 449  
277 450  
278 451  
279 452  
280 453  
281 454  
282 455  
283 456  
... ... @@ -303,50 +476,130 @@
303 476 flags);
304 477 }
305 478  
306   -void slab_numa(struct slabinfo *s)
  479 +/*
  480 + * Analyze debug options. Return false if something is amiss.
  481 + */
  482 +int debug_opt_scan(char *opt)
307 483 {
308   - int node;
  484 + if (!opt || !opt[0] || strcmp(opt, "-") == 0)
  485 + return 1;
309 486  
310   - if (!highest_node)
311   - fatal("No NUMA information available.\n");
  487 + if (strcasecmp(opt, "a") == 0) {
  488 + sanity = 1;
  489 + poison = 1;
  490 + redzone = 1;
  491 + tracking = 1;
  492 + return 1;
  493 + }
312 494  
313   - if (skip_zero && !s->slabs)
314   - return;
  495 + for ( ; *opt; opt++)
  496 + switch (*opt) {
  497 + case 'F' : case 'f':
  498 + if (sanity)
  499 + return 0;
  500 + sanity = 1;
  501 + break;
  502 + case 'P' : case 'p':
  503 + if (poison)
  504 + return 0;
  505 + poison = 1;
  506 + break;
315 507  
316   - if (!line) {
317   - printf("\nSlab Node ");
318   - for(node = 0; node <= highest_node; node++)
319   - printf(" %4d", node);
320   - printf("\n----------------------");
321   - for(node = 0; node <= highest_node; node++)
322   - printf("-----");
323   - printf("\n");
324   - }
325   - printf("%-21s ", s->name);
326   - for(node = 0; node <= highest_node; node++) {
327   - char b[20];
  508 + case 'Z' : case 'z':
  509 + if (redzone)
  510 + return 0;
  511 + redzone = 1;
  512 + break;
328 513  
329   - store_size(b, s->numa[node]);
330   - printf(" %4s", b);
331   - }
332   - printf("\n");
333   - line++;
  514 + case 'U' : case 'u':
  515 + if (tracking)
  516 + return 0;
  517 + tracking = 1;
  518 + break;
  519 +
  520 + case 'T' : case 't':
  521 + if (tracing)
  522 + return 0;
  523 + tracing = 1;
  524 + break;
  525 + default:
  526 + return 0;
  527 + }
  528 + return 1;
334 529 }
335 530  
336   -void show_tracking(struct slabinfo *s)
  531 +int slab_empty(struct slabinfo *s)
337 532 {
338   - printf("\n%s: Calls to allocate a slab object\n", s->name);
339   - printf("---------------------------------------------------\n");
340   - if (read_obj("alloc_calls"))
341   - printf(buffer);
  533 + if (s->objects > 0)
  534 + return 0;
342 535  
343   - printf("%s: Calls to free a slab object\n", s->name);
344   - printf("-----------------------------------------------\n");
345   - if (read_obj("free_calls"))
346   - printf(buffer);
  536 + /*
  537 + * We may still have slabs even if there are no objects. Shrinking will
  538 + * remove them.
  539 + */
  540 + if (s->slabs != 0)
  541 + set_obj(s, "shrink", 1);
347 542  
  543 + return 1;
348 544 }
349 545  
  546 +void slab_debug(struct slabinfo *s)
  547 +{
  548 + if (sanity && !s->sanity_checks) {
  549 + set_obj(s, "sanity", 1);
  550 + }
  551 + if (!sanity && s->sanity_checks) {
  552 + if (slab_empty(s))
  553 + set_obj(s, "sanity", 0);
  554 + else
  555 + fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
  556 + }
  557 + if (redzone && !s->red_zone) {
  558 + if (slab_empty(s))
  559 + set_obj(s, "red_zone", 1);
  560 + else
  561 + fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
  562 + }
  563 + if (!redzone && s->red_zone) {
  564 + if (slab_empty(s))
  565 + set_obj(s, "red_zone", 0);
  566 + else
  567 + fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
  568 + }
  569 + if (poison && !s->poison) {
  570 + if (slab_empty(s))
  571 + set_obj(s, "poison", 1);
  572 + else
  573 + fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
  574 + }
  575 + if (!poison && s->poison) {
  576 + if (slab_empty(s))
  577 + set_obj(s, "poison", 0);
  578 + else
  579 + fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
  580 + }
  581 + if (tracking && !s->store_user) {
  582 + if (slab_empty(s))
  583 + set_obj(s, "store_user", 1);
  584 + else
  585 + fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
  586 + }
  587 + if (!tracking && s->store_user) {
  588 + if (slab_empty(s))
  589 + set_obj(s, "store_user", 0);
  590 + else
  591 + fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
  592 + }
  593 + if (tracing && !s->trace) {
  594 + if (slabs == 1)
  595 + set_obj(s, "trace", 1);
  596 + else
  597 + fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
  598 + }
  599 + if (!tracing && s->trace)
  600 + set_obj(s, "trace", 1);
  601 +}
  602 +
350 603 void totals(void)
351 604 {
352 605 struct slabinfo *s;
... ... @@ -673,7 +926,7 @@
673 926  
674 927 for (a = aliasinfo; a < aliasinfo + aliases; a++) {
675 928  
676   - for(s = slabinfo; s < slabinfo + slabs; s++)
  929 + for (s = slabinfo; s < slabinfo + slabs; s++)
677 930 if (strcmp(a->ref, s->name) == 0) {
678 931 a->slab = s;
679 932 s->refs++;
... ... @@ -704,7 +957,7 @@
704 957 continue;
705 958 }
706 959 }
707   - printf("\n%-20s <- %s", a->slab->name, a->name);
  960 + printf("\n%-12s <- %s", a->slab->name, a->name);
708 961 active = a->slab->name;
709 962 }
710 963 else
... ... @@ -729,7 +982,12 @@
729 982  
730 983 a = find_one_alias(s);
731 984  
732   - s->name = a->name;
  985 + if (a)
  986 + s->name = a->name;
  987 + else {
  988 + s->name = "*";
  989 + actual_slabs--;
  990 + }
733 991 }
734 992 }
735 993  
736 994  
... ... @@ -748,11 +1006,14 @@
748 1006 char *t;
749 1007 int count;
750 1008  
  1009 + if (chdir("/sys/slab"))
  1010 + fatal("SYSFS support for SLUB not active\n");
  1011 +
751 1012 dir = opendir(".");
752 1013 while ((de = readdir(dir))) {
753 1014 if (de->d_name[0] == '.' ||
754   - slab_mismatch(de->d_name))
755   - continue;
  1015 + (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
  1016 + continue;
756 1017 switch (de->d_type) {
757 1018 case DT_LNK:
758 1019 alias->name = strdup(de->d_name);
... ... @@ -807,6 +1068,7 @@
807 1068 }
808 1069 closedir(dir);
809 1070 slabs = slab - slabinfo;
  1071 + actual_slabs = slabs;
810 1072 aliases = alias - aliasinfo;
811 1073 if (slabs > MAX_SLABS)
812 1074 fatal("Too many slabs\n");
813 1075  
814 1076  
815 1077  
816 1078  
817 1079  
818 1080  
819 1081  
... ... @@ -825,34 +1087,37 @@
825 1087  
826 1088  
827 1089 if (show_numa)
828   - slab_numa(slab);
829   - else
830   - if (show_track)
  1090 + slab_numa(slab, 0);
  1091 + else if (show_track)
831 1092 show_tracking(slab);
832   - else
833   - if (validate)
  1093 + else if (validate)
834 1094 slab_validate(slab);
835   - else
836   - if (shrink)
  1095 + else if (shrink)
837 1096 slab_shrink(slab);
838   - else {
839   - if (show_slab)
840   - slabcache(slab);
841   - }
  1097 + else if (set_debug)
  1098 + slab_debug(slab);
  1099 + else if (show_ops)
  1100 + ops(slab);
  1101 + else if (show_slab)
  1102 + slabcache(slab);
842 1103 }
843 1104 }
844 1105  
845 1106 struct option opts[] = {
846 1107 { "aliases", 0, NULL, 'a' },
847   - { "slabs", 0, NULL, 'l' },
848   - { "numa", 0, NULL, 'n' },
849   - { "zero", 0, NULL, 'z' },
850   - { "help", 0, NULL, 'h' },
851   - { "validate", 0, NULL, 'v' },
  1108 + { "debug", 2, NULL, 'd' },
  1109 + { "empty", 0, NULL, 'e' },
852 1110 { "first-alias", 0, NULL, 'f' },
  1111 + { "help", 0, NULL, 'h' },
  1112 + { "inverted", 0, NULL, 'i'},
  1113 + { "numa", 0, NULL, 'n' },
  1114 + { "ops", 0, NULL, 'o' },
  1115 + { "report", 0, NULL, 'r' },
853 1116 { "shrink", 0, NULL, 's' },
  1117 + { "slabs", 0, NULL, 'l' },
854 1118 { "track", 0, NULL, 't'},
855   - { "inverted", 0, NULL, 'i'},
  1119 + { "validate", 0, NULL, 'v' },
  1120 + { "zero", 0, NULL, 'z' },
856 1121 { "1ref", 0, NULL, '1'},
857 1122 { NULL, 0, NULL, 0 }
858 1123 };
859 1124  
... ... @@ -864,10 +1129,9 @@
864 1129 char *pattern_source;
865 1130  
866 1131 page_size = getpagesize();
867   - if (chdir("/sys/slab"))
868   - fatal("This kernel does not have SLUB support.\n");
869 1132  
870   - while ((c = getopt_long(argc, argv, "afhil1npstvzTS", opts, NULL)) != -1)
  1133 + while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS",
  1134 + opts, NULL)) != -1)
871 1135 switch(c) {
872 1136 case '1':
873 1137 show_single_ref = 1;
... ... @@ -875,6 +1139,14 @@
875 1139 case 'a':
876 1140 show_alias = 1;
877 1141 break;
  1142 + case 'd':
  1143 + set_debug = 1;
  1144 + if (!debug_opt_scan(optarg))
  1145 + fatal("Invalid debug option '%s'\n", optarg);
  1146 + break;
  1147 + case 'e':
  1148 + show_empty = 1;
  1149 + break;
878 1150 case 'f':
879 1151 show_first_alias = 1;
880 1152 break;
... ... @@ -887,6 +1159,12 @@
887 1159 case 'n':
888 1160 show_numa = 1;
889 1161 break;
  1162 + case 'o':
  1163 + show_ops = 1;
  1164 + break;
  1165 + case 'r':
  1166 + show_report = 1;
  1167 + break;
890 1168 case 's':
891 1169 shrink = 1;
892 1170 break;
... ... @@ -914,8 +1192,8 @@
914 1192  
915 1193 }
916 1194  
917   - if (!show_slab && !show_alias && !show_track
918   - && !validate && !shrink)
  1195 + if (!show_slab && !show_alias && !show_track && !show_report
  1196 + && !validate && !shrink && !set_debug && !show_ops)
919 1197 show_slab = 1;
920 1198  
921 1199 if (argc > optind)