From: Andrew Morton <akpm@zip.com.au>
To: Ed Tomlinson <tomlins@cam.org>
Cc: linux-mm@kvack.org
Subject: Re: slablru for 2.5.32-mm1
Date: Mon, 02 Sep 2002 11:35:31 -0700 [thread overview]
Message-ID: <3D73AF73.C8FE455@zip.com.au> (raw)
In-Reply-To: 200209021100.47508.tomlins@cam.org
Ed Tomlinson wrote:
>
> On September 2, 2002 01:26 am, Andrew Morton wrote:
> > Ed, this code can be sped up a bit, I think. We can make
> > kmem_count_page() return a boolean back to shrink_cache(), telling it
> > whether it needs to call kmem_do_prunes() at all. Often, there won't
> > be any work to do in there, and taking that semaphore can be quite
> > costly.
> >
> > The code as-is will even run kmem_do_prunes() when we're examining
> > ZONE_HIGHMEM, which certainly won't have any slab pages. This boolean
> > will fix that too.
>
> How about this? I have modified things so we only try for the sem if there
> is work to do. It also always uses a down_trylock - if we cannot do the prune
> now later is ok too...
>
well... Using a global like that is a bit un-linuxy. (bitops
are only defined on longs, btw...)
How about this one? It does both: tells the caller whether or
not to perform the shrink, and defers the pruning until we
have at least a page's worth of objects to be pruned.
Also, make sure that only the CPU which was responsible for
the transition-past-threshold is told to do some pruning. Reduces
the possibility of two CPUs running the prune.
Also, when we make the sweep across the to-be-pruned caches, only
prune the ones which are over threshold.
Breakpoint 1, age_dcache_memory (cachep=0xc189f66c, entries=396, gfp_mask=464) at dcache.c:585
Breakpoint 1, age_dcache_memory (cachep=0xc189f66c, entries=66, gfp_mask=464) at dcache.c:585
Breakpoint 1, age_dcache_memory (cachep=0xc189f66c, entries=429, gfp_mask=464) at dcache.c:585
Breakpoint 1, age_dcache_memory (cachep=0xc189f66c, entries=66, gfp_mask=464) at dcache.c:585
Breakpoint 1, age_dcache_memory (cachep=0xc189f66c, entries=264, gfp_mask=464) at dcache.c:585
Breakpoint 1, age_dcache_memory (cachep=0xc189f66c, entries=198, gfp_mask=464) at dcache.c:585
Breakpoint 1, age_dcache_memory (cachep=0xc189f66c, entries=66, gfp_mask=464) at dcache.c:585
Breakpoint 1, age_dcache_memory (cachep=0xc189f66c, entries=429, gfp_mask=464) at dcache.c:585
Breakpoint 1, age_dcache_memory (cachep=0xc189f66c, entries=66, gfp_mask=464) at dcache.c:585
Breakpoint 1, age_dcache_memory (cachep=0xc189f66c, entries=66, gfp_mask=464) at dcache.c:585
It'll make things a bit lumpier. Under high internal fragmentation
we'll suddenly release great gobs of pages, but I think it'll average
out OK.
What sayest thou?
include/linux/slab.h | 2 +-
mm/slab.c | 23 +++++++++++++++++++----
mm/vmscan.c | 22 ++++++++++++----------
3 files changed, 32 insertions(+), 15 deletions(-)
--- 2.5.33/mm/vmscan.c~slablru-speedup Mon Sep 2 11:07:33 2002
+++ 2.5.33-akpm/mm/vmscan.c Mon Sep 2 11:07:33 2002
@@ -95,8 +95,8 @@ static inline int is_page_cache_freeable
}
static /* inline */ int
-shrink_list(struct list_head *page_list, int nr_pages,
- unsigned int gfp_mask, int priority, int *max_scan)
+shrink_list(struct list_head *page_list, int nr_pages, unsigned int gfp_mask,
+ int priority, int *max_scan, int *prunes_needed)
{
struct address_space *mapping;
LIST_HEAD(ret_pages);
@@ -124,7 +124,7 @@ shrink_list(struct list_head *page_list,
*/
if (PageSlab(page)) {
int ref = TestClearPageReferenced(page);
- if (kmem_count_page(page, ref)) {
+ if (kmem_count_page(page, ref, prunes_needed)) {
if (kmem_shrink_slab(page))
goto free_ref;
}
@@ -292,8 +292,8 @@ keep:
* in the kernel (apart from the copy_*_user functions).
*/
static /* inline */ int
-shrink_cache(int nr_pages, struct zone *zone,
- unsigned int gfp_mask, int priority, int max_scan)
+shrink_cache(int nr_pages, struct zone *zone, unsigned int gfp_mask,
+ int priority, int max_scan, int *prunes_needed)
{
LIST_HEAD(page_list);
struct pagevec pvec;
@@ -342,8 +342,8 @@ shrink_cache(int nr_pages, struct zone *
max_scan -= n;
KERNEL_STAT_ADD(pgscan, n);
- nr_pages = shrink_list(&page_list, nr_pages,
- gfp_mask, priority, &max_scan);
+ nr_pages = shrink_list(&page_list, nr_pages, gfp_mask,
+ priority, &max_scan, prunes_needed);
if (nr_pages <= 0 && list_empty(&page_list))
goto done;
@@ -489,6 +489,7 @@ shrink_zone(struct zone *zone, int prior
{
unsigned long ratio;
int max_scan;
+ int prunes_needed = 0;
/*
* Try to keep the active list 2/3 of the size of the cache. And
@@ -509,9 +510,10 @@ shrink_zone(struct zone *zone, int prior
}
max_scan = zone->nr_inactive / priority;
- nr_pages = shrink_cache(nr_pages, zone,
- gfp_mask, priority, max_scan);
- kmem_do_prunes(gfp_mask);
+ nr_pages = shrink_cache(nr_pages, zone, gfp_mask,
+ priority, max_scan, &prunes_needed);
+ if (prunes_needed)
+ kmem_do_prunes(gfp_mask);
if (nr_pages <= 0)
return 0;
--- 2.5.33/mm/slab.c~slablru-speedup Mon Sep 2 11:07:33 2002
+++ 2.5.33-akpm/mm/slab.c Mon Sep 2 11:30:27 2002
@@ -217,7 +217,8 @@ struct kmem_cache_s {
unsigned int growing;
unsigned int dflags; /* dynamic flags */
kmem_pruner_t pruner; /* shrink callback */
- int count; /* count used to trigger shrink */
+ int count; /* nr of objects to be pruned */
+ int prune_thresh; /* threshold triggers pruning */
/* constructor func */
void (*ctor)(void *, kmem_cache_t *, unsigned long);
@@ -418,8 +419,11 @@ static void enable_all_cpucaches (void);
/*
* Used by shrink_cache to determine caches that need pruning.
+ *
+ * If this particular call to kmem_count_page takes a slab over its to-be-pruned
+ * threshold then we tell the caller that kmem_do_prunes() needs to be called.
*/
-int kmem_count_page(struct page *page, int ref)
+int kmem_count_page(struct page *page, int ref, int *prunes_needed)
{
kmem_cache_t *cachep = GET_PAGE_CACHE(page);
slab_t *slabp = GET_PAGE_SLAB(page);
@@ -427,7 +431,12 @@ int kmem_count_page(struct page *page, i
spin_lock_irq(&cachep->spinlock);
if (cachep->pruner != NULL) {
+ int old_count = cachep->count;
+
cachep->count += slabp->inuse;
+ if (old_count < cachep->prune_thresh &&
+ cachep->count >= cachep->prune_thresh)
+ *prunes_needed = 1;
ret = !slabp->inuse;
} else {
ret = !ref && !slabp->inuse;
@@ -453,8 +462,11 @@ int kmem_do_prunes(int gfp_mask)
kmem_cache_t *cachep = list_entry(p, kmem_cache_t, next);
if (cachep->pruner != NULL) {
spin_lock_irq(&cachep->spinlock);
- nr = cachep->count;
- cachep->count = 0;
+ nr = 0;
+ if (cachep->count >= cachep->prune_thresh) {
+ nr = cachep->count;
+ cachep->count = 0;
+ }
spin_unlock_irq(&cachep->spinlock);
if (nr > 0)
(*cachep->pruner)(cachep, nr, gfp_mask);
@@ -872,6 +884,9 @@ next:
cachep->flags = flags;
cachep->pruner = thepruner;
cachep->count = 0;
+ cachep->prune_thresh = 0;
+ if (thepruner)
+ cachep->prune_thresh = PAGE_SIZE / size;
cachep->gfpflags = 0;
if (flags & SLAB_CACHE_DMA)
cachep->gfpflags |= GFP_DMA;
--- 2.5.33/include/linux/slab.h~slablru-speedup Mon Sep 2 11:07:33 2002
+++ 2.5.33-akpm/include/linux/slab.h Mon Sep 2 11:07:33 2002
@@ -60,7 +60,7 @@ extern int kmem_cache_destroy(kmem_cache
extern int kmem_cache_shrink(kmem_cache_t *);
extern int kmem_do_prunes(int);
-extern int kmem_count_page(struct page *, int);
+extern int kmem_count_page(struct page *page, int ref, int *prunes_needed);
#define kmem_touch_page(addr) SetPageReferenced(virt_to_page(addr));
/* shrink a slab */
.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/
next prev parent reply other threads:[~2002-09-02 18:35 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-08-26 22:09 MM patches against 2.5.31 Ed Tomlinson
2002-08-26 22:09 ` Ed Tomlinson
2002-08-26 23:58 ` Andrew Morton
2002-08-26 23:58 ` Andrew Morton
2002-08-27 0:13 ` Rik van Riel
2002-08-27 0:13 ` Rik van Riel
2002-08-28 17:06 ` slablru for 2.5.32-mm1 Ed Tomlinson
2002-08-28 21:24 ` Andrew Morton
2002-08-28 22:23 ` Rik van Riel
2002-09-02 5:26 ` Andrew Morton
2002-09-02 15:00 ` Ed Tomlinson
2002-09-02 18:35 ` Andrew Morton [this message]
2002-09-02 19:09 ` Ed Tomlinson
2002-09-02 19:51 ` Andrew Morton
2002-09-02 6:50 ` Andrew Morton
-- strict thread matches above, loose matches on Subject: below --
2002-08-28 22:11 Ed Tomlinson
2002-09-06 4:07 Craig Kulesa
2002-09-06 4:24 ` Robert Love
2002-09-08 21:43 ` Daniel Phillips
2002-09-09 4:36 ` Robert Love
2002-09-09 5:10 ` Daniel Phillips
2002-09-06 4:38 ` Andrew Morton
2002-09-06 11:39 ` Ed Tomlinson
2002-09-06 18:57 ` Craig Kulesa
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3D73AF73.C8FE455@zip.com.au \
--to=akpm@zip.com.au \
--cc=linux-mm@kvack.org \
--cc=tomlins@cam.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.