Re: [PATCH][RFC] appling preasure to icache and dcache

Ed Tomlinson (tomlins@cam.org)
Mon, 2 Apr 2001 08:58:21 -0400


Hi,

The patch in the last message was scrambled. The last two lines
belong to the previous fragment. Here is the correct beast.

Ed Tomlinson <tomlins@cam.org

---
diff -u -r --exclude-from=ex.txt linux.ac28/mm/page_alloc.c linux/mm/page_alloc.c
--- linux.ac28/mm/page_alloc.c	Sun Apr  1 18:52:22 2001
+++ linux/mm/page_alloc.c	Mon Apr  2 07:54:05 2001
@@ -138,11 +138,9 @@
 
 	/*
 	 * We don't want to protect this variable from race conditions
-	 * since it's nothing important, but we do want to make sure
-	 * it never gets negative.
+	 * since it's nothing important.
 	 */
-	if (memory_pressure > NR_CPUS)
-		memory_pressure--;
+	inactivate_pressure++;
 }
 
 #define MARK_USED(index, order, area) \
diff -u -r --exclude-from=ex.txt linux.ac28/mm/swap.c linux/mm/swap.c
--- linux.ac28/mm/swap.c	Mon Jan 22 16:30:21 2001
+++ linux/mm/swap.c	Thu Mar 29 11:37:47 2001
@@ -47,10 +47,12 @@
  * many inactive pages we should have.
  *
  * In reclaim_page and __alloc_pages: memory_pressure++
- * In __free_pages_ok: memory_pressure--
+ * In __free_pages_ok: inactivate_pressure++
+ * In invalidate_pages_scan: inactivate_pressure++
  * In recalculate_vm_stats the value is decayed (once a second)
  */
 int memory_pressure;
+int inactivate_pressure;
 
 /* We track the number of pages currently being asynchronously swapped
    out, so that we don't try to swap TOO many pages out at once */
@@ -287,6 +289,7 @@
 	 * memory_pressure.
 	 */
 	memory_pressure -= (memory_pressure >> INACTIVE_SHIFT);
+	inactivate_pressure -= (inactivate_pressure >> INACTIVE_SHIFT);
 }
 
 /*
diff -u -r --exclude-from=ex.txt linux.ac28/mm/vmscan.c linux/mm/vmscan.c
--- linux.ac28/mm/vmscan.c	Sun Apr  1 18:52:22 2001
+++ linux/mm/vmscan.c	Mon Apr  2 07:42:55 2001
@@ -759,6 +791,8 @@
 	}
 	spin_unlock(&pagemap_lru_lock);
 
+	inactivate_pressure += nr_deactivated;
+
 	return nr_deactivated;
 }
 
@@ -937,6 +971,76 @@
 	return ret;
 }
 
+/*
+ * Try to shrink the dcache if either its size or free space
+ * has grown, and it looks like we might get the required pages.
+ * This function would simplify if the caches tracked how
+ * many _pages_ were freeable.
+ */
+int try_shrinking_dcache(int goal, unsigned int gfp_mask)
+{
+
+	/* base - projects the threshold above which we can free pages */
+	
+	static int base, free = 0;
+	int pages, old, ret;
+
+	old = free;			/* save old free space size */
+
+	pages = (dentry_stat.nr_dentry * sizeof(struct dentry)) >> PAGE_SHIFT;
+	free = (dentry_stat.nr_unused * sizeof(struct dentry)) >> PAGE_SHIFT;
+
+	if (base > pages)	/* If the cache shrunk reset base,  The cache
+		base = pages;	 * growing applies preasure as does expanding
+	if (free > old)		 * free space - even if later shrinks */
+		base -= (base>free-old) ? free-old : base;
+
+	/* try free pages...  Note that the using inactive_pressure _is_
+	 * racy.  It does not matter, a bad guess will not hurt us.
+	 * Testing free here does not work effectivily.
+	 */
+	
+	if (pages-base >= goal) { 
+		ret = inactivate_pressure;
+       		shrink_dcache_memory(DEF_PRIORITY, gfp_mask);
+		ret = inactivate_pressure - ret; 
+		base += (!ret) ? pages-base : (ret>goal) ? ret : goal; 
+	} else
+		ret = 0;
+
+	return ret;
+}
+
+/*
+ * Same logic as above but for the icache.
+ */
+int try_shrinking_icache(int goal, unsigned int gfp_mask)
+{
+	static int base, free = 0;
+	int pages, old, ret;
+	
+	old = free;
+
+	pages = (inodes_stat.nr_inodes * sizeof(struct inode)) >> PAGE_SHIFT;
+	free = (inodes_stat.nr_unused * sizeof(struct inode)) >> PAGE_SHIFT;
+	
+	if (base > pages)
+		base = pages;
+	if (free > old)
+		base -= (base>free-old) ? free-old : base;
+
+	if (pages-base >= goal) { 
+		ret = inactivate_pressure;
+       		shrink_icache_memory(DEF_PRIORITY, gfp_mask);
+		ret = inactivate_pressure - ret; 
+		base += (!ret) ? pages-base : (ret>goal) ? ret : goal; 
+	} else
+		ret = 0;
+
+	return ret;
+}
+
+
 DECLARE_WAIT_QUEUE_HEAD(kswapd_wait);
 DECLARE_WAIT_QUEUE_HEAD(kswapd_done);
 struct task_struct *kswapd_task;
@@ -984,18 +1088,28 @@
 	 */
 	for (;;) {
 		static int recalc = 0;
+		int delta = 0;
 
 		/* If needed, try to free some memory. */
 		if (inactive_shortage() || free_shortage()) 
 			do_try_to_free_pages(GFP_KSWAPD, 0);
 
 		/*
-		 * Do some (very minimal) background scanning. This
-		 * will scan all pages on the active list once
-		 * every minute. This clears old referenced bits
-		 * and moves unused pages to the inactive list.
+		 * Try to keep the rate of pages inactivations 
+		 * similar to the rate of pages allocations.  This
+		 * also perform background page aging, but only
+		 * when there is preasure on the vm.  We get the
+		 * pages from the dcache and icache if its likely
+		 * there are enought freeable pages there.
 		 */
-		refill_inactive_scan(DEF_PRIORITY, 0);
+		delta = (memory_pressure >> INACTIVE_SHIFT) \
+			- (inactivate_pressure >> INACTIVE_SHIFT);
+		if (delta > 0)
+			delta -= try_shrinking_dcache(delta,GFP_KSWAPD);
+		if (delta > 0)
+			delta -= try_shrinking_icache(delta,GFP_KSWAPD);
+		if (delta > 0)
+			refill_inactive_scan(DEF_PRIORITY, delta);
 
 		/* Once a second, recalculate some VM stats. */
 		if (time_after(jiffies, recalc + HZ)) {
--- linux.ac28/include/linux/swap.h	Sun Apr  1 18:52:22 2001
+++ linux/include/linux/swap.h	Thu Mar 29 11:31:09 2001
@@ -102,6 +102,7 @@
 
 /* linux/mm/swap.c */
 extern int memory_pressure;
+extern int inactivate_pressure;
 extern void age_page_up(struct page *);
 extern void age_page_up_nolock(struct page *);
 extern void age_page_down(struct page *);
---
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/