Re: [patch] my latest oom stuff

Andrea Arcangeli (andrea@e-mind.com)
Wed, 4 Nov 1998 15:14:33 +0100 (CET)


On Tue, 3 Nov 1998, Linus Torvalds wrote:

>It also feels pretty good under other load. Do you concur?

The OOM problem seems solved fine after the merging. The only thing is
that I think you missed the GFP_USER in the swapin stage (at the end of
swap_state.c). I' ve seen that you fixed also some of my not very clever
schedule_timeout() usage, that' s very good, thanks ;-).

This patch implements my kswapd, add a sense to the swap cache find stats
and fix the last GFP_USER. I think that my kswapd is very better than
yours since you depends on the fact that your machine swapout many pages
in 10msec. It' s not good to depens in function of time (if we must run in
any kind of hardware). And I don' t agree with playing with p->counter.
The kswapd-run-all-the-time is no more an issue if you don' t play with
p->counter and without the RT flag (and scheduling() between
do_try_to_free_pages() if resched is needed of course ;-).

Index: linux/mm/swap_state.c
diff -u linux/mm/swap_state.c:1.1.1.2 linux/mm/swap_state.c:1.1.1.1.14.6
--- linux/mm/swap_state.c:1.1.1.2 Sat Oct 24 15:42:51 1998
+++ linux/mm/swap_state.c Wed Nov 4 14:59:40 1998
@@ -310,9 +334,14 @@
*/
found_page = lookup_swap_cache(entry);
if (found_page)
+ {
+#ifdef SWAP_CACHE_INFO
+ swap_cache_find_success++;
+#endif
goto out;
+ }

- new_page_addr = __get_free_page(GFP_KERNEL);
+ new_page_addr = __get_free_page(GFP_USER);
if (!new_page_addr)
goto out; /* Out of memory */
new_page = mem_map + MAP_NR(new_page_addr);
@@ -322,7 +351,20 @@
*/
found_page = lookup_swap_cache(entry);
if (found_page)
+ {
+#ifdef SWAP_CACHE_INFO
+ swap_cache_find_success++;
+#endif
goto out_free_page;
+ }
+
+#ifdef SWAP_CACHE_INFO
+ /*
+ * Not found in the swap cache.
+ */
+ swap_cache_find_total++;
+#endif
+
/*
* Make sure the swap entry is still in use.
*/
Index: linux/mm/vmscan.c
diff -u linux/mm/vmscan.c:1.1.1.7 linux/mm/vmscan.c:1.1.1.2.4.35
--- linux/mm/vmscan.c:1.1.1.7 Wed Nov 4 13:09:43 1998
+++ linux/mm/vmscan.c Wed Nov 4 14:28:45 1998
@@ -7,6 +7,8 @@
* kswapd added: 7.1.96 sct
* Removed kswapd_ctl limits, and swap out as many pages as needed
* to bring the system back to freepages.high: 2.4.97, Rik van Riel.
+ * Removed RT priority from kswapd. Now kswapd schedule() and runs as a normal
+ * process with dynamic priority in F(free_memory). 1998 Andrea Arcangeli
* Version: $Id: vmscan.c,v 1.5 1998/02/23 22:14:28 sct Exp $
*/

@@ -29,12 +31,6 @@
#include <asm/pgtable.h>

/*
- * How often do we do a pageout scan during normal conditions?
- * Default is four times a second.
- */
-int swapout_interval = HZ / 4;
-
-/*
* The wait queue for waking up the pageout daemon:
*/
struct task_struct * kswapd_task = NULL;
@@ -445,7 +441,7 @@
kmem_cache_reap(gfp_mask);

if (buffer_over_borrow() || pgcache_over_borrow())
- shrink_mmap(i, gfp_mask);
+ state = 0;

