Lib unit tests have been renamed to tests.
This commit is contained in:
343
test/nxt_rbtree1_test.c
Normal file
343
test/nxt_rbtree1_test.c
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user