X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=Documentation%2Fvm%2Fslabinfo.c;h=df3227605d59bf594c3a962a7bf08d9e8d5097a9;hb=acee709cab689ec7703770e8b8cb5cc3a4abcb31;hp=41710ccf3a29a1f138537de5c96d00f429289096;hpb=c09d87517298fd01543739ba26987645deb4e6a9;p=safe%2Fjmp%2Flinux-2.6 diff --git a/Documentation/vm/slabinfo.c b/Documentation/vm/slabinfo.c index 41710cc..df32276 100644 --- a/Documentation/vm/slabinfo.c +++ b/Documentation/vm/slabinfo.c @@ -1,7 +1,7 @@ /* * Slabinfo: Tool to get reports about slabs * - * (C) 2007 sgi, Christoph Lameter + * (C) 2007 sgi, Christoph Lameter * * Compile by: * @@ -11,11 +11,13 @@ #include #include #include +#include #include #include #include #include #include +#include #define MAX_SLABS 500 #define MAX_ALIASES 500 @@ -29,7 +31,14 @@ struct slabinfo { int hwcache_align, object_size, objs_per_slab; int sanity_checks, slab_size, store_user, trace; int order, poison, reclaim_account, red_zone; - unsigned long partial, objects, slabs; + unsigned long partial, objects, slabs, objects_partial, objects_total; + unsigned long alloc_fastpath, alloc_slowpath; + unsigned long free_fastpath, free_slowpath; + unsigned long free_frozen, free_add_partial, free_remove_partial; + unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill; + unsigned long cpuslab_flush, deactivate_full, deactivate_empty; + unsigned long deactivate_to_head, deactivate_to_tail; + unsigned long deactivate_remote_frees, order_fallback; int numa[MAX_NODES]; int numa_partial[MAX_NODES]; } slabinfo[MAX_SLABS]; @@ -41,12 +50,15 @@ struct aliasinfo { } aliasinfo[MAX_ALIASES]; int slabs = 0; +int actual_slabs = 0; int aliases = 0; int alias_targets = 0; int highest_node = 0; char buffer[4096]; +int show_empty = 0; +int show_report = 0; int show_alias = 0; int show_slab = 0; int skip_zero = 1; @@ -59,6 +71,17 @@ int show_inverted = 0; int show_single_ref = 0; int show_totals = 0; int sort_size = 0; +int sort_active = 0; +int set_debug = 0; +int show_ops = 0; +int show_activity = 0; + +/* Debug options */ +int sanity = 0; +int redzone = 0; +int poison = 0; +int tracking = 0; +int tracing = 0; int page_size; @@ -71,36 +94,51 @@ void fatal(const char *x, ...) va_start(ap, x); vfprintf(stderr, x, ap); va_end(ap); - exit(1); + exit(EXIT_FAILURE); } void usage(void) { - printf("slabinfo [-ahnpvtsz] [slab-regexp]\n" + printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n" + "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n" "-a|--aliases Show aliases\n" + "-A|--activity Most active slabs first\n" + "-d|--debug= Set/Clear Debug options\n" + "-D|--display-active Switch line format to activity\n" + "-e|--empty Show empty slabs\n" + "-f|--first-alias Show first alias\n" "-h|--help Show usage information\n" + "-i|--inverted Inverted list\n" + "-l|--slabs Show slabs\n" "-n|--numa Show NUMA information\n" + "-o|--ops Show kmem_cache_ops\n" "-s|--shrink Shrink slabs\n" - "-v|--validate Validate slabs\n" + "-r|--report Detailed report on single slabs\n" + "-S|--Size Sort by size\n" "-t|--tracking Show alloc/free information\n" "-T|--Totals Show summary information\n" - "-l|--slabs Show slabs\n" - "-S|--Size Sort by size\n" + "-v|--validate Validate slabs\n" "-z|--zero Include empty slabs\n" - "-f|--first-alias Show first alias\n" - "-i|--inverted Inverted list\n" "-1|--1ref Single reference\n" + "\nValid debug options (FZPUT may be combined)\n" + "a / A Switch on all debug options (=FZUP)\n" + "- Switch off all debug options\n" + "f / F Sanity Checks (SLAB_DEBUG_FREE)\n" + "z / Z Redzoning\n" + "p / P Poisoning\n" + "u / U Tracking\n" + "t / T Tracing\n" ); } -unsigned long read_obj(char *name) +unsigned long read_obj(const char *name) { FILE *f = fopen(name, "r"); if (!f) buffer[0] = 0; else { - if (!fgets(buffer,sizeof(buffer), f)) + if (!fgets(buffer, sizeof(buffer), f)) buffer[0] = 0; fclose(f); if (buffer[strlen(buffer)] == '\n') @@ -113,7 +151,7 @@ unsigned long read_obj(char *name) /* * Get the contents of an attribute */ -unsigned long get_obj(char *name) +unsigned long get_obj(const char *name) { if (!read_obj(name)) return 0; @@ -121,7 +159,7 @@ unsigned long get_obj(char *name) return atol(buffer); } -unsigned long get_obj_and_str(char *name, char **x) +unsigned long get_obj_and_str(const char *name, char **x) { unsigned long result = 0; char *p; @@ -140,14 +178,13 @@ unsigned long get_obj_and_str(char *name, char **x) return result; } -void set_obj(struct slabinfo *s, char *name, int n) +void set_obj(struct slabinfo *s, const char *name, int n) { char x[100]; + FILE *f; - sprintf(x, "%s/%s", s->name, name); - - FILE *f = fopen(x, "w"); - + snprintf(x, 100, "%s/%s", s->name, name); + f = fopen(x, "w"); if (!f) fatal("Cannot write to %s\n", x); @@ -155,6 +192,26 @@ void set_obj(struct slabinfo *s, char *name, int n) fclose(f); } +unsigned long read_slab_obj(struct slabinfo *s, const char *name) +{ + char x[100]; + FILE *f; + size_t l; + + snprintf(x, 100, "%s/%s", s->name, name); + f = fopen(x, "r"); + if (!f) { + buffer[0] = 0; + l = 0; + } else { + l = fread(buffer, 1, sizeof(buffer), f); + buffer[l] = 0; + fclose(f); + } + return l; +} + + /* * Put a size string together */ @@ -197,6 +254,9 @@ void decode_numa_list(int *numa, char *t) memset(numa, 0, MAX_NODES * sizeof(int)); + if (!t) + return; + while (*t == 'N') { t++; node = strtoul(t, &t, 10); @@ -214,11 +274,17 @@ void decode_numa_list(int *numa, char *t) void slab_validate(struct slabinfo *s) { + if (strcmp(s->name, "*") == 0) + return; + set_obj(s, "validate", 1); } void slab_shrink(struct slabinfo *s) { + if (strcmp(s->name, "*") == 0) + return; + set_obj(s, "shrink", 1); } @@ -226,8 +292,11 @@ int line = 0; void first_line(void) { - printf("Name Objects Objsize Space " - "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); + if (show_activity) + printf("Name Objects Alloc Free %%Fast Fallb O\n"); + else + printf("Name Objects Objsize Space " + "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); } /* @@ -246,10 +315,7 @@ struct aliasinfo *find_one_alias(struct slabinfo *find) return best; } } - if (best) - return best; - fatal("Cannot find alias for %s\n", find->name); - return NULL; + return best; } unsigned long slab_size(struct slabinfo *s) @@ -257,6 +323,200 @@ unsigned long slab_size(struct slabinfo *s) return s->slabs * (page_size << s->order); } +unsigned long slab_activity(struct slabinfo *s) +{ + return s->alloc_fastpath + s->free_fastpath + + s->alloc_slowpath + s->free_slowpath; +} + +void slab_numa(struct slabinfo *s, int mode) +{ + int node; + + if (strcmp(s->name, "*") == 0) + return; + + if (!highest_node) { + printf("\n%s: No NUMA information available.\n", s->name); + return; + } + + if (skip_zero && !s->slabs) + return; + + if (!line) { + printf("\n%-21s:", mode ? "NUMA nodes" : "Slab"); + for(node = 0; node <= highest_node; node++) + printf(" %4d", node); + printf("\n----------------------"); + for(node = 0; node <= highest_node; node++) + printf("-----"); + printf("\n"); + } + printf("%-21s ", mode ? "All slabs" : s->name); + for(node = 0; node <= highest_node; node++) { + char b[20]; + + store_size(b, s->numa[node]); + printf(" %4s", b); + } + printf("\n"); + if (mode) { + printf("%-21s ", "Partial slabs"); + for(node = 0; node <= highest_node; node++) { + char b[20]; + + store_size(b, s->numa_partial[node]); + printf(" %4s", b); + } + printf("\n"); + } + line++; +} + +void show_tracking(struct slabinfo *s) +{ + printf("\n%s: Kernel object allocation\n", s->name); + printf("-----------------------------------------------------------------------\n"); + if (read_slab_obj(s, "alloc_calls")) + printf(buffer); + else + printf("No Data\n"); + + printf("\n%s: Kernel object freeing\n", s->name); + printf("------------------------------------------------------------------------\n"); + if (read_slab_obj(s, "free_calls")) + printf(buffer); + else + printf("No Data\n"); + +} + +void ops(struct slabinfo *s) +{ + if (strcmp(s->name, "*") == 0) + return; + + if (read_slab_obj(s, "ops")) { + printf("\n%s: kmem_cache operations\n", s->name); + printf("--------------------------------------------\n"); + printf(buffer); + } else + printf("\n%s has no kmem_cache operations\n", s->name); +} + +const char *onoff(int x) +{ + if (x) + return "On "; + return "Off"; +} + +void slab_stats(struct slabinfo *s) +{ + unsigned long total_alloc; + unsigned long total_free; + unsigned long total; + + if (!s->alloc_slab) + return; + + total_alloc = s->alloc_fastpath + s->alloc_slowpath; + total_free = s->free_fastpath + s->free_slowpath; + + if (!total_alloc) + return; + + printf("\n"); + printf("Slab Perf Counter Alloc Free %%Al %%Fr\n"); + printf("--------------------------------------------------\n"); + printf("Fastpath %8lu %8lu %3lu %3lu\n", + s->alloc_fastpath, s->free_fastpath, + s->alloc_fastpath * 100 / total_alloc, + s->free_fastpath * 100 / total_free); + printf("Slowpath %8lu %8lu %3lu %3lu\n", + total_alloc - s->alloc_fastpath, s->free_slowpath, + (total_alloc - s->alloc_fastpath) * 100 / total_alloc, + s->free_slowpath * 100 / total_free); + printf("Page Alloc %8lu %8lu %3lu %3lu\n", + s->alloc_slab, s->free_slab, + s->alloc_slab * 100 / total_alloc, + s->free_slab * 100 / total_free); + printf("Add partial %8lu %8lu %3lu %3lu\n", + s->deactivate_to_head + s->deactivate_to_tail, + s->free_add_partial, + (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc, + s->free_add_partial * 100 / total_free); + printf("Remove partial %8lu %8lu %3lu %3lu\n", + s->alloc_from_partial, s->free_remove_partial, + s->alloc_from_partial * 100 / total_alloc, + s->free_remove_partial * 100 / total_free); + + printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n", + s->deactivate_remote_frees, s->free_frozen, + s->deactivate_remote_frees * 100 / total_alloc, + s->free_frozen * 100 / total_free); + + printf("Total %8lu %8lu\n\n", total_alloc, total_free); + + if (s->cpuslab_flush) + printf("Flushes %8lu\n", s->cpuslab_flush); + + if (s->alloc_refill) + printf("Refill %8lu\n", s->alloc_refill); + + total = s->deactivate_full + s->deactivate_empty + + s->deactivate_to_head + s->deactivate_to_tail; + + if (total) + printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) " + "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n", + s->deactivate_full, (s->deactivate_full * 100) / total, + s->deactivate_empty, (s->deactivate_empty * 100) / total, + s->deactivate_to_head, (s->deactivate_to_head * 100) / total, + s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total); +} + +void report(struct slabinfo *s) +{ + if (strcmp(s->name, "*") == 0) + return; + + printf("\nSlabcache: %-20s Aliases: %2d Order : %2d Objects: %lu\n", + s->name, s->aliases, s->order, s->objects); + if (s->hwcache_align) + printf("** Hardware cacheline aligned\n"); + if (s->cache_dma) + printf("** Memory is allocated in a special DMA zone\n"); + if (s->destroy_by_rcu) + printf("** Slabs are destroyed via RCU\n"); + if (s->reclaim_account) + printf("** Reclaim accounting active\n"); + + printf("\nSizes (bytes) Slabs Debug Memory\n"); + printf("------------------------------------------------------------------------\n"); + printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n", + s->object_size, s->slabs, onoff(s->sanity_checks), + s->slabs * (page_size << s->order)); + printf("SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld\n", + s->slab_size, s->slabs - s->partial - s->cpu_slabs, + onoff(s->red_zone), s->objects * s->object_size); + printf("SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld\n", + page_size << s->order, s->partial, onoff(s->poison), + s->slabs * (page_size << s->order) - s->objects * s->object_size); + printf("Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld\n", + s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user), + (s->slab_size - s->object_size) * s->objects); + printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n", + s->align, s->objs_per_slab, onoff(s->trace), + ((page_size << s->order) - s->objs_per_slab * s->slab_size) * + s->slabs); + + ops(s); + show_tracking(s); + slab_numa(s, 1); + slab_stats(s); +} void slabcache(struct slabinfo *s) { @@ -265,11 +525,23 @@ void slabcache(struct slabinfo *s) char flags[20]; char *p = flags; - if (skip_zero && !s->slabs) + if (strcmp(s->name, "*") == 0) + return; + + if (actual_slabs == 1) { + report(s); + return; + } + + if (skip_zero && !show_empty && !s->slabs) + return; + + if (show_empty && s->slabs) return; store_size(size_str, slab_size(s)); - sprintf(dist_str,"%lu/%lu/%d", s->slabs, s->partial, s->cpu_slabs); + snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs, + s->partial, s->cpu_slabs); if (!line++) first_line(); @@ -294,57 +566,155 @@ void slabcache(struct slabinfo *s) *p++ = 'T'; *p = 0; - printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n", - s->name, s->objects, s->object_size, size_str, dist_str, - s->objs_per_slab, s->order, - s->slabs ? (s->partial * 100) / s->slabs : 100, - s->slabs ? (s->objects * s->object_size * 100) / - (s->slabs * (page_size << s->order)) : 100, - flags); + if (show_activity) { + unsigned long total_alloc; + unsigned long total_free; + + total_alloc = s->alloc_fastpath + s->alloc_slowpath; + total_free = s->free_fastpath + s->free_slowpath; + + printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d\n", + s->name, s->objects, + total_alloc, total_free, + total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0, + total_free ? (s->free_fastpath * 100 / total_free) : 0, + s->order_fallback, s->order); + } + else + printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n", + s->name, s->objects, s->object_size, size_str, dist_str, + s->objs_per_slab, s->order, + s->slabs ? (s->partial * 100) / s->slabs : 100, + s->slabs ? (s->objects * s->object_size * 100) / + (s->slabs * (page_size << s->order)) : 100, + flags); } -void slab_numa(struct slabinfo *s) +/* + * Analyze debug options. Return false if something is amiss. + */ +int debug_opt_scan(char *opt) { - int node; + if (!opt || !opt[0] || strcmp(opt, "-") == 0) + return 1; + + if (strcasecmp(opt, "a") == 0) { + sanity = 1; + poison = 1; + redzone = 1; + tracking = 1; + return 1; + } - if (!highest_node) - fatal("No NUMA information available.\n"); + for ( ; *opt; opt++) + switch (*opt) { + case 'F' : case 'f': + if (sanity) + return 0; + sanity = 1; + break; + case 'P' : case 'p': + if (poison) + return 0; + poison = 1; + break; - if (skip_zero && !s->slabs) - return; + case 'Z' : case 'z': + if (redzone) + return 0; + redzone = 1; + break; - if (!line) { - printf("\nSlab Node "); - for(node = 0; node <= highest_node; node++) - printf(" %4d", node); - printf("\n----------------------"); - for(node = 0; node <= highest_node; node++) - printf("-----"); - printf("\n"); - } - printf("%-21s ", s->name); - for(node = 0; node <= highest_node; node++) { - char b[20]; + case 'U' : case 'u': + if (tracking) + return 0; + tracking = 1; + break; - store_size(b, s->numa[node]); - printf(" %4s", b); - } - printf("\n"); - line++; + case 'T' : case 't': + if (tracing) + return 0; + tracing = 1; + break; + default: + return 0; + } + return 1; } -void show_tracking(struct slabinfo *s) +int slab_empty(struct slabinfo *s) { - printf("\n%s: Calls to allocate a slab object\n", s->name); - printf("---------------------------------------------------\n"); - if (read_obj("alloc_calls")) - printf(buffer); + if (s->objects > 0) + return 0; - printf("%s: Calls to free a slab object\n", s->name); - printf("-----------------------------------------------\n"); - if (read_obj("free_calls")) - printf(buffer); + /* + * We may still have slabs even if there are no objects. Shrinking will + * remove them. + */ + if (s->slabs != 0) + set_obj(s, "shrink", 1); + return 1; +} + +void slab_debug(struct slabinfo *s) +{ + if (strcmp(s->name, "*") == 0) + return; + + if (sanity && !s->sanity_checks) { + set_obj(s, "sanity", 1); + } + if (!sanity && s->sanity_checks) { + if (slab_empty(s)) + set_obj(s, "sanity", 0); + else + fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name); + } + if (redzone && !s->red_zone) { + if (slab_empty(s)) + set_obj(s, "red_zone", 1); + else + fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name); + } + if (!redzone && s->red_zone) { + if (slab_empty(s)) + set_obj(s, "red_zone", 0); + else + fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name); + } + if (poison && !s->poison) { + if (slab_empty(s)) + set_obj(s, "poison", 1); + else + fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name); + } + if (!poison && s->poison) { + if (slab_empty(s)) + set_obj(s, "poison", 0); + else + fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name); + } + if (tracking && !s->store_user) { + if (slab_empty(s)) + set_obj(s, "store_user", 1); + else + fprintf(stderr, "%s not empty cannot enable tracking\n", s->name); + } + if (!tracking && s->store_user) { + if (slab_empty(s)) + set_obj(s, "store_user", 0); + else + fprintf(stderr, "%s not empty cannot disable tracking\n", s->name); + } + if (tracing && !s->trace) { + if (slabs == 1) + set_obj(s, "trace", 1); + else + fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name); + } + if (!tracing && s->trace) + set_obj(s, "trace", 1); } void totals(void) @@ -408,7 +778,6 @@ void totals(void) unsigned long used; unsigned long long wasted; unsigned long long objwaste; - long long objects_in_partial_slabs; unsigned long percentage_partial_slabs; unsigned long percentage_partial_objs; @@ -422,18 +791,11 @@ void totals(void) wasted = size - used; objwaste = s->slab_size - s->object_size; - objects_in_partial_slabs = s->objects - - (s->slabs - s->partial - s ->cpu_slabs) * - s->objs_per_slab; - - if (objects_in_partial_slabs < 0) - objects_in_partial_slabs = 0; - percentage_partial_slabs = s->partial * 100 / s->slabs; if (percentage_partial_slabs > 100) percentage_partial_slabs = 100; - percentage_partial_objs = objects_in_partial_slabs * 100 + percentage_partial_objs = s->objects_partial * 100 / s->objects; if (percentage_partial_objs > 100) @@ -455,8 +817,8 @@ void totals(void) min_objects = s->objects; if (used < min_used) min_used = used; - if (objects_in_partial_slabs < min_partobj) - min_partobj = objects_in_partial_slabs; + if (s->objects_partial < min_partobj) + min_partobj = s->objects_partial; if (percentage_partial_slabs < min_ppart) min_ppart = percentage_partial_slabs; if (percentage_partial_objs < min_ppartobj) @@ -480,8 +842,8 @@ void totals(void) max_objects = s->objects; if (used > max_used) max_used = used; - if (objects_in_partial_slabs > max_partobj) - max_partobj = objects_in_partial_slabs; + if (s->objects_partial > max_partobj) + max_partobj = s->objects_partial; if (percentage_partial_slabs > max_ppart) max_ppart = percentage_partial_slabs; if (percentage_partial_objs > max_ppartobj) @@ -496,7 +858,7 @@ void totals(void) total_objects += s->objects; total_used += used; - total_partobj += objects_in_partial_slabs; + total_partobj += s->objects_partial; total_ppart += percentage_partial_slabs; total_ppartobj += percentage_partial_objs; @@ -538,11 +900,11 @@ void totals(void) store_size(b1, total_size);store_size(b2, total_waste); store_size(b3, total_waste * 100 / total_used); - printf("Memory used: %6s # Loss : %6s MRatio: %6s%%\n", b1, b2, b3); + printf("Memory used: %6s # Loss : %6s MRatio:%6s%%\n", b1, b2, b3); store_size(b1, total_objects);store_size(b2, total_partobj); store_size(b3, total_partobj * 100 / total_objects); - printf("# Objects : %6s # PartObj: %6s ORatio: %6s%%\n", b1, b2, b3); + printf("# Objects : %6s # PartObj: %6s ORatio:%6s%%\n", b1, b2, b3); printf("\n"); printf("Per Cache Average Min Max Total\n"); @@ -565,7 +927,7 @@ void totals(void) store_size(b1, avg_ppart);store_size(b2, min_ppart); store_size(b3, max_ppart); store_size(b4, total_partial * 100 / total_slabs); - printf("%%PartSlab %10s%% %10s%% %10s%% %10s%%\n", + printf("%%PartSlab%10s%% %10s%% %10s%% %10s%%\n", b1, b2, b3, b4); store_size(b1, avg_partobj);store_size(b2, min_partobj); @@ -577,7 +939,7 @@ void totals(void) store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj); store_size(b3, max_ppartobj); store_size(b4, total_partobj * 100 / total_objects); - printf("%% PartObj %10s%% %10s%% %10s%% %10s%%\n", + printf("%% PartObj%10s%% %10s%% %10s%% %10s%%\n", b1, b2, b3, b4); store_size(b1, avg_size);store_size(b2, min_size); @@ -624,6 +986,8 @@ void sort_slabs(void) if (sort_size) result = slab_size(s1) < slab_size(s2); + else if (sort_active) + result = slab_activity(s1) < slab_activity(s2); else result = strcasecmp(s1->name, s2->name); @@ -673,7 +1037,7 @@ void link_slabs(void) for (a = aliasinfo; a < aliasinfo + aliases; a++) { - for(s = slabinfo; s < slabinfo + slabs; s++) + for (s = slabinfo; s < slabinfo + slabs; s++) if (strcmp(a->ref, s->name) == 0) { a->slab = s; s->refs++; @@ -704,7 +1068,7 @@ void alias(void) continue; } } - printf("\n%-20s <- %s", a->slab->name, a->name); + printf("\n%-12s <- %s", a->slab->name, a->name); active = a->slab->name; } else @@ -729,7 +1093,12 @@ void rename_slabs(void) a = find_one_alias(s); - s->name = a->name; + if (a) + s->name = a->name; + else { + s->name = "*"; + actual_slabs--; + } } } @@ -748,11 +1117,14 @@ void read_slab_dir(void) char *t; int count; + if (chdir("/sys/kernel/slab") && chdir("/sys/slab")) + fatal("SYSFS support for SLUB not active\n"); + dir = opendir("."); while ((de = readdir(dir))) { if (de->d_name[0] == '.' || - slab_mismatch(de->d_name)) - continue; + (de->d_name[0] != ':' && slab_mismatch(de->d_name))) + continue; switch (de->d_type) { case DT_LNK: alias->name = strdup(de->d_name); @@ -782,11 +1154,14 @@ void read_slab_dir(void) slab->hwcache_align = get_obj("hwcache_align"); slab->object_size = get_obj("object_size"); slab->objects = get_obj("objects"); + slab->objects_partial = get_obj("objects_partial"); + slab->objects_total = get_obj("objects_total"); slab->objs_per_slab = get_obj("objs_per_slab"); slab->order = get_obj("order"); slab->partial = get_obj("partial"); slab->partial = get_obj_and_str("partial", &t); decode_numa_list(slab->numa_partial, t); + free(t); slab->poison = get_obj("poison"); slab->reclaim_account = get_obj("reclaim_account"); slab->red_zone = get_obj("red_zone"); @@ -794,8 +1169,27 @@ void read_slab_dir(void) slab->slab_size = get_obj("slab_size"); slab->slabs = get_obj_and_str("slabs", &t); decode_numa_list(slab->numa, t); + free(t); slab->store_user = get_obj("store_user"); slab->trace = get_obj("trace"); + slab->alloc_fastpath = get_obj("alloc_fastpath"); + slab->alloc_slowpath = get_obj("alloc_slowpath"); + slab->free_fastpath = get_obj("free_fastpath"); + slab->free_slowpath = get_obj("free_slowpath"); + slab->free_frozen= get_obj("free_frozen"); + slab->free_add_partial = get_obj("free_add_partial"); + slab->free_remove_partial = get_obj("free_remove_partial"); + slab->alloc_from_partial = get_obj("alloc_from_partial"); + slab->alloc_slab = get_obj("alloc_slab"); + slab->alloc_refill = get_obj("alloc_refill"); + slab->free_slab = get_obj("free_slab"); + slab->cpuslab_flush = get_obj("cpuslab_flush"); + slab->deactivate_full = get_obj("deactivate_full"); + slab->deactivate_empty = get_obj("deactivate_empty"); + slab->deactivate_to_head = get_obj("deactivate_to_head"); + slab->deactivate_to_tail = get_obj("deactivate_to_tail"); + slab->deactivate_remote_frees = get_obj("deactivate_remote_frees"); + slab->order_fallback = get_obj("order_fallback"); chdir(".."); if (slab->name[0] == ':') alias_targets++; @@ -807,6 +1201,7 @@ void read_slab_dir(void) } closedir(dir); slabs = slab - slabinfo; + actual_slabs = slabs; aliases = alias - aliasinfo; if (slabs > MAX_SLABS) fatal("Too many slabs\n"); @@ -825,34 +1220,41 @@ void output_slabs(void) if (show_numa) - slab_numa(slab); - else - if (show_track) + slab_numa(slab, 0); + else if (show_track) show_tracking(slab); - else - if (validate) + else if (validate) slab_validate(slab); - else - if (shrink) + else if (shrink) slab_shrink(slab); - else { - if (show_slab) - slabcache(slab); - } + else if (set_debug) + slab_debug(slab); + else if (show_ops) + ops(slab); + else if (show_slab) + slabcache(slab); + else if (show_report) + report(slab); } } struct option opts[] = { { "aliases", 0, NULL, 'a' }, - { "slabs", 0, NULL, 'l' }, - { "numa", 0, NULL, 'n' }, - { "zero", 0, NULL, 'z' }, - { "help", 0, NULL, 'h' }, - { "validate", 0, NULL, 'v' }, + { "activity", 0, NULL, 'A' }, + { "debug", 2, NULL, 'd' }, + { "display-activity", 0, NULL, 'D' }, + { "empty", 0, NULL, 'e' }, { "first-alias", 0, NULL, 'f' }, + { "help", 0, NULL, 'h' }, + { "inverted", 0, NULL, 'i'}, + { "numa", 0, NULL, 'n' }, + { "ops", 0, NULL, 'o' }, + { "report", 0, NULL, 'r' }, { "shrink", 0, NULL, 's' }, + { "slabs", 0, NULL, 'l' }, { "track", 0, NULL, 't'}, - { "inverted", 0, NULL, 'i'}, + { "validate", 0, NULL, 'v' }, + { "zero", 0, NULL, 'z' }, { "1ref", 0, NULL, '1'}, { NULL, 0, NULL, 0 } }; @@ -864,17 +1266,30 @@ int main(int argc, char *argv[]) char *pattern_source; page_size = getpagesize(); - if (chdir("/sys/slab")) - fatal("This kernel does not have SLUB support.\n"); - while ((c = getopt_long(argc, argv, "afhil1npstvzTS", opts, NULL)) != -1) - switch(c) { + while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS", + opts, NULL)) != -1) + switch (c) { case '1': show_single_ref = 1; break; case 'a': show_alias = 1; break; + case 'A': + sort_active = 1; + break; + case 'd': + set_debug = 1; + if (!debug_opt_scan(optarg)) + fatal("Invalid debug option '%s'\n", optarg); + break; + case 'D': + show_activity = 1; + break; + case 'e': + show_empty = 1; + break; case 'f': show_first_alias = 1; break; @@ -887,6 +1302,12 @@ int main(int argc, char *argv[]) case 'n': show_numa = 1; break; + case 'o': + show_ops = 1; + break; + case 'r': + show_report = 1; + break; case 's': shrink = 1; break; @@ -914,8 +1335,8 @@ int main(int argc, char *argv[]) } - if (!show_slab && !show_alias && !show_track - && !validate && !shrink) + if (!show_slab && !show_alias && !show_track && !show_report + && !validate && !shrink && !set_debug && !show_ops) show_slab = 1; if (argc > optind)