Skip to contentSkip to conversation

2.6.4-rc2-mm1: vm-split-active-lists

PATCH In review Nick Piggin 8 participants 18 messages Mar 11, 2004 – Mar 13, 2004

Subsystems (9)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 2.6.4-rc2-mm1: vm-split-active-lists

Here is my updated patches rolled into one.

 linux-2.6-npiggin/arch/i386/mm/hugetlbpage.c    |    4 
 linux-2.6-npiggin/arch/ia64/mm/hugetlbpage.c    |    4 
 linux-2.6-npiggin/arch/ppc64/mm/hugetlbpage.c   |    4 
 linux-2.6-npiggin/arch/sparc64/mm/hugetlbpage.c |    4 
 linux-2.6-npiggin/include/linux/mm_inline.h     |   33 +++-
 linux-2.6-npiggin/include/linux/mmzone.h        |   28 ---
 linux-2.6-npiggin/include/linux/page-flags.h    |   50 +++---
 linux-2.6-npiggin/include/linux/swap.h          |    2 
 linux-2.6-npiggin/kernel/sysctl.c               |    9 -
 linux-2.6-npiggin/mm/page_alloc.c               |   26 +--
 linux-2.6-npiggin/mm/swap.c                     |   35 +++-
 linux-2.6-npiggin/mm/vmscan.c                   |  193 ++++++++++--------------
 12 files changed, 197 insertions(+), 195 deletions(-)
arch/i386/mm/hugetlbpage.c renamed from arch/i386/mm/hugetlbpage.c~rollup +2 -2
diff -puN arch/i386/mm/hugetlbpage.c~rollup arch/i386/mm/hugetlbpage.c
@@ -411,8 +411,8 @@ static void update_and_free_page(struct 
 	htlbzone_pages--;
 	for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) {
 		map->flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced |
-				1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
-				1 << PG_private | 1<< PG_writeback);
+				1 << PG_dirty | 1 << PG_active_mapped | 1 << PG_active_unmapped |
+				1 << PG_reserved | 1 << PG_private | 1<< PG_writeback);
 		set_page_count(map, 0);
 		map++;
 	}
arch/ia64/mm/hugetlbpage.c renamed from arch/ia64/mm/hugetlbpage.c~rollup +2 -2
diff -puN arch/ia64/mm/hugetlbpage.c~rollup arch/ia64/mm/hugetlbpage.c
@@ -431,8 +431,8 @@ void update_and_free_page(struct page *p
 	htlbzone_pages--;
 	for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) {
 		map->flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced |
-				1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
-				1 << PG_private | 1<< PG_writeback);
+				1 << PG_dirty | 1 << PG_active_mapped | 1 << PG_active_unmapped |
+				1 << PG_reserved | 1 << PG_private | 1<< PG_writeback);
 		set_page_count(map, 0);
 		map++;
 	}
arch/ppc64/mm/hugetlbpage.c renamed from arch/ppc64/mm/hugetlbpage.c~rollup +2 -2
diff -puN arch/ppc64/mm/hugetlbpage.c~rollup arch/ppc64/mm/hugetlbpage.c
@@ -800,8 +800,8 @@ static void split_and_free_hugepage(stru
 	htlbpage_total--;
 	for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) {
 		map->flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced |
-				1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
-				1 << PG_private | 1<< PG_writeback);
+				1 << PG_dirty | 1 << PG_active_mapped | 1 << PG_active_unmapped |
+				1 << PG_reserved | 1 << PG_private | 1<< PG_writeback);
 		set_page_count(map, 0);
 		map++;
 	}
arch/sparc64/mm/hugetlbpage.c renamed from arch/sparc64/mm/hugetlbpage.c~rollup +2 -2
diff -puN arch/sparc64/mm/hugetlbpage.c~rollup arch/sparc64/mm/hugetlbpage.c
@@ -365,8 +365,8 @@ static void update_and_free_page(struct 
 	htlbzone_pages--;
 	for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) {
 		map->flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced |
-				1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
-				1 << PG_private | 1<< PG_writeback);
+				1 << PG_dirty | 1 << PG_active_mapped | 1 << PG_active_unmapped |
+				1 << PG_reserved | 1 << PG_private | 1<< PG_writeback);
 		set_page_count(map, 0);
 		map++;
 	}
include/linux/mm_inline.h renamed from include/linux/mm_inline.h~rollup +25 -8
diff -puN include/linux/mm_inline.h~rollup include/linux/mm_inline.h
@@ -1,9 +1,16 @@
 
 static inline void
