diff --git a/include/tr/memory.h b/include/tr/memory.h index 7c905cc..127ae86 100644 --- a/include/tr/memory.h +++ b/include/tr/memory.h @@ -27,6 +27,48 @@ #include +/** + * I found this at stanford.edu: + * https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup + * + * Really cool way of dealing with this. The oneat stanford.edu is slightly + * different as ist deals only with 32bit values. I need a 64bit version + * because on a 64bit system size_t is also 64bit and thus it is possible + * to allocate that much amount of memory theoretically. + */ +static +inline +int +bitwidth(size_t value) +{ + static const char LogTable256[256] = { + -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, +#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n + LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6), + LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7) + }; +#undef LT + + int r; // r will be lg(v) + register size_t t1, t2, t3; // temporaries + + if ((t3 = value >> 32)) { + if ((t2 = t3 >> 16)) { + r = (t1 = t2 >> 8) ? 56 + LogTable256[t1] : 48 + LogTable256[t2]; + } else { + r = (t1 = t3 >> 8) ? 40 + LogTable256[t1] : 32 + LogTable256[t3]; + } + } else { + if ((t2 = value >> 16)) { + r = (t1 = t2 >> 8) ? 24 + LogTable256[t1] : 16 + LogTable256[t2]; + } else { + r = (t1 = value >> 8) ? 8 + LogTable256[t1] : LogTable256[value]; + } + } + + return r; +} + void * TR_malloc(size_t); void * TR_calloc(size_t, size_t); void * TR_reference(void *); diff --git a/src/memory.c b/src/memory.c index 4d109a8..87ff5af 100644 --- a/src/memory.c +++ b/src/memory.c @@ -53,310 +53,73 @@ #include #include #include +#include #include "tr/memory.h" -#include "tr/tree_macros.h" struct memSegment { size_t ref_count; size_t size; + int idx; void * ptr; - TR_rbColor color; - - struct memSegment * data; - struct memSegment * next; - struct memSegment * last; - - struct memSegment * parent; - struct memSegment * left; - struct memSegment * right; }; static struct memSegment * -newElement(size_t size) +newElement(size_t size, int idx) { struct memSegment * element = malloc(size); element->ref_count = 1; element->size = size; + element->idx = idx; element->ptr = (void*)element + sizeof(struct memSegment); - element->data = element; - element->next = NULL; - element->last = NULL; - - element->color = rbRed; - element->parent = NULL; - element->left = NULL; - element->right = NULL; return element; } #ifdef MEM_OPT -static -int -_memSegmentFindCompare(const void * a, const void * b) -{ - struct memSegment * _a = (struct memSegment *)a; - size_t _b = *(size_t *)b; - - /* - * find the smallest bigger or equal size segment - */ - return _a->size < _b ? -1 - : _a->size > _b && _a->left && _a->left->size >= _b ? 1 : 0; -} - -static -int -_memSegmentCompare(const void * a, const void * b) -{ - size_t _a = ((struct memSegment *)a)->size; - size_t _b = ((struct memSegment *)b)->size; - - return _a < _b ? -1 : _a > _b ? 1 : 0; -} - /** * insert element in tree */ static +inline struct memSegment * -insertElement(struct memSegment ** tree, struct memSegment * element) +insertElement(struct memSegment ** stack, struct memSegment * element) { - struct memSegment * node = *tree; - struct memSegment * new_node = NULL; - int found; - - element->next = NULL; - element->last = NULL; - - element->color = rbRed; - element->parent = NULL; - element->left = NULL; - element->right = NULL; - - TR_TREE_FIND(node, element, found, _memSegmentCompare); - - // if tree is empty it's simple... :) - if (NULL == node) { - *tree = node = new_node = element; - } else { - // normal binary tree add.... - if (found == 0) { - if (NULL == node->next) { - node->next = element; - node->last = element; - } else { - node->last->next = element; - node->last = element; - } - return node; - } else { - if (0 < found) { - node->left = element; - node->left->parent = node; - new_node = node = node->left; - } else { - node->right = element; - node->right->parent = node; - new_node = node = node->right; + element->next = *stack; + *stack = element; - } - } - } - - /* - * handle reballancing rb style - */ - TR_TREE_BALANCE_INSERT(tree, node); - - return new_node; + return element; } static +inline struct memSegment * -deleteElement(struct memSegment ** tree, size_t size) +deleteElement(struct memSegment ** stack) { - struct memSegment * node = *tree; - struct memSegment * del_node; - struct memSegment * child; - struct memSegment * s; - int found; - - // find the relevant node and it's parent - TR_TREE_FIND(node, &size, found, _memSegmentFindCompare); + struct memSegment * del_node = *stack; - //while (node) { - if (found != 0) { - return NULL; - } else { - if (NULL != node->next) { - if (NULL != node->parent) { - if (node == node->parent->left) { - node->parent->left = node->next; - } else { - node->parent->right = node->next; - } - } else { - *tree = node->next; - } - - if (NULL != node->left) { - node->left->parent = node->next; - } - - if (NULL != node->right) { - node->right->parent = node->next; - } - - node->next->last = node->last; - node->next->color = node->color; - node->next->parent = node->parent; - node->next->left = node->left; - node->next->right = node->right; - - return node; - } + if (*stack) { + *stack = (*stack)->next; } - del_node = node; - - // now our cases follows...the first one is the same as with - // simple binary search trees. Two non null children. - - // case 1: two children - if (NULL != node->left && NULL != node->right) { - struct memSegment * successor; - struct memSegment * tmpparent; - struct memSegment * tmpleft; - struct memSegment * tmpright; - TR_rbColor tmpcolor; - - TR_TREE_INORDER_SUCC(node, successor); - tmpparent = successor->parent; - tmpleft = successor->left; - tmpright = successor->right; - tmpcolor = successor->color; - - TR_TREE_REPLACE_NODE(tree, node, successor); - - successor->color = node->color; - successor->left = node->left; - successor->left->parent = successor; - // the right one might be successor... - if (node->right == successor) { - successor->right = node; - node->parent = successor; - } else { - successor->right = node->right; - node->right->parent = successor; - node->parent = tmpparent; - tmpparent->left = node; - } - - node->color = tmpcolor; - node->left = tmpleft; - node->right = tmpright; - } - - // Precondition: n has at most one non-null child. - child = (NULL == node->right) ? node->left : node->right; - TR_TREE_REPLACE_NODE(tree, node, child); - - // delete one child case - // TODO this is overly complex as simply derived from the function... - // maybe this can be simplified. Maybe not...check. - if (node->color == rbBlack) { - if (NULL != child && child->color == rbRed) { - child->color = rbBlack; - // done despite modifying tree itself if neccessary.. - return del_node; - } else { - if (NULL != child) { - node = child; - } else { - node->color = rbBlack; - node->left = NULL; - node->right = NULL; - } - } - } else { - return del_node; - } - - TR_TREE_BALANCE_DELETE(tree, node, s); - - return del_node; + return del_node; } -static -void -post(struct memSegment * tree, void (*cb)(struct memSegment *, int)) -{ - struct memSegment * previous = tree; - struct memSegment * node = tree; - int depth = 1; - - /* - * I think this has something like O(n+log(n)) on a ballanced - * tree because I have to traverse back the rightmost leaf to - * the root to get a break condition. - */ - while (node) { - /* - * If we come from the right so nothing and go to our - * next parent. - */ - if (((NULL == node->left || previous == node->left) - && NULL == node->right) - || previous == node->right) { - - struct memSegment * parent = node->parent; - - cb(node, depth); - - previous = node; - node = parent; - depth--; - continue; - } +#define TR_MAX_MEM_IDX 1024 - if ((NULL == node->left || previous == node->left)) { - /* - * If there are no more elements to the left or we - * came from the left, process data. - */ - previous = node; - - if (NULL != node->right) { - node = node->right; - depth++; - } else { - node = node->parent; - depth--; - } - } else { - /* - * if there are more elements to the left go there. - */ - previous = node; - node = node->left; - depth++; - } - } -} - -struct memSegment * segments = NULL; +struct memSegment * segments[TR_MAX_MEM_IDX] = {}; +pthread_mutex_t TR_memop_lock = PTHREAD_MUTEX_INITIALIZER; static +inline void segmentFree(struct memSegment * segment, int depth) { @@ -378,8 +141,6 @@ TR_reference(void * mem) return mem; } -pthread_mutex_t TR_memop_lock = PTHREAD_MUTEX_INITIALIZER; - /* * This tries to reflect the memory management behaviour of the * GNU version of malloc. For other versions this might need @@ -410,41 +171,60 @@ pthread_mutex_t TR_memop_lock = PTHREAD_MUTEX_INITIALIZER; void * TR_malloc(size_t size) { - struct memSegment * seg = NULL; - long psize = sysconf(_SC_PAGESIZE); + struct memSegment * seg = NULL; + long psize = sysconf(_SC_PAGESIZE); + static int psize_width = 0; + int idx; + + if (psize_width == 0) psize_width = bitwidth(psize); size += sizeof(struct memSegment); - if (size > psize) { - if (0 != (size % psize)) { - // size if not a multiple of pagesize so bring it to one. - size = ((size / psize) + 1) * psize; - } - } else { - if (size < 8) { - size = 8; - } else { - size_t check = size >> 4; - size_t mask = 0x1F; +#define MIN_BITS 8 - while (check >>= 1) { - mask = (mask << 1) | 1; - } + if (size >= psize) { + idx = size / psize; - if (size != (size & ~(mask >> 1))) { - size = (size << 1) & ~mask; - } - } - } + if (0 != (size % psize)) { + // size if not a multiple of pagesize so bring it to one. + size = (idx + 1) * psize; + idx++; + } + + idx += psize_width - MIN_BITS; + } else { + if (size <= 1 << (MIN_BITS - 1)) { + size = 1 << (MIN_BITS - 1); + idx = 0; + } else { + size_t mask; + + idx = bitwidth(size); + mask = (1 << (idx + 1)) - 1; + idx -= (MIN_BITS - 1); + + if (size != (size & ~(mask >> 1))) { + size = (size << 1) & ~mask; + idx++; + } + } + } + +#undef MIN_BITS #ifdef MEM_OPT - pthread_mutex_lock(&TR_memop_lock); - seg = deleteElement(&segments, size); - pthread_mutex_unlock(&TR_memop_lock); + if (idx < TR_MAX_MEM_IDX) { + pthread_mutex_lock(&TR_memop_lock); + seg = deleteElement(&(segments[idx])); + pthread_mutex_unlock(&TR_memop_lock); + } else #endif + { + idx = -1; + } if (NULL == seg) { - seg = newElement(size); + seg = newElement(size, idx); } return seg->ptr; @@ -479,12 +259,15 @@ TR_free(void ** mem) seg->ref_count--; } else { #ifdef MEM_OPT - pthread_mutex_lock(&TR_memop_lock); - insertElement(&segments, seg); - pthread_mutex_unlock(&TR_memop_lock); -#else - free(seg); + if (-1 != seg->idx) { + pthread_mutex_lock(&TR_memop_lock); + insertElement(&(segments[seg->idx]), seg); + pthread_mutex_unlock(&TR_memop_lock); + } else #endif + { + free(seg); + } } *mem = NULL; @@ -508,7 +291,15 @@ void TR_cleanup() { #ifdef MEM_OPT - post(segments, segmentFree); + int i; + + for (i=0; inext; + free(segments[i]); + segments[i] = next; + } + } #endif }