mm: Implement swap prefetching
Subsystems (7)
PATCH 1/1 mm: Implement swap prefetching
Resync unchanged with 2.6.16-rc4-mm2.
Cheers,
Con
---
This patch implements 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.
Documentation/sysctl/vm.txt | 11 include/linux/mm_inline.h | 7 include/linux/swap.h | 55 ++++ include/linux/sysctl.h | 1 init/Kconfig | 22 + kernel/sysctl.c | 10 mm/Makefile | 1 mm/swap.c | 43 +++ mm/swap_prefetch.c | 496 ++++++++++++++++++++++++++++++++++++++++++++ mm/swap_state.c | 10 mm/vmscan.c | 5 11 files changed, 660 insertions(+), 1 deletion(-)
Documentation/sysctl/vm.txt +11 -0
@@ -29,6 +29,7 @@ Currently, these files are in /proc/sys/ - drop-caches - zone_reclaim_mode - zone_reclaim_interval +- swap_prefetch ==============================================================
@@ -178,3 +179,13 @@ Time is set in seconds and set by defaul Reduce the interval if undesired off node allocations occur. However, too frequent scans will have a negative impact onoff node allocation performance. +============================================================== + +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/swap.h +55 -0
79 lines not on this page · raw message
include/linux/sysctl.h +1 -0
@@ -185,6 +185,7 @@ enumVM_PERCPU_PAGELIST_FRACTION =30 ,/* int: fraction of pages in each percpu_pagelist */ VM_ZONE_RECLAIM_MODE =31 ,/* reclaim local zone memory before going off node */ VM_ZONE_RECLAIM_INTERVAL =32 ,/* time period to wait after reclaim failure */ + VM_SWAP_PREFETCH=33, /* swap prefetch */ };
init/Kconfig +22 -0
@@ -92,6 +92,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 +10 -0
@@ -901,6 +901,16 @@ static ctl_table vm_table[] = { .strategy = &sysctl_jiffies, },#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 +1 -0
@@ -13,6 +13,7 @@ obj-y := bootmem.o filemap.o mempool.o prio_tree.o util.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 +43 -0
54 lines not on this page · raw message
mm/swap_prefetch.c new file +496 -0
496 lines not on this page · raw message
mm/swap_state.c +9 -1
@@ -81,6 +81,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);
@@ -94,11 +95,12 @@ static int __add_to_swap_cache(struct pareturn 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 ; }
@@ -147,6 +149,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 (); +if (!PageLocked (page))BUG ();
@@ -320,6 +325,9 @@ struct page *read_swap_cache_async(swp_estruct 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 +5 -0
@@ -390,6 +390,7 @@ static int remove_mapping(struct addressif (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);
@@ -1451,6 +1452,8 @@ unsigned long try_to_free_pages(struct z .may_swap = 1, }; +delay_swap_prefetch (); +inc_page_state (allocstall);for (i =0 ; zones[i] !=NULL ; i++) {
@@ -1794,6 +1797,8 @@ int shrink_all_memory(unsigned long nr_p .reclaimed_slab = 0, }; +delay_swap_prefetch (); + current->reclaim_state = &reclaim_state;for_each_pgdat (pgdat) {int freed;
include/linux/mm_inline.h +7 -0
@@ -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);
--
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>