Re: Large slab cache in 2.6.1

From: Nick Piggin
Date: Sat Feb 21 2004 - 23:03:04 EST




Chris Wedgwood wrote:

On Sat, Feb 21, 2004 at 07:28:24PM -0800, Linus Torvalds wrote:


What happened to the experiment of having slab pages on the
(in)active lists and letting them be free'd that way? Didn't
somebody already do that? Ed Tomlinson and Craig Kulesa?


Just as a data point:

cw@taniwha:~/wk/linux/bk-2.5.x$ grep -E '(LowT|Slab)' /proc/meminfo
LowTotal: 898448 kB
Slab: 846260 kB

So the slab pressure I have right now is simply because there is
nowhere else it has to grow...



Can you try the following patch? It is against 2.6.3-mm2.

linux-2.6-npiggin/fs/dcache.c | 4 ++--
linux-2.6-npiggin/fs/dquot.c | 2 +-
linux-2.6-npiggin/fs/inode.c | 4 ++--
linux-2.6-npiggin/fs/mbcache.c | 2 +-
linux-2.6-npiggin/fs/xfs/linux/kmem.h | 2 +-
linux-2.6-npiggin/include/linux/mm.h | 3 +--
linux-2.6-npiggin/mm/vmscan.c | 22 ++++++++++++----------
7 files changed, 20 insertions(+), 19 deletions(-)

diff -puN mm/vmscan.c~vm-slab-balance mm/vmscan.c
--- linux-2.6/mm/vmscan.c~vm-slab-balance 2004-02-22 14:52:45.000000000 +1100
+++ linux-2.6-npiggin/mm/vmscan.c 2004-02-22 15:00:24.000000000 +1100
@@ -82,7 +82,6 @@ static long total_memory;
struct shrinker {
shrinker_t shrinker;
struct list_head list;
- int seeks; /* seeks to recreate an obj */
long nr; /* objs pending delete */
};

@@ -92,14 +91,13 @@ static DECLARE_MUTEX(shrinker_sem);
/*
* Add a shrinker callback to be called from the vm
*/
-struct shrinker *set_shrinker(int seeks, shrinker_t theshrinker)
+struct shrinker *set_shrinker(shrinker_t theshrinker)
{
struct shrinker *shrinker;

shrinker = kmalloc(sizeof(*shrinker), GFP_KERNEL);
if (shrinker) {
shrinker->shrinker = theshrinker;
- shrinker->seeks = seeks;
shrinker->nr = 0;
down(&shrinker_sem);
list_add(&shrinker->list, &shrinker_list);
@@ -139,20 +137,24 @@ EXPORT_SYMBOL(remove_shrinker);
*/
static int shrink_slab(unsigned long scanned, unsigned int gfp_mask)
{
+ unsigned long long to_scan = scanned;
+ unsigned long slab_size = 0;
struct shrinker *shrinker;
- long pages;

if (down_trylock(&shrinker_sem))
return 0;

- pages = nr_used_zone_pages();
list_for_each_entry(shrinker, &shrinker_list, list) {
- unsigned long long delta;
+ slab_size += (*shrinker->shrinker)(0, gfp_mask);
+ }

- delta = 4 * scanned / shrinker->seeks;
- delta *= (*shrinker->shrinker)(0, gfp_mask);
- do_div(delta, pages + 1);
- shrinker->nr += delta;
+ list_for_each_entry(shrinker, &shrinker_list, list) {
+ unsigned long long delta = to_scan;
+ int this_size = (*shrinker->shrinker)(0, gfp_mask);
+ delta *= this_size;
+ do_div(delta, slab_size + 1);
+ /* + 1 to make sure some scanning is eventually done */
+ shrinker->nr += delta + 1;
if (shrinker->nr > SHRINK_BATCH) {
long nr_to_scan = shrinker->nr;

diff -puN include/linux/mm.h~vm-slab-balance include/linux/mm.h
--- linux-2.6/include/linux/mm.h~vm-slab-balance 2004-02-22 14:52:45.000000000 +1100
+++ linux-2.6-npiggin/include/linux/mm.h 2004-02-22 14:52:45.000000000 +1100
@@ -483,9 +483,8 @@ typedef int (*shrinker_t)(int nr_to_scan
* to recreate one of the objects that these functions age.
*/

-#define DEFAULT_SEEKS 2
struct shrinker;
-extern struct shrinker *set_shrinker(int, shrinker_t);
+extern struct shrinker *set_shrinker(shrinker_t);
extern void remove_shrinker(struct shrinker *shrinker);

/*
diff -puN fs/dcache.c~vm-slab-balance fs/dcache.c
--- linux-2.6/fs/dcache.c~vm-slab-balance 2004-02-22 14:52:45.000000000 +1100
+++ linux-2.6-npiggin/fs/dcache.c 2004-02-22 14:52:45.000000000 +1100
@@ -657,7 +657,7 @@ static int shrink_dcache_memory(int nr,
if (gfp_mask & __GFP_FS)
prune_dcache(nr);
}
- return dentry_stat.nr_unused;
+ return dentry_stat.nr_dentry;
}

#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
@@ -1564,7 +1564,7 @@ static void __init dcache_init(unsigned
if (!dentry_cache)
panic("Cannot create dentry cache");

- set_shrinker(DEFAULT_SEEKS, shrink_dcache_memory);
+ set_shrinker(shrink_dcache_memory);

if (!dhash_entries)
dhash_entries = PAGE_SHIFT < 13 ?
diff -puN fs/dquot.c~vm-slab-balance fs/dquot.c
--- linux-2.6/fs/dquot.c~vm-slab-balance 2004-02-22 14:52:45.000000000 +1100
+++ linux-2.6-npiggin/fs/dquot.c 2004-02-22 14:52:45.000000000 +1100
@@ -1661,7 +1661,7 @@ static int __init dquot_init(void)
if (!dquot_cachep)
panic("Cannot create dquot SLAB cache");

- set_shrinker(DEFAULT_SEEKS, shrink_dqcache_memory);
+ set_shrinker(shrink_dqcache_memory);

return 0;
}
diff -puN fs/inode.c~vm-slab-balance fs/inode.c
--- linux-2.6/fs/inode.c~vm-slab-balance 2004-02-22 14:52:45.000000000 +1100
+++ linux-2.6-npiggin/fs/inode.c 2004-02-22 14:52:45.000000000 +1100
@@ -479,7 +479,7 @@ static int shrink_icache_memory(int nr,
if (gfp_mask & __GFP_FS)
prune_icache(nr);
}
- return inodes_stat.nr_unused;
+ return inodes_stat.nr_inodes;
}

static void __wait_on_freeing_inode(struct inode *inode);
@@ -1394,7 +1394,7 @@ void __init inode_init(unsigned long mem
if (!inode_cachep)
panic("cannot create inode slab cache");

- set_shrinker(DEFAULT_SEEKS, shrink_icache_memory);
+ set_shrinker(shrink_icache_memory);
}

void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
diff -puN fs/mbcache.c~vm-slab-balance fs/mbcache.c
--- linux-2.6/fs/mbcache.c~vm-slab-balance 2004-02-22 14:52:45.000000000 +1100
+++ linux-2.6-npiggin/fs/mbcache.c 2004-02-22 14:52:45.000000000 +1100
@@ -629,7 +629,7 @@ mb_cache_entry_find_next(struct mb_cache

static int __init init_mbcache(void)
{
- mb_shrinker = set_shrinker(DEFAULT_SEEKS, mb_cache_shrink_fn);
+ mb_shrinker = set_shrinker(mb_cache_shrink_fn);
return 0;
}

diff -puN fs/xfs/linux/kmem.h~vm-slab-balance fs/xfs/linux/kmem.h
--- linux-2.6/fs/xfs/linux/kmem.h~vm-slab-balance 2004-02-22 14:52:45.000000000 +1100
+++ linux-2.6-npiggin/fs/xfs/linux/kmem.h 2004-02-22 14:52:45.000000000 +1100
@@ -171,7 +171,7 @@ typedef int (*kmem_shake_func_t)(int, un
static __inline kmem_shaker_t
kmem_shake_register(kmem_shake_func_t sfunc)
{
- return set_shrinker(DEFAULT_SEEKS, sfunc);
+ return set_shrinker(sfunc);
}

static __inline void

_