-add_page_to_active_list(struct zone *zone, struct page *page)
+add_page_to_active_mapped_list(struct zone *zone, struct page *page)
 {
-	list_add(&page->lru, &zone->active_list);
-	zone->nr_active++;
+	list_add(&page->lru, &zone->active_mapped_list);
+	zone->nr_active_mapped++;
+}
+
+static inline void
+add_page_to_active_unmapped_list(struct zone *zone, struct page *page)
+{
+	list_add(&page->lru, &zone->active_unmapped_list);
+	zone->nr_active_unmapped++;
 }
 
 static inline void
@@ -14,10 +21,17 @@ add_page_to_inactive_list(struct zone *z
 }
 
 static inline void
-del_page_from_active_list(struct zone *zone, struct page *page)
+del_page_from_active_mapped_list(struct zone *zone, struct page *page)
+{
+	list_del(&page->lru);
+	zone->nr_active_mapped--;
+}
+
+static inline void
+del_page_from_active_unmapped_list(struct zone *zone, struct page *page)
 {
 	list_del(&page->lru);
-	zone->nr_active--;
+	zone->nr_active_unmapped--;
 }
 
 static inline void
@@ -31,9 +45,12 @@ static inline void
 del_page_from_lru(struct zone *zone, struct page *page)
 {
 	list_del(&page->lru);
-	if (PageActive(page)) {
-		ClearPageActive(page);
-		zone->nr_active--;
+	if (PageActiveMapped(page)) {
+		ClearPageActiveMapped(page);
+		zone->nr_active_mapped--;
+	} else if (PageActiveUnmapped(page)) {
+		ClearPageActiveUnmapped(page);
+		zone->nr_active_unmapped--;
 	} else {
 		zone->nr_inactive--;
 	}
include/linux/mmzone.h renamed from include/linux/mmzone.h~rollup +6 -22
diff -puN include/linux/mmzone.h~rollup include/linux/mmzone.h
@@ -74,11 +74,14 @@ struct zone {
 	ZONE_PADDING(_pad1_)
 
 	spinlock_t		lru_lock;	
-	struct list_head	active_list;
+	struct list_head	active_mapped_list;
+	struct list_head	active_unmapped_list;
 	struct list_head	inactive_list;
-	atomic_t		nr_scan_active;
+	atomic_t		nr_scan_active_mapped;
+	atomic_t		nr_scan_active_unmapped;
 	atomic_t		nr_scan_inactive;
-	unsigned long		nr_active;
+	unsigned long		nr_active_mapped;
+	unsigned long		nr_active_unmapped;
 	unsigned long		nr_inactive;
 	int			all_unreclaimable; /* All pages pinned */
 	unsigned long		pages_scanned;	   /* since last reclaim */
@@ -86,25 +89,6 @@ struct zone {
 	ZONE_PADDING(_pad2_)
 
 	/*
-	 * prev_priority holds the scanning priority for this zone.  It is
-	 * defined as the scanning priority at which we achieved our reclaim
-	 * target at the previous try_to_free_pages() or balance_pgdat()
-	 * invokation.
-	 *
-	 * We use prev_priority as a measure of how much stress page reclaim is
-	 * under - it drives the swappiness decision: whether to unmap mapped
-	 * pages.
-	 *
-	 * temp_priority is used to remember the scanning priority at which
-	 * this zone was successfully refilled to free_pages == pages_high.
-	 *
-	 * Access to both these fields is quite racy even on uniprocessor.  But
-	 * it is expected to average out OK.
-	 */
-	int temp_priority;
-	int prev_priority;
-
-	/*
 	 * free areas of different sizes
 	 */
 	struct free_area	free_area[MAX_ORDER];
include/linux/page-flags.h renamed from include/linux/page-flags.h~rollup +29 -21

63 lines not on this page · raw message

include/linux/swap.h renamed from include/linux/swap.h~rollup +1 -1
diff -puN include/linux/swap.h~rollup include/linux/swap.h
@@ -175,7 +175,7 @@ extern void swap_setup(void);
 /* linux/mm/vmscan.c */
 extern int try_to_free_pages(struct zone **, unsigned int, unsigned int);
 extern int shrink_all_memory(int);
-extern int vm_swappiness;
+extern int vm_mapped_page_cost;
 
 /* linux/mm/rmap.c */
 #ifdef CONFIG_MMU
kernel/sysctl.c renamed from kernel/sysctl.c~rollup +5 -4
diff -puN kernel/sysctl.c~rollup kernel/sysctl.c
@@ -621,6 +621,7 @@ static ctl_table kern_table[] = {
 /* Constants for minimum and maximum testing in vm_table.
    We use these as one-element integer vectors. */
 static int zero;
+static int one = 1;
 static int one_hundred = 100;
 
 
@@ -697,13 +698,13 @@ static ctl_table vm_table[] = {
 	},
 	{
 		.ctl_name	= VM_SWAPPINESS,
-		.procname	= "swappiness",
-		.data		= &vm_swappiness,
-		.maxlen		= sizeof(vm_swappiness),
+		.procname	= "mapped_page_cost",
+		.data		= &vm_mapped_page_cost,
+		.maxlen		= sizeof(vm_mapped_page_cost),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec_minmax,
 		.strategy	= &sysctl_intvec,
-		.extra1		= &zero,
+		.extra1		= &one,
 		.extra2		= &one_hundred,
 	},
 #ifdef CONFIG_HUGETLB_PAGE
mm/page_alloc.c renamed from mm/page_alloc.c~rollup +15 -11
diff -puN mm/page_alloc.c~rollup mm/page_alloc.c
@@ -81,7 +81,7 @@ static void bad_page(const char *functio
 	page->flags &= ~(1 << PG_private	|
 			1 << PG_locked	|
 			1 << PG_lru	|
-			1 << PG_active	|
+			1 << PG_active_mapped	|
 			1 << PG_dirty	|
 			1 << PG_writeback);
 	set_page_count(page, 0);
@@ -217,7 +217,8 @@ static inline void free_pages_check(cons
 			1 << PG_lru	|
 			1 << PG_private |
 			1 << PG_locked	|
-			1 << PG_active	|
+			1 << PG_active_mapped	|
+			1 << PG_active_unmapped	|
 			1 << PG_reclaim	|
 			1 << PG_slab	|
 			1 << PG_writeback )))
@@ -324,7 +325,8 @@ static void prep_new_page(struct page *p
 			1 << PG_private	|
 			1 << PG_locked	|
 			1 << PG_lru	|
-			1 << PG_active	|
+			1 << PG_active_mapped	|
+			1 << PG_active_unmapped	|
 			1 << PG_dirty	|
 			1 << PG_reclaim	|
 			1 << PG_writeback )))
@@ -818,7 +820,8 @@ unsigned int nr_used_zone_pages(void)
 	struct zone *zone;
 
 	for_each_zone(zone)
-		pages += zone->nr_active + zone->nr_inactive;
+		pages += zone->nr_active_mapped + zone->nr_active_unmapped
+			+ zone->nr_inactive;
 
 	return pages;
 }
@@ -955,7 +958,7 @@ void get_zone_counts(unsigned long *acti
 	*inactive = 0;
 	*free = 0;
 	for_each_zone(zone) {
-		*active += zone->nr_active;
+		*active += zone->nr_active_mapped + zone->nr_active_unmapped;
 		*inactive += zone->nr_inactive;
 		*free += zone->free_pages;
 	}
@@ -1068,7 +1071,7 @@ void show_free_areas(void)
 			K(zone->pages_min),
 			K(zone->pages_low),
 			K(zone->pages_high),
-			K(zone->nr_active),
+			K(zone->nr_active_mapped + zone->nr_active_unmapped),
 			K(zone->nr_inactive),
 			K(zone->present_pages)
 			);
@@ -1408,8 +1411,6 @@ static void __init free_area_init_core(s
 		zone->zone_pgdat = pgdat;
 		zone->free_pages = 0;
 
-		zone->temp_priority = zone->prev_priority = DEF_PRIORITY;
-
 		/*
 		 * The per-cpu-pages pools are set to around 1000th of the
 		 * size of the zone.  But no more than 1/4 of a meg - there's
@@ -1443,11 +1444,14 @@ static void __init free_area_init_core(s
 		}
 		printk("  %s zone: %lu pages, LIFO batch:%lu\n",
 				zone_names[j], realsize, batch);
-		INIT_LIST_HEAD(&zone->active_list);
+		INIT_LIST_HEAD(&zone->active_mapped_list);
+		INIT_LIST_HEAD(&zone->active_unmapped_list);
 		INIT_LIST_HEAD(&zone->inactive_list);
-		atomic_set(&zone->nr_scan_active, 0);
+		atomic_set(&zone->nr_scan_active_mapped, 0);
+		atomic_set(&zone->nr_scan_active_unmapped, 0);
 		atomic_set(&zone->nr_scan_inactive, 0);
-		zone->nr_active = 0;
+		zone->nr_active_mapped = 0;
+		zone->nr_active_unmapped = 0;
 		zone->nr_inactive = 0;
 		if (!size)
 			continue;
mm/swap.c renamed from mm/swap.c~rollup +26 -9
diff -puN mm/swap.c~rollup mm/swap.c
@@ -58,14 +58,18 @@ int rotate_reclaimable_page(struct page 
 		return 1;
 	if (PageDirty(page))
 		return 1;
-	if (PageActive(page))
+	if (PageActiveMapped(page))
+		return 1;
+	if (PageActiveUnmapped(page))
 		return 1;
 	if (!PageLRU(page))
 		return 1;
 
 	zone = page_zone(page);
 	spin_lock_irqsave(&zone->lru_lock, flags);
-	if (PageLRU(page) && !PageActive(page)) {
+	if (PageLRU(page)
+		&& !PageActiveMapped(page) && !PageActiveUnmapped(page)) {
+
 		list_del(&page->lru);
 		list_add_tail(&page->lru, &zone->inactive_list);
 		inc_page_state(pgrotated);
@@ -84,10 +88,18 @@ void fastcall activate_page(struct page 
 	struct zone *zone = page_zone(page);
 
 	spin_lock_irq(&zone->lru_lock);
-	if (PageLRU(page) && !PageActive(page)) {
+	if (PageLRU(page)
+		&& !PageActiveMapped(page) && !PageActiveUnmapped(page)) {
+
 		del_page_from_inactive_list(zone, page);
-		SetPageActive(page);
-		add_page_to_active_list(zone, page);
+
+		if (page_mapped(page)) {
+			SetPageActiveMapped(page);
+			add_page_to_active_mapped_list(zone, page);
+		} else {
+			SetPageActiveUnmapped(page);
+			add_page_to_active_unmapped_list(zone, page);
+		}
 		inc_page_state(pgactivate);
 	}
 	spin_unlock_irq(&zone->lru_lock);
@@ -102,7 +114,8 @@ void fastcall activate_page(struct page 
  */
 void fastcall mark_page_accessed(struct page *page)
 {
-	if (!PageActive(page) && PageReferenced(page) && PageLRU(page)) {
+	if (!PageActiveMapped(page) && !PageActiveUnmapped(page)
+			&& PageReferenced(page) && PageLRU(page)) {
 		activate_page(page);
 		ClearPageReferenced(page);
 	} else if (!PageReferenced(page)) {
@@ -310,9 +323,13 @@ void __pagevec_lru_add_active(struct pag
 		}
 		if (TestSetPageLRU(page))
 			BUG();
-		if (TestSetPageActive(page))
-			BUG();
-		add_page_to_active_list(zone, page);
+		if (page_mapped(page)) {
+			SetPageActiveMapped(page);
+			add_page_to_active_mapped_list(zone, page);
+		} else {
+			SetPageActiveMapped(page);
+			add_page_to_active_unmapped_list(zone, page);
+		}
 	}
 	if (zone)
 		spin_unlock_irq(&zone->lru_lock);
mm/vmscan.c renamed from mm/vmscan.c~rollup +82 -111

372 lines not on this page · raw message

_

#1 lore raw

On Thursday 11 March 2004 01:04, Nick Piggin wrote:

Hi Nick,

Quoted 1 line

Here is my updated patches rolled into one.

hmm, using this in 2.6.4-rc2-mm1 my machine starts to swap very very soon. Machine has squid, bind, apache running, X 4.3.0, Windowmaker, so nothing special.

Swap grows very easily starting to untar'gunzip a kernel tree. About + 150-200MB goes to swap. Everything is very smooth though, but I just wondered because w/o your patches swap isn't used at all, even after some days of uptime.

ciao, Marc

--
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>

#2 lore raw
Quoted 5 lines · Marc-Christian Petersen

On Thursday 11 March 2004 01:04, Nick Piggin wrote:

Hi Nick,

Quoted 8 lines
Quoted 2 lines

Here is my updated patches rolled into one.

hmm, using this in 2.6.4-rc2-mm1 my machine starts to swap very very soon. Machine has squid, bind, apache running, X 4.3.0, Windowmaker, so nothing special.

Swap grows very easily starting to untar'gunzip a kernel tree. About + 150-200MB goes to swap. Everything is very smooth though, but I just wondered because w/o your patches swap isn't used at all, even after some days of uptime.

Hmm... I guess it is still smooth because it is swapping out only inactive pages. If the standard VM isn't being pushed very hard it doesn't scan mapped pages at all which is why it isn't swapping.

I have a preference for allowing it to scan some mapped pages though. I'm not sure if there is any attempt at a drop behind logic. That might help. Add new unmapped pagecache pages to the inactive list or something might help... hmm, actually that's what it does now by the looks.

I guess you don't have a problem though.

--
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>

#3 lore raw
Quoted 6 lines · Nick Piggin

Hmm... I guess it is still smooth because it is swapping out only
inactive pages. If the standard VM isn't being pushed very hard it doesn't scan mapped pages at all which is why it isn't swapping.

I have a preference for allowing it to scan some mapped pages though.

I haven't looked at the code but if, as I assume, it is always scanning mapped pages, although at a reduced rate then the effect will be the same as setting swappiness to 100, except it will take longer.

That effect is to cause the whole world to be swapped out when people return to their machines in the morning. Once they're swapped back in the first thing they do it send bitchy emails to you know who.

Quoted 1 line

From a performance perspective it's the right thing to do, but nobody likes

it.

--
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>

#4 lore raw
Quoted 6 lines · Andrew Morton
Quoted 4 lines · Nick Piggin

Hmm... I guess it is still smooth because it is swapping out only inactive pages. If the standard VM isn't being pushed very hard it doesn't scan mapped pages at all which is why it isn't swapping.

Quoted 8 lines
Quoted 2 lines

I have a preference for allowing it to scan some mapped pages though.

I haven't looked at the code but if, as I assume, it is always scanning mapped pages, although at a reduced rate then the effect will be the same as setting swappiness to 100, except it will take longer.

Yep

Quoted 8 lines

That effect is to cause the whole world to be swapped out when people return to their machines in the morning. Once they're swapped back in the first thing they do it send bitchy emails to you know who.

Quoted 1 line

From a performance perspective it's the right thing to do, but nobody likes

it.

Yeah. I wonder if there is a way to be smarter about dropping these used once pages without putting pressure on more permanent pages... I guess all heuristics will fall down somewhere or other.

--
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>

#5 lore raw
In reply to Andrew Morton
Quoted 2 lines · Andrew Morton

That effect is to cause the whole world to be swapped out when people return to their machines in the morning.

The correct solution to this problem is "suspend-to-disk" -- if the machine isn't doing anything anyway, TURN IT OFF.

One slightly more practical solution from the "you-now-who gets angry mails" POV anyway, would be to tie the reduced-rate scanning to the load average -- if nothing at all happens, swap-out doesn't need to happen either.

Signature · 1 line
Matthias Urlichs
#6 lore raw
Quoted 5 lines · Matthias Urlichs
Quoted 2 lines

That effect is to cause the whole world to be swapped out when people return to their machines in the morning.

The correct solution to this problem is "suspend-to-disk" -- if the machine isn't doing anything anyway, TURN IT OFF.

How is that better for people complaining that everything needs to be swapped in in the morning?

Suspend-to-disk will cause everything to be paged in too. Faster I suspect (haven't tried it; it doesn't work on my box), but still a wait especially when you add in the BIOS boot time.

Environmentally turning an unused machine off is good. But I don't see how suspend-to-disk will convince people who are annoyed by swapping in the morning.

Quoted 4 lines

One slightly more practical solution from the "you-now-who gets angry mails" POV anyway, would be to tie the reduced-rate scanning to the load average -- if nothing at all happens, swap-out doesn't need to happen either.

If nothing at all happens, does it matter that pages are written to swap? They're still in RAM as well.

-- Jamie

#7 lore raw
In reply to Matthias Urlichs
Quoted 11 lines · Matthias Urlichs
Quoted 3 lines · Andrew Morton

That effect is to cause the whole world to be swapped out when people return to their machines in the morning.

The correct solution to this problem is "suspend-to-disk" -- if the machine isn't doing anything anyway, TURN IT OFF.

Without arguing that point, the VM also should have a solution to the problem where people don't turn it off.

Quoted 6 lines

One slightly more practical solution from the "you-now-who gets angry mails" POV anyway, would be to tie the reduced-rate scanning to the load average -- if nothing at all happens, swap-out doesn't need to happen either.

Well if nothing at all happens we don't swap out, but when something is happening, desktop users don't want any of their programs to be swapped out no matter how long they have been sitting idle. They don't want to wait 10 seconds to page something in even if it means they're waiting an extra 10 minutes throughout the day for their kernel greps and diffs to finish.

#8 lore raw
Quoted 9 lines · Nick Piggin

Well if nothing at all happens we don't swap out, but when something is happening, desktop users don't want any of their programs to be swapped out no matter how long they have been sitting idle. They don't want to wait 10 seconds to page something in even if it means they're waiting an extra 10 minutes throughout the day for their kernel greps and diffs to finish.

Just had a try of doing things like updatedb and dd if=/dev/zero of=./blah It is pretty swappy I guess. The following patch I think makes things less swappy. It still isn't true dropbehind because new unmapped pages still do place some pressure on the more established pagecache, but not as much.

It is unclear whether full dropbehind is actually good or not. If you have 512MB of memory and a 256MB working set of file data (unmapped), with 400MB of mapped memory doing nothing, after enough thrashing through your 256MB, you'd expect some of that mapped memory to be swapped out.

By the way, I would be interested to know the rationale behind mark_page_accessed as it is without this patch, also what is it doing in rmap.c (I know hardly anything actually uses page_test_and_clear_young, but still). It seems to me like it only serves to make VM behaviour harder to understand, but I'm probably missing something. Andrew?

 linux-2.6-npiggin/mm/filemap.c |    3 +--
 linux-2.6-npiggin/mm/rmap.c    |    2 +-
 linux-2.6-npiggin/mm/swap.c    |    7 +------
 3 files changed, 3 insertions(+), 9 deletions(-)
mm/filemap.c renamed from mm/filemap.c~vm-dropbehind +1 -2
diff -puN mm/filemap.c~vm-dropbehind mm/filemap.c
@@ -662,8 +662,7 @@ page_ok:
 		/*
 		 * Mark the page accessed if we read the beginning.
 		 */
-		if (!offset)
-			mark_page_accessed(page);
+		mark_page_accessed(page);
 
 		/*
 		 * Ok, we have the page, and it's up-to-date, so
mm/swap.c renamed from mm/swap.c~vm-dropbehind +1 -6
diff -puN mm/swap.c~vm-dropbehind mm/swap.c
@@ -111,13 +111,8 @@ void fastcall activate_page(struct page 
  */
 void fastcall mark_page_accessed(struct page *page)
 {
-	if (!PageActiveMapped(page) && !PageActiveUnmapped(page)
-			&& PageReferenced(page) && PageLRU(page)) {
-		activate_page(page);
-		ClearPageReferenced(page);
-	} else if (!PageReferenced(page)) {
+	if (!PageReferenced(page))
 		SetPageReferenced(page);
-	}
 }
 
 EXPORT_SYMBOL(mark_page_accessed);
mm/rmap.c renamed from mm/rmap.c~vm-dropbehind +1 -1
diff -puN mm/rmap.c~vm-dropbehind mm/rmap.c
@@ -118,7 +118,7 @@ int fastcall page_referenced(struct page
 	int referenced = 0;
 
 	if (page_test_and_clear_young(page))
-		mark_page_accessed(page);
+		referenced++;
 
 	if (TestClearPageReferenced(page))
 		referenced++;

_

#9 lore raw
Quoted 1 line · Nick Piggin

[...]

Quoted 6 lines

By the way, I would be interested to know the rationale behind mark_page_accessed as it is without this patch, also what is it doing in rmap.c (I know hardly anything actually uses page_test_and_clear_young, but still). It seems to me like it only serves to make VM behaviour harder to understand, but I'm probably missing something. Andrew?

With your patch, once a page got into inactive list, its PG_referenced bit will only be checked by VM scanner when page wanders to the tail of list. In particular, if is impossible to tell pages that were accessed only once while on inactive list from ones that were accessed multiple times. Original mark_page_accessed() moves page to the active list on the second access, thus making it less eligible for the reclaim.

I actually tried quite an opposite modification:
(ftp://ftp.namesys.com/pub/misc-patches/unsupported/extra/2004.03.10-2.6.4-rc3/a_1[5678]*)

/* roughly, modulo locking, etc. */
void fastcall mark_page_accessed(struct page *page)

{
		if (!PageReferenced(page))
			SetPageReferenced(page);
		else if (!PageLRU(page))
			continue;
		else if (!PageActive(page)) {
			/* page is on inactive list */
			del_page_from_inactive_list(zone, page);
			SetPageActive(page);
			add_page_to_active_list(zone, page);
			inc_page_state(pgactivate);
			ClearPageReferenced(page);
		} else {
			/* page is on active list, move it to head */
			list_move(&page->lru, &zone->active_list);
			ClearPageReferenced(page);
		}
}

That is, referenced and active page is moved to head of the active list. While somewhat improving file system performance it badly affects anonymous memory, because (it seems) file system pages tend to push mapped ones out of active list. Probably it should have better effect with your split active lists.

Quoted 1 line

Nikita.

#10 lore raw
Quoted 12 lines · Nikita Danilov
Quoted 1 line · Nick Piggin

[...]

Quoted 6 lines

By the way, I would be interested to know the rationale behind mark_page_accessed as it is without this patch, also what is it doing in rmap.c (I know hardly anything actually uses page_test_and_clear_young, but still). It seems to me like it only serves to make VM behaviour harder to understand, but I'm probably missing something. Andrew?

Quoted 8 lines

With your patch, once a page got into inactive list, its PG_referenced bit will only be checked by VM scanner when page wanders to the tail of list. In particular, if is impossible to tell pages that were accessed only once while on inactive list from ones that were accessed multiple times. Original mark_page_accessed() moves page to the active list on the second access, thus making it less eligible for the reclaim.

With my patch though, it gives unmapped pages the same treatment as mapped pages. Without my patch, pages getting a lot of mark_page_accessed activity can easily be promoted unfairly past mapped ones which are simply getting activity through the pte.

I say just set the bit and let the scanner handle it.

Quoted 24 lines

I actually tried quite an opposite modification:
(ftp://ftp.namesys.com/pub/misc-patches/unsupported/extra/2004.03.10-2.6.4-rc3/a_1[5678]*)

/* roughly, modulo locking, etc. */
void fastcall mark_page_accessed(struct page *page)

{
		if (!PageReferenced(page))
			SetPageReferenced(page);
		else if (!PageLRU(page))
			continue;
		else if (!PageActive(page)) {
			/* page is on inactive list */
			del_page_from_inactive_list(zone, page);
			SetPageActive(page);
			add_page_to_active_list(zone, page);
			inc_page_state(pgactivate);
			ClearPageReferenced(page);
		} else {
			/* page is on active list, move it to head */
			list_move(&page->lru, &zone->active_list);
			ClearPageReferenced(page);
		}
}
Quoted 6 lines

That is, referenced and active page is moved to head of the active list. While somewhat improving file system performance it badly affects anonymous memory, because (it seems) file system pages tend to push mapped ones out of active list. Probably it should have better effect with your split active lists.

Yeah. Hmm, I think it might be a good idea to do this sorting for unmapped pages on the active list. It shouldn't do ClearPageReferenced though, because your !PageReferenced pages now get their referenced bit set, and next time around the scanner they come in above the PageReferenced page.

I don't like the inactive->active promotion here though, as I explained.

#11 lore raw
Quoted 25 lines · Nick Piggin
Quoted 12 lines · Nikita Danilov
Quoted 1 line · Nick Piggin

[...]

Quoted 6 lines

By the way, I would be interested to know the rationale behind mark_page_accessed as it is without this patch, also what is it doing in rmap.c (I know hardly anything actually uses page_test_and_clear_young, but still). It seems to me like it only serves to make VM behaviour harder to understand, but I'm probably missing something. Andrew?

Quoted 8 lines

With your patch, once a page got into inactive list, its PG_referenced bit will only be checked by VM scanner when page wanders to the tail of list. In particular, if is impossible to tell pages that were accessed only once while on inactive list from ones that were accessed multiple times. Original mark_page_accessed() moves page to the active list on the second access, thus making it less eligible for the reclaim.

Quoted 4 lines

With my patch though, it gives unmapped pages the same treatment as mapped pages. Without my patch, pages getting a lot of mark_page_accessed activity can easily be promoted unfairly past mapped ones which are simply getting activity through the pte.

Another way to put it is that treatment of file system pages is dumbed down to the level of mapped ones: information about access patterns is just discarded.

Quoted 2 lines

I say just set the bit and let the scanner handle it.

I think that decisions about balancing VM and file system caches should be done by higher level, rather than by forcing file system to use low-level mechanisms designed for VM, where only limited information is provided by hardware. Splitting page queues is a step in a right direction, as it allows to implement more precise replacement for the file system cache.

Nikita.

#12 lore raw
Quoted 12 lines · Nikita Danilov
Quoted 4 lines · Nick Piggin

With my patch though, it gives unmapped pages the same treatment as mapped pages. Without my patch, pages getting a lot of mark_page_accessed activity can easily be promoted unfairly past mapped ones which are simply getting activity through the pte.

Another way to put it is that treatment of file system pages is dumbed down to the level of mapped ones: information about access patterns is just discarded.

In a way, yes.

Quoted 11 lines
Quoted 2 lines

I say just set the bit and let the scanner handle it.

I think that decisions about balancing VM and file system caches should be done by higher level, rather than by forcing file system to use low-level mechanisms designed for VM, where only limited information is provided by hardware. Splitting page queues is a step in a right direction, as it allows to implement more precise replacement for the file system cache.

It makes it that much harder to calculate the pressure you are putting on mapped vs unmapped pages though.

#13 lore raw
In reply to Nick Piggin
Quoted 3 lines · Nick Piggin

Just had a try of doing things like updatedb and dd if=/dev/zero of=./blah It is pretty swappy I guess.

You'll need to bring the scanning priority back into the picture: don't move mapped pages down onto the inactive list at low scanning priorities. And that eans retaining the remember-the-priority-from-last-time logic.

Otherwise it's inevitable that even a `cat monster_file > /dev/null' will eventually swap out everything it can.

Quoted 5 lines

By the way, I would be interested to know the rationale behind mark_page_accessed as it is without this patch, also what is it doing in rmap.c (I know hardly anything actually uses page_test_and_clear_young, but still). It seems to me like it only serves to make VM behaviour harder to understand, but I'm probably missing something. Andrew?

hm, that's left-over code which is pretty pointless now.

	if (page_test_and_clear_young(page))
		mark_page_accessed(page);

	if (TestClearPageReferenced(page))
		referenced++;

The pages in here are never on the LRU, so all the mark_page_accessed() will do is to set PG_Referenced. And we immediately clear it again. So the mark_page_accessed() can be replaced with referenced++.

#14 lore raw
Quoted 6 lines · Andrew Morton
Quoted 3 lines · Nick Piggin

Just had a try of doing things like updatedb and dd if=/dev/zero of=./blah It is pretty swappy I guess.

Quoted 7 lines

You'll need to bring the scanning priority back into the picture: don't
move mapped pages down onto the inactive list at low scanning priorities. And that eans retaining the remember-the-priority-from-last-time logic.

Otherwise it's inevitable that even a `cat monster_file > /dev/null' will eventually swap out everything it can.

Hmm I dunno. At mapped_page_cost 8, I don't think it is swappy enough that your desktop users will be running into problems. I need to write 4GB of file to push out 70MB of swap here (256MB RAM). And not much of that swap has come back in, by the way...

Quoted 16 lines
Quoted 6 lines

By the way, I would be interested to know the rationale behind mark_page_accessed as it is without this patch, also what is it doing in rmap.c (I know hardly anything actually uses page_test_and_clear_young, but still). It seems to me like it only serves to make VM behaviour harder to understand, but I'm probably missing something. Andrew?

hm, that's left-over code which is pretty pointless now.

	if (page_test_and_clear_young(page))
		mark_page_accessed(page);

	if (TestClearPageReferenced(page))
		referenced++;
Quoted 6 lines

The pages in here are never on the LRU, so all the mark_page_accessed() will do is to set PG_Referenced. And we immediately clear it again. So the mark_page_accessed() can be replaced with referenced++.

Yep, see the patch I'd attached before.

#15 lore raw
In reply to Nick Piggin
Quoted 26 lines · Nick Piggin
Quoted 11 lines · Matthias Urlichs
Quoted 3 lines · Andrew Morton

That effect is to cause the whole world to be swapped out when people return to their machines in the morning.

The correct solution to this problem is "suspend-to-disk" -- if the machine isn't doing anything anyway, TURN IT OFF.

Without arguing that point, the VM also should have a solution to the problem where people don't turn it off.

Quoted 6 lines

One slightly more practical solution from the "you-now-who gets angry mails" POV anyway, would be to tie the reduced-rate scanning to the load average -- if nothing at all happens, swap-out doesn't need to happen either.

Quoted 6 lines

Well if nothing at all happens we don't swap out, but when something is happening, desktop users don't want any of their programs to be swapped out no matter how long they have been sitting idle. They don't want to wait 10 seconds to page something in even if it means they're waiting an extra 10 minutes throughout the day for their kernel greps and diffs to finish.

I have noticed that 2.6 seems to clear memory (any version I've run for a while) and a lunch break results in a burst of disk activity before the screen saver even gets in to unlock the screen. I know this box has no cron activity during the day, so the pages were not forced out.

It's a good thing IMHO to write dirty pages to swap so the space can be reclaimed if needed, but shouldn't the page be marked as clean and left in memory for use without swap-in nif it's needed? I see this on backup servers, and a machine with 3GB of free memory, no mail, no cron and no app running isn't getting much memory pressure ;-)

I am not saying the behaviour is wrong, I just fail to see why the last application run isn't still in memory an hour later, absent memory pressure.

Signature · 1 line
		-bill
#16 lore raw
Quoted 3 lines · Bill Davidsen

I have noticed that 2.6 seems to clear memory (any version I've run for a while) and a lunch break results in a burst of disk activity before the screen saver even gets in to unlock the screen. I know this box has no cron activity during the day, so the pages were not forced out.

It shouldn't. Perhaps something else is using memory in the background?

Quoted 2 lines

It's a good thing IMHO to write dirty pages to swap so the space can be reclaimed if needed, but shouldn't the page be marked as clean and left in memory for use without swap-in nif it's needed? I see this on backup servers, and a machine with 3GB of free memory, no mail, no cron and no app running isn't getting much memory pressure ;-)

Well it is basically just written out and reclaimed when it is needed, it won't just be swapped out without memory pressure.

Although, there were some highmem balancing problems in 2.6 including 2.6.4 (now fixed in -bk). This causes too much pressure to be put on ZONE_NORMAL mapped and file cache memory in favour of slab cache. This could easily be causing the misbehaviour.

Quoted 2 lines

I am not saying the behaviour is wrong, I just fail to see why the last application run isn't still in memory an hour later, absent memory pressure.

There would have to be *some* memory pressure... honestly, try 2.6-bk, or if they are production machines and you can't, then wait for 2.6.5.

#17 lore raw
In reply to Matthias Urlichs

Hi!

Quoted 5 lines
Quoted 2 lines

That effect is to cause the whole world to be swapped out when people return to their machines in the morning.

The correct solution to this problem is "suspend-to-disk" -- if the machine isn't doing anything anyway, TURN IT OFF.

Try it.

With current design, machine swaps *a lot* after resume.

Suspend-to-ram is probably better.

But if you don't run your updatedb overnight, you are going to run it while you are logged in, and that is going to suck.

Signature · 1 line
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms