Browse Source

I do not use trees anymore within the optimized memory management. I realized that I can calculate the index of an array by the size and use stacks of memory segments under each array element. This should be much faster.

1.0.2
Georg Hopp 11 years ago
parent
commit
bec6f38730
  1. 42
      include/tr/memory.h
  2. 369
      src/memory.c

42
include/tr/memory.h

@ -27,6 +27,48 @@
#include <sys/types.h>
/**
* 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 *);

369
src/memory.c

@ -53,310 +53,73 @@
#include <string.h>
#include <search.h>
#include <unistd.h>
#include <stdint.h>
#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; i<TR_MAX_MEM_IDX; i++) {
while(segments[i]) {
struct memSegment * next = segments[i]->next;
free(segments[i]);
segments[i] = next;
}
}
#endif
}

Loading…
Cancel
Save