[pypy-commit] stmgc hashtable: in-progress: enough to pass the tests, but more testing needed
arigo
noreply at buildbot.pypy.org
Fri Oct 31 11:34:23 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: hashtable
Changeset: r1485:083635ad2834
Date: 2014-10-31 11:33 +0100
http://bitbucket.org/pypy/stmgc/changeset/083635ad2834/
Log: in-progress: enough to pass the tests, but more testing needed
diff --git a/c7/stm/hashtable.c b/c7/stm/hashtable.c
--- a/c7/stm/hashtable.c
+++ b/c7/stm/hashtable.c
@@ -158,7 +158,8 @@
}
}
-static stm_hashtable_entry_t *_stm_hashtable_lookup(stm_hashtable_t *hashtable,
+static stm_hashtable_entry_t *_stm_hashtable_lookup(object_t *hashtableobj,
+ stm_hashtable_t *hashtable,
uintptr_t index)
{
stm_hashtable_table_t *table;
@@ -220,19 +221,29 @@
item in the current table.
*/
if (rc > 6) {
- char *p = allocate_outside_nursery_large(sizeof(stm_hashtable_entry_t));
- entry = (stm_hashtable_entry_t *)(p - stm_object_pages);
+ if (_is_from_same_transaction(hashtableobj)) {
+ entry = (stm_hashtable_entry_t *)
+ stm_allocate(sizeof(stm_hashtable_entry_t));
+ entry->userdata = stm_hashtable_entry_userdata;
+ entry->index = index;
+ entry->object = NULL;
+ }
+ else {
+ char *p = allocate_outside_nursery_large(
+ sizeof(stm_hashtable_entry_t));
+ entry = (stm_hashtable_entry_t *)(p - stm_object_pages);
- long j;
- for (j = 0; j <= NB_SEGMENTS; j++) {
- struct stm_hashtable_entry_s *e = (struct stm_hashtable_entry_s *)
- REAL_ADDRESS(get_segment_base(j), entry);
- e->header.stm_flags = GCFLAG_WRITE_BARRIER;
- e->userdata = stm_hashtable_entry_userdata;
- e->index = index;
- e->object = NULL;
+ long j;
+ for (j = 0; j <= NB_SEGMENTS; j++) {
+ struct stm_hashtable_entry_s *e;
+ e = (struct stm_hashtable_entry_s *)
+ REAL_ADDRESS(get_segment_base(j), entry);
+ e->header.stm_flags = GCFLAG_WRITE_BARRIER;
+ e->userdata = stm_hashtable_entry_userdata;
+ e->index = index;
+ e->object = NULL;
+ }
}
-
write_fence(); /* make sure 'entry' is fully initialized here */
table->items[i] = entry;
write_fence(); /* make sure 'table->items' is written here */
@@ -242,13 +253,15 @@
else {
/* if rc is smaller than 6, we must allocate a new bigger table.
*/
- uintptr_t biggercount = (table->mask + 1) * 2;
+ uintptr_t biggercount = table->mask + 1;
if (biggercount < 50000)
+ biggercount *= 4;
+ else
biggercount *= 2;
size_t size = (offsetof(stm_hashtable_table_t, items)
+ biggercount * sizeof(stm_hashtable_entry_t *));
stm_hashtable_table_t *biggertable = malloc(size);
- assert(biggertable);
+ assert(biggertable); // XXX
table->resize_counter = (uintptr_t)biggertable;
/* unlock, but put the new table, so IS_EVEN() is still true */
@@ -265,7 +278,7 @@
}
biggertable->resize_counter = rc;
- write_fence(); /* make sure as well that 'biggertable' is valid here;
+ write_fence(); /* make sure that 'biggertable' is valid here,
and make sure 'table->resize_counter' is updated
('table' must be immutable from now on). */
VOLATILE_HASHTABLE(hashtable)->table = biggertable;
@@ -273,17 +286,34 @@
}
}
-object_t *stm_hashtable_read(stm_hashtable_t *hashtable, uintptr_t index)
+object_t *stm_hashtable_read(object_t *hashtableobj, stm_hashtable_t *hashtable,
+ uintptr_t index)
{
- stm_hashtable_entry_t *e = _stm_hashtable_lookup(hashtable, index);
+ stm_hashtable_entry_t *e = _stm_hashtable_lookup(hashtableobj, hashtable,
+ index);
stm_read((object_t *)e);
return e->object;
}
-void stm_hashtable_write(stm_hashtable_t *hashtable, uintptr_t index,
- object_t *nvalue)
+void stm_hashtable_write(object_t *hashtableobj, stm_hashtable_t *hashtable,
+ uintptr_t index, object_t *nvalue)
{
- stm_hashtable_entry_t *e = _stm_hashtable_lookup(hashtable, index);
+ stm_hashtable_entry_t *e = _stm_hashtable_lookup(hashtableobj, hashtable,
+ index);
stm_write((object_t *)e);
e->object = nvalue;
}
+
+void stm_hashtable_tracefn(stm_hashtable_t *hashtable, void trace(object_t **))
+{
+ stm_hashtable_table_t *table;
+ table = VOLATILE_HASHTABLE(hashtable)->table;
+
+ uintptr_t j, mask = table->mask;
+ for (j = 0; j <= mask; j++) {
+ stm_hashtable_entry_t **pentry = &table->items[j];
+ if (*pentry != NULL) {
+ trace((object_t **)pentry);
+ }
+ }
+}
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -44,6 +44,10 @@
tree_contains(STM_PSEGMENT->young_outside_nursery, (uintptr_t)obj));
}
+static inline bool _is_from_same_transaction(object_t *obj) {
+ return _is_young(obj) || IS_OVERFLOW_OBJ(STM_PSEGMENT, obj);
+}
+
long stm_can_move(object_t *obj)
{
/* 'long' return value to avoid using 'bool' in the public interface */
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -536,9 +536,11 @@
typedef struct stm_hashtable_s stm_hashtable_t;
stm_hashtable_t *stm_hashtable_create(void);
void stm_hashtable_free(stm_hashtable_t *);
-object_t *stm_hashtable_read(stm_hashtable_t *, uintptr_t key);
-void stm_hashtable_write(stm_hashtable_t *, uintptr_t key, object_t *nvalue);
+object_t *stm_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key);
+void stm_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key,
+ object_t *nvalue);
extern uint32_t stm_hashtable_entry_userdata;
+void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
/* ==================== END ==================== */
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -169,11 +169,15 @@
typedef struct stm_hashtable_s stm_hashtable_t;
stm_hashtable_t *stm_hashtable_create(void);
void stm_hashtable_free(stm_hashtable_t *);
-object_t *stm_hashtable_read(stm_hashtable_t *, uintptr_t key);
-bool _check_hashtable_read(stm_hashtable_t *, uintptr_t key);
+bool _check_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key);
object_t *hashtable_read_result;
-bool _check_hashtable_write(stm_hashtable_t *, uintptr_t key, object_t *nvalue);
+bool _check_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key,
+ object_t *nvalue);
uint32_t stm_hashtable_entry_userdata;
+void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
+
+void _set_hashtable(object_t *obj, stm_hashtable_t *h);
+stm_hashtable_t *_get_hashtable(object_t *obj);
""")
@@ -251,14 +255,15 @@
object_t *hashtable_read_result;
-bool _check_hashtable_read(stm_hashtable_t *h, uintptr_t key)
+bool _check_hashtable_read(object_t *hobj, stm_hashtable_t *h, uintptr_t key)
{
- CHECKED(hashtable_read_result = stm_hashtable_read(h, key));
+ CHECKED(hashtable_read_result = stm_hashtable_read(hobj, h, key));
}
-bool _check_hashtable_write(stm_hashtable_t *h, uintptr_t key, object_t *nvalue)
+bool _check_hashtable_write(object_t *hobj, stm_hashtable_t *h, uintptr_t key,
+ object_t *nvalue)
{
- CHECKED(stm_hashtable_write(h, key, nvalue));
+ CHECKED(stm_hashtable_write(hobj, h, key, nvalue));
}
#undef CHECKED
@@ -289,6 +294,20 @@
return *WEAKREF_PTR(obj, size);
}
+void _set_hashtable(object_t *obj, stm_hashtable_t *h)
+{
+ stm_char *field_addr = ((stm_char*)obj);
+ field_addr += SIZEOF_MYOBJ; /* header */
+ *(stm_hashtable_t *TLPREFIX *)field_addr = h;
+}
+
+stm_hashtable_t *_get_hashtable(object_t *obj)
+{
+ stm_char *field_addr = ((stm_char*)obj);
+ field_addr += SIZEOF_MYOBJ; /* header */
+ return *(stm_hashtable_t *TLPREFIX *)field_addr;
+}
+
void _set_ptr(object_t *obj, int n, object_t *v)
{
long nrefs = (long)((myobj_t*)obj)->type_id - 421420;
@@ -317,7 +336,14 @@
ssize_t stmcb_size_rounded_up(struct object_s *obj)
{
struct myobj_s *myobj = (struct myobj_s*)obj;
+ assert(myobj->type_id != 0);
if (myobj->type_id < 421420) {
+ if (myobj->type_id == 421419) { /* hashtable */
+ return sizeof(struct myobj_s) + 1 * sizeof(void*);
+ }
+ if (myobj->type_id == 421418) { /* hashtable entry */
+ return 8 * 3;
+ }
/* basic case: tid equals 42 plus the size of the object */
assert(myobj->type_id >= 42 + sizeof(struct myobj_s));
assert((myobj->type_id - 42) >= 16);
@@ -337,6 +363,17 @@
{
int i;
struct myobj_s *myobj = (struct myobj_s*)obj;
+ if (myobj->type_id == 421419) {
+ /* hashtable */
+ stm_hashtable_t *h = *((stm_hashtable_t **)(myobj + 1));
+ stm_hashtable_tracefn(h, visit);
+ return;
+ }
+ if (myobj->type_id == 421418) {
+ /* hashtable entry */
+ object_t **ref = ((object_t **)myobj) + 2;
+ visit(ref);
+ }
if (myobj->type_id < 421420) {
/* basic case: no references */
return;
@@ -355,6 +392,8 @@
{
int i;
struct myobj_s *myobj = (struct myobj_s*)obj;
+ assert(myobj->type_id != 421419);
+ assert(myobj->type_id != 421418);
if (myobj->type_id < 421420) {
/* basic case: no references */
return;
@@ -425,7 +464,7 @@
CARD_SIZE = lib._STM_CARD_SIZE # 16b at least
NB_SEGMENTS = lib.STM_NB_SEGMENTS
FAST_ALLOC = lib._STM_FAST_ALLOC
-lib.stm_hashtable_entry_userdata = 42 + HDR + 2 * 8
+lib.stm_hashtable_entry_userdata = 421418
class Conflict(Exception):
pass
@@ -463,6 +502,18 @@
lib._set_weakref(o, point_to_obj)
return o
+def stm_allocate_hashtable():
+ o = lib.stm_allocate(16)
+ tid = 421419
+ lib._set_type_id(o, tid)
+ h = lib.stm_hashtable_create()
+ lib._set_hashtable(o, h)
+ return o
+
+def get_hashtable(o):
+ assert lib._get_type_id(o) == 421419
+ return lib._get_hashtable(o)
+
def stm_get_weakref(o):
return lib._get_weakref(o)
diff --git a/c7/test/test_hashtable.py b/c7/test/test_hashtable.py
--- a/c7/test/test_hashtable.py
+++ b/c7/test/test_hashtable.py
@@ -3,112 +3,118 @@
import py
-class StmHashTable(object):
- def __init__(self):
- self.h = lib.stm_hashtable_create()
+def htget(o, key):
+ h = get_hashtable(o)
+ res = lib._check_hashtable_read(o, h, key)
+ if res:
+ raise Conflict
+ return lib.hashtable_read_result
- def free(self):
- lib.stm_hashtable_free(self.h)
-
- def __getitem__(self, key):
- res = lib._check_hashtable_read(self.h, key)
- if res:
- raise Conflict
- return lib.hashtable_read_result
-
- def __setitem__(self, key, nvalue):
- res = lib._check_hashtable_write(self.h, key, nvalue)
- if res:
- raise Conflict
+def htset(o, key, nvalue):
+ h = get_hashtable(o)
+ res = lib._check_hashtable_write(o, h, key, nvalue)
+ if res:
+ raise Conflict
class TestHashtable(BaseTest):
def test_empty(self):
self.start_transaction()
- h = StmHashTable()
+ h = stm_allocate_hashtable()
for i in range(100):
index = random.randrange(0, 1<<64)
- got = h[index]
+ got = htget(h, index)
assert got == ffi.NULL
- h.free()
def test_set_value(self):
self.start_transaction()
- h = StmHashTable()
+ h = stm_allocate_hashtable()
lp1 = stm_allocate(16)
- h[12345678901] = lp1
- assert h[12345678901] == lp1
+ htset(h, 12345678901, lp1)
+ assert htget(h, 12345678901) == lp1
for i in range(64):
index = 12345678901 ^ (1 << i)
- assert h[index] == ffi.NULL
- assert h[12345678901] == lp1
- h.free()
+ assert htget(h, index) == ffi.NULL
+ assert htget(h, 12345678901) == lp1
def test_no_conflict(self):
- h = StmHashTable()
lp1 = stm_allocate_old(16)
lp2 = stm_allocate_old(16)
#
self.start_transaction()
+ h = stm_allocate_hashtable()
+ self.push_root(h)
stm_set_char(lp1, 'A')
- h[1234] = lp1
+ htset(h, 1234, lp1)
self.commit_transaction()
#
self.start_transaction()
+ h = self.pop_root()
stm_set_char(lp2, 'B')
- h[9991234] = lp2
+ htset(h, 9991234, lp2)
#
self.switch(1)
self.start_transaction()
- lp1b = h[1234]
+ lp1b = htget(h, 1234)
+ assert lp1b != ffi.NULL
assert stm_get_char(lp1b) == 'A'
assert lp1b == lp1
self.commit_transaction()
#
self.switch(0)
- assert h[9991234] == lp2
+ assert htget(h, 9991234) == lp2
assert stm_get_char(lp2) == 'B'
- assert h[1234] == lp1
- h[1234] = ffi.NULL
+ assert htget(h, 1234) == lp1
+ htset(h, 1234, ffi.NULL)
self.commit_transaction()
- h.free()
def test_conflict(self):
- h = StmHashTable()
lp1 = stm_allocate_old(16)
lp2 = stm_allocate_old(16)
#
self.start_transaction()
- h[1234] = lp1
+ h = stm_allocate_hashtable()
+ self.push_root(h)
+ self.commit_transaction()
+ #
+ self.start_transaction()
+ h = self.pop_root()
+ self.push_root(h)
+ htset(h, 1234, lp1)
#
self.switch(1)
self.start_transaction()
- py.test.raises(Conflict, "h[1234] = lp2")
+ py.test.raises(Conflict, "htset(h, 1234, lp2)")
def test_keepalive_minor(self):
- h = StmHashTable()
self.start_transaction()
+ h = stm_allocate_hashtable()
+ self.push_root(h)
lp1 = stm_allocate(16)
stm_set_char(lp1, 'N')
- h[1234] = lp1
+ htset(h, 1234, lp1)
stm_minor_collect()
- lp1b = h[1234]
+ h = self.pop_root()
+ lp1b = htget(h, 1234)
assert lp1b != ffi.NULL
assert stm_get_char(lp1b) == 'N'
assert lp1b != lp1
def test_keepalive_major(self):
- h = StmHashTable()
lp1 = stm_allocate_old(16)
#
self.start_transaction()
+ h = stm_allocate_hashtable()
+ self.push_root(h)
stm_set_char(lp1, 'N')
- h[1234] = lp1
+ htset(h, 1234, lp1)
self.commit_transaction()
#
self.start_transaction()
stm_major_collect()
- lp1b = h[1234]
+ h = self.pop_root()
+ self.push_root(h)
+ lp1b = htget(h, 1234)
assert lp1b == lp1
assert stm_get_char(lp1b) == 'N'
More information about the pypy-commit
mailing list