]> Zhao Yanbai Git Server - minix.git/commitdiff
auto-tune mfs cache size based on FS usage and remaining system memory
authorBen Gras <ben@minix3.org>
Mon, 28 Feb 2011 14:19:19 +0000 (14:19 +0000)
committerBen Gras <ben@minix3.org>
Mon, 28 Feb 2011 14:19:19 +0000 (14:19 +0000)
common/include/minix/com.h
servers/mfs/cache.c
servers/mfs/mount.c
servers/mfs/proto.h
servers/mfs/stadir.c
servers/mfs/stats.c

index 961d3c0ad227759e9bbce9502c86dbb889745747..bd1b9e2808619f58bd53ee73869e75d19bc3fef1 100644 (file)
 /* 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                                   *
index 5bcb80154b806b3946866d09e12890409fb09c79..675b208245d5825c5e4339d34f7bd86ba059275f 100644 (file)
 
 #include "fs.h"
 #include <minix/u64.h>
+#include <sys/param.h>
 #include <stdlib.h>
 #include <assert.h>
+#include <math.h>
 #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);
index cec06108f295e77969e1592ad75518a4ab4e11c8..9e3b43b08c72a12b77a17165ce2dffdc521928a0 100644 (file)
@@ -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)  {
index 0eecbe98f6ea8c6d6dc742d67baf7ea64f24c7b0..aeabb79953fd0741a539be2501639d4f1524ceae 100644 (file)
@@ -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)                                       );
index 7719c59f14e083fbc045e973b3b66146c8feb029..3f2a205cf4976c36772c366c149fff80e3428fbc 100644 (file)
@@ -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;
index ebae236eb1819710fc448faaf587db404f7d14ba..6fcd933b02db64901670cfb9d07803ed915815ea 100644 (file)
@@ -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;
+}