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