Author: Armin Rigo <ar...@tunes.org> 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 pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit