[patch 7/7] SLUB: Major slabinfo update

clameter
2007-04-26T05:11:56Z

[-- Attachment #1: slub_slabinfo_update --]
[-- Type: text/plain, Size: 23258 bytes --]

Enhancement to slabinfo
- Support for slab shrinking (-r option)
- Slab summary showing system totals
- Sync with new form of alias handling
- Sort by size, reverse sorting etc
- Alias lookups

Signed-off-by: Christoph Lameter <clameter@sgi.com>

Index: linux-2.6.21-rc7-mm1/Documentation/vm/slabinfo.c
===================================================================
--- linux-2.6.21-rc7-mm1.orig/Documentation/vm/slabinfo.c 2007-04-25 21:20:24.000000000 -0700
+++ linux-2.6.21-rc7-mm1/Documentation/vm/slabinfo.c 2007-04-25 21:46:40.000000000 -0700
@@ -3,7 +3,7 @@
*
* (C) 2007 sgi, Christoph Lameter <clameter@sgi.com>
*
- * Compile by doing:
+ * Compile by:
*
* gcc -o slabinfo slabinfo.c
*/
@@ -17,15 +17,47 @@
#include <getopt.h>
#include <regex.h>

+#define MAX_SLABS 500
+#define MAX_ALIASES 500
+#define MAX_NODES 1024
+
+struct slabinfo {
+ char *name;
+ int alias;
+ int refs;
+ int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
+ 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;
+ int numa[MAX_NODES];
+ int numa_partial[MAX_NODES];
+} slabinfo[MAX_SLABS];
+
+struct aliasinfo {
+ char *name;
+ char *ref;
+ struct slabinfo *slab;
+} aliasinfo[MAX_ALIASES];
+
+int slabs = 0;
+int aliases = 0;
+int highest_node = 0;
+
char buffer[4096];

int show_alias = 0;
int show_slab = 0;
-int show_parameters = 0;
int skip_zero = 1;
int show_numa = 0;
int show_track = 0;
+int show_first_alias = 0;
int validate = 0;
+int shrink = 0;
+int show_inverted = 0;
+int show_single_ref = 0;
+int show_totals = 0;
+int sort_size = 0;

int page_size;

@@ -47,11 +79,16 @@ void usage(void)
"-a|--aliases Show aliases\n"
"-h|--help Show usage information\n"
"-n|--numa Show NUMA information\n"
- "-p|--parameters Show global parameters\n"
+ "-r|--reduce Shrink slabs\n"
"-v|--validate Validate slabs\n"
"-t|--tracking Show alloc/free information\n"
+ "-T|--Totals Show summary information\n"
"-s|--slabs Show slabs\n"
+ "-S|--Size Sort by size\n"
"-z|--zero Include empty slabs\n"
+ "-f|--first-alias Show first alias\n"
+ "-i|--inverted Inverted list\n"
+ "-1|--1ref Single reference\n"
);
}

@@ -86,23 +123,32 @@ unsigned long get_obj(char *name)
unsigned long get_obj_and_str(char *name, char **x)
{
unsigned long result = 0;
+ char *p;
+
+ *x = NULL;

if (!read_obj(name)) {
x = NULL;
return 0;
}
- result = strtoul(buffer, x, 10);
- while (**x == ' ')
- (*x)++;
+ result = strtoul(buffer, &p, 10);
+ while (*p == ' ')
+ p++;
+ if (*p)
+ *x = strdup(p);
return result;
}

