1
2 /**
3 * Here is the assertions to ensure rightness of bst maintenance
4 * After each insertion and delete, a tree must still be binary search tree,
5 * and still remain balanced
6 */
7
8 #include <assert.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <mm_aspace.h>
13 #include <mm_private.h>
14
15 #define BUF_SIZE 1000000
16 static void *_start;
17 static void *_boundary;
18 static int _count;
19 static rt_varea_t _buf[BUF_SIZE];
20 #define RT_ASSERT assert
21
_print_varea(rt_varea_t varea,int depth)22 static void _print_varea(rt_varea_t varea, int depth)
23 {
24 if (depth == 0)
25 {
26 printf("%p ", varea->start);
27 }
28 else
29 {
30 rt_varea_t lchild = VAREA_ENTRY(varea->node.node.avl_left);
31 rt_varea_t rchild = VAREA_ENTRY(varea->node.node.avl_right);
32 depth--;
33 if (lchild)
34 _print_varea(lchild, depth);
35 else
36 printf("0x**** ");
37
38 if (rchild)
39 _print_varea(rchild, depth);
40 else
41 printf("0x**** ");
42 }
43 }
_print_tree(rt_aspace_t aspace)44 static void _print_tree(rt_aspace_t aspace)
45 {
46 rt_varea_t varea = VAREA_ENTRY(aspace->tree.tree.root_node);
47 if (!varea)
48 return ;
49
50 for (size_t i = 0; i < aspace->tree.tree.root_node->height; i++) {
51 _print_varea(varea, i);
52 putchar('\n');
53 }
54
55 return ;
56 }
57
_is_bst(rt_varea_t varea)58 static int _is_bst(rt_varea_t varea)
59 {
60 rt_varea_t lchild = VAREA_ENTRY(varea->node.node.avl_left);
61 rt_varea_t rchild = VAREA_ENTRY(varea->node.node.avl_right);
62 if (lchild)
63 {
64 RT_ASSERT(lchild->node.node.parent == &varea->node.node);
65 RT_ASSERT(varea->start > lchild->start);
66 }
67 if (rchild)
68 {
69 RT_ASSERT(rchild->node.node.parent == &varea->node.node);
70 if (varea->start >= rchild->start)
71 {
72 RT_ASSERT(0);
73 }
74 }
75 return 1;
76 }
77
78 /* return height of current varea */
_is_balanced(rt_varea_t varea)79 static int _is_balanced(rt_varea_t varea)
80 {
81 if (!varea)
82 {
83 return 1;
84 }
85
86 rt_varea_t lchild = VAREA_ENTRY(varea->node.node.avl_left);
87 rt_varea_t rchild = VAREA_ENTRY(varea->node.node.avl_right);
88 int lbal = _is_balanced(lchild);
89 int rbal = _is_balanced(rchild);
90
91 if (lbal && rbal)
92 {
93 int diff = lbal - rbal;
94 if (diff > 1 || diff < -1)
95 {
96 printf("lbal %d, rbal %d\n", lbal, rbal);
97 return 0;
98 }
99 else
100 {
101 int height = lbal > rbal ? lbal : rbal;
102 return height + 1;
103 }
104 }
105 }
106
107 /* add bst assertion */
_check_asc_before(rt_varea_t varea,void * arg)108 static int _check_asc_before(rt_varea_t varea, void *arg)
109 {
110 if (varea->start >= _start && (!_boundary || varea->start >= _boundary) && _is_bst(varea))
111 {
112 _buf[_count] = varea;
113 _start = varea->start;
114 _boundary = varea->start + varea->size;
115 _count++;
116 RT_ASSERT(_count < BUF_SIZE);
117 }
118 else
119 {
120 RT_ASSERT(0);
121 }
122 return 0;
123 }
124
_check_asc_before_rev(rt_varea_t varea,void * arg)125 static int _check_asc_before_rev(rt_varea_t varea, void *arg)
126 {
127 _count--;
128 RT_ASSERT(varea == _buf[_count]);
129 return 0;
130 }
131
_check_asc_after(rt_varea_t varea,void * arg)132 static int _check_asc_after(rt_varea_t varea, void *arg)
133 {
134 rt_varea_t add_elem = (rt_varea_t)arg;
135 if (!_is_bst(varea))
136 {
137 RT_ASSERT(0);
138 }
139
140 if (varea == _buf[_count])
141 {
142 _buf[_count] = 0;
143 _count++;
144 RT_ASSERT(_count < BUF_SIZE);
145 }
146 else if (add_elem && add_elem == varea)
147 {
148 /* adding, skip adding elem */
149 }
150 else if (!add_elem && varea == _buf[_count + 1])
151 {
152 /* deleting */
153 _buf[_count] = 0;
154 _buf[_count] = 0;
155 _count++;
156 RT_ASSERT(_count < BUF_SIZE);
157 }
158 else
159 {
160 printf("add_elem %p, varea %p, _count %d, in buf %p\n",
161 add_elem->start, varea->start, _count, _buf[_count]);
162 RT_ASSERT(0);
163 }
164 return 0;
165 }
166
_aspace_traversal(rt_aspace_t aspace,int (* fn)(rt_varea_t varea,void * arg),void * arg)167 static int _aspace_traversal(rt_aspace_t aspace, int (*fn)(rt_varea_t varea, void *arg), void *arg)
168 {
169 rt_varea_t varea = ASPACE_VAREA_FIRST(aspace);
170 while (varea)
171 {
172 fn(varea, arg);
173 varea = ASPACE_VAREA_NEXT(varea);
174 }
175
176 return 0;
177 }
178
_aspace_traversal_reverse(rt_aspace_t aspace,int (* fn)(rt_varea_t varea,void * arg),void * arg)179 static int _aspace_traversal_reverse(rt_aspace_t aspace, int (*fn)(rt_varea_t varea, void *arg), void *arg)
180 {
181 rt_varea_t varea = ASPACE_VAREA_LAST(aspace);
182 while (varea)
183 {
184 fn(varea, arg);
185 varea = ASPACE_VAREA_PREV(varea);
186 }
187
188 return 0;
189 }
190
_check_bst_before(struct rt_aspace * aspace,struct rt_varea * varea)191 static int _check_bst_before(struct rt_aspace *aspace, struct rt_varea *varea)
192 {
193 rt_varea_t root = VAREA_ENTRY(aspace->tree.tree.root_node);
194 int height = _is_balanced(root);
195
196 if (root)
197 RT_ASSERT(height);
198
199 memset(_buf, 0, sizeof(_buf)); // clear first avoiding none tree error
200 _start = 0;
201 _boundary = 0;
202 _count = 0;
203
204 _aspace_traversal(aspace, _check_asc_before, varea);
205 int saved = _count;
206 _aspace_traversal_reverse(aspace, _check_asc_before_rev, varea);
207 _count = saved;
208
209 return 1;
210 }
211
_check_bst_after(struct rt_aspace * aspace,struct rt_varea * varea,int isdel)212 static int _check_bst_after(struct rt_aspace *aspace, struct rt_varea *varea, int isdel)
213 {
214 rt_varea_t root = VAREA_ENTRY(aspace->tree.tree.root_node);
215 int height = _is_balanced(root);
216
217 if (root)
218 RT_ASSERT(height);
219
220 int prev_count = _count;
221 _start = 0;
222 _boundary = 0;
223 _count = 0;
224 _aspace_traversal(aspace, _check_asc_after, isdel ? NULL : varea);
225 _count = isdel ? _count : _count + 1;
226
227 if (isdel)
228 {
229 RT_ASSERT(prev_count - 1 == _count);
230 }
231 else
232 {
233 RT_ASSERT(prev_count + 1 == _count);
234 }
235
236 return 1;
237 }
238
239 /* test library */
240 #define RANDOM(n) (xrand() % (n))
241 static unsigned int xseed = 0x11223344;
242
xrand(void)243 static inline unsigned int xrand(void)
244 {
245 return (((xseed = xseed * 214013L + 2531011L) >> 16) & 0x7fffffff);
246 }
247
248 // generate keys
init_random_keys(int * keys,int count,int seed)249 static inline void init_random_keys(int *keys, int count, int seed)
250 {
251 int save_seed = time(NULL);
252 int *array = (int*)malloc(sizeof(int) * count);
253 int length = count, i;
254 xseed = seed;
255 for (i = 0; i < count; i++) {
256 array[i] = i;
257 }
258 for (i = 0; i < length; i++) {
259 int pos = xrand() % count;
260 int key = array[pos];
261 keys[i] = key;
262 array[pos] = array[--count];
263 }
264 free(array);
265 xseed = save_seed;
266 }
267
268 // A utility function to swap to integers
swap(int * a,int * b)269 static inline void swap (int *a, int *b)
270 {
271 int temp = *a;
272 *a = *b;
273 *b = temp;
274 }
275
276 // A function to generate a random permutation of arr[]
randomize(int arr[],int n)277 static void randomize ( int arr[], int n )
278 {
279 // Use a different seed value so that we don't get same
280 // result each time we run this program
281 srand ( time(NULL) );
282
283 // Start from the last element and swap one by one. We don't
284 // need to run for the first element that's why i > 0
285 for (int i = n-1; i > 0; i--)
286 {
287 // Pick a random index from 0 to i
288 int j = rand() % (i+1);
289
290 // Swap arr[i] with the element at random index
291 swap(&arr[i], &arr[j]);
292 }
293 }
294
295 /* time */
296 #include <time.h>
297
gettime(void)298 static int gettime(void)
299 {
300 struct timespec ts;
301 clock_gettime(CLOCK_REALTIME_COARSE, &ts);
302 time_t seconds = ts.tv_sec;
303 int millisecond = ts.tv_nsec / 1000000;
304 return millisecond + seconds * 1000;
305 }
306
307 /* Adapt Layer */
308
309 /**
310 * @brief Adapter Layer for lwp AVL BST
311 */
312
_aspace_bst_init(struct rt_aspace * aspace)313 int _aspace_bst_init(struct rt_aspace *aspace)
314 {
315 aspace->tree.tree.root_node = AVL_ROOT;
316 return 0;
317 }
318
compare_overlap(void * as,void * ae,void * bs,void * be)319 static int compare_overlap(void *as, void *ae, void *bs, void *be)
320 {
321 LOG_D("as %lx, ae %lx, bs %lx, be %lx", as, ae, bs, be);
322 int cmp;
323 if (as > be)
324 {
325 cmp = 1;
326 }
327 else if (ae < bs)
328 {
329 cmp = -1;
330 }
331 else
332 {
333 cmp = 0;
334 }
335 LOG_D("ret %d", cmp);
336 return cmp;
337 }
338
compare_exceed(void * as,void * ae,void * bs,void * be)339 static int compare_exceed(void *as, void *ae, void *bs, void *be)
340 {
341 LOG_D("as %lx, ae %lx, bs %lx, be %lx", as, ae, bs, be);
342 int cmp;
343 if (as > bs)
344 {
345 cmp = 1;
346 }
347 else if (as < bs)
348 {
349 cmp = -1;
350 }
351 else
352 {
353 cmp = 0;
354 }
355 LOG_D("ret %d", cmp);
356 return cmp;
357 }
358
search(struct util_avl_root * root,struct _mm_range range,int (* compare)(void * as,void * ae,void * bs,void * be))359 static struct rt_varea *search(struct util_avl_root *root,
360 struct _mm_range range,
361 int (*compare)(void *as, void *ae, void *bs,
362 void *be))
363 {
364 struct util_avl_struct *node = root->root_node;
365 while (node)
366 {
367 rt_varea_t varea = VAREA_ENTRY(node);
368 int cmp = compare(range.start, range.end, varea->start,
369 varea->start + varea->size - 1);
370
371 if (cmp < 0)
372 {
373 node = node->avl_left;
374 }
375 else if (cmp > 0)
376 {
377 node = node->avl_right;
378 }
379 else
380 {
381 return varea;
382 }
383 }
384 return NULL;
385 }
386
_aspace_bst_search(struct rt_aspace * aspace,void * key)387 struct rt_varea *_aspace_bst_search(struct rt_aspace *aspace, void *key)
388 {
389 struct util_avl_root *root = &aspace->tree.tree;
390 struct _mm_range range = {key, key};
391 return search(root, range, compare_overlap);
392 }
393
_aspace_bst_search_exceed(struct rt_aspace * aspace,void * start)394 rt_varea_t _aspace_bst_search_exceed(struct rt_aspace *aspace, void *start)
395 {
396 struct util_avl_root *root = &aspace->tree.tree;
397 struct util_avl_struct *node = root->root_node;
398 rt_varea_t closest = NULL;
399 ptrdiff_t min_off = PTRDIFF_MAX;
400 while (node)
401 {
402 rt_varea_t varea = VAREA_ENTRY(node);
403 void *va_s = varea->start;
404 int cmp = compare_exceed(start, start, va_s, va_s);
405
406 if (cmp < 0)
407 {
408 ptrdiff_t off = va_s - start;
409 if (off < min_off)
410 {
411 min_off = off;
412 closest = varea;
413 }
414 node = node->avl_left;
415 }
416 else if (cmp > 0)
417 {
418 node = node->avl_right;
419 }
420 else
421 {
422 return varea;
423 }
424 }
425 return closest;
426 }
427
_aspace_bst_search_overlap(struct rt_aspace * aspace,struct _mm_range range)428 struct rt_varea *_aspace_bst_search_overlap(struct rt_aspace *aspace,
429 struct _mm_range range)
430 {
431 struct util_avl_root *root = &aspace->tree.tree;
432 return search(root, range, compare_overlap);
433 }
434
435 #ifdef ENABLE_DEBUG
436 #include "bst_assert.h"
437 #else
438 #define _check_bst_before(x, ...)
439 #define _check_bst_after(x, ...)
440 #endif
441
_aspace_bst_insert(struct rt_aspace * aspace,struct rt_varea * varea)442 void _aspace_bst_insert(struct rt_aspace *aspace, struct rt_varea *varea)
443 {
444 struct util_avl_root *root = &aspace->tree.tree;
445 struct util_avl_struct *current = NULL;
446 struct util_avl_struct **next = &(root->root_node);
447 rt_ubase_t key = (rt_ubase_t)varea->start;
448
449 /* Figure out where to put new node */
450 while (*next)
451 {
452 current = *next;
453 struct rt_varea *data = VAREA_ENTRY(current);
454
455 if (key < (rt_ubase_t)data->start)
456 next = &(current->avl_left);
457 else if (key > (rt_ubase_t)data->start)
458 next = &(current->avl_right);
459 else
460 return;
461 }
462
463 /* Add new node and rebalance tree. */
464 _check_bst_before(aspace, varea);
465 util_avl_link(&varea->node.node, current, next);
466 util_avl_rebalance(current, root);
467 _check_bst_after(aspace, varea, 0);
468 return;
469 }
470
_aspace_bst_remove(struct rt_aspace * aspace,struct rt_varea * varea)471 void _aspace_bst_remove(struct rt_aspace *aspace, struct rt_varea *varea)
472 {
473 struct util_avl_struct *node = &varea->node.node;
474 _check_bst_before(aspace, varea);
475 util_avl_remove(node, &aspace->tree.tree);
476 _check_bst_after(aspace, varea, 1);
477 }
478
479 struct rt_aspace aspace;
480
481 /**
482 * @brief Simulate environment of varea and BSTs
483 */
484
485 /* test data set */
486 int *dataset;
487 int loop_count;
488
489 /* preallocate varea to decrease influence by malloc routine */
490 struct rt_varea *_varea_buf;
491
492 #define STOPWATCH(fun, time) do { \
493 unsigned int _time; \
494 _time = gettime(); \
495 fun(); \
496 _time = gettime()-_time; \
497 time = _time; \
498 } while (0);
499
init_test(void)500 static void init_test(void)
501 {
502 _aspace_bst_init(&aspace);
503
504 dataset = malloc(loop_count * sizeof(*dataset));
505 assert(dataset);
506
507 _varea_buf = malloc(loop_count * sizeof(*_varea_buf));
508 assert(_varea_buf);
509
510 init_random_keys(dataset, loop_count, 0xabcdabcd);
511 }
512
insert_test(void)513 static void insert_test(void)
514 {
515 for (size_t i = 0; i < loop_count; i++)
516 {
517 struct rt_varea *varea;
518 varea = &_varea_buf[i];
519 varea->start = (void *)(uintptr_t)dataset[i];
520 varea->size = 1;
521 _aspace_bst_insert(&aspace, varea);
522 }
523 }
524
search_test(void)525 static void search_test(void)
526 {
527 for (size_t i = 0; i < loop_count; i++)
528 {
529 void *start = (void *)(uintptr_t)dataset[i];
530 struct rt_varea *varea;
531 varea = _aspace_bst_search(&aspace, start);
532 assert(varea);
533 assert(varea->start == start);
534 }
535 }
536
delete_test(void)537 static void delete_test(void)
538 {
539 for (size_t i = 0; i < loop_count; i++)
540 {
541 void *start = (void *)(uintptr_t)dataset[i];
542 struct rt_varea *varea;
543 varea = _aspace_bst_search(&aspace, start);
544 _aspace_bst_remove(&aspace, varea);
545 }
546 }
547
cleanup(void)548 static void cleanup(void)
549 {
550 free(dataset);
551
552 free(_varea_buf);
553 }
554
main(int argc,char * argv[])555 int main(int argc, char *argv[])
556 {
557 if (argc == 2)
558 {
559 rt_sscanf(argv[1], "%d", &loop_count);
560 }
561 else
562 {
563 loop_count = 1000;
564 }
565
566 puts("Benchmark");
567 printf("looping times: %d\n", loop_count);
568
569 init_test();
570 int endurance;
571 STOPWATCH(insert_test, endurance);
572 printf("Insertion: %d ms\n", endurance);
573
574 randomize(dataset, loop_count);
575 STOPWATCH(search_test, endurance);
576 printf("Search: %d ms\n", endurance);
577
578 randomize(dataset, loop_count);
579 STOPWATCH(delete_test, endurance);
580 printf("Delete: %d ms\n", endurance);
581
582 cleanup();
583 puts("Benchmark exit");
584 return 0;
585 }
586