ref: 249915c3795858582dbf5b0f1e1533b50b90737d
parent: 0a7e9ba1f567da92a4de50232e77dda924a9b7b8
author: cinap_lenrek <[email protected]>
date: Fri Jun 14 13:31:04 EDT 2013
pool: use splaying to balance free node tree use splaytree algorithm to balance the tree of free allocations as an optimization. the data structures are unchanged by this optimization.
--- a/sys/src/libc/port/pool.c
+++ b/sys/src/libc/port/pool.c
@@ -141,10 +141,7 @@
static ulong dsize2bsize(Pool*, ulong);
static ulong getdsize(Alloc*);
static Alloc* trim(Pool*, Alloc*, ulong);
-static Free* listadd(Free*, Free*);
-static Free* listdelete(Free*, Free*);
static void logstack(Pool*);
-static Free** ltreewalk(Free**, ulong);
static void memmark(void*, int, ulong);
static Free* pooladd(Pool*, Alloc*);
static void* poolallocl(Pool*, ulong);
@@ -157,9 +154,8 @@
static void poolfreel(Pool*, void*);
static void poolnewarena(Pool*, ulong);
static void* poolreallocl(Pool*, void*, ulong);
-static Free* treedelete(Free*, Free*);
-static Free* treeinsert(Free*, Free*);
static Free* treelookupgt(Free*, ulong);
+static Free* treesplay(Free*, ulong);
/*
* Debugging
@@ -225,76 +221,6 @@
}
-/* ltreewalk: return address of pointer to node of size == size */
-static Free**
-ltreewalk(Free **t, ulong size)
-{
- Free *f;
-
- for(;;) {
- f = *t;
- if(f == nil || f->magic != FREE_MAGIC)
- return t;
- if(size == f->size)
- return t;
- if(size < f->size)
- t = &f->left;
- else
- t = &f->right;
- }
-}
-
-/* treeinsert: insert node into tree */
-static Free*
-treeinsert(Free *tree, Free *node)
-{
- Free **loc, *repl;
-
- assert(node != nil /* treeinsert */);
-
- loc = ltreewalk(&tree, node->size);
- repl = *loc;
- if(repl == nil || repl->magic != FREE_MAGIC) {
- node->left = nil;
- node->right = nil;
- } else { /* replace existing node */
- node->left = repl->left;
- node->right = repl->right;
- }
- *loc = node;
- return tree;
-}
-
-/* treedelete: remove node from tree */
-static Free*
-treedelete(Free *tree, Free *node)
-{
- Free **loc, **lsucc, *succ;
-
- assert(node != nil /* treedelete */);
-
- loc = ltreewalk(&tree, node->size);
- if(*loc != node || node->magic != FREE_MAGIC)
- return tree; /* free nodes corrupted */
-
- if(node->left == nil)
- *loc = node->right;
- else if(node->right == nil)
- *loc = node->left;
- else {
- /* have two children, use inorder successor as replacement */
- for(lsucc = &node->right; (*lsucc)->left; lsucc = &(*lsucc)->left)
- ;
- succ = *lsucc;
- *lsucc = succ->right;
- succ->left = node->left;
- succ->right = node->right;
- *loc = succ;
- }
- node->left = node->right = Poison;
- return tree;
-}
-
/* treelookupgt: find smallest node in tree with size >= size */
static Free*
treelookupgt(Free *t, ulong size)
@@ -303,8 +229,9 @@
lastgood = nil;
for(;;) {
- if(t == nil || t->magic != FREE_MAGIC)
+ if(t == nil)
return lastgood;
+ assert(t->magic == FREE_MAGIC);
if(size == t->size)
return t;
if(size < t->size) {
@@ -315,59 +242,64 @@
}
}
-/*
- * List maintenance
- */
-
-/* listadd: add a node to a doubly linked list */
+/* treesplay: splay node of size size to the root and return new root */
static Free*
-listadd(Free *list, Free *node)
+treesplay(Free *t, ulong size)
{
- if(list == nil) {
- node->next = node;
- node->prev = node;
- return node;
- }
+ Free N, *l, *r, *y;
- node->prev = list->prev;
- node->next = list;
+ N.left = N.right = nil;
+ l = r = &N;
- node->prev->next = node;
- node->next->prev = node;
-
- return list;
-}
-
-/* listdelete: remove node from a doubly linked list */
-static Free*
-listdelete(Free *list, Free *node)
-{
- if(node->next == node) { /* singular list */
- node->prev = node->next = Poison;
- return nil;
+ for(;;) {
+ assert(t->magic == FREE_MAGIC);
+ if(size < t->size) {
+ y = t->left;
+ if(y != nil) {
+ assert(y->magic == FREE_MAGIC);
+ if(size < y->size) {
+ t->left = y->right;
+ y->right = t;
+ t = y;
+ }
+ }
+ if(t->left == nil)
+ break;
+ r->left = t;
+ r = t;
+ t = t->left;
+ } else if(size > t->size) {
+ y = t->right;
+ if(y != nil) {
+ assert(y->magic == FREE_MAGIC);
+ if(size > y->size) {
+ t->right = y->left;
+ y->left = t;
+ t = y;
+ }
+ }
+ if(t->right == nil)
+ break;
+ l->right = t;
+ l = t;
+ t = t->right;
+ } else
+ break;
}
- node->next->prev = node->prev;
- node->prev->next = node->next;
+ l->right=t->left;
+ r->left=t->right;
+ t->left=N.right;
+ t->right=N.left;
- if(list == node)
- list = node->next;
-
- node->prev = node->next = Poison;
- return list;
+ return t;
}
-/*
- * Pool maintenance
- */
-
/* pooladd: add anode to the free pool */
static Free*
pooladd(Pool *p, Alloc *anode)
{
- Free *lst, *olst;
- Free *node;
- Free **parent;
+ Free *node, *root;
antagonism {
memmark(_B2D(anode), 0xF7, anode->size-sizeof(Bhdr)-sizeof(Btail));
@@ -375,17 +307,33 @@
node = (Free*)anode;
node->magic = FREE_MAGIC;
- parent = ltreewalk(&p->freeroot, node->size);
- olst = *parent;
- if(olst != nil && olst->magic != FREE_MAGIC){
- /* corruption of free nodes */
- poolcheckl(p);
- olst = *parent = nil;
+ node->left = node->right = nil;
+ node->next = node->prev = node;
+
+ if(p->freeroot != nil) {
+ root = treesplay(p->freeroot, node->size);
+ if(root->size > node->size) {
+ node->left = root->left;
+ node->right = root;
+ root->left = nil;
+ } else if(root->size < node->size) {
+ node->right = root->right;
+ node->left = root;
+ root->right = nil;
+ } else {
+ node->left = root->left;
+ node->right = root->right;
+ root->left = root->right = Poison;
+
+ node->prev = root->prev;
+ node->next = root;
+ node->prev->next = node;
+ node->next->prev = node;
+ }
}
- lst = listadd(olst, node);
- if(olst != lst) /* need to update tree */
- *parent = treeinsert(*parent, lst);
+ p->freeroot = node;
p->curfree += node->size;
+
return node;
}
@@ -393,30 +341,38 @@
static Alloc*
pooldel(Pool *p, Free *node)
{
- Free *lst, *olst;
- Free **parent;
+ Free *root;
- parent = ltreewalk(&p->freeroot, node->size);
- olst = *parent;
- if(olst == nil || olst->magic != FREE_MAGIC){
- /* corruption of free nodes */
- poolcheckl(p);
- *parent = nil;
+ root = treesplay(p->freeroot, node->size);
+ if(node == root && node->next == node) {
+ if(node->left == nil)
+ root = node->right;
+ else {
+ root = treesplay(node->left, node->size);
+ assert(root->right == nil);
+ root->right = node->right;
+ }
} else {
- lst = listdelete(olst, node);
- if(lst == nil)
- *parent = treedelete(*parent, olst);
- else if(lst != olst)
- *parent = treeinsert(*parent, lst);
+ if(node == root) {
+ root = node->next;
+ root->left = node->left;
+ root->right = node->right;
+ }
+ assert(root->magic == FREE_MAGIC && root->size == node->size);
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
}
- node->left = node->right = Poison;
+ p->freeroot = root;
p->curfree -= node->size;
+ node->left = node->right = node->next = node->prev = Poison;
+
antagonism {
memmark(_B2D(node), 0xF9, node->size-sizeof(Bhdr)-sizeof(Btail));
}
node->magic = UNALLOC_MAGIC;
+
return (Alloc*)node;
}