lkml.org 
[lkml]   [1999]   [Mar]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectSwap cache patch for 2.0.36/37
Hi all you conservative people still using 2.0.x (like me).
This is a fix for the swap cache bug^H^H^Hdesign feature. By the way,
previous version posted here a couple of months ago was broken, so all
users / testers of this patch should upgrade.

The main idea is counting of swap cache entries as free swap entries.
To avoid possible memory overcommit, a mechanism of re-using swap cache
entries is needed in the situation, when all swap entries are occupied.
Such code has been added. It is currently rather suboptimal, but at least
works reliably.

All page cache hacks have been removed. Alan and other people made the
page cache more nice, so i decided not to tweak with shrink_mmap.

Why am i doing it? That's simple. Set your swap space to be equal to RAM.
Try to run attached program in one VT (give the number of RAM pages of your
computer as the argument), login in the 2'nd and run top.

#include <limits.h>
#include <asm/page.h>
#include <stdio.h>
double ustaw(double *gdzie, int rw) {
if (rw) *gdzie = ((double) rand()) / ((double) RAND_MAX);
return *gdzie;
}

main(int argc, char **argv) {
int npages,rw,i;
char *gdzie,*tmp;
double sum;
if (argc < 2) {
printf("usemem npages [anything here gives writing to memory]\n");
return -1;
}
npages=atoi(argv[1]);
gdzie=(char *)malloc(npages*PAGE_SIZE);
if (gdzie == (char *) NULL) {
printf("malloc failed\n");
return -1;
}
rw = 1;
sum = 0.;
while (1) {
tmp = gdzie;
for (i=0;i<npages;i++) {
sum = sum + ustaw(tmp,rw);
tmp = tmp + PAGE_SIZE;
}
sum = 1. / (1. + sum);
rw = (argc > 2);
}
}

Look, the swap space disappears! Even if you have a 1GB RAM + 1GB swap
machine, it will be quickly unusable. No new processes.
By the way, how it works with 2.2?
Currently, in 2.0.x
max(RAM size, swap size) <= VM size <= RAM size + swap size.
With the attached patch, VM size = RAM size + swap size.
Regards
Krzysztof.
PS All optimizations are welcome.
PS2 Additional entry in /proc/sys/vm/freepages interferes with the nfs swap
patch. Be careful!

diff -u -r linux-orig/Documentation/memory-tuning.txt linux/Documentation/memory-tuning.txt
--- linux-orig/Documentation/memory-tuning.txt Mon Jul 13 22:47:25 1998
+++ linux/Documentation/memory-tuning.txt Thu Feb 11 15:12:37 1999
@@ -5,14 +5,14 @@
/proc/sys/vm/freepages:

'# cat /proc/sys/vm/freepages' may yield:
-64 96 128
+64 96 128 128

-These three numbers are: min_free_pages, free_pages_low and
-free_pages_high.
+These four numbers are: min_free_pages, free_pages_low,
+free_pages_high and min_swap_pages.

You can adjust these with a command such as:

-# echo "128 256 512" > /proc/sys/vm/freepages
+# echo "128 256 512 256" > /proc/sys/vm/freepages

Free memory never goes down below min_free_pages except for atomic
allocation. Background swapping is started if the number of free
@@ -23,6 +23,7 @@
machine with n>=8 Megabytes of memory, set min_free_pages = n*2,
free_pages_low = n*3 and free_pages_high = n*4. Machines with
8 Megabytes or less behave as if they had 8 Megabytes.
+Min_swap_pages is initialized by default to 128.

If "out of memory" errors sometimes occur, or if your machine does lots
of networking, increasing min_free_pages to 64 or more may be a good
@@ -43,6 +44,11 @@
gives good performance for a 32 Meg system used as a small server and
personal workstation.

+Min_swap_pages controls the minimal number of free swap entries.
+If nr_swap_pages falls below min_swap_pages, swap cache entries
+for accessed pages are freed asynchronously.
+
The other three files in /proc/sys/vm are undocumented, as yet.

Thomas Koenig, ig25@rz.uni-karlsruhe.de
+min_swap_pages added by Krzysztof Strasburger, strasbur@chkw386.ch.pwr.wroc.pl
diff -u -r linux-orig/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile
--- linux-orig/arch/i386/boot/compressed/Makefile Sun Sep 8 18:50:20 1996
+++ linux/arch/i386/boot/compressed/Makefile Mon Feb 22 07:16:11 1999
@@ -75,4 +75,4 @@
endif

