[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