Skip to contentSkip to conversation

vm - swap_prefetch-15

PATCH In review Con Kolivas 5 participants 14 messages Oct 6, 2005 – Oct 7, 2005

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

PATCH 1/1 vm - swap_prefetch-15

The last known bugs were addressed in this latest version of the swap prefetching patch. Thanks to the testers out there who helped it get this far.

-Prefetched pages weren't handled properly by the lru lists. -Prefetch groups are now 10 times larger when laptop_mode is enabled thus decreasing the amount of time spent prefetching and thus the disk spinning. -Documentation as suggested by Ingo Oeser

Incremental patches and latest available here:
http://ck.kolivas.org/patches/swap-prefetch/

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 early work 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. The pages are prefetched in 128kb groups every 1 second until the vm is busy for the tests above, the watermarks fail to detect adequate free ram or the list is emptied. 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.

The amount prefetched in each group is configurable via the tunable in /proc/sys/vm/swap_prefetch . This is set to 2 by default (256kb). When laptop_mode is enabled it prefetches in ten times larger blocks to minimise the time spent reading.

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 an static web page.

 include/linux/swap.h   |   33 +++
 include/linux/sysctl.h |    1
 init/Kconfig           |   21 ++
 kernel/sysctl.c        |   12 +
 mm/Makefile            |    1
 mm/page_alloc.c        |   14 +
 mm/swap.c              |    3
 mm/swap_prefetch.c     |  445 +++++++++++++++++++++++++++++++++++++++++++++++++
 mm/swap_state.c        |   10 -
 mm/vmscan.c            |    5
 10 files changed, 540 insertions(+), 5 deletions(-)
include/linux/swap.h +33 -0
Index: linux-2.6.13-sp/include/linux/swap.h
===================================================================
@@ -185,6 +185,38 @@ extern int shmem_unuse(swp_entry_t entry
 
 extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *);
 
+#ifdef CONFIG_SWAP_PREFETCH
+/* only used by prefetch externally */
+/*	mm/swap_prefetch.c */
+extern void prepare_prefetch(void);
+extern void add_to_swapped_list(unsigned long index);
+extern void remove_from_swapped_list(unsigned long index);
+extern void delay_prefetch(void);
+/* linux/mm/page_alloc.c */
+extern struct page *
+buffered_rmqueue(struct zone *zone, int order, unsigned int __nocast gfp_flags);
+extern void zone_statistics(struct zonelist *zonelist, struct zone *z);
+extern int swap_prefetch;
+
+#else	/* CONFIG_SWAP_PREFETCH */
+static inline void add_to_swapped_list(unsigned long index)
+{
+}
+
+static inline void prepare_prefetch(void)
+{
+}
+
+static inline void remove_from_swapped_list(unsigned long index)
+{
+}
+
+static inline void delay_prefetch(void)
+{
+}
+
+#endif	/* CONFIG_SWAP_PREFETCH */
+
 #ifdef CONFIG_SWAP
 /* linux/mm/page_io.c */
 extern int swap_readpage(struct file *, struct page *);
@@ -206,6 +238,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 +1 -0
Index: linux-2.6.13-sp/include/linux/sysctl.h
===================================================================
@@ -180,6 +180,7 @@ enum
 	VM_VFS_CACHE_PRESSURE=26, /* dcache/icache reclaim pressure */
 	VM_LEGACY_VA_LAYOUT=27, /* legacy/compatibility virtual address space layout */
 	VM_SWAP_TOKEN_TIMEOUT=28, /* default time for token time out */
+	VM_SWAP_PREFETCH=29,	/* int: amount to swap prefetch */
 };
 
 
init/Kconfig +21 -0
Index: linux-2.6.13-sp/init/Kconfig
===================================================================
@@ -87,6 +87,27 @@ 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 n
+	---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.
+	  
+	  Desktop users will most likely want to say Y.
+
 config SYSVIPC
 	bool "System V IPC"
 	depends on MMU
kernel/sysctl.c +12 -0
Index: linux-2.6.13-sp/kernel/sysctl.c
===================================================================
@@ -850,6 +850,18 @@ static ctl_table vm_table[] = {
 		.proc_handler	= &proc_dointvec_jiffies,
 		.strategy	= &sysctl_jiffies,
 	},
