Module Name: src
Committed By: yamt
Date: Wed May 20 10:56:29 UTC 2009
Modified Files:
src/common/lib/libc/gen: rpst.c
Log Message:
- fix various bugs in the iteration code.
- add assertions.
- unittest: more tests. verify query results by comparing with linear search.
To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/common/lib/libc/gen/rpst.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/common/lib/libc/gen/rpst.c
diff -u src/common/lib/libc/gen/rpst.c:1.1 src/common/lib/libc/gen/rpst.c:1.2
--- src/common/lib/libc/gen/rpst.c:1.1 Tue May 19 12:39:56 2009
+++ src/common/lib/libc/gen/rpst.c Wed May 20 10:56:29 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: rpst.c,v 1.1 2009/05/19 12:39:56 yamt Exp $ */
+/* $NetBSD: rpst.c,v 1.2 2009/05/20 10:56:29 yamt Exp $ */
/*-
* Copyright (c)2009 YAMAMOTO Takashi,
@@ -43,14 +43,18 @@
#include <sys/cdefs.h>
#if defined(_KERNEL)
-__KERNEL_RCSID(0, "$NetBSD: rpst.c,v 1.1 2009/05/19 12:39:56 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rpst.c,v 1.2 2009/05/20 10:56:29 yamt Exp $");
#include <sys/param.h>
#else /* defined(_KERNEL) */
-__RCSID("$NetBSD: rpst.c,v 1.1 2009/05/19 12:39:56 yamt Exp $");
+__RCSID("$NetBSD: rpst.c,v 1.2 2009/05/20 10:56:29 yamt Exp $");
#include <assert.h>
#include <stdbool.h>
#include <string.h>
+#if 1
#define KASSERT assert
+#else
+#define KASSERT(a)
+#endif
#endif /* defined(_KERNEL) */
#include <sys/rpst.h>
@@ -93,6 +97,25 @@
}
/*
+ * rpst_level2mask: calculate the mask for the given level in the tree.
+ *
+ * the mask used to index root's children is level 0.
+ */
+
+static uint64_t
+rpst_level2mask(const struct rpst_tree *t, unsigned int level)
+{
+ uint64_t mask;
+
+ if (t->t_height < level) {
+ mask = 0;
+ } else {
+ mask = UINT64_C(1) << (t->t_height - level);
+ }
+ return mask;
+}
+
+/*
* rpst_startmask: calculate the mask for the start of a search.
* (ie. the mask for the top-most bit)
*/
@@ -100,8 +123,10 @@
static uint64_t
rpst_startmask(const struct rpst_tree *t)
{
+ const uint64_t mask = rpst_level2mask(t, 0);
- return UINT64_C(1) << t->t_height;
+ KASSERT((mask | (mask - 1)) == rpst_height2max(t->t_height));
+ return mask;
}
/*
@@ -156,6 +181,8 @@
KASSERT(*where == cur);
idx = (n->n_x & mask) != 0;
where = &cur->n_children[idx];
+ KASSERT((*where) == NULL || ((((*where)->n_x & mask) != 0) == idx));
+ KASSERT((*where) == NULL || (*where)->n_y >= cur->n_y);
mask >>= 1;
goto next;
}
@@ -196,12 +223,15 @@
cur = *where;
KASSERT(cur != NULL);
if (cur == n) {
+ KASSERT(pn == NULL || pn->n_y <= n->n_y);
*parentp = pn;
return where;
}
idx = (n->n_x & mask) != 0;
pn = cur;
where = &cur->n_children[idx];
+ KASSERT((*where) == NULL || ((((*where)->n_x & mask) != 0) == idx));
+ KASSERT((*where) == NULL || (*where)->n_y >= cur->n_y);
mask >>= 1;
goto next;
}
@@ -277,16 +307,6 @@
return true;
}
-static uint64_t
-rpst_level2mask(const struct rpst_tree *t, unsigned int level)
-{
-
- if (t->t_height < level) {
- return 0;
- }
- return UINT64_C(1) << (t->t_height - level);
-}
-
struct rpst_node *
rpst_iterate_first(struct rpst_tree *t, uint64_t max_y, uint64_t min_x,
uint64_t max_x, struct rpst_iterator *it)
@@ -295,12 +315,12 @@
KASSERT(min_x <= max_x);
n = t->t_root;
- if (n == NULL) {
+ if (n == NULL || n->n_y > max_y) {
return NULL;
}
it->it_tree = t;
it->it_cur = n;
- it->it_idx = 0;
+ it->it_idx = (min_x & rpst_startmask(t)) != 0;
it->it_level = 0;
it->it_max_y = max_y;
it->it_min_x = min_x;
@@ -308,6 +328,35 @@
return rpst_iterate_next(it);
}
+static unsigned int
+rpst_node_on_edge_p(const struct rpst_node *n, uint64_t val, uint64_t mask)
+{
+
+ return ((n->n_x ^ val) & ((-mask) << 1)) == 0;
+}
+
+static uint64_t
+rpst_maxidx(const struct rpst_node *n, uint64_t max_x, uint64_t mask)
+{
+
+ if (rpst_node_on_edge_p(n, max_x, mask)) {
+ return (max_x & mask) != 0;
+ } else {
+ return 1;
+ }
+}
+
+static uint64_t
+rpst_minidx(const struct rpst_node *n, uint64_t min_x, uint64_t mask)
+{
+
+ if (rpst_node_on_edge_p(n, min_x, mask)) {
+ return (min_x & mask) != 0;
+ } else {
+ return 0;
+ }
+}
+
struct rpst_node *
rpst_iterate_next(struct rpst_iterator *it)
{
@@ -327,11 +376,12 @@
idx = it->it_idx;
level = it->it_level;
mask = rpst_level2mask(t, level);
- maxidx = (max_x & mask) != 0;
+ maxidx = rpst_maxidx(n, max_x, mask);
KASSERT(n == t->t_root || rpst_iterator_match_p(n, it));
next:
KASSERT(mask == rpst_level2mask(t, level));
- KASSERT(maxidx == ((max_x & mask) != 0));
+ KASSERT(idx >= rpst_minidx(n, min_x, mask));
+ KASSERT(maxidx == rpst_maxidx(n, max_x, mask));
KASSERT(idx <= maxidx + 2);
KASSERT(n != NULL);
#if 0
@@ -361,9 +411,9 @@
}
KASSERT(level > 0);
level--;
- mask = rpst_level2mask(t, level);
- maxidx = (max_x & mask) != 0;
n = next;
+ mask = rpst_level2mask(t, level);
+ maxidx = rpst_maxidx(n, max_x, mask);
idx = where - n->n_children + 1;
KASSERT(idx < 2 + 1);
goto next;
@@ -375,11 +425,16 @@
idx++;
goto next;
}
+ KASSERT(next->n_y >= n->n_y);
level++;
mask >>= 1;
- maxidx = (max_x & mask) != 0;
n = next;
- idx = (min_x & mask) != 0;
+ idx = rpst_minidx(n, min_x, mask);
+ maxidx = rpst_maxidx(n, max_x, mask);
+#if 0
+ printf("%s: visit %p idx=%u level=%u mask=%llx\n",
+ __func__, n, idx, level, mask);
+#endif
goto next;
}
@@ -414,35 +469,92 @@
rpst_dump_tree(const struct rpst_tree *t)
{
- printf("pst %p bits=%u\n", (const void *)t, t->t_height);
+ printf("pst %p height=%u\n", (const void *)t, t->t_height);
rpst_dump_node(t->t_root, 0);
}
struct testnode {
struct rpst_node n;
struct testnode *next;
+ bool failed;
+ bool found;
};
+struct rpst_tree t;
+struct testnode *h = NULL;
+
+static uintmax_t
+tvdiff(const struct timeval *tv1, const struct timeval *tv2)
+{
+
+ return (uintmax_t)tv1->tv_sec * 1000000 + tv1->tv_usec -
+ tv2->tv_sec * 1000000 - tv2->tv_usec;
+}
+
+static unsigned int
+query(uint64_t max_y, uint64_t min_x, uint64_t max_x)
+{
+ struct testnode *n;
+ struct rpst_node *rn;
+ struct rpst_iterator it;
+ struct timeval start;
+ struct timeval end;
+ unsigned int done;
+
+ printf("quering max_y=%" PRIu64 " min_x=%" PRIu64 " max_x=%" PRIu64
+ "\n",
+ max_y, min_x, max_x);
+ done = 0;
+ gettimeofday(&start, NULL);
+ for (rn = rpst_iterate_first(&t, max_y, min_x, max_x, &it);
+ rn != NULL;
+ rn = rpst_iterate_next(&it)) {
+ done++;
+#if 0
+ printf("found %p x=%" PRIu64 " y=%" PRIu64 "\n",
+ (void *)rn, rn->n_x, rn->n_y);
+#endif
+ n = (void *)rn;
+ assert(!n->found);
+ n->found = true;
+ }
+ gettimeofday(&end, NULL);
+ printf("%u nodes found in %ju usecs\n", done,
+ tvdiff(&end, &start));
+
+ gettimeofday(&start, NULL);
+ for (n = h; n != NULL; n = n->next) {
+ assert(n->failed ||
+ n->found == rpst_iterator_match_p(&n->n, &it));
+ n->found = false;
+ }
+ gettimeofday(&end, NULL);
+ printf("(linear search took %ju usecs)\n", tvdiff(&end, &start));
+ return done;
+}
+
int
main(int argc, char *argv[])
{
- struct rpst_tree t;
- struct testnode *h = NULL;
struct testnode *n;
- struct rpst_node *rn;
- unsigned int i = 500000;
+ unsigned int i;
struct rpst_iterator it;
struct timeval start;
struct timeval end;
+ uint64_t min_y = UINT64_MAX;
+ uint64_t max_y = 0;
+ uint64_t min_x = UINT64_MAX;
+ uint64_t max_x = 0;
+ uint64_t w;
unsigned int done;
+ unsigned int fail;
+ unsigned int num = 500000;
rpst_init_tree(&t);
rpst_dump_tree(&t);
assert(NULL == rpst_iterate_first(&t, UINT64_MAX, 0, UINT64_MAX, &it));
- done = 0;
- gettimeofday(&start, NULL);
- while (i > 0) {
+ for (i = 0; i < num; i++) {
n = malloc(sizeof(*n));
if (i > 499000) {
n->n.n_x = 10;
@@ -454,54 +566,82 @@
n->n.n_x = random();
n->n.n_y = random();
}
-#if 0
- printf("[%u] insert %p x=%" PRIu64 " y=%" PRIu64 "\n",
- i, n, n->n.n_x, n->n.n_y);
-#endif
- rpst_insert_node(&t, &n->n);
+ if (n->n.n_y < min_y) {
+ min_y = n->n.n_y;
+ }
+ if (n->n.n_y > max_y) {
+ max_y = n->n.n_y;
+ }
+ if (n->n.n_x < min_x) {
+ min_x = n->n.n_x;
+ }
+ if (n->n.n_x > max_x) {
+ max_x = n->n.n_x;
+ }
+ n->found = false;
+ n->failed = false;
n->next = h;
h = n;
- i--;
- done++;
}
- gettimeofday(&end, NULL);
- printf("%u nodes inserted in %ju usecs\n", done,
- (uintmax_t)end.tv_sec * 1000000 + end.tv_usec -
- start.tv_sec * 1000000 - start.tv_usec);
done = 0;
+ fail = 0;
gettimeofday(&start, NULL);
- for (rn = rpst_iterate_first(&t, 100000000, 10, 1000000, &it);
- rn != NULL;
- rn = rpst_iterate_next(&it)) {
- done++;
+ for (n = h; n != NULL; n = n->next) {
+ struct rpst_node *o;
#if 0
- printf("found %p x=%" PRIu64 " y=%" PRIu64 "\n",
- (void *)rn, rn->n_x, rn->n_y);
+ printf("insert %p x=%" PRIu64 " y=%" PRIu64 "\n",
+ n, n->n.n_x, n->n.n_y);
#endif
+ o = rpst_insert_node(&t, &n->n);
+ if (o == NULL) {
+ done++;
+ } else {
+ n->failed = true;
+ fail++;
+ }
}
gettimeofday(&end, NULL);
- printf("%u nodes found in %ju usecs\n", done,
- (uintmax_t)end.tv_sec * 1000000 + end.tv_usec -
- start.tv_sec * 1000000 - start.tv_usec);
+ printf("%u nodes inserted and %u insertion failed in %ju usecs\n",
+ done, fail,
+ tvdiff(&end, &start));
+
+ assert(min_y == 0 || 0 == query(min_y - 1, 0, UINT64_MAX));
+ assert(max_x == UINT64_MAX ||
+ 0 == query(UINT64_MAX, max_x + 1, UINT64_MAX));
+ assert(min_x == 0 || 0 == query(UINT64_MAX, 0, min_x - 1));
+
+ done = query(max_y, min_x, max_x);
+ assert(done == num - fail);
+
+ done = query(UINT64_MAX, 0, UINT64_MAX);
+ assert(done == num - fail);
+
+ w = max_x - min_x;
+ query(max_y / 2, min_x, max_x);
+ query(max_y, min_x + w / 2, max_x);
+ query(max_y / 2, min_x + w / 2, max_x);
+ query(max_y / 2, min_x, max_x - w / 2);
+ query(max_y / 2, min_x + w / 3, max_x - w / 3);
+ query(max_y - 1, min_x + 1, max_x - 1);
+ query(UINT64_MAX, 10, 10);
done = 0;
gettimeofday(&start, NULL);
- while (h != NULL) {
- n = h;
- h = n->next;
+ for (n = h; n != NULL; n = n->next) {
+ if (n->failed) {
+ continue;
+ }
#if 0
- printf("[%u] remove %p x=%" PRIu64 " y=%" PRIu64 "\n",
+ printf("remove %p x=%" PRIu64 " y=%" PRIu64 "\n",
n, n->n.n_x, n->n.n_y);
#endif
rpst_remove_node(&t, &n->n);
- i++;
done++;
}
gettimeofday(&end, NULL);
printf("%u nodes removed in %ju usecs\n", done,
- (uintmax_t)end.tv_sec * 1000000 + end.tv_usec -
- start.tv_sec * 1000000 - start.tv_usec);
+ tvdiff(&end, &start));
rpst_dump_tree(&t);
}