shithub: riscv

Download patch

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;
 }