Since no one else has stepped forward: 'ZeroD' patch

Ingo Molnar (mingo@pc5829.hil.siemens.at)
Tue, 7 Jan 1997 20:08:59 +0100 (MET)


Here is a patch that implements 'ZeroD', a simple kernel thread that uses
up CPU idle time to keep a pool of pre-zeroed pages around. Almost
anything that doesnt burn 100% CPU time all the time should benefit from
this.

the patch is against a clean 2.1.20. Comments, ideas, flames welcome.

--mingo

diff -u --recursive --new-file --exclude-from=exclude_from linux-2.1.20_orig/include/linux/mm.h linux/include/linux/mm.h
--- linux-2.1.20_orig/include/linux/mm.h Thu Jan 2 14:34:30 1997
+++ linux/include/linux/mm.h Tue Jan 7 18:26:31 1997
@@ -230,10 +230,14 @@
#define __get_free_page(priority) __get_free_pages((priority),0,0)
#define __get_dma_pages(priority, order) __get_free_pages((priority),(order),1)
extern unsigned long __get_free_pages(int priority, unsigned long gfporder, int dma);
+extern unsigned long get_precleared_page (void);

extern inline unsigned long get_free_page(int priority)
{
unsigned long page;
+
+ if ((page=get_precleared_page()))
+ return page;

page = __get_free_page(priority);
if (page)
diff -u --recursive --new-file --exclude-from=exclude_from linux-2.1.20_orig/init/main.c linux/init/main.c
--- linux-2.1.20_orig/init/main.c Thu Jan 2 14:13:27 1997
+++ linux/init/main.c Tue Jan 7 20:05:51 1997
@@ -58,6 +58,7 @@
extern int console_loglevel;

static int init(void *);
+extern int zerod(void *);
extern int bdflush(void *);
extern int kswapd(void *);

@@ -905,6 +906,11 @@
* make syscalls (and thus be locked).
*/
kernel_thread(init, NULL, 0);
+
+ /*
+ * start up ZeroD:
+ */
+ kernel_thread(zerod, NULL, 0);
/*
* task[0] is meant to be used as an "idle" task: it may not sleep, but
* it might do some general things like count free pages or it could be
diff -u --recursive --new-file --exclude-from=exclude_from linux-2.1.20_orig/mm/Makefile linux/mm/Makefile
--- linux-2.1.20_orig/mm/Makefile Fri Mar 22 11:56:56 1996
+++ linux/mm/Makefile Tue Jan 7 18:22:48 1997
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definition is now in the main makefile...

O_TARGET := mm.o
-O_OBJS := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
+O_OBJS := zerod.o memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
kmalloc.o vmalloc.o \
swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o

diff -u --recursive --new-file --exclude-from=exclude_from linux-2.1.20_orig/mm/zerod.c linux/mm/zerod.c
--- linux-2.1.20_orig/mm/zerod.c Thu Jan 1 01:00:00 1970
+++ linux/mm/zerod.c Tue Jan 7 19:44:31 1997
@@ -0,0 +1,99 @@
+/*
+ * linux/mm/zerod.c
+ *
+ * Copyright (C) 1997 Ingo Molnar
+ *
+ * This kernel thread keeps a pool of pre-zeroed pages. It runs at
+ * lowest possible process priority, so it will use up only idle time.
+ * It's a simple 'idle time' --> 'cleared page' converter.
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/wait.h>
+
+#define DEBUG_ZEROD
+#ifdef DEBUG_ZEROD
+#define dprintk(args...) printk(## args)
+#else
+#define dprintk(args...) { ; }/* nothing */
+#endif
+
+/*
+ * This one must be power of 2.
+ */
+#define ZEROD_POOLSIZE 32
+
+static struct wait_queue *zerod_wait = NULL;
+unsigned long nr_cleared_pages;
+
+unsigned long cleared_pages [ZEROD_POOLSIZE];
+
+int first_page, last_page;
+
+int zerod(void * unused)
+{
+ unsigned long page;
+ int i;
+
+ printk("zerod started.\n");
+
+ current->session = 1;
+ current->pgrp = 1;
+ sprintf(current->comm, "zerod");
+
+ /*
+ * Set to the lowest possible priority:
+ */
+ current->priority = 0;
+
+ last_page = first_page = 0;
+
+ for (i=0; i<ZEROD_POOLSIZE; i++)
+ cleared_pages[i]=0;
+
+ /*
+ * Never ending loop, clearing pages all the time:
+ */
+ for (;;) {
+ while (!cleared_pages[last_page]) {
+
+ page = __get_free_page(GFP_KERNEL);
+ if (page) {
+ clear_page(page);
+ cli();
+ cleared_pages[last_page++]=page;
+ last_page &= ZEROD_POOLSIZE-1;
+ sti();
+ continue;
+ }
+ break;
+ }
+ sleep_on (&zerod_wait);
+ }
+}
+
+unsigned long get_precleared_page (void)
+{
+ unsigned long flags;
+ unsigned long page=0;
+
+ save_flags(flags);
+ cli();
+
+ if (cleared_pages[first_page]) {
+ page=cleared_pages[first_page];
+ cleared_pages[first_page++]=0;
+ first_page &= ZEROD_POOLSIZE-1;
+
+ wake_up (&zerod_wait);
+ }
+
+ restore_flags(flags);
+ return page;
+}
+
+
+
+
+