All of lore.kernel.org
 help / color / mirror / Atom feed
From: clameter@sgi.com
To: akpm@linux-foundation.org
Cc: linux-mm@kvack.org
Subject: [patch 04/17] SLUB: slabinfo upgrade
Date: Mon, 07 May 2007 14:22:44 -0700	[thread overview]
Message-ID: <20070507212408.225671736@sgi.com> (raw)
In-Reply-To: 20070507212240.254911542@sgi.com

[-- Attachment #1: slabinfo_debug --]
[-- Type: text/plain, Size: 15897 bytes --]

-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>

---
 Documentation/vm/slabinfo.c |  426 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 352 insertions(+), 74 deletions(-)

Index: slub/Documentation/vm/slabinfo.c
===================================================================
--- slub.orig/Documentation/vm/slabinfo.c	2007-05-07 13:51:40.000000000 -0700
+++ slub/Documentation/vm/slabinfo.c	2007-05-07 13:57:38.000000000 -0700
@@ -16,6 +16,7 @@
 #include <stdarg.h>
 #include <getopt.h>
 #include <regex.h>
+#include <errno.h>
 
 #define MAX_SLABS 500
 #define MAX_ALIASES 500
@@ -41,12 +42,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 +63,15 @@ int show_inverted = 0;
 int show_single_ref = 0;
 int show_totals = 0;
 int sort_size = 0;
+int set_debug = 0;
+int show_ops = 0;
+
+/* Debug options */
+int sanity = 0;
+int redzone = 0;
+int poison = 0;
+int tracking = 0;
+int tracing = 0;
 
 int page_size;
 
@@ -76,20 +89,33 @@ void fatal(const char *x, ...)
 
 void usage(void)
 {
-	printf("slabinfo [-ahnpvtsz] [slab-regexp]\n"
+	printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n"
+		"slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
 		"-a|--aliases           Show aliases\n"
+		"-d<options>|--debug=<options> Set/Clear Debug options\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"
 	);
 }
 
@@ -143,11 +169,10 @@ unsigned long get_obj_and_str(char *name
 void set_obj(struct slabinfo *s, char *name, int n)
 {
 	char x[100];
+	FILE *f;
 
 	sprintf(x, "%s/%s", s->name, name);
-
-	FILE *f = fopen(x, "w");
-
+	f = fopen(x, "w");
 	if (!f)
 		fatal("Cannot write to %s\n", x);
 
@@ -155,6 +180,26 @@ void set_obj(struct slabinfo *s, char *n
 	fclose(f);
 }
 
+unsigned long read_slab_obj(struct slabinfo *s, char *name)
+{
+	char x[100];
+	FILE *f;
+	int l;
+
+	sprintf(x, "%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
  */
@@ -226,7 +271,7 @@ int line = 0;
 
 void first_line(void)
 {
-	printf("Name                 Objects   Objsize    Space "
+	printf("Name                   Objects Objsize    Space "
 		"Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
 }
 
@@ -246,10 +291,7 @@ struct aliasinfo *find_one_alias(struct 
 					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 +299,126 @@ unsigned long slab_size(struct slabinfo 
 	return 	s->slabs * (page_size << s->order);
 }
 
+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 report(struct slabinfo *s)
+{
+	if (strcmp(s->name, "*") == 0)
+		return;
+	printf("\nSlabcache: %-20s  Aliases: %2d Order : %2d\n", s->name, s->aliases, s->order);
+	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);
+}
 
 void slabcache(struct slabinfo *s)
 {
@@ -265,7 +427,18 @@ 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));
@@ -303,48 +476,128 @@ void slabcache(struct slabinfo *s)
 		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 (!highest_node)
-		fatal("No NUMA information available.\n");
+	if (strcasecmp(opt, "a") == 0) {
+		sanity = 1;
+		poison = 1;
+		redzone = 1;
+		tracking = 1;
+		return 1;
+	}
+
+	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 (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)
@@ -673,7 +926,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 +957,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 +982,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 +1006,14 @@ void read_slab_dir(void)
 	char *t;
 	int count;
 
+	if (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);
@@ -807,6 +1068,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 +1087,37 @@ 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);
 	}
 }
 
 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' },
+	{ "debug", 2, 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,10 +1129,9 @@ 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)
+	while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS",
+						opts, NULL)) != -1)
 	switch(c) {
 		case '1':
 			show_single_ref = 1;
@@ -875,6 +1139,14 @@ int main(int argc, char *argv[])
 		case 'a':
 			show_alias = 1;
 			break;
+		case 'd':
+			set_debug = 1;
+			if (!debug_opt_scan(optarg))
+				fatal("Invalid debug option '%s'\n", optarg);
+			break;
+		case 'e':
+			show_empty = 1;
+			break;
 		case 'f':
 			show_first_alias = 1;
 			break;
@@ -887,6 +1159,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 +1192,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)

-- 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

  parent reply	other threads:[~2007-05-07 21:22 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-07 21:22 [patch 00/17] SLUB fixes and enhancements against 2.6.21-m1 clameter
2007-05-07 21:22 ` [patch 01/17] SLUB: Add support for dynamic cacheline size determination clameter
2007-05-07 23:10   ` Christoph Lameter
2007-05-07 21:22 ` [patch 02/17] SLUB: Reduce antifrag max order clameter
2007-05-07 21:22 ` [patch 03/17] SLUB: After object padding only needed for Redzoning clameter
2007-05-07 21:22 ` clameter [this message]
2007-05-07 21:22 ` [patch 05/17] Move remote node draining out of slab allocators clameter
2007-05-07 21:22 ` [patch 06/17] SLUB: Use check_valid_pointer in kmem_ptr_validate clameter
2007-05-07 21:22 ` [patch 07/17] SLUB: Clean up krealloc clameter
2007-05-08  2:41   ` Christoph Lameter
2007-05-07 21:22 ` [patch 08/17] SLUB: Get rid of finish_bootstrap clameter
2007-05-07 21:22 ` [patch 09/17] SLUB: Update comments clameter
2007-05-07 21:22 ` [patch 10/17] SLUB: Add macros for scanning objects in a slab clameter
2007-05-07 21:22 ` [patch 11/17] SLUB: Move resiliency check into SYSFS section clameter
2007-05-07 21:22 ` [patch 12/17] SLUB: Introduce DebugSlab(page) clameter
2007-05-07 21:22 ` [patch 13/17] SLUB: Consolidate trace code clameter
2007-05-07 21:22 ` [patch 14/17] SLUB: Move tracking definitions and check_valid_pointer() away from debug code clameter
2007-05-07 21:22 ` [patch 15/17] SLUB: Add CONFIG_SLUB_DEBUG clameter
2007-05-07 21:22 ` [patch 16/17] SLUB: Include lifetime stats and sets of cpus / nodes in tracking output clameter
2007-05-08  2:48   ` Christoph Lameter
2007-05-07 21:22 ` [patch 17/17] SLUB: Rework slab order determination clameter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070507212408.225671736@sgi.com \
    --to=clameter@sgi.com \
    --cc=akpm@linux-foundation.org \
    --cc=linux-mm@kvack.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.