vm - hash table for block cache

This commit is contained in:
Ben Gras 2010-10-15 09:10:14 +00:00
parent cb2e3a98a2
commit ddde360e3e
11 changed files with 116 additions and 36 deletions

View file

@ -392,8 +392,5 @@ PUBLIC int proc_new(struct vmproc *vmp,
panic("exec_newmem: pt_bind failed: %d", s);
}
/* No yielded memory blocks. */
yielded_init(&vmp->vm_yielded_blocks);
return OK;
}

View file

@ -45,6 +45,7 @@ PUBLIC void clear_proc(struct vmproc *vmp)
vmp->vm_callback = NULL; /* No pending vfs callback. */
vmp->vm_flags = 0; /* Clear INUSE, so slot is free. */
vmp->vm_heap = NULL;
vmp->vm_yielded = 0;
#if VMSTATS
vmp->vm_bytecopies = 0;
#endif

View file

@ -70,7 +70,6 @@ PUBLIC int do_fork(message *msg)
*vmc = *vmp;
vmc->vm_slot = childproc;
region_init(&vmc->vm_regions_avl);
yielded_init(&vmc->vm_yielded_blocks);
vmc->vm_endpoint = NONE; /* In case someone tries to use it. */
vmc->vm_pt = origpt;
vmc->vm_flags &= ~VMF_HASPT;

View file

@ -255,6 +255,9 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
vmp->vm_flags |= VMF_SEPARATE;
}
/* region management initialization. */
map_region_init();
/* Architecture-dependent initialization. */
pt_init(limit);

View file

@ -16,6 +16,7 @@ struct phys_region;
#include <pagetable.h>
#include "vm.h"
#include "yielded.h"
/* alloc.c */
_PROTOTYPE( phys_clicks alloc_mem, (phys_clicks clicks, u32_t flags) );
@ -137,6 +138,7 @@ _PROTOTYPE(int slabsane_f,(char *file, int line, void *mem, int bytes));
#endif
/* region.c */
_PROTOTYPE(void map_region_init, (void));
_PROTOTYPE(struct vir_region * map_page_region,(struct vmproc *vmp, \
vir_bytes min, vir_bytes max, vir_bytes length, vir_bytes what, \
u32_t flags, int mapflags));
@ -159,6 +161,7 @@ _PROTOTYPE(int map_writept, (struct vmproc *vmp));
_PROTOTYPE(void printregionstats, (struct vmproc *vmp));
_PROTOTYPE(phys_bytes map_lookup_phys, (struct vmproc *vmp, u32_t tag));
_PROTOTYPE(void map_setparent, (struct vmproc *vmp));
_PROTOTYPE(int yielded_block_cmp, (struct block_id *, struct block_id *));
_PROTOTYPE(struct vir_region * map_region_lookup_tag, (struct vmproc *vmp, u32_t tag));
_PROTOTYPE(void map_region_set_tag, (struct vir_region *vr, u32_t tag));

View file

