bird/filter/tree_test.c
Maria Matejka 4c553c5a5b Filter refactoring: dropped the recursion from the interpreter
This is a major change of how the filters are interpreted. If everything
works how it should, it should not affect you unless you are hacking the
filters themselves.

Anyway, this change should make a huge improvement in the filter performance
as previous benchmarks showed that our major problem lies in the
recursion itself.

There are also some changes in nest and protocols, related mostly to
spreading const declarations throughout the whole BIRD and also to
refactored dynamic attribute definitions. The need of these came up
during the whole work and it is too difficult to split out these
not-so-related changes.
2019-02-20 22:30:54 +01:00

304 lines
6.8 KiB
C

/*
* Filters: Utility Functions Tests
*
* (c) 2015 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include "test/birdtest.h"
#include "test/bt-utils.h"
#include "filter/filter.h"
#include "conf/conf.h"
#define MAX_TREE_HEIGHT 13
static void
start_conf_env(void)
{
bt_bird_init();
pool *p = rp_new(&root_pool, "helper_pool");
linpool *l = lp_new_default(p);
cfg_mem = l;
}
static struct f_tree *
new_tree(uint id)
{
struct f_tree *tree = f_new_tree();
tree->from.type = tree->to.type = T_INT;
tree->from.val.i = tree->to.val.i = id;
return tree;
}
/*
* Show subtree in infix notation
*/
static void
show_subtree(struct f_tree *node)
{
if (!node)
return;
show_subtree(node->left);
if (node->from.val.i == node->to.val.i)
bt_debug("%u ", node->from.val.i);
else
bt_debug("%u..%u ", node->from.val.i, node->to.val.i);
show_subtree(node->right);
}
static void
show_tree2(struct f_tree *root_node, const char *tree_name)
{
bt_debug("%s: \n", tree_name);
bt_debug("[ ");
show_subtree(root_node);
bt_debug("]\n\n");
}
#define show_tree(tree) show_tree2(tree, #tree);
static uint
get_nodes_count_full_bin_tree(uint height)
{
return (bt_naive_pow(2, height+1) - 1);
}
static struct f_tree *
get_balanced_full_subtree(uint height, uint idx)
{
struct f_tree *node = new_tree(idx);
if (height > 0)
{
uint nodes_in_subtree = get_nodes_count_full_bin_tree(--height);
node->left = get_balanced_full_subtree(height, idx - nodes_in_subtree/2 - 1);
node->right = get_balanced_full_subtree(height, idx + nodes_in_subtree/2 + 1);
}
return node;
}
static struct f_tree *
get_balanced_full_tree(uint height)
{
return get_balanced_full_subtree(height, get_nodes_count_full_bin_tree(height)/2);
}
static struct f_tree *
get_degenerated_left_tree(uint nodes_count)
{
struct f_tree *old = NULL;
struct f_tree *new = NULL;
uint i;
for (i = 0; i < nodes_count; i++)
{
old = new;
new = new_tree(nodes_count-1-i);
new->left = old;
}
return new;
}
static struct f_tree *
get_random_degenerated_left_tree(uint nodes_count)
{
struct f_tree *tree = get_degenerated_left_tree(nodes_count);
size_t avaible_indexes_size = nodes_count * sizeof(byte);
byte *avaible_indexes = malloc(avaible_indexes_size);
memset(avaible_indexes, 0, avaible_indexes_size);
struct f_tree *n;
for (n = tree; n; n = n->left)
{
uint selected_idx;
do
{
selected_idx = bt_random() % nodes_count;
} while(avaible_indexes[selected_idx] != 0);
avaible_indexes[selected_idx] = 1;
n->from.type = n->to.type = T_INT;
n->from.val.i = n->to.val.i = selected_idx;
}
free(avaible_indexes);
return tree;
}
static struct f_tree *
get_balanced_tree_with_ranged_values(uint nodes_count)
{
struct f_tree *tree = get_degenerated_left_tree(nodes_count);
uint idx = 0;
struct f_tree *n;
for (n = tree; n; n = n->left)
{
n->from.type = n->to.type = T_INT;
n->from.val.i = idx;
idx += (uint)bt_random() / nodes_count; /* (... / nodes_count) preventing overflow an uint idx */
n->to.val.i = idx++;
}
return build_tree(tree);
}
static int
t_balancing(void)
{
start_conf_env();
uint height;
for (height = 1; height < MAX_TREE_HEIGHT; height++)
{
uint nodes_count = get_nodes_count_full_bin_tree(height);
struct f_tree *simple_degenerated_tree = get_degenerated_left_tree(nodes_count);
show_tree(simple_degenerated_tree);
struct f_tree *expected_balanced_tree = get_balanced_full_tree(height);
show_tree(expected_balanced_tree);
struct f_tree *balanced_tree_from_simple = build_tree(simple_degenerated_tree);
show_tree(balanced_tree_from_simple);
bt_assert(same_tree(balanced_tree_from_simple, expected_balanced_tree));
}
return 1;
}
static int
t_balancing_random(void)
{
start_conf_env();
uint height;
for (height = 1; height < MAX_TREE_HEIGHT; height++)
{
uint nodes_count = get_nodes_count_full_bin_tree(height);
struct f_tree *expected_balanced_tree = get_balanced_full_tree(height);
uint i;
for(i = 0; i < 10; i++)
{
struct f_tree *random_degenerated_tree = get_random_degenerated_left_tree(nodes_count);
show_tree(random_degenerated_tree);
struct f_tree *balanced_tree_from_random = build_tree(random_degenerated_tree);
show_tree(expected_balanced_tree);
show_tree(balanced_tree_from_random);
bt_assert(same_tree(balanced_tree_from_random, expected_balanced_tree));
}
}
return 1;
}
static int
t_find(void)
{
start_conf_env();
uint height;
for (height = 1; height < MAX_TREE_HEIGHT; height++)
{
uint nodes_count = get_nodes_count_full_bin_tree(height);
struct f_tree *tree = get_balanced_full_tree(height);
show_tree(tree);
struct f_val looking_up_value = {
.type = T_INT
};
for(looking_up_value.val.i = 0; looking_up_value.val.i < nodes_count; looking_up_value.val.i++)
{
const struct f_tree *found_tree = find_tree(tree, &looking_up_value);
bt_assert((val_compare(&looking_up_value, &(found_tree->from)) == 0) && (val_compare(&looking_up_value, &(found_tree->to)) == 0));
}
}
return 1;
}
static uint
get_max_value_in_unbalanced_tree(struct f_tree *node, uint max)
{
if (!node)
return max;
if (node->to.val.i > max)
max = node->to.val.i;
uint max_left = get_max_value_in_unbalanced_tree(node->left, max);
if (max_left > max)
max = max_left;
uint max_right = get_max_value_in_unbalanced_tree(node->right, max);
if (max_right > max)
max = max_right;
return max;
}
static int
t_find_ranges(void)
{
start_conf_env();
uint height;
for (height = 1; height < MAX_TREE_HEIGHT; height++)
{
uint nodes_count = get_nodes_count_full_bin_tree(height);
struct f_tree *tree = get_balanced_tree_with_ranged_values(nodes_count);
uint max_value = get_max_value_in_unbalanced_tree(tree, 0);
show_tree(tree);
bt_debug("max_value: %u \n", max_value);
struct f_val needle = {
.type = T_INT
};
uint *i = &needle.val.i;
for(*i = 0; *i <= max_value; *i += (uint)bt_random()/nodes_count)
{
const struct f_tree *found_tree = find_tree(tree, &needle);
bt_debug("searching: %u \n", *i);
bt_assert(
(val_compare(&needle, &(found_tree->from)) == 0) || (val_compare(&needle, &(found_tree->to)) == 0) ||
((val_compare(&needle, &(found_tree->from)) == 1) && (val_compare(&needle, &(found_tree->to)) == -1))
);
}
}
return 1;
}
int
main(int argc, char *argv[])
{
bt_init(argc, argv);
bt_test_suite(t_balancing, "Balancing strong unbalanced trees");
bt_test_suite(t_balancing_random, "Balancing random unbalanced trees");
bt_test_suite(t_find, "Finding values in trees");
bt_test_suite(t_find_ranges, "Finding values in trees with random ranged values");
return bt_exit_value();
}