clean:
- rm -f xtract piggyback vmlinux bvmlinux
+ rm -f xtract piggyback vmlinux bvmlinux piggy.o
diff -u -r linux-orig/fs/proc/array.c linux/fs/proc/array.c
--- linux-orig/fs/proc/array.c Sun Nov 15 19:33:14 1998
+++ linux/fs/proc/array.c Thu Feb 11 15:08:12 1999
@@ -290,7 +290,7 @@
* Tagged format, for easy grepping and expansion. The above will go away
* eventually, once the tools have been updated.
*/
- return len + sprintf(buffer+len,
+ len = len + sprintf(buffer+len,
"MemTotal: %8lu kB\n"
"MemFree: %8lu kB\n"
"MemShared: %8lu kB\n"
@@ -305,6 +305,11 @@
page_cache_size << (PAGE_SHIFT - 10),
i.totalswap >> 10,
i.freeswap >> 10);
+#ifdef SWAP_CACHE_INFO
+ len = len + sprintf(buffer+len,
+ "Swap cache: %d pages\n",nr_swap_cache_pages);
+#endif
+ return len;
}

static int get_version(char * buffer)
diff -u -r linux-orig/include/linux/mm.h linux/include/linux/mm.h
--- linux-orig/include/linux/mm.h Tue Dec 2 23:18:11 1997
+++ linux/include/linux/mm.h Thu Feb 11 09:08:36 1999
@@ -10,6 +10,7 @@
#include <linux/string.h>

extern unsigned long high_memory;
+extern int min_swap_pages;

#include <asm/page.h>
#include <asm/atomic.h>
diff -u -r linux-orig/include/linux/swap.h linux/include/linux/swap.h
--- linux-orig/include/linux/swap.h Thu Jun 4 00:17:50 1998
+++ linux/include/linux/swap.h Thu Feb 25 13:22:36 1999
@@ -37,6 +37,7 @@

extern int nr_swap_pages;
extern int nr_free_pages;
+extern int nr_swap_cache_pages;
extern atomic_t nr_async_pages;
extern int min_free_pages;
extern int free_pages_low;
@@ -108,7 +109,7 @@
return swap_cache[index];
}

-extern inline long find_in_swap_cache(unsigned long index)
+extern inline unsigned long find_in_swap_cache(unsigned long index)
{
unsigned long entry;

@@ -116,14 +117,16 @@
swap_cache_find_total++;
#endif
entry = xchg(swap_cache + index, 0);
+ if (entry) {
#ifdef SWAP_CACHE_INFO
- if (entry)
swap_cache_find_success++;
#endif
+ nr_swap_cache_pages--;
+ }
return entry;
}

-extern inline int delete_from_swap_cache(unsigned long index)
+extern inline unsigned long delete_from_swap_cache(unsigned long index)
{
unsigned long entry;

@@ -136,11 +139,10 @@
swap_cache_del_success++;
#endif
swap_free(entry);
- return 1;
+ nr_swap_cache_pages--;
}
- return 0;
+ return entry;
}
-

#endif /* __KERNEL__*/

diff -u -r linux-orig/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-orig/kernel/sysctl.c Mon Jul 13 22:47:40 1998
+++ linux/kernel/sysctl.c Wed Feb 10 13:19:45 1999
@@ -157,7 +157,7 @@
{VM_KSWAPD, "kswapd",
&kswapd_ctl, sizeof(kswapd_ctl), 0600, NULL, &proc_dointvec},
{VM_FREEPG, "freepages",
- &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
+ &min_free_pages, 4*sizeof(int), 0600, NULL, &proc_dointvec},
{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
&proc_dointvec_minmax, &sysctl_intvec, NULL,
&bdflush_min, &bdflush_max},
diff -u -r linux-orig/mm/mmap.c linux/mm/mmap.c
--- linux-orig/mm/mmap.c Sun Nov 15 19:33:20 1998
+++ linux/mm/mmap.c Wed Feb 10 13:11:39 1999
@@ -59,6 +59,7 @@
freepages >>= 1;
freepages += nr_free_pages;
freepages += nr_swap_pages;
+ freepages += nr_swap_cache_pages;
freepages -= MAP_NR(high_memory) >> 4;
return freepages > pages;
}
diff -u -r linux-orig/mm/swap.c linux/mm/swap.c
--- linux-orig/mm/swap.c Mon Jun 3 14:38:37 1996
+++ linux/mm/swap.c Wed Feb 10 13:18:16 1999
@@ -35,12 +35,15 @@
* fall below the min_free_pages except for atomic allocations. We
* start background swapping if we fall below free_pages_high free
* pages, and we begin intensive swapping below free_pages_low.
+ * If nr_swap_pages falls below min_swap_pages, we begin freeing
+ * swap cache pages.
*
- * Keep these three variables contiguous for sysctl(2).
+ * Keep these four variables contiguous for sysctl(2).
*/
int min_free_pages = 20;
int free_pages_low = 30;
int free_pages_high = 40;
+int min_swap_pages = 128;

