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

Reply via email to