VM pageout scalability improvements
Subsystems (20)
cover VM pageout scalability improvements
On large memory systems, the VM can spend way too much time scanning through pages that it cannot (or should not) evict from memory. Not only does it use up CPU time, but it also provokes lock contention and can leave large systems under memory presure in a catatonic state.
Against 2.6.24-rc6-mm1
This patch series improves VM scalability by:
1) making the locking a little more scalable
2) putting filesystem backed, swap backed and non-reclaimable pages onto their own LRUs, so the system only scans the pages that it can/should evict from memory
3) switching to SEQ replacement for the anonymous LRUs, so the number of pages that need to be scanned when the system starts swapping is bound to a reasonable number
More info on the overall design can be found at:
http://linux-mm.org/PageReplacementDesign
Changelog:
- pull the memcontrol lru arrayification earlier into the patch series
- use a pagevec array similar to the lru array
- clean up the code in various places
- improved pageout balancing and reduced pageout cpu use
- fix compilation on PPC and without memcontrol
- make page_is_pagecache more readable
- replace get_scan_ratio with correct version
- merge memcontroller split LRU code into the main split LRU patch, since it is not functionally different (it was split up only to help people who had seen the last version of the patch series review it)
- drop the page_file_cache debugging patch, since it never triggered
- reintroduce code to not scan anon list if swap is full
- add code to scan anon list if page cache is very small already
- use lumpy reclaim more aggressively for smaller order > 1 allocations
Signature · 7 lines
All Rights Reversed -- 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/21 move isolate_lru_page() to vmscan.c
V1 -> V2 [lts]:
+ fix botched merge -- add back "get_page_unless_zero()"
From: Nick Piggin <[email protected]>
To: Linux Memory Management <[email protected]>
Subject: [patch 1/4] mm: move and rework isolate_lru_page
Date: Mon, 12 Mar 2007 07:38:44 +0100 (CET)
isolate_lru_page logically belongs to be in vmscan.c than migrate.c.
It is tough, because we don't need that function without memory migration so there is a valid argument to have it in migrate.c. However a subsequent patch needs to make use of it in the core mm, so we can happily move it to vmscan.c.
Also, make the function a little more generic by not requiring that it adds an isolated page to a given list. Callers can do that.
Note that we now have '__isolate_lru_page()', that does something quite different, visible outside of vmscan.c for use with memory controller. Methinks we need to
rationalize these names/purposes. --lts
include/linux/migrate.h +0 -3
@@ -25,7 +25,6 @@ static inline int vma_migratable(structreturn 1 ; } -extern int isolate_lru_page (struct page *p,struct list_head *pagelist);extern int putback_lru_pages (struct list_head *l);extern int migrate_page (struct address_space *,struct page *,struct page *);
@@ -42,8 +41,6 @@ extern int migrate_vmas(struct mm_structstatic inline int vma_migratable (struct vm_area_struct *vma) {return 0 ; } -static inline int isolate_lru_page (struct page *p,struct list_head *list) - {return -ENOSYS ; }static inline int putback_lru_pages (struct list_head *l) {return 0 ; }static inline int migrate_pages (struct list_head *l,new_page_t x,unsigned long private) {return -ENOSYS ; }
mm/internal.h +2 -0
@@ -34,6 +34,8 @@ static inline void __put_page(struct pagatomic_dec (&page->_count); } +extern int isolate_lru_page (struct page *page); +extern void __init __free_pages_bootmem (struct page *page,unsigned int order);
mm/migrate.c +10 -37
60 lines not on this page · raw message
mm/vmscan.c +41 -0
47 lines not on this page · raw message
mm/mempolicy.c +7 -2
@@ -93,6 +93,8 @@#include <asm/tlbflush.h> #include <asm/uaccess.h> +#include "internal.h" +/* Internal flags */ #define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0)/* Skip checks for continuous vmas */ #define MPOL_MF_INVERT (MPOL_MF_INTERNAL << 1)/* Invert check for nodemask */
@@ -618,8 +620,11 @@ static void migrate_page_add(struct page/* * Avoid migrating a page that is shared with others. */ -if ((flags &MPOL_MF_MOVE_ALL ) ||page_mapcount (page) ==1 ) -isolate_lru_page (page, pagelist); +if ((flags &MPOL_MF_MOVE_ALL ) ||page_mapcount (page) ==1 ) { +if (!isolate_lru_page (page)) { +list_add_tail (&page->lru, pagelist); + } + } }static struct page *new_node_page (struct page *page,unsigned long node,int **x)
Signature · 7 lines
All Rights Reversed -- 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 01/21] move isolate_lru_page() to vmscan.c
Hi Rik
Quoted 12 lines
mm/migrate.c +2
-5@@ -870,14 +840,17 @@ static int do_move_pages(struct mm_struc !migrate_all) goto put_and_set; - err =isolate_lru_page (page, &pagelist); + err =isolate_lru_page (page); +if (err) { put_and_set: -/* -* Either remove the duplicate refcount from -* isolate_lru_page() or drop the page ref if it was -* not isolated.
mm/migrate.c static int do_move_pages(struct mm_struc · line 853
Quoted 10 lines
mm/migrate.c +8
-2-*/ -put_page (page); +/* +* Either remove the duplicate refcount from +* isolate_lru_page() or drop the page ref if it was +* not isolated. +*/ +put_page (page); + }else +list_add_tail (&page->lru, &pagelist);
We think this portion change to following code.
---------------------------------------------
err = isolate_lru_page(page); if (!err) list_add_tail(&page->lru, &pagelist);
put_and_set:
put_page(page); /* drop follow_page() reference */
---------------------------------------------
because nobody hope change page_count.
original do_move_pages:
follow_page: page_count +1
isolate_lru_page: page_count +1
put_page: page_count -1
----------------------------------
total +1
this patch:
follow_page: page_count +1
isolate_lru_page: page_count +1
----------------------------------
total +2
- kosaki
--
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 01/21] move isolate_lru_page() to vmscan.c
Quoted 9 lines · On Fri, 29 Feb 2008 11:29:18 +0900 KOSAKI Motohiro…
We think this portion change to following code.
---------------------------------------------
err = isolate_lru_page(page); if (!err) list_add_tail(&page->lru, &pagelist);
put_and_set:
put_page(page); /* dropfollow_page()reference */
---------------------------------------------
If I understand you right, this is what the incremental patch looks like:
mm/migrate.c +3 -9
@@ -841,16 +841,10 @@ static int do_move_pages(struct mm_struc goto put_and_set; err =isolate_lru_page (page); -if (err) { -put_and_set: -/* -* Either remove the duplicate refcount from -* isolate_lru_page() or drop the page ref if it was -* not isolated. -*/ -put_page (page); - }else +if (!err)list_add_tail (&page->lru, &pagelist); +put_and_set: +put_page (page); set_status: pp->status = err; }
Is this OK for me to commit to my tree?
(folding it into patch 01/21)
Signature · 7 lines
All rights reversed. -- 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 01/21] move isolate_lru_page() to vmscan.c
Quoted 27 lines
If I understand you right, this is what the incremental patch looks like:
Index:
linux-2.6.25-rc2-mm1/mm/migrate.c
===================================================================mm/migrate.c +3
-9@@ -841,16 +841,10 @@ static int do_move_pages(struct mm_struc goto put_and_set; err =isolate_lru_page (page); -if (err) { -put_and_set: -/* -* Either remove the duplicate refcount from -* isolate_lru_page() or drop the page ref if it was -* not isolated. -*/ -put_page (page); - }else +if (!err)list_add_tail (&page->lru, &pagelist); +put_and_set: +put_page (page); set_status: pp->status = err; }
Quoted 2 lines
Is this OK for me to commit to my tree?
(folding it into patch 01/21)
Yes. thanks.
--
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/21 Use an indexed array for LRU variables
In reply to Rik van RielV3 [riel]: memcontrol LRU arrayification
V1 -> V2 [lts]:
+ Remove extraneous __dec_zone_state(zone, NR_ACTIVE) pointed out by Mel G.
Quoted 1 line
From [email protected] Wed Aug 29 11:39:51 2007
Currently we are defining explicit variables for the inactive and active list. An indexed array can be more generic and avoid repeating similar code in several places in the reclaim code.
We are saving a few bytes in terms of code size:
Before:
text data bss dec hex filename
4097753 573120 4092484 8763357 85b7dd vmlinux
After:
text data bss dec hex filename
4097729 573120 4092484 8763333 85b7c5 vmlinux
Having an easy way to add new lru lists may ease future work on the reclaim code.
include/linux/memcontrol.h | 17 +--- include/linux/mm_inline.h | 33 +++++--- include/linux/mmzone.h | 17 ++-- mm/memcontrol.c | 116 ++++++++++------------------ mm/page_alloc.c | 9 +- mm/swap.c | 2 mm/vmscan.c | 141 +++++++++++++++++------------------ mm/vmstat.c | 3 8 files changed, 158 insertions(+), 180 deletions(-)
include/linux/mmzone.h +11 -6
@@ -80,8 +80,8 @@ struct zone_padding {enum zone_stat_item {/* First 128 byte cacheline (assuming 64 bit words) */ NR_FREE_PAGES , -NR_INACTIVE , -NR_ACTIVE , +NR_INACTIVE ,/* must match order of LRU_[IN]ACTIVE */ +NR_ACTIVE ,/* " " " " " */ NR_ANON_PAGES ,/* Mapped anonymous pages */ NR_FILE_MAPPED ,/* pagecache pages mapped into pagetables. only modified from process context */
@@ -105,6 +105,13 @@ enum zone_stat_item {#endif NR_VM_ZONE_STAT_ITEMS }; +enum lru_list { +LRU_INACTIVE ,/* must match order of NR_[IN]ACTIVE */ +LRU_ACTIVE ,/* " " " " " */ +NR_LRU_LISTS }; + +#define for_each_lru (l) for (l = 0; l < NR_LRU_LISTS; l++) +struct per_cpu_pages {int count;/* number of pages in the list */ int high;/* high watermark, emptying needed */
@@ -258,10 +265,8 @@ struct zone {/* Fields commonly accessed by the page reclaim scanner */ spinlock_t lru_lock; -struct list_head active_list; -struct list_head inactive_list; -unsigned long nr_scan_active; -unsigned long nr_scan_inactive; +struct list_head list[NR_LRU_LISTS ]; +unsigned long nr_scan[NR_LRU_LISTS ];unsigned long pages_scanned;/* since last reclaim */ unsigned long flags;/* zone flags, see below */
include/linux/mm_inline.h +22 -11
@@ -1,40 +1,51 @@static inline void +add_page_to_lru_list (struct zone *zone,struct page *page,enum lru_list l) +{ +list_add (&page->lru, &zone->list[l]); +__inc_zone_state (zone,NR_INACTIVE + l); +} + +static inline void +del_page_from_lru_list (struct zone *zone,struct page *page,enum lru_list l) +{ +list_del (&page->lru); +__dec_zone_state (zone,NR_INACTIVE + l); +} + +static inline void add_page_to_active_list (struct zone *zone,struct page *page) { -list_add (&page->lru, &zone->active_list); -__inc_zone_state (zone,NR_ACTIVE ); +add_page_to_lru_list (zone, page,LRU_ACTIVE ); }static inline void add_page_to_inactive_list (struct zone *zone,struct page *page) { -list_add (&page->lru, &zone->inactive_list); -__inc_zone_state (zone,NR_INACTIVE ); +add_page_to_lru_list (zone, page,LRU_INACTIVE ); }static inline void del_page_from_active_list (struct zone *zone,struct page *page) { -list_del (&page->lru); -__dec_zone_state (zone,NR_ACTIVE ); +del_page_from_lru_list (zone, page,LRU_ACTIVE ); }static inline void del_page_from_inactive_list (struct zone *zone,struct page *page) { -list_del (&page->lru); -__dec_zone_state (zone,NR_INACTIVE ); +del_page_from_lru_list (zone, page,LRU_INACTIVE ); }static inline void del_page_from_lru (struct zone *zone,struct page *page) { +enum lru_list l =LRU_INACTIVE ; +list_del (&page->lru);if (PageActive (page)) {__ClearPageActive (page); -__dec_zone_state (zone,NR_ACTIVE ); - }else { -__dec_zone_state (zone,NR_INACTIVE ); + l =LRU_ACTIVE ; } +__dec_zone_state (zone,NR_INACTIVE + l); }
mm/page_alloc.c +5 -4
@@ -3411,6 +3411,7 @@ static void __meminit free_area_init_corfor (j =0 ; j <MAX_NR_ZONES ; j++) {struct zone *zone = pgdat->node_zones + j;unsigned long size, realsize, memmap_pages; +enum lru_list l; size =zone_spanned_pages_in_node (nid, j, zones_size); realsize = size - zone_absent_pages_in_node(nid, j,
@@ -3460,10 +3461,10 @@ static void __meminit free_area_init_cor zone->prev_priority =DEF_PRIORITY ;zone_pcp_init (zone); -INIT_LIST_HEAD (&zone->active_list); -INIT_LIST_HEAD (&zone->inactive_list); - zone->nr_scan_active =0 ; - zone->nr_scan_inactive =0 ; +for_each_lru (l) { +INIT_LIST_HEAD (&zone->list[l]); + zone->nr_scan[l] =0 ; + }zap_zone_vm_stats (zone); zone->flags =0 ;if (!size)
mm/swap.c +1 -1
@@ -118,7 +118,7 @@ static void pagevec_move_tail(struct pagspin_lock (&zone->lru_lock); }if (PageLRU (page) && !PageActive (page)) { -list_move_tail (&page->lru, &zone->inactive_list); +list_move_tail (&page->lru, &zone->list[LRU_INACTIVE ]); pgmoved++; } }
mm/vmscan.c +69 -72
240 lines not on this page · raw message
mm/vmstat.c +2 -1
@@ -758,7 +758,8 @@ static void zoneinfo_show_print(struct s zone->pages_low, zone->pages_high, zone->pages_scanned, - zone->nr_scan_active, zone->nr_scan_inactive, + zone->nr_scan[LRU_ACTIVE ], + zone->nr_scan[LRU_INACTIVE ], zone->spanned_pages, zone->present_pages);
include/linux/memcontrol.h +5 -12
@@ -67,10 +67,8 @@ extern void mem_cgroup_note_reclaim_prioextern void mem_cgroup_record_reclaim_priority (struct mem_cgroup *mem,int priority); -extern long mem_cgroup_calc_reclaim_active (struct mem_cgroup *mem, -struct zone *zone,int priority); -extern long mem_cgroup_calc_reclaim_inactive (struct mem_cgroup *mem, -struct zone *zone,int priority); +extern long mem_cgroup_calc_reclaim (struct mem_cgroup *mem,struct zone *zone, +int priority,enum lru_list lru);#else /* CONFIG_CGROUP_MEM_CONT */ static inline void mm_init_cgroup(struct mm_struct *mm,
@@ -168,14 +166,9 @@ static inline void mem_cgroup_record_rec { } -static inline long mem_cgroup_calc_reclaim_active (struct mem_cgroup *mem, -struct zone *zone,int priority) -{ -return 0 ; -} - -static inline long mem_cgroup_calc_reclaim_inactive (struct mem_cgroup *mem, -struct zone *zone,int priority) +static inline long mem_cgroup_calc_reclaim (struct mem_cgroup *mem, +struct zone *zone,int priority, +enum lru_list lru) {return 0 ; }
mm/memcontrol.c +43 -73
230 lines not on this page · raw message
Signature · 7 lines
All Rights Reversed -- 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 02/21] Use an indexed array for LRU variables
Quoted 46 lines · Rik van Riel
V3 [riel]: memcontrol LRU arrayification
V1 -> V2 [lts]:
+ Remove extraneous__dec_zone_state(zone, NR_ACTIVE)pointed out by Mel G.Quoted 1 line
From [email protected] Wed Aug 29 11:39:51 2007
Currently we are defining explicit variables for the inactive and active list. An indexed array can be more generic and avoid repeating similar code in several places in the reclaim code.
We are saving a few bytes in terms of code size:
Before:
text data bss dec hex filename
4097753 573120 4092484 8763357 85b7dd vmlinuxAfter:
text data bss dec hex filename
4097729 573120 4092484 8763333 85b7c5 vmlinuxHaving an easy way to add new lru lists may ease future work on the reclaim code.
Signed-off-by Rik van Riel <[email protected]>Signed-off-by Lee Schermerhorn <[email protected]>Signed-off-by Christoph Lameter <[email protected]>include/linux/memcontrol.h | 17 +--- include/linux/mm_inline.h | 33 +++++--- include/linux/mmzone.h | 17 ++-- mm/memcontrol.c | 116 ++++++++++------------------ mm/page_alloc.c | 9 +- mm/swap.c | 2 mm/vmscan.c | 141 +++++++++++++++++------------------ mm/vmstat.c | 3 8 files changed, 158 insertions(+), 180 deletions(-)Index:
linux-2.6.25-rc2-mm1/include/linux/mmzone.h
===================================================================
include/linux/mmzone.h struct zone_padding { · line 84
Quoted 7 lines
include/linux/mmzone.h +2
-2@@ -80,8 +80,8 @@ struct zone_padding {enum zone_stat_item {/* First 128 byte cacheline (assuming 64 bit words) */ NR_FREE_PAGES , -NR_INACTIVE , -NR_ACTIVE , +NR_INACTIVE ,/* must match order of LRU_[IN]ACTIVE */ +NR_ACTIVE ,/* " " " " " */
This little ordering constraint is a little nasty. If we have enum_list available at this point then we can make sure that these order correctly automatically with something like this:
#define NR_LRU(lru) NR_ ## lru = NR_LRU_BASE + LRU_ ## lru
enum foo {
NR_FOO,
NR_BAR,
NR_LRU_BASE,
NR_LRU(ACTIVE),
NR_LRU(INACTIVE),
NR_LRU_END = NR_LRU_BASE + NR_LRU_LISTS - 1,
NR_YOU,
NR_ME,
};The NR_LRU_END must be last to ensure that counting continues for those later.
Quoted 35 lines
include/linux/mmzone.h +9
-4NR_ANON_PAGES ,/* Mapped anonymous pages */ NR_FILE_MAPPED, /* pagecache pages mapped into pagetables.only modified from process context */ @@ -105,6 +105,13 @@ enum zone_stat_item {#endif NR_VM_ZONE_STAT_ITEMS }; +enum lru_list { +LRU_INACTIVE ,/* must match order of NR_[IN]ACTIVE */ +LRU_ACTIVE ,/* " " " " " */ +NR_LRU_LISTS }; + +#define for_each_lru (l) for (l = 0; l < NR_LRU_LISTS; l++) +struct per_cpu_pages {int count;/* number of pages in the list */ int high;/* high watermark, emptying needed */ @@ -258,10 +265,8 @@ struct zone {/* Fields commonly accessed by the page reclaim scanner */ spinlock_t lru_lock; -struct list_head active_list; -struct list_head inactive_list; -unsigned long nr_scan_active; -unsigned long nr_scan_inactive; +struct list_head list[NR_LRU_LISTS ]; +unsigned long nr_scan[NR_LRU_LISTS ];unsigned long pages_scanned;/* since last reclaim */ unsigned long flags;/* zone flags, see below */ Index:
linux-2.6.25-rc2-mm1/include/linux/mm_inline.h
===================================================================
include/linux/mm_inline.h line 5
Quoted 5 lines
include/linux/mm_inline.h +4
-0@@ -1,40 +1,51 @@static inline void +add_page_to_lru_list (struct zone *zone,struct page *page,enum lru_list l) +{ +list_add (&page->lru, &zone->list[l]); +__inc_zone_state (zone,NR_INACTIVE + l);
... and by adding a NR_LRU_BASE this implicit assumption that NR_INACTIVE is 0 would be removed as we would do this:
__inc_zone_state(zone, NR_LRU_BASE + l);
include/linux/mm_inline.h line 12
Quoted 7 lines
include/linux/mm_inline.h +7
-0+} + +static inline void +del_page_from_lru_list (struct zone *zone,struct page *page,enum lru_list l) +{ +list_del (&page->lru); +__dec_zone_state (zone,NR_INACTIVE + l);
and here.
Quoted 38 lines
include/linux/mm_inline.h +8
-8+} + +static inline void add_page_to_active_list (struct zone *zone,struct page *page) { - list_add(&page->lru, &zone->active_list); -__inc_zone_state (zone,NR_ACTIVE ); +add_page_to_lru_list (zone, page,LRU_ACTIVE ); }static inline void add_page_to_inactive_list (struct zone *zone,struct page *page) { -list_add (&page->lru, &zone->inactive_list); -__inc_zone_state (zone,NR_INACTIVE ); +add_page_to_lru_list (zone, page,LRU_INACTIVE ); }static inline void del_page_from_active_list (struct zone *zone,struct page *page) { -list_del (&page->lru); -__dec_zone_state (zone,NR_ACTIVE ); +del_page_from_lru_list (zone, page,LRU_ACTIVE ); }static inline void del_page_from_inactive_list (struct zone *zone,struct page *page) { -list_del (&page->lru); -__dec_zone_state (zone,NR_INACTIVE ); +del_page_from_lru_list (zone, page,LRU_INACTIVE ); }static inline void del_page_from_lru (struct zone *zone,struct page *page) { +enum lru_list l =LRU_INACTIVE ;
include/linux/mm_inline.h line 49
Quoted 10 lines
include/linux/mm_inline.h +3
-3+list_del (&page->lru);if (PageActive (page)) {__ClearPageActive (page); -__dec_zone_state (zone,NR_ACTIVE ); - }else { -__dec_zone_state (zone,NR_INACTIVE ); + l =LRU_ACTIVE ; } +__dec_zone_state (zone,NR_INACTIVE + l);
and here.
Quoted 182 lines
include/linux/mm_inline.h +0
-0}Index:
linux-2.6.25-rc2-mm1/mm/page_alloc.c
===================================================================mm/page_alloc.c +5
-4@@ -3411,6 +3411,7 @@ static void __meminit free_area_init_corfor (j =0 ; j <MAX_NR_ZONES ; j++) {struct zone *zone = pgdat->node_zones + j;unsigned long size, realsize, memmap_pages; +enum lru_list l; size =zone_spanned_pages_in_node (nid, j, zones_size); realsize = size - zone_absent_pages_in_node(nid, j,@@ -3460,10 +3461,10 @@ static void __meminit free_area_init_cor zone->prev_priority =DEF_PRIORITY ;zone_pcp_init (zone); -INIT_LIST_HEAD (&zone->active_list); -INIT_LIST_HEAD (&zone->inactive_list); - zone->nr_scan_active =0 ; - zone->nr_scan_inactive =0 ; +for_each_lru (l) { +INIT_LIST_HEAD (&zone->list[l]); + zone->nr_scan[l] =0 ; + }zap_zone_vm_stats (zone); zone->flags =0 ;if (!size)Index:
linux-2.6.25-rc2-mm1/mm/swap.c
===================================================================mm/swap.c +1
-1@@ -118,7 +118,7 @@ static void pagevec_move_tail(struct pagspin_lock (&zone->lru_lock); }if (PageLRU (page) && !PageActive (page)) { -list_move_tail (&page->lru, &zone->inactive_list); +list_move_tail (&page->lru, &zone->list[LRU_INACTIVE ]); pgmoved++; } }Index:
linux-2.6.25-rc2-mm1/mm/vmscan.c
===================================================================mm/vmscan.c +31
-29@@ -804,10 +804,10 @@ static unsigned long isolate_pages_globa int active) {if (active) -return isolate_lru_pages (nr, &z->active_list, dst, +return isolate_lru_pages (nr, &z->list[LRU_ACTIVE ], dst, scanned, order, mode);else -return isolate_lru_pages (nr, &z->inactive_list, dst, +return isolate_lru_pages (nr, &z->list[LRU_INACTIVE ], dst, scanned, order, mode); }@@ -954,10 +954,7 @@ static unsigned long shrink_inactive_lisVM_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); +add_page_to_lru_list (zone, page,PageActive (page));if (!pagevec_add (&pvec, page)) {spin_unlock_irq (&zone->lru_lock);__pagevec_release (&pvec);@@ -1125,11 +1122,14 @@ static void shrink_active_list(unsignedint pgdeactivate =0 ;unsigned long pgscanned;LIST_HEAD (l_hold);/* The pages which were snipped off */ -LIST_HEAD (l_inactive);/* Pages to go onto the inactive_list */ -LIST_HEAD (l_active);/* Pages to go onto the active_list */ +struct list_head list[NR_LRU_LISTS ];struct page *page;struct pagevec pvec;int reclaim_mapped =0 ; +enum lru_list l; + +for_each_lru (l) +INIT_LIST_HEAD (&list[l]);if (sc->may_swap) reclaim_mapped =calc_reclaim_mapped (sc, zone, priority);@@ -1157,28 +1157,28 @@ static void shrink_active_list(unsignedif (!reclaim_mapped || (total_swap_pages ==0 &&PageAnon (page)) ||page_referenced (page,0 , sc->mem_cgroup)) { -list_add (&page->lru, &l_active); +list_add (&page->lru, &list[LRU_ACTIVE ]);continue ; } }else if (TestClearPageReferenced (page)) { -list_add (&page->lru, &l_active); +list_add (&page->lru, &list[LRU_ACTIVE ]);continue ; } -list_add (&page->lru, &l_inactive); +list_add (&page->lru, &list[LRU_INACTIVE ]); }pagevec_init (&pvec,1 ); pgmoved =0 ;spin_lock_irq (&zone->lru_lock); -while (!list_empty (&l_inactive)) { - page =lru_to_page (&l_inactive); -prefetchw_prev_lru_page (page, &l_inactive, flags); +while (!list_empty (&list[LRU_INACTIVE ])) { + page =lru_to_page (&list[LRU_INACTIVE ]); +prefetchw_prev_lru_page (page, &list[LRU_INACTIVE ], flags);VM_BUG_ON (PageLRU (page));SetPageLRU (page);VM_BUG_ON (!PageActive (page));ClearPageActive (page); -list_move (&page->lru, &zone->inactive_list); +list_move (&page->lru, &zone->list[LRU_INACTIVE ]);mem_cgroup_move_lists (page_get_page_cgroup (page), false); pgmoved++;if (!pagevec_add (&pvec, page)) {@@ -1201,13 +1201,13 @@ static void shrink_active_list(unsigned } pgmoved =0 ; -while (!list_empty (&l_active)) { - page =lru_to_page (&l_active); -prefetchw_prev_lru_page (page, &l_active, flags); +while (!list_empty (&list[LRU_ACTIVE ])) { + page =lru_to_page (&list[LRU_ACTIVE ]); +prefetchw_prev_lru_page (page, &list[LRU_ACTIVE ], flags);VM_BUG_ON (PageLRU (page));SetPageLRU (page);VM_BUG_ON (!PageActive (page)); -list_move (&page->lru, &zone->active_list); +list_move (&page->lru, &zone->list[LRU_ACTIVE ]);mem_cgroup_move_lists (page_get_page_cgroup (page), true); pgmoved++;if (!pagevec_add (&pvec, page)) {@@ -1227,65 +1227,64 @@ static void shrink_active_list(unsignedpagevec_release (&pvec); } +static unsigned long shrink_list (enum lru_list l,unsigned long nr_to_scan, +struct zone *zone,struct scan_control *sc,int priority) +{ +if (l ==LRU_ACTIVE ) { +shrink_active_list (nr_to_scan, zone, sc, priority); +return 0 ; + } +return shrink_inactive_list (nr_to_scan, zone, sc); +} +/* * This is a basic per-zone page freer. Used by both kswapd and direct reclaim. */ static unsigned long shrink_zone (int priority,struct zone *zone,struct scan_control *sc) { -unsigned long nr_active; -unsigned long nr_inactive; +unsigned long nr[NR_LRU_LISTS ];unsigned long nr_to_scan;unsigned long nr_reclaimed =0 ; +enum lru_list l;if (scan_global_lru (sc)) {/* * Add one to nr_to_scan just to make sure that the kernel * will slowly sift through the active list. */ - zone->nr_scan_active += - (zone_page_state (zone,NR_ACTIVE ) >> priority) +1 ; - nr_active = zone->nr_scan_active; - zone->nr_scan_inactive += - (zone_page_state (zone,NR_INACTIVE ) >> priority) +1 ; - nr_inactive = zone->nr_scan_inactive; -if (nr_inactive >= sc->swap_cluster_max) - zone->nr_scan_inactive =0 ;
mm/vmscan.c static void shrink_active_list(unsigned · line 1258
Quoted 10 lines
mm/vmscan.c +3
-7-else - nr_inactive =0 ; - -if (nr_active >= sc->swap_cluster_max) - zone->nr_scan_active =0 ; -else - nr_active =0 ; +for_each_lru (l) { + zone->nr_scan[l] += (zone_page_state (zone, +NR_INACTIVE + l) >> priority) +1 ;
and here.
Quoted 201 lines
mm/vmscan.c +35
-36+ nr[l] = zone->nr_scan[l]; +if (nr[l] >= sc->swap_cluster_max) + zone->nr_scan[l] =0 ; +else + nr[l] =0 ; + } }else {/* * This reclaim occurs not because zone memory shortage but * because memory controller hits its limit. * Then, don't modify zone reclaim related data. */ - nr_active =mem_cgroup_calc_reclaim_active (sc->mem_cgroup, - zone, priority); + nr[LRU_ACTIVE ] =mem_cgroup_calc_reclaim (sc->mem_cgroup, + zone, priority,LRU_ACTIVE ); - nr_inactive =mem_cgroup_calc_reclaim_inactive (sc->mem_cgroup, - zone, priority); + nr[LRU_INACTIVE ] =mem_cgroup_calc_reclaim (sc->mem_cgroup, + zone, priority,LRU_INACTIVE ); } - -while (nr_active || nr_inactive) { -if (nr_active) { - nr_to_scan =min (nr_active, +while (nr[LRU_ACTIVE ] || nr[LRU_INACTIVE ]) { +for_each_lru (l) { +if (nr[l]) { + nr_to_scan =min (nr[l], (unsigned long )sc->swap_cluster_max); - nr_active -= nr_to_scan; -shrink_active_list (nr_to_scan, zone, sc, priority); - } + nr[l] -= nr_to_scan; -if (nr_inactive) { - nr_to_scan =min (nr_inactive, - (unsigned long )sc->swap_cluster_max); - nr_inactive -= nr_to_scan; - nr_reclaimed +=shrink_inactive_list (nr_to_scan, zone, - sc); + nr_reclaimed +=shrink_list (l, nr_to_scan, + zone, sc, priority); + } } }@@ -1802,6 +1801,7 @@ static unsigned long shrink_all_zones(un {struct zone *zone;unsigned long nr_to_scan, ret =0 ; +enum lru_list l;for_each_zone (zone) {@@ -1811,28 +1811,25 @@ static unsigned long shrink_all_zones(unif (zone_is_all_unreclaimable (zone) && prio !=DEF_PRIORITY )continue ; -/* For pass = 0 we don't shrink the active list */ -if (pass >0 ) { - zone->nr_scan_active += - (zone_page_state (zone,NR_ACTIVE ) >> prio) +1 ; -if (zone->nr_scan_active >= nr_pages || pass >3 ) { - zone->nr_scan_active =0 ; +for_each_lru (l) { +/* For pass = 0 we don't shrink the active list */ +if (pass ==0 && l ==LRU_ACTIVE ) +continue ; + + zone->nr_scan[l] += + (zone_page_state (zone,NR_INACTIVE + l) + >> prio) +1 ; +if (zone->nr_scan[l] >= nr_pages || pass >3 ) { + zone->nr_scan[l] =0 ; nr_to_scan =min (nr_pages, -zone_page_state (zone,NR_ACTIVE )); -shrink_active_list (nr_to_scan, zone, sc, prio); +zone_page_state (zone, +NR_INACTIVE + l)); + ret +=shrink_list (l, nr_to_scan, zone, + sc, prio); +if (ret >= nr_pages) +return ret; } } - - zone->nr_scan_inactive += - (zone_page_state (zone,NR_INACTIVE ) >> prio) +1 ; -if (zone->nr_scan_inactive >= nr_pages || pass >3 ) { - zone->nr_scan_inactive =0 ; - nr_to_scan =min (nr_pages, -zone_page_state (zone,NR_INACTIVE )); - ret +=shrink_inactive_list (nr_to_scan, zone, sc); -if (ret >= nr_pages) -return ret; - } }return ret;Index:
linux-2.6.25-rc2-mm1/mm/vmstat.c
===================================================================mm/vmstat.c +2
-1@@ -758,7 +758,8 @@ static void zoneinfo_show_print(struct s zone->pages_low, zone->pages_high, zone->pages_scanned, - zone->nr_scan_active, zone->nr_scan_inactive, + zone->nr_scan[LRU_ACTIVE ], + zone->nr_scan[LRU_INACTIVE ], zone->spanned_pages, zone->present_pages);Index:
linux-2.6.25-rc2-mm1/include/linux/memcontrol.h
===================================================================include/linux/memcontrol.h +5
-12@@ -67,10 +67,8 @@ extern void mem_cgroup_note_reclaim_prioextern void mem_cgroup_record_reclaim_priority (struct mem_cgroup *mem,int priority); -extern long mem_cgroup_calc_reclaim_active (struct mem_cgroup *mem, -struct zone *zone,int priority); -extern long mem_cgroup_calc_reclaim_inactive (struct mem_cgroup *mem, -struct zone *zone,int priority); +extern long mem_cgroup_calc_reclaim (struct mem_cgroup *mem,struct zone *zone, +int priority,enum lru_list lru);#else /* CONFIG_CGROUP_MEM_CONT */ static inline void mm_init_cgroup(struct mm_struct *mm,@@ -168,14 +166,9 @@ static inline void mem_cgroup_record_rec { } -static inline long mem_cgroup_calc_reclaim_active (struct mem_cgroup *mem, -struct zone *zone,int priority) -{ -return 0 ; -} - -static inline long mem_cgroup_calc_reclaim_inactive (struct mem_cgroup *mem, -struct zone *zone,int priority) +static inline long mem_cgroup_calc_reclaim (struct mem_cgroup *mem, +struct zone *zone,int priority, +enum lru_list lru) {return 0 ; }Index:
linux-2.6.25-rc2-mm1/mm/memcontrol.c
===================================================================mm/memcontrol.c +4
-12@@ -30,6 +30,7 @@#include <linux/spinlock.h> #include <linux/fs.h> #include <linux/seq_file.h> +#include <linux/mm_inline.h> #include <asm/uaccess.h> @@ -80,22 +81,13 @@ static s64 mem_cgroup_read_stat(struct m/* * per-zone information in memory controller. */ - -enum mem_cgroup_zstat_index { -MEM_CGROUP_ZSTAT_ACTIVE , -MEM_CGROUP_ZSTAT_INACTIVE , - -NR_MEM_CGROUP_ZSTAT , -}; -struct mem_cgroup_per_zone {/* * spin_lock to protect the per cgroup LRU */ spinlock_t lru_lock; -struct list_head active_list; -struct list_head inactive_list; -unsigned long count[NR_MEM_CGROUP_ZSTAT ]; +struct list_head lists[NR_LRU_LISTS ]; +unsigned long count[NR_LRU_LISTS ]; };/* Macro for accessing counter */ #define MEM_CGROUP_ZSTAT (mz, idx) ((mz)->count[(idx)])@@ -220,7 +212,7 @@ page_cgroup_zoneinfo(struct page_cgroup }static unsigned long mem_cgroup_get_all_zonestat (struct mem_cgroup *mem, -enum mem_cgroup_zstat_index idx) +enum lru_list idx) {int nid, zid;struct mem_cgroup_per_zone *mz;@@ -346,13 +338,13 @@ static struct page_cgroup *clear_page_cgstatic void __mem_cgroup_remove_list (struct page_cgroup *pc) {
mm/memcontrol.c static struct page_cgroup *clear_page_cg · line 345
Quoted 10 lines
mm/memcontrol.c +3
-5-int from = pc->flags &PAGE_CGROUP_FLAG_ACTIVE ;struct mem_cgroup_per_zone *mz =page_cgroup_zoneinfo (pc); +int lru =LRU_INACTIVE ; -if (from) -MEM_CGROUP_ZSTAT (mz,MEM_CGROUP_ZSTAT_ACTIVE ) -=1 ; -else -MEM_CGROUP_ZSTAT (mz,MEM_CGROUP_ZSTAT_INACTIVE ) -=1 ; +if (pc->flags &PAGE_CGROUP_FLAG_ACTIVE ) + lru +=LRU_ACTIVE ;
This is making the assumption that LRU_INACTIVE is 0, this should really be:
lru += LRU_ACTIVE - LRU_INACTIVE;
Quoted 6 lines
mm/memcontrol.c +2
-0+ +MEM_CGROUP_ZSTAT (mz, lru) -=1 ;mem_cgroup_charge_statistics (pc->mem_cgroup, pc->flags, false);list_del_init (&pc->lru);
mm/memcontrol.c static void __mem_cgroup_remove_list(str · line 359
Quoted 9 lines
mm/memcontrol.c +4
-1@@ -360,16 +352,15 @@ static void __mem_cgroup_remove_list(strstatic void __mem_cgroup_add_list (struct page_cgroup *pc) { -int to = pc->flags &PAGE_CGROUP_FLAG_ACTIVE ;struct mem_cgroup_per_zone *mz =page_cgroup_zoneinfo (pc); +int lru =LRU_INACTIVE ; + +if (pc->flags &PAGE_CGROUP_FLAG_ACTIVE ) + lru +=LRU_ACTIVE ;
and here.
Quoted 15 lines
mm/memcontrol.c +3
-7+ +MEM_CGROUP_ZSTAT (mz, lru) +=1 ; +list_add (&pc->lru, &mz->lists[lru]); -if (!to) { -MEM_CGROUP_ZSTAT (mz,MEM_CGROUP_ZSTAT_INACTIVE ) +=1 ; -list_add (&pc->lru, &mz->inactive_list); - }else { -MEM_CGROUP_ZSTAT (mz,MEM_CGROUP_ZSTAT_ACTIVE ) +=1 ; -list_add (&pc->lru, &mz->active_list); - }mem_cgroup_charge_statistics (pc->mem_cgroup, pc->flags, true); }
mm/memcontrol.c static void __mem_cgroup_move_lists(stru · line 371
Quoted 4 lines
mm/memcontrol.c +1
-0@@ -377,21 +368,18 @@ static void __mem_cgroup_move_lists(stru {int from = pc->flags &PAGE_CGROUP_FLAG_ACTIVE ;struct mem_cgroup_per_zone *mz =page_cgroup_zoneinfo (pc); +int lru = !!from;
This really is meant to mean:
lru = (from)? LRU_ACTIVE : LRU_INACTIVE
and if those change it will break completely. We should either spell it out explicitly, or put some kind of build failure in place if they are not those values. If we want something without branches perhaps:
int lru_list = { LRU_INACTIVE, LRU_ACTIVE };
int lru = lru_list[!!from];Quoted 71 lines
mm/memcontrol.c +14
-30-if (from) -MEM_CGROUP_ZSTAT (mz,MEM_CGROUP_ZSTAT_ACTIVE ) -=1 ; -else -MEM_CGROUP_ZSTAT (mz,MEM_CGROUP_ZSTAT_INACTIVE ) -=1 ; +MEM_CGROUP_ZSTAT (mz, lru) -=1 ; -if (active) { -MEM_CGROUP_ZSTAT (mz,MEM_CGROUP_ZSTAT_ACTIVE ) +=1 ; +if (active) pc->flags |=PAGE_CGROUP_FLAG_ACTIVE ; -list_move (&pc->lru, &mz->active_list); - }else { -MEM_CGROUP_ZSTAT (mz,MEM_CGROUP_ZSTAT_INACTIVE ) +=1 ; +else pc->flags &= ~PAGE_CGROUP_FLAG_ACTIVE ; -list_move (&pc->lru, &mz->inactive_list); - } + + lru = !!active; +MEM_CGROUP_ZSTAT (mz, lru) +=1 ; +list_move (&pc->lru, &mz->lists[lru]); }int task_in_mem_cgroup (struct task_struct *task,const struct mem_cgroup *mem)@@ -447,8 +435,8 @@ long mem_cgroup_reclaim_imbalance(struct {unsigned long active, inactive;/* active and inactive are the number of pages. 'long' is ok.*/ - active =mem_cgroup_get_all_zonestat (mem,MEM_CGROUP_ZSTAT_ACTIVE ); - inactive =mem_cgroup_get_all_zonestat (mem,MEM_CGROUP_ZSTAT_INACTIVE ); + active =mem_cgroup_get_all_zonestat (mem,LRU_ACTIVE ); + inactive =mem_cgroup_get_all_zonestat (mem,LRU_INACTIVE );return (long ) (active / (inactive +1 )); }@@ -479,29 +467,17 @@ void mem_cgroup_record_reclaim_priority(* (see include/linux/mmzone.h) */ -long mem_cgroup_calc_reclaim_active (struct mem_cgroup *mem, -struct zone *zone,int priority) +long mem_cgroup_calc_reclaim (struct mem_cgroup *mem,struct zone *zone, +int priority,enum lru_list lru) { -long nr_active; +long nr_pages;int nid = zone->zone_pgdat->node_id;int zid =zone_idx (zone);struct mem_cgroup_per_zone *mz =mem_cgroup_zoneinfo (mem, nid, zid); - nr_active =MEM_CGROUP_ZSTAT (mz,MEM_CGROUP_ZSTAT_ACTIVE ); -return (nr_active >> priority); -} - -long mem_cgroup_calc_reclaim_inactive (struct mem_cgroup *mem, -struct zone *zone,int priority) -{ -long nr_inactive; -int nid = zone->zone_pgdat->node_id; -int zid =zone_idx (zone); -struct mem_cgroup_per_zone *mz =mem_cgroup_zoneinfo (mem, nid, zid); + nr_pages =MEM_CGROUP_ZSTAT (mz, lru); - nr_inactive =MEM_CGROUP_ZSTAT (mz,MEM_CGROUP_ZSTAT_INACTIVE ); - -return (nr_inactive >> priority); +return (nr_pages >> priority); } unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
mm/memcontrol.c unsigned long mem_cgroup_isolate_pages(u · line 499
Quoted 4 lines
mm/memcontrol.c +1
-0@@ -520,13 +496,10 @@ unsigned long mem_cgroup_isolate_pages(uint nid = z->zone_pgdat->node_id;int zid =zone_idx (z);struct mem_cgroup_per_zone *mz; +int lru = !!active;
same issue here
Quoted 69 lines
mm/memcontrol.c +9
-16mz =mem_cgroup_zoneinfo (mem_cont, nid, zid); -if (active) - src = &mz->active_list; -else - src = &mz->inactive_list; - + src = &mz->lists[lru];spin_lock (&mz->lru_lock); scan =0 ;@@ -833,7 +806,7 @@ retry:static void mem_cgroup_force_empty_list (struct mem_cgroup *mem,struct mem_cgroup_per_zone *mz, -int active) +enum lru_list lru) {struct page_cgroup *pc;struct page *page;@@ -841,10 +814,7 @@ mem_cgroup_force_empty_list(struct mem_cunsigned long flags;struct list_head *list; -if (active) - list = &mz->active_list; -else - list = &mz->inactive_list; + list = &mz->lists[lru];if (list_empty (list))return ;@@ -894,11 +864,10 @@ int mem_cgroup_force_empty(struct mem_cgfor_each_node_state (node,N_POSSIBLE )for (zid =0 ; zid <MAX_NR_ZONES ; zid++) {struct mem_cgroup_per_zone *mz; +enum lru_list l; mz =mem_cgroup_zoneinfo (mem, node, zid); -/* drop all page_cgroup in active_list */ -mem_cgroup_force_empty_list (mem, mz,1 ); -/* drop all page_cgroup in inactive_list */ -mem_cgroup_force_empty_list (mem, mz,0 ); +for_each_lru (l) +mem_cgroup_force_empty_list (mem, mz, l); } } ret =0 ;@@ -994,9 +963,9 @@ static int mem_control_stat_show(structunsigned long active, inactive; inactive =mem_cgroup_get_all_zonestat (mem_cont, -MEM_CGROUP_ZSTAT_INACTIVE ); +LRU_INACTIVE ); active =mem_cgroup_get_all_zonestat (mem_cont, -MEM_CGROUP_ZSTAT_ACTIVE ); +LRU_ACTIVE );seq_printf (m,"active %ld\n" , (active) *PAGE_SIZE );seq_printf (m,"inactive %ld\n" , (inactive) *PAGE_SIZE ); }@@ -1052,6 +1021,7 @@ static int alloc_mem_cgroup_per_zone_inf {struct mem_cgroup_per_node *pn;struct mem_cgroup_per_zone *mz; +enum lru_list l;int zone;/* * This routine is called against possible nodes. @@ -1073,9 +1043,9 @@ static int alloc_mem_cgroup_per_zone_inf
mm/memcontrol.c static int alloc_mem_cgroup_per_zone_inf · line 1051
Quoted 10 lines
mm/memcontrol.c +2
-2for (zone =0 ; zone <MAX_NR_ZONES ; zone++) { mz = &pn->zoneinfo[zone]; -INIT_LIST_HEAD (&mz->active_list); -INIT_LIST_HEAD (&mz->inactive_list);spin_lock_init (&mz->lru_lock); +for_each_lru (l) +INIT_LIST_HEAD (&mz->lists[l]); }return 0 ; }
-apw
Re: [patch 02/21] Use an indexed array for LRU variables
Quoted 10 lines · On Fri, 29 Feb 2008 16:03:20 +0000 Andy Whitcroft <[email protected]> wrote:
include/linux/mmzone.h struct zone_padding { · line 84
Quoted 6 lines
include/linux/mmzone.h +2
-2/* First 128 byte cacheline (assuming 64 bit words) */ NR_FREE_PAGES , -NR_INACTIVE , - NR_ACTIVE, +NR_INACTIVE ,/* must match order of LRU_[IN]ACTIVE */ + NR_ACTIVE, /* " " " " " */This little ordering constraint is a little nasty. If we have
enum_listavailable at this point then we can make sure that these order correctly automatically with something like this:
A little, true.
However, we need to line up with vmstat_text as well, so I suspect the best way to make this friendlier to people new to this part of the kernel would be to add more documentation, not more magic.
Signature · 7 lines
All Rights Reversed -- 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/21 use an array for the LRU pagevecs
In reply to Rik van RielTurn the pagevecs into an array just like the LRUs. This significantly cleans up the source code and reduces the size of the kernel by about 13kB after all the LRU lists have been created further down in the split VM patch series.
include/linux/mmzone.h | 15 +++++- include/linux/pagevec.h | 13 ++++- include/linux/swap.h | 18 ++++++- mm/migrate.c | 11 ---- mm/swap.c | 87 +++++++++++++++----------------------- 5 files changed, 76 insertions(+), 68 deletions(-)
include/linux/mmzone.h +13 -2
@@ -105,13 +105,24 @@ enum zone_stat_item {#endif NR_VM_ZONE_STAT_ITEMS }; +#define LRU_BASE 0 +enum lru_list { -LRU_INACTIVE ,/* must match order of NR_[IN]ACTIVE */ -LRU_ACTIVE ,/* " " " " " */ +LRU_INACTIVE =LRU_BASE ,/* must match order of NR_[IN]ACTIVE */ +LRU_ACTIVE ,/* " " " " " */ NR_LRU_LISTS };#define for_each_lru (l) for (l = 0; l < NR_LRU_LISTS; l++) +static inline int is_active_lru (enum lru_list l) +{ +if (l ==LRU_ACTIVE ) +return 1 ; +return 0 ; +} + +enum lru_list page_lru (struct page *page); +struct per_cpu_pages {int count;/* number of pages in the list */ int high;/* high watermark, emptying needed */
mm/swap.c +35 -52
140 lines not on this page · raw message
include/linux/pagevec.h +11 -2
@@ -23,8 +23,7 @@ struct pagevec {void __pagevec_release (struct pagevec *pvec);void __pagevec_release_nonlru (struct pagevec *pvec);void __pagevec_free (struct pagevec *pvec); -void __pagevec_lru_add (struct pagevec *pvec); -void __pagevec_lru_add_active (struct pagevec *pvec); +void ____pagevec_lru_add (struct pagevec *pvec,enum lru_list lru);void pagevec_strip (struct pagevec *pvec);unsigned pagevec_lookup (struct pagevec *pvec,struct address_space *mapping,pgoff_t start,unsigned nr_pages);
@@ -81,6 +80,16 @@ static inline void pagevec_free(struct p__pagevec_free (pvec); } +static inline void __pagevec_lru_add (struct pagevec *pvec) +{ +____pagevec_lru_add (pvec,LRU_INACTIVE ); +} + +static inline void __pagevec_lru_add_active (struct pagevec *pvec) +{ +____pagevec_lru_add (pvec,LRU_ACTIVE ); +} +static inline void pagevec_lru_add (struct pagevec *pvec) {if (pagevec_count (pvec))
include/linux/swap.h +16 -2
@@ -171,8 +171,8 @@ extern unsigned int nr_free_pagecache_pa/* linux/mm/swap.c */ -extern void lru_cache_add (struct page *); -extern void lru_cache_add_active (struct page *); +extern void __lru_cache_add (struct page *,enum lru_list lru); +extern void lru_cache_add_lru (struct page *,enum lru_list lru);extern void activate_page (struct page *);extern void mark_page_accessed (struct page *);extern void lru_add_drain (void );
@@ -180,6 +180,20 @@ extern int lru_add_drain_all(void);extern int rotate_reclaimable_page (struct page *page);extern void swap_setup (void ); +/** +* lru_cache_add: add a page to the page lists +* @page: the page to add +*/ +static inline void lru_cache_add (struct page *page) +{ +__lru_cache_add (page,LRU_INACTIVE ); +} + +static inline void lru_cache_add_active (struct page *page) +{ +__lru_cache_add (page,LRU_ACTIVE ); +} +/* linux/mm/vmscan.c */ extern unsigned long try_to_free_pages (struct zone **zones,int order,gfp_t gfp_mask);
mm/migrate.c +1 -10
@@ -54,16 +54,7 @@ int migrate_prep(void)static inline void move_to_lru (struct page *page) { -if (PageActive (page)) { -/* -* lru_cache_add_active checks that -* the PG_active bit is off. -*/ -ClearPageActive (page); -lru_cache_add_active (page); - }else { -lru_cache_add (page); - } +lru_cache_add_lru (page,page_lru (page));put_page (page); }
Signature · 7 lines
All Rights Reversed -- 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 03/21] use an array for the LRU pagevecs
Quoted 21 lines · Rik van Riel
Turn the pagevecs into an array just like the LRUs. This significantly cleans up the source code and reduces the size of the kernel by about 13kB after all the LRU lists have been created further down in the split VM patch series.
Signed-off-by Rik van Riel <[email protected]>Signed-off-by KOSAKI Motohiro <[email protected]>include/linux/mmzone.h | 15 +++++- include/linux/pagevec.h | 13 ++++- include/linux/swap.h | 18 ++++++- mm/migrate.c | 11 ---- mm/swap.c | 87 +++++++++++++++----------------------- 5 files changed, 76 insertions(+), 68 deletions(-)Index:
linux-2.6.25-rc2-mm1/include/linux/mmzone.h
===================================================================include/linux/mmzone.h +0
-0@@ -105,13 +105,24 @@ enum zone_stat_item {#endif
include/linux/mmzone.h enum zone_stat_item { · line 113
Quoted 10 lines
include/linux/mmzone.h +4
-2NR_VM_ZONE_STAT_ITEMS }; +#define LRU_BASE 0 +enum lru_list { -LRU_INACTIVE ,/* must match order of NR_[IN]ACTIVE */ -LRU_ACTIVE ,/* " " " " " */ +LRU_INACTIVE =LRU_BASE ,/* must match order of NR_[IN]ACTIVE */ +LRU_ACTIVE ,/* " " " " " */ NR_LRU_LISTS };
Can this not be:
enum lru_list {
LRU_BASE = 0,
LRU_INACTIVE = LRU_BASE,
LRU_ACTIVE,
NR_LRU_LISTS
};Also, can we not rely on enum's being based at 0 anyhow? We assume often that it will be, as we did here with NR_LRU_LISTS being meaningful should it be. Could it not then be:
enum lru_list {
LRU_BASE,
LRU_INACTIVE = LRU_BASE,
LRU_ACTIVE,
NR_LRU_LISTS
};include/linux/mmzone.h enum zone_stat_item { · line 121
Quoted 7 lines
include/linux/mmzone.h +5
-0#define for_each_lru (l) for (l = 0; l < NR_LRU_LISTS; l++) +static inline int is_active_lru (enum lru_list l) +{ +if (l ==LRU_ACTIVE ) +return 1 ; +return 0 ;
Can this not be:
return (l == LRU_ACTIVE);
Quoted 23 lines
include/linux/mmzone.h +4
-0+} + +enum lru_list page_lru (struct page *page); +struct per_cpu_pages {int count;/* number of pages in the list */ int high;/* high watermark, emptying needed */ Index:
linux-2.6.25-rc2-mm1/mm/swap.c
===================================================================mm/swap.c +1
-2@@ -34,8 +34,7 @@/* How many pages do we try to swap or page in/out together? */ int page_cluster; -static DEFINE_PER_CPU(struct pagevec, lru_add_pvecs) = { 0, }; -static DEFINE_PER_CPU(struct pagevec, lru_add_active_pvecs) = { 0, }; +static DEFINE_PER_CPU(struct pagevec[NR_LRU_LISTS], lru_add_pvecs) = { {0,}, }; static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs) = { 0, };/* @@ -98,6 +97,19 @@ void put_pages_list(struct list_head *paEXPORT_SYMBOL (put_pages_list);
mm/swap.c void put_pages_list(struct list_head *pa · line 107
Quoted 10 lines
mm/swap.c +8
-0/* +* Returns the LRU list a page should be on. +*/ +enum lru_list page_lru (struct page *page) +{ +enum lru_list lru =LRU_BASE ; + +if (PageActive (page)) + lru +=LRU_ACTIVE ;
This is introducing an assumption that LRU_BASE and LRU_INACTIVE are synonymous? Would it not be better to explicitly use LRU_INACTIVE:
So either:
if (PageActive(page)) lru = LRU_ACTIVE; else lru = LRU_INACTIVE;
Or if (as I assume) this is later going to have other mappings added in you could do it more like the following. This should produce identicle asm, but removes any possiblity of LRU_BASE/INACTIVE slippage breaking things:
enum lru_list lru = LRU_INACTIVE; if (PageActive(page)) lru += (LRU_ACTIVE - LRU_INACTIVE);
Quoted 26 lines
mm/swap.c +8
-7+ +return lru; +} + +/* * pagevec_move_tail() must be called with IRQ disabled. * Otherwise this may cause nasty races. */ @@ -200,28 +212,24 @@ void mark_page_accessed(struct page *pagEXPORT_SYMBOL (mark_page_accessed); -/** -* lru_cache_add: add a page to the page lists -* @page: the page to add -*/ -void lru_cache_add (struct page *page) +void __lru_cache_add (struct page *page,enum lru_list lru) { -struct pagevec *pvec = &get_cpu_var (lru_add_pvecs); +struct pagevec *pvec = &get_cpu_var (lru_add_pvecs)[lru];page_cache_get (page);if (!pagevec_add (pvec, page)) -__pagevec_lru_add (pvec); +____pagevec_lru_add (pvec, lru);
mm/swap.c void mark_page_accessed(struct page *pag · line 229
Quoted 10 lines
mm/swap.c +4
-2put_cpu_var (lru_add_pvecs); } -void lru_cache_add_active (struct page *page) +void lru_cache_add_lru (struct page *page,enum lru_list lru) { -struct pagevec *pvec = &get_cpu_var (lru_add_active_pvecs); +if (PageActive (page)) { +ClearPageActive (page); + }
{}'s are not needed here.
Quoted 167 lines
mm/swap.c +14
-41-page_cache_get (page); -if (!pagevec_add (pvec, page)) -__pagevec_lru_add_active (pvec); -put_cpu_var (lru_add_active_pvecs); +VM_BUG_ON (PageLRU (page) ||PageActive (page)); +__lru_cache_add (page, lru); }/* @@ -231,15 +239,15 @@ void lru_cache_add_active(struct page *p*/ static void drain_cpu_pagevecs (int cpu) { +struct pagevec *pvecs =per_cpu (lru_add_pvecs, cpu);struct pagevec *pvec; +int lru; - pvec = &per_cpu (lru_add_pvecs, cpu); -if (pagevec_count (pvec)) -__pagevec_lru_add (pvec); - - pvec = &per_cpu (lru_add_active_pvecs, cpu); -if (pagevec_count (pvec)) -__pagevec_lru_add_active (pvec); +for_each_lru (lru) { + pvec = &pvecs[lru -LRU_BASE ]; +if (pagevec_count (pvec)) +____pagevec_lru_add (pvec, lru); + } pvec = &per_cpu (lru_rotate_pvecs, cpu);if (pagevec_count (pvec)) {@@ -393,7 +401,7 @@ void __pagevec_release_nonlru(struct pag* Add the passed pages to the LRU, then drop the caller's refcount * on them. Reinitialises the caller's pagevec. */ -void __pagevec_lru_add (struct pagevec *pvec) +void ____pagevec_lru_add (struct pagevec *pvec,enum lru_list lru) {int i;struct zone *zone =NULL ;@@ -410,7 +418,9 @@ void __pagevec_lru_add(struct pagevec *p }VM_BUG_ON (PageLRU (page));SetPageLRU (page); -add_page_to_inactive_list (zone, page); +if (is_active_lru (lru)) +SetPageActive (page); +add_page_to_lru_list (zone, page, lru); }if (zone)spin_unlock_irq (&zone->lru_lock);@@ -418,34 +428,7 @@ void __pagevec_lru_add(struct pagevec *ppagevec_reinit (pvec); } -EXPORT_SYMBOL (__pagevec_lru_add); - -void __pagevec_lru_add_active (struct pagevec *pvec) -{ -int i; -struct zone *zone =NULL ; - -for (i =0 ; i <pagevec_count (pvec); i++) { -struct page *page = pvec->pages[i]; -struct zone *pagezone =page_zone (page); - -if (pagezone != zone) { -if (zone) -spin_unlock_irq (&zone->lru_lock); - zone = pagezone; -spin_lock_irq (&zone->lru_lock); - } -VM_BUG_ON (PageLRU (page)); -SetPageLRU (page); -VM_BUG_ON (PageActive (page)); -SetPageActive (page); -add_page_to_active_list (zone, page); - } -if (zone) -spin_unlock_irq (&zone->lru_lock); -release_pages (pvec->pages, pvec->nr, pvec->cold); -pagevec_reinit (pvec); -} +EXPORT_SYMBOL (____pagevec_lru_add);/* * Try to drop buffers from the pages in a pagevec Index:
linux-2.6.25-rc2-mm1/include/linux/pagevec.h
===================================================================include/linux/pagevec.h +11
-2@@ -23,8 +23,7 @@ struct pagevec {void __pagevec_release (struct pagevec *pvec);void __pagevec_release_nonlru (struct pagevec *pvec);void __pagevec_free (struct pagevec *pvec); -void __pagevec_lru_add (struct pagevec *pvec); -void __pagevec_lru_add_active (struct pagevec *pvec); +void ____pagevec_lru_add (struct pagevec *pvec,enum lru_list lru);void pagevec_strip (struct pagevec *pvec);unsigned pagevec_lookup (struct pagevec *pvec,struct address_space *mapping,pgoff_t start,unsigned nr_pages);@@ -81,6 +80,16 @@ static inline void pagevec_free(struct p__pagevec_free (pvec); } +static inline void __pagevec_lru_add (struct pagevec *pvec) +{ +____pagevec_lru_add (pvec,LRU_INACTIVE ); +} + +static inline void __pagevec_lru_add_active (struct pagevec *pvec) +{ +____pagevec_lru_add (pvec,LRU_ACTIVE ); +} +static inline void pagevec_lru_add (struct pagevec *pvec) {if (pagevec_count (pvec))Index:
linux-2.6.25-rc2-mm1/include/linux/swap.h
===================================================================include/linux/swap.h +16
-2@@ -171,8 +171,8 @@ extern unsigned int nr_free_pagecache_pa/* linux/mm/swap.c */ -extern void lru_cache_add (struct page *); -extern void lru_cache_add_active (struct page *); +extern void __lru_cache_add (struct page *,enum lru_list lru); +extern void lru_cache_add_lru (struct page *,enum lru_list lru);extern void activate_page (struct page *);extern void mark_page_accessed (struct page *);extern void lru_add_drain (void );@@ -180,6 +180,20 @@ extern int lru_add_drain_all(void);extern int rotate_reclaimable_page (struct page *page);extern void swap_setup (void ); +/** +* lru_cache_add: add a page to the page lists +* @page: the page to add +*/ +static inline void lru_cache_add (struct page *page) +{ +__lru_cache_add (page,LRU_INACTIVE ); +} + +static inline void lru_cache_add_active (struct page *page) +{ +__lru_cache_add (page,LRU_ACTIVE ); +} +/* linux/mm/vmscan.c */ extern unsigned long try_to_free_pages (struct zone **zones,int order,gfp_t gfp_mask);Index:
linux-2.6.25-rc2-mm1/mm/migrate.c
===================================================================mm/migrate.c +0
-3@@ -54,16 +54,7 @@ int migrate_prep(void)static inline void move_to_lru (struct page *page) { -if (PageActive (page)) { -/* -* lru_cache_add_active checks that
mm/migrate.c int migrate_prep(void) · line 59
Quoted 10 lines
mm/migrate.c +1
-7-* the PG_active bit is off. -*/ -ClearPageActive (page); -lru_cache_add_active (page); - }else { -lru_cache_add (page); - } +lru_cache_add_lru (page,page_lru (page));put_page (page); }
-apw
Re: [patch 03/21] use an array for the LRU pagevecs
Hi Andy
sorry, almost mistake maked by me.
Quoted 11 lines
include/linux/mmzone.h enum zone_stat_item { · line 121
Quoted 7 lines
#define
for_each_lru(l)for (l = 0; l <NR_LRU_LISTS; l++)include/linux/mmzone.h +5
-0+static inline int is_active_lru (enum lru_list l) +{ +if (l ==LRU_ACTIVE ) +return 1 ; +return 0 ;Can this not be:
return (l == LRU_ACTIVE);
yes, your code is more better.
Thanks.
Quoted 15 lines
mm/swap.c void put_pages_list(struct list_head *pa · line 107
Quoted 12 lines
mm/swap.c +8
-0@@ -98,6 +97,19 @@ void put_pages_list(struct list_head *paEXPORT_SYMBOL (put_pages_list);/* +* Returns the LRU list a page should be on. +*/ +enum lru_list page_lru (struct page *page) +{ +enum lru_list lru =LRU_BASE ; + +if (PageActive (page)) + lru +=LRU_ACTIVE ;This is introducing an assumption that
LRU_BASEandLRU_INACTIVEare synonymous? Would it not be better to explicitly useLRU_INACTIVE:
Yes.
this patch series assume LRU_BASE == LRU_INACTIVE.
Quoted 6 lines
So either:
if (PageActive(page)) lru = LRU_ACTIVE; else lru = LRU_INACTIVE;
if add LRU_FILE, this statement makes messy.
key point of indexed arraynize is able to arithmetic calculationed.
Quoted 9 lines
Or if (as I assume) this is later going to have other mappings added in you could do it more like the following. This should produce identicle asm, but removes any possiblity of LRU_BASE/INACTIVE slippage breaking things:
enum lru_list lru = LRU_INACTIVE; if (PageActive(page)) lru += (LRU_ACTIVE - LRU_INACTIVE);
I think your code is more descriptive, but not best simply. I think LRU_BASE == LRU_INACTIVE assumption make simply code.
Quoted 6 lines
mm/swap.c void mark_page_accessed(struct page *pag · line 229
Quoted 4 lines
mm/swap.c +3
-1-struct pagevec *pvec = &get_cpu_var (lru_add_active_pvecs); +if (PageActive (page)) { +ClearPageActive (page); + }{}'s are not needed here.
agghh
thank you good catch ;)
Thank you again for your very careful reviews.
- kosaki
--
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 03/21] use an array for the LRU pagevecs
Hi Rik
this is fixed patch of Andy Whitcroft's point out. (at least, I hope it)
--- include/linux/mmzone.h | 4 +--- mm/swap.c | 15 +++++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-)
include/linux/mmzone.h +1 -3
@@ -116,9 +116,7 @@ enum lru_list {static inline int is_active_lru (enum lru_list l) { -if (l ==LRU_ACTIVE ) -return 1 ; -return 0 ; +return (l ==LRU_ACTIVE ); }enum lru_list page_lru (struct page *page);
mm/swap.c +11 -4
@@ -96,8 +96,9 @@ void put_pages_list(struct list_head *pa }EXPORT_SYMBOL (put_pages_list); -/* +/** * Returns the LRU list a page should be on. +* @page: the page we're checking. */ enum lru_list page_lru (struct page *page) {
@@ -222,11 +223,15 @@ void __lru_cache_add(struct page *page,put_cpu_var (lru_add_pvecs); } +/** +* lru_cache_add_lru: add a page to the page lists +* @page: the page to be added to LRU. +* @lru: the lru to which the page is added. +*/ void lru_cache_add_lru (struct page *page,enum lru_list lru) { -if (PageActive (page)) { +if (PageActive (page))ClearPageActive (page); - }VM_BUG_ON (PageLRU (page) ||PageActive (page));__lru_cache_add (page, lru);
@@ -397,9 +402,11 @@ void __pagevec_release_nonlru(struct pagpagevec_reinit (pvec); } -/* +/** * Add the passed pages to the LRU, then drop the caller's refcount * on them. Reinitialises the caller's pagevec. +* @pvec: the pagevec of pages to be added to LRU. +* @lru: the lru to which pages are added. */ void ____pagevec_lru_add (struct pagevec *pvec,enum lru_list lru) {
--
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>
Rik van Riel
AppliedRe: [patch 03/21] use an array for the LRU pagevecs
Quoted 4 lines · On Tue, 04 Mar 2008 20:04:05 +0900 KOSAKI Motohiro…
Hi Rik
this is fixed patch of Andy Whitcroft's point out. (at least, I hope it)
Applied, except for the documentation to ____pagevec_lru_add, since that function should, IMHO, probably stay internal to the VM and not be exposed in documentation.
Signature · 7 lines
All Rights Reversed -- 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 03/21] use an array for the LRU pagevecs
Quoted 6 lines
Quoted 2 lines
this is fixed patch of Andy Whitcroft's point out. (at least, I hope it)
Applied, except for the documentation to
____pagevec_lru_add, since that function should, IMHO, probably stay internal to the VM and not be exposed in documentation.
That makes sense.
Thanks!
--
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/21 free swap space on swap-in/activation
In reply to Rik van Riel+ lts' convert anon_vma list lock to reader/write lock patch
+ Nick Piggin's move and rework isolate_lru_page() patch
Free swap cache entries when swapping in pages if vm_swap_full() [swap space > 1/2 used?]. Uses new pagevec to reduce pressure on locks.
mm/vmscan.c +7 -0
@@ -632,6 +632,9 @@ free_it:continue ; activate_locked: +/* Not a candidate for swapping, so reclaim swap space. */ +if (PageSwapCache (page) &&vm_swap_full ()) +remove_exclusive_swap_page (page);SetPageActive (page); pgactivate++; keep_locked:
@@ -1214,6 +1217,8 @@ static void shrink_active_list(unsigned__mod_zone_page_state (zone,NR_ACTIVE , pgmoved); pgmoved =0 ;spin_unlock_irq (&zone->lru_lock); +if (vm_swap_full ()) +pagevec_swap_free (&pvec);__pagevec_release (&pvec);spin_lock_irq (&zone->lru_lock); }
@@ -1223,6 +1228,8 @@ static void shrink_active_list(unsigned__count_zone_vm_events (PGREFILL , zone, pgscanned);__count_vm_events (PGDEACTIVATE , pgdeactivate);spin_unlock_irq (&zone->lru_lock); +if (vm_swap_full ()) +pagevec_swap_free (&pvec);pagevec_release (&pvec); }
mm/swap.c +18 -0
@@ -448,6 +448,24 @@ void pagevec_strip(struct pagevec *pvec) } } +/* +* Try to free swap space from the pages in a pagevec +*/ +void pagevec_swap_free (struct pagevec *pvec) +{ +int i; + +for (i =0 ; i <pagevec_count (pvec); i++) { +struct page *page = pvec->pages[i]; + +if (PageSwapCache (page) && !TestSetPageLocked (page)) { +if (PageSwapCache (page)) +remove_exclusive_swap_page (page); +unlock_page (page); + } + } +} +/** * pagevec_lookup - gang pagecache lookup * @pvec: Where the resulting pages are placed
include/linux/pagevec.h +1 -0
@@ -25,6 +25,7 @@ void __pagevec_release_nonlru(struct pagvoid __pagevec_free (struct pagevec *pvec);void ____pagevec_lru_add (struct pagevec *pvec,enum lru_list lru);void pagevec_strip (struct pagevec *pvec); +void pagevec_swap_free (struct pagevec *pvec);unsigned pagevec_lookup (struct pagevec *pvec,struct address_space *mapping,pgoff_t start,unsigned nr_pages); unsigned pagevec_lookup_tag(struct pagevec *pvec,
Signature · 7 lines
All Rights Reversed -- 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 04/21] free swap space on swap-in/activation
Quoted 3 lines · Rik van Riel
plain text document attachment (rvr-00-linux-2.6-swapfree.patch)
+ lts' convertanon_vmalist lock to reader/write lock patch
+ Nick Piggin's move and reworkisolate_lru_page()patch
Hi, Rik:
We no long depend on the anon_vma rwlock patch, right? And, since
they're now all part of the same series, we can probably loose the note about depending on Nick's move/rework patch. These are hold overs from my overly paranoid dependency annotations. We can fix the description on next posting. [Or am I being too pessimistic?]
Lee
Quoted 75 lines
Free swap cache entries when swapping in pages if
vm_swap_full()[swap space > 1/2 used?]. Uses new pagevec to reduce pressure on locks.Signed-off-by Rik van Riel <[email protected]>Signed-off-by Lee Schermerhorn <[email protected]>Index:
linux-2.6.25-rc2-mm1/mm/vmscan.c
===================================================================mm/vmscan.c +7
-0@@ -632,6 +632,9 @@ free_it:continue ; activate_locked: +/* Not a candidate for swapping, so reclaim swap space. */ +if (PageSwapCache (page) &&vm_swap_full ()) +remove_exclusive_swap_page (page);SetPageActive (page); pgactivate++; keep_locked:@@ -1214,6 +1217,8 @@ static void shrink_active_list(unsigned__mod_zone_page_state (zone,NR_ACTIVE , pgmoved); pgmoved =0 ;spin_unlock_irq (&zone->lru_lock); +if (vm_swap_full ()) +pagevec_swap_free (&pvec);__pagevec_release (&pvec);spin_lock_irq (&zone->lru_lock); }@@ -1223,6 +1228,8 @@ static void shrink_active_list(unsigned__count_zone_vm_events (PGREFILL , zone, pgscanned);__count_vm_events (PGDEACTIVATE , pgdeactivate);spin_unlock_irq (&zone->lru_lock); +if (vm_swap_full ()) +pagevec_swap_free (&pvec);pagevec_release (&pvec); }Index:
linux-2.6.25-rc2-mm1/mm/swap.c
===================================================================mm/swap.c +18
-0@@ -448,6 +448,24 @@ void pagevec_strip(struct pagevec *pvec) } } +/* +* Try to free swap space from the pages in a pagevec +*/ +void pagevec_swap_free (struct pagevec *pvec) +{ +int i; + +for (i =0 ; i <pagevec_count (pvec); i++) { +struct page *page = pvec->pages[i]; + +if (PageSwapCache (page) && !TestSetPageLocked (page)) { +if (PageSwapCache (page)) +remove_exclusive_swap_page (page); +unlock_page (page); + } + } +} +/** * pagevec_lookup - gang pagecache lookup * @pvec: Where the resulting pages are placed Index:
linux-2.6.25-rc2-mm1/include/linux/pagevec.h
===================================================================
include/linux/pagevec.h void __pagevec_release_nonlru(struct pag · line 31
Quoted 7 lines
include/linux/pagevec.h +1
-0@@ -25,6 +25,7 @@ void __pagevec_release_nonlru(struct pagvoid __pagevec_free (struct pagevec *pvec);void ____pagevec_lru_add (struct pagevec *pvec,enum lru_list lru);void pagevec_strip (struct pagevec *pvec); +void pagevec_swap_free (struct pagevec *pvec);unsigned pagevec_lookup (struct pagevec *pvec,struct address_space *mapping,pgoff_t start,unsigned nr_pages); unsigned pagevec_lookup_tag(struct pagevec *pvec,
--
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 04/21] free swap space on swap-in/activation
Quoted 5 lines · On Thu, 28 Feb 2008 15:05:53 -0500 Lee Schermerhorn <[email protected]>…
Quoted 3 lines · Rik van Riel
plain text document attachment (rvr-00-linux-2.6-swapfree.patch)
+ lts' convertanon_vmalist lock to reader/write lock patch
+ Nick Piggin's move and reworkisolate_lru_page()patch
Quoted 7 lines
Hi, Rik:
We no long depend on the
anon_vmarwlock patch, right? And, since
they're now all part of the same series, we can probably loose the note about depending on Nick's move/rework patch. These are hold overs from my overly paranoid dependency annotations. We can fix the description on next posting. [Or am I being too pessimistic?]
Fixed the description for the next posting. Thanks.
Signature · 7 lines
All rights reversed. -- 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/21 define page_file_cache() function
In reply to Rik van RielDefine page_file_cache() function to answer the question:
is page backed by a file?
Originally part of Rik van Riel's split-lru patch. Extracted to make available for other, independent reclaim patches.
Moved inline function to linux/mm_inline.h where it will be needed by subsequent "split LRU" and "noreclaim" patches.
Unfortunately this needs to use a page flag, since the PG_swapbacked state needs to be preserved all the way to the point where the page is last removed from the LRU. Trying to derive the status from other info in the page resulted in wrong VM statistics in earlier split VM patchsets.
include/linux/mm_inline.h +22 -0
@@ -1,3 +1,24 @@ +#ifndef LINUX_MM_INLINE_H +#define LINUX_MM_INLINE_H + +/** +* page_file_cache(@page) +* Returns !0 if @page is page cache page backed by a regular filesystem, +* or 0 if @page is anonymous, tmpfs or otherwise ram or swap backed. +* +* We would like to get this info without a page flag, but the state +* needs to survive until the page is last deleted from the LRU, which +* could be as far down as __page_cache_release. +*/ +static inline int page_file_cache (struct page *page) +{ +if (PageSwapBacked (page)) +return 0 ; + +/* The page is page cache backed by a normal filesystem. */ +return 2 ; +} +static inline void add_page_to_lru_list (struct zone *zone,struct page *page,enum lru_list l) {
@@ -49,3 +70,4 @@ del_page_from_lru(struct zone *zone, str __dec_zone_state(zone, NR_INACTIVE + l); } +#endif
mm/shmem.c +1 -0
@@ -1434,6 +1434,7 @@ repeat: goto failed; } +SetPageSwapBacked (filepage);spin_lock (&info->lock); entry =shmem_swp_alloc (info, idx, sgp);if (IS_ERR (entry))
include/linux/page-flags.h +5 -0
@@ -89,6 +89,7 @@#define PG_mappedtodisk 16/* Has blocks allocated on-disk */ #define PG_reclaim 17/* To be reclaimed asap */ #define PG_buddy 19/* Page is free, on buddy lists */ +#define PG_swapbacked 20/* Page is backed by RAM/swap */ /* PG_readahead is only used for file reads; PG_reclaim is only for writes */ #define PG_readahead PG_reclaim/* Reminder to do async read-ahead */
@@ -252,6 +253,10 @@ static inline void SetPageUptodate(struc#define ClearPageReclaim (page) clear_bit(PG_reclaim, &(page)->flags)#define TestClearPageReclaim (page) test_and_clear_bit(PG_reclaim, &(page)->flags) +#define PageSwapBacked (page) test_bit(PG_swapbacked, &(page)->flags) +#define SetPageSwapBacked (page) set_bit(PG_swapbacked, &(page)->flags) +#define __ClearPageSwapBacked (page) __clear_bit(PG_swapbacked, &(page)->flags) +#define PageCompound (page) test_bit(PG_compound, &(page)->flags)#define __SetPageCompound (page) __set_bit(PG_compound, &(page)->flags)#define __ClearPageCompound (page) __clear_bit(PG_compound, &(page)->flags)
mm/memory.c +3 -0
@@ -1677,6 +1677,7 @@ gotten:ptep_clear_flush (vma, address, page_table);set_pte_at (mm, address, page_table, entry);update_mmu_cache (vma, address, entry); +SetPageSwapBacked (new_page);lru_cache_add_active (new_page);page_add_new_anon_rmap (new_page, vma, address);
@@ -2148,6 +2149,7 @@ static int do_anonymous_page(struct mm_sif (!pte_none (*page_table)) goto release;inc_mm_counter (mm, anon_rss); +SetPageSwapBacked (page);lru_cache_add_active (page);page_add_new_anon_rmap (page, vma, address);set_pte_at (mm, address, page_table, entry);
@@ -2291,6 +2293,7 @@ static int __do_fault(struct mm_struct *set_pte_at (mm, address, page_table, entry);if (anon) {inc_mm_counter (mm, anon_rss); +SetPageSwapBacked (page);lru_cache_add_active (page);page_add_new_anon_rmap (page, vma, address); }else {
mm/swap_state.c +1 -0
@@ -82,6 +82,7 @@ int add_to_swap_cache(struct page *page,if (!error) {page_cache_get (page);SetPageSwapCache (page); +SetPageSwapBacked (page);set_page_private (page, entry.val); total_swapcache_pages++;__inc_zone_page_state (page,NR_FILE_PAGES );
mm/migrate.c +2 -0
@@ -537,6 +537,8 @@ static int move_to_new_page(struct page/* Prepare mapping for the new page.*/ newpage->index = page->index; newpage->mapping = page->mapping; +if (PageSwapBacked (page)) +SetPageSwapBacked (newpage); mapping =page_mapping (page);if (!mapping)
mm/page_alloc.c +4 -0
@@ -253,6 +253,7 @@ static void bad_page(struct page *page)1 << PG_slab |1 << PG_swapcache |1 << PG_writeback | +1 << PG_swapbacked | 1 << PG_buddy );set_page_count (page,0 );reset_page_mapcount (page);
@@ -485,6 +486,8 @@ static inline int free_pages_check(strucbad_page (page);if (PageDirty (page))__ClearPageDirty (page); +if (PageSwapBacked (page)) +__ClearPageSwapBacked (page);/* * For now, we report if PG_reserved was found set, but do not * clear it, and do not free the page. But we shall soon need
@@ -631,6 +634,7 @@ static int prep_new_page(struct page *pa 1 << PG_swapcache | 1 << PG_writeback | 1 << PG_reserved | + 1 << PG_swapbacked | 1 << PG_buddy ))))bad_page (page);
Signature · 7 lines
All Rights Reversed -- 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 05/21] define page_file_cache() function
Hi
mm/swap_state.c int add_to_swap_cache(struct page *page, · line 88
Quoted 12 lines
Index:
linux-2.6.25-rc2-mm1/mm/swap_state.c
===================================================================mm/swap_state.c +1
-0@@ -82,6 +82,7 @@ int add_to_swap_cache(struct page *page,if (!error) {page_cache_get (page);SetPageSwapCache (page); +SetPageSwapBacked (page);set_page_private (page, entry.val); total_swapcache_pages++;__inc_zone_page_state (page,NR_FILE_PAGES );
hmm,
What do you think NR_FILE_PAGES counted? SetPageSwapBacked() and increase NR_FILE_PAGES is a bit strange.
but I am worried now.
because if change it, make a incompatibility... ;)
- kosaki
--
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 6/21 split LRU lists into anon & file sets
In reply to Rik van RielSplit the LRU lists in two, one set for pages that are backed by real file systems ("file") and one for pages that are backed by memory and swap ("anon"). The latter includes tmpfs.
Eventually mlocked pages will be taken off the LRUs alltogether. A patch for that already exists and just needs to be integrated into this series.
This patch mostly has the infrastructure and a basic policy to balance how much we scan the anon lists and how much we scan the file lists. The big policy changes are in separate patches.
fs/proc/proc_misc.c +35 -31
@@ -153,43 +153,47 @@ static int meminfo_read_proc(char *page,* Tagged format, for easy grepping and expansion. */ len = sprintf(page, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" - "Buffers: %8lu kB\n" - "Cached: %8lu kB\n" - "SwapCached: %8lu kB\n" - "Active: %8lu kB\n" - "Inactive: %8lu kB\n" + "MemTotal: %8lu kB\n" + "MemFree: %8lu kB\n" + "Buffers: %8lu kB\n" + "Cached: %8lu kB\n" + "SwapCached: %8lu kB\n" + "Active(anon): %8lu kB\n" + "Inactive(anon): %8lu kB\n" + "Active(file): %8lu kB\n" + "Inactive(file): %8lu kB\n" #ifdef CONFIG_HIGHMEM - "HighTotal: %8lu kB\n" - "HighFree: %8lu kB\n" - "LowTotal: %8lu kB\n" - "LowFree: %8lu kB\n" -#endif - "SwapTotal: %8lu kB\n" - "SwapFree: %8lu kB\n" - "Dirty: %8lu kB\n" - "Writeback: %8lu kB\n" - "AnonPages: %8lu kB\n" - "Mapped: %8lu kB\n" - "Slab: %8lu kB\n" - "SReclaimable: %8lu kB\n" - "SUnreclaim: %8lu kB\n" - "PageTables: %8lu kB\n" - "NFS_Unstable: %8lu kB\n" - "Bounce: %8lu kB\n" - "CommitLimit: %8lu kB\n" - "Committed_AS: %8lu kB\n" - "VmallocTotal: %8lu kB\n" - "VmallocUsed: %8lu kB\n" - "VmallocChunk: %8lu kB\n", + "HighTotal: %8lu kB\n" + "HighFree: %8lu kB\n" + "LowTotal: %8lu kB\n" + "LowFree: %8lu kB\n" +#endif + "SwapTotal: %8lu kB\n" + "SwapFree: %8lu kB\n" + "Dirty: %8lu kB\n" + "Writeback: %8lu kB\n" + "AnonPages: %8lu kB\n" + "Mapped: %8lu kB\n" + "Slab: %8lu kB\n" + "SReclaimable: %8lu kB\n" + "SUnreclaim: %8lu kB\n" + "PageTables: %8lu kB\n" + "NFS_Unstable: %8lu kB\n" + "Bounce: %8lu kB\n" + "CommitLimit: %8lu kB\n" + "Committed_AS: %8lu kB\n" + "VmallocTotal: %8lu kB\n" + "VmallocUsed: %8lu kB\n" + "VmallocChunk: %8lu kB\n", K(i.totalram), K(i.freeram), K(i.bufferram), K(cached), K(total_swapcache_pages), - K(global_page_state(NR_ACTIVE)), - K(global_page_state(NR_INACTIVE)), + K(global_page_state(NR_ACTIVE_ANON)), + K(global_page_state(NR_INACTIVE_ANON)), + K(global_page_state(NR_ACTIVE_FILE)), + K(global_page_state(NR_INACTIVE_FILE)), #ifdef CONFIG_HIGHMEM K(i.totalhigh), K(i.freehigh),
fs/cifs/file.c +2 -2
@@ -1778,7 +1778,7 @@ static void cifs_copy_cache_pages(structSetPageUptodate (page);unlock_page (page);if (!pagevec_add (plru_pvec, page)) -__pagevec_lru_add (plru_pvec); +__pagevec_lru_add_file (plru_pvec); data +=PAGE_CACHE_SIZE ; }return ;
@@ -1912,7 +1912,7 @@ static int cifs_readpages(struct file *f bytes_read =0 ; } -pagevec_lru_add (&lru_pvec); +pagevec_lru_add_file (&lru_pvec);/* need to free smb_read_data buf before exit */ if (smb_read_data) {
fs/ntfs/file.c +2 -2
@@ -439,7 +439,7 @@ static inline int __ntfs_grab_cache_page pages[nr] = *cached_page;page_cache_get (*cached_page);if (unlikely (!pagevec_add (lru_pvec, *cached_page))) -__pagevec_lru_add (lru_pvec); +__pagevec_lru_add_file (lru_pvec); *cached_page =NULL ; } index++;
@@ -2084,7 +2084,7 @@ err_out: OSYNC_METADATA|OSYNC_DATA); } } -pagevec_lru_add (&lru_pvec); +pagevec_lru_add_file (&lru_pvec);ntfs_debug ("Done. Returning %s (written 0x%lx, status %li)." , written ?"written" :"status" , (unsigned long )written, (long )status);
fs/nfs/dir.c +1 -1
@@ -1522,7 +1522,7 @@ static int nfs_symlink(struct inode *dirif (!add_to_page_cache (page, dentry->d_inode->i_mapping,0 ,GFP_KERNEL )) {pagevec_add (&lru_pvec, page); -pagevec_lru_add (&lru_pvec); +pagevec_lru_add_file (&lru_pvec);SetPageUptodate (page);unlock_page (page); }else
fs/ramfs/file-nommu.c +2 -2
@@ -111,12 +111,12 @@ static int ramfs_nommu_expand_for_mappin goto add_error;if (!pagevec_add (&lru_pvec, page)) -__pagevec_lru_add (&lru_pvec); +__pagevec_lru_add_file (&lru_pvec);unlock_page (page); } -pagevec_lru_add (&lru_pvec); +pagevec_lru_add_file (&lru_pvec);return 0 ; fsize_exceeded:
drivers/base/node.c +26 -22
59 lines not on this page · raw message
mm/memory.c +3 -3
@@ -1678,7 +1678,7 @@ gotten:set_pte_at (mm, address, page_table, entry);update_mmu_cache (vma, address, entry);SetPageSwapBacked (new_page); -lru_cache_add_active (new_page); +lru_cache_add_active_anon (new_page);page_add_new_anon_rmap (new_page, vma, address);/* Free the old page.. */
@@ -2150,7 +2150,7 @@ static int do_anonymous_page(struct mm_s goto release;inc_mm_counter (mm, anon_rss);SetPageSwapBacked (page); -lru_cache_add_active (page); +lru_cache_add_active_anon (page);page_add_new_anon_rmap (page, vma, address);set_pte_at (mm, address, page_table, entry);
@@ -2294,7 +2294,7 @@ static int __do_fault(struct mm_struct *if (anon) {inc_mm_counter (mm, anon_rss);SetPageSwapBacked (page); -lru_cache_add_active (page); +lru_cache_add_active_anon (page);page_add_new_anon_rmap (page, vma, address); }else {inc_mm_counter (mm, file_rss);
mm/page_alloc.c +17 -7
@@ -1889,10 +1889,13 @@ void show_free_areas(void) } } - printk("Active:%lu inactive:%lu dirty:%lu writeback:%lu unstable:%lu\n" + printk("Active_anon:%lu active_file:%lu inactive_anon%lu\n" + " inactive_file:%lu dirty:%lu writeback:%lu unstable:%lu\n" " free:%lu slab:%lu mapped:%lu pagetables:%lu bounce:%lu\n", - global_page_state(NR_ACTIVE), - global_page_state(NR_INACTIVE), + global_page_state(NR_ACTIVE_ANON), + global_page_state(NR_ACTIVE_FILE), + global_page_state(NR_INACTIVE_ANON), + global_page_state(NR_INACTIVE_FILE), global_page_state(NR_FILE_DIRTY), global_page_state(NR_WRITEBACK), global_page_state(NR_UNSTABLE_NFS),
@@ -1915,8 +1918,10 @@ void show_free_areas(void)" min:%lukB" " low:%lukB" " high:%lukB" -" active:%lukB" -" inactive:%lukB" +" active_anon:%lukB" +" inactive_anon:%lukB" +" active_file:%lukB" +" inactive_file:%lukB" " present:%lukB" " pages_scanned:%lu" " all_unreclaimable? %s"
@@ -1926,8 +1931,10 @@ void show_free_areas(void)K (zone->pages_min),K (zone->pages_low),K (zone->pages_high), -K (zone_page_state (zone,NR_ACTIVE )), -K (zone_page_state (zone,NR_INACTIVE )), +K (zone_page_state (zone,NR_ACTIVE_ANON )), +K (zone_page_state (zone,NR_INACTIVE_ANON )), +K (zone_page_state (zone,NR_ACTIVE_FILE )), +K (zone_page_state (zone,NR_INACTIVE_FILE )),K (zone->present_pages), zone->pages_scanned, (zone_is_all_unreclaimable (zone) ?"yes" :"no" )
@@ -3469,6 +3476,9 @@ static void __meminit free_area_init_corINIT_LIST_HEAD (&zone->list[l]); zone->nr_scan[l] =0 ; } + zone->recent_rotated_anon =0 ; + zone->recent_rotated_file =0 ; +//TODO recent_scanned_* ??? zap_zone_vm_stats (zone); zone->flags =0 ;if (!size)
mm/swap.c +14 -3
@@ -105,6 +105,7 @@ enum lru_list page_lru(struct page *pageif (PageActive (page)) lru +=LRU_ACTIVE ; + lru +=page_file_cache (page);return lru; }
@@ -130,7 +131,13 @@ static void pagevec_move_tail(struct pagspin_lock (&zone->lru_lock); }if (PageLRU (page) && !PageActive (page)) { -list_move_tail (&page->lru, &zone->list[LRU_INACTIVE ]); +if (page_file_cache (page)) { +list_move_tail (&page->lru, + &zone->list[LRU_INACTIVE_FILE ]); + }else { +list_move_tail (&page->lru, + &zone->list[LRU_INACTIVE_ANON ]); + } pgmoved++; } }
@@ -184,9 +191,13 @@ void activate_page(struct page *page)spin_lock_irq (&zone->lru_lock);if (PageLRU (page) && !PageActive (page)) { -del_page_from_inactive_list (zone, page); +int lru =LRU_BASE ; + lru +=page_file_cache (page); +del_page_from_lru_list (zone, page, lru); +SetPageActive (page); -add_page_to_active_list (zone, page); + lru +=LRU_ACTIVE ; +add_page_to_lru_list (zone, page, lru);__count_vm_event (PGACTIVATE );mem_cgroup_move_lists (page_get_page_cgroup (page), true); }
mm/readahead.c +1 -1
@@ -229,7 +229,7 @@ int do_page_cache_readahead(struct addre*/ unsigned long max_sane_readahead (unsigned long nr) { -return min (nr, (node_page_state (numa_node_id (),NR_INACTIVE ) +return min (nr, (node_page_state (numa_node_id (),NR_INACTIVE_FILE ) +node_page_state (numa_node_id (),NR_FREE_PAGES )) /2 ); }
mm/filemap.c +7 -2
@@ -34,6 +34,7 @@#include <linux/cpuset.h> #include <linux/hardirq.h> /* for BUG_ON(!in_atomic()) only */ #include <linux/memcontrol.h> +#include <linux/mm_inline.h> /* for page_file_cache() */ #include "internal.h" /*
@@ -493,8 +494,12 @@ int add_to_page_cache_lru(struct page *p pgoff_t offset, gfp_t gfp_mask) { int ret = add_to_page_cache(page, mapping, offset, gfp_mask); -if (ret ==0 ) -lru_cache_add (page); +if (ret ==0 ) { +if (page_file_cache (page)) +lru_cache_add_file (page); +else +lru_cache_add_active_anon (page); + }return ret; }
mm/vmstat.c +9 -5
@@ -686,8 +686,10 @@ const struct seq_operations pagetypeinfostatic const char *const vmstat_text[] = {/* Zoned VM counters */ "nr_free_pages" , -"nr_inactive" , -"nr_active" , +"nr_inactive_anon" , +"nr_active_anon" , +"nr_inactive_file" , +"nr_active_file" ,"nr_anon_pages" ,"nr_mapped" ,"nr_file_pages" ,
@@ -750,7 +752,7 @@ static void zoneinfo_show_print(struct s"\n min %lu" "\n low %lu" "\n high %lu" -"\n scanned %lu (a: %lu i: %lu)" +"\n scanned %lu (aa: %lu ia: %lu af: %lu if: %lu)" "\n spanned %lu" "\n present %lu" , zone_page_state(zone, NR_FREE_PAGES),
@@ -758,8 +760,10 @@ static void zoneinfo_show_print(struct s zone->pages_low, zone->pages_high, zone->pages_scanned, - zone->nr_scan[LRU_ACTIVE ], - zone->nr_scan[LRU_INACTIVE ], + zone->nr_scan[LRU_ACTIVE_ANON ], + zone->nr_scan[LRU_INACTIVE_ANON ], + zone->nr_scan[LRU_ACTIVE_FILE ], + zone->nr_scan[LRU_INACTIVE_FILE ], zone->spanned_pages, zone->present_pages);
mm/vmscan.c +217 -242
772 lines not on this page · raw message
mm/swap_state.c +1 -1
@@ -300,7 +300,7 @@ struct page *read_swap_cache_async(swp_e/* * Initiate read into locked page and return. */ -lru_cache_add_active (new_page); +lru_cache_add_active_anon (new_page);swap_readpage (NULL , new_page);return new_page; }
include/linux/mmzone.h +29 -6
@@ -80,21 +80,23 @@ struct zone_padding {enum zone_stat_item {/* First 128 byte cacheline (assuming 64 bit words) */ NR_FREE_PAGES , -NR_INACTIVE ,/* must match order of LRU_[IN]ACTIVE */ -NR_ACTIVE ,/* " " " " " */ +NR_INACTIVE_ANON ,/* must match order of LRU_[IN]ACTIVE_* */ +NR_ACTIVE_ANON ,/* " " " " " */ +NR_INACTIVE_FILE ,/* " " " " " */ +NR_ACTIVE_FILE ,/* " " " " " */ NR_ANON_PAGES ,/* Mapped anonymous pages */ NR_FILE_MAPPED ,/* pagecache pages mapped into pagetables. only modified from process context */ NR_FILE_PAGES ,NR_FILE_DIRTY ,NR_WRITEBACK , -/* Second 128 byte cacheline */ NR_SLAB_RECLAIMABLE ,NR_SLAB_UNRECLAIMABLE ,NR_PAGETABLE ,/* used for pagetables */ NR_UNSTABLE_NFS ,/* NFS unstable pages */ NR_BOUNCE ,NR_VMSCAN_WRITE , +/* Second 128 byte cacheline */ #ifdef CONFIG_NUMA NUMA_HIT ,/* allocated in intended node */ NUMA_MISS ,/* allocated in non intended node */
@@ -105,18 +107,35 @@ enum zone_stat_item {#endif NR_VM_ZONE_STAT_ITEMS }; +/* +* We do arithmetic on the LRU lists in various places in the code, +* so it is important to keep the active lists LRU_ACTIVE higher in +* the array than the corresponding inactive lists, and to keep +* the *_FILE lists LRU_FILE higher than the corresponding _ANON lists. +*/ #define LRU_BASE 0 +#define LRU_ACTIVE 1 +#define LRU_FILE 2enum lru_list { -LRU_INACTIVE =LRU_BASE ,/* must match order of NR_[IN]ACTIVE */ -LRU_ACTIVE ,/* " " " " " */ +LRU_INACTIVE_ANON =LRU_BASE , +LRU_ACTIVE_ANON =LRU_BASE +LRU_ACTIVE , +LRU_INACTIVE_FILE =LRU_BASE +LRU_FILE , +LRU_ACTIVE_FILE =LRU_BASE +LRU_FILE +LRU_ACTIVE ,NR_LRU_LISTS };#define for_each_lru (l) for (l = 0; l < NR_LRU_LISTS; l++) +static inline int is_file_lru (enum lru_list l) +{ +if (l ==LRU_INACTIVE_FILE || l ==LRU_ACTIVE_FILE ) +return 1 ; +return 0 ; +} +static inline int is_active_lru (enum lru_list l) { -if (l ==LRU_ACTIVE ) +if (l ==LRU_ACTIVE_ANON || l ==LRU_ACTIVE_FILE )return 1 ;return 0 ; }
@@ -278,6 +297,10 @@ struct zone {spinlock_t lru_lock;struct list_head list[NR_LRU_LISTS ];unsigned long nr_scan[NR_LRU_LISTS ]; + +unsigned long recent_rotated_anon; +unsigned long recent_rotated_file; +unsigned long pages_scanned;/* since last reclaim */ unsigned long flags;/* zone flags, see below */
include/linux/mm_inline.h +39 -14
97 lines not on this page · raw message
include/linux/pagevec.h +23 -6
@@ -81,20 +81,37 @@ static inline void pagevec_free(struct p__pagevec_free (pvec); } -static inline void __pagevec_lru_add (struct pagevec *pvec) +static inline void __pagevec_lru_add_anon (struct pagevec *pvec) { -____pagevec_lru_add (pvec,LRU_INACTIVE ); +____pagevec_lru_add (pvec,LRU_INACTIVE_ANON ); } -static inline void __pagevec_lru_add_active (struct pagevec *pvec) +static inline void __pagevec_lru_add_active_anon (struct pagevec *pvec) { -____pagevec_lru_add (pvec,LRU_ACTIVE ); +____pagevec_lru_add (pvec,LRU_ACTIVE_ANON ); } -static inline void pagevec_lru_add (struct pagevec *pvec) +static inline void __pagevec_lru_add_file (struct pagevec *pvec) +{ +____pagevec_lru_add (pvec,LRU_INACTIVE_FILE ); +} + +static inline void __pagevec_lru_add_active_file (struct pagevec *pvec) +{ +____pagevec_lru_add (pvec,LRU_ACTIVE_FILE ); +} + + +static inline void pagevec_lru_add_file (struct pagevec *pvec) +{ +if (pagevec_count (pvec)) +__pagevec_lru_add_file (pvec); +} + +static inline void pagevec_lru_add_anon (struct pagevec *pvec) {if (pagevec_count (pvec)) -__pagevec_lru_add (pvec); +__pagevec_lru_add_anon (pvec); }#endif /* _LINUX_PAGEVEC_H */
include/linux/vmstat.h +10 -0
@@ -149,6 +149,16 @@ static inline unsigned long zone_page_streturn x; } +extern unsigned long global_lru_pages (void ); + +static inline unsigned long zone_lru_pages (struct zone *zone) +{ +return (zone_page_state (zone,NR_ACTIVE_ANON ) + +zone_page_state (zone,NR_ACTIVE_FILE ) + +zone_page_state (zone,NR_INACTIVE_ANON ) + +zone_page_state (zone,NR_INACTIVE_FILE )); +} +#ifdef CONFIG_NUMA /* * Determine the per node value of a stat item. This function
mm/page-writeback.c +2 -6
@@ -320,9 +320,7 @@ static unsigned long highmem_dirtyable_mstruct zone *z = &NODE_DATA (node)->node_zones[ZONE_HIGHMEM ]; - x +=zone_page_state (z,NR_FREE_PAGES ) - +zone_page_state (z,NR_INACTIVE ) - +zone_page_state (z,NR_ACTIVE ); + x +=zone_page_state (z,NR_FREE_PAGES ) +zone_lru_pages (z); }/* * Make sure that the number of highmem pages is never larger
@@ -340,9 +338,7 @@ static unsigned long determine_dirtyable {unsigned long x; - x =global_page_state (NR_FREE_PAGES ) - +global_page_state (NR_INACTIVE ) - +global_page_state (NR_ACTIVE ); + x =global_page_state (NR_FREE_PAGES ) +global_lru_pages ();if (!vm_highmem_is_dirtyable) x -=highmem_dirtyable_memory (x);
include/linux/swap.h +15 -5
@@ -184,14 +184,24 @@ extern void swap_setup(void);* lru_cache_add: add a page to the page lists * @page: the page to add */ -static inline void lru_cache_add (struct page *page) +static inline void lru_cache_add_anon (struct page *page) { -__lru_cache_add (page,LRU_INACTIVE ); +__lru_cache_add (page,LRU_INACTIVE_ANON ); } -static inline void lru_cache_add_active (struct page *page) +static inline void lru_cache_add_active_anon (struct page *page) { -__lru_cache_add (page,LRU_ACTIVE ); +__lru_cache_add (page,LRU_ACTIVE_ANON ); +} + +static inline void lru_cache_add_file (struct page *page) +{ +__lru_cache_add (page,LRU_INACTIVE_FILE ); +} + +static inline void lru_cache_add_active_file (struct page *page) +{ +__lru_cache_add (page,LRU_ACTIVE_FILE ); }/* linux/mm/vmscan.c */
@@ -199,7 +209,7 @@ extern unsigned long try_to_free_pages(s gfp_t gfp_mask);extern unsigned long try_to_free_mem_cgroup_pages (struct mem_cgroup *mem,gfp_t gfp_mask); -extern int __isolate_lru_page (struct page *page,int mode); +extern int __isolate_lru_page (struct page *page,int mode,int file);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);
include/linux/memcontrol.h +1 -1
@@ -42,7 +42,7 @@ extern unsigned long mem_cgroup_isolate_ unsigned long *scanned, int order, int mode, struct zone *z, struct mem_cgroup *mem_cont, - int active); + int active, int file);extern void mem_cgroup_out_of_memory (struct mem_cgroup *mem,gfp_t gfp_mask);extern int mem_cgroup_cache_charge (struct page *page,struct mm_struct *mm,gfp_t gfp_mask);
mm/memcontrol.c +32 -28
140 lines not on this page · raw message
Signature · 7 lines
All Rights Reversed -- 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 06/21] split LRU lists into anon & file sets
Hi
Quoted 1 line
(quoted diff) +0
-0@@ -1128,64 +1026,65 @@ static void shrink_active_list(unsigned
(snip)
Review
Quoted 5 lines
(quoted diff) +5
-0+ /* + * For sorting active vs inactive pages, we'll use the 'anon' + * elements of the local list[] array and sort out the file vs + * anon pages below. + */
IMHO this comment implies code is not so good...
I think shrink_active_list should not change to indexed array. because this function almost use no indexed array operation.
the following is only explain my intention patch.
--- mm/vmscan.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-)
mm/vmscan.c +11 -18
@@ -1023,14 +1023,12 @@ static void shrink_active_list(unsignedint pgdeactivate =0 ;unsigned long pgscanned;LIST_HEAD (l_hold);/* The pages which were snipped off */ -struct list_head list[NR_LRU_LISTS ]; +LIST_HEAD (l_active); +LIST_HEAD (l_inactive);struct page *page;struct pagevec pvec;enum lru_list lru; -for_each_lru (lru) -INIT_LIST_HEAD (&list[lru]); -lru_add_drain ();spin_lock_irq (&zone->lru_lock); pgmoved = sc->isolate_pages(nr_pages, &l_hold, &pgscanned, sc->order,
@@ -1048,19 +1046,14 @@ static void shrink_active_list(unsigned__mod_zone_page_state (zone,NR_ACTIVE_ANON , -pgmoved);spin_unlock_irq (&zone->lru_lock); -/* -* For sorting active vs inactive pages, we'll use the 'anon' -* elements of the local list[] array and sort out the file vs -* anon pages below. -*/ while (!list_empty (&l_hold)) { - lru =LRU_INACTIVE_ANON ;cond_resched (); page =lru_to_page (&l_hold);list_del (&page->lru);if (page_referenced (page,0 , sc->mem_cgroup)) - lru =LRU_ACTIVE_ANON ; -list_add (&page->lru, &list[lru]); +list_add (&page->lru, &l_active); +else +list_add (&page->lru, &l_inactive); }/*
@@ -1071,9 +1064,9 @@ static void shrink_active_list(unsigned pgmoved =0 ; lru =LRU_BASE + file *LRU_FILE ;spin_lock_irq (&zone->lru_lock); -while (!list_empty (&list[LRU_INACTIVE_ANON ])) { - page =lru_to_page (&list[LRU_INACTIVE_ANON ]); -prefetchw_prev_lru_page (page, &list[LRU_INACTIVE_ANON ], flags); +while (!list_empty (&l_inactive)) { + page =lru_to_page (&l_inactive); +prefetchw_prev_lru_page (page, &l_inactive, flags);VM_BUG_ON (PageLRU (page));SetPageLRU (page);VM_BUG_ON (!PageActive (page));
@@ -1104,9 +1097,9 @@ static void shrink_active_list(unsigned pgmoved =0 ; lru =LRU_ACTIVE + file *LRU_FILE ; -while (!list_empty (&list[LRU_ACTIVE_ANON ])) { - page =lru_to_page (&list[LRU_ACTIVE_ANON ]); -prefetchw_prev_lru_page (page, &list[LRU_ACTIVE_ANON ], flags); +while (!list_empty (&l_active)) { + page =lru_to_page (&l_active); +prefetchw_prev_lru_page (page, &l_active, flags);VM_BUG_ON (PageLRU (page));SetPageLRU (page);VM_BUG_ON (!PageActive (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>
Re: [patch 06/21] split LRU lists into anon & file sets
In reply to Rik van RielHi
Quoted 10 lines
(quoted diff) +0
-6@@ -153,43 +153,47 @@ static int meminfo_read_proc(char *page, * Tagged format, for easy grepping and expansion. */ len = sprintf(page, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" - "Buffers: %8lu kB\n" - "Cached: %8lu kB\n" - "SwapCached: %8lu kB\n" - "Active: %8lu kB\n"
Review static int meminfo_read_proc(char *page, · line 164
Quoted 10 lines
(quoted diff) +9
-1- "Inactive: %8lu kB\n" + "MemTotal: %8lu kB\n" + "MemFree: %8lu kB\n" + "Buffers: %8lu kB\n" + "Cached: %8lu kB\n" + "SwapCached: %8lu kB\n" + "Active(anon): %8lu kB\n" + "Inactive(anon): %8lu kB\n" + "Active(file): %8lu kB\n" + "Inactive(file): %8lu kB\n"
Unfortunately this change corrupt "vmstat -a".
could we add field instead replace it?
-kosaki
--- fs/proc/proc_misc.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
fs/proc/proc_misc.c 2008-03-01 21:39:04.000000000 +0900 renamed from fs/proc/proc_misc.c 2008-03-01 21:32:13.000000000 +0900 +17 -4
@@ -131,6 +131,10 @@ static int meminfo_read_proc(char *page, unsigned long allowed; struct vmalloc_info vmi; long cached; + unsigned long active_anon; + unsigned long inactive_anon; + unsigned long active_file; + unsigned long inactive_file; /* * display in kilobytes.
@@ -149,6 +153,11 @@ static int meminfo_read_proc(char *page, get_vmalloc_info(&vmi); + active_anon = global_page_state(NR_ACTIVE_ANON); + inactive_anon = global_page_state(NR_INACTIVE_ANON); + active_file = global_page_state(NR_ACTIVE_FILE); + inactive_file = global_page_state(NR_INACTIVE_FILE); + /* * Tagged format, for easy grepping and expansion. */
@@ -158,6 +167,8 @@ static int meminfo_read_proc(char *page, "Buffers: %8lu kB\n" "Cached: %8lu kB\n" "SwapCached: %8lu kB\n" + "Active: %8lu kB\n" + "Inactive: %8lu kB\n" "Active(anon): %8lu kB\n" "Inactive(anon): %8lu kB\n" "Active(file): %8lu kB\n"
@@ -190,10 +201,12 @@ static int meminfo_read_proc(char *page, K(i.bufferram), K(cached), K(total_swapcache_pages), - K(global_page_state(NR_ACTIVE_ANON)), - K(global_page_state(NR_INACTIVE_ANON)), - K(global_page_state(NR_ACTIVE_FILE)), - K(global_page_state(NR_INACTIVE_FILE)), + K(active_anon + active_file), + K(inactive_anon + inactive_file), + K(active_anon), + K(inactive_anon), + K(active_file), + K(inactive_file), #ifdef CONFIG_HIGHMEM K(i.totalhigh), K(i.freehigh),
--
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 7/21 SEQ replacement for anonymous pages
In reply to Rik van RielWe avoid evicting and scanning anonymous pages for the most part, but under some workloads we can end up with most of memory filled with anonymous pages. At that point, we suddenly need to clear the referenced bits on all of memory, which can take ages on very large memory systems.
We can reduce the maximum number of pages that need to be scanned by not taking the referenced state into account when deactivating an anonymous page. After all, every anonymous page starts out referenced, so why check?
If an anonymous page gets referenced again before it reaches the end of the inactive list, we move it back to the active list.
To keep the maximum amount of necessary work reasonable, we scale the active to inactive ratio with the size of memory, using the formula active:inactive ratio = sqrt(memory in GB * 10).
Kswapd CPU use now seems to scale by the amount of pageout bandwidth, instead of by the amount of memory present in the system.
include/linux/mm_inline.h +12 -0
@@ -95,4 +95,16 @@ del_page_from_lru(struct zone *zone, str __dec_zone_state(zone, NR_INACTIVE_ANON + l); } +static inline int inactive_anon_low (struct zone *zone) +{ +unsigned long active, inactive; + + active =zone_page_state (zone,NR_ACTIVE_ANON ); + inactive =zone_page_state (zone,NR_INACTIVE_ANON ); + +if (inactive * zone->inactive_ratio < active) +return 1 ; + +return 0 ; +}#endif
include/linux/mmzone.h +5 -0
@@ -322,6 +322,11 @@ struct zone {*/ int prev_priority; +/* +* The ratio of active to inactive pages. +*/ +unsigned int inactive_ratio; +ZONE_PADDING (_pad2_)/* Rarely used or read-mostly fields */
mm/page_alloc.c +40 -0
@@ -4232,6 +4232,45 @@ void setup_per_zone_pages_min(void)calculate_totalreserve_pages (); } +/** +* setup_per_zone_inactive_ratio - called when min_free_kbytes changes. +* +* The inactive anon list should be small enough that the VM never has to +* do too much work, but large enough that each inactive page has a chance +* to be referenced again before it is swapped out. +* +* The inactive_anon ratio is the ratio of active to inactive anonymous +* pages. Ie. a ratio of 3 means 3:1 or 25% of the anonymous pages are +* on the inactive list. +* +* total return max +* memory value inactive anon +* ------------------------------------- +* 10MB 1 5MB +* 100MB 1 50MB +* 1GB 3 250MB +* 10GB 10 0.9GB +* 100GB 31 3GB +* 1TB 101 10GB +* 10TB 320 32GB +*/ +void setup_per_zone_inactive_ratio (void ) +{ +struct zone *zone; + +for_each_zone (zone) { +unsigned int gb, ratio; + +/* Zone size in gigabytes */ + gb = zone->present_pages >> (30 -PAGE_SHIFT ); + ratio =int_sqrt (10 * gb); +if (!ratio) + ratio =1 ; + + zone->inactive_ratio = ratio; + } +} +/* * Initialise min_free_kbytes. *
@@ -4269,6 +4308,7 @@ static int __init init_per_zone_pages_mi min_free_kbytes =65536 ;setup_per_zone_pages_min ();setup_per_zone_lowmem_reserve (); +setup_per_zone_inactive_ratio ();return 0 ; }module_init (init_per_zone_pages_min)
mm/vmscan.c +31 -6
@@ -1019,7 +1019,7 @@ static inline int zone_is_near_oom(strucstatic void shrink_active_list (unsigned long nr_pages,struct zone *zone,struct scan_control *sc,int priority,int file) { -unsigned long pgmoved; +unsigned long pgmoved =0 ;int pgdeactivate =0 ;unsigned long pgscanned;LIST_HEAD (l_hold);/* The pages which were snipped off */
@@ -1058,12 +1058,25 @@ static void shrink_active_list(unsignedcond_resched (); page =lru_to_page (&l_hold);list_del (&page->lru); -if (page_referenced (page,0 , sc->mem_cgroup)) - lru =LRU_ACTIVE_ANON ; +if (page_referenced (page,0 , sc->mem_cgroup)) { +if (file) +/* Referenced file pages stay active. */ + lru =LRU_ACTIVE_ANON ; +else +/* Anonymous pages always get deactivated. */ + pgmoved++; + }list_add (&page->lru, &list[lru]); }/* +* Count the referenced anon pages as rotated, to balance pageout +* scan pressure between file and anonymous pages in get_scan_ratio. +*/ +if (!file) + zone->recent_rotated_anon += pgmoved; + +/* * Now put the pages back to the appropriate [file or anon] inactive * and active lists. */
@@ -1145,7 +1158,11 @@ static unsigned long shrink_list(enum lr {int file =is_file_lru (lru); -if (lru ==LRU_ACTIVE_ANON || lru ==LRU_ACTIVE_FILE ) { +if (lru ==LRU_ACTIVE_FILE ) { +shrink_active_list (nr_to_scan, zone, sc, priority, file); +return 0 ; + } +if (lru ==LRU_ACTIVE_ANON &&inactive_anon_low (zone)) {shrink_active_list (nr_to_scan, zone, sc, priority, file);return 0 ; }
@@ -1255,8 +1272,8 @@ static unsigned long shrink_zone(int pri } } -while (nr[LRU_ACTIVE_ANON ] || nr[LRU_INACTIVE_ANON ] || - nr[LRU_ACTIVE_FILE ] || nr[LRU_INACTIVE_FILE ]) { +while (nr[LRU_INACTIVE_ANON ] || nr[LRU_ACTIVE_FILE ] || + nr[LRU_INACTIVE_FILE ]) {for_each_lru (l) {if (nr[l]) { nr_to_scan = min(nr[l],
@@ -1560,6 +1577,14 @@ loop_again: priority != DEF_PRIORITY)continue ; +/* +* Do some background aging of the anon list, to give +* pages a chance to be referenced before reclaiming. +*/ +if (inactive_anon_low (zone)) +shrink_active_list (SWAP_CLUSTER_MAX , zone, + &sc, priority,0 ); +if (!zone_watermark_ok (zone, order, zone->pages_high,0 ,0 )) { end_zone = i;
mm/vmstat.c +4 -2
@@ -800,10 +800,12 @@ static void zoneinfo_show_print(struct sseq_printf (m,"\n all_unreclaimable: %u" "\n prev_priority: %i" -"\n start_pfn: %lu" , +"\n start_pfn: %lu" +"\n inactive_ratio: %u" ,zone_is_all_unreclaimable (zone), zone->prev_priority, - zone->zone_start_pfn); + zone->zone_start_pfn, + zone->inactive_ratio);seq_putc (m,'\n' ); }
Signature · 7 lines
All Rights Reversed -- 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 07/21] SEQ replacement for anonymous pages
Hi, Rik.
static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
struct scan_control *sc, int priority, int file)
{
- unsigned long pgmoved;
+ unsigned long pgmoved = 0;
int pgdeactivate = 0;
unsigned long pgscanned;
LIST_HEAD(l_hold); /* The pages which were snipped off */
@@ -1058,12 +1058,25 @@ static void shrink_active_list(unsigned
cond_resched();
page = lru_to_page(&l_hold);
list_del(&page->lru);
- if (page_referenced(page, 0, sc->mem_cgroup))
- lru = LRU_ACTIVE_ANON;
+ if (page_referenced(page, 0, sc->mem_cgroup)) {
+ if (file)
+ /* Referenced file pages stay active. */
+ lru = LRU_ACTIVE_ANON;
+ else
+ /* Anonymous pages always get deactivated. */
+ pgmoved++;
+ }
list_add(&page->lru, &list[lru]);
}
Why do you insert referenced page to LRU_ACTIVE_ANON ?
I have seen picture in your design document (http://linux-mm.org/PageReplacementDesign)
If I understand your point well, page referenced is inserted to LRU_ACTIVE_FILE.
What am I missing in your point?
Thanks, barrios
--
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 8/21 (NEW) add some sanity checks to get_scan_ratio
In reply to Rik van RielThe access ratio based scan rate determination in get_scan_ratio works ok in most situations, but needs to be corrected in some corner cases:
- if we run out of swap space, do not bother scanning the anon LRUs
- if we have already freed all of the page cache, we need to scan the anon LRUs
- restore the *actual* access ratio based scan rate algorithm, the previous versions of this patch series had the wrong version
- scale the number of pages added to zone->nr_scan[l]
mm/vmscan.c +62 -33
@@ -906,8 +906,13 @@ static unsigned long shrink_inactive_lis__mod_zone_page_state (zone,NR_INACTIVE_ANON , -count[LRU_INACTIVE_ANON ]); -if (scan_global_lru (sc)) +if (scan_global_lru (sc)) { zone->pages_scanned += nr_scan; + zone->recent_scanned_anon += count[LRU_ACTIVE_ANON ] + + count[LRU_INACTIVE_ANON ]; + zone->recent_scanned_file += count[LRU_ACTIVE_FILE ] + + count[LRU_INACTIVE_FILE ]; + }spin_unlock_irq (&zone->lru_lock); nr_scanned += nr_scan;
@@ -957,11 +962,13 @@ static unsigned long shrink_inactive_lisVM_BUG_ON (PageLRU (page));SetPageLRU (page);list_del (&page->lru); -if (page_file_cache (page)) { +if (page_file_cache (page)) lru +=LRU_FILE ; - zone->recent_rotated_file++; - }else { - zone->recent_rotated_anon++; +if (scan_global_lru (sc)) { +if (page_file_cache (page)) + zone->recent_rotated_file++; +else + zone->recent_rotated_anon++; }if (PageActive (page)) lru +=LRU_ACTIVE ;
@@ -1040,8 +1047,13 @@ static void shrink_active_list(unsigned* zone->pages_scanned is used for detect zone's oom * mem_cgroup remembers nr_scan by itself. */ -if (scan_global_lru (sc)) +if (scan_global_lru (sc)) { zone->pages_scanned += pgscanned; +if (file) + zone->recent_scanned_file += pgscanned; +else + zone->recent_scanned_anon += pgscanned; + }if (file)__mod_zone_page_state (zone,NR_ACTIVE_FILE , -pgmoved);else
@@ -1182,9 +1194,8 @@ static unsigned long shrink_list(enum lrstatic void get_scan_ratio (struct zone *zone,struct scan_control * sc,unsigned long *percent) { -unsigned long anon, file; +unsigned long anon, file, free;unsigned long anon_prio, file_prio; -unsigned long rotate_sum;unsigned long ap, fp; anon = zone_page_state(zone, NR_ACTIVE_ANON) +
@@ -1192,15 +1203,19 @@ static void get_scan_ratio(struct zone * file =zone_page_state (zone,NR_ACTIVE_FILE ) +zone_page_state (zone,NR_INACTIVE_FILE ); - rotate_sum = zone->recent_rotated_file + zone->recent_rotated_anon; -/* Keep a floating average of RECENT references. */ -if (unlikely (rotate_sum >min (anon, file))) { +if (unlikely (zone->recent_scanned_anon > anon / zone->inactive_ratio)) {spin_lock_irq (&zone->lru_lock); - zone->recent_rotated_file /=2 ; + zone->recent_scanned_anon /=2 ; zone->recent_rotated_anon /=2 ;spin_unlock_irq (&zone->lru_lock); - rotate_sum /=2 ; + } + +if (unlikely (zone->recent_scanned_file > file /4 )) { +spin_lock_irq (&zone->lru_lock); + zone->recent_scanned_file /=2 ; + zone->recent_rotated_file /=2 ; +spin_unlock_irq (&zone->lru_lock); }/*
@@ -1213,23 +1228,33 @@ static void get_scan_ratio(struct zone */* * anon recent_rotated_anon * %anon = 100 * ----------- / ------------------- * IO cost -* anon + file rotate_sum +* anon + file recent_scanned_anon */ - ap = (anon_prio * anon) / (anon + file +1 ); - ap *= rotate_sum / (zone->recent_rotated_anon +1 ); -if (ap ==0 ) - ap =1 ; -else if (ap >100 ) - ap =100 ; - percent[0 ] = ap; - - fp = (file_prio * file) / (anon + file +1 ); - fp *= rotate_sum / (zone->recent_rotated_file +1 ); -if (fp ==0 ) - fp =1 ; -else if (fp >100 ) - fp =100 ; - percent[1 ] = fp; + ap = (anon_prio +1 ) * (zone->recent_scanned_anon +1 ); + ap /= zone->recent_rotated_anon +1 ; + + fp = (file_prio +1 ) * (zone->recent_scanned_file +1 ); + fp /= zone->recent_rotated_file +1 ; + +/* Normalize to percentages */ + percent[0 ] =100 * ap / (ap + fp +1 ); + percent[1 ] =100 - percent[0 ]; + + free =zone_page_state (zone,NR_FREE_PAGES ); + +/* +* If we have no swap space, do not bother scanning anon pages. +*/ +if (nr_swap_pages <=0 ) { + percent[0 ] =0 ; + percent[1 ] =100 ; + } +/* +* If we already freed most file pages, scan the anon pages +* regardless of the page access ratios or swappiness setting. +*/ +else if (file + free <= zone->pages_high) + percent[0 ] =100 ; }
@@ -1250,13 +1275,17 @@ static unsigned long shrink_zone(int prifor_each_lru (l) {if (scan_global_lru (sc)) {int file =is_file_lru (l); +int scan;/* * Add one to nr_to_scan just to make sure that the -* kernel will slowly sift through the active list. +* kernel will slowly sift through each list. */ - zone->nr_scan[l] += (zone_page_state (zone, -NR_INACTIVE_ANON + l) >> priority) +1 ; - nr[l] = zone->nr_scan[l] * percent[file] /100 ; + scan =zone_page_state (zone,NR_INACTIVE_ANON + l); + scan >>= priority; + scan = (scan * percent[file]) /100 ; + + zone->nr_scan[l] += scan +1 ; + nr[l] = zone->nr_scan[l];if (nr[l] >= sc->swap_cluster_max) zone->nr_scan[l] =0 ;else
include/linux/mmzone.h +2 -0
@@ -300,6 +300,8 @@ struct zone {unsigned long recent_rotated_anon;unsigned long recent_rotated_file; +unsigned long recent_scanned_anon; +unsigned long recent_scanned_file;unsigned long pages_scanned;/* since last reclaim */ unsigned long flags;/* zone flags, see below */
mm/page_alloc.c +2 -1
@@ -3478,7 +3478,8 @@ static void __meminit free_area_init_cor } zone->recent_rotated_anon =0 ; zone->recent_rotated_file =0 ; -//TODO recent_scanned_* ??? + zone->recent_scanned_anon =0 ; + zone->recent_scanned_file =0 ;zap_zone_vm_stats (zone); zone->flags =0 ;if (!size)
mm/swap.c +11 -2
@@ -191,8 +191,8 @@ void activate_page(struct page *page)spin_lock_irq (&zone->lru_lock);if (PageLRU (page) && !PageActive (page)) { -int lru =LRU_BASE ; - lru +=page_file_cache (page); +int file =page_file_cache (page); +int lru =LRU_BASE + file;del_page_from_lru_list (zone, page, lru);SetPageActive (page);
@@ -200,6 +200,15 @@ void activate_page(struct page *page)add_page_to_lru_list (zone, page, lru);__count_vm_event (PGACTIVATE );mem_cgroup_move_lists (page_get_page_cgroup (page), true); + +if (file) { + zone->recent_scanned_file++; + zone->recent_rotated_file++; + }else { +/* Can this happen? Maybe through tmpfs... */ + zone->recent_scanned_anon++; + zone->recent_rotated_anon++; + } }spin_unlock_irq (&zone->lru_lock); }
Signature · 7 lines
All Rights Reversed -- 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 08/21] (NEW) add some sanity checks to get_scan_ratio
@@ -1182,9 +1194,8 @@ static unsigned long shrink_list(enum lr
static void get_scan_ratio(struct zone *zone, struct scan_control * sc,
unsigned long *percent)
{
- unsigned long anon, file;
+ unsigned long anon, file, free;
unsigned long anon_prio, file_prio;
- unsigned long rotate_sum;
unsigned long ap, fp;
anon = zone_page_state(zone, NR_ACTIVE_ANON) +
@@ -1192,15 +1203,19 @@ static void get_scan_ratio(struct zone *
file = zone_page_state(zone, NR_ACTIVE_FILE) +
zone_page_state(zone, NR_INACTIVE_FILE);
- rotate_sum = zone->recent_rotated_file + zone->recent_rotated_anon;
-
/* Keep a floating average of RECENT references. */
- if (unlikely(rotate_sum > min(anon, file))) {
+ if (unlikely(zone->recent_scanned_anon > anon / zone->inactive_ratio)) {
spin_lock_irq(&zone->lru_lock);
- zone->recent_rotated_file /= 2;
+ zone->recent_scanned_anon /= 2;
zone->recent_rotated_anon /= 2; spin_unlock_irq(&zone->lru_lock);
- rotate_sum /= 2;
+ }
+
+ if (unlikely(zone->recent_scanned_file > file / 4)) {
+ spin_lock_irq(&zone->lru_lock);
+ zone->recent_scanned_file /= 2;
+ zone->recent_rotated_file /= 2;
+ spin_unlock_irq(&zone->lru_lock);
}
/*
@@ -1213,23 +1228,33 @@ static void get_scan_ratio(struct zone *
/*
* anon recent_rotated_anon
* %anon = 100 * ----------- / ------------------- * IO cost
- * anon + file rotate_sum
+ * anon + file recent_scanned_anon
*/
- ap = (anon_prio * anon) / (anon + file + 1);
- ap *= rotate_sum / (zone->recent_rotated_anon + 1);
- if (ap == 0)
- ap = 1;
- else if (ap > 100)
- ap = 100;
- percent[0] = ap;
-
- fp = (file_prio * file) / (anon + file + 1);
- fp *= rotate_sum / (zone->recent_rotated_file + 1);
- if (fp == 0)
- fp = 1;
- else if (fp > 100)
- fp = 100;
- percent[1] = fp;
+ ap = (anon_prio + 1) * (zone->recent_scanned_anon + 1);
+ ap /= zone->recent_rotated_anon + 1;
+
+ fp = (file_prio + 1) * (zone->recent_scanned_file + 1);
+ fp /= zone->recent_rotated_file + 1;
+
+ /* Normalize to percentages */
+ percent[0] = 100 * ap / (ap + fp + 1);
+ percent[1] = 100 - percent[0];
+
+ free = zone_page_state(zone, NR_FREE_PAGES);
+
+ /*
+ * If we have no swap space, do not bother scanning anon pages.
+ */
+ if (nr_swap_pages <= 0) {
+ percent[0] = 0;
+ percent[1] = 100;
+ }
+ /*
+ * If we already freed most file pages, scan the anon pages
+ * regardless of the page access ratios or swappiness setting.
+ */
+ else if (file + free <= zone->pages_high)
+ percent[0] = 100;
}
I think we don't need to calculate ratio percent if it don't have any swap device.
we can get a little bit performance gain.
mm/vmscan.c +11 -8
@@ -1313,6 +1313,15 @@ static void get_scan_ratio(struct zone *zone, struct scan_control * sc,unsigned long anon_prio, file_prio;unsigned long ap, fp; +/* +* If we have no swap space, do not bother scanning anon pages and unnessary calculation. +*/ +if (nr_swap_pages <=0 ) { + percent[0 ] =0 ; + percent[1 ] =100 ; +return ; + } + anon =zone_page_state (zone,NR_ACTIVE_ANON ) +zone_page_state (zone,NR_INACTIVE_ANON ); file = zone_page_state(zone, NR_ACTIVE_FILE) +
@@ -1357,18 +1366,12 @@ static void get_scan_ratio(struct zone *zone, struct scan_control * sc, free =zone_page_state (zone,NR_FREE_PAGES ); -/* -* If we have no swap space, do not bother scanning anon pages. -*/ -if (nr_swap_pages <=0 ) { - percent[0 ] =0 ; - percent[1 ] =100 ; - } +/* * If we already freed most file pages, scan the anon pages * regardless of the page access ratios or swappiness setting. */ -else if (file + free <= zone->pages_high) +if (file + free <= zone->pages_high) percent[0 ] =100 ; }
Thanks,
barrios
--
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 9/21 (NEW) improve reclaim balancing
In reply to Rik van Riel- deactivate anonymous pages regardless of the scan ratio
- go through the reclaim loop at least once for the deactivation
- break out of the reclaim loop if we freed sc->swap_cluster_max pages, on big systems the nr[FOO] targets can get ridiculously large
mm/vmscan.c +9 -1
@@ -1302,7 +1302,7 @@ static unsigned long shrink_zone(int pri }while (nr[LRU_INACTIVE_ANON ] || nr[LRU_ACTIVE_FILE ] || - nr[LRU_INACTIVE_FILE ]) { + nr[LRU_INACTIVE_FILE ]) {for_each_lru (l) {if (nr[l]) { nr_to_scan = min(nr[l],
@@ -1315,6 +1315,14 @@ static unsigned long shrink_zone(int pri } } +/* +* Even if we did not try to evict anon pages at all, we want to +* rebalance the anon lru active/inactive ratio. +*/ +if (inactive_anon_low (zone)) +shrink_list (NR_ACTIVE_ANON ,SWAP_CLUSTER_MAX , zone, sc, + priority); +throttle_vm_writeout (sc->gfp_mask);return nr_reclaimed; }
Signature · 7 lines
All Rights Reversed -- 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 09/21] (NEW) improve reclaim balancing
hi
Review
Quoted 8 lines
(quoted diff) +8
-0+ /* + * Even if we did not try to evict anon pages at all, we want to + * rebalance the anon lru active/inactive ratio. + */ + if (inactive_anon_low(zone)) + shrink_list(NR_ACTIVE_ANON, SWAP_CLUSTER_MAX, zone, sc, + priority); +
you want check global zone status, right? if so, this statement only do that at global scan.
- kosaki
--- mm/vmscan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
mm/vmscan.c 2008-03-01 22:42:42.000000000 +0900 renamed from mm/vmscan.c 2008-03-01 22:18:42.000000000 +0900 +1 -1
@@ -1319,9 +1319,9 @@ static unsigned long shrink_zone(int pri * Even if we did not try to evict anon pages at all, we want to * rebalance the anon lru active/inactive ratio. */ - if (inactive_anon_low(zone)) + if (scan_global_lru(sc) && inactive_anon_low(zone)) shrink_list(NR_ACTIVE_ANON, SWAP_CLUSTER_MAX, zone, sc, priority); throttle_vm_writeout(sc->gfp_mask); return nr_reclaimed;
--
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 09/21] (NEW) improve reclaim balancing
Quoted 13 lines · On Sat, 01 Mar 2008 22:35:44 +0900 KOSAKI Motohiro…
hi
Review
Quoted 8 lines
(quoted diff) +8
-0+ /* + * Even if we did not try to evict anon pages at all, we want to + * rebalance the anon lru active/inactive ratio. + */ + if (inactive_anon_low(zone)) + shrink_list(NR_ACTIVE_ANON, SWAP_CLUSTER_MAX, zone, sc, + priority); +you want check global zone status, right? if so, this statement only do that at global scan.
Good catch. I have merged your suggestions.
Signature · 7 lines
All Rights Reversed -- 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 10/21 add newly swapped in pages to the inactive list
In reply to Rik van RielSwapin_readahead can read in a lot of data that the processes in memory never need. Adding swap cache pages to the inactive list prevents them from putting too much pressure on the working set.
This has the potential to help the programs that are already in memory, but it could also be a disadvantage to processes that are trying to get swapped in.
In short, this patch needs testing.
mm/swap_state.c +1 -1
@@ -300,7 +300,7 @@ struct page *read_swap_cache_async(swp_e/* * Initiate read into locked page and return. */ -lru_cache_add_active_anon (new_page); +lru_cache_add_anon (new_page);swap_readpage (NULL , new_page);return new_page; }
Signature · 7 lines
All Rights Reversed -- 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 11/21 (NEW) more aggressively use lumpy reclaim
In reply to Rik van RielDuring an AIM7 run on a 16GB system, fork started failing around 32000 threads, despite the system having plenty of free swap and 15GB of pageable memory.
If normal pageout does not result in contiguous free pages for kernel stacks, fall back to lumpy reclaim instead of failing fork or doing excessive pageout IO.
I do not know whether this change is needed due to the extreme stress test or because the inactive list is a smaller fraction of system memory on huge systems.
mm/vmscan.c +16 -4
@@ -870,7 +870,8 @@ int isolate_lru_page(struct page *page)* of reclaimed pages */ static unsigned long shrink_inactive_list (unsigned long max_scan, -struct zone *zone,struct scan_control *sc,int file) +struct zone *zone,struct scan_control *sc, +int priority,int file) {LIST_HEAD (page_list);struct pagevec pvec;
@@ -888,8 +889,19 @@ static unsigned long shrink_inactive_lisunsigned long nr_freed;unsigned long nr_active;unsigned int count[NR_LRU_LISTS ] = {0 , }; -int mode = (sc->order >PAGE_ALLOC_COSTLY_ORDER ) ? -ISOLATE_BOTH :ISOLATE_INACTIVE ; +int mode =ISOLATE_INACTIVE ; + +/* +* If we need a large contiguous chunk of memory, or have +* trouble getting a small set of contiguous pages, we +* will reclaim both active and inactive pages. +* +* We use the same threshold as pageout congestion_wait below. +*/ +if (sc->order >PAGE_ALLOC_COSTLY_ORDER ) + mode =ISOLATE_BOTH ; +else if (sc->order && priority <DEF_PRIORITY -2 ) + mode =ISOLATE_BOTH ; nr_taken = sc->isolate_pages(sc->swap_cluster_max, &page_list, &nr_scan, sc->order, mode,
@@ -1178,7 +1190,7 @@ static unsigned long shrink_list(enum lrshrink_active_list (nr_to_scan, zone, sc, priority, file);return 0 ; } -return shrink_inactive_list (nr_to_scan, zone, sc, file); +return shrink_inactive_list (nr_to_scan, zone, sc, priority, file); }/*
Signature · 7 lines
All Rights Reversed -- 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 11/21] (NEW) more aggressively use lumpy reclaim
Hi
I think this patch is very good improvement.
but it is not related to split lru.
Why don't you separate this patch?
IMHO treat as independent patch is better.
Thanks.
Quoted 11 lines
During an AIM7 run on a 16GB system, fork started failing around 32000 threads, despite the system having plenty of free swap and 15GB of pageable memory.
If normal pageout does not result in contiguous free pages for kernel stacks, fall back to lumpy reclaim instead of failing fork or doing excessive pageout IO.
I do not know whether this change is needed due to the extreme stress test or because the inactive list is a smaller fraction of system memory on huge systems.
--
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 11/21] (NEW) more aggressively use lumpy reclaim
Quoted 5 lines · On Sun, 02 Mar 2008 19:35:44 +0900 KOSAKI Motohiro…
I think this patch is very good improvement.
but it is not related to split lru.Why don't you separate this patch?
IMHO treat as independent patch is better.
Agreed, I should probably pull this to the start of the patch series and submit it to Andrew Morton soon.
The arrayification of the LRU lists and pagevecs should probably go into -mm soon, as well. That code is ready and it can be merged independently of the split VM code.
Signature · 7 lines
All rights reversed. -- 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 12/21 No Reclaim LRU Infrastructure
In reply to Rik van RielV1 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU series
+ define NR_NORECLAIM and LRU_NORECLAIM to avoid errors when not configured.
V1 -> V2:
+ handle review comments -- various typos and errors.
+ extract "putback_all_noreclaim_pages()" into a separate patch and rework as "scan_all_zones_noreclaim_pages().
Infrastructure to manage pages excluded from reclaim--i.e., hidden from vmscan. Based on a patch by Larry Woodman of Red Hat. Reworked to maintain "nonreclaimable" pages on a separate per-zone LRU list, to "hide" them from vmscan. A separate noreclaim pagevec is provided for shrink_active_list() to move nonreclaimable pages to the noreclaim list without over burdening the zone lru_lock.
Pages on the noreclaim list have both PG_noreclaim and PG_lru set. Thus, PG_noreclaim is analogous to and mutually exclusive with PG_active--it specifies which LRU list the page is on.
The noreclaim infrastructure is enabled by a new mm Kconfig option [CONFIG_]NORECLAIM.
A new function 'page_reclaimable(page, vma)' in vmscan.c tests whether or not a page is reclaimable. Subsequent patches will add the various !reclaimable tests. We'll want to keep these tests light-weight for use in shrink_active_list() and, possibly, the fault path.
Notes:
1. for now, use bit 30 in page flags. This restricts the no reclaim infrastructure to 64-bit systems. [The mlock patch, later in this series, uses another of these 64-bit-system-only flags.]
Rationale: 32-bit systems have no free page flags and are less likely to have the large amounts of memory that exhibit the problems this series attempts to solve. [I'm sure someone will disabuse me of this notion.]
Thus, NORECLAIM currently depends on [CONFIG_]64BIT.
2. The pagevec to move pages to the noreclaim list results in another loop at the end of shrink_active_list(). If we ultimately adopt Rik van Riel's split lru approach, I think we'll need to find a way to factor all of these loops into some common code.
3. TODO: Memory Controllers maintain separate active and inactive lists. Need to consider whether they should also maintain a noreclaim list. Also, convert to use Christoph's array of indexed lru variables?
See //TODO note in mm/memcontrol.c re: isolating non-reclaimable pages.
4. TODO: more factoring of lru list handling. But, I want to get this as close to functionally correct as possible before introducing those perturbations.
mm/Kconfig +10 -0
@@ -193,3 +193,13 @@ config NR_QUICK config VIRT_TO_BUS def_bool y depends on !ARCH_NO_VIRT_TO_BUS + +config NORECLAIM + bool "Track non-reclaimable pages (EXPERIMENTAL; 64BIT only)" + depends on EXPERIMENTAL && 64BIT + help + Supports tracking of non-reclaimable pages off the [in]active lists + to avoid excessive reclaim overhead on large memory systems. Pages + may be non-reclaimable because: they are locked into memory, they + are anonymous pages for which no swap space exists, or they are anon + pages that are expensive to unmap [long anon_vma "related vma" list.]
include/linux/page-flags.h +18 -0
@@ -107,6 +107,8 @@* 63 32 0 */ #define PG_uncached 31/* Page has been mapped as uncached */ + +#define PG_noreclaim 30/* Page is "non-reclaimable" */ #endif /*
@@ -196,6 +198,7 @@ static inline void SetPageUptodate(struc#define SetPageActive (page) set_bit(PG_active, &(page)->flags)#define ClearPageActive (page) clear_bit(PG_active, &(page)->flags)#define __ClearPageActive (page) __clear_bit(PG_active, &(page)->flags) +#define TestClearPageActive (page) test_and_clear_bit(PG_active, &(page)->flags)#define PageSlab (page) test_bit(PG_slab, &(page)->flags)#define __SetPageSlab (page) __set_bit(PG_slab, &(page)->flags)
@@ -297,6 +300,21 @@ static inline void __ClearPageTail(struc#define PageSwapCache (page) 0#endif +#ifdef CONFIG_NORECLAIM +#define PageNoreclaim (page) test_bit(PG_noreclaim, &(page)->flags) +#define SetPageNoreclaim (page) set_bit(PG_noreclaim, &(page)->flags) +#define ClearPageNoreclaim (page) clear_bit(PG_noreclaim, &(page)->flags) +#define __ClearPageNoreclaim (page) __clear_bit(PG_noreclaim, &(page)->flags) +#define TestClearPageNoreclaim (page) test_and_clear_bit(PG_noreclaim, \ + &(page)->flags) +#else +#define PageNoreclaim (page) 0 +#define SetPageNoreclaim (page) +#define ClearPageNoreclaim (page) +#define __ClearPageNoreclaim (page) +#define TestClearPageNoreclaim (page) 0 +#endif +#define PageUncached (page) test_bit(PG_uncached, &(page)->flags)#define SetPageUncached (page) set_bit(PG_uncached, &(page)->flags)#define ClearPageUncached (page) clear_bit(PG_uncached, &(page)->flags)
include/linux/mmzone.h +23 -1
@@ -84,6 +84,11 @@ enum zone_stat_item {NR_ACTIVE_ANON ,/* " " " " " */ NR_INACTIVE_FILE ,/* " " " " " */ NR_ACTIVE_FILE ,/* " " " " " */ +#ifdef CONFIG_NORECLAIM +NR_NORECLAIM ,/* " " " " " */ +#else +NR_NORECLAIM =NR_ACTIVE_FILE ,/* avoid compiler errors in dead code */ +#endifNR_ANON_PAGES ,/* Mapped anonymous pages */ NR_FILE_MAPPED ,/* pagecache pages mapped into pagetables. only modified from process context */
@@ -122,10 +127,18 @@ enum lru_list {LRU_ACTIVE_ANON =LRU_BASE +LRU_ACTIVE ,LRU_INACTIVE_FILE =LRU_BASE +LRU_FILE ,LRU_ACTIVE_FILE =LRU_BASE +LRU_FILE +LRU_ACTIVE , - NR_LRU_LISTS }; +#ifdef CONFIG_NORECLAIM +LRU_NORECLAIM , +#else +LRU_NORECLAIM =LRU_ACTIVE_FILE ,/* avoid compiler errors in dead code */ +#endif + NR_LRU_LISTS +};#define for_each_lru (l) for (l = 0; l < NR_LRU_LISTS; l++) +#define for_each_reclaimable_lru (l) for (l = 0; l <= LRU_ACTIVE_FILE; l++) +static inline int is_file_lru (enum lru_list l) {if (l ==LRU_INACTIVE_FILE || l ==LRU_ACTIVE_FILE )
@@ -140,6 +153,15 @@ static inline int is_active_lru(enum lrureturn 0 ; } +static inline int is_noreclaim_lru (enum lru_list l) +{ +#ifdef CONFIG_NORECLAIM +if (l ==LRU_NORECLAIM ) +return 1 ; +#endif +return 0 ; +} +enum lru_list page_lru (struct page *page);struct per_cpu_pages {
mm/page_alloc.c +9 -0
@@ -248,6 +248,9 @@ static void bad_page(struct page *page) 1 << PG_private | 1 << PG_locked | 1 << PG_active | +#ifdef CONFIG_NORECLAIM + 1 << PG_noreclaim | +#endif 1 << PG_dirty | 1 << PG_reclaim | 1 << PG_slab |
@@ -482,6 +485,9 @@ static inline int free_pages_check(struc 1 << PG_swapcache | 1 << PG_writeback | 1 << PG_reserved | +#ifdef CONFIG_NORECLAIM + 1 << PG_noreclaim | +#endif 1 << PG_buddy ))))bad_page (page);if (PageDirty (page))
@@ -629,6 +635,9 @@ static int prep_new_page(struct page *pa 1 << PG_private | 1 << PG_locked | 1 << PG_active | +#ifdef CONFIG_NORECLAIM + 1 << PG_noreclaim | +#endif 1 << PG_dirty | 1 << PG_slab | 1 << PG_swapcache |
include/linux/mm_inline.h +29 -4
@@ -81,17 +81,42 @@ del_page_from_active_file_list(struct zodel_page_from_lru_list (zone, page,LRU_INACTIVE_FILE ); } +#ifdef CONFIG_NORECLAIM +static inline void +add_page_to_noreclaim_list (struct zone *zone,struct page *page) +{ +add_page_to_lru_list (zone, page,LRU_NORECLAIM ); +} + +static inline void +del_page_from_noreclaim_list (struct zone *zone,struct page *page) +{ +del_page_from_lru_list (zone, page,LRU_NORECLAIM ); +} +#else +static inline void +add_page_to_noreclaim_list (struct zone *zone,struct page *page) { } + +static inline void +del_page_from_noreclaim_list (struct zone *zone,struct page *page) { } +#endif +static inline void del_page_from_lru (struct zone *zone,struct page *page) {enum lru_list l =LRU_INACTIVE_ANON ;list_del (&page->lru); -if (PageActive (page)) { -__ClearPageActive (page); - l +=LRU_ACTIVE ; +if (PageNoreclaim (page)) { +__ClearPageNoreclaim (page); + l =LRU_NORECLAIM ; + }else { +if (PageActive (page)) { +__ClearPageActive (page); + l +=LRU_ACTIVE ; + } + l +=page_file_cache (page); } - l +=page_file_cache (page);__dec_zone_state (zone,NR_INACTIVE_ANON + l); }
include/linux/swap.h +24 -0
@@ -173,6 +173,8 @@ extern unsigned int nr_free_pagecache_pa/* linux/mm/swap.c */ extern void __lru_cache_add (struct page *,enum lru_list lru);extern void lru_cache_add_lru (struct page *,enum lru_list lru); +extern void lru_cache_add_active_or_noreclaim (struct page *, +struct vm_area_struct *);extern void activate_page (struct page *);extern void mark_page_accessed (struct page *);extern void lru_add_drain (void );
@@ -204,6 +206,18 @@ static inline void lru_cache_add_active___lru_cache_add (page,LRU_ACTIVE_FILE ); } +#ifdef CONFIG_NORECLAIM +static inline void lru_cache_add_noreclaim (struct page *page) +{ +__lru_cache_add (page,LRU_NORECLAIM ); +} +#else +static inline void lru_cache_add_noreclaim (struct page *page) +{ +BUG ("Noreclaim not configured, but page added anyway?!" ); +} +#endif +/* linux/mm/vmscan.c */ extern unsigned long try_to_free_pages (struct zone **zones,int order,gfp_t gfp_mask);
@@ -228,6 +242,16 @@ static inline int zone_reclaim(struct zo }#endif +#ifdef CONFIG_NORECLAIM +extern int page_reclaimable (struct page *page,struct vm_area_struct *vma); +#else +static inline int page_reclaimable (struct page *page, +struct vm_area_struct *vma) +{ +return 1 ; +} +#endif +extern int kswapd_run (int nid);#ifdef CONFIG_MMU
include/linux/pagevec.h +6 -0
@@ -101,6 +101,12 @@ static inline void __pagevec_lru_add_act____pagevec_lru_add (pvec,LRU_ACTIVE_FILE ); } +#ifdef CONFIG_NORECLAIM +static inline void __pagevec_lru_add_noreclaim (struct pagevec *pvec) +{ +____pagevec_lru_add (pvec,LRU_NORECLAIM ); +} +#endif static inline void pagevec_lru_add_file (struct pagevec *pvec) {
mm/swap.c +39 -10
113 lines not on this page · raw message
mm/migrate.c +4 -2
@@ -326,8 +326,11 @@ static void migrate_page_copy(struct pagSetPageReferenced (newpage);if (PageUptodate (page))SetPageUptodate (newpage); -if (PageActive (page)) +if (TestClearPageActive (page)) { +VM_BUG_ON (PageNoreclaim (page));SetPageActive (newpage); + }else if (TestClearPageNoreclaim (page)) +SetPageNoreclaim (newpage);if (PageChecked (page))SetPageChecked (newpage);if (PageMappedToDisk (page))
@@ -341,7 +344,6 @@ static void migrate_page_copy(struct pag#ifdef CONFIG_SWAP ClearPageSwapCache (page);#endif -ClearPageActive (page);ClearPagePrivate (page);set_page_private (page,0 ); page->mapping =NULL ;
mm/vmscan.c +103 -17
204 lines not on this page · raw message
mm/mempolicy.c +1 -1
@@ -1922,7 +1922,7 @@ static void gather_stats(struct page *paif (PageSwapCache (page)) md->swapcache++; -if (PageActive (page)) +if (PageActive (page) ||PageNoreclaim (page)) md->active++;if (PageWriteback (page))
mm/memcontrol.c +4 -0
@@ -519,6 +519,10 @@ unsigned long mem_cgroup_isolate_pages(u scan++;list_move (&pc->lru, &pc_list); +//TODO: for now, don't isolate non-reclaimable pages. When/if +// mem controller supports a noreclaim list, we'll need to make +// at least ISOLATE_ACTIVE visible outside of vm_scan and pass +// the 'take_nonreclaimable' flag accordingly. if (__isolate_lru_page (page, mode, file) ==0 ) {list_move (&page->lru, dst); nr_taken++;
Signature · 7 lines
All Rights Reversed -- 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>
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [patch 12/21] No Reclaim LRU Infrastructure
Quoted 15 lines · minchan Kim
+#ifdef CONFIG_NORECLAIM
+static inline void lru_cache_add_noreclaim(struct page *page)
+{
+ __lru_cache_add(page, LRU_NORECLAIM);
+}
+#else
+static inline void lru_cache_add_noreclaim(struct page *page)
+{
+ BUG("Noreclaim not configured, but page added
anyway?!");
+}
+#endif
+Quoted 1 line
BUG()can't take a argument.
Right. I don't have a clue how that got there :-(.
Thanks,
Lee
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [patch 12/21] No Reclaim LRU Infrastructure
Sorry, I sended HTML format, so fail to send [email protected] I will resend in TEXT/PLAIN format.
Quoted 45 lines · minchan Kim
One more thing.
zoneinfo_show_printfail to show right information.
That's why 'enumzone_stat_item' and 'vmstat_text' index didn't matched. This is a problem aboutCONFIG_NORECLAIM, too.Quoted 19 lines · Lee Schermerhorn
Quoted 15 lines · minchan Kim
+#ifdef CONFIG_NORECLAIM +static inline void lru_cache_add_noreclaim(struct page *page) +{ + __lru_cache_add(page, LRU_NORECLAIM); +} +#else +static inline void lru_cache_add_noreclaim(struct page *page) +{ + BUG("Noreclaim not configured, but page added anyway?!"); +} +#endif +Quoted 8 lines
Quoted 1 line
BUG()can't take a argument.Right. I don't have a clue how that got there :-(.
Thanks,
Lee--
Thanks,
barrios
Signature · 8 lines
Thanks, barrios -- 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 12/21] No Reclaim LRU Infrastructure
In reply to a message not in the archiveQuoted 5 lines · On Mon, 3 Mar 2008 12:04:14 +0900 "minchan Kim" <[email protected]> wrote:
One more thing.
zoneinfo_show_printfail to show right information.
That's why 'enumzone_stat_item' and 'vmstat_text' index didn't matched. This is a problem aboutCONFIG_NORECLAIM, too.
In what configuration do they not line up, and why?
AFAICS the #ifdefs in zone_stat_item and vmstat_text match up...
Signature · 7 lines
All Rights Reversed -- 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 12/21] No Reclaim LRU Infrastructure
Quoted 5 lines · Rik van Riel
Quoted 2 lines · On Mon, 3 Mar 2008 12:04:14 +0900 "minchan Kim" <[email protected]> wrote:
One more thing.
Quoted 8 lines
Quoted 3 lines
zoneinfo_show_printfail to show right information.
That's why 'enumzone_stat_item' and 'vmstat_text' index didn't matched. This is a problem aboutCONFIG_NORECLAIM, too.In what configuration do they not line up, and why?
AFAICS the #ifdefs in
zone_stat_itemandvmstat_textmatch up...
So sorry, It was my mistake.
I seem to have a bad eye :(
Thanks,
barrios
--
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 12/21] No Reclaim LRU Infrastructure
Quoted 10 lines · On Tue, 04 Mar 2008 08:38:52 +0900 "barrioskmc@gmail" <[email protected]>…
Quoted 9 lines · Rik van Riel
Quoted 5 lines · On Mon, 3 Mar 2008 12:04:14 +0900 "minchan Kim" <[email protected]> wrote:
One more thing.
zoneinfo_show_printfail to show right information.
That's why 'enumzone_stat_item' and 'vmstat_text' index didn't matched. This is a problem aboutCONFIG_NORECLAIM, too.
Quoted 7 lines
Quoted 4 lines
In what configuration do they not line up, and why?
AFAICS the #ifdefs in
zone_stat_itemandvmstat_textmatch up...So sorry, It was my mistake.
I seem to have a bad eye :(
Not at all. You found a number of real issues with my patch series, which I have fixed today. I am happy that people like you take a good look at my patches, so I get a chance to improve them.
Signature · 7 lines
All rights reversed. -- 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 12/21] No Reclaim LRU Infrastructure
In reply to Rik van RielHi
sorry for late review.
mm/Kconfig config NR_QUICK · line 199
Quoted 13 lines
Index: linux-2.6.25-rc2-mm1/mm/Kconfig
===================================================================mm/Kconfig +4
-0@@ -193,3 +193,13 @@ config NR_QUICK config VIRT_TO_BUS def_bool y depends on !ARCH_NO_VIRT_TO_BUS + +config NORECLAIM + bool "Track non-reclaimable pages (EXPERIMENTAL; 64BIT only)" + depends on EXPERIMENTAL && 64BIT
as far as I remembered, somebody said CONFIG_NORECLAIM is easy confusable. may be..
IMHO insert "lru" word is better.
example,
config NORECLAIM_LRU
bool "Zone LRU of track non-reclaimable pages (EXPERIMENTAL; 64BIT only)" depends on EXPERIMENTAL && 64BIT
mm/Kconfig void release_pages(struct page **pages, · line 388
Quoted 12 lines
mm/Kconfig +4
-2@@ -356,8 +380,10 @@ void release_pages(struct page **pages, zone = pagezone; spin_lock_irqsave(&zone->lru_lock, flags); } - VM_BUG_ON(!PageLRU(page)); - __ClearPageLRU(page); + is_lru_page = PageLRU(page); + VM_BUG_ON(!(is_lru_page)); + if (is_lru_page) + __ClearPageLRU(page); del_page_from_lru(zone, page); }
it seems unnecessary change??
--
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 12/21] No Reclaim LRU Infrastructure
Quoted 21 lines · KOSAKI Motohiro
Hi
sorry for late review.
mm/Kconfig config NR_QUICK · line 199
Quoted 13 lines
Index: linux-2.6.25-rc2-mm1/mm/Kconfig
===================================================================mm/Kconfig +4
-0@@ -193,3 +193,13 @@ config NR_QUICK config VIRT_TO_BUS def_bool y depends on !ARCH_NO_VIRT_TO_BUS + +config NORECLAIM + bool "Track non-reclaimable pages (EXPERIMENTAL; 64BIT only)" + depends on EXPERIMENTAL && 64BITas far as I remembered, somebody said
CONFIG_NORECLAIMis easy confusable. may be..
Quoted 6 lines
IMHO insert "lru" word is better.
example,config
NORECLAIM_LRUbool "Zone LRU of track non-reclaimable pages (EXPERIMENTAL; 64BIT only)" depends on EXPERIMENTAL && 64BIT
OK. But, I'd suggest the 'bool' description be something like:
config NORECLAIM_LRU
bool "Add LRU list to track non-reclaimable pages (EXPERIMENTAL; 64BIT only)"
Quoted 16 lines
Quoted 4 lines
mm/Kconfig +0
-0@@ -356,8 +380,10 @@ void release_pages(struct page **pages, zone = pagezone;mm/Kconfig void release_pages(struct page **pages, · line 388
Quoted 10 lines
mm/Kconfig +4
-2spin_lock_irqsave(&zone->lru_lock, flags); } - VM_BUG_ON(!PageLRU(page)); - __ClearPageLRU(page); + is_lru_page = PageLRU(page); + VM_BUG_ON(!(is_lru_page)); + if (is_lru_page) + __ClearPageLRU(page); del_page_from_lru(zone, page); }it seems unnecessary change??
Hmmm. Not sure what I was thinking here. Might be a relic of some previous debug instrumentation. Guess I don't have any problem with removing this change.
Lee
Re: [patch 12/21] No Reclaim LRU Infrastructure
Quoted 11 lines · On Tue, 04 Mar 2008 10:05:58 -0500 Lee Schermerhorn <[email protected]>…
Quoted 6 lines
IMHO insert "lru" word is better.
example,config
NORECLAIM_LRUbool "Zone LRU of track non-reclaimable pages (EXPERIMENTAL; 64BIT only)" depends on EXPERIMENTAL && 64BITOK. But, I'd suggest the 'bool' description be something like:
config
NORECLAIM_LRU
bool "Add LRU list to track non-reclaimable pages (EXPERIMENTAL; 64BIT only)"
I have added this in the 2.6.25-rc3-mm1 port.
Quoted 16 lines
Quoted 15 lines
mm/swap.c void release_pages(struct page **pages, · line 388
Quoted 13 lines
mm/swap.c +4
-2@@ -356,8 +380,10 @@ void release_pages(struct page **pages, zone = pagezone;spin_lock_irqsave (&zone->lru_lock, flags); } -VM_BUG_ON (!PageLRU (page)); -__ClearPageLRU (page); + is_lru_page =PageLRU (page); +VM_BUG_ON (!(is_lru_page)); +if (is_lru_page) +__ClearPageLRU (page);del_page_from_lru (zone, page); }it seems unnecessary change??
Quoted 3 lines
Hmmm. Not sure what I was thinking here. Might be a relic of some previous debug instrumentation. Guess I don't have any problem with removing this change.
Removed.
Signature · 7 lines
All Rights Reversed -- 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 12/21] No Reclaim LRU Infrastructure
In reply to Lee SchermerhornQuoted 10 lines
Quoted 10 lines
mm/Kconfig config NR_QUICK · line 199
Quoted 3 lines
mm/Kconfig +3
-0+config NORECLAIM + bool "Track non-reclaimable pages (EXPERIMENTAL; 64BIT only)" + depends on EXPERIMENTAL && 64BITas far as I remembered, somebody said
CONFIG_NORECLAIMis easy confusable. may be..IMHO insert "lru" word is better.
example,
Quoted 8 lines
Quoted 3 lines
config
NORECLAIM_LRUbool "Zone LRU of track non-reclaimable pages (EXPERIMENTAL; 64BIT only)" depends on EXPERIMENTAL && 64BITOK. But, I'd suggest the 'bool' description be something like:
config
NORECLAIM_LRU
bool "Add LRU list to track non-reclaimable pages (EXPERIMENTAL; 64BIT only)"
That's nice. thanks.
--
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 13/21 Non-reclaimable page statistics
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU series
V1 -> V2:
no changes
Report non-reclaimable pages per zone and system wide.
Note: may want to track/report some specific reasons for nonreclaimability for deciding when to splice the noreclaim lists back to the normal lru. That will be tricky, especially in shrink_active_list(), where we'd need someplace to save the per page reason for non-reclaimability until the pages are dumped back onto the noreclaim list from the pagevec.
Note: my tests indicate that NR_NORECLAIM and probably the other LRU stats aren't being maintained properly--especially with large amounts of mlocked memory and the mlock patch in this series installed. Can't be sure of this, as I don't know why the pages are on the noreclaim list. Needs further investigation.
mm/page_alloc.c +15 -1
@@ -1899,12 +1899,20 @@ void show_free_areas(void) } printk("Active_anon:%lu active_file:%lu inactive_anon%lu\n" - " inactive_file:%lu dirty:%lu writeback:%lu unstable:%lu\n" + " inactive_file:%lu" +//TODO: check/adjust line lengths +#ifdef CONFIG_NORECLAIM +" noreclaim:%lu" +#endif +" dirty:%lu writeback:%lu unstable:%lu\n" " free:%lu slab:%lu mapped:%lu pagetables:%lu bounce:%lu\n" ,global_page_state (NR_ACTIVE_ANON ),global_page_state (NR_ACTIVE_FILE ),global_page_state (NR_INACTIVE_ANON ),global_page_state (NR_INACTIVE_FILE ), +#ifdef CONFIG_NORECLAIM +global_page_state (NR_NORECLAIM ), +#endifglobal_page_state (NR_FILE_DIRTY ),global_page_state (NR_WRITEBACK ), global_page_state(NR_UNSTABLE_NFS),
@@ -1931,6 +1939,9 @@ void show_free_areas(void) " inactive_anon:%lukB" " active_file:%lukB" " inactive_file:%lukB" +#ifdef CONFIG_NORECLAIM + " noreclaim:%lukB" +#endif" present:%lukB" " pages_scanned:%lu" " all_unreclaimable? %s"
@@ -1944,6 +1955,9 @@ void show_free_areas(void)K (zone_page_state (zone,NR_INACTIVE_ANON )),K (zone_page_state (zone,NR_ACTIVE_FILE )),K (zone_page_state (zone,NR_INACTIVE_FILE )), +#ifdef CONFIG_NORECLAIM +K (zone_page_state (zone,NR_NORECLAIM )), +#endifK (zone->present_pages), zone->pages_scanned, (zone_is_all_unreclaimable (zone) ?"yes" :"no" )
mm/vmstat.c +3 -0
@@ -690,6 +690,9 @@ static const char * const vmstat_text[]"nr_active_anon" ,"nr_inactive_file" ,"nr_active_file" , +#ifdef CONFIG_NORECLAIM +"nr_noreclaim" , +#endif"nr_anon_pages" ,"nr_mapped" , "nr_file_pages",
drivers/base/node.c +6 -0
@@ -52,6 +52,9 @@ static ssize_t node_read_meminfo(struct "Node %d Inactive(anon): %8lu kB\n" "Node %d Active(file): %8lu kB\n" "Node %d Inactive(file): %8lu kB\n" +#ifdef CONFIG_NORECLAIM + "Node %d Noreclaim: %8lu kB\n" +#endif#ifdef CONFIG_HIGHMEM "Node %d HighTotal: %8lu kB\n" "Node %d HighFree: %8lu kB\n"
@@ -76,6 +79,9 @@ static ssize_t node_read_meminfo(struct nid,node_page_state (nid,NR_INACTIVE_ANON ), nid,node_page_state (nid,NR_ACTIVE_FILE ), nid,node_page_state (nid,NR_INACTIVE_FILE ), +#ifdef CONFIG_NORECLAIM + nid,node_page_state (nid,NR_NORECLAIM ), +#endif #ifdef CONFIG_HIGHMEM nid,K (i.totalhigh), nid, K(i.freehigh),
fs/proc/proc_misc.c +6 -0
@@ -162,6 +162,9 @@ static int meminfo_read_proc(char *page, "Inactive(anon): %8lu kB\n" "Active(file): %8lu kB\n" "Inactive(file): %8lu kB\n" +#ifdef CONFIG_NORECLAIM + "Noreclaim: %8lu kB\n" +#endif#ifdef CONFIG_HIGHMEM "HighTotal: %8lu kB\n" "HighFree: %8lu kB\n"
@@ -194,6 +197,9 @@ static int meminfo_read_proc(char *page,K (global_page_state (NR_INACTIVE_ANON )),K (global_page_state (NR_ACTIVE_FILE )),K (global_page_state (NR_INACTIVE_FILE )), +#ifdef CONFIG_NORECLAIM +K (global_page_state (NR_NORECLAIM )), +#endif #ifdef CONFIG_HIGHMEMK (i.totalhigh), K(i.freehigh),
Signature · 7 lines
All Rights Reversed -- 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 14/21 scan noreclaim list for reclaimable pages
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU series
New in V2
This patch adds a function to scan individual or all zones' noreclaim lists and move any pages that have become reclaimable onto the respective zone's inactive list, where shrink_inactive_list() will deal with them.
This replaces the function to splice the entire noreclaim list onto the active list for rescan by shrink_active_list(). That method had problems with vmstat accounting and complicated '[__]isolate_lru_pages()'. Now, __isolate_lru_page() will never isolate a non-reclaimable page. The only time it should see one is when scanning nearby pages for lumpy reclaim.
TODO: This approach may still need some refinement.
E.g., put back to active list?
DEBUGGING ONLY: NOT FOR UPSTREAM MERGE
include/linux/swap.h +15 -0
@@ -7,6 +7,7 @@#include <linux/list.h> #include <linux/memcontrol.h> #include <linux/sched.h> +#include <linux/node.h> #include <asm/atomic.h> #include <asm/page.h>
@@ -244,12 +245,26 @@ static inline int zone_reclaim(struct zo#ifdef CONFIG_NORECLAIM extern int page_reclaimable (struct page *page,struct vm_area_struct *vma); +extern void scan_zone_noreclaim_pages (struct zone *); +extern void scan_all_zones_noreclaim_pages (void ); +extern unsigned long scan_noreclaim_pages; +extern int scan_noreclaim_handler (struct ctl_table *,int ,struct file *, +void __user *,size_t *,loff_t *); +extern int scan_noreclaim_register_node (struct node *node); +extern void scan_noreclaim_unregister_node (struct node *node);#else static inline int page_reclaimable (struct page *page,struct vm_area_struct *vma) {return 1 ; } +static inline void scan_zone_noreclaim_pages (struct zone *z) { } +static inline void scan_all_zones_noreclaim_pages (void ) { } +static inline int scan_noreclaim_register_node (struct node *node) +{ +return 0 ; +} +static inline void scan_noreclaim_unregister_node (struct node *node) { }#endif extern int kswapd_run (int nid);
mm/vmscan.c +141 -0
151 lines not on this page · raw message
kernel/sysctl.c +10 -0
@@ -1165,6 +1165,16 @@ static struct ctl_table vm_table[] = { .extra2 = &one, },#endif +#ifdef CONFIG_NORECLAIM + { + .ctl_name = CTL_UNNUMBERED, + .procname = "scan_noreclaim_pages", + .data = &scan_noreclaim_pages, + .maxlen = sizeof(scan_noreclaim_pages), + .mode = 0644, + .proc_handler = &scan_noreclaim_handler, + }, +#endif /* * NOTE: do not add new entries to this table unless you have read * Documentation/sysctl/ctl_unnumbered.txt
drivers/base/node.c +5 -0
@@ -13,6 +13,7 @@#include <linux/nodemask.h> #include <linux/cpu.h> #include <linux/device.h> +#include <linux/swap.h> static struct sysdev_class node_class = { .name ="node" ,
@@ -162,6 +163,8 @@ int register_node(struct node *node, intsysdev_create_file (&node->sysdev, &attr_meminfo);sysdev_create_file (&node->sysdev, &attr_numastat);sysdev_create_file (&node->sysdev, &attr_distance); + +scan_noreclaim_register_node (node); }return error; }
@@ -180,6 +183,8 @@ void unregister_node(struct node *node)sysdev_remove_file (&node->sysdev, &attr_numastat);sysdev_remove_file (&node->sysdev, &attr_distance); +scan_noreclaim_unregister_node (node); +sysdev_unregister (&node->sysdev); }
Signature · 7 lines
All Rights Reversed -- 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 14/21] scan noreclaim list for reclaimable pages
Quoted 16 lines · On Thu, 28 Feb 2008 14:29:22 -0500 Rik van Riel wrote:
V2 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU seriesNew in V2
This patch adds a function to scan individual or all zones' noreclaim lists and move any pages that have become reclaimable onto the respective zone's inactive list, where
shrink_inactive_list()will deal with them.This replaces the function to splice the entire noreclaim list onto the active list for rescan by
shrink_active_list(). That method had problems with vmstat accounting and complicated '[__]isolate_lru_pages()'. Now,__isolate_lru_page()will never isolate a non-reclaimable page. The only time it should see one is when scanning nearby pages for lumpy reclaim.
Quoted 7 lines
TODO: This approach may still need some refinement.
E.g., put back to active list?DEBUGGING ONLY: NOT FOR UPSTREAM MERGE
Signed-off-by Lee Schermerhorn <[email protected]>Signed-off-by Rik van Riel <[email protected]>
Hi,
I haven't looked at all 21 patches, but please use kernel-doc notation as it's defined. See Documentation/kernel-doc-nano-HOWTO.txt for details, or ask.
mm/vmscan.c int page_reclaimable(struct page *page, · line 2302
Quoted 12 lines
Index:
linux-2.6.25-rc2-mm1/mm/vmscan.c
===================================================================mm/vmscan.c +4
-0@@ -2295,4 +2296,144 @@ int page_reclaimable(struct page *page,return 1 ; } + +/** +* scan_zone_noreclaim_pages(@zone) +* @zone - zone to scan
E.g.:
* scan_zone_reclaim_pages - some short description here
* @zone: zone to scan
mm/vmscan.c int page_reclaimable(struct page *page, · line 2310
Quoted 8 lines
mm/vmscan.c +8
-0+* +* Scan @zone's noreclaim LRU lists to check for pages that have become +* reclaimable. Move those that have to @zone's inactive list where they +* become candidates for reclaim, unless shrink_inactive_zone() decides +* to reactivate them. Pages that are still non-reclaimable are rotated +* back onto @zone's noreclaim list. +*/ +#define SCAN_NORECLAIM_BATCH_SIZE 16UL/* arbitrary lock hold batch size */
and don't insert macros between the kernel-doc section and the function definition, please.
Quoted 2 lines
mm/vmscan.c +2
-0+void scan_zone_noreclaim_pages (struct zone *zone) +{
...
Quoted 1 line
+}
---
~Randy
--
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 14/21] scan noreclaim list for reclaimable pages
Quoted 27 lines · Randy Dunlap
Quoted 16 lines · On Thu, 28 Feb 2008 14:29:22 -0500 Rik van Riel wrote:
V2 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU seriesNew in V2
This patch adds a function to scan individual or all zones' noreclaim lists and move any pages that have become reclaimable onto the respective zone's inactive list, where
shrink_inactive_list()will deal with them.This replaces the function to splice the entire noreclaim list onto the active list for rescan by
shrink_active_list(). That method had problems with vmstat accounting and complicated '[__]isolate_lru_pages()'. Now,__isolate_lru_page()will never isolate a non-reclaimable page. The only time it should see one is when scanning nearby pages for lumpy reclaim.Quoted 7 lines
TODO: This approach may still need some refinement.
E.g., put back to active list?DEBUGGING ONLY: NOT FOR UPSTREAM MERGE
Signed-off-by Lee Schermerhorn <[email protected]>Signed-off-by Rik van Riel <[email protected]>
Quoted 5 lines
Hi,
I haven't looked at all 21 patches, but please use kernel-doc notation as it's defined. See
Documentation/kernel-doc-nano-HOWTO.txtfor details, or ask.
Hi, Randy:
I'll make a pass thru the noreclaim patches and fix up the comment blocks that are not quite kernel-doc. I have to update some of the patch descriptions as well, as some have become stale thanks to additional work by Kosaki-san [e.g., the page vec cleanup].
I'll discuss with Rik, off-list, how to coordinate for the next reposting.
Thanks,
Lee
--
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 15/21 ramfs pages are non-reclaimable
In reply to Rik van RielV3 -> V4:
+ drivers/block/rd.c was replaced by brd.c in 24-rc4-mm1. Update patch to add brd_open() to mark mapping as nonreclaimable
V2 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU series [no changes]
V1 -> V2:
+ add ramfs pages to this class of non-reclaimable pages by marking ramfs address_space [mapping] as non-reclaimble.
Christoph Lameter pointed out that ram disk pages also clutter the LRU lists. When vmscan finds them dirty and tries to clean them, the ram disk writeback function just redirties the page so that it goes back onto the active list. Round and round she goes...
Define new address_space flag [shares address_space flags member with mapping's gfp mask] to indicate that the address space contains all non-reclaimable pages. This will provide for efficient testing of ramdisk pages in page_reclaimable().
Also provide wrapper functions to set/test the noreclaim state to minimize #ifdefs in ramdisk driver and any other users of this facility.
Set the noreclaim state on address_space structures for new ramdisk inodes. Test the noreclaim state in page_reclaimable() to cull non-reclaimable pages.
Similarly, ramfs pages are non-reclaimable. Set the 'noreclaim' address_space flag for new ramfs inodes.
These changes depend on [CONFIG_]NORECLAIM.
include/linux/pagemap.h +22 -0
@@ -30,6 +30,28 @@ static inline void mapping_set_error(str } } +#ifdef CONFIG_NORECLAIM +#define AS_NORECLAIM (__GFP_BITS_SHIFT + 2)/* e.g., ramdisk, SHM_LOCK */ + +static inline void mapping_set_noreclaim (struct address_space *mapping) +{ +set_bit (AS_NORECLAIM , &mapping->flags); +} + +static inline int mapping_non_reclaimable (struct address_space *mapping) +{ +if (mapping && (mapping->flags &AS_NORECLAIM )) +return 1 ; +return 0 ; +} +#else +static inline void mapping_set_noreclaim (struct address_space *mapping) { } +static inline int mapping_non_reclaimable (struct address_space *mapping) +{ +return 0 ; +} +#endif +static inline gfp_t mapping_gfp_mask (struct address_space * mapping) {return (__force gfp_t )mapping->flags & __GFP_BITS_MASK;
mm/vmscan.c +4 -0
@@ -2283,6 +2283,7 @@ int zone_reclaim(struct zone *zone, gfp_* If !NULL, called from fault path. * * Reasons page might not be reclaimable: +* + page's mapping marked non-reclaimable * TODO - later patches * * TODO: specify locking assumptions
@@ -2292,6 +2293,9 @@ int page_reclaimable(struct page *page,VM_BUG_ON (PageNoreclaim (page)); +if (mapping_non_reclaimable (page_mapping (page))) +return 0 ; +/* TODO: test page [!]reclaimable conditions */ return 1 ;
fs/ramfs/inode.c +1 -0
@@ -61,6 +61,7 @@ struct inode *ramfs_get_inode(struct sup inode->i_mapping->a_ops = &ramfs_aops; inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;mapping_set_gfp_mask (inode->i_mapping,GFP_HIGHUSER ); +mapping_set_noreclaim (inode->i_mapping); inode->i_atime = inode->i_mtime = inode->i_ctime =CURRENT_TIME ;switch (mode &S_IFMT ) {default :
drivers/block/brd.c +13 -0
@@ -373,8 +373,21 @@ static int brd_ioctl(struct inode *inodereturn error; } +/* +* brd_open(): +* Just mark the mapping as containing non-reclaimable pages +*/ +static int brd_open (struct inode *inode,struct file *filp) +{ +struct address_space *mapping = inode->i_mapping; + +mapping_set_noreclaim (mapping); +return 0 ; +} +static struct block_device_operations brd_fops = { .owner =THIS_MODULE , + .open = brd_open, .ioctl = brd_ioctl, #ifdef CONFIG_BLK_DEV_XIP .direct_access = brd_direct_access,
Signature · 7 lines
All Rights Reversed -- 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 16/21 SHM_LOCKED pages are nonreclaimable
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU series.
+ Use scan_mapping_noreclaim_page() on unlock. See below.
V1 -> V2:
+ modify to use reworked 'scan_all_zones_noreclaim_pages()' See 'TODO' below - still pending.
While working with Nick Piggin's mlock patches, I noticed that shmem segments locked via shmctl(SHM_LOCKED) were not being handled. SHM_LOCKed pages work like ramdisk pages--the writeback function just redirties the page so that it can't be reclaimed. Deal with these using the same approach as for ram disk pages.
Use the AS_NORECLAIM flag to mark address_space of SHM_LOCKed shared memory regions as non-reclaimable. Then these pages will be culled off the normal LRU lists during vmscan.
Add new wrapper function to clear the mapping's noreclaim state when/if shared memory segment is munlocked.
Add 'scan_mapping_noreclaim_page()' to mm/vmscan.c to scan all pages in the shmem segment's mapping [struct address_space] for reclaimability now that they're no longer locked. If so, move them to the appropriate zone lru list.
Changes depend on [CONFIG_]NORECLAIM.
mm/shmem.c +3 -0
@@ -1525,10 +1525,13 @@ int shmem_lock(struct file *file, int loif (!user_shm_lock (inode->i_size, user)) goto out_nomem; info->flags |=VM_LOCKED ; +mapping_set_noreclaim (file->f_mapping); }if (!lock && (info->flags &VM_LOCKED ) && user) {user_shm_unlock (inode->i_size, user); info->flags &= ~VM_LOCKED ; +mapping_clear_noreclaim (file->f_mapping); +scan_mapping_noreclaim_pages (file->f_mapping); } retval =0 ; out_nomem:
include/linux/pagemap.h +8 -2
@@ -38,14 +38,20 @@ static inline void mapping_set_noreclaim set_bit(AS_NORECLAIM, &mapping->flags); } +static inline void mapping_clear_noreclaim (struct address_space *mapping) +{ +clear_bit (AS_NORECLAIM , &mapping->flags); +} +static inline int mapping_non_reclaimable (struct address_space *mapping) { -if (mapping && (mapping->flags &AS_NORECLAIM )) -return 1 ; +if (mapping) +return test_bit (AS_NORECLAIM , &mapping->flags);return 0 ; }#else static inline void mapping_set_noreclaim (struct address_space *mapping) { } +static inline void mapping_clear_noreclaim (struct address_space *mapping) { }static inline int mapping_non_reclaimable (struct address_space *mapping) {return 0 ;
mm/vmscan.c +84 -17
130 lines not on this page · raw message
include/linux/swap.h +4 -0
@@ -247,6 +247,7 @@ static inline int zone_reclaim(struct zoextern int page_reclaimable (struct page *page,struct vm_area_struct *vma);extern void scan_zone_noreclaim_pages (struct zone *);extern void scan_all_zones_noreclaim_pages (void ); +extern void scan_mapping_noreclaim_pages (struct address_space *);extern unsigned long scan_noreclaim_pages;extern int scan_noreclaim_handler (struct ctl_table *,int ,struct file *,void __user *,size_t *,loff_t *);
@@ -260,6 +261,9 @@ static inline int page_reclaimable(struc }static inline void scan_zone_noreclaim_pages (struct zone *z) { }static inline void scan_all_zones_noreclaim_pages (void ) { } +static inline void scan_mapping_noreclaim_pages (struct address_space *mapping) +{ +}static inline int scan_noreclaim_register_node (struct node *node) {return 0 ;
Signature · 7 lines
All Rights Reversed -- 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 17/21 non-reclaimable mlocked pages
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split lru series
+ fix page flags macros for *PageMlocked() when not configured.
+ ensure lru_add_drain_all() runs on all cpus when NORECLIM_MLOCK configured. Was just for NUMA.
V1 -> V2:
+ moved this patch [and related patches] up to right after ramdisk/ramfs and SHM_LOCKed patches.
+ add [back] missing put_page() in putback_lru_page(). This solved page leakage as seen by stats in previous version.
+ fix up munlock_vma_page() to isolate page from lru before calling try_to_unlock(). Think I detected a race here.
+ use TestClearPageMlock() on old page in migrate.c's migrate_page_copy() to clean up old page.
+ live dangerously: remove TestSetPageLocked() in is_mlocked_vma()--should only be called on new pages in the fault path--iff we chose to cull there [later patch].
+ Add PG_mlocked to free_pages_check() etc to detect mlock state mismanagement.
NOTE: temporarily [???] commented out--tripping over it under load. Why?
Rework of a patch by Nick Piggin -- part 1 of 2.
This patch:
1) defines the [CONFIG_]NORECLAIM_MLOCK sub-option and the stub version of the mlock/noreclaim APIs when it's not configured. Depends on [CONFIG_]NORECLAIM.
2) add yet another page flag--PG_mlocked--to indicate that the page is locked for efficient testing in vmscan and, optionally, fault path. This allows early culling of nonreclaimable pages, preventing them from getting to page_referenced()/try_to_unmap(). Also allows separate accounting of mlock'd pages, as Nick's original patch did.
Uses a bit available only to 64-bit systems.
Note: Nick's original mlock patch used a PG_mlocked flag. I had removed this in favor of the PG_noreclaim flag + an mlock_count [new page struct member]. I restored the PG_mlocked flag to eliminate the new count field.
3) add the mlock/noreclaim infrastructure to mm/mlock.c, with internal APIs in mm/internal.h. This is a rework of Nick's original patch to these files, taking into account that mlocked pages are now kept on noreclaim LRU list.
4) update vmscan.c:page_reclaimable() to check PageMlocked() and, if vma passed in, the vm_flags. Note that the vma will only be passed in for new pages in the fault path; and then only if the "cull nonreclaimable pages in fault path" patch is included.
5) add try_to_unlock() to rmap.c to walk a page's rmap and ClearPageMlocked() if no other vmas have it mlocked. Reuses as much of try_to_unmap() as possible. This effectively replaces the use of one of the lru list links as an mlock count. If this mechanism let's pages in mlocked vmas leak through w/o PG_mlocked set [I don't know that it does], we should catch them later in try_to_unmap(). One hopes this will be rare, as it will be relatively expensive.
mm/internal.h and mm/mlock.c changes:
Originally Signed-off-by: Nick Piggin <[email protected]>
mm/Kconfig +14 -0
@@ -203,3 +203,17 @@ config NORECLAIM may be non-reclaimable because: they are locked into memory, they are anonymous pages for which no swap space exists, or they are anon pages that are expensive to unmap [long anon_vma "related vma" list.] + +config NORECLAIM_MLOCK + bool "Exclude mlock'ed pages from reclaim" + depends on NORECLAIM + help + Treats mlock'ed pages as no-reclaimable. Removing these pages from + the LRU [in]active lists avoids the overhead of attempting to reclaim + them. Pages marked non-reclaimable for this reason will become + reclaimable again when the last mlock is removed. + when no swap space exists. Removing these pages from the LRU lists + avoids the overhead of attempting to reclaim them. Pages marked + non-reclaimable for this reason will become reclaimable again when/if + sufficient swap space is added to the system. +
mm/internal.h +58 -0
64 lines not on this page · raw message
mm/mlock.c +210 -13
263 lines not on this page · raw message
mm/vmscan.c +46 -2
68 lines not on this page · raw message
include/linux/page-flags.h +21 -2
@@ -109,6 +109,7 @@#define PG_uncached 31/* Page has been mapped as uncached */ #define PG_noreclaim 30/* Page is "non-reclaimable" */ +#define PG_mlocked 29/* Page is vma mlocked */ #endif /*
@@ -198,6 +199,7 @@ static inline void SetPageUptodate(struc#define SetPageActive (page) set_bit(PG_active, &(page)->flags)#define ClearPageActive (page) clear_bit(PG_active, &(page)->flags)#define __ClearPageActive (page) __clear_bit(PG_active, &(page)->flags) +#define TestSetPageActive (page) test_and_set_bit(PG_active, &(page)->flags)#define TestClearPageActive (page) test_and_clear_bit(PG_active, &(page)->flags)#define PageSlab (page) test_bit(PG_slab, &(page)->flags)
@@ -305,8 +307,17 @@ static inline void __ClearPageTail(struc#define SetPageNoreclaim (page) set_bit(PG_noreclaim, &(page)->flags)#define ClearPageNoreclaim (page) clear_bit(PG_noreclaim, &(page)->flags)#define __ClearPageNoreclaim (page) __clear_bit(PG_noreclaim, &(page)->flags) -#define TestClearPageNoreclaim (page) test_and_clear_bit(PG_noreclaim, \ - &(page)->flags) +#define TestClearPageNoreclaim (page) \ + test_and_clear_bit(PG_noreclaim, &(page)->flags) +#ifdef CONFIG_NORECLAIM_MLOCK +#define PageMlocked (page) test_bit(PG_mlocked, &(page)->flags) +#define SetPageMlocked (page) set_bit(PG_mlocked, &(page)->flags) +#define ClearPageMlocked (page) clear_bit(PG_mlocked, &(page)->flags) +#define __ClearPageMlocked (page) __clear_bit(PG_mlocked, &(page)->flags) +#define TestSetPageMlocked (page) test_and_set_bit(PG_mlocked, &(page)->flags) +#define TestClearPageMlocked (page) \ + test_and_clear_bit(PG_mlocked, &(page)->flags) +#endif #else #define PageNoreclaim (page) 0#define SetPageNoreclaim (page)
@@ -314,6 +325,14 @@ static inline void __ClearPageTail(struc#define __ClearPageNoreclaim (page)#define TestClearPageNoreclaim (page) 0#endif +#ifndef CONFIG_NORECLAIM_MLOCK +#define PageMlocked (page) 0 +#define SetPageMlocked (page) +#define ClearPageMlocked (page) +#define __ClearPageMlocked (page) +#define TestSetPageMlocked (page) 0 +#define TestClearPageMlocked (page) 0 +#endif #define PageUncached (page) test_bit(PG_uncached, &(page)->flags)#define SetPageUncached (page) set_bit(PG_uncached, &(page)->flags)
include/linux/rmap.h +12 -0
@@ -109,6 +109,17 @@ unsigned long page_address_in_vma(struct*/ int page_mkclean (struct page *); +#ifdef CONFIG_NORECLAIM_MLOCK +/* +* called in munlock()/munmap() path to check for other vmas holding +* the page mlocked. +*/ +int try_to_unlock (struct page *); +#define TRY_TO_UNLOCK 1 +#else +#define TRY_TO_UNLOCK 0/* for compiler -- dead code elimination */ +#endif +#else /* !CONFIG_MMU */ #define anon_vma_init () do {} while (0)
@@ -132,5 +143,6 @@ static inline int page_mkclean(struct pa#define SWAP_SUCCESS 0#define SWAP_AGAIN 1#define SWAP_FAIL 2 +#define SWAP_MLOCK 3#endif /* _LINUX_RMAP_H */
mm/rmap.c +135 -25
270 lines not on this page · raw message
mm/migrate.c +3 -0
@@ -341,6 +341,9 @@ static void migrate_page_copy(struct pagset_page_dirty (newpage); } +if (TestClearPageMlocked (page)) +SetPageMlocked (newpage); +#ifdef CONFIG_SWAP ClearPageSwapCache (page);#endif
mm/page_alloc.c +9 -1
@@ -257,6 +257,7 @@ static void bad_page(struct page *page)1 << PG_swapcache |1 << PG_writeback |1 << PG_swapbacked | +1 << PG_mlocked | 1 << PG_buddy );set_page_count (page,0 );reset_page_mapcount (page);
@@ -488,6 +489,9 @@ static inline int free_pages_check(struc#ifdef CONFIG_NORECLAIM 1 << PG_noreclaim |#endif +// TODO: always trip this under heavy workloads. +// Why isn't this being cleared on last unmap/unlock? +// 1 << PG_mlocked | 1 << PG_buddy ))))bad_page (page);if (PageDirty (page))
@@ -644,6 +648,8 @@ static int prep_new_page(struct page *pa 1 << PG_writeback | 1 << PG_reserved | 1 << PG_swapbacked | +//TODO: why hitting this? +// 1 << PG_mlocked | 1 << PG_buddy ))))bad_page (page);
@@ -656,7 +662,9 @@ static int prep_new_page(struct page *pa page->flags &= ~(1 << PG_uptodate |1 << PG_error |1 << PG_readahead |1 << PG_referenced |1 << PG_arch_1 | -1 << PG_owner_priv_1 |1 << PG_mappedtodisk); +1 << PG_owner_priv_1 |1 << PG_mappedtodisk | +//TODO take care of it here, for now. +1 << PG_mlocked );set_page_private (page,0 );set_page_refcounted (page);
mm/swap.c +1 -1
@@ -308,7 +308,7 @@ void lru_add_drain(void)put_cpu (); } -#ifdef CONFIG_NUMA +#if defined(CONFIG_NUMA ) || defined(CONFIG_NORECLAIM_MLOCK )static void lru_add_drain_per_cpu (struct work_struct *dummy) {lru_add_drain ();
Signature · 7 lines
All Rights Reversed -- 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>
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [patch 17/21] non-reclaimable mlocked pages
Quoted 33 lines · minchan Kim
Index: linux-2.6.25-rc2-mm1/mm/page_alloc.c =================================================================== --- linux-2.6.25-rc2-mm1.orig/mm/page_alloc.c 2008-02-28 12:47:36.000000000 -0500 +++ linux-2.6.25-rc2-mm1/mm/page_alloc.c 2008-02-28 12:49:02.000000000 -0500 @@ -257,6 +257,7 @@ static void bad_page(struct page *page) 1 << PG_swapcache | 1 << PG_writeback | 1 << PG_swapbacked | + 1 << PG_mlocked | 1 << PG_buddy ); set_page_count(page, 0); reset_page_mapcount(page);It would be compile error unless
CONFIG_NORECLAIM_MLOCKis defined.@@ -656,7 +662,9 @@ static int prep_new_page(struct page *pa page->flags &= ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_readahead | 1 << PG_referenced | 1 << PG_arch_1 | - 1 << PG_owner_priv_1 | 1 << PG_mappedtodisk); + 1 << PG_owner_priv_1 | 1 << PG_mappedtodisk | +//TODO take care of it here, for now. + 1 << PG_mlocked ); set_page_private(page, 0); set_page_refcounted(page);
Quoted 1 line
ditto
Well, it will be a compile error for 32-bit systems, so we need to fix
it. PG_mlocked is unconditionally defined/reserved when (BITS_PER_LONG
Quoted 1 line
32).
Thanks,
Lee
Quoted 1 line
--
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 18/21 mlock vma pages under mmap_sem held for read
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split lru series [no change]
+ fix function return types [void -> int] to fix build when not configured.
New in V2.
We need to hold the mmap_sem for write to initiatate mlock()/munlock() because we may need to merge/split vmas. However, this can lead to very long lock hold times attempting to fault in a large memory region
to mlock it into memory. This can hold off other faults against the
mm [multithreaded tasks] and other scans of the mm, such as via /proc. To alleviate this, downgrade the mmap_sem to read mode during the population of the region for locking. This is especially the case if we need to reclaim memory to lock down the region. We [probably?] don't need to do this for unlocking as all of the pages should be resident--they're already mlocked.
Now, the caller's of the mlock functions [mlock_fixup() and mlock_vma_pages_range()] expect the mmap_sem to be returned in write mode. Changing all callers appears to be way too much effort at this point. So, restore write mode before returning. Note that this opens a window where the mmap list could change in a multithreaded process. So, at least for mlock_fixup(), where we could be called in a loop over multiple vmas, we check that a vma still exists at the start address and that vma still covers the page range [start,end). If not, we return an error, -EAGAIN, and let the caller deal with it.
Return -EAGAIN from mlock_vma_pages_range() function and mlock_fixup() if the vma at 'start' disappears or changes so that the page range [start,end) is no longer contained in the vma. Again, let the caller deal with it. Looks like only sys_remap_file_pages() [via mmap_region()] should actually care.
With this patch, I no longer see processes like ps(1) blocked for seconds or minutes at a time waiting for a large [multiple gigabyte] region to be locked down.
mm/mlock.c +56 -1
@@ -200,6 +200,37 @@ int __mlock_vma_pages_range(struct vm_ar return ret; } +/** +* mlock_vma_pages_range +* @vma - vm area to mlock into memory +* @start - start address in @vma of range to mlock, +* @end - end address in @vma of range +* +* Called with current->mm->mmap_sem held write locked. Downgrade to read +* for faulting in pages. This can take a looong time for large segments. +* +* We need to restore the mmap_sem to write locked because our callers' +* callers expect this. However, because the mmap could have changed +* [in a multi-threaded process], we need to recheck. +*/ +int mlock_vma_pages_range (struct vm_area_struct *vma, +unsigned long start,unsigned long end) +{ +struct mm_struct *mm = vma->vm_mm; + +downgrade_write (&mm->mmap_sem); +__mlock_vma_pages_range (vma, start, end,1 ); + +up_read (&mm->mmap_sem); +/* vma can change or disappear */ +down_write (&mm->mmap_sem); + vma =find_vma (mm, start); +/* non-NULL vma must contain @start, but need to check @end */ +if (!vma || end > vma->vm_end) +return -EAGAIN ; +return 0 ; +} +#else /* CONFIG_NORECLAIM_MLOCK */ /*
@@ -266,14 +297,38 @@ success: mm->locked_vm += nr_pages;/* -* vm_flags is protected by the mmap_sem held in write mode. +* vm_flags is protected by the mmap_sem held for write. * It's okay if try_to_unmap_one unmaps a page just after we * set VM_LOCKED, __mlock_vma_pages_range will bring it back. */ vma->vm_flags = newflags; +/* +* mmap_sem is currently held for write. If we're locking pages, +* downgrade the write lock to a read lock so that other faults, +* mmap scans, ... while we fault in all pages. +*/ +if (lock) +downgrade_write (&mm->mmap_sem); +__mlock_vma_pages_range (vma, start, end, lock); +if (lock) { +/* +* Need to reacquire mmap sem in write mode, as our callers +* expect this. We have no support for atomically upgrading +* a sem to write, so we need to check for changes while sem +* is unlocked. +*/ +up_read (&mm->mmap_sem); +/* vma can change or disappear */ +down_write (&mm->mmap_sem); + *prev =find_vma (mm, start); +/* non-NULL *prev must contain @start, but need to check @end */ +if (!(*prev) || end > (*prev)->vm_end) + ret = -EAGAIN ; + } + out:if (ret == -ENOMEM ) ret = -EAGAIN ;
mm/internal.h +8 -11
@@ -61,24 +61,21 @@ extern int __mlock_vma_pages_range(struc/* * mlock all pages in this vma range. For mmap()/mremap()/... */ -static inline void mlock_vma_pages_range (struct vm_area_struct *vma, -unsigned long start,unsigned long end) -{ -__mlock_vma_pages_range (vma, start, end,1 ); -} +extern int mlock_vma_pages_range (struct vm_area_struct *vma, +unsigned long start,unsigned long end);/* * munlock range of pages. For munmap() and exit(). * Always called to operate on a full vma that is being unmapped. */ -static inline void munlock_vma_pages_range (struct vm_area_struct *vma, +static inline int munlock_vma_pages_range (struct vm_area_struct *vma,unsigned long start,unsigned long end) {// TODO: verify my assumption. Should we just drop the start/end args? VM_BUG_ON (start != vma->vm_start || end != vma->vm_end); vma->vm_flags &= ~VM_LOCKED ;/* try_to_unlock() needs this */ -__mlock_vma_pages_range (vma, start, end,0 ); +return __mlock_vma_pages_range (vma, start, end,0 ); }extern void clear_page_mlock (struct page *page);
@@ -90,10 +87,10 @@ static inline int is_mlocked_vma(struct }static inline void clear_page_mlock (struct page *page) { }static inline void mlock_vma_page (struct page *page) { } -static inline void mlock_vma_pages_range (struct vm_area_struct *vma, -unsigned long start,unsigned long end) { } -static inline void munlock_vma_pages_range (struct vm_area_struct *vma, -unsigned long start,unsigned long end) { } +static inline int mlock_vma_pages_range (struct vm_area_struct *vma, +unsigned long start,unsigned long end) {return 0 ; } +static inline int munlock_vma_pages_range (struct vm_area_struct *vma, +unsigned long start,unsigned long end) {return 0 ; }#endif /* CONFIG_NORECLAIM_MLOCK */
Signature · 7 lines
All Rights Reversed -- 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 19/21 handle mlocked pages during map/unmap and truncate
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split lru series [no changes]
V1 -> V2:
+ modified mmap.c:mmap_region() to return error if mlock_vma_pages_range() does. This can only occur if the vma gets removed/changed while
we're switching mmap_sem lock modes. Most callers don't care, but
sys_remap_file_pages() appears to.
Rework of Nick Piggins's "mm: move mlocked pages off the LRU" patch -- part 2 0f 2.
Remove mlocked pages from the LRU using "NoReclaim infrastructure" during mmap()/mremap(). Try to move back to normal LRU lists on munmap() when last locked mapping removed. Removed PageMlocked() status when page truncated from file.
Originally Signed-off-by: Nick Piggin <[email protected]>
mm/mmap.c +37 -5
@@ -32,6 +32,8 @@#include <asm/tlb.h> #include <asm/mmu_context.h> +#include "internal.h" +#ifndef arch_mmap_check#define arch_mmap_check (addr, len, flags) (0)#endif
@@ -1208,9 +1210,13 @@ out:vm_stat_account (mm, vm_flags, file, len >>PAGE_SHIFT );if (vm_flags &VM_LOCKED ) { mm->locked_vm += len >>PAGE_SHIFT ; -make_pages_present (addr, addr + len); - } -if ((flags &MAP_POPULATE ) && !(flags &MAP_NONBLOCK )) +/* +* makes pages present; downgrades, drops, requires mmap_sem +*/ + error =mlock_vma_pages_range (vma, addr, addr + len); +if (error) +return error;/* vma gone! */ + }else if ((flags &MAP_POPULATE ) && !(flags &MAP_NONBLOCK ))make_pages_present (addr, addr + len);return addr;
@@ -1896,6 +1902,19 @@ int do_munmap(struct mm_struct *mm, unsi vma = prev? prev->vm_next: mm->mmap;/* +* unlock any mlock()ed ranges before detaching vmas +*/ +if (mm->locked_vm) { +struct vm_area_struct *tmp = vma; +while (tmp && tmp->vm_start < end) { +if (tmp->vm_flags &VM_LOCKED ) +munlock_vma_pages_range (tmp, + tmp->vm_start, tmp->vm_end); + tmp = tmp->vm_next; + } + } + +/* * Remove the vma's, and unmap the actual pages */ detach_vmas_to_be_unmapped (mm, vma, prev, end);
@@ -2031,7 +2050,7 @@ out: mm->total_vm += len >>PAGE_SHIFT ;if (flags &VM_LOCKED ) { mm->locked_vm += len >>PAGE_SHIFT ; -make_pages_present (addr, addr + len); +mlock_vma_pages_range (vma, addr, addr + len); }return addr; }
@@ -2042,13 +2061,26 @@ EXPORT_SYMBOL(do_brk);void exit_mmap (struct mm_struct *mm) {struct mmu_gather *tlb; -struct vm_area_struct *vma = mm->mmap; +struct vm_area_struct *vma;unsigned long nr_accounted =0 ;unsigned long end;/* mm's last user has gone, and its about to be pulled down */ arch_exit_mmap (mm); +if (mm->locked_vm) { + vma = mm->mmap; +while (vma) { +if (vma->vm_flags &VM_LOCKED ) +munlock_vma_pages_range (vma, + vma->vm_start, vma->vm_end); + vma = vma->vm_next; + } + } + + vma = mm->mmap; + +lru_add_drain ();flush_cache_mm (mm); tlb =tlb_gather_mmu (mm,1 );
mm/mremap.c +5 -3
@@ -23,6 +23,8 @@#include <asm/cacheflush.h> #include <asm/tlbflush.h> +#include "internal.h" +static pmd_t *get_old_pmd (struct mm_struct *mm,unsigned long addr) {pgd_t *pgd;
@@ -232,8 +234,8 @@ static unsigned long move_vma(struct vm_if (vm_flags &VM_LOCKED ) { mm->locked_vm += new_len >>PAGE_SHIFT ;if (new_len > old_len) -make_pages_present (new_addr + old_len, - new_addr + new_len); +mlock_vma_pages_range (vma, new_addr + old_len, + new_addr + new_len); }return new_addr;
@@ -373,7 +375,7 @@ unsigned long do_mremap(unsigned long advm_stat_account (mm, vma->vm_flags, vma->vm_file, pages);if (vma->vm_flags &VM_LOCKED ) { mm->locked_vm += pages; -make_pages_present (addr + old_len, +mlock_vma_pages_range (vma, addr + old_len, addr + new_len); } ret = addr;
mm/vmscan.c +4 -0
@@ -540,6 +540,10 @@ static unsigned long shrink_page_list(st goto activate_locked;case SWAP_AGAIN : goto keep_locked; +case SWAP_MLOCK : +ClearPageActive (page); +SetPageNoreclaim (page); + goto keep_locked;/* to noreclaim list */ case SWAP_SUCCESS : ;/* try to free the page below */ }
mm/filemap.c +9 -1
@@ -2521,8 +2521,16 @@ generic_file_direct_IO(int rw, struct kiif (rw ==WRITE ) { write_len =iov_length (iov, nr_segs); end = (offset + write_len -1 ) >>PAGE_CACHE_SHIFT ; -if (mapping_mapped (mapping)) +if (mapping_mapped (mapping)) { +/* +* Calling unmap_mapping_range like this is wrong, +* because it can lead to mlocked pages being +* discarded (this is true even before the Noreclaim +* mlock work). direct-IO vs pagecache is a load of +* junk anyway, so who cares. +*/ unmap_mapping_range (mapping, offset, write_len,0 ); + } } retval =filemap_write_and_wait (mapping);
mm/truncate.c +4 -0
@@ -18,6 +18,7 @@#include <linux/task_io_accounting_ops.h> #include <linux/buffer_head.h> /* grr. try_to_release_page, do_invalidatepage */ +#include "internal.h" /**
@@ -104,6 +105,7 @@ truncate_complete_page(struct address_spcancel_dirty_page (page,PAGE_CACHE_SIZE );remove_from_page_cache (page); +clear_page_mlock (page);ClearPageUptodate (page);ClearPageMappedToDisk (page);page_cache_release (page);/* pagecache ref */
@@ -128,6 +130,7 @@ invalidate_complete_page(struct address_if (PagePrivate (page) && !try_to_release_page (page,0 ))return 0 ; +clear_page_mlock (page); ret =remove_mapping (mapping, page);return ret;
@@ -354,6 +357,7 @@ invalidate_complete_page2(struct addressif (PageDirty (page)) goto failed; +clear_page_mlock (page);BUG_ON (PagePrivate (page));__remove_from_page_cache (page);write_unlock_irq (&mapping->tree_lock);
Signature · 7 lines
All Rights Reversed -- 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 20/21 account mlocked pages
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split lru series
+ fix definitions of NR_MLOCK to fix build errors when not configured.
V1 -> V2:
+ new in V2 -- pulled in & reworked from Nick's previous series
From: Nick Piggin <[email protected]>
To: Linux Memory Management <[email protected]>
Cc: Nick Piggin <[email protected]>, Andrew Morton <[email protected]>
Subject: [patch 4/4] mm: account mlocked pages
Date: Mon, 12 Mar 2007 07:39:14 +0100 (CET)
Add NR_MLOCK zone page state, which provides a (conservative) count of mlocked pages (actually, the number of mlocked pages moved off the LRU).
Reworked by lts to fit in with the modified mlock page support in the Reclaim Scalability series. I don't know whether we'll want to keep these stats in the long run, but during testing of this series, I find them useful.
drivers/base/node.c +6 -0
@@ -55,6 +55,9 @@ static ssize_t node_read_meminfo(struct "Node %d Inactive(file): %8lu kB\n" #ifdef CONFIG_NORECLAIM "Node %d Noreclaim: %8lu kB\n" +#ifdef CONFIG_NORECLAIM_MLOCK + "Node %d Mlocked: %8lu kB\n" +#endif #endif#ifdef CONFIG_HIGHMEM "Node %d HighTotal: %8lu kB\n"
@@ -82,6 +85,9 @@ static ssize_t node_read_meminfo(struct nid, node_page_state(nid, NR_INACTIVE_FILE),#ifdef CONFIG_NORECLAIM nid, node_page_state(nid, NR_NORECLAIM), +#ifdef CONFIG_NORECLAIM_MLOCK + nid, K(node_page_state(nid, NR_MLOCK)), +#endif #endif #ifdef CONFIG_HIGHMEM nid, K(i.totalhigh),
fs/proc/proc_misc.c +6 -0
@@ -164,6 +164,9 @@ static int meminfo_read_proc(char *page, "Inactive(file): %8lu kB\n" #ifdef CONFIG_NORECLAIM "Noreclaim: %8lu kB\n" +#ifdef CONFIG_NORECLAIM_MLOCK + "Mlocked: %8lu kB\n" +#endif #endif#ifdef CONFIG_HIGHMEM "HighTotal: %8lu kB\n"
@@ -199,6 +202,9 @@ static int meminfo_read_proc(char *page, K(global_page_state(NR_INACTIVE_FILE)),#ifdef CONFIG_NORECLAIM K(global_page_state(NR_NORECLAIM)), +#ifdef CONFIG_NORECLAIM_MLOCK + K(global_page_state(NR_MLOCK)), +#endif #endif #ifdef CONFIG_HIGHMEM K(i.totalhigh),
include/linux/mmzone.h +6 -1
@@ -87,7 +87,12 @@ enum zone_stat_item {#ifdef CONFIG_NORECLAIM NR_NORECLAIM, /* " " " " " */ #else -NR_NORECLAIM =NR_ACTIVE_FILE ,/* avoid compiler errors in dead code */ + NR_NORECLAIM=NR_ACTIVE_FILE, /* avoid compiler errors in dead code */ +#endif +#ifdef CONFIG_NORECLAIM_MLOCK +NR_MLOCK ,/* mlock()ed pages found and moved off LRU */ +#else +NR_MLOCK =NR_ACTIVE_FILE ,/* avoid compiler errors... */ #endifNR_ANON_PAGES ,/* Mapped anonymous pages */ NR_FILE_MAPPED, /* pagecache pages mapped into pagetables.
mm/mlock.c +27 -11
@@ -60,11 +60,11 @@ void clear_page_mlock(struct page *page) {BUG_ON (!PageLocked (page)); -if (likely (!PageMlocked (page))) -return ; -ClearPageMlocked (page); -if (!isolate_lru_page (page)) -putback_lru_page (page); +if (unlikely (TestClearPageMlocked (page))) { +dec_zone_page_state (page,NR_MLOCK ); +if (!isolate_lru_page (page)) +putback_lru_page (page); + } }/*
@@ -75,8 +75,11 @@ void mlock_vma_page(struct page *page) {BUG_ON (!PageLocked (page)); -if (!TestSetPageMlocked (page) && !isolate_lru_page (page)) +if (!TestSetPageMlocked (page)) { +inc_zone_page_state (page,NR_MLOCK ); +if (!isolate_lru_page (page))putback_lru_page (page); + } }/*
@@ -98,10 +101,22 @@ static void munlock_vma_page(struct page {BUG_ON (!PageLocked (page)); -if (TestClearPageMlocked (page) && !isolate_lru_page (page)) { -if (try_to_unlock (page) ==SWAP_MLOCK ) -SetPageMlocked (page);/* still VM_LOCKED */ -putback_lru_page (page); +if (TestClearPageMlocked (page)) { +dec_zone_page_state (page,NR_MLOCK ); +if (!isolate_lru_page (page)) { +if (try_to_unlock (page) ==SWAP_MLOCK ) { +SetPageMlocked (page);/* still VM_LOCKED */ +inc_zone_page_state (page,NR_MLOCK ); + } +putback_lru_page (page); + } +/* +* Else we lost the race. let try_to_unmap() deal with it. +* At least we get the page state and mlock stats right. +* However, page is still on the noreclaim list. We'll fix +* that up when the page is eventually freed or we scan the +* noreclaim list. +*/ } }
@@ -118,7 +133,8 @@ int is_mlocked_vma(struct vm_area_structif (likely (!(vma->vm_flags &VM_LOCKED )))return 0 ; -SetPageMlocked (page); +if (!TestSetPageMlocked (page)) +inc_zone_page_state (page,NR_MLOCK );return 1 ; }
mm/migrate.c +8 -1
@@ -341,8 +341,15 @@ static void migrate_page_copy(struct pagset_page_dirty (newpage); } -if (TestClearPageMlocked (page)) +if (TestClearPageMlocked (page)) { +unsigned long flags; + +local_irq_save (flags); +__dec_zone_page_state (page,NR_MLOCK );SetPageMlocked (newpage); +__inc_zone_page_state (newpage,NR_MLOCK ); +local_irq_restore (flags); + }#ifdef CONFIG_SWAP ClearPageSwapCache (page);
mm/vmstat.c +3 -0
@@ -693,6 +693,9 @@ static const char * const vmstat_text[]#ifdef CONFIG_NORECLAIM "nr_noreclaim",#endif +#ifdef CONFIG_NORECLAIM_MLOCK +"nr_mlock" , +#endif"nr_anon_pages" ,"nr_mapped" , "nr_file_pages",
Signature · 7 lines
All Rights Reversed -- 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 21/21 cull non-reclaimable anon pages from the LRU at fault time
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split lru series.
V1 -> V2:
+ no changes
Optional part of "noreclaim infrastructure"
In the fault paths that install new anonymous pages, check whether the page is reclaimable or not using lru_cache_add_active_or_noreclaim(). If the page is reclaimable, just add it to the active lru list [via the pagevec cache], else add it to the noreclaim list.
This "proactive" culling in the fault path mimics the handling of mlocked pages in Nick Piggin's series to keep mlocked pages off the lru lists.
Notes:
1) This patch is optional--e.g., if one is concerned about the additional test in the fault path. We can defer the moving of nonreclaimable pages until when vmscan [shrink_*_list()] encounters them. Vmscan will only need to handle such pages once.
2) I moved the call to page_add_new_anon_rmap() to before the test for page_reclaimable() and thus before the calls to lru_cache_add_{active|noreclaim}(), so that page_reclaimable() could recognize the page as anon, thus obviating, I think, the vma arg to page_reclaimable() for this purpose. Still needed for culling mlocked pages in fault path [later patch].
TBD: I think this reordering is OK, but the previous order may
have existed to close some obscure race?
3) With this and other patches above installed, any anon pages created before swap is added--e.g., init's anonymous memory-- will be declared non-reclaimable and placed on the noreclaim LRU list. Need to add mechanism to bring such pages back when swap becomes available.
mm/memory.c +5 -5
@@ -1678,7 +1678,7 @@ gotten:set_pte_at (mm, address, page_table, entry);update_mmu_cache (vma, address, entry);SetPageSwapBacked (new_page); -lru_cache_add_active_anon (new_page); +lru_cache_add_active_or_noreclaim (new_page, vma);page_add_new_anon_rmap (new_page, vma, address);/* Free the old page.. */
@@ -2150,7 +2150,7 @@ static int do_anonymous_page(struct mm_s goto release;inc_mm_counter (mm, anon_rss);SetPageSwapBacked (page); -lru_cache_add_active_anon (page); +lru_cache_add_active_or_noreclaim (page, vma);page_add_new_anon_rmap (page, vma, address);set_pte_at (mm, address, page_table, entry);
@@ -2292,10 +2292,10 @@ static int __do_fault(struct mm_struct * entry =maybe_mkwrite (pte_mkdirty (entry), vma);set_pte_at (mm, address, page_table, entry);if (anon) { -inc_mm_counter (mm, anon_rss); +inc_mm_counter (mm, anon_rss);SetPageSwapBacked (page); -lru_cache_add_active_anon (page); -page_add_new_anon_rmap (page, vma, address); +lru_cache_add_active_or_noreclaim (page, vma); +page_add_new_anon_rmap (page, vma, address); }else {inc_mm_counter (mm, file_rss);page_add_file_rmap (page);
mm/swap_state.c +4 -1
@@ -300,7 +300,10 @@ struct page *read_swap_cache_async(swp_e/* * Initiate read into locked page and return. */ -lru_cache_add_anon (new_page); +if (!page_reclaimable (new_page, vma)) +lru_cache_add_noreclaim (new_page); +else +lru_cache_add_anon (new_page);swap_readpage (NULL , new_page);return new_page; }
Signature · 7 lines
All Rights Reversed -- 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 21/21] cull non-reclaimable anon pages from the LRU at fault time
On Thu, 2008-02-28 at 14:29 -0500, Rik van Riel wrote:
corrections to description in case we decide to keep this patch.
Quoted 25 lines
V2 -> V3:
+ rebase to 23-mm1 atop RvR's split lru series.V1 -> V2:
+ no changesOptional part of "noreclaim infrastructure"
In the fault paths that install new anonymous pages, check whether the page is reclaimable or not using
lru_cache_add_active_or_noreclaim(). If the page is reclaimable, just add it to the active lru list [via the pagevec cache], else add it to the noreclaim list.This "proactive" culling in the fault path mimics the handling of mlocked pages in Nick Piggin's series to keep mlocked pages off the lru lists.
Notes:
1) This patch is optional--e.g., if one is concerned about the additional test in the fault path. We can defer the moving of nonreclaimable pages until when vmscan [shrink_*_list()] encounters them. Vmscan will only need to handle such pages once.
Quoted 4 lines
2) I moved the call to
page_add_new_anon_rmap()to before the test forpage_reclaimable()and thus before the calls to lru_cache_add_{active|noreclaim}(), so thatpage_reclaimable()could recognize the page as anon,
<snip the bit about the vma arg. replaced with new note 3 below>
Quoted 3 lines
TBD: I think this reordering is OK, but the previous order may
have existed to close some obscure race?
<delete prev note 3, as it referred to patches that are no longer in the series [altho' I continue to maintain them separately, "just in case"]. replace with this note about vma arg to page_reclaimable()>
3) The 'vma' argument to page_reclaimable() is require to notice that we're faulting a page into an mlock()ed vma w/o having to scan the
page's rmap in the fault path. Culling mlock()ed anon pages is
currently the only reason for this patch.
Quoted 47 lines
Signed-off-by Lee Schermerhorn <[email protected]>Signed-off-by Rik van Riel <[email protected]>Index:
linux-2.6.25-rc2-mm1/mm/memory.c
===================================================================mm/memory.c +5
-5@@ -1678,7 +1678,7 @@ gotten:set_pte_at (mm, address, page_table, entry);update_mmu_cache (vma, address, entry);SetPageSwapBacked (new_page); -lru_cache_add_active_anon (new_page); +lru_cache_add_active_or_noreclaim (new_page, vma);page_add_new_anon_rmap (new_page, vma, address);/* Free the old page.. */ @@ -2150,7 +2150,7 @@ static int do_anonymous_page(struct mm_s goto release;inc_mm_counter (mm, anon_rss);SetPageSwapBacked (page); -lru_cache_add_active_anon (page); +lru_cache_add_active_or_noreclaim (page, vma);page_add_new_anon_rmap (page, vma, address);set_pte_at (mm, address, page_table, entry);@@ -2292,10 +2292,10 @@ static int __do_fault(struct mm_struct * entry =maybe_mkwrite (pte_mkdirty (entry), vma);set_pte_at (mm, address, page_table, entry);if (anon) { -inc_mm_counter (mm, anon_rss); +inc_mm_counter (mm, anon_rss);SetPageSwapBacked (page); -lru_cache_add_active_anon (page); -page_add_new_anon_rmap (page, vma, address); +lru_cache_add_active_or_noreclaim (page, vma); +page_add_new_anon_rmap (page, vma, address); }else {inc_mm_counter (mm, file_rss);page_add_file_rmap (page);Index:
linux-2.6.25-rc2-mm1/mm/swap_state.c
===================================================================mm/swap_state.c +0
-0@@ -300,7 +300,10 @@ struct page *read_swap_cache_async(swp_e/*
mm/swap_state.c struct page *read_swap_cache_async(swp_e · line 309
Quoted 10 lines
mm/swap_state.c +4
-1* Initiate read into locked page and return. */ -lru_cache_add_anon (new_page); +if (!page_reclaimable (new_page, vma)) +lru_cache_add_noreclaim (new_page); +else +lru_cache_add_anon (new_page);swap_readpage (NULL , new_page);return new_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>
Re: [patch 21/21] cull non-reclaimable anon pages from the LRU at fault time
Quoted 3 lines · On Thu, 28 Feb 2008 15:19:33 -0500 Lee Schermerhorn <[email protected]>…
On Thu, 2008-02-28 at 14:29 -0500, Rik van Riel wrote:
corrections to description in case we decide to keep this patch.
Thanks. I have merged your new description.
Signature · 7 lines
All rights reversed. -- 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>
Quoted 1 line · On Thu, 28 Feb 2008 14:29:08 -0500 Rik van Riel <[email protected]> wrote:
Against 2.6.24-rc6-mm1
I rediffed all the patches, but forgot to edit the intro email.
It really is against 2.6.25-rc2-mm1.
Signature · 7 lines
All rights reversed. -- 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>
Rik> On large memory systems, the VM can spend way too much time Rik> scanning through pages that it cannot (or should not) evict from Rik> memory. Not only does it use up CPU time, but it also provokes Rik> lock contention and can leave large systems under memory presure Rik> in a catatonic state.
Nitpicky, but what is a large memory system? I read your web page and you talk about large memory being greater than several Gb, and about huge systems (> 128gb). So which is this patch addressing?
I ask because I've got a new system with 4Gb of RAM and my motherboard can goto 8Gb. Should this be a large memory system or not? I've also only got a single dual core CPU, how does that affect things?
You talk about the Inactive list in the Anonymous memory section, and about limiting it. You say 30% on a 1Gb system, but 1% on a 1Tb system, which is interesting numbers but it's not clear where they come from.
Should the IO limits (raised lower down in the document) be a more core feature? I.e. if you only have 20MBytes/sec bandwidth to disk for swap, should you be limiting the inactive list to 5seconds of bandwidth in terms of size? Or 10s, or 60s?
Should we be more aggresive in pre-swapping Anonymous memory to swap, but keeping it cached in memory for use? If there's pressure, it seems like it would be easy to just dump pre-swapped pages from the inactive list, without having to spend time writing them out.
Also, how does having more CPUs/IO bandwidth change things? Do we need an exponential backoff algorithm in terms of how much memory is allocated to the various lists? As memory gets bigger and bigger, do we allocated fewer and fewer pages since we can't swap them out fast enough?
I dunno... I honestly don't have the time or the knowledge to do more than poke sticks into things and see what happens. And to ask annoying questions.
I do appreciate your work on this.
John
Rik> Against 2.6.24-rc6-mm1
Rik> This patch series improves VM scalability by:
Rik> 1) making the locking a little more scalable
Rik> 2) putting filesystem backed, swap backed and non-reclaimable pages
Rik> onto their own LRUs, so the system only scans the pages that it
Rik> can/should evict from memory
Rik> 3) switching to SEQ replacement for the anonymous LRUs, so the
Rik> number of pages that need to be scanned when the system
Rik> starts swapping is bound to a reasonable number
Rik> More info on the overall design can be found at:
Rik> http://linux-mm.org/PageReplacementDesign
Rik> Changelog:
Rik> - pull the memcontrol lru arrayification earlier into the patch series Rik> - use a pagevec array similar to the lru array
Rik> - clean up the code in various places
Rik> - improved pageout balancing and reduced pageout cpu use
Rik> - fix compilation on PPC and without memcontrol Rik> - make page_is_pagecache more readable Rik> - replace get_scan_ratio with correct version
Rik> - merge memcontroller split LRU code into the main split LRU patch,
Rik> since it is not functionally different (it was split up only to help
Rik> people who had seen the last version of the patch series review it)
Rik> - drop the page_file_cache debugging patch, since it never triggered Rik> - reintroduce code to not scan anon list if swap is full Rik> - add code to scan anon list if page cache is very small already Rik> - use lumpy reclaim more aggressively for smaller order > 1 allocations
Rik> --
Rik> All Rights Reversed
Rik> --
Rik> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Rik> the body of a message to [email protected]
Rik> More majordomo info at http://vger.kernel.org/majordomo-info.html
Rik> Please read the FAQ at http://www.tux.org/lkml/
Rik> !DSPAM:47c70f4e50261498712856!
--
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>
Quoted 7 lines · On Thu, 28 Feb 2008 15:14:02 -0500 "John Stoffel" <[email protected]> wrote:
Nitpicky, but what is a large memory system? I read your web page and you talk about large memory being greater than several Gb, and about huge systems (> 128gb). So which is this patch addressing?
I ask because I've got a new system with 4Gb of RAM and my motherboard can goto 8Gb. Should this be a large memory system or not? I've also only got a single dual core CPU, how does that affect things?
It depends a lot on the workload.
On a few workloads, the current VM explodes with as little as 16GB of RAM, while a few other workloads the current VM works fine with 128GB of RAM.
This patch tries to address the behaviour of the kernel when faced with workloads that trip up the current VM.
Quoted 4 lines
You talk about the Inactive list in the Anonymous memory section, and about limiting it. You say 30% on a 1Gb system, but 1% on a 1Tb system, which is interesting numbers but it's not clear where they come from.
They seemed a reasonable balance between limiting the maximum amount of work the VM needs to do and allowing pages the time to get referenced again. If benchmarks suggest that the ratio should be tweaked, we can do so quite easily.
Quoted 3 lines
I dunno... I honestly don't have the time or the knowledge to do more than poke sticks into things and see what happens. And to ask annoying questions.
Patch series like this can always use a good poking. Especially by people who run all kinds of nasty programs to trip up the VM :)
Signature · 7 lines
All rights reversed. -- 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>