+#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,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &zero,
+	},
+#endif
 #endif
 	{ .ctl_name = 0 }
 };
mm/Makefile +1 -0
Index: linux-2.6.13-sp/mm/Makefile
===================================================================
@@ -13,6 +13,7 @@ obj-y			:= bootmem.o filemap.o mempool.o
 			   prio_tree.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/page_alloc.c +10 -4
Index: linux-2.6.13-sp/mm/page_alloc.c
===================================================================
@@ -607,7 +607,7 @@ void drain_local_pages(void)
 }
 #endif /* CONFIG_PM */
 
-static void zone_statistics(struct zonelist *zonelist, struct zone *z)
+void zone_statistics(struct zonelist *zonelist, struct zone *z)
 {
 #ifdef CONFIG_NUMA
 	unsigned long flags;
@@ -684,7 +684,7 @@ static inline void prep_zero_page(struct
  * we cheat by calling it from here, in the order > 0 path.  Saves a branch
  * or two.
  */
-static struct page *
+struct page *
 buffered_rmqueue(struct zone *zone, int order, unsigned int __nocast gfp_flags)
 {
 	unsigned long flags;
@@ -745,7 +745,7 @@ int zone_watermark_ok(struct zone *z, in
 		min -= min / 4;
 
 	if (free_pages <= min + z->lowmem_reserve[classzone_idx])
-		return 0;
+		goto out_failed;
 	for (o = 0; o < order; o++) {
 		/* At the next order, this order's pages become unavailable */
 		free_pages -= z->free_area[o].nr_free << o;
@@ -754,9 +754,15 @@ int zone_watermark_ok(struct zone *z, in
 		min >>= 1;
 
 		if (free_pages <= min)
-			return 0;
+			goto out_failed;
 	}
+
 	return 1;
+out_failed:
+	/* Swap prefetching is delayed if any watermark is low */
+	delay_prefetch();
+
+	return 0;	
 }
 
 static inline int
mm/swap.c +3 -0
Index: linux-2.6.13-sp/mm/swap.c
===================================================================
@@ -481,5 +481,8 @@ void __init swap_setup(void)
 	 * Right now other parts of the system means that we
 	 * _really_ don't want to cluster much more
 	 */
+
+	prepare_prefetch();
+
 	hotcpu_notifier(cpu_swap_callback, 0);
 }
mm/swap_prefetch.c +445 -0

445 lines not on this page · raw message

mm/swap_state.c +9 -1
Index: linux-2.6.13-sp/mm/swap_state.c
===================================================================
@@ -80,6 +80,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);
@@ -93,11 +94,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;
 	}
@@ -145,6 +147,9 @@ int add_to_swap(struct page * page)
 	swp_entry_t entry;
 	int err;
 
+	/* Swap prefetching is delayed if we're swapping pages */
+	delay_prefetch();
+
 	if (!PageLocked(page))
 		BUG();
 
@@ -325,6 +330,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_prefetch();
+
 	do {
 		/*
 		 * First check the swap cache.  Since this is normally
mm/vmscan.c +5 -0
Index: linux-2.6.13-sp/mm/vmscan.c
===================================================================
@@ -519,6 +519,7 @@ static int shrink_list(struct list_head 
 #ifdef CONFIG_SWAP
 		if (PageSwapCache(page)) {
 			swp_entry_t swap = { .val = page->private };
+			add_to_swapped_list(swap.val);
 			__delete_from_swap_cache(page);
 			write_unlock_irq(&mapping->tree_lock);
 			swap_free(swap);
@@ -929,6 +930,8 @@ int try_to_free_pages(struct zone **zone
 	unsigned long lru_pages = 0;
 	int i;
 
+	delay_prefetch();
+
 	sc.gfp_mask = gfp_mask;
 	sc.may_writepage = 0;
 	sc.may_swap = 1;
@@ -1275,6 +1278,8 @@ int shrink_all_memory(int nr_pages)
 		.reclaimed_slab = 0,
 	};
 
+	delay_prefetch();
+
 	current->reclaim_state = &reclaim_state;
 	for_each_pgdat(pgdat) {
 		int freed;
#1 lore raw

PATCH 1/1 vm - swap_prefetch-15 docs

Quoted 11 lines · Con Kolivas

The last known bugs were addressed in this latest version of the swap prefetching patch. Thanks to the testers out there who helped it get this far.

(quoted diff) +0 -2
-Prefetched pages weren't handled properly by the lru lists.
-Prefetch groups are now 10 times larger when laptop_mode is enabled thus

decreasing the amount of time spent prefetching and thus the disk spinning. -Documentation as suggested by Ingo Oeser

Incremental patches and latest available here:
http://ck.kolivas.org/patches/swap-prefetch/

And the docs...

Cheers,
Con
---

Documentation/sysctl/vm.txt +12 -0
Index: linux-2.6.13-ck7/Documentation/sysctl/vm.txt
===================================================================
@@ -26,6 +26,7 @@ Currently, these files are in /proc/sys/
 - min_free_kbytes
 - laptop_mode
 - block_dump
+- swap_prefetch
 
 ==============================================================
 
@@ -102,3 +103,14 @@ This is used to force the Linux VM to ke
 of kilobytes free.  The VM uses this number to compute a pages_min
 value for each lowmem zone in the system.  Each lowmem zone gets 
 a number of reserved free pages based proportionally on its size.
+
+==============================================================
+
+swap_prefetch
+
+This is the amount of data prefetched per prefetching interval when
+swap prefetching is compiled in. The value means multiples of 128K,
+except when laptop_mode is enabled and then it is ten times larger.
+Setting it to 0 disables prefetching entirely.
+
+The default value is 2.
#2 lore raw
In reply to Con Kolivas

Hi Con,

A teeny-weeny nitpick:

Quoted 1 line · Con Kolivas

+struct swapped_root_t {

[snip]

Quoted 1 line

+struct swapped_entry_t {

[snip]

Since these are not typedefs, please drop the _t postfix.

Pekka

#3 lore raw
Quoted 7 lines · Pekka Enberg

Hi Con,

A teeny-weeny nitpick:

Quoted 1 line · Con Kolivas

+struct swapped_root_t {

Quoted 7 lines

[snip]

Quoted 1 line

+struct swapped_entry_t {

[snip]

Since these are not typedefs, please drop the _t postfix.

Good point, thanks! Any and all feedback is appreciated.

Cheers,
Con

#4 lore raw

Hi,

Quoted 1 line · Con Kolivas

Good point, thanks! Any and all feedback is appreciated.

Well, since you asked :-)

mm/swap_prefetch.c line 34

Quoted 7 lines
mm/swap_prefetch.c +7 -0
+/*
+ * How many pages to prefetch at a time. We prefetch SWAP_CLUSTER_MAX *
+ * swap_prefetch per PREFETCH_INTERVAL, but prefetch ten times as much at a
+ * time in laptop_mode to minimise the time we keep the disk spinning.
+ */
+#define PREFETCH_PAGES()     (SWAP_CLUSTER_MAX * swap_prefetch * \
+                                     (1 + 9 * laptop_mode))

This looks strange. Please either drop the parenthesis from PREFETCH_PAGES or make it a real static inline function.

mm/swap_prefetch.c line 183

Quoted 7 lines
mm/swap_prefetch.c +7 -0
+/*
+ * Find the zone with the most free pages, recheck the watermarks and
+ * then directly allocate the ram. We don't want prefetch to use
+ * __alloc_pages and go calling on reclaim.
+ */
+static struct page *prefetch_get_page(void)
+{

Should this be put in mm/page_alloc.c? It is, after all, a special-purpose page allocator. That way you wouldn't have to export zone_statistics and buffered_rmqueue.

mm/swap_prefetch.c line 355

Quoted 10 lines
mm/swap_prefetch.c +10 -0
+/*
+ * trickle_swap is the main function that initiates the swap prefetching. It
+ * first checks to see if the busy flag is set, and does not prefetch if it
+ * is, as the flag implied we are low on memory or swapping in currently.
+ * Otherwise it runs till PREFETCH_PAGES() are prefetched.
+ * This function returns 1 if it succeeds in a cycle of prefetching, 0 if it
+ * is interrupted or -1 if there is nothing left to prefetch.
+ */
+static int trickle_swap(void)
+{

This could perhaps use a three-state enum as return value. I find return value checks in kprefetchd() slightly confusing.

Pekka

#5 lore raw
Quoted 7 lines · Pekka Enberg

Hi,

Quoted 1 line · Con Kolivas

Good point, thanks! Any and all feedback is appreciated.

Well, since you asked :-)

Quoted 10 lines

mm/swap_prefetch.c line 34

Quoted 7 lines

+/*
+ * How many pages to prefetch at a time. We prefetch SWAP_CLUSTER_MAX *
+ * swap_prefetch per PREFETCH_INTERVAL, but prefetch ten times as much at a + * time in laptop_mode to minimise the time we keep the disk spinning. + */

mm/swap_prefetch.c +2 -0
+#define PREFETCH_PAGES()     (SWAP_CLUSTER_MAX * swap_prefetch * \
+                                     (1 + 9 * laptop_mode))

This looks strange. Please either drop the parenthesis from PREFETCH_PAGES or make it a real static inline function.

I have seen this sort of macro style before in the kernel where () just makes it clear that it is a function but a real static inline is ok with me.

Quoted 11 lines

mm/swap_prefetch.c line 183

Quoted 7 lines
mm/swap_prefetch.c +7 -0
+/*
+ * Find the zone with the most free pages, recheck the watermarks and
+ * then directly allocate the ram. We don't want prefetch to use
+ * __alloc_pages and go calling on reclaim.
+ */
+static struct page *prefetch_get_page(void)
+{

Should this be put in mm/page_alloc.c? It is, after all, a special-purpose page allocator. That way you wouldn't have to export zone_statistics and buffered_rmqueue.

Makes sense but it is only used in the CONFIG_SWAP_PREFETCH case so it would end up as a static inline in swap.h to avoid ending being #ifdefed in page_alloc.c. Do you think that's preferable to having it in swap_prefetch.c ?

Quoted 15 lines

Review

Quoted 12 lines

+/*
+ * trickle_swap is the main function that initiates the swap prefetching. It + * first checks to see if the busy flag is set, and does not prefetch if it + * is, as the flag implied we are low on memory or swapping in currently. + * Otherwise it runs till PREFETCH_PAGES() are prefetched.
+ * This function returns 1 if it succeeds in a cycle of prefetching, 0 if it + * is interrupted or -1 if there is nothing left to prefetch.
+ */

(quoted diff) +2 -0
+static int trickle_swap(void)
+{

This could perhaps use a three-state enum as return value. I find return value checks in kprefetchd() slightly confusing.

Good idea.

Thanks!
Con

#6 lore raw
Quoted 4 lines · Con Kolivas

Makes sense but it is only used in the CONFIG_SWAP_PREFETCH case so it would end up as a static inline in swap.h to avoid ending being #ifdefed in page_alloc.c. Do you think that's preferable to having it in swap_prefetch.c ?

But then you would still have to open up buffered_rmqueue() and zone_statistics() to everyone, no? How about you implement a new gfp flag __GFP_NEVER_RECLAIM similar to __GFP_NORECLAIM instead so you don't have to duplicate __page_alloc()?

Pekka

#7 lore raw
Quoted 8 lines · Pekka J Enberg
Quoted 4 lines · Con Kolivas

Makes sense but it is only used in the CONFIG_SWAP_PREFETCH case so it would end up as a static inline in swap.h to avoid ending being #ifdefed in page_alloc.c. Do you think that's preferable to having it in swap_prefetch.c ?

But then you would still have to open up buffered_rmqueue() and zone_statistics() to everyone, no?

bah of course.. /me slaps forehead

Quoted 3 lines

How about you implement a new gfp flag
__GFP_NEVER_RECLAIM similar to __GFP_NORECLAIM instead so you don't have to duplicate __page_alloc()?

That will end up being far more intrusive than this version and __alloc_pages would need more tests that affect every call to __alloc_pages which seems much more expensive to me than exporting buffered_rmqueue and zone_statistics, and the modified __alloc_pages will still be a much more complicated function than prefetch_get_page.

Thanks,
Con

#8 lore raw
Quoted 5 lines · Con Kolivas

That will end up being far more intrusive than this version and __alloc_pages would need more tests that affect every call to __alloc_pages which seems much more expensive to me than exporting buffered_rmqueue and zone_statistics, and the modified __alloc_pages will still be a much more complicated function than prefetch_get_page.

Short-term, perhaps. However, what you are doing is inventing your own page allocator which, I suspect, is more expensive in the long term.

Up to you of course and I am probably the wrong person to talk to about this. Never the less, here's a totally untested patch to do it.

Pekka

include/linux/gfp.h +1 -0
Index: 2.6/include/linux/gfp.h
===================================================================
@@ -41,6 +41,7 @@ struct vm_area_struct;
 #define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */
 #define __GFP_NORECLAIM  0x20000u /* No realy zone reclaim during allocation */
 #define __GFP_HARDWALL   0x40000u /* Enforce hardwall cpuset memory allocs */
+#define __GFP_NEVER_RECLAIM 0x80000u /* Never attempt to reclaim */
 
 #define __GFP_BITS_SHIFT 20	/* Room for 20 __GFP_FOO bits */
 #define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1)
mm/page_alloc.c +6 -1
Index: 2.6/mm/page_alloc.c
===================================================================
@@ -778,6 +778,7 @@ __alloc_pages(unsigned int __nocast gfp_
 		struct zonelist *zonelist)
 {
 	const int wait = gfp_mask & __GFP_WAIT;
+	const int can_reclaim = !(gfp_mask & __GFP_NEVER_RECLAIM);
 	struct zone **zones, *z;
 	struct page *page;
 	struct reclaim_state reclaim_state;
@@ -812,7 +813,7 @@ restart:
 	 * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
 	 */
 	for (i = 0; (z = zones[i]) != NULL; i++) {
-		int do_reclaim = should_reclaim_zone(z, gfp_mask);
+		int do_reclaim = can_reclaim && should_reclaim_zone(z, gfp_mask);
 
 		if (!cpuset_zone_allowed(z, __GFP_HARDWALL))
 			continue;
@@ -840,6 +841,9 @@ zone_reclaim_retry:
 			goto got_pg;
 	}
 
+	if (unlikely(!can_reclaim))
+		goto out;
+
 	for (i = 0; (z = zones[i]) != NULL; i++)
 		wakeup_kswapd(z, order);
 
@@ -966,6 +970,7 @@ nopage:
 		dump_stack();
 		show_mem();
 	}
+out:
 	return NULL;
 got_pg:
 	zone_statistics(zonelist, z);
#9 lore raw
In reply to Pekka Enberg
Quoted 7 lines · Pekka Enberg

Hi,

Quoted 1 line · Con Kolivas

Good point, thanks! Any and all feedback is appreciated.

Well, since you asked :-)

Quoted 10 lines

mm/swap_prefetch.c line 34

Quoted 7 lines
mm/swap_prefetch.c +7 -0
+/*
+ * How many pages to prefetch at a time. We prefetch SWAP_CLUSTER_MAX *
+ * swap_prefetch per PREFETCH_INTERVAL, but prefetch ten times as much at a
+ * time in laptop_mode to minimise the time we keep the disk spinning.
+ */
+#define PREFETCH_PAGES()     (SWAP_CLUSTER_MAX * swap_prefetch * \
+                                     (1 + 9 * laptop_mode))

This looks strange. Please either drop the parenthesis from PREFETCH_PAGES or make it a real static inline function.

Or make it a "const static" variable, so compiler will check types and everything, but the symbol will not be present in the binary, causing no overhead. So it could be:

const unsigned PREFETCH_PAGES = (SWAP_CLUSTER_MAX * swap_prefetch * \
        (1 + 9 * laptop_mode));

--
Gustavo Sverzut Barbieri
---------------------------------------
Computer Engineer 2001 - UNICAMP
GPSL - Grupo Pro Software Livre
Cell..: +55 (19) 9165 8010
Jabber: [email protected]
ICQ#: 17249123
MSN: [email protected]
Skype: gsbarbieri
GPG: 0xB640E1A2 @ wwwkeys.pgp.net

#10 lore raw
Quoted 6 lines

Or make it a "const static" variable, so compiler will check types and everything, but the symbol will not be present in the binary, causing no overhead. So it could be:

const unsigned PREFETCH_PAGES = (SWAP_CLUSTER_MAX * swap_prefetch * \
        (1 + 9 * laptop_mode));

This won't work, AFAICT. swap_prefetch and laptop_mode are variables, but with the code above, they would be evaluated only once. And maybe the compiler will reject that code immediately...

Rudo.

#11 lore raw
Quoted 10 lines · Rudo Thomas
Quoted 6 lines

Or make it a "const static" variable, so compiler will check types and everything, but the symbol will not be present in the binary, causing no overhead. So it could be:

const unsigned PREFETCH_PAGES = (SWAP_CLUSTER_MAX * swap_prefetch * \
        (1 + 9 * laptop_mode));

This won't work, AFAICT. swap_prefetch and laptop_mode are variables, but with the code above, they would be evaluated only once. And maybe the compiler will reject that code immediately...

Ah... yes, you're right! These may change in runtime.

--
Gustavo Sverzut Barbieri
---------------------------------------
Computer Engineer 2001 - UNICAMP
GPSL - Grupo Pro Software Livre
Cell..: +55 (19) 9165 8010
Jabber: [email protected]
ICQ#: 17249123
MSN: [email protected]
Skype: gsbarbieri
GPG: 0xB640E1A2 @ wwwkeys.pgp.net

#12 lore raw
In reply to Con Kolivas
Quoted 9 lines · Con Kolivas

The last known bugs were addressed in this latest version of the swap prefetching patch. Thanks to the testers out there who helped it get this far.

(quoted diff) +0 -2
-Prefetched pages weren't handled properly by the lru lists.
-Prefetch groups are now 10 times larger when laptop_mode is enabled thus

decreasing the amount of time spent prefetching and thus the disk spinning. -Documentation as suggested by Ingo Oeser

Quoted 3 lines

Incremental patches and latest available here:
http://ck.kolivas.org/patches/swap-prefetch/

Ciao Con,
i downloading right now kernel 2.6.14-rc3 and your latest patch (v15), in the weekend I'll update my Ubuntu platform and I'll like to compare performance of vanilla vs vm-swap_prefetch.

Any hint about what kind of instrumentation I could use in order to get interesting and useful numbers ?

Thanks!

Regards,
--
Paolo
http://technologynews.altervista.org

#13 lore raw
Quoted 10 lines · Paolo Ciarrocchi
Quoted 9 lines · Con Kolivas

The last known bugs were addressed in this latest version of the swap prefetching patch. Thanks to the testers out there who helped it get this far.

(quoted diff) +0 -2
-Prefetched pages weren't handled properly by the lru lists.
-Prefetch groups are now 10 times larger when laptop_mode is enabled thus

decreasing the amount of time spent prefetching and thus the disk spinning. -Documentation as suggested by Ingo Oeser

Quoted 7 lines
Quoted 2 lines

Incremental patches and latest available here:
http://ck.kolivas.org/patches/swap-prefetch/

Ciao Con,
i downloading right now kernel 2.6.14-rc3 and your latest patch (v15), in the weekend I'll update my Ubuntu platform and I'll like to compare performance of vanilla vs vm-swap_prefetch.

Great!

Quoted 2 lines

Any hint about what kind of instrumentation I could use in order to get interesting and useful numbers ?

To get some useful advantage from it you have to have a workload that swaps on your hardware in the first place. I have a simple mechanism to induce it reliably where I open a few large applications concurrently - browser and office suite come to mind, then create my swap load:

tail -f /dev/zero

works real nice. Either let it run to completion and hope that tail gets oom-killed or ctrl-c it after you've used up half your swapspace. Then I usually let vmstat 1 run in the background. Leave the machine for 5 or 10 minutes and do simple wallclock time from the moment you click on the application till it is available. Try changing swap_prefetch from 2 to 0 in /proc/sys/vm/swap_prefetch to compare the difference. This is a very coarse and somewhat contrived example, but even in real world settings where you hit swapspace during normal usage it is slowly trickling in in the background and I find it makes a noticeable difference.

If you watch vmstat with swap_prefetch enabled, you'll notice it doing SI of 256KB (at default setting of swap_prefetch==2) every second when the machine is very idle. Then after all the pages have been prefetched, when you click on the application you shouldn't see anything in SI at all implying no swap in. You can see how many entries are currently in the prefetch swaplist easily enough with
cat /proc/slabinfo | grep swapped_entry

where the first numeric column of active objects shows the number of pages in the list (not all of them will result in a swapped in page).

Cheers,
Con