Linear reclaim V1
Subsystems (7)
cover Linear reclaim V1
Linear Reclaim (V1)
When we are out of memory of a suitable size we enter reclaim. The current reclaim algorithm targets pages in LRU order, which is great for fairness but highly unsuitable if you desire pages at higher orders. To get pages of higher order we must shoot down a very high proportion of memory; >95% in a lot of cases.
This patch set adds a linear reclaim algorithm to the allocator. It targets groups of pages at the specified order rather than in lru order. Passing over each area at this size and assessing the likelyhood of reclaiming all of the pages within. If chances are high, we apply reclaim to all of the busy pages in this area in the hopes of consolidating a complete page at that order. This is designed to be used when we are out of higher order pages.
This patch set is particularly effective when utilised with an anti-fragmentation scheme which groups pages of similar reclaimability together.
As it stands we introduce a complete second reclaim algorithm. Once this has stablised it would make sense to merge the two algorithms. Targetting variable size blocks using pages at the end of the LRU as seeds. When operating at order 0 the algorithms would then be equivalent.
-apw
Base: 2.6.18-rc5-mm1
Patches:
o linear-reclaim-add-order-to-reclaim-path
o linear-reclaim-export-page_order-and-family
o linear-reclaim-pull-out-unfreeable-page-return
o linear-reclaim-add-pfn_valid_within-for-zone-holes
o linear-reclaim-core
Current version: V1
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/5 linear reclaim add order to reclaim path
linear reclaim add order to reclaim path
In order to select an appropriate reclaim algorithm we need to know the order of the original failure. Pass the order down in the reclaim path.
Added in: V1
---
fs/buffer.c +1 -1
@@ -371,7 +371,7 @@ static void free_more_memory(void)for_each_online_pgdat (pgdat) { zones = pgdat->node_zonelists[gfp_zone (GFP_NOFS )].zones;if (*zones) -try_to_free_pages (zones,GFP_NOFS ); +try_to_free_pages (zones,0 ,GFP_NOFS ); } }
include/linux/swap.h +1 -1
@@ -187,7 +187,7 @@ extern int rotate_reclaimable_page(strucextern void swap_setup (void );/* linux/mm/vmscan.c */ -extern unsigned long try_to_free_pages (struct zone **,gfp_t ); +extern unsigned long try_to_free_pages (struct zone **,int ,gfp_t );extern unsigned long shrink_all_memory (unsigned long nr_pages);extern int vm_swappiness;extern int remove_mapping (struct address_space *mapping,struct page *page);
mm/page_alloc.c +1 -1
@@ -1132,7 +1132,7 @@ rebalance: reclaim_state.reclaimed_slab =0 ; p->reclaim_state = &reclaim_state; - did_some_progress =try_to_free_pages (zonelist->zones, gfp_mask); + did_some_progress =try_to_free_pages (zonelist->zones, order, gfp_mask); p->reclaim_state =NULL ; p->flags &= ~PF_MEMALLOC ;
mm/vmscan.c +1 -1
@@ -978,7 +978,7 @@ static unsigned long shrink_zones(int pr* holds filesystem locks which prevent writeout this might not work, and the * allocation attempt will fail. */ -unsigned long try_to_free_pages (struct zone **zones,gfp_t gfp_mask) +unsigned long try_to_free_pages (struct zone **zones,int order,gfp_t gfp_mask) {int priority;int ret =0 ;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 2/5 linear reclaim export page_order and family
In reply to Andy Whitcroftlinear reclaim export page_order and family
We need the free page page order in the linear reclaim algorithm. Export page_order and friends, adding a note indicating that they are only valid when a page is free and owned by the buddy allocator.
Added in: V1
---
include/linux/mm.h +27 -0
@@ -292,6 +292,33 @@ #define VM_BUG_ON(condition) do { } whil#endif /* +* function for dealing with page's order in buddy system. +* zone->lock is already acquired when we use these. +* So, we don't need atomic page->flags operations here. +* NOTE: these are only valid on free pages owned by the buddy +* allocator. +*/ +static inline unsigned long page_order (struct page *page) +{ +VM_BUG_ON (!PageBuddy (page)); +return page_private (page); +} + +static inline void set_page_order (struct page *page,int order) +{ +VM_BUG_ON (PageBuddy (page)); +set_page_private (page, order); +__SetPageBuddy (page); +} + +static inline void rmv_page_order (struct page *page) +{ +VM_BUG_ON (!PageBuddy (page)); +__ClearPageBuddy (page); +set_page_private (page,0 ); +} + +/* * Methods to modify the page usage count. * * What counts for a page usage:
mm/page_alloc.c +0 -22
@@ -290,28 +290,6 @@ static inline void prep_zero_page(struct }/* -* function for dealing with page's order in buddy system. -* zone->lock is already acquired when we use these. -* So, we don't need atomic page->flags operations here. -*/ -static inline unsigned long page_order (struct page *page) -{ -return page_private (page); -} - -static inline void set_page_order (struct page *page,int order) -{ -set_page_private (page, order); -__SetPageBuddy (page); -} - -static inline void rmv_page_order (struct page *page) -{ -__ClearPageBuddy (page); -set_page_private (page,0 ); -} - -/* * Locate the struct page for both the matching buddy in our * pair (buddy1) and the combined O(n+1) page they form (page). *
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 3/5 linear reclaim pull out unfreeable page return
In reply to Andy Whitcroftlinear reclaim pull out unfreeable page return
Both lru reclaim and linear reclaim need to return unused pages. Pull out unfreeable page return code for later use by linear reclaim.
Added in: V1
---
mm/vmscan.c +28 -19
@@ -632,6 +632,32 @@ static unsigned long isolate_lru_pages(u }/* +* Put back any unfreeable pages, returning them to the appropriate +* lru list. +*/ +static void return_unfreeable_pages (struct list_head *page_list, +struct zone *zone,struct pagevec *pvec) +{ +struct page *page; + +while (!list_empty (page_list)) { + page =lru_to_page (page_list); +VM_BUG_ON (PageLRU (page)); +SetPageLRU (page); +list_del (&page->lru); +if (PageActive (page)) +add_page_to_active_list (zone, page); +else +add_page_to_inactive_list (zone, page); +if (!pagevec_add (pvec, page)) { +spin_unlock_irq (&zone->lru_lock); +__pagevec_release (pvec); +spin_lock_irq (&zone->lru_lock); + } + } +} + +/* * shrink_inactive_list() is a helper for shrink_zone(). It returns the number * of reclaimed pages */
@@ -648,7 +674,6 @@ static unsigned long shrink_inactive_lislru_add_drain ();spin_lock_irq (&zone->lru_lock); do { - struct page *page; unsigned long nr_taken; unsigned long nr_scan; unsigned long nr_freed;
@@ -676,24 +701,8 @@ static unsigned long shrink_inactive_lis goto done;spin_lock (&zone->lru_lock); -/* -* Put back any unfreeable pages. -*/ -while (!list_empty (&page_list)) { - page =lru_to_page (&page_list); -VM_BUG_ON (PageLRU (page)); -SetPageLRU (page); -list_del (&page->lru); -if (PageActive (page)) -add_page_to_active_list (zone, page); -else -add_page_to_inactive_list (zone, page); -if (!pagevec_add (&pvec, page)) { -spin_unlock_irq (&zone->lru_lock); -__pagevec_release (&pvec); -spin_lock_irq (&zone->lru_lock); - } - } + +return_unfreeable_pages (&page_list, zone, &pvec); }while (nr_scanned < max_scan);spin_unlock (&zone->lru_lock); done:
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 4/5 linear reclaim add pfn_valid_within for zone holes
In reply to Andy Whitcroftlinear reclaim add pfn_valid_within for zone holes
Generally we work under the assumption that memory the mem_map array is contigious and valid out to MAX_ORDER blocks. When this is not true we much check each and every reference we make from a pfn. Add a pfn_valid_within() which should be used when checking pages within a block when we have already checked the validility of the block normally. This can then be optimised away when we have holes.
Added in: V1
---
include/linux/mmzone.h +12 -0
@@ -680,6 +680,18 @@ #endifvoid memory_present (int nid,unsigned long start,unsigned long end);unsigned long __init node_memmap_size_bytes (int ,unsigned long ,unsigned long ); +/* +* If we have holes within zones (smaller than MAX_ORDER) then we need +* to check pfn validility within MAX_ORDER blocks. pfn_valid_within +* should be used in this case; we optimise this away when we have +* no holes. +*/ +#ifdef CONFIG_HOLES_IN_ZONE +#define pfn_valid_within (pfn) pfn_valid(pfn) +#else +#define pfn_valid_within (pfn) (1) +#endif +#endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _LINUX_MMZONE_H */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 5/5 linear reclaim core
In reply to Andy Whitcroftlinear reclaim core
When we are out of memory of a suitable size we enter reclaim. The current reclaim algorithm targets pages in LRU order, which is great for fairness but highly unsuitable if you desire pages at higher orders. To get pages of higher order we must shoot down a very high proportion of memory; >95% in a lot of cases.
This patch introduces an alternative algorithm used when requesting higher order allocations. Here we look at memory in ranges at the order requested. We make a quick pass to see if all pages in that area are likely to be reclaimed, only then do we apply reclaim to the pages in the area.
Testing in combination with fragmentation avoidance shows significantly improved chances of a successful allocation at higher order.
Added in: V1
Issues:
o no longer need to be MAX_ORDER aligned with new iterators
---
include/linux/mmzone.h +1 -0
@@ -199,6 +199,7 @@ #endifunsigned long nr_inactive;unsigned long pages_scanned;/* since last reclaim */ int all_unreclaimable;/* All pages pinned */ +unsigned long linear_scan_hand;/* The accumulated number of activities that may cause page aging, * that is, make some pages closer to the tail of inactive_list.
mm/page_alloc.c +1 -0
@@ -2049,6 +2049,7 @@ __meminit int init_currently_empty_zone( pgdat->nr_zones =zone_idx (zone) +1 ; zone->zone_start_pfn = zone_start_pfn; + zone->linear_scan_hand = zone_start_pfn;memmap_init (size, pgdat->node_id,zone_idx (zone), zone_start_pfn);
mm/vmscan.c +299 -1
315 lines not on this page · raw message
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 5/5] linear reclaim core
Quoted 12 lines · On Fri, 8 Sep 2006 13:27:18 +0100 Andy Whitcroft <[email protected]> wrote:
When we are out of memory of a suitable size we enter reclaim. The current reclaim algorithm targets pages in LRU order, which is great for fairness but highly unsuitable if you desire pages at higher orders. To get pages of higher order we must shoot down a very high proportion of memory; >95% in a lot of cases.
This patch introduces an alternative algorithm used when requesting higher order allocations. Here we look at memory in ranges at the order requested. We make a quick pass to see if all pages in that area are likely to be reclaimed, only then do we apply reclaim to the pages in the area.
Quoted 3 lines
Testing in combination with fragmentation avoidance shows significantly improved chances of a successful allocation at higher order.
I bet it does.
I'm somewhat surprised at the implementation. Would it not be sufficient to do this within shrink_inactive_list()? Something along the lines of:
- Pick tail page off LRU.
- For all "neighbour" pages (alignment == 1<<order, count == 1<<order)
- If they're all PageLRU and !PageActive, add them all to page_list for possible reclaim
And, in shrink_active_list:
- Pick tail page off LRU
- For all "neighbour" pages (alignment == 1<<order, count == 1<<order)
If they're all PageLRU, put all the active pages in this block onto l_hold for possible deactivation.
Maybe all that can be done in isolate_lru_pages().
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 5/5] linear reclaim core
Quoted 35 lines · Andrew Morton
Quoted 12 lines · On Fri, 8 Sep 2006 13:27:18 +0100 Andy Whitcroft <[email protected]> wrote:
When we are out of memory of a suitable size we enter reclaim. The current reclaim algorithm targets pages in LRU order, which is great for fairness but highly unsuitable if you desire pages at higher orders. To get pages of higher order we must shoot down a very high proportion of memory; >95% in a lot of cases.
This patch introduces an alternative algorithm used when requesting higher order allocations. Here we look at memory in ranges at the order requested. We make a quick pass to see if all pages in that area are likely to be reclaimed, only then do we apply reclaim to the pages in the area.
Quoted 3 lines
Testing in combination with fragmentation avoidance shows significantly improved chances of a successful allocation at higher order.
I bet it does.
I'm somewhat surprised at the implementation. Would it not be sufficient to do this within
shrink_inactive_list()? Something along the lines of:- Pick tail page off LRU.
- For all "neighbour" pages (alignment == 1<<order, count == 1<<order)
- If they're all PageLRU and !PageActive, add them all to
page_listfor possible reclaimAnd, in
shrink_active_list:- Pick tail page off LRU
Quoted 7 lines
- For all "neighbour" pages (alignment == 1<<order, count == 1<<order)
If they're all PageLRU, put all the active pages in this block onto
l_holdfor possible deactivation.Maybe all that can be done in
isolate_lru_pages().
When we started out down this road we though we needed to scan linearly too due to the buddy marking scheme. Now that we're at this end of the road we know thats pretty easy to fix, we're already considering merging the two reclaims anyhow.
Probabally this would do something pretty similar. It feels at a quick glance as it its going to have slightly different semantics, but that may be better or worse.
I'll go try it out and see how it looks.
Thanks for reading.
-apw
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 5/5] linear reclaim core
In reply to Andrew MortonQuoted 11 lines · Andrew Morton
- Pick tail page off LRU.
- For all "neighbour" pages (alignment == 1<<order, count == 1<<order)
- If they're all PageLRU and !PageActive, add them all to
page_listfor possible reclaimAnd, in
shrink_active_list:- Pick tail page off LRU
Quoted 7 lines
- For all "neighbour" pages (alignment == 1<<order, count == 1<<order)
If they're all PageLRU, put all the active pages in this block onto
l_holdfor possible deactivation.Maybe all that can be done in
isolate_lru_pages().
--- fs/buffer.c | 2 - include/linux/swap.h | 2 - mm/page_alloc.c | 2 - mm/vmscan.c | 70 ++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 53 insertions(+), 23 deletions(-)
mm/vmscan.c +50 -20
@@ -62,6 +62,8 @@ struct scan_control {int swap_cluster_max;int swappiness; + +int order; };/*
@@ -590,35 +592,62 @@ keep:* * returns how many pages were moved onto *@dst. */ +int __isolate_lru_page (struct page *page,int active) +{ +int ret = -EINVAL ; + +if (PageLRU (page) && (PageActive (page) == active)) { + ret = -EBUSY ; +if (likely (get_page_unless_zero (page))) { +/* +* Be careful not to clear PageLRU until after we're +* sure the page is not being freed elsewhere -- the +* page release code relies on it. +*/ +ClearPageLRU (page); + ret =0 ; + } + } + +return ret; +} +static unsigned long isolate_lru_pages (unsigned long nr_to_scan,struct list_head *src,struct list_head *dst, -unsigned long *scanned) +unsigned long *scanned,int order) {unsigned long nr_taken =0 ;struct page *page; -unsigned long scan; +unsigned long scan, pfn, base_pfn; +int active; -for (scan =0 ; scan < nr_to_scan && !list_empty (src); scan++) { -struct list_head *target; +for (scan =0 ; scan < nr_to_scan && !list_empty (src);) { page =lru_to_page (src);prefetchw_prev_lru_page (page, src, flags);BUG_ON (!PageLRU (page)); -list_del (&page->lru); - target = src; -if (likely (get_page_unless_zero (page))) { -/* -* Be careful not to clear PageLRU until after we're -* sure the page is not being freed elsewhere -- the -* page release code relies on it. -*/ -ClearPageLRU (page); - target = dst; + active =PageActive (page); + pfn =page_to_pfn (page); + base_pfn = pfn &= ~((1 << order) -1 ); +for (; pfn < (base_pfn + (1 << order)) &&pfn_valid (pfn); pfn++) { +struct page *tmp =pfn_to_page (pfn); +int ret; + +BUG_ON (!tmp); + + ret =__isolate_lru_page (tmp, active); + scan++; +if (ret) { +if (ret == -EBUSY ) { +/* else it is being freed elsewhere */ +list_move (&tmp->lru, src); + } +break ; + }else +list_move (&tmp->lru, dst); nr_taken++; - }/* else it is being freed elsewhere */ - -list_add (&page->lru, target); + } } *scanned = scan;
@@ -649,7 +678,7 @@ static unsigned long shrink_inactive_lis nr_taken =isolate_lru_pages (sc->swap_cluster_max, &zone->inactive_list, - &page_list, &nr_scan); + &page_list, &nr_scan, sc->order); zone->nr_inactive -= nr_taken; zone->pages_scanned += nr_scan;spin_unlock_irq (&zone->lru_lock);
@@ -771,7 +800,7 @@ static void shrink_active_list(unsignedlru_add_drain ();spin_lock_irq (&zone->lru_lock); pgmoved =isolate_lru_pages (nr_pages, &zone->active_list, - &l_hold, &pgscanned); + &l_hold, &pgscanned, sc->order); zone->pages_scanned += pgscanned; zone->nr_active -= pgmoved;spin_unlock_irq (&zone->lru_lock);
@@ -959,7 +988,7 @@ static unsigned long shrink_zones(int pr* holds filesystem locks which prevent writeout this might not work, and the * allocation attempt will fail. */ -unsigned long try_to_free_pages (struct zone **zones,gfp_t gfp_mask) +unsigned long try_to_free_pages (struct zone **zones,int order,gfp_t gfp_mask) {int priority;int ret =0 ;
@@ -974,6 +1003,7 @@ unsigned long try_to_free_pages(struct z .swap_cluster_max = SWAP_CLUSTER_MAX, .may_swap = 1, .swappiness = vm_swappiness, + .order = order, };count_vm_event (ALLOCSTALL );
fs/buffer.c +1 -1
@@ -498,7 +498,7 @@ static void free_more_memory(void)for_each_online_pgdat (pgdat) { zones = pgdat->node_zonelists[gfp_zone (GFP_NOFS )].zones;if (*zones) -try_to_free_pages (zones,GFP_NOFS ); +try_to_free_pages (zones,0 ,GFP_NOFS ); } }
include/linux/swap.h +1 -1
@@ -181,7 +181,7 @@ extern int rotate_reclaimable_page(strucextern void swap_setup (void );/* linux/mm/vmscan.c */ -extern unsigned long try_to_free_pages (struct zone **,gfp_t ); +extern unsigned long try_to_free_pages (struct zone **,int ,gfp_t );extern unsigned long shrink_all_memory (unsigned long nr_pages);extern int vm_swappiness;extern int remove_mapping (struct address_space *mapping,struct page *page);
mm/page_alloc.c +1 -1
@@ -1000,7 +1000,7 @@ rebalance: reclaim_state.reclaimed_slab =0 ; p->reclaim_state = &reclaim_state; - did_some_progress =try_to_free_pages (zonelist->zones, gfp_mask); + did_some_progress =try_to_free_pages (zonelist->zones, order, gfp_mask); p->reclaim_state =NULL ; p->flags &= ~PF_MEMALLOC ;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/1 lumpy reclaim -v2
Hi,
I found a live-lock in my previous version. Unfortunatly this one is a bit longer.
The live lock would occur if we break out of the order loop before moving the tail page ahead, this would lead to retrying the same order block again and again.
This version first handles the tail page, and after that tries to complete the block.
---
When trying to reclaim pages for a higher order allocation, make reclaim try to move lumps of pages (fitting the requested order) about, instead of single pages. This should significantly reduce the number of reclaimed pages for higher order allocations.
--- fs/buffer.c | 2 - include/linux/swap.h | 2 - mm/page_alloc.c | 2 - mm/vmscan.c | 94 ++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 77 insertions(+), 23 deletions(-)
mm/vmscan.c +74 -20
@@ -62,6 +62,8 @@ struct scan_control {int swap_cluster_max;int swappiness; + +int order; };/*
@@ -590,35 +592,86 @@ keep:* * returns how many pages were moved onto *@dst. */ +int __isolate_lru_page (struct page *page,int active) +{ +int ret = -EINVAL ; + +if (PageLRU (page) && (PageActive (page) == active)) { + ret = -EBUSY ; +if (likely (get_page_unless_zero (page))) { +/* +* Be careful not to clear PageLRU until after we're +* sure the page is not being freed elsewhere -- the +* page release code relies on it. +*/ +ClearPageLRU (page); + ret =0 ; + } + } + +return ret; +} +static unsigned long isolate_lru_pages (unsigned long nr_to_scan,struct list_head *src,struct list_head *dst, -unsigned long *scanned) +unsigned long *scanned,int order) {unsigned long nr_taken =0 ; -struct page *page; -unsigned long scan; +struct page *page, *tmp; +unsigned long scan, pfn, end_pfn, page_pfn; +int active;for (scan =0 ; scan < nr_to_scan && !list_empty (src); scan++) { -struct list_head *target; page =lru_to_page (src);prefetchw_prev_lru_page (page, src, flags);BUG_ON (!PageLRU (page)); -list_del (&page->lru); - target = src; -if (likely (get_page_unless_zero (page))) { -/* -* Be careful not to clear PageLRU until after we're -* sure the page is not being freed elsewhere -- the -* page release code relies on it. -*/ -ClearPageLRU (page); - target = dst; - nr_taken++; - }/* else it is being freed elsewhere */ + active =PageActive (page); +switch (__isolate_lru_page (page, active)) { +case 0 : +list_move (&page->lru, dst); + nr_taken++; +break ; + +case -EBUSY : +/* else it is being freed elsewhere */ +list_move (&page->lru, src); +continue ; + +default : +BUG (); + } -list_add (&page->lru, target); +if (!order) +continue ; + + page_pfn = pfn =__page_to_pfn (page); + end_pfn = pfn &= ~((1 << order) -1 ); + end_pfn +=1 << order; +for (; pfn < end_pfn; pfn++) { +if (unlikely (pfn == page_pfn)) +continue ; +if (unlikely (!pfn_valid (pfn))) +break ; + + scan++; + tmp =__pfn_to_page (pfn); +switch (__isolate_lru_page (tmp, active)) { +case 0 : +list_move (&tmp->lru, dst); + nr_taken++; +continue ; + +case -EBUSY : +/* else it is being freed elsewhere */ +list_move (&tmp->lru, src); +default : +break ; + + } +break ; + } } *scanned = scan;
@@ -649,7 +702,7 @@ static unsigned long shrink_inactive_lis nr_taken =isolate_lru_pages (sc->swap_cluster_max, &zone->inactive_list, - &page_list, &nr_scan); + &page_list, &nr_scan, sc->order); zone->nr_inactive -= nr_taken; zone->pages_scanned += nr_scan;spin_unlock_irq (&zone->lru_lock);
@@ -771,7 +824,7 @@ static void shrink_active_list(unsignedlru_add_drain ();spin_lock_irq (&zone->lru_lock); pgmoved =isolate_lru_pages (nr_pages, &zone->active_list, - &l_hold, &pgscanned); + &l_hold, &pgscanned, sc->order); zone->pages_scanned += pgscanned; zone->nr_active -= pgmoved;spin_unlock_irq (&zone->lru_lock);
@@ -959,7 +1012,7 @@ static unsigned long shrink_zones(int pr* holds filesystem locks which prevent writeout this might not work, and the * allocation attempt will fail. */ -unsigned long try_to_free_pages (struct zone **zones,gfp_t gfp_mask) +unsigned long try_to_free_pages (struct zone **zones,int order,gfp_t gfp_mask) {int priority;int ret =0 ;
@@ -974,6 +1027,7 @@ unsigned long try_to_free_pages(struct z .swap_cluster_max = SWAP_CLUSTER_MAX, .may_swap = 1, .swappiness = vm_swappiness, + .order = order, };count_vm_event (ALLOCSTALL );
fs/buffer.c +1 -1
@@ -498,7 +498,7 @@ static void free_more_memory(void)for_each_online_pgdat (pgdat) { zones = pgdat->node_zonelists[gfp_zone (GFP_NOFS )].zones;if (*zones) -try_to_free_pages (zones,GFP_NOFS ); +try_to_free_pages (zones,0 ,GFP_NOFS ); } }
include/linux/swap.h +1 -1
@@ -181,7 +181,7 @@ extern int rotate_reclaimable_page(strucextern void swap_setup (void );/* linux/mm/vmscan.c */ -extern unsigned long try_to_free_pages (struct zone **,gfp_t ); +extern unsigned long try_to_free_pages (struct zone **,int ,gfp_t );extern unsigned long shrink_all_memory (unsigned long nr_pages);extern int vm_swappiness;extern int remove_mapping (struct address_space *mapping,struct page *page);
mm/page_alloc.c +1 -1
@@ -1000,7 +1000,7 @@ rebalance: reclaim_state.reclaimed_slab =0 ; p->reclaim_state = &reclaim_state; - did_some_progress =try_to_free_pages (zonelist->zones, gfp_mask); + did_some_progress =try_to_free_pages (zonelist->zones, order, gfp_mask); p->reclaim_state =NULL ; p->flags &= ~PF_MEMALLOC ;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 5/5] linear reclaim core
In reply to Andrew MortonQuoted 11 lines · Andrew Morton
I'm somewhat surprised at the implementation. Would it not be sufficient to do this within
shrink_inactive_list()? Something along the lines of:- Pick tail page off LRU.
- For all "neighbour" pages (alignment == 1<<order, count == 1<<order)
- If they're all PageLRU and !PageActive, add them all to
page_listfor possible reclaim
Quoted 8 lines
And, in
shrink_active_list:- Pick tail page off LRU
- For all "neighbour" pages (alignment == 1<<order, count == 1<<order)
If they're all PageLRU, put all the active pages in this block onto
l_holdfor possible deactivation.
Hmm. Trying to shoot holes into your approach, I find two potential problems:
A) With sufficient fragmentation, all inactive pages have one active neighbour, so shrink_inactive_list() will never find a cluster of the required order.
B) With some likelihood, shrink_active_list() will pick neighbours which happen to be rather hot pages. They get freed, only to get paged in again within little more than rotational latency.
How about something like:
1. Free 1<<order pages from the inactive list.
2. Pick a page cluster of requested order.
3. Move all pages from the cluster to the just freed pages.
[ Disclaimer: I just started dabbling in mm after Andi Kleen's presentation on Linux Kongress on friday. My tiny gem of knowledge, if present at all, might be well hidden in the ignorance of an mm-newbie. ]
Jorn
Signature · 8 lines
It's not whether you win or lose, it's how you place the blame. -- unknown -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 5/5] linear reclaim core
Quoted 18 lines · On Mon, 11 Sep 2006 01:45:09 +0200 Jorn Engel <[email protected]>…
Quoted 17 lines · Andrew Morton
I'm somewhat surprised at the implementation. Would it not be sufficient to do this within
shrink_inactive_list()? Something along the lines of:- Pick tail page off LRU.
- For all "neighbour" pages (alignment == 1<<order, count == 1<<order)
- If they're all PageLRU and !PageActive, add them all to
page_listfor possible reclaimAnd, in
shrink_active_list:- Pick tail page off LRU
- For all "neighbour" pages (alignment == 1<<order, count == 1<<order)
Quoted 8 lines
Quoted 2 lines
If they're all PageLRU, put all the active pages in this block onto
l_holdfor possible deactivation.Hmm. Trying to shoot holes into your approach, I find two potential problems:
A) With sufficient fragmentation, all inactive pages have one active neighbour, soshrink_inactive_list()will never find a cluster of the required order.
Nope. If the clump of pages has a mix of active and inactive, the above design would cause the active ones to be deactivated, so now the entire clump is eligible for treatment by shrink_inactive_list().
Quoted 3 lines
B) With some likelihood,
shrink_active_list()will pick neighbours which happen to be rather hot pages. They get freed, only to get paged in again within little more than rotational latency.
Maybe. Careful benchmarking and carefully-designed microbenchmarks are, as always, needed.
Bear in mind that simply moving the pages to the inactive list isn't enough to get them reclaimed: we still do various forms of page aging and the pages can still be preserved due to that. IOW, we have several different forms of page aging, one of which is LRU-ordering. The above design compromises just one of those aging steps.
I'd be more concerned about higher-order atomic allocations. If this thing is to work I suspect we'll need per-zone, per-order watermarks and kswapd will need to maintain those.
Quoted 4 lines
How about something like:
1. Free 1<<order pages from the inactive list.
2. Pick a page cluster of requested order.
3. Move all pages from the cluster to the just freed pages.
Don't think in terms of "freeing". Think in terms of "scanning". A lot of page reclaim's balancing tricks are cast in terms of pages-scanned, slabs-scanned, etc.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 5/5] linear reclaim core
Quoted 8 lines · Andrew Morton
Quoted 4 lines
A) With sufficient fragmentation, all inactive pages have one active neighbour, so
shrink_inactive_list()will never find a cluster of the required order.Nope. If the clump of pages has a mix of active and inactive, the above design would cause the active ones to be deactivated, so now the entire clump is eligible for treatment by
shrink_inactive_list().
Ok? More reading seems necessary before I can follow you here...
Quoted 5 lines
Bear in mind that simply moving the pages to the inactive list isn't enough to get them reclaimed: we still do various forms of page aging and the pages can still be preserved due to that. IOW, we have several different forms of page aging, one of which is LRU-ordering. The above design compromises just one of those aging steps.
Are these different forms of page aging described in written form somewhere?
Quoted 3 lines
I'd be more concerned about higher-order atomic allocations. If this thing is to work I suspect we'll need per-zone, per-order watermarks and kswapd will need to maintain those.
Or simply declare higher-order atomic allocations to be undesired? Not sure how many of those we have that make sense.
Quoted 3 lines
Don't think in terms of "freeing". Think in terms of "scanning". A lot of page reclaim's balancing tricks are cast in terms of pages-scanned, slabs-scanned, etc.
There is a related problem I'm sure you are aware of. Trying to shrink the dentry_cache or the various foofs_inode_caches we remove tons of objects before a full slab (in most cases a page) is free and can be returned. ext3_inode_cache has 8 objects per slab, dentry_cache has 29. That's the equivalent of an order-3 or order-5 page allocation in terms of inefficiency.
And having just started thinking about the problem, my envisioned solution looks fairly similar to Andy's work for high-order allocations here. Except that I cannot think in terms of "scanning", afaict.
Jorn
Signature · 8 lines
Anything that can go wrong, will. -- Finagle's Law -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>