[patch] dynamic buffer cache hash table size

Andrea Arcangeli (andrea@e-mind.com)
Fri, 22 Jan 1999 01:20:42 +0100 (CET)


On Thu, 21 Jan 1999, Andrea Arcangeli wrote:

> On Thu, 21 Jan 1999, Heinz Mauelshagen wrote:
>
> > - buffermem is 200M of my 256M system afterwards
> > - minimum swap.
> > - lots of system time searching the buffer cache with
> > commands afterwards.
>
> so the problem is just only the ~O(n) search in the buffer cache right?
>
> > - commands running 50 to 100!!! times slower than before filling buffercache
>
> No this is a workaround of the problem I think that right now I should
> enlarge the buffer hash table of the buffer headers for high memory
> machines.

I've done that now. Worked fine here so far. I am allocating now 65 pages
for my 128Mbyte RAM machine. In 64Mbyte the pages allocated for the buffer
hash table will be 33 (continue linear...). Maybe it's too much?

Could you try out if this patch against pre-8.gz (in testing) fix the `too
much allocated buffers' problem without having to set max limit on the
buffer cache?

BTW, since I was there I also enlarged the page cache hash table from
8kbyte (2k entry) to 32kbyte (8k entries) since with 128Mbyte I don't care
to lose 1 page and half to go 4 time faster (if I guess the math right)
while browsing the cache.

Andrea Arcangeli

Index: linux/fs/buffer.c
===================================================================
RCS file: /var/cvs/linux/fs/buffer.c,v
retrieving revision 1.1.2.5
diff -u -r1.1.2.5 buffer.c
--- buffer.c 1999/01/21 20:00:15 1.1.2.5
+++ linux/fs/buffer.c 1999/01/22 00:16:01
@@ -24,6 +24,10 @@
* - RMK
*/

+/*
+ * Dynamic hash table size. Copyright (C) 1999 Andrea Arcangeli
+ */
+
#include <linux/malloc.h>
#include <linux/locks.h>
#include <linux/errno.h>
@@ -1524,23 +1528,45 @@
/* ===================== Init ======================= */

/*
- * allocate the hash table and init the free list
- * Use gfp() for the hash table to decrease TLB misses, use
- * SLAB cache for buffer heads.
+ * Here we takes care of allocatin the buffer hash table before
+ * slab cache and other things are initialized to be able to allocate
+ * huge size of RAM. -arca
*/
-void __init buffer_init(void)
+unsigned long __init buffer_hash_init(unsigned long start, unsigned long end)
{
- int order = 5; /* Currently maximum order.. */
- unsigned int nr_hash;
-
- nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct buffer_head *);
- hash_table = (struct buffer_head **) __get_free_pages(GFP_ATOMIC, order);
+ unsigned long mem_pages, hash_size, nr_hash;

- if (!hash_table)
+ /* gets rid of CPU cacheline issues -arca */
+ start= PAGE_ALIGN(start);
+
+ mem_pages = (end - start) >> PAGE_SHIFT;
+ /* we may want to use 17 pages for a 32 Mbyte machines -arca */
+ mem_pages = (mem_pages + (1<<9)) >> 9;
+
+ hash_size = mem_pages << PAGE_SHIFT;
+ nr_hash = hash_size / sizeof(struct buffer_head *);
+
+ hash_table = (struct buffer_head **) start;
+ start += hash_size;
+ if (start > end)
panic("Failed to allocate buffer hash table\n");
+ else
+ printk("buffer_hash table size: %lu pages\n", mem_pages);
+
memset(hash_table, 0, nr_hash * sizeof(struct buffer_head *));
bh_hash_mask = nr_hash-1;

+ /* if there is no buggy code around we can avoid to page align -arca */
+ return start;
+}
+
+/*
+ * allocate the hash table and init the free list
+ * Use gfp() for the hash table to decrease TLB misses, use
+ * SLAB cache for buffer heads.
+ */
+void __init buffer_init(void)
+{
bh_cachep = kmem_cache_create("buffer_head",
sizeof(struct buffer_head),
0,
Index: linux/include/linux/fs.h
===================================================================
RCS file: /var/cvs/linux/include/linux/fs.h,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 fs.h
--- fs.h 1999/01/18 15:27:40 1.1.2.2
+++ linux/include/linux/fs.h 1999/01/21 23:48:12
@@ -164,6 +164,7 @@
extern void update_atime (struct inode *inode);
#define UPDATE_ATIME(inode) update_atime (inode)

+extern unsigned long buffer_hash_init(unsigned long start, unsigned long end);
extern void buffer_init(void);
extern void inode_init(void);
extern void file_table_init(void);
Index: linux/include/linux/pagemap.h
===================================================================
RCS file: /var/cvs/linux/include/linux/pagemap.h,v
retrieving revision 1.1.2.3
diff -u -r1.1.2.3 pagemap.h
--- pagemap.h 1999/01/21 22:39:21 1.1.2.3
+++ linux/include/linux/pagemap.h 1999/01/21 23:48:14
@@ -18,7 +18,7 @@
return PAGE_OFFSET + (page->map_nr << PAGE_SHIFT);
}

-#define PAGE_HASH_BITS 11
+#define PAGE_HASH_BITS 13
#define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS)

extern unsigned long page_cache_size; /* # of pages currently in the hash table */
Index: linux/init/main.c
===================================================================
RCS file: /var/cvs/linux/init/main.c,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 main.c
--- main.c 1999/01/18 15:27:41 1.1.2.2
+++ linux/init/main.c 1999/01/21 20:35:23
@@ -1139,6 +1139,7 @@
}

memory_start = namei_init(memory_start, memory_end);
+ memory_start = buffer_hash_init(memory_start, memory_end);
memory_start = kmem_cache_init(memory_start, memory_end);
sti();
calibrate_delay();

-
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/