From: Ben Gras Date: Mon, 28 Feb 2011 14:19:19 +0000 (+0000) Subject: auto-tune mfs cache size based on FS usage and remaining system memory X-Git-Tag: v3.2.0~626 X-Git-Url: http://zhaoyanbai.com/repos/%22../static/icons/man.7.txt?a=commitdiff_plain;h=c90cdadcfbbc7d6e3d9faa123201382a4baa0443;p=minix.git auto-tune mfs cache size based on FS usage and remaining system memory --- diff --git a/common/include/minix/com.h b/common/include/minix/com.h index 961d3c0ad..bd1b9e280 100644 --- a/common/include/minix/com.h +++ b/common/include/minix/com.h @@ -1100,7 +1100,7 @@ /* Basic vm calls allowed to every process. */ #define VM_BASIC_CALLS \ VM_MMAP, VM_MUNMAP, VM_MUNMAP_TEXT, VM_MAP_PHYS, VM_UNMAP_PHYS, \ - VM_FORGETBLOCKS, VM_FORGETBLOCK, VM_YIELDBLOCKGETBLOCK + VM_FORGETBLOCKS, VM_FORGETBLOCK, VM_YIELDBLOCKGETBLOCK, VM_INFO /*===========================================================================* * Messages for IPC server * diff --git a/servers/mfs/cache.c b/servers/mfs/cache.c index 5bcb80154..675b20824 100644 --- a/servers/mfs/cache.c +++ b/servers/mfs/cache.c @@ -16,8 +16,10 @@ #include "fs.h" #include +#include #include #include +#include #include "buf.h" #include "super.h" #include "inode.h" @@ -538,14 +540,17 @@ struct buf *bp; } /*===========================================================================* - * set_blocksize * + * cache_resize * *===========================================================================*/ -PUBLIC void set_blocksize(unsigned int blocksize) +PRIVATE void cache_resize(unsigned int blocksize, unsigned int bufs) { struct buf *bp; struct inode *rip; + int scale, r; - ASSERT(blocksize > 0); +#define MINBUFS 10 + assert(blocksize > 0); + assert(bufs >= MINBUFS); for (bp = &buf[0]; bp < &buf[nr_bufs]; bp++) if(bp->b_count != 0) panic("change blocksize with buffer in use"); @@ -553,10 +558,76 @@ PUBLIC void set_blocksize(unsigned int blocksize) for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) if (rip->i_count > 0) panic("change blocksize with inode in use"); - buf_pool(nr_bufs); + buf_pool(bufs); + fs_block_size = blocksize; } +/*===========================================================================* + * bufs_heuristic * + *===========================================================================*/ +PRIVATE int bufs_heuristic(struct super_block *sp) +{ + struct vm_stats_info vsi; + int r, bufs; + u32_t btotal, bfree, bused, kbytes_used_fs, + kbytes_total_fs, kbcache, kb_fsmax; + u32_t kbytes_remain_mem; + + /* but we simply need MINBUFS no matter what, and we don't + * want more than that if we're a memory device + */ + if(major(sp->s_dev) == MEMORY_MAJOR) { + bufs = MINBUFS; + return bufs; + } + + /* set a reasonable cache size; cache at most a certain + * portion of the used FS, and at most a certain %age of remaining + * memory + */ + if((vm_info_stats(&vsi) != OK)) { + bufs = 1024; + printf("mfs: heuristic info fail: default to %d bufs\n", bufs); + return bufs; + } + + kbytes_remain_mem = div64u(mul64u(vsi.vsi_free, vsi.vsi_pagesize), 1024); + + /* check fs usage. */ + blockstats(&btotal, &bfree, &bused); + kbytes_used_fs = div64u(mul64u(bused, sp->s_block_size), 1024); + kbytes_total_fs = div64u(mul64u(btotal, sp->s_block_size), 1024); + + /* heuristic for a desired cache size based on FS usage; + * but never bigger than half of the total filesystem + */ + kb_fsmax = sqrt(kbytes_used_fs)*40; + kb_fsmax = MIN(kb_fsmax, kbytes_total_fs/2); + + /* heuristic for a maximum usage - 10% of remaining memory */ + kbcache = MIN(kbytes_remain_mem/10, kb_fsmax); + bufs = kbcache * 1024 / sp->s_block_size; + + /* but we simply need MINBUFS no matter what */ + if(bufs < MINBUFS) + bufs = MINBUFS; + + return bufs; +} + +/*===========================================================================* + * set_blocksize * + *===========================================================================*/ +PUBLIC void set_blocksize(struct super_block *sp) +{ + int bufs; + + cache_resize(sp->s_block_size, MINBUFS); + bufs = bufs_heuristic(sp); + cache_resize(sp->s_block_size, bufs); +} + /*===========================================================================* * buf_pool * *===========================================================================*/ @@ -565,7 +636,7 @@ PUBLIC void buf_pool(int new_nr_bufs) /* Initialize the buffer pool. */ register struct buf *bp; - assert(new_nr_bufs > 0); + assert(new_nr_bufs >= MINBUFS); if(nr_bufs > 0) { assert(buf); diff --git a/servers/mfs/mount.c b/servers/mfs/mount.c index cec06108f..9e3b43b08 100644 --- a/servers/mfs/mount.c +++ b/servers/mfs/mount.c @@ -68,7 +68,7 @@ PUBLIC int fs_readsuper() return(r); } - set_blocksize(superblock.s_block_size); + set_blocksize(&superblock); /* Get the root inode of the mounted file system. */ if( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) { diff --git a/servers/mfs/proto.h b/servers/mfs/proto.h index 0eecbe98f..aeabb7995 100644 --- a/servers/mfs/proto.h +++ b/servers/mfs/proto.h @@ -18,7 +18,7 @@ _PROTOTYPE( void free_zone, (dev_t dev, zone_t numb) ); _PROTOTYPE( struct buf *get_block, (dev_t dev, block_t block,int only_search)); _PROTOTYPE( void invalidate, (dev_t device) ); _PROTOTYPE( void put_block, (struct buf *bp, int block_type) ); -_PROTOTYPE( void set_blocksize, (unsigned int blocksize) ); +_PROTOTYPE( void set_blocksize, (struct super_block *) ); _PROTOTYPE( void rw_scattered, (dev_t dev, struct buf **bufq, int bufqsize, int rw_flag) ); @@ -103,6 +103,7 @@ _PROTOTYPE( int read_super, (struct super_block *sp) ); /* stats.c */ _PROTOTYPE( bit_t count_free_bits, (struct super_block *sp, int map)); +_PROTOTYPE( void blockstats, (u32_t *total, u32_t *free, u32_t *avail)); /* time.c */ _PROTOTYPE( int fs_utime, (void) ); diff --git a/servers/mfs/stadir.c b/servers/mfs/stadir.c index 7719c59f1..3f2a205cf 100644 --- a/servers/mfs/stadir.c +++ b/servers/mfs/stadir.c @@ -81,16 +81,17 @@ PUBLIC int fs_statvfs() struct statvfs st; struct super_block *sp; int r, scale; + u32_t used; sp = get_super(fs_dev); scale = sp->s_log_zone_size; + blockstats(&st.f_blocks, &st.f_bfree, &used); + st.f_bavail = st.f_bfree; + st.f_bsize = sp->s_block_size << scale; st.f_frsize = sp->s_block_size; - st.f_blocks = sp->s_zones << scale; - st.f_bfree = count_free_bits(sp, ZMAP) << scale; - st.f_bavail = st.f_bfree; st.f_files = sp->s_ninodes; st.f_ffree = count_free_bits(sp, IMAP); st.f_favail = st.f_ffree; diff --git a/servers/mfs/stats.c b/servers/mfs/stats.c index ebae236eb..6fcd933b0 100644 --- a/servers/mfs/stats.c +++ b/servers/mfs/stats.c @@ -85,3 +85,25 @@ int map; /* IMAP (inode map) or ZMAP (zone map) */ } while (--bcount > 0); return free_bits; /* no bit could be allocated */ } + + +/*===========================================================================* + * blockstats * + *===========================================================================*/ +PUBLIC void blockstats(u32_t *blocks, u32_t *free, u32_t *used) +{ + struct super_block *sp; + int scale; + + sp = get_super(fs_dev); + + assert(sp); + + scale = sp->s_log_zone_size; + + *blocks = sp->s_zones << scale; + *free = count_free_bits(sp, ZMAP) << scale; + *used = *blocks - *free; + + return; +}