summaryrefslogtreecommitdiffhomepage
path: root/src/test/nxt_rbtree1_test.c
diff options
context:
space:
mode:
authorAndrey Zelenkov <zelenkov@nginx.com>2017-11-21 18:55:28 +0300
committerAndrey Zelenkov <zelenkov@nginx.com>2017-11-21 18:55:28 +0300
commit78a77c3e38593a5dd1ba0970d036ed5f5100f88d (patch)
tree3011f02b551c623a926e85ed1532986b947da300 /src/test/nxt_rbtree1_test.c
parent89a1c66dd0c396cda30a960e790817d28dc9a2de (diff)
downloadunit-78a77c3e38593a5dd1ba0970d036ed5f5100f88d.tar.gz
unit-78a77c3e38593a5dd1ba0970d036ed5f5100f88d.tar.bz2
Tests: move existing tests to "src" folder.
Diffstat (limited to 'src/test/nxt_rbtree1_test.c')
-rw-r--r--src/test/nxt_rbtree1_test.c343
1 files changed, 343 insertions, 0 deletions
diff --git a/src/test/nxt_rbtree1_test.c b/src/test/nxt_rbtree1_test.c
new file mode 100644
index 00000000..d4783ea1
--- /dev/null
+++ b/src/test/nxt_rbtree1_test.c
@@ -0,0 +1,343 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_main.h>
+#include "nxt_tests.h"
+#include "nxt_rbtree1.h"
+
+
+#define \
+nxt_rbtree1_is_empty(tree) \
+ (((tree)->root) == (tree)->sentinel)
+
+
+#define \
+nxt_rbtree1_is_there_successor(tree, node) \
+ ((node) != (tree)->sentinel)
+
+
+nxt_inline nxt_rbtree1_node_t *
+nxt_rbtree1_node_successor(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node)
+{
+ nxt_rbtree1_node_t *parent;
+
+ if (node->right != tree->sentinel) {
+ return nxt_rbtree1_min(node->right, tree->sentinel);
+ }
+
+ for ( ;; ) {
+ parent = node->parent;
+
+ if (parent == NULL) {
+ return tree->sentinel;
+ }
+
+ if (node == parent->left) {
+ return parent;
+ }
+
+ node = parent;
+ }
+}
+
+
+static void nxt_rbtree1_test_insert_value(nxt_rbtree1_node_t *temp,
+ nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel);
+static nxt_int_t nxt_rbtree1_test_compare(nxt_rbtree1_node_t *node1,
+ nxt_rbtree1_node_t *node2);
+static int nxt_cdecl nxt_rbtree1_test_sort_cmp(const void *one,
+ const void *two);
+static nxt_rbtree1_node_t *nxt_rbtree1_test_find(nxt_rbtree1_t *tree,
+ nxt_rbtree1_node_t *node);
+
+
+nxt_int_t
+nxt_rbtree1_test(nxt_thread_t *thr, nxt_uint_t n)
+{
+ uint32_t key, *keys;
+ nxt_uint_t i;
+ nxt_nsec_t start, end;
+ nxt_rbtree1_t tree;
+ nxt_rbtree1_node_t *node, *nodes, sentinel;
+
+ nxt_thread_time_update(thr);
+
+ nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree1 test started: %ui", n);
+
+ nxt_rbtree1_init(&tree, &sentinel, nxt_rbtree1_test_insert_value);
+
+ nodes = nxt_malloc(n * sizeof(nxt_rbtree1_node_t));
+ if (nodes == NULL) {
+ return NXT_ERROR;
+ }
+
+ keys = nxt_malloc(n * sizeof(uint32_t));
+ if (keys == NULL) {
+ nxt_free(keys);
+ return NXT_ERROR;
+ }
+
+ key = 0;
+
+ for (i = 0; i < n; i++) {
+ key = nxt_murmur_hash2(&key, sizeof(uint32_t));
+
+ keys[i] = key;
+ nodes[i].key = key;
+ }
+
+ nxt_qsort(keys, n, sizeof(uint32_t), nxt_rbtree1_test_sort_cmp);
+
+ nxt_thread_time_update(thr);
+ start = nxt_thread_monotonic_time(thr);
+
+ for (i = 0; i < n; i++) {
+ nxt_rbtree1_insert(&tree, &nodes[i]);
+ }
+
+ for (i = 0; i < n; i++) {
+ if (nxt_rbtree1_test_find(&tree, &nodes[i]) != &nodes[i]) {
+ nxt_log_alert(thr->log, "rbtree1 test failed: %08XD not found",
+ nodes[i].key);
+ goto fail;
+ }
+ }
+
+ i = 0;
+ node = nxt_rbtree1_min(tree.root, tree.sentinel);
+
+ while (nxt_rbtree1_is_there_successor(&tree, node)) {
+
+ if (keys[i] != node->key) {
+ nxt_log_alert(thr->log, "rbtree1 test failed: %i: %08XD %08XD",
+ i, keys[i], node->key);
+ goto fail;
+ }
+
+ i++;
+ node = nxt_rbtree1_node_successor(&tree, node);
+ }
+
+ if (i != n) {
+ nxt_log_alert(thr->log, "rbtree1 test failed: %ui", i);
+ goto fail;
+ }
+
+ for (i = 0; i < n; i++) {
+ nxt_rbtree1_delete(&tree, &nodes[i]);
+ nxt_memset(&nodes[i], 0xA5, sizeof(nxt_rbtree1_node_t));
+ }
+
+ nxt_thread_time_update(thr);
+ end = nxt_thread_monotonic_time(thr);
+
+ if (!nxt_rbtree1_is_empty(&tree)) {
+ nxt_log_alert(thr->log, "rbtree1 test failed: tree is not empty");
+ goto fail;
+ }
+
+ nxt_free(keys);
+ nxt_free(nodes);
+
+ nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree1 test passed %0.3fs",
+ (end - start) / 1000000000.0);
+
+ return NXT_OK;
+
+fail:
+
+ nxt_free(keys);
+ nxt_free(nodes);
+
+ return NXT_ERROR;
+}
+
+
+static void
+nxt_rbtree1_test_insert_value(nxt_rbtree1_node_t *temp,
+ nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel)
+{
+ nxt_rbtree1_node_t **p;
+
+ for ( ;; ) {
+ nxt_prefetch(temp->left);
+ nxt_prefetch(temp->right);
+
+ p = (node->key < temp->key) ? &temp->left : &temp->right;
+
+ if (*p == sentinel) {
+ break;
+ }
+
+ temp = *p;
+ }
+
+ *p = node;
+ node->parent = temp;
+ node->left = sentinel;
+ node->right = sentinel;
+ nxt_rbtree1_red(node);
+}
+
+
+/*
+ * Subtraction cannot be used in these comparison functions because the key
+ * values are spread uniform in whole 0 .. 2^32 range but are not grouped
+ * around some value as timeout values are.
+ */
+
+nxt_inline nxt_int_t
+nxt_rbtree1_test_compare(nxt_rbtree1_node_t *node1, nxt_rbtree1_node_t *node2)
+{
+ if (node1->key < node2->key) {
+ return -1;
+ }
+
+ if (node1->key == node2->key) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int nxt_cdecl
+nxt_rbtree1_test_sort_cmp(const void *one, const void *two)
+{
+ const uint32_t *first, *second;
+
+ first = one;
+ second = two;
+
+ if (*first < *second) {
+ return -1;
+ }
+
+ if (*first == *second) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static nxt_rbtree1_node_t *
+nxt_rbtree1_test_find(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node)
+{
+ nxt_int_t n;
+ nxt_rbtree1_node_t *next, *sentinel;
+
+ next = tree->root;
+ sentinel = tree->sentinel;
+
+ while (next != sentinel) {
+ nxt_prefetch(next->left);
+ nxt_prefetch(next->right);
+
+ n = nxt_rbtree1_test_compare(node, next);
+
+ if (n < 0) {
+ next = next->left;
+
+ } else if (n > 0) {
+ next = next->right;
+
+ } else {
+ return next;
+ }
+ }
+
+ return NULL;
+}
+
+
+#if (NXT_TEST_RTDTSC)
+
+#define NXT_RBT_STEP (21 * nxt_pagesize / 10 / sizeof(nxt_rbtree1_node_t))
+
+static nxt_rbtree1_t mb_tree;
+static nxt_rbtree1_node_t mb_sentinel;
+static nxt_rbtree1_node_t *mb_nodes;
+
+
+nxt_int_t
+nxt_rbtree1_mb_start(nxt_thread_t *thr)
+{
+ uint32_t key;
+ uint64_t start, end;
+ nxt_uint_t i, n;
+
+ n = NXT_RBT_STEP;
+
+ mb_nodes = nxt_malloc(NXT_RBT_NODES * n * sizeof(nxt_rbtree1_node_t));
+ if (mb_nodes == NULL) {
+ return NXT_ERROR;
+ }
+
+ nxt_rbtree1_init(&mb_tree, &mb_sentinel, nxt_rbtree1_test_insert_value);
+
+ key = 0;
+
+ for (i = 0; i < NXT_RBT_NODES; i++) {
+ key = nxt_murmur_hash2(&key, sizeof(uint32_t));
+ mb_nodes[n * i].key = key;
+ }
+
+ for (i = 0; i < NXT_RBT_NODES - 2; i++) {
+ nxt_rbtree1_insert(&mb_tree, &mb_nodes[n * i]);
+ }
+
+ n *= (NXT_RBT_NODES - 2);
+
+ start = nxt_rdtsc();
+ nxt_rbtree1_insert(&mb_tree, &mb_nodes[n]);
+ end = nxt_rdtsc();
+
+ nxt_log_error(NXT_LOG_NOTICE, thr->log,
+ "rbtree1 mb cached insert: %L cycles", end - start);
+
+ return NXT_OK;
+}
+
+
+void
+nxt_rbtree1_mb_insert(nxt_thread_t *thr)
+{
+ uint64_t start, end;
+ nxt_uint_t n;
+
+ n = NXT_RBT_STEP;
+ n *= (NXT_RBT_NODES - 1);
+
+ start = nxt_rdtsc();
+ nxt_rbtree1_insert(&mb_tree, &mb_nodes[n]);
+ end = nxt_rdtsc();
+
+ nxt_log_error(NXT_LOG_NOTICE, thr->log,
+ "rbtree1 mb insert: %L cycles", end - start);
+}
+
+
+void
+nxt_rbtree1_mb_delete(nxt_thread_t *thr)
+{
+ uint64_t start, end;
+ nxt_uint_t n;
+
+ n = NXT_RBT_STEP;
+ n *= (NXT_RBT_NODES / 4 + 1);
+
+ start = nxt_rdtsc();
+ nxt_rbtree1_delete(&mb_tree, &mb_nodes[n]);
+ end = nxt_rdtsc();
+
+ nxt_log_error(NXT_LOG_NOTICE, thr->log,
+ "rbtree1 mb delete: %L cycles", end - start);
+
+ nxt_free(mb_nodes);
+}
+
+#endif