@ -10,6 +10,7 @@
#include <minix/syslib.h>
#include <minix/debug.h>
#include <minix/bitmap.h>
#include <minix/hash.h>
#include <sys/mman.h>
@ -56,6 +57,36 @@ FORWARD _PROTOTYPE(struct phys_region *map_clone_ph_block, (struct vmproc *vmp,
FORWARD _PROTOTYPE(void lrucheck, (void));
#endif
/* hash table of yielded blocks */
#define YIELD_HASHSIZE 65536
PRIVATE yielded_avl vm_yielded_blocks[YIELD_HASHSIZE];
PRIVATE int avl_inited = 0;
PUBLIC void map_region_init(void)
{
int h;
assert(!avl_inited);
for(h = 0; h < YIELD_HASHSIZE; h++)
yielded_init(&vm_yielded_blocks[h]);
avl_inited = 1;
}
PRIVATE yielded_avl *get_yielded_avl(block_id_t id)
{
u32_t h;
assert(avl_inited);
hash_i_64(id.owner, id.id, h);
h = h % YIELD_HASHSIZE;
assert(h >= 0);
assert(h < YIELD_HASHSIZE);
return &vm_yielded_blocks[h];
}
PRIVATE char *map_name(struct vir_region *vr)
{
static char name[100];
@ -435,9 +466,6 @@ PRIVATE vir_bytes region_find_slot_range(struct vmproc *vmp,
nextvr = region_get_iter(&iter);
FREEVRANGE(vr->vaddr + vr->length,
nextvr ? nextvr->vaddr : VM_DATATOP);
if(!foundflag) {
printf("incr from 0x%lx to 0x%lx; v range 0x%lx-0x%lx\n", vr->vaddr, nextvr->vaddr);
}
}
}
@ -721,27 +749,52 @@ PRIVATE int map_free(struct vmproc *vmp, struct vir_region *region)
return OK;
}
/*===========================================================================*
* yielded_block_cmp *
*===========================================================================*/
PUBLIC int yielded_block_cmp(struct block_id *id1, struct block_id *id2)
{
if(id1->owner < id2->owner)
return -1;
if(id1->owner > id2->owner)
return 1;
return cmp64(id1->id, id2->id);
}
/*===========================================================================*
* free_yielded_proc *
*===========================================================================*/
PRIVATE vir_bytes free_yielded_proc(struct vmproc *vmp)
{
yielded_t *yb;
int y = 0;
vir_bytes total = 0;
int h;
SANITYCHECK(SCL_FUNCTIONS);
/* Free associated regions. */
while((yb = yielded_search_root(&vmp->vm_yielded_blocks))) {
SLABSANE(yb);
total += freeyieldednode(yb, 1);
y++;
for(h = 0; h < YIELD_HASHSIZE && vmp->vm_yielded > 0; h++) {
yielded_t *yb;
yielded_iter iter;
yielded_avl *avl = &vm_yielded_blocks[h];
yielded_start_iter_least(avl, &iter);
while((yb = yielded_get_iter(&iter))) {
yielded_t *next_yb;
SLABSANE(yb);
yielded_incr_iter(&iter);
if(yb->id.owner != vmp->vm_endpoint)
continue;
next_yb = yielded_get_iter(&iter);
total += freeyieldednode(yb, 1);
/* the above removal invalidated our iter; restart it
* for the node we want to start at.
*/
if(!next_yb) break;
yielded_start_iter(avl, &iter, next_yb->id, AVL_EQUAL);
assert(yielded_get_iter(&iter) == next_yb);
}
}
yielded_init(&vmp->vm_yielded_blocks);
return total;
}
@ -749,8 +802,9 @@ PRIVATE vir_bytes free_yielded_proc(struct vmproc *vmp)
PRIVATE phys_bytes freeyieldednode(yielded_t *node, int freemem)
{
yielded_t *older, *younger, *removed;
int p;
vir_bytes len;
yielded_avl *avl;
int p;
SLABSANE(node);
@ -783,11 +837,13 @@ PRIVATE phys_bytes freeyieldednode(yielded_t *node, int freemem)
/* Update AVL. */
if(vm_isokendpt(node->owner, &p) != OK)
panic("out of date owner of yielded block %d", node->owner);
removed = yielded_remove(&vmproc[p].vm_yielded_blocks, node->id);
if(vm_isokendpt(node->id.owner, &p) != OK)
panic("out of date owner of yielded block %d", node->id.owner);
avl = get_yielded_avl(node->id);
removed = yielded_remove(avl, node->id);
assert(removed == node);
assert(vmproc[p].vm_yielded > 0);
vmproc[p].vm_yielded--;
/* Free associated memory if requested. */
@ -1199,7 +1255,6 @@ PUBLIC int map_pin_memory(struct vmproc *vmp)
}
region_incr_iter(&iter);
}
return OK;
}
@ -2388,9 +2443,14 @@ PRIVATE int getblock(struct vmproc *vmp, u64_t id,
yielded_t *yb;
struct phys_region *ph;
struct vir_region *region;
yielded_avl *avl;
block_id_t blockid;
/* Try to get the yielded block */
if(!(yb = yielded_search(&vmp->vm_yielded_blocks, id, AVL_EQUAL))) {
blockid.owner = vmp->vm_endpoint;
blockid.id = id;
avl = get_yielded_avl(blockid);
if(!(yb = yielded_search(avl, blockid, AVL_EQUAL))) {
return ESRCH;
}
@ -2434,11 +2494,16 @@ PRIVATE int yieldblock(struct vmproc *vmp, u64_t id,
vir_bytes mem_clicks, newmem, clicks;
struct vir_region *region;
struct phys_region *ph;
yielded_avl *avl;
block_id_t blockid;
/* Makes no sense if yielded block ID already exists, and
* is likely a serious bug in the caller.
*/
if(yielded_search(&vmp->vm_yielded_blocks, id, AVL_EQUAL)) {
blockid.id = id;
blockid.owner = vmp->vm_endpoint;
avl = get_yielded_avl(blockid);
if(yielded_search(avl, blockid, AVL_EQUAL)) {
printf("!");
return EINVAL;
}
@ -2465,10 +2530,9 @@ PRIVATE int yieldblock(struct vmproc *vmp, u64_t id,
/* Update yielded block info. */
USE(newyb,
newyb->id = id;
newyb->id = blockid;
newyb->addr = ph->ph->phys;
newyb->len = ph->ph->length;
newyb->owner = vmp->vm_endpoint;
newyb->younger = NULL;);
/* Set new phys block to new addr and update pagetable. */
@ -2482,7 +2546,9 @@ PRIVATE int yieldblock(struct vmproc *vmp, u64_t id,
}
/* Remember yielded block. */
yielded_insert(&vmp->vm_yielded_blocks, newyb);
yielded_insert(avl, newyb);
vmp->vm_yielded++;
/* Add to LRU list too. It's the youngest block. */
LRUCHECK;
@ -2542,6 +2608,8 @@ PUBLIC int do_forgetblock(message *m)
endpoint_t caller = m->m_source;
yielded_t *yb;
u64_t id;
block_id_t blockid;
yielded_avl *avl;
if(vm_isokendpt(caller, &n) != OK)
panic("do_yield_block: message from strange source: %d",
@ -2556,7 +2624,10 @@ PUBLIC int do_forgetblock(message *m)
id = make64(m->VMFB_IDLO, m->VMFB_IDHI);
if((yb = yielded_search(&vmp->vm_yielded_blocks, id, AVL_EQUAL))) {
blockid.id = id;
blockid.owner = vmp->vm_endpoint;
avl = get_yielded_avl(blockid);
if((yb = yielded_search(avl, blockid, AVL_EQUAL))) {
freeyieldednode(yb, 1);
}

View file

@ -467,6 +467,9 @@ PUBLIC void slabfree(void *mem, int bytes)
#if SANITYCHECKS
#if MEMPROTECT
slabunlock(mem, bytes);
#endif
#if JUNKFREE
memset(mem, 0xa6, bytes);
#endif
*(u32_t *) mem = JUNK;
nojunkwarning++;

View file

@ -274,10 +274,6 @@ PUBLIC int swap_proc_slot(struct vmproc *src_vmp, struct vmproc *dst_vmp)
dst_vmp->vm_endpoint = orig_dst_vmproc.vm_endpoint;
dst_vmp->vm_slot = orig_dst_vmproc.vm_slot;
/* Preserve yielded blocks. */
src_vmp->vm_yielded_blocks = orig_src_vmproc.vm_yielded_blocks;
dst_vmp->vm_yielded_blocks = orig_dst_vmproc.vm_yielded_blocks;
#if LU_DEBUG
printf("VM: swap_proc: swapped %d (%d) and %d (%d)\n",
src_vmp->vm_endpoint, src_vmp->vm_slot,

View file

@ -32,7 +32,6 @@ struct vmproc {
/* Regions in virtual address space. */
region_avl vm_regions_avl;
vir_bytes vm_region_top; /* highest vaddr last inserted */
yielded_avl vm_yielded_blocks; /* avl of yielded physblocks */
/* Heap for brk() to extend. */
struct vir_region *vm_heap;
@ -46,6 +45,7 @@ struct vmproc {
int vm_callback_type; /* expected message type */
int vm_slot; /* process table slot */
int vm_yielded; /* yielded regions */
union {
struct {

View file

@ -4,10 +4,17 @@
#include <minix/type.h>
typedef struct yielded {
typedef struct block_id {
u64_t id;
phys_bytes addr, len;
endpoint_t owner;
} block_id_t;
typedef struct yielded {
/* the owner-given id and owner together
* uniquely identify a yielded block.
*/
block_id_t id;
phys_bytes addr, len;
/* LRU fields */
struct yielded *younger, *older;

View file

@ -2,7 +2,7 @@
#define AVL_UNIQUE(id) yielded_ ## id
#define AVL_HANDLE yielded_t *
#define AVL_KEY u64_t
#define AVL_KEY block_id_t
#define AVL_MAX_DEPTH 30 /* good for 2 million nodes */
#define AVL_NULL NULL
#define AVL_GET_LESS(h, a) (h)->less
@ -12,7 +12,7 @@
#define AVL_GET_BALANCE_FACTOR(h) (h)->factor
#define AVL_SET_BALANCE_FACTOR(h, f) USE((h), (h)->factor = f;);
#define AVL_SET_ROOT(h, v) (h)->root = v;
#define AVL_COMPARE_KEY_KEY(k1, k2) cmp64((k1), (k2))
#define AVL_COMPARE_KEY_KEY(k1, k2) yielded_block_cmp(&(k1), &(k2))
#define AVL_COMPARE_KEY_NODE(k, h) AVL_COMPARE_KEY_KEY((k), (h)->id)
#define AVL_COMPARE_NODE_NODE(h1, h2) AVL_COMPARE_KEY_KEY((h1)->id, (h2)->id)
#define AVL_INSIDE_STRUCT char pad[4];