-void set_obj(char *name, int n)
+void set_obj(struct slabinfo *s, char *name, int n)
{
- FILE *f = fopen(name, "w");
+ char x[100];
+
+ sprintf(x, "%s/%s", s->name, name);
+
+ FILE *f = fopen(x, "w");

if (!f)
- fatal("Cannot write to %s\n", name);
+ fatal("Cannot write to %s\n", x);

fprintf(f, "%d\n", n);
fclose(f);
@@ -143,167 +189,613 @@ int store_size(char *buffer, unsigned lo
return n;
}

-void alias(const char *name)
+void decode_numa_list(int *numa, char *t)
{
- int count;
- char *p;
-
- if (!show_alias)
- return;
+ int node;
+ int nr;

- count = readlink(name, buffer, sizeof(buffer));
+ memset(numa, 0, MAX_NODES * sizeof(int));

- if (count < 0)
- return;
+ while (*t == 'N') {
+ t++;
+ node = strtoul(t, &t, 10);
+ if (*t == '=') {
+ t++;
+ nr = strtoul(t, &t, 10);
+ numa[node] = nr;
+ if (node > highest_node)
+ highest_node = node;
+ }
+ while (*t == ' ')
+ t++;
+ }
+}

- buffer[count] = 0;
+char *hackname(struct slabinfo *s)
+{
+ char *n = s->name;

- p = buffer + count;
+ if (n[0] == ':') {
+ char *nn = malloc(20);
+ char *p;
+
+ strncpy(nn, n, 20);
+ n = nn;
+ p = n + 4;
+ while (*p && *p !=':')
+ p++;
+ *p = 0;
+ }
+ return n;
+}

- while (p > buffer && p[-1] != '/')
- p--;
- printf("%-20s -> %s\n", name, p);
+void slab_validate(struct slabinfo *s)
+{
+ set_obj(s, "validate", 1);
}

-void slab_validate(char *name)
+void slab_shrink(struct slabinfo *s)
{
- set_obj("validate", 1);
+ set_obj(s, "shrink", 1);
}

int line = 0;

void first_line(void)
{
- printf("Name Objects Objsize Space "
- "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
+ printf("Name Objects Objsize Space "
+ "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
+}
+
+/*
+ * Find the shortest alias of a slab
+ */
+struct aliasinfo *find_one_alias(struct slabinfo *find)
+{
+ struct aliasinfo *a;
+ struct aliasinfo *best = NULL;
+
+ for(a = aliasinfo;a < aliasinfo + aliases; a++) {
+ if (a->slab == find &&
+ (!best || strlen(best->name) < strlen(a->name))) {
+ best = a;
+ if (strncmp(a->name,"kmall", 5) == 0)
+ return best;
+ }
+ }
+ if (best)
+ return best;
+ fatal("Cannot find alias for %s\n", find->name);
+ return NULL;
}

-void slab(const char *name)
+unsigned long slab_size(struct slabinfo *s)
+{
+ return s->slabs * (page_size << s->order);
+}
+
+
+void slabcache(struct slabinfo *s)
{
- unsigned long aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
- unsigned long hwcache_align, object_size, objects, objs_per_slab;
- unsigned long order, partial, poison, reclaim_account, red_zone;
- unsigned long sanity_checks, slab_size, slabs, store_user, trace;
char size_str[20];
char dist_str[40];
char flags[20];
char *p = flags;
+ char *n;

- if (!show_slab)
+ if (skip_zero && !s->slabs)
return;

- aliases = get_obj("aliases");
- align = get_obj("align");
- cache_dma = get_obj("cache_dma");
- cpu_slabs = get_obj("cpu_slabs");
- destroy_by_rcu = get_obj("destroy_by_rcu");
- hwcache_align = get_obj("hwcache_align");
- object_size = get_obj("object_size");
- objects = get_obj("objects");
- objs_per_slab = get_obj("objs_per_slab");
- order = get_obj("order");
- partial = get_obj("partial");
- poison = get_obj("poison");
- reclaim_account = get_obj("reclaim_account");
- red_zone = get_obj("red_zone");
- sanity_checks = get_obj("sanity_checks");
- slab_size = get_obj("slab_size");
- slabs = get_obj("slabs");
- store_user = get_obj("store_user");
- trace = get_obj("trace");
-
- if (skip_zero && !slabs)
- return;
-
- store_size(size_str, slabs * page_size);
- sprintf(dist_str,"%lu/%lu/%lu", slabs, partial, cpu_slabs);
+ store_size(size_str, slab_size(s));
+ sprintf(dist_str,"%lu/%lu/%d", s->slabs, s->partial, s->cpu_slabs);

if (!line++)
first_line();

- if (aliases)
+ if (s->aliases)
*p++ = '*';
- if (cache_dma)
+ if (s->cache_dma)
*p++ = 'd';
- if (hwcache_align)
+ if (s->hwcache_align)
*p++ = 'A';
- if (poison)
+ if (s->poison)
*p++ = 'P';
- if (reclaim_account)
+ if (s->reclaim_account)
*p++ = 'a';
- if (red_zone)
+ if (s->red_zone)
*p++ = 'Z';
- if (sanity_checks)
+ if (s->sanity_checks)
*p++ = 'F';
- if (store_user)
+ if (s->store_user)
*p++ = 'U';
- if (trace)
+ if (s->trace)
*p++ = 'T';

*p = 0;
- printf("%-20s %8ld %7ld %8s %14s %3ld %1ld %3ld %3ld %s\n",
- name, objects, object_size, size_str, dist_str,
- objs_per_slab, order,
- slabs ? (partial * 100) / slabs : 100,
- slabs ? (objects * object_size * 100) /
- (slabs * (page_size << order)) : 100,
+ n = hackname(s);
+ printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
+ n, 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(const char *name)
+void slab_numa(struct slabinfo *s)
{
- unsigned long slabs;
- char *numainfo;
-
- slabs = get_obj_and_str("slabs", &numainfo);
+ char *n;
+ int node;

- if (skip_zero && !slabs)
+ if (skip_zero && !s->slabs)
return;
+ n = hackname(s);

- printf("%-20s %s", name, numainfo);
-}
+ 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 ", n);
+ for(node = 0; node <= highest_node; node++) {
+ char b[20];

-void parameter(const char *name)
-{
- if (!show_parameters)
- return;
+ store_size(b, s->numa[node]);
+ printf(" %4s", b);
+ }
+ printf("\n");
+ line++;
}

-void show_tracking(const char *name)
+void show_tracking(struct slabinfo *s)
{
- printf("\n%s: Calls to allocate a slab object\n", name);
+ printf("\n%s: Calls to allocate a slab object\n", s->name);
printf("---------------------------------------------------\n");
if (read_obj("alloc_calls"))
printf(buffer);

- printf("%s: Calls to free a slab object\n", name);
+ printf("%s: Calls to free a slab object\n", s->name);
printf("-----------------------------------------------\n");
if (read_obj("free_calls"))
printf(buffer);

}

+void totals(void)
+{
+ struct slabinfo *s;
+
+ int used_slabs = 0;
+ char b1[20], b2[20], b3[20], b4[20];
+ unsigned long long min_objsize = 0, max_objsize = 0, avg_objsize;
+ unsigned long long min_partial = 0, max_partial = 0, avg_partial, total_partial = 0;
+ unsigned long long min_slabs = 0, max_slabs = 0, avg_slabs, total_slabs = 0;
+ unsigned long long min_size = 0, max_size = 0, avg_size, total_size = 0;
+ unsigned long long min_waste = 0, max_waste = 0, avg_waste, total_waste = 0;
+ unsigned long long min_objects = 0, max_objects = 0, avg_objects, total_objects = 0;
+ unsigned long long min_objwaste = 0, max_objwaste = 0, avg_objwaste;
+ unsigned long long min_used = 0, max_used = 0, avg_used, total_used = 0;
+ unsigned long min_ppart = 0, max_ppart = 0, avg_ppart, total_ppart = 0;
+ unsigned long min_partobj = 0, max_partobj = 0, avg_partobj;
+ unsigned long total_objects_in_partial = 0;
+
+ for (s = slabinfo; s < slabinfo + slabs; s++) {
+ unsigned long long size;
+ unsigned long partial;
+ unsigned long slabs;
+ unsigned long used;
+ unsigned long long wasted;
+ unsigned long long objwaste;
+ long long objects_in_partial;
+ unsigned long percentage_partial;
+
+ if (!s->slabs || !s->objects)
+ continue;
+
+ used_slabs++;
+
+ size = slab_size(s);
+ partial = s->partial << s->order;
+ slabs = s->slabs << s->order;
+ used = s->objects * s->object_size;
+ wasted = size - used;
+ objwaste = wasted / s->objects;
+
+ objects_in_partial = s->objects - (s->slabs - s->partial - s ->cpu_slabs)
+ * s->objs_per_slab;
+
+ if (objects_in_partial < 0)
+ objects_in_partial = 0;
+
+ percentage_partial = objects_in_partial * 100 / s->objects;
+ if (percentage_partial > 100)
+ percentage_partial = 100;
+
+ if (s->object_size < min_objsize || !min_objsize)
+ min_objsize = s->object_size;
+ if (partial && (partial < min_partial || !min_partial))
+ min_partial = partial;
+ if (slabs < min_slabs || !min_partial)
+ min_slabs = slabs;
+ if (size < min_size)
+ min_size = size;
+ if (wasted < min_waste && !min_waste)
+ min_waste = wasted;
+ if (objwaste < min_objwaste || !min_objwaste)
+ min_objwaste = objwaste;
+ if (s->objects < min_objects || !min_objects)
+ min_objects = s->objects;
+ if (used < min_used || !min_used)
+ min_used = used;
+ if (objects_in_partial < min_partobj || !min_partobj)
+ min_partobj = objects_in_partial;
+ if (percentage_partial < min_ppart || !min_ppart)
+ min_ppart = percentage_partial;
+
+ if (s->object_size > max_objsize)
+ max_objsize = s->object_size;
+ if (partial > max_partial)
+ max_partial = partial;
+ if (slabs > max_slabs)
+ max_slabs = slabs;
+ if (size > max_size)
+ max_size = size;
+ if (wasted > max_waste)
+ max_waste = wasted;
+ if (objwaste > max_objwaste)
+ max_objwaste = objwaste;
+ if (s->objects > max_objects)
+ max_objects = s->objects;
+ if (used > max_used)
+ max_used = used;
+ if (objects_in_partial > max_partobj)
+ max_partobj = objects_in_partial;
+ if (percentage_partial > max_ppart)
+ max_ppart = percentage_partial;
+
+ total_objects += s->objects;
+ total_partial += partial;
+ total_slabs += slabs;
+ total_used += used;
+ total_waste += wasted;
+ total_size += size;
+ total_ppart += percentage_partial;
+ total_objects_in_partial += objects_in_partial;
+ }
+
+ if (!total_objects) {
+ printf("No objects\n");
+ return;
+ }
+ if (!used_slabs) {
+ printf("No slabs\n");
+ return;
+ }
+ avg_partial = total_partial / used_slabs;
+ avg_slabs = total_slabs / used_slabs;
+ avg_waste = total_waste / used_slabs;
+ avg_size = total_waste / used_slabs;
+ avg_objects = total_objects / used_slabs;
+ avg_used = total_used / used_slabs;
+ avg_ppart = total_ppart / used_slabs;
+ avg_partobj = total_objects_in_partial / used_slabs;
+
+ avg_objsize = total_used / total_objects;
+ avg_objwaste = total_waste / total_objects;
+
+ printf("Slabcache Totals\n");
+ printf("----------------\n");
+ printf("Slabcaches : %3d Aliases : %3d Active: %3d\n",
+ slabs, aliases, used_slabs);
+
+ store_size(b1, total_used);store_size(b2, total_waste);
+ store_size(b3, total_waste * 100 / total_used);
+ printf("Memory used: %5s # Loss : %5s MRatio: %3s%%\n", b1, b2, b3);
+
+ store_size(b1, total_objects);store_size(b2, total_objects_in_partial);
+ store_size(b3, total_objects_in_partial * 100 / total_objects);
+ printf("# Objects : %5s # PartObj: %5s ORatio: %3s%%\n", b1, b2, b3);
+
+ printf("\n");
+ printf("Per Cache Average Min Max Total\n");
+ printf("---------------------------------------------------------\n");
+
+ store_size(b1, avg_objects);store_size(b2, min_objects);
+ store_size(b3, max_objects);store_size(b4, total_objects);
+ printf("# Objects %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_slabs);store_size(b2, min_slabs);
+ store_size(b3, max_slabs);store_size(b4, total_slabs);
+ printf("# Slabs %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_partial);store_size(b2, min_partial);
+ store_size(b3, max_partial);store_size(b4, total_partial);
+ printf("# Partial %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+ store_size(b1, avg_ppart);store_size(b2, min_ppart);
+ store_size(b3, max_ppart);
+ printf("Partial %10s%% %10s%% %10s%%\n",
+ b1, b2, b3);
+
+ store_size(b1, avg_size);store_size(b2, min_size);
+ store_size(b3, max_size);store_size(b4, total_size);
+ printf("Memory %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_used);store_size(b2, min_used);
+ store_size(b3, max_used);store_size(b4, total_used);
+ printf("Used %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_slabs);store_size(b2, min_slabs);
+ store_size(b3, max_slabs);store_size(b4, total_slabs);
+ printf("Waste %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ printf("\n");
+ printf("Per Object Average Min Max\n");
+ printf("---------------------------------------------\n");
+
+ store_size(b1, avg_objsize);store_size(b2, min_objsize);
+ store_size(b3, max_objsize);
+ printf("Size %10s %10s %10s\n",
+ b1, b2, b3);
+
+ store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
+ store_size(b3, max_objwaste);
+ printf("Loss %10s %10s %10s\n",
+ b1, b2, b3);
+}
+
+void sort_slabs(void)
+{
+ struct slabinfo *s1,*s2;
+
+ for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
+ for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
+ int result;
+
+ if (sort_size)
+ result = slab_size(s1) < slab_size(s2);
+ else
+ result = strcasecmp(s1->name, s2->name);
+
+ if (show_inverted)
+ result = -result;
+
+ if (result > 0) {
+ struct slabinfo t;
+
+ memcpy(&t, s1, sizeof(struct slabinfo));
+ memcpy(s1, s2, sizeof(struct slabinfo));
+ memcpy(s2, &t, sizeof(struct slabinfo));
+ }
+ }
+ }
+}
+
+void sort_aliases(void)
+{
+ struct aliasinfo *a1,*a2;
+
+ for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
+ for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
+ char *n1, *n2;
+
+ n1 = a1->name;
+ n2 = a2->name;
+ if (show_alias && !show_inverted) {
+ n1 = a1->ref;
+ n2 = a2->ref;
+ }
+ if (strcasecmp(n1, n2) > 0) {
+ struct aliasinfo t;
+
+ memcpy(&t, a1, sizeof(struct aliasinfo));
+ memcpy(a1, a2, sizeof(struct aliasinfo));
+ memcpy(a2, &t, sizeof(struct aliasinfo));
+ }
+ }
+ }
+}
+
+void link_slabs(void)
+{
+ struct aliasinfo *a;
+ struct slabinfo *s;
+
+ for (a = aliasinfo; a < aliasinfo + aliases; a++) {
+
+ for(s = slabinfo; s < slabinfo + slabs; s++)
+ if (strcmp(a->ref, s->name) == 0) {
+ a->slab = s;
+ s->refs++;
+ break;
+ }
+ if (s == slabinfo + slabs)
+ fatal("Unresolved alias %s\n", a->ref);
+ }
+}
+
+void alias(void)
+{
+ struct aliasinfo *a;
+ char *active = NULL;
+
+ sort_aliases();
+ link_slabs();
+
+ for(a = aliasinfo; a < aliasinfo + aliases; a++) {
+
+ if (!show_single_ref && a->slab->refs == 1)
+ continue;
+
+ if (!show_inverted) {
+ if (active) {
+ if (strcmp(a->slab->name, active) == 0) {
+ printf(" %s", a->name);
+ continue;
+ }
+ }
+ printf("\n%-20s <- %s", a->slab->name, a->name);
+ active = a->slab->name;
+ }
+ else
+ printf("%-20s -> %s\n", a->name, a->slab->name);
+ }
+ if (active)
+ printf("\n");
+}
+
+
+void rename_slabs(void)
+{
+ struct slabinfo *s;
+ struct aliasinfo *a;
+
+ for (s = slabinfo; s < slabinfo + slabs; s++) {
+ if (*s->name != ':')
+ continue;
+
+ if (s->refs > 1 && !show_first_alias)
+ continue;
+
+ a = find_one_alias(s);
+
+ s->name = a->name;
+ }
+}
+
int slab_mismatch(char *slab)
{
return regexec(&pattern, slab, 0, NULL, 0);
}

+void read_slab_dir(void)
+{
+ DIR *dir;
+ struct dirent *de;
+ struct slabinfo *slab = slabinfo;
+ struct aliasinfo *alias = aliasinfo;
+ char *p;
+ char *t;
+ int count;
+
+ dir = opendir(".");
+ while ((de = readdir(dir))) {
+ if (de->d_name[0] == '.' ||
+ slab_mismatch(de->d_name))
+ continue;
+ switch (de->d_type) {
+ case DT_LNK:
+ alias->name = strdup(de->d_name);
+ count = readlink(de->d_name, buffer, sizeof(buffer));
+
+ if (count < 0)
+ fatal("Cannot read symlink %s\n", de->d_name);
+
+ buffer[count] = 0;
+ p = buffer + count;
+ while (p > buffer && p[-1] != '/')
+ p--;
+ alias->ref = strdup(p);
+ alias++;
+ break;
+ case DT_DIR:
+ if (chdir(de->d_name))
+ fatal("Unable to access slab %s\n", slab->name);
+ slab->name = strdup(de->d_name);
+ slab->alias = 0;
+ slab->refs = 0;
+ slab->aliases = get_obj("aliases");
+ slab->align = get_obj("align");
+ slab->cache_dma = get_obj("cache_dma");
+ slab->cpu_slabs = get_obj("cpu_slabs");
+ slab->destroy_by_rcu = get_obj("destroy_by_rcu");
+ slab->hwcache_align = get_obj("hwcache_align");
+ slab->object_size = get_obj("object_size");
+ slab->objects = get_obj("objects");
+ 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);
+ slab->poison = get_obj("poison");
+ slab->reclaim_account = get_obj("reclaim_account");
+ slab->red_zone = get_obj("red_zone");
+ slab->sanity_checks = get_obj("sanity_checks");
+ slab->slab_size = get_obj("slab_size");
+ slab->slabs = get_obj_and_str("slabs", &t);
+ decode_numa_list(slab->numa, t);
+ slab->store_user = get_obj("store_user");
+ slab->trace = get_obj("trace");
+ chdir("..");
+ slab++;
+ break;
+ default :
+ fatal("Unknown file type %lx\n", de->d_type);
+ }
+ }
+ closedir(dir);
+ slabs = slab - slabinfo;
+ aliases = alias - aliasinfo;
+ if (slabs > MAX_SLABS)
+ fatal("Too many slabs\n");
+ if (aliases > MAX_ALIASES)
+ fatal("Too many aliases\n");
+}
+
+void output_slabs(void)
+{
+ struct slabinfo *slab;
+
+ for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
+
+ if (slab->alias)
+ continue;
+
+
+ if (show_numa)
+ slab_numa(slab);
+ else
+ if (show_track)
+ show_tracking(slab);
+ else
+ if (validate)
+ slab_validate(slab);
+ else
+ if (shrink)
+ slab_shrink(slab);
+ else {
+ if (show_slab)
+ slabcache(slab);
+ }
+ }
+}
+
struct option opts[] = {
{ "aliases", 0, NULL, 'a' },
{ "slabs", 0, NULL, 's' },
{ "numa", 0, NULL, 'n' },
- { "parameters", 0, NULL, 'p' },
{ "zero", 0, NULL, 'z' },
{ "help", 0, NULL, 'h' },
{ "validate", 0, NULL, 'v' },
+ { "first-alias", 0, NULL, 'f' },
+ { "reduce", 0, NULL, 'r' },
{ "track", 0, NULL, 't'},
+ { "inverted", 0, NULL, 'i'},
+ { "1ref", 0, NULL, '1'},
{ NULL, 0, NULL, 0 }
};

int main(int argc, char *argv[])
{
- DIR *dir;
- struct dirent *de;
int c;
int err;
char *pattern_source;
@@ -312,22 +804,31 @@ int main(int argc, char *argv[])
if (chdir("/sys/slab"))
fatal("This kernel does not have SLUB support.\n");

- while ((c = getopt_long(argc, argv, "ahtvnpsz", opts, NULL)) != -1)
+ while ((c = getopt_long(argc, argv, "afhi1nprstvzTS", opts, NULL)) != -1)
switch(c) {
- case 's':
- show_slab = 1;
+ case '1':
+ show_single_ref = 1;
break;
case 'a':
show_alias = 1;
break;
+ case 'f':
+ show_first_alias = 1;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ case 'i':
+ show_inverted = 1;
+ break;
case 'n':
show_numa = 1;
break;
- case 'p':
- show_parameters = 1;
+ case 'r':
+ shrink = 1;
break;
- case 'z':
- skip_zero = 0;
+ case 's':
+ show_slab = 1;
break;
case 't':
show_track = 1;
@@ -335,17 +836,23 @@ int main(int argc, char *argv[])
case 'v':
validate = 1;
break;
- case 'h':
- usage();
- return 0;
+ case 'z':
+ skip_zero = 0;
+ break;
+ case 'T':
+ show_totals = 1;
+ break;
+ case 'S':
+ sort_size = 1;
+ break;

default:
fatal("%s: Invalid option '%c'\n", argv[0], optopt);

}

- if (!show_slab && !show_alias && !show_parameters && !show_track
- && !validate)
+ if (!show_slab && !show_alias && !show_track
+ && !validate && !shrink)
show_slab = 1;

if (argc > optind)
@@ -357,39 +864,17 @@ int main(int argc, char *argv[])
if (err)
fatal("%s: Invalid pattern '%s' code %d\n",
argv[0], pattern_source, err);
-
- dir = opendir(".");
- while ((de = readdir(dir))) {
- if (de->d_name[0] == '.' ||
- slab_mismatch(de->d_name))
- continue;
- switch (de->d_type) {
- case DT_LNK:
- alias(de->d_name);
- break;
- case DT_DIR:
- if (chdir(de->d_name))
- fatal("Unable to access slab %s\n", de->d_name);
-
- if (show_numa)
- slab_numa(de->d_name);
- else
- if (show_track)
- show_tracking(de->d_name);
- else
- if (validate)
- slab_validate(de->d_name);
- else
- slab(de->d_name);
- chdir("..");
- break;
- case DT_REG:
- parameter(de->d_name);
- break;
- default :
- fatal("Unknown file type %lx\n", de->d_type);
- }
+ read_slab_dir();
+ if (show_alias)
+ alias();
+ else
+ if (show_totals)
+ totals();
+ else {
+ link_slabs();
+ rename_slabs();
+ sort_slabs();
+ output_slabs();
}
- closedir(dir);
return 0;
}

--