Skip to contentSkip to conversation

merging swap prefetching

DISCUSSION Nick Piggin 2 participants 2 messages Jun 10, 2006

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

I wasn't aware there was a push to merge swap prefetching in 2.6.18, until the -mm merge plans post.

I would have expected to see some numbers, however I guess the "merge unless proven bad" approach for new features works too.

I had a quick look at the code, and I think it still needs more cleanup and review... it is vaguely difficult to participate in discussions about these patches because they are often split over several iterations of versions/fixes, and because it isn't always clear what they depend on (although in the case of swap prefetching, that isn't so much of a problem).

And also, there is no linux-mm thread to reply to... could we have some of the intrusive mm/ patches intended for 2.6.18 posted here before they get merged, or is that too much trouble?

As far as swap prefetching itself goes, I still don't like it much (same issues still stand), but with some cleaning up the patch shouldn't be too bad, and I can turn it off... so if people want it and if numbers show it is working, I wouldn't object.

Signature · 8 lines
SUSE Labs, Novell Inc.
Send instant messages to your online friends http://au.messenger.yahoo.com 

--
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>
#1 lore raw
Quoted 6 lines · On Sat, 10 Jun 2006 17:50:33 +1000 Nick Piggin <[email protected]> wrote:

I had a quick look at the code, and I think it still needs more cleanup and review... it is vaguely difficult to participate in discussions about these patches because they are often split over several iterations of versions/fixes, and because it isn't always clear what they depend on (although in the case of swap prefetching, that isn't so much of a problem).

I rolled all the patches together:

From: Con Kolivas <[email protected]>

Implement swap prefetching when the vm is relatively idle and there is free ram available. The code is based on some preliminary code by Thomas Schlichter.

This stores a list of swapped entries in a list ordered most recently used and a radix tree. It generates a low priority kernel thread running at nice 19 to do the prefetching at a later stage.

Once pages have been added to the swapped list, a timer is started, testing for conditions suitable to prefetch swap pages every 5 seconds. Suitable conditions are defined as lack of swapping out or in any pages, and no watermark tests failing. Significant amounts of dirtied ram and changes in free ram representing disk writes or reads also prevent prefetching.

It then checks that we have spare ram looking for at least 3* pages_high free per zone and if it succeeds that will prefetch pages from swap into the swap cache. The pages are added to the tail of the inactive list to preserve LRU ordering.

Pages are prefetched until the list is empty or the vm is seen as busy according to the previously described criteria. Node data on numa is stored with the entries and an appropriate zonelist based on this is used when allocating ram.

The pages are copied to swap cache and kept on backing store. This allows pressure on either physical ram or swap to readily find free pages without further I/O.

Prefetching can be enabled/disabled via the tunable in /proc/sys/vm/swap_prefetch initially set to 1 (enabled).

Enabling laptop_mode disables swap prefetching to prevent unnecessary spin ups.

In testing on modern pc hardware this results in wall-clock time activation of the firefox browser to speed up 5 fold after a worst case complete swap-out of the browser on a static web page.

From: Ingo Molnar <[email protected]>

Fix potential swap-prefetch deadlock, found by the locking correctness validator.

---

 Documentation/sysctl/vm.txt   |   11 
 include/linux/mm_inline.h     |    7 
 include/linux/swap-prefetch.h |   55 +++
 include/linux/swap.h          |    2 
 include/linux/sysctl.h        |    2 
 init/Kconfig                  |   22 +
 kernel/sysctl.c               |   11 
 mm/Makefile                   |    1 
 mm/swap.c                     |   48 ++
 mm/swap_prefetch.c            |  579 ++++++++++++++++++++++++++++++++
 mm/swap_state.c               |   11 
 mm/vmscan.c                   |    5 
 12 files changed, 752 insertions(+), 2 deletions(-)
Documentation/sysctl/vm.txt renamed from Documentation/sysctl/vm.txt~mm-implement-swap-prefetching +11 -0
diff -puN Documentation/sysctl/vm.txt~mm-implement-swap-prefetching Documentation/sysctl/vm.txt
@@ -30,6 +30,7 @@ Currently, these files are in /proc/sys/
 - zone_reclaim_mode
 - zone_reclaim_interval
 - panic_on_oom
+- swap_prefetch
 
 ==============================================================
 
@@ -191,3 +192,13 @@ rather than killing rogue processes, set
 
 The default value is 0.
 