/* 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 */
diff -u -r linux-orig/mm/swap_state.c linux/mm/swap_state.c
--- linux-orig/mm/swap_state.c Thu Jun 4 00:17:50 1998
+++ linux/mm/swap_state.c Mon Feb 22 10:57:25 1999
@@ -32,6 +32,9 @@
*/
unsigned long *swap_cache;

+int nr_swap_cache_pages = 0;
+unsigned long swap_cache_size = 0;
+
#ifdef SWAP_CACHE_INFO
unsigned long swap_cache_add_total = 0;
unsigned long swap_cache_add_success = 0;
@@ -64,6 +67,7 @@
#ifdef SWAP_CACHE_INFO
swap_cache_add_success++;
#endif
+ nr_swap_cache_pages++;
return 1;
}
return 0;
@@ -72,7 +76,6 @@
unsigned long init_swap_cache(unsigned long mem_start,
unsigned long mem_end)
{
- unsigned long swap_cache_size;

mem_start = (mem_start + 15) & ~15;
swap_cache = (unsigned long *) mem_start;
diff -u -r linux-orig/mm/swapfile.c linux/mm/swapfile.c
--- linux-orig/mm/swapfile.c Sun Nov 15 19:33:20 1998
+++ linux/mm/swapfile.c Thu Feb 25 13:23:50 1999
@@ -77,6 +77,9 @@

unsigned long get_swap_page(void)
{
+ static unsigned long index = 0;
+ extern unsigned long swap_cache_size;
+
struct swap_info_struct * p;
unsigned long offset, entry;
int type, wrapped = 0;
@@ -84,9 +87,26 @@
type = swap_list.next;
if (type < 0)
return 0;
- if (nr_swap_pages == 0)
- return 0;

+ if (nr_swap_pages > 0)
+ goto scan_swap;
+scan_swap_cache:
+ if (nr_swap_cache_pages == 0)
+ return 0;
+ /* We really need swap space - let us try to free
+ * a swap cache entry. */
+ offset = index;
+ while (1) {
+ entry = delete_from_swap_cache(index);
+ index++;
+ if (index >= swap_cache_size)
+ index = 0;
+ if (entry)
+ goto scan_swap;
+ if (index == offset)
+ return 0; /* Out of swap space, no swap cache entries. */
+ }
+scan_swap:
while (1) {
p = &swap_info[type];
if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
@@ -113,7 +133,7 @@
wrapped = 1;
}
} else if (type < 0) {
- return 0; /* out of swap space */
+ goto scan_swap_cache; /* out of swap space */
}
}
}
@@ -576,6 +596,7 @@
++val->totalswap;
}
}
+ val->freeswap += nr_swap_cache_pages;
val->freeswap <<= PAGE_SHIFT;
val->totalswap <<= PAGE_SHIFT;
return;
diff -u -r linux-orig/mm/vmscan.c linux/mm/vmscan.c
--- linux-orig/mm/vmscan.c Sun Nov 15 19:33:20 1998
+++ linux/mm/vmscan.c Thu Feb 25 13:26:29 1999
@@ -104,6 +104,9 @@
* is oldest). */
if ((pte_dirty(pte) && delete_from_swap_cache(MAP_NR(page)))
|| pte_young(pte)) {
+ /* Free swap cache entries for non dirty pages */
+ if (pte_young(pte) && nr_swap_pages < min_swap_pages)
+ delete_from_swap_cache(MAP_NR(page));
set_pte(page_table, pte_mkold(pte));
touch_page(page_map);
return 0;
@@ -111,7 +114,8 @@
age_page(page_map);
if (page_map->age)
return 0;
- if (pte_dirty(pte)) {
+ entry = find_in_swap_cache(MAP_NR(page));
+ if (pte_dirty(pte) || !(entry || page_map->inode || page_map->buffers || page_map->count != 1)) {
if(!can_do_io)
return 0;
if (vma->vm_ops && vma->vm_ops->swapout) {
@@ -132,7 +136,7 @@
free_page(page);
return 1; /* we slept: the process may not exist any more */
}
- if ((entry = find_in_swap_cache(MAP_NR(page)))) {
+ if (entry) {
if (page_map->count != 1) {
set_pte(page_table, pte_mkdirty(pte));
printk("Aiee.. duplicated cached swap-cache entry\n");
-
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/

\
 
 \ /
  Last update: 2005-03-22 13:50    [W:1.460 / U:0.016 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site