[pypy-commit] stmgc c7-refactor: Copy the dictionary-like trees from "c4".
arigo
noreply at buildbot.pypy.org
Tue Feb 25 09:50:22 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: c7-refactor
Changeset: r852:85c1e725fba0
Date: 2014-02-25 09:19 +0100
http://bitbucket.org/pypy/stmgc/changeset/85c1e725fba0/
Log: Copy the dictionary-like trees from "c4".
diff --git a/c7/stm/list.c b/c7/stm/list.c
--- a/c7/stm/list.c
+++ b/c7/stm/list.c
@@ -29,3 +29,150 @@
lst->last_allocated = nalloc - 1;
return lst;
}
+
+
+/************************************************************/
+
+static void _tree_clear_node(wlog_node_t *node)
+{
+ memset(node, 0, sizeof(wlog_node_t));
+}
+
+static void tree_clear(struct tree_s *tree)
+{
+ if (tree->raw_current != tree->raw_start) {
+ _tree_clear_node(&tree->toplevel);
+ tree->raw_current = tree->raw_start;
+ }
+}
+
+static struct tree_s *tree_create(void)
+{
+ return (struct tree_s *)calloc(1, sizeof(struct tree_s));
+}
+
+static void tree_free(struct tree_s *tree)
+{
+ free(tree->raw_start);
+ free(tree);
+}
+
+static void _tree_compress(struct tree_s *tree)
+{
+ wlog_t *item;
+ struct tree_s tree_copy;
+ memset(&tree_copy, 0, sizeof(struct tree_s));
+
+ TREE_LOOP_FORWARD(*tree, item)
+ {
+ tree_insert(&tree_copy, item->addr, item->val);
+
+ } TREE_LOOP_END;
+
+ free(tree->raw_start);
+ *tree = tree_copy;
+}
+
+static wlog_t *_tree_find(char *entry, uintptr_t addr)
+{
+ uintptr_t key = addr;
+ while (((long)entry) & 1) {
+ /* points to a further level */
+ key >>= TREE_BITS;
+ entry = *(char **)((entry - 1) + (key & TREE_MASK));
+ }
+ return (wlog_t *)entry; /* may be NULL */
+}
+
+static void _tree_grow(struct tree_s *tree, long extra)
+{
+ struct tree_s newtree;
+ wlog_t *item;
+ long alloc = tree->raw_end - tree->raw_start;
+ long newalloc = (alloc + extra + (alloc >> 2) + 31) & ~15;
+ //fprintf(stderr, "growth: %ld\n", newalloc);
+ char *newitems = malloc(newalloc);
+ if (newitems == NULL) {
+ stm_fatalerror("out of memory!\n"); /* XXX */
+ }
+ newtree.raw_start = newitems;
+ newtree.raw_current = newitems;
+ newtree.raw_end = newitems + newalloc;
+ _tree_clear_node(&newtree.toplevel);
+ TREE_LOOP_FORWARD(*tree, item)
+ {
+ tree_insert(&newtree, item->addr, item->val);
+ } TREE_LOOP_END;
+ free(tree->raw_start);
+ *tree = newtree;
+}
+
+static char *_tree_grab(struct tree_s *tree, long size)
+{
+ char *result;
+ result = tree->raw_current;
+ tree->raw_current += size;
+ if (tree->raw_current > tree->raw_end) {
+ _tree_grow(tree, size);
+ return NULL;
+ }
+ return result;
+}
+
+static void tree_insert(struct tree_s *tree, uintptr_t addr, uintptr_t val)
+{
+ retry:;
+ wlog_t *wlog;
+ uintptr_t key = addr;
+ int shift = 0;
+ char *p = (char *)(tree->toplevel.items);
+ char *entry;
+ while (1) {
+ p += (key >> shift) & TREE_MASK;
+ shift += TREE_BITS;
+ entry = *(char **)p;
+ if (entry == NULL)
+ break;
+ else if (((long)entry) & 1) {
+ /* points to a further level */
+ p = entry - 1;
+ }
+ else {
+ wlog_t *wlog1 = (wlog_t *)entry;
+ if (wlog1->addr == 0) {
+ /* reuse the deleted entry and that's it */
+ wlog1->addr = addr;
+ wlog1->val = val;
+ return;
+ }
+ /* the key must not already be present */
+ assert(wlog1->addr != addr);
+ /* collision: there is already a different wlog here */
+ wlog_node_t *node = (wlog_node_t *)
+ _tree_grab(tree, sizeof(wlog_node_t));
+ if (node == NULL) goto retry;
+ _tree_clear_node(node);
+ uintptr_t key1 = wlog1->addr;
+ char *p1 = (char *)(node->items);
+ *(wlog_t **)(p1 + ((key1 >> shift) & TREE_MASK)) = wlog1;
+ *(char **)p = ((char *)node) + 1;
+ p = p1;
+ }
+ }
+ wlog = (wlog_t *)_tree_grab(tree, sizeof(wlog_t));
+ if (wlog == NULL) goto retry;
+ wlog->addr = addr;
+ wlog->val = val;
+ *(char **)p = (char *)wlog;
+}
+
+static bool tree_delete_item(struct tree_s *tree, uintptr_t addr)
+{
+ wlog_t *entry;
+ TREE_FIND(*tree, addr, entry, goto missing);
+ entry->addr = 0;
+ return true;
+
+ missing:
+ return false;
+}
diff --git a/c7/stm/list.h b/c7/stm/list.h
--- a/c7/stm/list.h
+++ b/c7/stm/list.h
@@ -1,5 +1,7 @@
#include <stdlib.h>
+/************************************************************/
+
struct list_s {
uintptr_t count;
uintptr_t last_allocated;
@@ -65,3 +67,121 @@
CODE; \
} \
} while (0)
+
+/************************************************************/
+
+/* The tree_xx functions are, like the name hints, implemented as a tree,
+ 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. */
+
+#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)
+ (x + TREE_BITS-1) / TREE_BITS = divide by TREE_BITS, rounding up
+*/
+
+#define TREE_MASK ((TREE_ARITY - 1) * sizeof(void*))
+
+typedef struct {
+ uintptr_t addr;
+ uintptr_t val;
+} wlog_t;
+
+typedef struct {
+ char *items[TREE_ARITY];
+} wlog_node_t;
+
+struct tree_s {
+ char *raw_start, *raw_current, *raw_end;
+ wlog_node_t toplevel;
+};
+
+static struct tree_s *tree_create(void);
+static void tree_free(struct tree_s *tree);
+static void tree_clear(struct tree_s *tree);
+//static inline void tree_delete_not_used_any_more(struct tree_s *tree)...
+
+static inline bool tree_any_entry(struct tree_s *tree) {
+ return tree->raw_current != tree->raw_start;
+}
+
+#define _TREE_LOOP(tree, item, INITIAL, _PLUS_) \
+{ \
+ struct { char **next; char **end; } _stack[TREE_DEPTH_MAX], *_stackp; \
+ char **_next, **_end, *_entry; \
+ long _deleted_factor = 0; \
+ struct tree_s *_tree = &(tree); \
+ /* initialization */ \
+ _stackp = _stack; /* empty stack */ \
+ _next = _tree->toplevel.items + INITIAL; \
+ _end = _next _PLUS_ TREE_ARITY; \
+ /* loop */ \
+ while (1) \
+ { \
+ if (_next == _end) \
+ { \
+ if (_stackp == _stack) \
+ break; /* done */ \
+ /* finished with this level, go to the next one */ \
+ _stackp--; \
+ _next = _stackp->next; \
+ _end = _stackp->end; \
+ continue; \
+ } \
+ _entry = *_next; \
+ _next = _next _PLUS_ 1; \
+ if (_entry == NULL) /* empty entry */ \
+ continue; \
+ if (((long)_entry) & 1) \
+ { /* points to a further level: enter it */ \
+ _stackp->next = _next; \
+ _stackp->end = _end; \
+ _stackp++; \
+ _next = ((wlog_node_t *)(_entry - 1))->items + INITIAL; \
+ _end = _next _PLUS_ TREE_ARITY; \
+ continue; \
+ } \
+ /* points to a wlog_t item */ \
+ if (((wlog_t *)_entry)->addr == 0) { /* deleted entry */ \
+ _deleted_factor += 3; \
+ continue; \
+ } \
+ _deleted_factor -= 4; \
+ item = (wlog_t *)_entry;
+
+#define TREE_LOOP_FORWARD(tree, item) \
+ _TREE_LOOP(tree, item, 0, +)
+#define TREE_LOOP_BACKWARD(tree, item) \
+ _TREE_LOOP(tree, item, (TREE_ARITY-1), -)
+#define TREE_LOOP_END } }
+#define TREE_LOOP_END_AND_COMPRESS \
+ } if (_deleted_factor > 9) _tree_compress(_tree); }
+#define TREE_LOOP_DELETE(item) { (item)->addr = NULL; _deleted_factor += 6; }
+
+#define TREE_FIND(tree, addr1, result, goto_not_found) \
+{ \
+ uintptr_t _key = (addr1); \
+ char *_p = (char *)((tree).toplevel.items); \
+ char *_entry = *(char **)(_p + (_key & TREE_MASK)); \
+ if (_entry == NULL) \
+ goto_not_found; /* common case, hopefully */ \
+ result = _tree_find(_entry, addr1); \
+ if (result == NULL || result->addr != (addr1)) \
+ goto_not_found; \
+}
+
+static wlog_t *_tree_find(char *entry, uintptr_t addr);
+static void _tree_compress(struct tree_s *tree) __attribute__((unused));
+static void tree_insert(struct tree_s *tree, uintptr_t addr, uintptr_t val);
+static bool tree_delete_item(struct tree_s *tree, uintptr_t addr);
+
+static inline bool tree_contains(struct tree_s *tree, uintptr_t addr)
+{
+ wlog_t *result;
+ TREE_FIND(*tree, addr, result, return false);
+ return true;
+}
diff --git a/c7/test/common.py b/c7/test/common.py
new file mode 100644
--- /dev/null
+++ b/c7/test/common.py
@@ -0,0 +1,8 @@
+import os
+import sys
+assert sys.maxint == 9223372036854775807, "requires a 64-bit environment"
+
+# ----------
+os.environ['CC'] = 'clang'
+
+parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -1,12 +1,8 @@
import os
import cffi, weakref
-import sys
-assert sys.maxint == 9223372036854775807, "requires a 64-bit environment"
+from common import parent_dir
# ----------
-os.environ['CC'] = 'clang'
-
-parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
source_files = [os.path.join(parent_dir, "stmgc.c")]
all_files = [os.path.join(parent_dir, "stmgc.h"),
diff --git a/c7/test/test_list.py b/c7/test/test_list.py
new file mode 100644
--- /dev/null
+++ b/c7/test/test_list.py
@@ -0,0 +1,49 @@
+import cffi
+from common import parent_dir
+
+
+ffi = cffi.FFI()
+ffi.cdef("""
+struct list_s *list_create(void);
+
+struct tree_s *tree_create(void);
+void tree_free(struct tree_s *tree);
+void tree_clear(struct tree_s *tree);
+bool tree_contains(struct tree_s *tree, uintptr_t addr);
+void tree_insert(struct tree_s *tree, uintptr_t addr, uintptr_t val);
+bool tree_delete_item(struct tree_s *tree, uintptr_t addr);
+""")
+
+lib = ffi.verify('''
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+
+#define LIKELY(x) (x)
+#define UNLIKELY(x) (x)
+#define stm_fatalerror(x) abort()
+
+#include "stm/list.h"
+
+#define _STM_CORE_H_
+#include "stm/list.c"
+''', define_macros=[('STM_TESTS', '1')],
+ undef_macros=['NDEBUG'],
+ include_dirs=[parent_dir],
+ extra_compile_args=['-g', '-O0', '-Werror', '-ferror-limit=1'],
+ force_generic_engine=True)
+
+# ____________________________________________________________
+
+def test_tree_empty():
+ t = lib.tree_create()
+ for i in range(100):
+ assert lib.tree_contains(t, i) == False
+ lib.tree_free(t)
+
+def test_tree_add():
+ t = lib.tree_create()
+ lib.tree_insert(t, 23, 456)
+ for i in range(100):
+ assert lib.tree_contains(t, i) == (i == 23)
+ lib.tree_free(t)
More information about the pypy-commit
mailing list