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,6 +27,48 @@ | ||
27 | 27 | ||
28 | #include <sys/types.h> | 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 | void * TR_malloc(size_t); | 72 | void * TR_malloc(size_t); |
31 | void * TR_calloc(size_t, size_t); | 73 | void * TR_calloc(size_t, size_t); |
32 | void * TR_reference(void *); | 74 | void * TR_reference(void *); |
@@ -53,310 +53,73 @@ | @@ -53,310 +53,73 @@ | ||
53 | #include <string.h> | 53 | #include <string.h> |
54 | #include <search.h> | 54 | #include <search.h> |
55 | #include <unistd.h> | 55 | #include <unistd.h> |
56 | +#include <stdint.h> | ||
56 | 57 | ||
57 | #include "tr/memory.h" | 58 | #include "tr/memory.h" |
58 | -#include "tr/tree_macros.h" | ||
59 | 59 | ||
60 | 60 | ||
61 | struct memSegment | 61 | struct memSegment |
62 | { | 62 | { |
63 | size_t ref_count; | 63 | size_t ref_count; |
64 | size_t size; | 64 | size_t size; |
65 | + int idx; | ||
65 | void * ptr; | 66 | void * ptr; |
66 | 67 | ||
67 | - TR_rbColor color; | ||
68 | - | ||
69 | - struct memSegment * data; | ||
70 | - | ||
71 | struct memSegment * next; | 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 | static | 71 | static |
80 | struct memSegment * | 72 | struct memSegment * |
81 | -newElement(size_t size) | 73 | +newElement(size_t size, int idx) |
82 | { | 74 | { |
83 | struct memSegment * element = malloc(size); | 75 | struct memSegment * element = malloc(size); |
84 | 76 | ||
85 | element->ref_count = 1; | 77 | element->ref_count = 1; |
86 | element->size = size; | 78 | element->size = size; |
79 | + element->idx = idx; | ||
87 | element->ptr = (void*)element + sizeof(struct memSegment); | 80 | element->ptr = (void*)element + sizeof(struct memSegment); |
88 | 81 | ||
89 | - element->data = element; | ||
90 | - | ||
91 | element->next = NULL; | 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 | return element; | 84 | return element; |
100 | } | 85 | } |
101 | 86 | ||
102 | #ifdef MEM_OPT | 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 | * insert element in tree | 89 | * insert element in tree |
129 | */ | 90 | */ |
130 | static | 91 | static |
92 | +inline | ||
131 | struct memSegment * | 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 | static | 102 | static |
103 | +inline | ||
185 | struct memSegment * | 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 | static | 121 | static |
122 | +inline | ||
360 | void | 123 | void |
361 | segmentFree(struct memSegment * segment, int depth) | 124 | segmentFree(struct memSegment * segment, int depth) |
362 | { | 125 | { |
@@ -378,8 +141,6 @@ TR_reference(void * mem) | @@ -378,8 +141,6 @@ TR_reference(void * mem) | ||
378 | return mem; | 141 | return mem; |
379 | } | 142 | } |
380 | 143 | ||
381 | -pthread_mutex_t TR_memop_lock = PTHREAD_MUTEX_INITIALIZER; | ||
382 | - | ||
383 | /* | 144 | /* |
384 | * This tries to reflect the memory management behaviour of the | 145 | * This tries to reflect the memory management behaviour of the |
385 | * GNU version of malloc. For other versions this might need | 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,41 +171,60 @@ pthread_mutex_t TR_memop_lock = PTHREAD_MUTEX_INITIALIZER; | ||
410 | void * | 171 | void * |
411 | TR_malloc(size_t size) | 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 | size += sizeof(struct memSegment); | 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 | #ifdef MEM_OPT | 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 | #endif | 221 | #endif |
222 | + { | ||
223 | + idx = -1; | ||
224 | + } | ||
445 | 225 | ||
446 | if (NULL == seg) { | 226 | if (NULL == seg) { |
447 | - seg = newElement(size); | 227 | + seg = newElement(size, idx); |
448 | } | 228 | } |
449 | 229 | ||
450 | return seg->ptr; | 230 | return seg->ptr; |
@@ -479,12 +259,15 @@ TR_free(void ** mem) | @@ -479,12 +259,15 @@ TR_free(void ** mem) | ||
479 | seg->ref_count--; | 259 | seg->ref_count--; |
480 | } else { | 260 | } else { |
481 | #ifdef MEM_OPT | 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 | #endif | 267 | #endif |
268 | + { | ||
269 | + free(seg); | ||
270 | + } | ||
488 | } | 271 | } |
489 | 272 | ||
490 | *mem = NULL; | 273 | *mem = NULL; |
@@ -508,7 +291,15 @@ void | @@ -508,7 +291,15 @@ void | ||
508 | TR_cleanup() | 291 | TR_cleanup() |
509 | { | 292 | { |
510 | #ifdef MEM_OPT | 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 | #endif | 303 | #endif |
513 | } | 304 | } |
514 | 305 |
Please
register
or
login
to post a comment