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