Avoid excessive time spend on concurrent slab shrinking

Christoph Lameter
2006-03-31T22:46:06Z

We experienced that concurrent slab shrinking on 2.6.16 can slow down a
system excessively due to lock contention. Slab shrinking is a global
operation so it does not make sense for multiple slab shrink operations
to be ongoing at the same time. The single shrinking task can perform the
shrinking for all nodes and processors in the system. Introduce an atomic
counter that works in the same was as in shrink_zone to limit concurrent
shrinking.

Also calculate the time it took to do the shrinking and wait at least twice
that time before doing it again. If we are spending excessive time
on slab shrinking then we need to pause for some time to insure that the
system is capable of archiving other tasks.

Signed-off-by: Christoph Lameter <clameter@sgi.com>

Index: linux-2.6.16/mm/vmscan.c
===================================================================
--- linux-2.6.16.orig/mm/vmscan.c 2006-03-19 21:53:29.000000000 -0800
+++ linux-2.6.16/mm/vmscan.c 2006-03-31 14:38:18.000000000 -0800
@@ -130,6 +130,8 @@ static long total_memory;

static LIST_HEAD(shrinker_list);
static DECLARE_RWSEM(shrinker_rwsem);
+static atomic_t active_shrinkers;
+static unsigned long next_slab_shrink;

/*
* Add a shrinker callback to be called from the vm
@@ -187,12 +189,18 @@ int shrink_slab(unsigned long scanned, g
{
struct shrinker *shrinker;
int ret = 0;
+ unsigned long shrinkstart;

if (scanned == 0)
scanned = SWAP_CLUSTER_MAX;

- if (!down_read_trylock(&shrinker_rwsem))
- return 1; /* Assume we'll be able to shrink next time */
+ if (atomic_read(&active_shrinkers) ||
+ time_before(jiffies, next_slab_shrink) ||
+ !down_read_trylock(&shrinker_rwsem))
+ /* Assume we'll be able to shrink next time */
+ return 1;
+ atomic_inc(&active_shrinkers);
+ shrinkstart = jiffies;

list_for_each_entry(shrinker, &shrinker_list, list) {
unsigned long long delta;
@@ -239,6 +247,12 @@ int shrink_slab(unsigned long scanned, g

shrinker->nr += total_scan;
}
+ /*
+ * If slab shrinking took a long time then lets at least wait
+ * twice as long as it took before we do it again.
+ */
+ next_slab_shrink = jiffies + 2 * (jiffies - shrinkstart);
+ atomic_dec(&active_shrinkers);
up_read(&shrinker_rwsem);
return ret;
}