Author: Remi Meier <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit