Author: Armin Rigo <[email protected]>
Branch:
Changeset: r80:1456f52e680d
Date: 2013-06-08 22:49 +0200
http://bitbucket.org/pypy/stmgc/changeset/1456f52e680d/
Log: in-progress
diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -60,38 +60,6 @@
/************************************************************/
-#if 0
-static inline gcptr AddInReadSet(struct tx_descriptor *d, gcptr R)
-{
- fprintf(stderr, "AddInReadSet(%p)\n", R);
- d->count_reads++;
- if (!fxcache_add(&d->recent_reads_cache, R)) {
- /* not in the cache: it may be the first time we see it,
- * so insert it into the list */
- gcptrlist_insert(&d->list_of_read_objects, R);
- }
- // break;
-
- // case 2:
- /* already in the cache, and FX_THRESHOLD reached */
- // return Localize(d, R);
- // }
- return R;
-}
-#endif
-
-static void steal(gcptr P)
-{
- struct tx_public_descriptor *foreign_pd;
- revision_t target_descriptor_index;
- revision_t v = ACCESS_ONCE(P->h_revision);
- if ((v & 3) != 2)
- return;
- target_descriptor_index = *(revision_t *)(v & ~(HANDLE_BLOCK_SIZE-1));
- //foreign_pd = ACCESS_ONCE(stm_descriptor_array[target_descriptor_index]);
- abort();
-}
-
gcptr stm_DirectReadBarrier(gcptr G)
{
struct tx_descriptor *d = thread_descriptor;
@@ -106,26 +74,26 @@
v = ACCESS_ONCE(P->h_revision);
if (!(v & 1)) // "is a pointer", i.e.
{ // "has a more recent revision"
- if (v & 2)
- goto old_to_young;
- assert(P->h_tid & GCFLAG_PUBLIC);
+ /* if we land on a P in read_barrier_cache: just return it */
+ gcptr P_next = (gcptr)v;
+ if (FXCACHE_AT(P_next) == P_next)
+ {
+ fprintf(stderr, "read_barrier: %p -> %p fxcache\n", G, P_next);
+ return P_next;
+ }
+
+ if (P->h_tid & GCFLAG_STUB)
+ goto follow_stub;
gcptr P_prev = P;
- P = (gcptr)v;
-
- /* if we land on a P in read_barrier_cache: just return it */
- if (FXCACHE_AT(P) == P)
- {
- fprintf(stderr, "read_barrier: %p -> %p fxcache\n", G, P);
- return P;
- }
+ P = P_next;
+ assert(P->h_tid & GCFLAG_PUBLIC);
v = ACCESS_ONCE(P->h_revision);
if (!(v & 1)) // "is a pointer", i.e.
{ // "has a more recent revision"
- if (v & 2)
- goto old_to_young;
- assert(P->h_tid & GCFLAG_PUBLIC);
+ if (P->h_tid & GCFLAG_STUB)
+ goto follow_stub;
/* we update P_prev->h_revision as a shortcut */
/* XXX check if this really gives a worse performance than only
@@ -171,12 +139,12 @@
gcptrlist_insert(&d->list_of_read_objects, P);
return P;
- old_to_young:;
- revision_t target_descriptor_index;
- target_descriptor_index = *(revision_t *)(v & ~(HANDLE_BLOCK_SIZE-1));
- if (target_descriptor_index == d->public_descriptor_index)
+ follow_stub:;
+ struct tx_public_descriptor *foreign_pd = STUB_THREAD(P);
+ if (foreign_pd == d->public_descriptor)
{
- P = (gcptr)(*(revision_t *)(v - 2));
+ /* same thread */
+ P = (gcptr)P->h_revision;
assert(!(P->h_tid & GCFLAG_PUBLIC));
if (P->h_revision == stm_private_rev_num)
{
@@ -200,8 +168,8 @@
else
{
/* stealing */
- fprintf(stderr, "read_barrier: %p -> stealing %p...", G, (gcptr)v);
- steal(P);
+ fprintf(stderr, "read_barrier: %p -> stealing %p...", G, P);
+ stm_steal_stub(P);
goto retry;
}
}
@@ -401,6 +369,8 @@
gcptr stm_get_backup_copy(gcptr P)
{
+ assert(P->h_revision == stm_private_rev_num);
+
struct tx_public_descriptor *pd = thread_descriptor->public_descriptor;
long i, size = pd->active_backup_copies.size;
gcptr *items = pd->active_backup_copies.items;
@@ -735,7 +705,7 @@
#endif
}
-static pthread_mutex_t mutex_prebuilt_gcroots = PTHREAD_MUTEX_INITIALIZER;
+//static pthread_mutex_t mutex_prebuilt_gcroots = PTHREAD_MUTEX_INITIALIZER;
static void UpdateChainHeads(struct tx_descriptor *d, revision_t cur_time,
revision_t localrev)
@@ -763,6 +733,11 @@
#endif
L->h_revision = new_revision;
+ gcptr stub = stm_stub_malloc(d->public_descriptor);
+ stub->h_tid = GCFLAG_PUBLIC | GCFLAG_STUB;
+ stub->h_revision = (revision_t)L;
+ item->val = stub;
+
} G2L_LOOP_END;
smp_wmb(); /* a memory barrier: make sure the new L->h_revisions are visible
@@ -779,22 +754,12 @@
assert(!(R->h_tid & GCFLAG_STOLEN));
assert(R->h_revision != localrev);
- /* XXX compactify and don't leak! */
- revision_t *handle_block = stm_malloc(3 * WORD);
- handle_block = (revision_t *)
- ((((intptr_t)handle_block) + HANDLE_BLOCK_SIZE-1)
- & ~(HANDLE_BLOCK_SIZE-1));
- handle_block[0] = d->public_descriptor_index;
- handle_block[1] = v;
-
- revision_t w = ((revision_t)(handle_block + 1)) + 2;
-
#ifdef DUMP_EXTRA
- fprintf(stderr, "%p->h_revision = %p (UpdateChainHeads2)\n",
- R, (gcptr)w);
+ fprintf(stderr, "%p->h_revision = %p (stub to %p)\n",
+ R, (gcptr)v, (gcptr)item->val->h_revision);
/*mark*/
#endif
- ACCESS_ONCE(R->h_revision) = w;
+ ACCESS_ONCE(R->h_revision) = v;
#if 0
if (R->h_tid & GCFLAG_PREBUILT_ORIGINAL)
diff --git a/c4/et.h b/c4/et.h
--- a/c4/et.h
+++ b/c4/et.h
@@ -13,9 +13,7 @@
#define MAX_THREADS 1024
#define LOCKED (INTPTR_MAX - 2*(MAX_THREADS-1))
-
#define WORD sizeof(gcptr)
-#define HANDLE_BLOCK_SIZE (2 * WORD)
/* Description of the flags
* ------------------------
@@ -52,8 +50,9 @@
* GCFLAG_STOLEN is set of protected objects after we notice that they
* have been stolen.
*
- * GCFLAG_STUB is used for debugging: it's set on stub objects made by
- * stealing or by major collections.
+ * GCFLAG_STUB is set on stub objects made by stealing or by major
+ * collections. It's removed once the stub's protected h_revision
+ * target is stolen and replaced by a regular public object.
*/
#define GCFLAG_OLD (STM_FIRST_GCFLAG << 0)
#define GCFLAG_VISITED (STM_FIRST_GCFLAG << 1)
@@ -64,7 +63,7 @@
#define GCFLAG_WRITE_BARRIER (STM_FIRST_GCFLAG << 6)
#define GCFLAG_NURSERY_MOVED (STM_FIRST_GCFLAG << 7)
#define GCFLAG_STOLEN (STM_FIRST_GCFLAG << 8)
-#define GCFLAG_STUB (STM_FIRST_GCFLAG << 9) /* debugging */
+#define GCFLAG_STUB (STM_FIRST_GCFLAG << 9)
/* this value must be reflected in PREBUILT_FLAGS in stmgc.h */
#define GCFLAG_PREBUILT (GCFLAG_VISITED | \
@@ -106,6 +105,8 @@
* thread shuts down. It is reused the next time a thread starts. */
struct tx_public_descriptor {
revision_t collection_lock;
+ struct stub_block_s *stub_blocks;
+ gcptr stub_free_list;
struct GcPtrList stolen_objects;
struct GcPtrList active_backup_copies;
revision_t free_list_next;
diff --git a/c4/steal.c b/c4/steal.c
new file mode 100644
--- /dev/null
+++ b/c4/steal.c
@@ -0,0 +1,57 @@
+#include "stmimpl.h"
+
+
+#define STUB_PAGE (4096 - 2*WORD)
+#define STUB_NB_OBJS ((STUB_BLOCK_SIZE - 2*WORD) / \
+ sizeof(struct stm_object_s))
+
+struct stub_block_s {
+ struct tx_public_descriptor *thread;
+ struct stub_block_s *next;
+ struct stm_object_s stubs[STUB_NB_OBJS];
+};
+
+gcptr stm_stub_malloc(struct tx_public_descriptor *pd)
+{
+ gcptr p = pd->stub_free_list;
+ if (p == NULL) {
+ assert(sizeof(struct stub_block_s) == STUB_BLOCK_SIZE);
+
+ char *page = stm_malloc(STUB_PAGE);
+ char *page_end = page + STUB_PAGE;
+ page += (-(revision_t)page) & (STUB_BLOCK_SIZE-1); /* round up */
+
+ struct stub_block_s *b = (struct stub_block_s *)page;
+ struct stub_block_s *nextb = NULL;
+ gcptr nextp = NULL;
+ int i;
+
+ while (((char *)(b + 1)) <= page_end) {
+ b->thread = pd;
+ b->next = nextb;
+ for (i = 0; i < STUB_NB_OBJS; i++) {
+ b->stubs[i].h_revision = (revision_t)nextp;
+ nextp = &b->stubs[i];
+ }
+ b++;
+ }
+ assert(nextp != NULL);
+ p = nextp;
+ }
+ pd->stub_free_list = (gcptr)p->h_revision;
+ assert(STUB_THREAD(p) == pd);
+ return p;
+}
+
+void stm_steal_stub(gcptr P)
+{
+ abort();
+ struct tx_public_descriptor *foreign_pd;
+ revision_t target_descriptor_index;
+ revision_t v = ACCESS_ONCE(P->h_revision);
+ if ((v & 3) != 2)
+ return;
+ target_descriptor_index = *(revision_t *)(v & ~(STUB_BLOCK_SIZE-1));
+ foreign_pd = stm_descriptor_array[target_descriptor_index];
+ abort();
+}
diff --git a/c4/steal.h b/c4/steal.h
new file mode 100644
--- /dev/null
+++ b/c4/steal.h
@@ -0,0 +1,14 @@
+#ifndef _SRCSTM_STEAL_H
+#define _SRCSTM_STEAL_H
+
+
+#define STUB_BLOCK_SIZE (16 * WORD) /* power of two */
+
+#define STUB_THREAD(h) (*(struct tx_public_descriptor **) \
+ (((revision_t)(h)) & ~(STUB_BLOCK_SIZE-1)))
+
+gcptr stm_stub_malloc(struct tx_public_descriptor *);
+void stm_steal_stub(gcptr);
+
+
+#endif
diff --git a/c4/stmimpl.h b/c4/stmimpl.h
--- a/c4/stmimpl.h
+++ b/c4/stmimpl.h
@@ -31,6 +31,7 @@
#include "lists.h"
#include "dbgmem.h"
#include "et.h"
+#include "steal.h"
#include "stmsync.h"
#endif
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -5,11 +5,11 @@
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
header_files = [os.path.join(parent_dir, _n) for _n in
- "et.h lists.h "
+ "et.h lists.h steal.h "
"stmsync.h dbgmem.h fprintcolor.h "
"stmgc.h stmimpl.h atomic_ops.h".split()]
source_files = [os.path.join(parent_dir, _n) for _n in
- "et.c lists.c "
+ "et.c lists.c steal.c "
"stmsync.c dbgmem.c fprintcolor.c".split()]
_pycache_ = os.path.join(parent_dir, 'test', '__pycache__')
@@ -70,6 +70,7 @@
void AbortTransaction(int);
gcptr stm_get_backup_copy(gcptr);
gcptr stm_get_read_obj(long index);
+ void *STUB_THREAD(gcptr);
gcptr getptr(gcptr, long);
void setptr(gcptr, long, gcptr);
@@ -84,7 +85,7 @@
gcptr pseudoprebuilt(size_t size, int tid);
revision_t get_private_rev_num(void);
revision_t get_start_time(void);
- revision_t get_descriptor_index(void);
+ void *my_stub_thread(void);
//gcptr *addr_of_thread_local(void);
//int in_nursery(gcptr);
@@ -93,7 +94,7 @@
/* some constants normally private that are useful in the tests */
#define WORD ...
#define GC_PAGE_SIZE ...
- #define HANDLE_BLOCK_SIZE ...
+ #define STUB_BLOCK_SIZE ...
#define GCFLAG_OLD ...
#define GCFLAG_VISITED ...
#define GCFLAG_PUBLIC ...
@@ -206,9 +207,9 @@
return thread_descriptor->start_time;
}
- revision_t get_descriptor_index(void)
+ void *my_stub_thread(void)
{
- return thread_descriptor->public_descriptor_index;
+ return (void *)thread_descriptor->public_descriptor;
}
/*gcptr *addr_of_thread_local(void)
@@ -526,10 +527,14 @@
private = p.h_revision == lib.get_private_rev_num()
public = (p.h_tid & GCFLAG_PUBLIC) != 0
backup = (p.h_tid & GCFLAG_BACKUP_COPY) != 0
+ stub = (p.h_tid & GCFLAG_STUB) != 0
assert private + public + backup <= 1
+ assert stub <= public
if private:
return "private"
if public:
+ if stub:
+ return "stub"
return "public"
if backup:
return "backup"
@@ -547,10 +552,4 @@
index += 1
return result
-def decode_handle(r):
- assert (r & 3) == 2
- p = r & ~(lib.HANDLE_BLOCK_SIZE-1)
- dindex = ffi.cast("revision_t *", p)[0]
- assert 0 <= dindex < 20
- ptr = ffi.cast("gcptr *", r - 2)[0]
- return ptr, dindex
+stub_thread = lib.STUB_THREAD
diff --git a/c4/test/test_et.py b/c4/test/test_et.py
--- a/c4/test/test_et.py
+++ b/c4/test/test_et.py
@@ -80,10 +80,9 @@
assert p.h_revision == lib.get_private_rev_num()
lib.stm_commit_transaction()
lib.stm_begin_inevitable_transaction()
- assert lib.stm_get_backup_copy(p) == ffi.NULL
assert classify(p) == "protected"
assert classify(pback) == "backup"
- assert ffi.cast("revision_t *", p.h_revision) == pback
+ assert ffi.cast("gcptr", p.h_revision) == pback
def test_protected_backup_reused():
p = nalloc(HDR + WORD)
@@ -95,7 +94,6 @@
assert pback != p
lib.stm_commit_transaction()
lib.stm_begin_inevitable_transaction()
- assert lib.stm_get_backup_copy(p) == ffi.NULL
assert classify(p) == "protected"
assert classify(pback) == "backup"
assert lib.rawgetlong(p, 0) == 927122
@@ -138,7 +136,9 @@
lib.stm_begin_inevitable_transaction()
assert classify(p) == "public"
assert classify(p2) == "protected"
- assert decode_handle(p.h_revision) == (p2, lib.get_descriptor_index())
+ pstub = ffi.cast("gcptr", p.h_revision)
+ assert classify(pstub) == "stub"
+ assert stub_thread(pstub) == lib.my_stub_thread()
assert lib.rawgetlong(p, 0) == 28971289
assert lib.rawgetlong(p2, 0) == 1289222
@@ -241,7 +241,7 @@
assert classify(p1) == "protected"
plist.append(p1)
# now p's most recent revision is protected
- assert p.h_revision % 4 == 2 # a handle
+ assert classify(ffi.cast("gcptr", p.h_revision)) == "stub"
r.set(2)
r.wait(3)
assert lib.list_stolen_objects() == plist[-2:]
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit