Author: Armin Rigo <[email protected]>
Branch:
Changeset: r1010:48150a83b44a
Date: 2014-03-14 11:17 +0100
http://bitbucket.org/pypy/stmgc/changeset/48150a83b44a/
Log: Give up with the constrain that tree_insert() only accepts keys
aligned to multiples of 8.
diff --git a/c7/stm/list.c b/c7/stm/list.c
--- a/c7/stm/list.c
+++ b/c7/stm/list.c
@@ -75,7 +75,7 @@
static wlog_t *_tree_find(char *entry, uintptr_t addr)
{
- uintptr_t key = addr;
+ uintptr_t key = TREE_HASH(addr);
while (((long)entry) & 1) {
/* points to a further level */
key >>= TREE_BITS;
@@ -122,10 +122,9 @@
static void tree_insert(struct tree_s *tree, uintptr_t addr, uintptr_t val)
{
assert(addr != 0); /* the NULL key is reserved */
- assert(!(addr & (sizeof(void *) - 1))); /* the key must be aligned */
retry:;
wlog_t *wlog;
- uintptr_t key = addr;
+ uintptr_t key = TREE_HASH(addr);
int shift = 0;
char *p = (char *)(tree->toplevel.items);
char *entry;
@@ -155,7 +154,7 @@
_tree_grab(tree, sizeof(wlog_node_t));
if (node == NULL) goto retry;
_tree_clear_node(node);
- uintptr_t key1 = wlog1->addr;
+ uintptr_t key1 = TREE_HASH(wlog1->addr);
char *p1 = (char *)(node->items);
*(wlog_t **)(p1 + ((key1 >> shift) & TREE_MASK)) = wlog1;
*(char **)p = ((char *)node) + 1;
diff --git a/c7/stm/list.h b/c7/stm/list.h
--- a/c7/stm/list.h
+++ b/c7/stm/list.h
@@ -82,17 +82,19 @@
supporting very high performance in TREE_FIND in the common case where
there are no or few elements in the tree, but scaling correctly
if the number of items becomes large (logarithmically, rather
- than almost-constant-time with hash maps, but with low constants). */
+ than almost-constant-time with hash maps, but with low constants).
+ The value 0 cannot be used as a key.
+*/
#define TREE_BITS 4
#define TREE_ARITY (1 << TREE_BITS)
-#define TREE_DEPTH_MAX ((sizeof(void*)*8 - 2 + TREE_BITS-1) / TREE_BITS)
-/* sizeof(void*) = total number of bits
- 2 = bits that we ignore anyway (2 or 3, conservatively 2)
+#define TREE_DEPTH_MAX ((sizeof(void*)*8 + TREE_BITS-1) / TREE_BITS)
+/* sizeof(void*)*8 = total number of bits
(x + TREE_BITS-1) / TREE_BITS = divide by TREE_BITS, rounding up
*/
+#define TREE_HASH(key) ((key) ^ ((key) << 4))
#define TREE_MASK ((TREE_ARITY - 1) * sizeof(void*))
typedef struct {
@@ -174,7 +176,7 @@
#define TREE_FIND(tree, addr1, result, goto_not_found) \
{ \
- uintptr_t _key = (addr1); \
+ uintptr_t _key = TREE_HASH(addr1); \
char *_p = (char *)((tree).toplevel.items); \
char *_entry = *(char **)(_p + (_key & TREE_MASK)); \
if (_entry == NULL) \
diff --git a/c7/stm/prebuilt.c b/c7/stm/prebuilt.c
--- a/c7/stm/prebuilt.c
+++ b/c7/stm/prebuilt.c
@@ -16,13 +16,11 @@
return;
/* If the object was already moved, it is stored in 'tree_prebuilt_objs'.
- For now we use this dictionary, with keys being equal to the double
- of the numeric address of the prebuilt object. We double them in
- order to support addresses that are only 4-byte-aligned in the
- static data.
+ For now we use this dictionary, with keys being equal to the numeric
+ address of the prebuilt object.
*/
wlog_t *item;
- TREE_FIND(*tree_prebuilt_objs, 2 * (uintptr_t)obj, item, goto not_found);
+ TREE_FIND(*tree_prebuilt_objs, (uintptr_t)obj, item, goto not_found);
*pstaticobj_invalid = (object_t *)item->val; /* already moved */
return;
@@ -42,7 +40,7 @@
nobj->stm_flags = GCFLAG_WRITE_BARRIER;
/* Add the object to the tree */
- tree_insert(tree_prebuilt_objs, 2 * (uintptr_t)obj, (uintptr_t)nobj);
+ tree_insert(tree_prebuilt_objs, (uintptr_t)obj, (uintptr_t)nobj);
/* Done */
*pstaticobj_invalid = nobj;
diff --git a/c7/test/test_list.py b/c7/test/test_list.py
--- a/c7/test/test_list.py
+++ b/c7/test/test_list.py
@@ -65,34 +65,34 @@
def test_tree_add():
t = lib.tree_create()
- lib.tree_insert(t, 23000, 456)
- for i in range(0, 100000, 1000):
- assert lib.tree_contains(t, i) == (i == 23000)
+ lib.tree_insert(t, 23, 456)
+ for i in range(0, 100):
+ assert lib.tree_contains(t, i) == (i == 23)
lib.tree_free(t)
def test_tree_is_cleared():
t = lib.tree_create()
assert lib.tree_is_cleared(t)
- lib.tree_insert(t, 23000, 456)
+ lib.tree_insert(t, 23, 456)
assert not lib.tree_is_cleared(t)
lib.tree_free(t)
def test_tree_delete_item():
t = lib.tree_create()
- lib.tree_insert(t, 23000, 456)
- lib.tree_insert(t, 42000, 34289)
+ lib.tree_insert(t, 23, 456)
+ lib.tree_insert(t, 42, 34289)
assert not lib.tree_is_cleared(t)
- assert lib.tree_contains(t, 23000)
- res = lib.tree_delete_item(t, 23000)
+ assert lib.tree_contains(t, 23)
+ res = lib.tree_delete_item(t, 23)
assert res
- assert not lib.tree_contains(t, 23000)
- res = lib.tree_delete_item(t, 23000)
+ assert not lib.tree_contains(t, 23)
+ res = lib.tree_delete_item(t, 23)
assert not res
- res = lib.tree_delete_item(t, 21000)
+ res = lib.tree_delete_item(t, 21)
assert not res
assert not lib.tree_is_cleared(t)
- assert lib.tree_contains(t, 42000)
- res = lib.tree_delete_item(t, 42000)
+ assert lib.tree_contains(t, 42)
+ res = lib.tree_delete_item(t, 42)
assert res
assert not lib.tree_is_cleared(t) # not cleared, but still empty
for i in range(100):
@@ -101,18 +101,18 @@
def test_tree_walk():
t = lib.tree_create()
- lib.tree_insert(t, 23000, 456)
- lib.tree_insert(t, 42000, 34289)
+ lib.tree_insert(t, 23, 456)
+ lib.tree_insert(t, 42, 34289)
a = ffi.new("uintptr_t[10]")
res = lib.test_tree_walk(t, a)
assert res == 2
- assert ((a[0] == 23000 and a[1] == 42000) or
- (a[0] == 42000 and a[1] == 23000))
+ assert ((a[0] == 23 and a[1] == 42) or
+ (a[0] == 42 and a[1] == 23))
lib.tree_free(t)
def test_tree_walk_big():
t = lib.tree_create()
- values = random.sample(xrange(0, 1000000, 8), 300)
+ values = random.sample(xrange(1, 100000), 300)
for x in values:
lib.tree_insert(t, x, x)
a = ffi.new("uintptr_t[1000]")
@@ -123,3 +123,7 @@
found.add(a[i])
assert found == set(values)
lib.tree_free(t)
+
+def test_hash_permutation():
+ hashes = [((n ^ (n << 4)) & 0xFF0) for n in range(256)]
+ assert set(hashes) == set(range(0, 4096, 16))
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit