From: Manfred Spraul The attached patch adds the ability to change the size of the new shared array at runtime, by writing to /proc/slabinfo. Additionally, it reduces the default sizes of the array caches. mm/slab.c | 46 +++++++++++++++++++++++++++++----------------- 1 files changed, 29 insertions(+), 17 deletions(-) diff -puN mm/slab.c~slab-magazine-tuning mm/slab.c --- 25/mm/slab.c~slab-magazine-tuning 2003-05-22 01:15:59.000000000 -0700 +++ 25-akpm/mm/slab.c 2003-05-22 01:15:59.000000000 -0700 @@ -201,7 +201,6 @@ struct arraycache_init { * into this structure, too. Figure out what causes * fewer cross-node spinlock operations. */ -#define SHARED_ARRAY_FACTOR 16 struct kmem_list3 { struct list_head slabs_partial; /* partial list first, better asm code */ struct list_head slabs_free; @@ -2109,7 +2108,7 @@ static void do_ccupdate_local(void *info } -static int do_tune_cpucache (kmem_cache_t* cachep, int limit, int batchcount) +static int do_tune_cpucache (kmem_cache_t* cachep, int limit, int batchcount, int shared) { struct ccupdate_struct new; struct array_cache *new_shared; @@ -2151,12 +2150,12 @@ static int do_tune_cpucache (kmem_cache_ spin_unlock_irq(&cachep->spinlock); kfree(ccold); } - new_shared = kmalloc(sizeof(void*)*batchcount*SHARED_ARRAY_FACTOR+ + new_shared = kmalloc(sizeof(void*)*batchcount*shared+ sizeof(struct array_cache), GFP_KERNEL); if (new_shared) { struct array_cache *old; new_shared->avail = 0; - new_shared->limit = batchcount*SHARED_ARRAY_FACTOR; + new_shared->limit = batchcount*shared; new_shared->batchcount = 0xbaadf00d; new_shared->touched = 0; @@ -2176,7 +2175,7 @@ static int do_tune_cpucache (kmem_cache_ static void enable_cpucache (kmem_cache_t *cachep) { int err; - int limit; + int limit, shared; /* The head array serves three purposes: * - create a LIFO ordering, i.e. return objects that are cache-warm @@ -2191,11 +2190,25 @@ static void enable_cpucache (kmem_cache_ else if (cachep->objsize > PAGE_SIZE) limit = 8; else if (cachep->objsize > 1024) - limit = 54; + limit = 24; else if (cachep->objsize > 256) - limit = 120; + limit = 54; else - limit = 248; + limit = 120; + + /* Cpu bound tasks (e.g. network routing) can exhibit cpu bound + * allocation behaviour: Most allocs on one cpu, most free operations + * on another cpu. For these cases, an efficient object passing between + * cpus is necessary. This is provided by a shared array. The array + * replaces Bonwick's magazine layer. + * On uniprocessor, it's functionally equivalent (but less efficient) + * to a larger limit. Thus disabled by default. + */ + shared = 0; +#ifdef CONFIG_SMP + if (cachep->objsize <= PAGE_SIZE) + shared = 8; +#endif #if DEBUG /* With debugging enabled, large batchcount lead to excessively @@ -2205,7 +2218,7 @@ static void enable_cpucache (kmem_cache_ if (limit > 32) limit = 32; #endif - err = do_tune_cpucache(cachep, limit, (limit+1)/2); + err = do_tune_cpucache(cachep, limit, (limit+1)/2, shared); if (err) printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n", cachep->name, -err); @@ -2513,7 +2526,7 @@ struct seq_operations slabinfo_op = { #define MAX_SLABINFO_WRITE 128 /** - * slabinfo_write - SMP tuning for the slab allocator + * slabinfo_write - Tuning for the slab allocator * @file: unused * @buffer: user buffer * @count: data len @@ -2523,7 +2536,7 @@ ssize_t slabinfo_write(struct file *file size_t count, loff_t *ppos) { char kbuf[MAX_SLABINFO_WRITE+1], *tmp; - int limit, batchcount, res; + int limit, batchcount, shared, res; struct list_head *p; if (count > MAX_SLABINFO_WRITE) @@ -2537,10 +2550,8 @@ ssize_t slabinfo_write(struct file *file return -EINVAL; *tmp = '\0'; tmp++; - limit = simple_strtol(tmp, &tmp, 10); - while (*tmp == ' ') - tmp++; - batchcount = simple_strtol(tmp, &tmp, 10); + if (sscanf(tmp, " %d %d %d", &limit, &batchcount, &shared) != 3) + return -EINVAL; /* Find the cache in the chain of caches. */ down(&cache_chain_sem); @@ -2551,10 +2562,11 @@ ssize_t slabinfo_write(struct file *file if (!strcmp(cachep->name, kbuf)) { if (limit < 1 || batchcount < 1 || - batchcount > limit) { + batchcount > limit || + shared < 0) { res = -EINVAL; } else { - res = do_tune_cpucache(cachep, limit, batchcount); + res = do_tune_cpucache(cachep, limit, batchcount, shared); } break; } _