Commit bec6f38730fb96bc6401db8097744c3a13c2af8d
1 parent
a92c8ac7
I do not use trees anymore within the optimized memory management. I realized th…
…at 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.
Showing
2 changed files
with
122 additions
and
289 deletions
| ... | ... | @@ -27,6 +27,48 @@ |
| 27 | 27 | |
| 28 | 28 | #include <sys/types.h> |
| 29 | 29 | |
| 30 | +/** | |
| 31 | + * I found this at stanford.edu: | |
| 32 | + * https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup | |
| 33 | + * | |
| 34 | + * Really cool way of dealing with this. The oneat stanford.edu is slightly | |
| 35 | + * different as ist deals only with 32bit values. I need a 64bit version | |
| 36 | + * because on a 64bit system size_t is also 64bit and thus it is possible | |
| 37 | + * to allocate that much amount of memory theoretically. | |
| 38 | + */ | |
| 39 | +static | |
| 40 | +inline | |
| 41 | +int | |
| 42 | +bitwidth(size_t value) | |
| 43 | +{ | |
| 44 | + static const char LogTable256[256] = { | |
| 45 | + -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, | |
| 46 | +#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n | |
| 47 | + LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6), | |
| 48 | + LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7) | |
| 49 | + }; | |
| 50 | +#undef LT | |
| 51 | + | |
| 52 | + int r; // r will be lg(v) | |
| 53 | + register size_t t1, t2, t3; // temporaries | |
| 54 | + | |
| 55 | + if ((t3 = value >> 32)) { | |
| 56 | + if ((t2 = t3 >> 16)) { | |
| 57 | + r = (t1 = t2 >> 8) ? 56 + LogTable256[t1] : 48 + LogTable256[t2]; | |
| 58 | + } else { | |
| 59 | + r = (t1 = t3 >> 8) ? 40 + LogTable256[t1] : 32 + LogTable256[t3]; | |
| 60 | + } | |
| 61 | + } else { | |
| 62 | + if ((t2 = value >> 16)) { | |
| 63 | + r = (t1 = t2 >> 8) ? 24 + LogTable256[t1] : 16 + LogTable256[t2]; | |
| 64 | + } else { | |
| 65 | + r = (t1 = value >> 8) ? 8 + LogTable256[t1] : LogTable256[value]; | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + return r; | |
| 70 | +} | |
| 71 | + | |
| 30 | 72 | void * TR_malloc(size_t); |
| 31 | 73 | void * TR_calloc(size_t, size_t); |
| 32 | 74 | void * TR_reference(void *); | ... | ... |
| ... | ... | @@ -53,310 +53,73 @@ |
| 53 | 53 | #include <string.h> |
| 54 | 54 | #include <search.h> |
| 55 | 55 | #include <unistd.h> |
| 56 | +#include <stdint.h> | |
| 56 | 57 | |
| 57 | 58 | #include "tr/memory.h" |
| 58 | -#include "tr/tree_macros.h" | |
| 59 | 59 | |
| 60 | 60 | |
| 61 | 61 | struct memSegment |
| 62 | 62 | { |
| 63 | 63 | size_t ref_count; |
| 64 | 64 | size_t size; |
| 65 | + int idx; | |
| 65 | 66 | void * ptr; |
| 66 | 67 | |
| 67 | - TR_rbColor color; | |
| 68 | - | |
| 69 | - struct memSegment * data; | |
| 70 | - | |
| 71 | 68 | struct memSegment * next; |
| 72 | - struct memSegment * last; | |
| 73 | - | |
| 74 | - struct memSegment * parent; | |
| 75 | - struct memSegment * left; | |
| 76 | - struct memSegment * right; | |
| 77 | 69 | }; |
| 78 | 70 | |
| 79 | 71 | static |
| 80 | 72 | struct memSegment * |
| 81 | -newElement(size_t size) | |
| 73 | +newElement(size_t size, int idx) | |
| 82 | 74 | { |
| 83 | 75 | struct memSegment * element = malloc(size); |
| 84 | 76 | |
| 85 | 77 | element->ref_count = 1; |
| 86 | 78 | element->size = size; |
| 79 | + element->idx = idx; | |
| 87 | 80 | element->ptr = (void*)element + sizeof(struct memSegment); |
| 88 | 81 | |
| 89 | - element->data = element; | |
| 90 | - | |
| 91 | 82 | element->next = NULL; |
| 92 | - element->last = NULL; | |
| 93 | - | |
| 94 | - element->color = rbRed; | |
| 95 | - element->parent = NULL; | |
| 96 | - element->left = NULL; | |
| 97 | - element->right = NULL; | |
| 98 | 83 | |
| 99 | 84 | return element; |
| 100 | 85 | } |
| 101 | 86 | |
| 102 | 87 | #ifdef MEM_OPT |
| 103 | -static | |
| 104 | -int | |
| 105 | -_memSegmentFindCompare(const void * a, const void * b) | |
| 106 | -{ | |
| 107 | - struct memSegment * _a = (struct memSegment *)a; | |
| 108 | - size_t _b = *(size_t *)b; | |
| 109 | - | |
| 110 | - /* | |
| 111 | - * find the smallest bigger or equal size segment | |
| 112 | - */ | |
| 113 | - return _a->size < _b ? -1 | |
| 114 | - : _a->size > _b && _a->left && _a->left->size >= _b ? 1 : 0; | |
| 115 | -} | |
| 116 | - | |
| 117 | -static | |
| 118 | -int | |
| 119 | -_memSegmentCompare(const void * a, const void * b) | |
| 120 | -{ | |
| 121 | - size_t _a = ((struct memSegment *)a)->size; | |
| 122 | - size_t _b = ((struct memSegment *)b)->size; | |
| 123 | - | |
| 124 | - return _a < _b ? -1 : _a > _b ? 1 : 0; | |
| 125 | -} | |
| 126 | - | |
| 127 | 88 | /** |
| 128 | 89 | * insert element in tree |
| 129 | 90 | */ |
| 130 | 91 | static |
| 92 | +inline | |
| 131 | 93 | struct memSegment * |
| 132 | -insertElement(struct memSegment ** tree, struct memSegment * element) | |
| 94 | +insertElement(struct memSegment ** stack, struct memSegment * element) | |
| 133 | 95 | { |
| 134 | - struct memSegment * node = *tree; | |
| 135 | - struct memSegment * new_node = NULL; | |
| 136 | - int found; | |
| 137 | - | |
| 138 | - element->next = NULL; | |
| 139 | - element->last = NULL; | |
| 140 | - | |
| 141 | - element->color = rbRed; | |
| 142 | - element->parent = NULL; | |
| 143 | - element->left = NULL; | |
| 144 | - element->right = NULL; | |
| 145 | - | |
| 146 | - TR_TREE_FIND(node, element, found, _memSegmentCompare); | |
| 147 | - | |
| 148 | - // if tree is empty it's simple... :) | |
| 149 | - if (NULL == node) { | |
| 150 | - *tree = node = new_node = element; | |
| 151 | - } else { | |
| 152 | - // normal binary tree add.... | |
| 153 | - if (found == 0) { | |
| 154 | - if (NULL == node->next) { | |
| 155 | - node->next = element; | |
| 156 | - node->last = element; | |
| 157 | - } else { | |
| 158 | - node->last->next = element; | |
| 159 | - node->last = element; | |
| 160 | - } | |
| 161 | - return node; | |
| 162 | - } else { | |
| 163 | - if (0 < found) { | |
| 164 | - node->left = element; | |
| 165 | - node->left->parent = node; | |
| 166 | - new_node = node = node->left; | |
| 167 | - } else { | |
| 168 | - node->right = element; | |
| 169 | - node->right->parent = node; | |
| 170 | - new_node = node = node->right; | |
| 96 | + element->next = *stack; | |
| 97 | + *stack = element; | |
| 171 | 98 | |
| 172 | - } | |
| 173 | - } | |
| 174 | - } | |
| 175 | - | |
| 176 | - /* | |
| 177 | - * handle reballancing rb style | |
| 178 | - */ | |
| 179 | - TR_TREE_BALANCE_INSERT(tree, node); | |
| 180 | - | |
| 181 | - return new_node; | |
| 99 | + return element; | |
| 182 | 100 | } |
| 183 | 101 | |
| 184 | 102 | static |
| 103 | +inline | |
| 185 | 104 | struct memSegment * |
| 186 | -deleteElement(struct memSegment ** tree, size_t size) | |
| 105 | +deleteElement(struct memSegment ** stack) | |
| 187 | 106 | { |
| 188 | - struct memSegment * node = *tree; | |
| 189 | - struct memSegment * del_node; | |
| 190 | - struct memSegment * child; | |
| 191 | - struct memSegment * s; | |
| 192 | - int found; | |
| 193 | - | |
| 194 | - // find the relevant node and it's parent | |
| 195 | - TR_TREE_FIND(node, &size, found, _memSegmentFindCompare); | |
| 107 | + struct memSegment * del_node = *stack; | |
| 196 | 108 | |
| 197 | - //while (node) { | |
| 198 | - if (found != 0) { | |
| 199 | - return NULL; | |
| 200 | - } else { | |
| 201 | - if (NULL != node->next) { | |
| 202 | - if (NULL != node->parent) { | |
| 203 | - if (node == node->parent->left) { | |
| 204 | - node->parent->left = node->next; | |
| 205 | - } else { | |
| 206 | - node->parent->right = node->next; | |
| 207 | - } | |
| 208 | - } else { | |
| 209 | - *tree = node->next; | |
| 210 | - } | |
| 211 | - | |
| 212 | - if (NULL != node->left) { | |
| 213 | - node->left->parent = node->next; | |
| 214 | - } | |
| 215 | - | |
| 216 | - if (NULL != node->right) { | |
| 217 | - node->right->parent = node->next; | |
| 218 | - } | |
| 219 | - | |
| 220 | - node->next->last = node->last; | |
| 221 | - node->next->color = node->color; | |
| 222 | - node->next->parent = node->parent; | |
| 223 | - node->next->left = node->left; | |
| 224 | - node->next->right = node->right; | |
| 225 | - | |
| 226 | - return node; | |
| 227 | - } | |
| 109 | + if (*stack) { | |
| 110 | + *stack = (*stack)->next; | |
| 228 | 111 | } |
| 229 | 112 | |
| 230 | - del_node = node; | |
| 231 | - | |
| 232 | - // now our cases follows...the first one is the same as with | |
| 233 | - // simple binary search trees. Two non null children. | |
| 234 | - | |
| 235 | - // case 1: two children | |
| 236 | - if (NULL != node->left && NULL != node->right) { | |
| 237 | - struct memSegment * successor; | |
| 238 | - struct memSegment * tmpparent; | |
| 239 | - struct memSegment * tmpleft; | |
| 240 | - struct memSegment * tmpright; | |
| 241 | - TR_rbColor tmpcolor; | |
| 242 | - | |
| 243 | - TR_TREE_INORDER_SUCC(node, successor); | |
| 244 | - tmpparent = successor->parent; | |
| 245 | - tmpleft = successor->left; | |
| 246 | - tmpright = successor->right; | |
| 247 | - tmpcolor = successor->color; | |
| 248 | - | |
| 249 | - TR_TREE_REPLACE_NODE(tree, node, successor); | |
| 250 | - | |
| 251 | - successor->color = node->color; | |
| 252 | - successor->left = node->left; | |
| 253 | - successor->left->parent = successor; | |
| 254 | - // the right one might be successor... | |
| 255 | - if (node->right == successor) { | |
| 256 | - successor->right = node; | |
| 257 | - node->parent = successor; | |
| 258 | - } else { | |
| 259 | - successor->right = node->right; | |
| 260 | - node->right->parent = successor; | |
| 261 | - node->parent = tmpparent; | |
| 262 | - tmpparent->left = node; | |
| 263 | - } | |
| 264 | - | |
| 265 | - node->color = tmpcolor; | |
| 266 | - node->left = tmpleft; | |
| 267 | - node->right = tmpright; | |
| 268 | - } | |
| 269 | - | |
| 270 | - // Precondition: n has at most one non-null child. | |
| 271 | - child = (NULL == node->right) ? node->left : node->right; | |
| 272 | - TR_TREE_REPLACE_NODE(tree, node, child); | |
| 273 | - | |
| 274 | - // delete one child case | |
| 275 | - // TODO this is overly complex as simply derived from the function... | |
| 276 | - // maybe this can be simplified. Maybe not...check. | |
| 277 | - if (node->color == rbBlack) { | |
| 278 | - if (NULL != child && child->color == rbRed) { | |
| 279 | - child->color = rbBlack; | |
| 280 | - // done despite modifying tree itself if neccessary.. | |
| 281 | - return del_node; | |
| 282 | - } else { | |
| 283 | - if (NULL != child) { | |
| 284 | - node = child; | |
| 285 | - } else { | |
| 286 | - node->color = rbBlack; | |
| 287 | - node->left = NULL; | |
| 288 | - node->right = NULL; | |
| 289 | - } | |
| 290 | - } | |
| 291 | - } else { | |
| 292 | - return del_node; | |
| 293 | - } | |
| 294 | - | |
| 295 | - TR_TREE_BALANCE_DELETE(tree, node, s); | |
| 296 | - | |
| 297 | - return del_node; | |
| 113 | + return del_node; | |
| 298 | 114 | } |
| 299 | 115 | |
| 300 | -static | |
| 301 | -void | |
| 302 | -post(struct memSegment * tree, void (*cb)(struct memSegment *, int)) | |
| 303 | -{ | |
| 304 | - struct memSegment * previous = tree; | |
| 305 | - struct memSegment * node = tree; | |
| 306 | - int depth = 1; | |
| 307 | - | |
| 308 | - /* | |
| 309 | - * I think this has something like O(n+log(n)) on a ballanced | |
| 310 | - * tree because I have to traverse back the rightmost leaf to | |
| 311 | - * the root to get a break condition. | |
| 312 | - */ | |
| 313 | - while (node) { | |
| 314 | - /* | |
| 315 | - * If we come from the right so nothing and go to our | |
| 316 | - * next parent. | |
| 317 | - */ | |
| 318 | - if (((NULL == node->left || previous == node->left) | |
| 319 | - && NULL == node->right) | |
| 320 | - || previous == node->right) { | |
| 321 | - | |
| 322 | - struct memSegment * parent = node->parent; | |
| 323 | - | |
| 324 | - cb(node, depth); | |
| 325 | - | |
| 326 | - previous = node; | |
| 327 | - node = parent; | |
| 328 | - depth--; | |
| 329 | - continue; | |
| 330 | - } | |
| 116 | +#define TR_MAX_MEM_IDX 1024 | |
| 331 | 117 | |
| 332 | - if ((NULL == node->left || previous == node->left)) { | |
| 333 | - /* | |
| 334 | - * If there are no more elements to the left or we | |
| 335 | - * came from the left, process data. | |
| 336 | - */ | |
| 337 | - previous = node; | |
| 338 | - | |
| 339 | - if (NULL != node->right) { | |
| 340 | - node = node->right; | |
| 341 | - depth++; | |
| 342 | - } else { | |
| 343 | - node = node->parent; | |
| 344 | - depth--; | |
| 345 | - } | |
| 346 | - } else { | |
| 347 | - /* | |
| 348 | - * if there are more elements to the left go there. | |
| 349 | - */ | |
| 350 | - previous = node; | |
| 351 | - node = node->left; | |
| 352 | - depth++; | |
| 353 | - } | |
| 354 | - } | |
| 355 | -} | |
| 356 | - | |
| 357 | -struct memSegment * segments = NULL; | |
| 118 | +struct memSegment * segments[TR_MAX_MEM_IDX] = {}; | |
| 119 | +pthread_mutex_t TR_memop_lock = PTHREAD_MUTEX_INITIALIZER; | |
| 358 | 120 | |
| 359 | 121 | static |
| 122 | +inline | |
| 360 | 123 | void |
| 361 | 124 | segmentFree(struct memSegment * segment, int depth) |
| 362 | 125 | { |
| ... | ... | @@ -378,8 +141,6 @@ TR_reference(void * mem) |
| 378 | 141 | return mem; |
| 379 | 142 | } |
| 380 | 143 | |
| 381 | -pthread_mutex_t TR_memop_lock = PTHREAD_MUTEX_INITIALIZER; | |
| 382 | - | |
| 383 | 144 | /* |
| 384 | 145 | * This tries to reflect the memory management behaviour of the |
| 385 | 146 | * GNU version of malloc. For other versions this might need |
| ... | ... | @@ -410,41 +171,60 @@ pthread_mutex_t TR_memop_lock = PTHREAD_MUTEX_INITIALIZER; |
| 410 | 171 | void * |
| 411 | 172 | TR_malloc(size_t size) |
| 412 | 173 | { |
| 413 | - struct memSegment * seg = NULL; | |
| 414 | - long psize = sysconf(_SC_PAGESIZE); | |
| 174 | + struct memSegment * seg = NULL; | |
| 175 | + long psize = sysconf(_SC_PAGESIZE); | |
| 176 | + static int psize_width = 0; | |
| 177 | + int idx; | |
| 178 | + | |
| 179 | + if (psize_width == 0) psize_width = bitwidth(psize); | |
| 415 | 180 | |
| 416 | 181 | size += sizeof(struct memSegment); |
| 417 | 182 | |
| 418 | - if (size > psize) { | |
| 419 | - if (0 != (size % psize)) { | |
| 420 | - // size if not a multiple of pagesize so bring it to one. | |
| 421 | - size = ((size / psize) + 1) * psize; | |
| 422 | - } | |
| 423 | - } else { | |
| 424 | - if (size < 8) { | |
| 425 | - size = 8; | |
| 426 | - } else { | |
| 427 | - size_t check = size >> 4; | |
| 428 | - size_t mask = 0x1F; | |
| 183 | +#define MIN_BITS 8 | |
| 429 | 184 | |
| 430 | - while (check >>= 1) { | |
| 431 | - mask = (mask << 1) | 1; | |
| 432 | - } | |
| 185 | + if (size >= psize) { | |
| 186 | + idx = size / psize; | |
| 433 | 187 | |
| 434 | - if (size != (size & ~(mask >> 1))) { | |
| 435 | - size = (size << 1) & ~mask; | |
| 436 | - } | |
| 437 | - } | |
| 438 | - } | |
| 188 | + if (0 != (size % psize)) { | |
| 189 | + // size if not a multiple of pagesize so bring it to one. | |
| 190 | + size = (idx + 1) * psize; | |
| 191 | + idx++; | |
| 192 | + } | |
| 193 | + | |
| 194 | + idx += psize_width - MIN_BITS; | |
| 195 | + } else { | |
| 196 | + if (size <= 1 << (MIN_BITS - 1)) { | |
| 197 | + size = 1 << (MIN_BITS - 1); | |
| 198 | + idx = 0; | |
| 199 | + } else { | |
| 200 | + size_t mask; | |
| 201 | + | |
| 202 | + idx = bitwidth(size); | |
| 203 | + mask = (1 << (idx + 1)) - 1; | |
| 204 | + idx -= (MIN_BITS - 1); | |
| 205 | + | |
| 206 | + if (size != (size & ~(mask >> 1))) { | |
| 207 | + size = (size << 1) & ~mask; | |
| 208 | + idx++; | |
| 209 | + } | |
| 210 | + } | |
| 211 | + } | |
| 212 | + | |
| 213 | +#undef MIN_BITS | |
| 439 | 214 | |
| 440 | 215 | #ifdef MEM_OPT |
| 441 | - pthread_mutex_lock(&TR_memop_lock); | |
| 442 | - seg = deleteElement(&segments, size); | |
| 443 | - pthread_mutex_unlock(&TR_memop_lock); | |
| 216 | + if (idx < TR_MAX_MEM_IDX) { | |
| 217 | + pthread_mutex_lock(&TR_memop_lock); | |
| 218 | + seg = deleteElement(&(segments[idx])); | |
| 219 | + pthread_mutex_unlock(&TR_memop_lock); | |
| 220 | + } else | |
| 444 | 221 | #endif |
| 222 | + { | |
| 223 | + idx = -1; | |
| 224 | + } | |
| 445 | 225 | |
| 446 | 226 | if (NULL == seg) { |
| 447 | - seg = newElement(size); | |
| 227 | + seg = newElement(size, idx); | |
| 448 | 228 | } |
| 449 | 229 | |
| 450 | 230 | return seg->ptr; |
| ... | ... | @@ -479,12 +259,15 @@ TR_free(void ** mem) |
| 479 | 259 | seg->ref_count--; |
| 480 | 260 | } else { |
| 481 | 261 | #ifdef MEM_OPT |
| 482 | - pthread_mutex_lock(&TR_memop_lock); | |
| 483 | - insertElement(&segments, seg); | |
| 484 | - pthread_mutex_unlock(&TR_memop_lock); | |
| 485 | -#else | |
| 486 | - free(seg); | |
| 262 | + if (-1 != seg->idx) { | |
| 263 | + pthread_mutex_lock(&TR_memop_lock); | |
| 264 | + insertElement(&(segments[seg->idx]), seg); | |
| 265 | + pthread_mutex_unlock(&TR_memop_lock); | |
| 266 | + } else | |
| 487 | 267 | #endif |
| 268 | + { | |
| 269 | + free(seg); | |
| 270 | + } | |
| 488 | 271 | } |
| 489 | 272 | |
| 490 | 273 | *mem = NULL; |
| ... | ... | @@ -508,7 +291,15 @@ void |
| 508 | 291 | TR_cleanup() |
| 509 | 292 | { |
| 510 | 293 | #ifdef MEM_OPT |
| 511 | - post(segments, segmentFree); | |
| 294 | + int i; | |
| 295 | + | |
| 296 | + for (i=0; i<TR_MAX_MEM_IDX; i++) { | |
| 297 | + while(segments[i]) { | |
| 298 | + struct memSegment * next = segments[i]->next; | |
| 299 | + free(segments[i]); | |
| 300 | + segments[i] = next; | |
| 301 | + } | |
| 302 | + } | |
| 512 | 303 | #endif |
| 513 | 304 | } |
| 514 | 305 | ... | ... |
Please
register
or
login
to post a comment