提交 35386e3b 编写于 作者: C Christoph Lameter 提交者: Linus Torvalds

[PATCH] slab: cache_reap(): further reduction in interrupt holdoff

cache_reap takes the l3->list_lock (disabling interrupts) unconditionally
and then does a few checks and maybe does some cleanup.  This patch makes
cache_reap() only take the lock if there is work to do and then the lock is
taken and released for each cleaning action.

The checking of when to do the next reaping is done without any locking and
becomes racy.  Should not matter since reaping can also be skipped if the
slab mutex cannot be acquired.

The same is true for the touched processing.  If we get this wrong once in
awhile then we will mistakenly clean or not clean the shared cache.  This
will impact performance slightly.

Note that the additional drain_array() function introduced here will fall
out in a subsequent patch since array cleaning will now be very similar
from all callers.
Signed-off-by: NChristoph Lameter <clameter@sgi.com>
Cc: Pekka Enberg <penberg@cs.helsinki.fi>
Cc: Manfred Spraul <manfred@colorfullife.com>
Signed-off-by: NAndrew Morton <akpm@osdl.org>
Signed-off-by: NLinus Torvalds <torvalds@osdl.org>
上级 248a0301
...@@ -292,13 +292,13 @@ struct kmem_list3 { ...@@ -292,13 +292,13 @@ struct kmem_list3 {
struct list_head slabs_full; struct list_head slabs_full;
struct list_head slabs_free; struct list_head slabs_free;
unsigned long free_objects; unsigned long free_objects;
unsigned long next_reap;
int free_touched;
unsigned int free_limit; unsigned int free_limit;
unsigned int colour_next; /* Per-node cache coloring */ unsigned int colour_next; /* Per-node cache coloring */
spinlock_t list_lock; spinlock_t list_lock;
struct array_cache *shared; /* shared per node */ struct array_cache *shared; /* shared per node */
struct array_cache **alien; /* on other nodes */ struct array_cache **alien; /* on other nodes */
unsigned long next_reap; /* updated without locking */
int free_touched; /* updated without locking */
}; };
/* /*
...@@ -3539,6 +3539,22 @@ static void drain_array_locked(struct kmem_cache *cachep, ...@@ -3539,6 +3539,22 @@ static void drain_array_locked(struct kmem_cache *cachep,
} }
} }
/*
* Drain an array if it contains any elements taking the l3 lock only if
* necessary.
*/
static void drain_array(struct kmem_cache *searchp, struct kmem_list3 *l3,
struct array_cache *ac)
{
if (ac && ac->avail) {
spin_lock_irq(&l3->list_lock);
drain_array_locked(searchp, ac, 0,
numa_node_id());
spin_unlock_irq(&l3->list_lock);
}
}
/** /**
* cache_reap - Reclaim memory from caches. * cache_reap - Reclaim memory from caches.
* @unused: unused parameter * @unused: unused parameter
...@@ -3572,33 +3588,48 @@ static void cache_reap(void *unused) ...@@ -3572,33 +3588,48 @@ static void cache_reap(void *unused)
searchp = list_entry(walk, struct kmem_cache, next); searchp = list_entry(walk, struct kmem_cache, next);
check_irq_on(); check_irq_on();
/*
* We only take the l3 lock if absolutely necessary and we
* have established with reasonable certainty that
* we can do some work if the lock was obtained.
*/
l3 = searchp->nodelists[numa_node_id()]; l3 = searchp->nodelists[numa_node_id()];
reap_alien(searchp, l3); reap_alien(searchp, l3);
spin_lock_irq(&l3->list_lock);
drain_array_locked(searchp, cpu_cache_get(searchp), 0, drain_array(searchp, l3, cpu_cache_get(searchp));
numa_node_id());
/*
* These are racy checks but it does not matter
* if we skip one check or scan twice.
*/
if (time_after(l3->next_reap, jiffies)) if (time_after(l3->next_reap, jiffies))
goto next_unlock; goto next;
l3->next_reap = jiffies + REAPTIMEOUT_LIST3; l3->next_reap = jiffies + REAPTIMEOUT_LIST3;
if (l3->shared) drain_array(searchp, l3, l3->shared);
drain_array_locked(searchp, l3->shared, 0,
numa_node_id());
if (l3->free_touched) { if (l3->free_touched) {
l3->free_touched = 0; l3->free_touched = 0;
goto next_unlock; goto next;
} }
tofree = (l3->free_limit + 5 * searchp->num - 1) / tofree = (l3->free_limit + 5 * searchp->num - 1) /
(5 * searchp->num); (5 * searchp->num);
do { do {
/*
* Do not lock if there are no free blocks.
*/
if (list_empty(&l3->slabs_free))
break;
spin_lock_irq(&l3->list_lock);
p = l3->slabs_free.next; p = l3->slabs_free.next;
if (p == &(l3->slabs_free)) if (p == &(l3->slabs_free)) {
spin_unlock_irq(&l3->list_lock);
break; break;
}
slabp = list_entry(p, struct slab, list); slabp = list_entry(p, struct slab, list);
BUG_ON(slabp->inuse); BUG_ON(slabp->inuse);
...@@ -3613,10 +3644,8 @@ static void cache_reap(void *unused) ...@@ -3613,10 +3644,8 @@ static void cache_reap(void *unused)
l3->free_objects -= searchp->num; l3->free_objects -= searchp->num;
spin_unlock_irq(&l3->list_lock); spin_unlock_irq(&l3->list_lock);
slab_destroy(searchp, slabp); slab_destroy(searchp, slabp);
spin_lock_irq(&l3->list_lock);
} while (--tofree > 0); } while (--tofree > 0);
next_unlock: next:
spin_unlock_irq(&l3->list_lock);
cond_resched(); cond_resched();
} }
check_irq_on(); check_irq_on();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册