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