+==============================================================
+
+swap_prefetch
+
+This enables or disables the swap prefetching feature. When the virtual
+memory subsystem has been extremely idle for at least 5 seconds it will start
+copying back pages from swap into the swapcache and keep a copy in swap. In
+practice it can take many minutes before the vm is idle enough.
+
+The default value is 1.
include/linux/mm_inline.h renamed from include/linux/mm_inline.h~mm-implement-swap-prefetching +7 -0
diff -puN include/linux/mm_inline.h~mm-implement-swap-prefetching include/linux/mm_inline.h
@@ -14,6 +14,13 @@ add_page_to_inactive_list(struct zone *z
 }
 
 static inline void
+add_page_to_inactive_list_tail(struct zone *zone, struct page *page)
+{
+	list_add_tail(&page->lru, &zone->inactive_list);
+	zone->nr_inactive++;
+}
+
+static inline void
 del_page_from_active_list(struct zone *zone, struct page *page)
 {
 	list_del(&page->lru);
include/linux/swap.h renamed from include/linux/swap.h~mm-implement-swap-prefetching +2 -0
diff -puN include/linux/swap.h~mm-implement-swap-prefetching include/linux/swap.h
@@ -173,6 +173,7 @@ extern unsigned int nr_free_pagecache_pa
 /* linux/mm/swap.c */
 extern void FASTCALL(lru_cache_add(struct page *));
 extern void FASTCALL(lru_cache_add_active(struct page *));
+extern void FASTCALL(lru_cache_add_tail(struct page *));
 extern void FASTCALL(activate_page(struct page *));
 extern void FASTCALL(mark_page_accessed(struct page *));
 extern void lru_add_drain(void);
@@ -228,6 +229,7 @@ extern void free_pages_and_swap_cache(st
 extern struct page * lookup_swap_cache(swp_entry_t);
 extern struct page * read_swap_cache_async(swp_entry_t, struct vm_area_struct *vma,
 					   unsigned long addr);
+extern int add_to_swap_cache(struct page *page, swp_entry_t entry);
 /* linux/mm/swapfile.c */
 extern long total_swap_pages;
 extern unsigned int nr_swapfiles;
include/linux/sysctl.h renamed from include/linux/sysctl.h~mm-implement-swap-prefetching +1 -1
diff -puN include/linux/sysctl.h~mm-implement-swap-prefetching include/linux/sysctl.h
@@ -191,9 +191,9 @@ enum
 	VM_ZONE_RECLAIM_MODE=31, /* reclaim local zone memory before going off node */
 	VM_PANIC_ON_OOM=33,	/* panic at out-of-memory */
 	VM_VDSO_ENABLED=34,	/* map VDSO into new processes? */
+	VM_SWAP_PREFETCH=35,	/* swap prefetch */
 };
 
-
 /* CTL_NET names: */
 enum
 {
init/Kconfig renamed from init/Kconfig~mm-implement-swap-prefetching +22 -0
diff -puN init/Kconfig~mm-implement-swap-prefetching init/Kconfig
@@ -100,6 +100,28 @@ config SWAP
 	  used to provide more virtual memory than the actual RAM present
 	  in your computer.  If unsure say Y.
 
+config SWAP_PREFETCH
+	bool "Support for prefetching swapped memory"
+	depends on SWAP
+	default y
+	---help---
+	  This option will allow the kernel to prefetch swapped memory pages
+	  when idle. The pages will be kept on both swap and in swap_cache
+	  thus avoiding the need for further I/O if either ram or swap space
+	  is required.
+
+	  What this will do on workstations is slowly bring back applications
+	  that have swapped out after memory intensive workloads back into
+	  physical ram if you have free ram at a later stage and the machine
+	  is relatively idle. This means that when you come back to your
+	  computer after leaving it idle for a while, applications will come
+	  to life faster. Note that your swap usage will appear to increase
+	  but these are cached pages, can be dropped freely by the vm, and it
+	  should stabilise around 50% swap usage maximum.
+
+	  Workstations and multiuser workstation servers will most likely want
+	  to say Y.
+
 config SYSVIPC
 	bool "System V IPC"
 	---help---
kernel/sysctl.c renamed from kernel/sysctl.c~mm-implement-swap-prefetching +11 -0
diff -puN kernel/sysctl.c~mm-implement-swap-prefetching kernel/sysctl.c
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/slab.h>
+#include <linux/swap-prefetch.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <linux/capability.h>
@@ -948,6 +949,16 @@ static ctl_table vm_table[] = {
 		.extra1		= &zero,
 	},
 #endif
+#ifdef CONFIG_SWAP_PREFETCH
+	{
+		.ctl_name	= VM_SWAP_PREFETCH,
+		.procname	= "swap_prefetch",
+		.data		= &swap_prefetch,
+		.maxlen		= sizeof(swap_prefetch),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+#endif
 	{ .ctl_name = 0 }
 };
 
mm/Makefile renamed from mm/Makefile~mm-implement-swap-prefetching +1 -0
diff -puN mm/Makefile~mm-implement-swap-prefetching mm/Makefile
@@ -13,6 +13,7 @@ obj-y			:= bootmem.o filemap.o mempool.o
 			   prio_tree.o util.o mmzone.o $(mmu-y)
 
 obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o thrash.o
+obj-$(CONFIG_SWAP_PREFETCH) += swap_prefetch.o
 obj-$(CONFIG_HUGETLBFS)	+= hugetlb.o
 obj-$(CONFIG_NUMA) 	+= mempolicy.o
 obj-$(CONFIG_SPARSEMEM)	+= sparse.o
mm/swap.c renamed from mm/swap.c~mm-implement-swap-prefetching +48 -0

83 lines not on this page · raw message

mm/swap_prefetch.c new file +579 -0

579 lines not on this page · raw message

mm/swap_state.c renamed from mm/swap_state.c~mm-implement-swap-prefetching +10 -1
diff -puN mm/swap_state.c~mm-implement-swap-prefetching mm/swap_state.c
@@ -10,6 +10,7 @@
 #include <linux/mm.h>
 #include <linux/kernel_stat.h>
 #include <linux/swap.h>
+#include <linux/swap-prefetch.h>
 #include <linux/init.h>
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
@@ -82,6 +83,7 @@ static int __add_to_swap_cache(struct pa
 		error = radix_tree_insert(&swapper_space.page_tree,
 						entry.val, page);
 		if (!error) {
+			remove_from_swapped_list(entry.val);
 			page_cache_get(page);
 			SetPageLocked(page);
 			SetPageSwapCache(page);
@@ -95,11 +97,12 @@ static int __add_to_swap_cache(struct pa
 	return error;
 }
 
-static int add_to_swap_cache(struct page *page, swp_entry_t entry)
+int add_to_swap_cache(struct page *page, swp_entry_t entry)
 {
 	int error;
 
 	if (!swap_duplicate(entry)) {
+		remove_from_swapped_list(entry.val);
 		INC_CACHE_INFO(noent_race);
 		return -ENOENT;
 	}
@@ -148,6 +151,9 @@ int add_to_swap(struct page * page, gfp_
 	swp_entry_t entry;
 	int err;
 
+	/* Swap prefetching is delayed if we're swapping pages */
+	delay_swap_prefetch();
+
 	BUG_ON(!PageLocked(page));
 
 	for (;;) {
@@ -320,6 +326,9 @@ struct page *read_swap_cache_async(swp_e
 	struct page *found_page, *new_page = NULL;
 	int err;
 
+	/* Swap prefetching is delayed if we're already reading from swap */
+	delay_swap_prefetch();
+
 	do {
 		/*
 		 * First check the swap cache.  Since this is normally
mm/vmscan.c renamed from mm/vmscan.c~mm-implement-swap-prefetching +5 -0
diff -puN mm/vmscan.c~mm-implement-swap-prefetching mm/vmscan.c
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/kernel_stat.h>
 #include <linux/swap.h>
+#include <linux/swap-prefetch.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
@@ -395,6 +396,7 @@ int remove_mapping(struct address_space 
 
 	if (PageSwapCache(page)) {
 		swp_entry_t swap = { .val = page_private(page) };
+		add_to_swapped_list(page);
 		__delete_from_swap_cache(page);
 		write_unlock_irq(&mapping->tree_lock);
 		swap_free(swap);
@@ -975,6 +977,7 @@ unsigned long try_to_free_pages(struct z
 		.swappiness = vm_swappiness,
 	};
 
+	delay_swap_prefetch();
 	count_vm_event(ALLOCSTALL);
 
 	for (i = 0; zones[i] != NULL; i++) {
@@ -1356,6 +1359,8 @@ unsigned long shrink_all_memory(unsigned
 		.swappiness = vm_swappiness,
 	};
 
+	delay_swap_prefetch();
+
 	current->reclaim_state = &reclaim_state;
 
 	lru_pages = 0;
include/linux/swap-prefetch.h new file +55 -0

55 lines not on this page · raw message

_

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>