[pypy-commit] pypy stm-gc: Random progress.
arigo
noreply at buildbot.pypy.org
Fri Apr 13 19:06:12 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: stm-gc
Changeset: r54341:e1e05308a3c9
Date: 2012-04-13 19:05 +0200
http://bitbucket.org/pypy/pypy/changeset/e1e05308a3c9/
Log: Random progress.
diff --git a/pypy/rpython/memory/gc/stmgc.py b/pypy/rpython/memory/gc/stmgc.py
--- a/pypy/rpython/memory/gc/stmgc.py
+++ b/pypy/rpython/memory/gc/stmgc.py
@@ -43,6 +43,7 @@
GCFLAG_HAS_SHADOW = first_gcflag << 2
GCFLAG_FIXED_HASH = first_gcflag << 3
GCFLAG_WEAKREF = first_gcflag << 4
+GCFLAG_VISITED = first_gcflag << 5
def always_inline(fn):
@@ -70,18 +71,18 @@
'stm_operations': 'use_real_one',
'nursery_size': 32*1024*1024, # 32 MB
- "page_size": 1024*WORD, # copied from minimark.py
- "arena_size": 65536*WORD, # copied from minimark.py
- "small_request_threshold": 35*WORD, # copied from minimark.py
+ #"page_size": 1024*WORD, # copied from minimark.py
+ #"arena_size": 65536*WORD, # copied from minimark.py
+ #"small_request_threshold": 35*WORD, # copied from minimark.py
}
def __init__(self, config,
stm_operations='use_emulator',
nursery_size=1024,
- page_size=16*WORD,
- arena_size=64*WORD,
- small_request_threshold=5*WORD,
- ArenaCollectionClass=None,
+ #page_size=16*WORD,
+ #arena_size=64*WORD,
+ #small_request_threshold=5*WORD,
+ #ArenaCollectionClass=None,
**kwds):
MovingGCBase.__init__(self, config, **kwds)
#
@@ -95,9 +96,7 @@
from pypy.rpython.memory.gc import stmshared
self.stm_operations = stm_operations
self.nursery_size = nursery_size
- self.sharedarea = stmshared.StmGCSharedArea(self, ArenaCollectionClass,
- page_size, arena_size,
- small_request_threshold)
+ self.sharedarea = stmshared.StmGCSharedArea(self)
#
def _get_size(obj): # indirection to hide 'self'
return self.get_size(obj)
diff --git a/pypy/rpython/memory/gc/stmshared.py b/pypy/rpython/memory/gc/stmshared.py
--- a/pypy/rpython/memory/gc/stmshared.py
+++ b/pypy/rpython/memory/gc/stmshared.py
@@ -1,18 +1,58 @@
+from pypy.rpython.lltypesystem import lltype, llmemory, llarena
+from pypy.rlib.objectmodel import free_non_gc_object
+
+NULL = llmemory.NULL
class StmGCSharedArea(object):
+ _alloc_flavor_ = 'raw'
- def __init__(self, gc, ArenaCollectionClass,
- page_size, arena_size, small_request_threshold):
+ def __init__(self, gc):
self.gc = gc
- # The ArenaCollection() handles the nonmovable objects allocation.
- # It contains all small GCFLAG_GLOBAL objects. The non-small ones
- # are directly malloc'ed.
- if ArenaCollectionClass is None:
- from pypy.rpython.memory.gc import minimarkpage
- ArenaCollectionClass = minimarkpage.ArenaCollection
- self.ac = ArenaCollectionClass(arena_size, page_size,
- small_request_threshold)
def setup(self):
pass
+
+
+class StmGCThreadLocalAllocator(object):
+ """A thread-local allocator for the shared area.
+ This is an optimization only: it lets us use thread-local variables
+ to keep track of what we allocated.
+ """
+ _alloc_flavor_ = 'raw'
+
+ def __init__(self, sharedarea):
+ self.gc = sharedarea.gc
+ self.sharedarea = sharedarea
+ self.chained_list = NULL
+ self.special_stack = self.gc.AddressStack()
+
+ def delete(self):
+ self.special_stack.delete()
+ free_non_gc_object(self)
+
+ def malloc_regular(self, size):
+ """Malloc for an object where the 'version' field can be used
+ internally for a chained list."""
+ adr1 = llarena.arena_malloc(size, 0)
+ adr2 = adr1 + self.gc.gcheaderbuilder
+ hdr = llmemory.cast_adr_to_ptr(adr1, lltype.Ptr(self.gc.HDR))
+ hdr.version = self.chained_list
+ self.chained_list = adr2
+ return adr2
+
+ def malloc_special(self, size):
+ """Malloc for an object where the 'version' field cannot be
+ used internally. It's the rare case here."""
+ adr1 = llarena.arena_malloc(size, 0)
+ adr2 = adr1 + self.gc.gcheaderbuilder.size_gc_header
+ self.special_stack.append(adr2)
+ return adr2
+
+ def free_object(self, adr2):
+ adr1 = adr2 - self.gc.gcheaderbuilder.size_gc_header
+ llarena.arena_free(adr1)
+
+ def replace_special_stack(self, new_special_stack):
+ self.special_stack.delete()
+ self.special_stack = new_special_stack
diff --git a/pypy/rpython/memory/gc/stmtls.py b/pypy/rpython/memory/gc/stmtls.py
--- a/pypy/rpython/memory/gc/stmtls.py
+++ b/pypy/rpython/memory/gc/stmtls.py
@@ -7,7 +7,7 @@
from pypy.rpython.memory.gc.stmgc import WORD, NULL
from pypy.rpython.memory.gc.stmgc import always_inline, dont_inline
-from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL
+from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL, GCFLAG_VISITED
class StmGCTLS(object):
@@ -19,6 +19,7 @@
nontranslated_dict = {}
def __init__(self, gc, in_main_thread):
+ from pypy.rpython.memory.gc.stmshared import StmGCThreadLocalAllocator
self.gc = gc
self.in_main_thread = in_main_thread
self.stm_operations = self.gc.stm_operations
@@ -37,13 +38,16 @@
self.nursery_start = self._alloc_nursery(self.nursery_size)
#
# --- the local raw-malloced objects (chained list via hdr.version)
- self.rawmalloced_objects = NULL
+ #self.rawmalloced_objects = NULL
# --- the local "normal" old objects (chained list via hdr.version)
self.old_objects = NULL
# --- the local objects with weakrefs (chained list via hdr.version)
#self.young_objects_with_weakrefs = NULL
#self.old_objects_with_weakrefs = NULL
#
+ # --- a thread-local allocator for the shared area
+ self.sharedarea_tls = StmGCThreadLocalAllocator(gc.sharedarea)
+ #
self._register_with_C_code()
def teardown_thread(self):
@@ -137,70 +141,52 @@
# ------------------------------------------------------------
def local_collection(self, run_finalizers=True):
- """Do a local collection. Finds all surviving young objects
- and make them old. Also looks for roots from the stack.
- The flag GCFLAG_WAS_COPIED is kept and the C tree is updated
- if the local young object moves.
+ """Do a local collection. This should be equivalent to a minor
+ collection only, but the GC is not generational so far, so it is
+ for now the same as a full collection --- but only on LOCAL
+ objects, not touching the GLOBAL objects. More precisely, this
+ finds all YOUNG LOCAL objects, move them out of the nursery if
+ necessary, and make them OLD LOCAL objects. This starts from
+ the roots from the stack. The flag GCFLAG_WAS_COPIED is kept
+ and the C tree is updated if the local young objects move.
"""
#
debug_start("gc-local")
#
- # First, find the roots that point to young objects. All nursery
- # objects found are copied out of the nursery, and the occasional
- # young raw-malloced object is flagged with GCFLAG_VISITED.
- # Note that during this step, we ignore references to further
- # young objects; only objects directly referenced by roots
- # are copied out or flagged. They are also added to the list
- # 'old_objects_pointing_to_young'.
+ # Linked list of LOCAL objects pending a visit. Note that no
+ # GLOBAL object can at any point contain a reference to a LOCAL
+ # object.
+ self.pending_list = NULL
+ #
+ # First, find the roots that point to LOCAL objects. All YOUNG
+ # (i.e. nursery) objects found are copied out of the nursery.
+ # All OLD objects found are flagged with GCFLAG_VISITED. At this
+ # point, the content of the objects is not modified; the objects
+ # are merely added to the chained list 'pending_list'.
self.collect_roots_in_nursery()
#
- while True:
- # If we are using card marking, do a partial trace of the arrays
- # that are flagged with GCFLAG_CARDS_SET.
- if self.card_page_indices > 0:
- self.collect_cardrefs_to_nursery()
- #
- # Now trace objects from 'old_objects_pointing_to_young'.
- # All nursery objects they reference are copied out of the
- # nursery, and again added to 'old_objects_pointing_to_young'.
- # All young raw-malloced object found are flagged GCFLAG_VISITED.
- # We proceed until 'old_objects_pointing_to_young' is empty.
- self.collect_oldrefs_to_nursery()
- #
- # We have to loop back if collect_oldrefs_to_nursery caused
- # new objects to show up in old_objects_with_cards_set
- if self.card_page_indices > 0:
- if self.old_objects_with_cards_set.non_empty():
- continue
- break
+ # Also find the roots that are the local copy of GCFLAG_WAS_COPIED
+ # objects.
+ self.collect_roots_from_tldict()
#
- # Now all live nursery objects should be out. Update the young
- # weakrefs' targets.
- if self.young_objects_with_weakrefs.non_empty():
- self.invalidate_young_weakrefs()
- if self.young_objects_with_light_finalizers.non_empty():
- self.deal_with_young_objects_with_finalizers()
+ # Now repeat following objects until 'pending_list' is empty.
+ self.collect_oldrefs_to_nursery()
#
- # Clear this mapping.
- if self.nursery_objects_shadows.length() > 0:
- self.nursery_objects_shadows.clear()
+ # Walk the list of LOCAL raw-malloced objects, and free them if
+ # necessary.
+ #self.free_local_rawmalloced_objects()
#
- # Walk the list of young raw-malloced objects, and either free
- # them or make them old.
- if self.young_rawmalloced_objects:
- self.free_young_rawmalloced_objects()
+ # Ask the ArenaCollection to visit all objects. Free the ones
+ # that have not been visited above, and reset GCFLAG_VISITED on
+ # the others.
+ self.ac.mass_free(self._free_if_unvisited)
#
# All live nursery objects are out, and the rest dies. Fill
# the whole nursery with zero and reset the current nursery pointer.
llarena.arena_reset(self.nursery, self.nursery_size, 2)
- self.debug_rotate_nursery()
- self.nursery_free = self.nursery
+ self.nursery_free = self.nursery_start
#
- debug_print("minor collect, total memory used:",
- self.get_total_memory_used())
- if self.DEBUG >= 2:
- self.debug_check_consistency() # expensive!
- debug_stop("gc-minor")
+ debug_stop("gc-local")
def end_of_transaction_collection(self):
"""Do an end-of-transaction collection. Finds all surviving
@@ -229,7 +215,7 @@
def allocate_object_of_size(self, size):
if not self.nursery_free:
fatalerror("malloc in a non-main thread but outside a transaction")
- if size > self.nursery_size:
+ if size > self.nursery_size // 8 * 7:
fatalerror("object too large to ever fit in the nursery")
while True:
self.local_collection()
@@ -251,12 +237,12 @@
hdr.tid |= GCFLAG_GLOBAL
obj = hdr.version
#
- obj = self.rawmalloced_objects
- self.rawmalloced_objects = NULL
- while obj:
- hdr = self.header(obj)
- hdr.tid |= GCFLAG_GLOBAL
- obj = hdr.version
+## obj = self.rawmalloced_objects
+## self.rawmalloced_objects = NULL
+## while obj:
+## hdr = self.header(obj)
+## hdr.tid |= GCFLAG_GLOBAL
+## obj = hdr.version
def _cleanup_state(self):
if self.rawmalloced_objects:
diff --git a/pypy/rpython/memory/gc/test/test_stmtls.py b/pypy/rpython/memory/gc/test/test_stmtls.py
--- a/pypy/rpython/memory/gc/test/test_stmtls.py
+++ b/pypy/rpython/memory/gc/test/test_stmtls.py
@@ -2,18 +2,42 @@
from pypy.rpython.lltypesystem import lltype, llmemory, llarena, llgroup, rffi
from pypy.rpython.memory.gc.stmtls import StmGCTLS, WORD
from pypy.rpython.memory.gc.test.test_stmgc import StmGCTests
+from pypy.rpython.memory.support import get_address_stack, get_address_deque
S = lltype.GcStruct('S', ('a', lltype.Signed), ('b', lltype.Signed),
('c', lltype.Signed))
-class TestStmGCTLS(StmGCTests):
- current_stack = ()
+class FakeStmOperations:
+ def set_tls(self, tlsaddr, num):
+ pass
+ def del_tls(self, tlsaddr):
+ pass
+
+class FakeSharedArea:
+ pass
+
+class FakeGC:
+ from pypy.rpython.memory.support import AddressDict, null_address_dict
+ AddressStack = get_address_stack()
+ AddressDeque = get_address_deque()
+ nursery_size = 128
+ stm_operations = FakeStmOperations()
+ sharedarea = FakeSharedArea()
+
+
+class TestStmGCTLS(object):
+
+ def setup_method(self, meth):
+ self.current_stack = []
+ self.gc = FakeGC()
+ self.gc.sharedarea.gc = self.gc
+ self.gctls_main = StmGCTLS(self.gc, in_main_thread=True)
+ self.gctls_thrd = StmGCTLS(self.gc, in_main_thread=False)
+ self.gc.main_thread_tls = self.gctls_main
def stack_add(self, p):
- if self.current_stack == ():
- self.current_stack = []
self.current_stack.append(p)
def stack_pop(self):
diff --git a/pypy/translator/c/src/allocator.h b/pypy/translator/c/src/allocator.h
--- a/pypy/translator/c/src/allocator.h
+++ b/pypy/translator/c/src/allocator.h
@@ -1,3 +1,14 @@
+#if defined(RPY_STM)
+
+
+/* XXX no special malloc function, use the thread-safe system-provided one */
+#define PyObject_Malloc malloc
+#define PyObject_Realloc realloc
+#define PyObject_Free free
+
+
+#else
+
/* allocation functions prototypes */
void *PyObject_Malloc(size_t n);
@@ -29,3 +40,4 @@
#endif
#endif
+#endif
diff --git a/pypy/translator/stm/stmgcintf.py b/pypy/translator/stm/stmgcintf.py
--- a/pypy/translator/stm/stmgcintf.py
+++ b/pypy/translator/stm/stmgcintf.py
@@ -11,7 +11,8 @@
eci = ExternalCompilationInfo(
include_dirs = [cdir, cdir2],
includes = ['src_stm/et.h', 'src_stm/et.c'],
- pre_include_bits = ['#define PYPY_LONG_BIT %d' % LONG_BIT],
+ pre_include_bits = ['#define PYPY_LONG_BIT %d' % LONG_BIT,
+ '#define RPY_STM 1'],
separate_module_sources = ['\n'], # hack for test_rffi_stm
)
More information about the pypy-commit
mailing list