From: Manfred Spraul The recent slab changes necessitate that additional info be exported from /proc/slabinfo. These include: - size of the shared array - number of allocations that were handled by the shared array (only if statistics is enabled). - It's important to identify if allocation/freeing is cpu bound, thus alloc/free data must be reported per-cpu. Given that slabinfo is already unweildy, and this adds a lot more stuff, it is time to change the format. We take it up to version 2.0. Manfred will update the slabinfo manpage and publish a parsing script. Adding per-cpu data to the single-line layout would make it completely unreadable, so it has been switched to a multi line layout. A header has been added which lists all fields. For example: slabinfo - version: 2.0 # name active_objs num_objs objsize objperslab pagesperslab #! tunables batchcount limit sharedfactor #! slabdata active_slabs num_slabs sharedavail rpc_buffers 8 8 2048 2 1 ! tunables 24 12 8 ! slabdata 4 4 0 rpc_tasks 8 24 160 24 1 ! tunables 120 60 8 ! slabdata 1 1 0 25-akpm/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 Tue May 27 13:40:55 2003 +++ 25-akpm/mm/slab.c Tue May 27 14:03:53 2003 @@ -278,10 +278,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 }; @@ -313,10 +313,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) @@ -2401,11 +2401,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--) { @@ -2489,13 +2496,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<gfporder)); - - seq_printf(m, " : %4u %4u", cachep->limit, cachep->batchcount); + cachep->num, (1<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; @@ -2504,22 +2514,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;iallochit[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; } _