From: Manfred Spraul <manfred@colorfullife.com>

attached is my proposal for a new layout of /proc/slabinfo:

- It's important to identify if allocation/freeing is cpu bound, thus
  alloc/free data must be reported per-cpu.

- The current format is not pretty: with statistics enabled, the line
  quite long.

Adding per-cpu data to the single-line layout would make it completely
unreadable, thus I've switch to a multi line layout.  I've added a header
that lists all fields.



 mm/slab.c |   68 +++++++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 41 insertions(+), 27 deletions(-)

diff -puN mm/slab.c~slabinfo-rework mm/slab.c
--- 25/mm/slab.c~slabinfo-rework	2003-05-22 01:16:01.000000000 -0700
+++ 25-akpm/mm/slab.c	2003-05-22 01:16:01.000000000 -0700
@@ -275,10 +275,10 @@ struct kmem_cache_s {
 	unsigned long		reaped;
 	unsigned long 		errors;
 	unsigned long		max_freeable;
-	atomic_t		allochit;
-	atomic_t		allocmiss;
-	atomic_t		freehit;
-	atomic_t		freemiss;
+	unsigned long		allochit[NR_CPUS];
+	unsigned long		allocmiss[NR_CPUS];
+	unsigned long		freehit[NR_CPUS];
+	unsigned long		freemiss[NR_CPUS];
 #endif
 };
 
@@ -310,10 +310,10 @@ struct kmem_cache_s {
 					(x)->max_freeable = i; \
 				} while (0)
 
-#define STATS_INC_ALLOCHIT(x)	atomic_inc(&(x)->allochit)
-#define STATS_INC_ALLOCMISS(x)	atomic_inc(&(x)->allocmiss)
-#define STATS_INC_FREEHIT(x)	atomic_inc(&(x)->freehit)
-#define STATS_INC_FREEMISS(x)	atomic_inc(&(x)->freemiss)
+#define STATS_INC_ALLOCHIT(x)	((x)->allochit[smp_processor_id()]++)
+#define STATS_INC_ALLOCMISS(x)	((x)->allocmiss[smp_processor_id()]++)
+#define STATS_INC_FREEHIT(x)	((x)->freehit[smp_processor_id()]++)
+#define STATS_INC_FREEMISS(x)	((x)->freemiss[smp_processor_id()]++)
 #else
 #define	STATS_INC_ACTIVE(x)	do { } while (0)
 #define	STATS_DEC_ACTIVE(x)	do { } while (0)
@@ -2379,11 +2379,18 @@ static void *s_start(struct seq_file *m,
 		 * Output format version, so at least we can change it
 		 * without _too_ many complaints.
 		 */
-		seq_puts(m, "slabinfo - version: 1.2"
 #if STATS
-				" (statistics)"
+		seq_puts(m, "slabinfo - version: 2.0 (statistics)\n");
+#else
+		seq_puts(m, "slabinfo - version: 2.0\n");
+#endif
+		seq_puts(m, "# name            active_objs num_objs objsize objperslab pagesperslab\n");
+		seq_puts(m, "#! tunables       batchcount limit sharedfactor\n");
+		seq_puts(m, "#! slabdata       active_slabs num_slabs sharedavail\n");
+#if STATS
+		seq_puts(m, "#! globalstat     listallocs maxobjs grown reaped error maxfreeable freelimit\n");
+		seq_puts(m, "#! cpustat N      allochit allocmiss freehit freemiss\n");
 #endif
-				"\n");
 	}
 	p = cache_chain.next;
 	while (n--) {
@@ -2469,13 +2476,16 @@ static int s_show(struct seq_file *m, vo
 	if (error)
 		printk(KERN_ERR "slab: cache %s error: %s\n", name, error);
 
-	seq_printf(m, "%-17s %6lu %6lu %6u %4lu %4lu %4u",
+	seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d\n",
 		name, active_objs, num_objs, cachep->objsize,
-		active_slabs, num_slabs, (1<<cachep->gfporder));
-
-	seq_printf(m, " : %4u %4u", cachep->limit, cachep->batchcount);
+		cachep->num, (1<<cachep->gfporder));
+	seq_printf(m, "! tunables          %4u %4u %4u\n",
+			cachep->limit, cachep->batchcount,
+			cachep->lists.shared->limit/cachep->batchcount);
+	seq_printf(m, "! slabdata        %6lu %6lu %6u\n",
+			active_slabs, num_slabs, cachep->lists.shared->avail);
 #if STATS
-	{	// list3 stats
+	{	/* list3 stats */
 		unsigned long high = cachep->high_mark;
 		unsigned long allocs = cachep->num_allocations;
 		unsigned long grown = cachep->grown;
@@ -2484,22 +2494,26 @@ static int s_show(struct seq_file *m, vo
 		unsigned long max_freeable = cachep->max_freeable;
 		unsigned long free_limit = cachep->free_limit;
 
-		seq_printf(m, " : %6lu %7lu %5lu %4lu %4lu %4lu %4lu",
-				high, allocs, grown, reaped, errors, 
+		seq_printf(m, "! globalstat     %7lu %6lu %5lu %4lu %4lu %4lu %4lu\n",
+				allocs, high, grown, reaped, errors, 
 				max_freeable, free_limit);
 	}
-	{	// cpucache stats
-		unsigned long allochit = atomic_read(&cachep->allochit);
-		unsigned long allocmiss = atomic_read(&cachep->allocmiss);
-		unsigned long freehit = atomic_read(&cachep->freehit);
-		unsigned long freemiss = atomic_read(&cachep->freemiss);
-
-		seq_printf(m, " : %6lu %6lu %6lu %6lu",
-				allochit, allocmiss, freehit, freemiss);
+	/* cpu stats */
+	{
+		int i;
+		for (i=0;i<NR_CPUS;i++) {
+			unsigned long allochit = cachep->allochit[i];
+			unsigned long allocmiss = cachep->allocmiss[i];
+			unsigned long freehit = cachep->freehit[i];
+			unsigned long freemiss = cachep->freemiss[i];
+
+			if (allochit | allocmiss | freehit | freemiss)
+				seq_printf(m, "! cpustat %3d     %6lu %6lu %6lu %6lu\n",
+					i, allochit, allocmiss, freehit, freemiss);
+		}
 	}
 #endif
 	spin_unlock_irq(&cachep->spinlock);
-	seq_putc(m, '\n');
 	return 0;
 }
 

_