switch (state) {
do {
@@ -489,6 +485,51 @@
printk ("Starting kswapd v%.*s\n", i, s);
}

+static long kswapd_priority(int free_memory)
+{
+ long priority;
+ switch (free_memory)
+ {
+ case 0:
+ priority = DEF_PRIORITY << 1;
+ break;
+ case 2:
+ priority = DEF_PRIORITY >> 1;
+ break;
+ default:
+ priority = DEF_PRIORITY;
+ }
+ return priority;
+}
+
+#define kswapd_renice(freemem) \
+ (kswapd_task->priority = kswapd_priority(freemem))
+
+#define kswapd_done(freemem) \
+ (freemem == 2 && buffer_under_max() && pgcache_under_max())
+
+#define kswapd_schedule() \
+ do { \
+ if (kswapd_task->need_resched) \
+ schedule(); \
+ } while(0)
+
+static void kswapd_engine(void)
+{
+ int free_memory = free_memory_available();
+ for (;;)
+ {
+ kswapd_renice(free_memory);
+ do_try_to_free_page(0);
+ if (kswapd_done(free_memory_available()))
+ break;
+ kswapd_schedule();
+ free_memory = free_memory_available();
+ if (kswapd_done(free_memory))
+ break;
+ }
+}
+
/*
* The background pageout daemon.
* Started as a kernel thread from the init process.
@@ -508,13 +549,6 @@
lock_kernel();

/*
- * Set the base priority to something smaller than a
- * regular process. We will scale up the priority
- * dynamically depending on how much memory we need.
- */
- current->priority = (DEF_PRIORITY * 2) / 3;
-
- /*
* Tell the memory management that we're a "memory allocator",
* and that if we need more memory we should get access to it
* regardless (see "try_to_free_pages()"). "kswapd" should
@@ -531,20 +565,16 @@
init_swap_timer();
kswapd_task = current;
while (1) {
- unsigned long end_time;
-
- current->state = TASK_INTERRUPTIBLE;
+/* run_task_queue(&tq_disk); */
flush_signals(current);
- run_task_queue(&tq_disk);
+ /*
+ * Remeber to enable up the swap tick before go to sleep.
+ */
+ timer_active |= 1<<SWAP_TIMER;
+ current->state = TASK_INTERRUPTIBLE;
schedule();
swapstats.wakeups++;
-
- /* max one hundreth of a second */
- end_time = jiffies + (HZ-1)/100;
- do {
- if (!do_try_to_free_page(0))
- break;
- } while (time_before_eq(jiffies,end_time));
+ kswapd_engine();
}
/* As if we could ever get here - maybe we want to make this killable */
kswapd_task = NULL;
@@ -581,20 +611,12 @@
return retval;
}

-/*
- * Wake up kswapd according to the priority
- * 0 - no wakeup
- * 1 - wake up as a low-priority process
- * 2 - wake up as a normal process
- * 3 - wake up as an almost real-time process
- *
- * This plays mind-games with the "goodness()"
- * function in kernel/sched.c.
- */
-static inline void kswapd_wakeup(struct task_struct *p, int priority)
+static inline void kswapd_wakeup(int free_memory)
{
- if (priority) {
- p->counter = p->priority << priority;
+ struct task_struct *p = kswapd_task;
+ if (p && p->state & TASK_INTERRUPTIBLE)
+ {
+ p->priority = kswapd_priority(free_memory);
wake_up_process(p);
}
}
@@ -604,41 +626,16 @@
*/
void swap_tick(void)
{
- struct task_struct *p = kswapd_task;
-
+ int free_memory = free_memory_available();
/*
- * Only bother to try to wake kswapd up
- * if the task exists and can be woken.
+ * Schedule for wakeup if there isn't lots
+ * of free memory or if there is too much
+ * of it used for buffers or pgcache.
*/
- if (p && (p->state & TASK_INTERRUPTIBLE)) {
- unsigned int pages;
- int want_wakeup;
-
- /*
- * Schedule for wakeup if there isn't lots
- * of free memory or if there is too much
- * of it used for buffers or pgcache.
- *
- * "want_wakeup" is our priority: 0 means
- * not to wake anything up, while 3 means
- * that we'd better give kswapd a realtime
- * priority.
- */
- want_wakeup = 0;
- if (buffer_over_max() || pgcache_over_max())
- want_wakeup = 1;
- pages = nr_free_pages;
- if (pages < freepages.high)
- want_wakeup = 1;
- if (pages < freepages.low)
- want_wakeup = 2;
- if (pages < freepages.min)
- want_wakeup = 3;
-
- kswapd_wakeup(p,want_wakeup);
- }
-
- timer_active |= (1<<SWAP_TIMER);
+ if (free_memory != 2 || buffer_over_max() || pgcache_over_max())
+ kswapd_wakeup(free_memory);
+ else
+ timer_active |= (1<<SWAP_TIMER);
}

/*

Andrea Arcangeli

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/