Author: Remi Meier <remi.me...@gmail.com> Branch: c7 Changeset: r604:75dfcdb650aa Date: 2014-01-14 14:57 +0100 http://bitbucket.org/pypy/stmgc/changeset/75dfcdb650aa/
Log: add tests diff --git a/c7/core.c b/c7/core.c --- a/c7/core.c +++ b/c7/core.c @@ -16,10 +16,20 @@ #define NB_PAGES (256*256) // 256MB #define NB_THREADS 2 -#define MAP_PAGES_FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE) +#define MAP_PAGES_FLAGS (MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE) #define LARGE_OBJECT_WORDS 36 #define NB_NURSERY_PAGES 1024 + +#define TOTAL_MEMORY (NB_PAGES * 4096UL * NB_THREADS) +#define READMARKER_END ((NB_PAGES * 4096UL) >> 4) +#define FIRST_OBJECT_PAGE ((READMARKER_END + 4095) / 4096UL) +#define READMARKER_START ((FIRST_OBJECT_PAGE * 4096UL) >> 4) +#define FIRST_READMARKER_PAGE (READMARKER_START / 4096UL) +#define FIRST_AFTER_NURSERY_PAGE (FIRST_OBJECT_PAGE + NB_NURSERY_PAGES) + + + #if defined(__i386__) || defined(__x86_64__) # define HAVE_FULL_EXCHANGE_INSN #endif @@ -64,6 +74,7 @@ asm("pause" : : : "memory"); } +#if 0 static void acquire_lock(int *lock) { while (__sync_lock_test_and_set(lock, 1) != 0) { @@ -92,6 +103,7 @@ { __sync_lock_release(lock); } +#endif static void write_fence(void) { @@ -102,12 +114,18 @@ #endif } -static bool _stm_was_read(object_t *obj) +bool _stm_was_read(object_t *obj) { read_marker_t *marker = (read_marker_t *)(((uintptr_t)obj) >> 4); return (marker->rm == _STM_TL1->transaction_read_version); } +bool _stm_was_written(object_t *obj) +{ + return obj->stm_flags & GCFLAG_WRITE_BARRIER; +} + + static void _stm_privatize(uintptr_t pagenum) { @@ -234,7 +252,6 @@ char* t0_addr = get_thread_base(0) + t0_offset; struct object_s *t0_obj = (struct object_s *)t0_addr; - int previous = __sync_lock_test_and_set(&t0_obj->stm_write_lock, 1); if (previous) abort(); /* XXX */ @@ -331,15 +348,6 @@ - - -#define TOTAL_MEMORY (NB_PAGES * 4096UL * NB_THREADS) -#define READMARKER_END ((NB_PAGES * 4096UL) >> 4) -#define FIRST_OBJECT_PAGE ((READMARKER_END + 4095) / 4096UL) -#define READMARKER_START ((FIRST_OBJECT_PAGE * 4096UL) >> 4) -#define FIRST_READMARKER_PAGE (READMARKER_START / 4096UL) -#define FIRST_AFTER_NURSERY_PAGE (FIRST_OBJECT_PAGE + NB_NURSERY_PAGES) - void stm_setup(void) { /* Check that some values are acceptable */ @@ -376,14 +384,16 @@ /* Pages in range(2, FIRST_READMARKER_PAGE) are never used */ if (FIRST_READMARKER_PAGE > 2) mprotect(thread_base + 8192, (FIRST_READMARKER_PAGE - 2) * 4096UL, - PROT_NONE); + PROT_NONE); - _STM_TL2->thread_num = i; - _STM_TL2->thread_base = thread_base; + struct _thread_local2_s *th = + (struct _thread_local2_s *)REAL_ADDRESS(thread_base, _STM_TL2); + + th->thread_num = i; + th->thread_base = thread_base; if (i > 0) { int res; - res = remap_file_pages( thread_base + FIRST_AFTER_NURSERY_PAGE * 4096UL, (NB_PAGES - FIRST_AFTER_NURSERY_PAGE) * 4096UL, @@ -414,12 +424,8 @@ int thread_num = __sync_fetch_and_add(&num_threads_started, 1); assert(thread_num < 2); /* only 2 threads for now */ - char *thread_base = get_thread_base(thread_num); - set_gs_register((uintptr_t)thread_base); - - assert(_STM_TL2->thread_num == thread_num); - assert(_STM_TL2->thread_base == thread_base); - + _stm_restore_local_state(thread_num); + _STM_TL2->modified_objects = stm_list_create(); assert(!_STM_TL2->running_transaction); } @@ -440,6 +446,14 @@ object_pages = NULL; } +void _stm_restore_local_state(int thread_num) +{ + char *thread_base = get_thread_base(thread_num); + set_gs_register((uintptr_t)thread_base); + + assert(_STM_TL2->thread_num == thread_num); + assert(_STM_TL2->thread_base == thread_base); +} static void reset_transaction_read_version(void) { @@ -504,6 +518,7 @@ _STM_TL2->running_transaction = 1; } +#if 0 static void update_new_objects_in_other_threads(uintptr_t pagenum, uint16_t start, uint16_t stop) { @@ -517,16 +532,17 @@ char *src = REAL_ADDRESS(_STM_TL2->thread_base, local_src); memcpy(dst, src, size); - ...; + abort(); } +#endif void stm_stop_transaction(void) { +#if 0 assert(_STM_TL2->running_transaction); write_fence(); /* see later in this function for why */ - acquire_lock(&undo_lock); if (leader_thread_num != _STM_TL2->thread_num) { /* non-leader thread */ @@ -617,7 +633,7 @@ } _STM_TL2->running_transaction = 0; - release_lock(&undo_lock); +#endif } void stm_abort_transaction(void) diff --git a/c7/core.h b/c7/core.h --- a/c7/core.h +++ b/c7/core.h @@ -44,7 +44,7 @@ uint8_t rm; }; -typedef intptr_t jmpbufptr_t[5]; /* for use with __builtin_setjmp() */ +typedef void* jmpbufptr_t[5]; /* for use with __builtin_setjmp() */ struct _thread_local1_s { jmpbufptr_t *jmpbufptr; @@ -78,5 +78,17 @@ /* must be provided by the user of this library */ extern size_t stm_object_size_rounded_up(object_t *); +void _stm_restore_local_state(int thread_num); +void _stm_teardown(void); +void _stm_teardown_thread(void); + +bool _stm_was_read(object_t *obj); +bool _stm_was_written(object_t *obj); + +object_t *stm_allocate(size_t size); +void stm_setup(void); +void stm_setup_thread(void); +void stm_start_transaction(jmpbufptr_t *jmpbufptr); +void stm_stop_transaction(void); #endif diff --git a/c7/list.c b/c7/list.c --- a/c7/list.c +++ b/c7/list.c @@ -1,6 +1,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <assert.h> #include "list.h" diff --git a/c7/test/support.py b/c7/test/support.py new file mode 100644 --- /dev/null +++ b/c7/test/support.py @@ -0,0 +1,119 @@ +import os +import cffi + +# ---------- + +parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +header_files = [os.path.join(parent_dir, _n) for _n in + "core.h pagecopy.h list.h".split()] +source_files = [os.path.join(parent_dir, _n) for _n in + "core.c pagecopy.c list.c".split()] + +_pycache_ = os.path.join(parent_dir, 'test', '__pycache__') +if os.path.exists(_pycache_): + _fs = [_f for _f in os.listdir(_pycache_) if _f.startswith('_cffi_')] + if _fs: + _fsmtime = min(os.stat(os.path.join(_pycache_, _f)).st_mtime + for _f in _fs) + if any(os.stat(src).st_mtime >= _fsmtime + for src in header_files + source_files): + import shutil + shutil.rmtree(_pycache_) + +# ---------- + +ffi = cffi.FFI() +ffi.cdef(""" +typedef ... object_t; +typedef ... jmpbufptr_t; + +void stm_setup(void); +void stm_setup_thread(void); + +void stm_start_transaction(jmpbufptr_t *); +void stm_stop_transaction(void); +object_t *stm_allocate(size_t size); + +void stm_read(object_t *object); +void stm_write(object_t *object); +_Bool _stm_was_read(object_t *object); +_Bool _stm_was_written(object_t *object); + +void _stm_restore_local_state(int thread_num); +void _stm_teardown(void); +void _stm_teardown_thread(void); + + +void *memset(void *s, int c, size_t n); +""") + +lib = ffi.verify(''' +#include <string.h> +#include "core.h" + +size_t stm_object_size_rounded_up(object_t * obj) { + return 16; +} + +''', sources=source_files, + define_macros=[('STM_TESTS', '1')], + undef_macros=['NDEBUG'], + include_dirs=[parent_dir], + extra_compile_args=['-g', '-O0', '-Werror'], + force_generic_engine=True) + +def intptr(p): + return int(ffi.cast("intptr_t", p)) + +def stm_allocate(size): + return ffi.cast("char *", lib.stm_allocate(size)) + +def stm_read(ptr): + lib.stm_read(ffi.cast("struct object_s *", ptr)) + +def stm_write(ptr): + lib.stm_write(ffi.cast("struct object_s *", ptr)) + +def _stm_was_read(ptr): + return lib._stm_was_read(ffi.cast("struct object_s *", ptr)) + +def _stm_was_written(ptr): + return lib._stm_was_written(ffi.cast("struct object_s *", ptr)) + +def stm_start_transaction(): + lib.stm_start_transaction() + +def stm_stop_transaction(expected_conflict): + res = lib.stm_stop_transaction() + if expected_conflict: + assert res == 0 + else: + assert res == 1 + + +class BaseTest(object): + + def setup_method(self, meth): + lib.stm_setup() + lib.stm_setup_thread() + self.saved_states = {} + self.current_proc = "main" + + def teardown_method(self, meth): + lib._stm_teardown_thread() + for saved_state in self.saved_states.values(): + lib._stm_restore_local_state(saved_state) + lib._stm_teardown_thread() + del self.saved_states + lib._stm_teardown() + + def switch(self, process_name): + self.saved_states[self.current_proc] = lib._stm_save_local_state() + try: + target_saved_state = self.saved_states.pop(process_name) + except KeyError: + lib.stm_setup_thread() + else: + lib._stm_restore_local_state(target_saved_state) + self.current_proc = process_name diff --git a/c7/test/test_basic.py b/c7/test/test_basic.py new file mode 100644 --- /dev/null +++ b/c7/test/test_basic.py @@ -0,0 +1,250 @@ +from support import * + + +class TestBasic(BaseTest): + + def test_empty(self): + pass + + def test_thread_local_allocations(self): + p1 = stm_allocate(16) + p2 = stm_allocate(16) + assert intptr(p2) - intptr(p1) == 16 + p3 = stm_allocate(16) + assert intptr(p3) - intptr(p2) == 16 + # + self.switch("sub1") + p1s = stm_allocate(16) + assert abs(intptr(p1s) - intptr(p3)) >= 4000 + # + self.switch("main") + p4 = stm_allocate(16) + assert intptr(p4) - intptr(p3) == 16 + + def test_read_write_1(self): + stm_start_transaction() + p1 = stm_allocate(16) + p1[8] = 'a' + stm_stop_transaction(False) + # + self.switch("sub1") + stm_start_transaction() + stm_write(p1) + assert p1[8] == 'a' + p1[8] = 'b' + # + self.switch("main") + stm_start_transaction() + stm_read(p1) + assert p1[8] == 'a' + # + self.switch("sub1") + stm_stop_transaction(False) + # + self.switch("main") + assert p1[8] == 'a' + + def test_start_transaction_updates(self): + stm_start_transaction() + p1 = stm_allocate(16) + p1[8] = 'a' + stm_stop_transaction(False) + # + self.switch("sub1") + stm_start_transaction() + stm_write(p1) + assert p1[8] == 'a' + p1[8] = 'b' + stm_stop_transaction(False) + # + self.switch("main") + assert p1[8] == 'a' + stm_start_transaction() + assert p1[8] == 'b' + + def test_resolve_no_conflict_empty(self): + stm_start_transaction() + # + self.switch("sub1") + stm_start_transaction() + stm_stop_transaction(False) + # + self.switch("main") + stm_stop_transaction(False) + + def test_resolve_no_conflict_write_only_in_already_committed(self): + stm_start_transaction() + p1 = stm_allocate(16) + p1[8] = 'a' + stm_stop_transaction(False) + stm_start_transaction() + # + self.switch("sub1") + stm_start_transaction() + stm_write(p1) + p1[8] = 'b' + stm_stop_transaction(False) + # + self.switch("main") + assert p1[8] == 'a' + stm_stop_transaction(False) + assert p1[8] == 'b' + + def test_resolve_write_read_conflict(self): + stm_start_transaction() + p1 = stm_allocate(16) + p1[8] = 'a' + stm_stop_transaction(False) + stm_start_transaction() + # + self.switch("sub1") + stm_start_transaction() + stm_write(p1) + p1[8] = 'b' + stm_stop_transaction(False) + # + self.switch("main") + stm_read(p1) + assert p1[8] == 'a' + stm_stop_transaction(expected_conflict=True) + assert p1[8] in ('a', 'b') + stm_start_transaction() + assert p1[8] == 'b' + + def test_resolve_write_write_conflict(self): + stm_start_transaction() + p1 = stm_allocate(16) + p1[8] = 'a' + stm_stop_transaction(False) + stm_start_transaction() + # + self.switch("sub1") + stm_start_transaction() + stm_write(p1) + p1[8] = 'b' + stm_stop_transaction(False) + # + self.switch("main") + assert p1[8] == 'a' + stm_write(p1) + p1[8] = 'c' + stm_stop_transaction(expected_conflict=True) + assert p1[8] in ('a', 'b') + stm_start_transaction() + assert p1[8] == 'b' + + def test_resolve_write_write_no_conflict(self): + stm_start_transaction() + p1 = stm_allocate(16) + p2 = stm_allocate(16) + p1[8] = 'a' + p2[8] = 'A' + stm_stop_transaction(False) + stm_start_transaction() + # + self.switch("sub1") + stm_start_transaction() + stm_write(p1) + p1[8] = 'b' + stm_stop_transaction(False) + # + self.switch("main") + stm_write(p2) + p2[8] = 'C' + stm_stop_transaction(False) + assert p1[8] == 'b' + assert p2[8] == 'C' + + def test_page_extra_malloc_unchanged_page(self): + stm_start_transaction() + p1 = stm_allocate(16) + p2 = stm_allocate(16) + p1[8] = 'A' + p2[8] = 'a' + stm_stop_transaction(False) + stm_start_transaction() + # + self.switch("sub1") + stm_start_transaction() + stm_write(p1) + assert p1[8] == 'A' + p1[8] = 'B' + stm_stop_transaction(False) + # + self.switch("main") + stm_read(p2) + assert p2[8] == 'a' + p3 = stm_allocate(16) # goes into the same page, which is + p3[8] = ':' # not otherwise modified + stm_stop_transaction(False) + # + assert p1[8] == 'B' + assert p2[8] == 'a' + assert p3[8] == ':' + + def test_page_extra_malloc_changed_page_before(self): + stm_start_transaction() + p1 = stm_allocate(16) + p2 = stm_allocate(16) + p1[8] = 'A' + p2[8] = 'a' + stm_stop_transaction(False) + stm_start_transaction() + # + self.switch("sub1") + stm_start_transaction() + stm_write(p1) + assert p1[8] == 'A' + p1[8] = 'B' + stm_stop_transaction(False) + # + self.switch("main") + stm_write(p2) + assert p2[8] == 'a' + p2[8] = 'b' + p3 = stm_allocate(16) # goes into the same page, which I already + p3[8] = ':' # modified just above + stm_stop_transaction(False) + # + assert p1[8] == 'B' + assert p2[8] == 'b' + assert p3[8] == ':' + + def test_page_extra_malloc_changed_page_after(self): + stm_start_transaction() + p1 = stm_allocate(16) + p2 = stm_allocate(16) + p1[8] = 'A' + p2[8] = 'a' + stm_stop_transaction(False) + stm_start_transaction() + # + self.switch("sub1") + stm_start_transaction() + stm_write(p1) + assert p1[8] == 'A' + p1[8] = 'B' + stm_stop_transaction(False) + # + self.switch("main") + p3 = stm_allocate(16) # goes into the same page, which I will + p3[8] = ':' # modify just below + stm_write(p2) + assert p2[8] == 'a' + p2[8] = 'b' + stm_stop_transaction(False) + # + assert p1[8] == 'B' + assert p2[8] == 'b' + assert p3[8] == ':' + + def test_overflow_write_history(self): + stm_start_transaction() + plist = [stm_allocate(n) for n in range(16, 256, 8)] + stm_stop_transaction(False) + # + for i in range(20): + stm_start_transaction() + for p in plist: + stm_write(p) + stm_stop_transaction(False) diff --git a/c7/test/test_bug.py b/c7/test/test_bug.py new file mode 100644 --- /dev/null +++ b/c7/test/test_bug.py @@ -0,0 +1,429 @@ +from support import * + + +class TestBug(BaseTest): + + def test_bug1(self): + stm_start_transaction() + p8 = stm_allocate(16) + p8[8] = '\x08' + stm_stop_transaction(False) + # + self.switch("sub1") + self.switch("main") + stm_start_transaction() + stm_write(p8) + p8[8] = '\x97' + # + self.switch("sub1") + stm_start_transaction() + stm_read(p8) + assert p8[8] == '\x08' + + def test_bug2(self): + stm_start_transaction() + p0 = stm_allocate(16) + p1 = stm_allocate(16) + p2 = stm_allocate(16) + p3 = stm_allocate(16) + p4 = stm_allocate(16) + p5 = stm_allocate(16) + p6 = stm_allocate(16) + p7 = stm_allocate(16) + p8 = stm_allocate(16) + p9 = stm_allocate(16) + p0[8] = '\x00' + p1[8] = '\x01' + p2[8] = '\x02' + p3[8] = '\x03' + p4[8] = '\x04' + p5[8] = '\x05' + p6[8] = '\x06' + p7[8] = '\x07' + p8[8] = '\x08' + p9[8] = '\t' + stm_stop_transaction(False) + self.switch(0) + self.switch(1) + self.switch(2) + # + self.switch(1) + stm_start_transaction() + stm_read(p7) + assert p7[8] == '\x07' + # + self.switch(1) + stm_read(p0) + assert p0[8] == '\x00' + # + self.switch(1) + stm_read(p4) + assert p4[8] == '\x04' + # + self.switch(0) + stm_start_transaction() + stm_read(p3) + assert p3[8] == '\x03' + # + self.switch(2) + stm_start_transaction() + stm_read(p8) + assert p8[8] == '\x08' + stm_write(p8) + p8[8] = '\x08' + # + self.switch(0) + stm_read(p0) + assert p0[8] == '\x00' + # + self.switch(0) + stm_read(p0) + assert p0[8] == '\x00' + # + self.switch(1) + stm_read(p2) + assert p2[8] == '\x02' + # + self.switch(2) + stm_read(p2) + assert p2[8] == '\x02' + # + self.switch(2) + stm_read(p2) + assert p2[8] == '\x02' + stm_write(p2) + p2[8] = 'm' + # + self.switch(0) + stm_read(p4) + assert p4[8] == '\x04' + stm_write(p4) + p4[8] = '\xc5' + # + self.switch(2) + stm_read(p1) + assert p1[8] == '\x01' + # + self.switch(2) + stm_stop_transaction(False) #1 + # ['\x00', '\x01', 'm', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\t'] + # log: [8, 2] + # + self.switch(0) + stm_stop_transaction(False) #2 + # ['\x00', '\x01', 'm', '\x03', '\xc5', '\x05', '\x06', '\x07', '\x08', '\t'] + # log: [4] + # + self.switch(0) + stm_start_transaction() + stm_read(p6) + assert p6[8] == '\x06' + # + self.switch(0) + stm_read(p4) + assert p4[8] == '\xc5' + # + self.switch(0) + stm_read(p4) + assert p4[8] == '\xc5' + # + self.switch(1) + stm_read(p0) + assert p0[8] == '\x00' + # + self.switch(1) + stm_stop_transaction(True) #3 + # conflict: 0xdf0a8028 + # + self.switch(2) + stm_start_transaction() + stm_read(p6) + assert p6[8] == '\x06' + # + self.switch(1) + stm_start_transaction() + stm_read(p1) + assert p1[8] == '\x01' + # + self.switch(0) + stm_read(p4) + assert p4[8] == '\xc5' + stm_write(p4) + p4[8] = '\x0c' + # + self.switch(2) + stm_read(p2) + assert p2[8] == 'm' + stm_write(p2) + p2[8] = '\x81' + # + self.switch(2) + stm_read(p7) + assert p7[8] == '\x07' + # + self.switch(0) + stm_read(p5) + assert p5[8] == '\x05' + stm_write(p5) + p5[8] = 'Z' + # + self.switch(1) + stm_stop_transaction(False) #4 + # ['\x00', '\x01', 'm', '\x03', '\xc5', '\x05', '\x06', '\x07', '\x08', '\t'] + # log: [] + # + self.switch(2) + stm_read(p8) + assert p8[8] == '\x08' + # + self.switch(0) + stm_read(p0) + assert p0[8] == '\x00' + # + self.switch(1) + stm_start_transaction() + stm_read(p0) + assert p0[8] == '\x00' + # + self.switch(2) + stm_read(p9) + assert p9[8] == '\t' + stm_write(p9) + p9[8] = '\x81' + # + self.switch(0) + stm_read(p0) + assert p0[8] == '\x00' + # + self.switch(1) + stm_read(p2) + assert p2[8] == 'm' + # + self.switch(2) + stm_read(p9) + assert p9[8] == '\x81' + stm_write(p9) + p9[8] = 'g' + # + self.switch(1) + stm_read(p3) + assert p3[8] == '\x03' + # + self.switch(2) + stm_read(p7) + assert p7[8] == '\x07' + # + self.switch(1) + stm_read(p1) + assert p1[8] == '\x01' + # + self.switch(0) + stm_read(p2) + assert p2[8] == 'm' + stm_write(p2) + p2[8] = 'T' + # + self.switch(2) + stm_read(p4) + assert p4[8] == '\xc5' + # + self.switch(2) + stm_read(p9) + assert p9[8] == 'g' + # + self.switch(2) + stm_read(p1) + assert p1[8] == '\x01' + stm_write(p1) + p1[8] = 'L' + # + self.switch(0) + stm_read(p0) + assert p0[8] == '\x00' + # + self.switch(2) + stm_read(p0) + assert p0[8] == '\x00' + stm_write(p0) + p0[8] = '\xf3' + # + self.switch(1) + stm_stop_transaction(False) #5 + # ['\x00', '\x01', 'm', '\x03', '\xc5', '\x05', '\x06', '\x07', '\x08', '\t'] + # log: [] + # + self.switch(0) + stm_read(p1) + assert p1[8] == '\x01' + stm_write(p1) + p1[8] = '*' + # + self.switch(1) + stm_start_transaction() + stm_read(p3) + assert p3[8] == '\x03' + stm_write(p3) + p3[8] = '\xd2' + # + self.switch(0) + stm_stop_transaction(False) #6 + # ['\x00', '*', 'T', '\x03', '\x0c', 'Z', '\x06', '\x07', '\x08', '\t'] + # log: [1, 2, 4, 5] + # + self.switch(1) + stm_read(p7) + assert p7[8] == '\x07' + stm_write(p7) + p7[8] = '.' + # + self.switch(0) + stm_start_transaction() + stm_read(p7) + assert p7[8] == '\x07' + # + self.switch(1) + stm_read(p2) + assert p2[8] == 'm' + stm_write(p2) + p2[8] = '\xe9' + # + self.switch(1) + stm_read(p0) + assert p0[8] == '\x00' + # + self.switch(0) + stm_read(p1) + assert p1[8] == '*' + # + self.switch(0) + stm_read(p8) + assert p8[8] == '\x08' + stm_write(p8) + p8[8] = 'X' + # + self.switch(2) + stm_stop_transaction(True) #7 + # conflict: 0xdf0a8018 + # + self.switch(1) + stm_read(p9) + assert p9[8] == '\t' + # + self.switch(0) + stm_read(p8) + assert p8[8] == 'X' + # + self.switch(1) + stm_read(p4) + assert p4[8] == '\xc5' + stm_write(p4) + p4[8] = '\xb2' + # + self.switch(0) + stm_read(p9) + assert p9[8] == '\t' + # + self.switch(2) + stm_start_transaction() + stm_read(p5) + assert p5[8] == 'Z' + stm_write(p5) + p5[8] = '\xfa' + # + self.switch(2) + stm_read(p3) + assert p3[8] == '\x03' + # + self.switch(1) + stm_read(p9) + assert p9[8] == '\t' + # + self.switch(1) + stm_read(p8) + assert p8[8] == '\x08' + stm_write(p8) + p8[8] = 'g' + # + self.switch(1) + stm_read(p8) + assert p8[8] == 'g' + # + self.switch(2) + stm_read(p5) + assert p5[8] == '\xfa' + stm_write(p5) + p5[8] = '\x86' + # + self.switch(2) + stm_read(p6) + assert p6[8] == '\x06' + # + self.switch(1) + stm_read(p4) + assert p4[8] == '\xb2' + stm_write(p4) + p4[8] = '\xce' + # + self.switch(2) + stm_read(p2) + assert p2[8] == 'T' + stm_write(p2) + p2[8] = 'Q' + # + self.switch(1) + stm_stop_transaction(True) #8 + # conflict: 0xdf0a8028 + # + self.switch(2) + stm_stop_transaction(False) #9 + # ['\x00', '*', 'Q', '\x03', '\x0c', '\x86', '\x06', '\x07', '\x08', '\t'] + # log: [2, 5] + # + self.switch(0) + stm_read(p0) + assert p0[8] == '\x00' + # + self.switch(1) + stm_start_transaction() + stm_read(p3) + assert p3[8] == '\x03' + # + self.switch(1) + stm_read(p5) + assert p5[8] == '\x86' + # + self.switch(2) + stm_start_transaction() + stm_read(p4) + assert p4[8] == '\x0c' + stm_write(p4) + p4[8] = '{' + # + self.switch(1) + stm_read(p2) + assert p2[8] == 'Q' + # + self.switch(2) + stm_read(p3) + assert p3[8] == '\x03' + stm_write(p3) + p3[8] = 'V' + # + self.switch(1) + stm_stop_transaction(False) #10 + # ['\x00', '*', 'Q', '\x03', '\x0c', '\x86', '\x06', '\x07', '\x08', '\t'] + # log: [] + # + self.switch(1) + stm_start_transaction() + stm_read(p7) + assert p7[8] == '\x07' + # + self.switch(2) + stm_read(p0) + assert p0[8] == '\x00' + stm_write(p0) + p0[8] = 'P' + # + self.switch(0) + stm_stop_transaction(False) #11 diff --git a/c7/test/test_largemalloc.py b/c7/test/test_largemalloc.py new file mode 100644 --- /dev/null +++ b/c7/test/test_largemalloc.py @@ -0,0 +1,114 @@ +from support import * +import sys, random + + +class TestLargeMalloc(object): + + def setup_method(self, meth): + size = 1024 * 1024 # 1MB + self.rawmem = ffi.new("char[]", size) + self.size = size + lib.memset(self.rawmem, 0xcd, size) + lib.stm_largemalloc_init(self.rawmem, size) + + def test_simple(self): + d1 = lib.stm_large_malloc(7000) + d2 = lib.stm_large_malloc(8000) + assert d2 - d1 == 7016 + d3 = lib.stm_large_malloc(9000) + assert d3 - d2 == 8016 + # + lib.stm_large_free(d1) + lib.stm_large_free(d2) + # + d4 = lib.stm_large_malloc(600) + assert d4 == d1 + d5 = lib.stm_large_malloc(600) + assert d5 == d4 + 616 + # + lib.stm_large_free(d5) + # + d6 = lib.stm_large_malloc(600) + assert d6 == d5 + # + lib.stm_large_free(d4) + # + d7 = lib.stm_large_malloc(608) + assert d7 == d6 + 616 + d8 = lib.stm_large_malloc(600) + assert d8 == d4 + # + lib._stm_large_dump() + + def test_overflow_1(self): + d = lib.stm_large_malloc(self.size - 32) + assert d == self.rawmem + 16 + lib._stm_large_dump() + + def test_overflow_2(self): + d = lib.stm_large_malloc(self.size - 16) + assert d == ffi.NULL + lib._stm_large_dump() + + def test_overflow_3(self): + d = lib.stm_large_malloc(sys.maxint & ~7) + assert d == ffi.NULL + lib._stm_large_dump() + + def test_resize_arena_reduce_1(self): + r = lib.stm_largemalloc_resize_arena(self.size - 32) + assert r == 1 + d = lib.stm_large_malloc(self.size - 32) + assert d == ffi.NULL + lib._stm_large_dump() + + def test_resize_arena_reduce_2(self): + lib.stm_large_malloc(self.size // 2 - 64) + r = lib.stm_largemalloc_resize_arena(self.size // 2) + assert r == 1 + lib._stm_large_dump() + + def test_resize_arena_reduce_3(self): + d1 = lib.stm_large_malloc(128) + r = lib.stm_largemalloc_resize_arena(self.size // 2) + assert r == 1 + d2 = lib.stm_large_malloc(128) + assert d1 == self.rawmem + 16 + assert d2 == d1 + 128 + 16 + lib._stm_large_dump() + + def test_resize_arena_cannot_reduce_1(self): + lib.stm_large_malloc(self.size // 2) + r = lib.stm_largemalloc_resize_arena(self.size // 2) + assert r == 0 + lib._stm_large_dump() + + def test_resize_arena_cannot_reduce_2(self): + lib.stm_large_malloc(self.size // 2 - 56) + r = lib.stm_largemalloc_resize_arena(self.size // 2) + assert r == 0 + lib._stm_large_dump() + + def test_random(self): + r = random.Random(1007) + p = [] + for i in range(100000): + if len(p) != 0 and (len(p) > 100 or r.randrange(0, 5) < 2): + index = r.randrange(0, len(p)) + d, length, content1, content2 = p.pop(index) + print ' free %5d (%s)' % (length, d) + assert d[0] == content1 + assert d[length - 1] == content2 + lib.stm_large_free(d) + else: + sz = r.randrange(8, 160) * 8 + d = lib.stm_large_malloc(sz) + print 'alloc %5d (%s)' % (sz, d) + assert d != ffi.NULL + lib.memset(d, 0xdd, sz) + content1 = chr(r.randrange(0, 256)) + content2 = chr(r.randrange(0, 256)) + d[0] = content1 + d[sz - 1] = content2 + p.append((d, sz, content1, content2)) + lib._stm_large_dump() diff --git a/c7/test/test_random.py b/c7/test/test_random.py new file mode 100644 --- /dev/null +++ b/c7/test/test_random.py @@ -0,0 +1,85 @@ +from support import * +import sys, random + + +class TestRandom(BaseTest): + + def test_fixed_16_bytes_objects(self): + rnd = random.Random(1010) + + N_OBJECTS = 10 + N_THREADS = 3 + print >> sys.stderr, 'stm_start_transaction()' + stm_start_transaction() + plist = [stm_allocate(16) for i in range(N_OBJECTS)] + read_sets = [{} for i in range(N_THREADS)] + write_sets = [{} for i in range(N_THREADS)] + active_transactions = {} + + for i in range(N_OBJECTS): + print >> sys.stderr, 'p%d = stm_allocate(16)' % i + for i in range(N_OBJECTS): + print >> sys.stderr, 'p%d[8] = %r' % (i, chr(i)) + plist[i][8] = chr(i) + head_state = [[chr(i) for i in range(N_OBJECTS)]] + commit_log = [] + print >> sys.stderr, 'stm_stop_transaction(False)' + stm_stop_transaction(False) + + for i in range(N_THREADS): + print >> sys.stderr, 'self.switch(%d)' % i + self.switch(i) + stop_count = 1 + + for i in range(10000): + n_thread = rnd.randrange(0, N_THREADS) + print >> sys.stderr, '#\nself.switch(%d)' % n_thread + self.switch(n_thread) + if n_thread not in active_transactions: + print >> sys.stderr, 'stm_start_transaction()' + stm_start_transaction() + active_transactions[n_thread] = len(commit_log) + + action = rnd.randrange(0, 7) + if action < 6: + is_write = action >= 4 + i = rnd.randrange(0, N_OBJECTS) + print >> sys.stderr, "stm_read(p%d)" % i + stm_read(plist[i]) + got = plist[i][8] + print >> sys.stderr, "assert p%d[8] ==" % i, + my_head_state = head_state[active_transactions[n_thread]] + prev = read_sets[n_thread].setdefault(i, my_head_state[i]) + print >> sys.stderr, "%r" % (prev,) + assert got == prev + # + if is_write: + print >> sys.stderr, 'stm_write(p%d)' % i + stm_write(plist[i]) + newval = chr(rnd.randrange(0, 256)) + print >> sys.stderr, 'p%d[8] = %r' % (i, newval) + plist[i][8] = newval + read_sets[n_thread][i] = write_sets[n_thread][i] = newval + else: + src_index = active_transactions.pop(n_thread) + conflict = False + for i in range(src_index, len(commit_log)): + for j in commit_log[i]: + if j in read_sets[n_thread]: + conflict = True + print >> sys.stderr, "stm_stop_transaction(%r) #%d" % ( + conflict, stop_count) + stop_count += 1 + stm_stop_transaction(conflict) + # + if not conflict: + hs = head_state[-1][:] + for i, newval in write_sets[n_thread].items(): + hs[i] = newval + assert plist[i][8] == newval + head_state.append(hs) + commit_log.append(write_sets[n_thread].keys()) + print >> sys.stderr, '#', head_state[-1] + print >> sys.stderr, '# log:', commit_log[-1] + write_sets[n_thread].clear() + read_sets[n_thread].clear() _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit