Author: Armin Rigo <ar...@tunes.org> Branch: incremental-gc Changeset: r67189:d108922be83a Date: 2013-10-08 09:38 +0200 http://bitbucket.org/pypy/pypy/changeset/d108922be83a/
Log: in-progress diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py --- a/rpython/memory/gc/incminimark.py +++ b/rpython/memory/gc/incminimark.py @@ -325,8 +325,6 @@ ArenaCollectionClass = minimarkpage.ArenaCollection self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) - self.ac_alternate = ArenaCollectionClass(arena_size, page_size, - small_request_threshold) # # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by @@ -1015,8 +1013,7 @@ """Return the total memory used, not counting any object in the nursery: only objects in the ArenaCollection or raw-malloced. """ - return self.ac.total_memory_used + self.ac_alternate.total_memory_used \ - + self.rawmalloced_total_size + return self.ac.total_memory_used + self.rawmalloced_total_size def card_marking_words_for_length(self, length): @@ -1689,11 +1686,6 @@ # Copy it. Note that references to other objects in the # nursery are kept unchanged in this step. llmemory.raw_memcopy(obj - size_gc_header, newhdr, totalsize) - # if the current state is sweeping or later, - # then all new objects surviving - # minor collection should be marked as visited - if self.gc_state >= STATE_SWEEPING_RAWMALLOC: - self.header(newhdr + size_gc_header).tid |= GCFLAG_VISITED # # Set the old object's tid to -42 (containing all flags) and # replace the old object's content with the target address. @@ -1718,8 +1710,10 @@ if self.has_gcptr(typeid): # we only have to do it if we have any gcptrs self.old_objects_pointing_to_young.append(newobj) - - + # + # If we are in STATE_MARKING, then the new object must be made gray. + if self.gc_state == STATE_MARKING: + self.write_to_visited_object_backward(newobj) _trace_drag_out._always_inline_ = True @@ -1838,7 +1832,7 @@ debug_print("number of objects to mark", self.objects_to_trace.length()) - estimate = 2000 + estimate = self.nursery_size # XXX self.visit_all_objects_step(estimate) # XXX A simplifying assumption that should be checked, @@ -1860,6 +1854,7 @@ #objects_to_trace processed fully, can move on to sweeping self.gc_state = STATE_SWEEPING_RAWMALLOC #prepare for the next state + self.ac.mass_free_prepare() self.start_free_rawmalloc_objects() #END MARKING elif self.gc_state == STATE_SWEEPING_RAWMALLOC: @@ -1876,40 +1871,42 @@ # 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) - self.num_major_collects += 1 - # - # We also need to reset the GCFLAG_VISITED on prebuilt GC objects. - self.prebuilt_root_objects.foreach(self._reset_gcflag_visited, None) - # - # Set the threshold for the next major collection to be when we - # have allocated 'major_collection_threshold' times more than - # we currently have -- but no more than 'max_delta' more than - # we currently have. - total_memory_used = float(self.get_total_memory_used()) - bounded = self.set_major_threshold_from( - min(total_memory_used * self.major_collection_threshold, - total_memory_used + self.max_delta), - reserving_size) - # - # Max heap size: gives an upper bound on the threshold. If we - # already have at least this much allocated, raise MemoryError. - if bounded and (float(self.get_total_memory_used()) + reserving_size >= - self.next_major_collection_initial): + max_pages = 3 * (self.nursery_size // self.ac.page_size) # XXX + if self.ac.mass_free_incremental(self._free_if_unvisited, + max_pages): + self.num_major_collects += 1 # - # First raise MemoryError, giving the program a chance to - # quit cleanly. It might still allocate in the nursery, - # which might eventually be emptied, triggering another - # major collect and (possibly) reaching here again with an - # even higher memory consumption. To prevent it, if it's - # the second time we are here, then abort the program. - if self.max_heap_size_already_raised: - llop.debug_fatalerror(lltype.Void, - "Using too much memory, aborting") - self.max_heap_size_already_raised = True - raise MemoryError + # We also need to reset the GCFLAG_VISITED on prebuilt GC objects. + self.prebuilt_root_objects.foreach(self._reset_gcflag_visited, None) + # + # Set the threshold for the next major collection to be when we + # have allocated 'major_collection_threshold' times more than + # we currently have -- but no more than 'max_delta' more than + # we currently have. + total_memory_used = float(self.get_total_memory_used()) + bounded = self.set_major_threshold_from( + min(total_memory_used * self.major_collection_threshold, + total_memory_used + self.max_delta), + reserving_size) + # + # Max heap size: gives an upper bound on the threshold. If we + # already have at least this much allocated, raise MemoryError. + if bounded and (float(self.get_total_memory_used()) + reserving_size >= + self.next_major_collection_initial): + # + # First raise MemoryError, giving the program a chance to + # quit cleanly. It might still allocate in the nursery, + # which might eventually be emptied, triggering another + # major collect and (possibly) reaching here again with an + # even higher memory consumption. To prevent it, if it's + # the second time we are here, then abort the program. + if self.max_heap_size_already_raised: + llop.debug_fatalerror(lltype.Void, + "Using too much memory, aborting") + self.max_heap_size_already_raised = True + raise MemoryError - self.gc_state = STATE_FINALIZING + self.gc_state = STATE_FINALIZING # FINALIZING not yet incrementalised # but it seems safe to allow mutator to run after sweeping and # before finalizers are called. This is because run_finalizers @@ -1995,6 +1992,7 @@ while nobjects > 0 and self.raw_malloc_might_sweep.non_empty(): self.free_rawmalloced_object_if_unvisited( self.raw_malloc_might_sweep.pop()) + nobjects -= 1 if not self.raw_malloc_might_sweep.non_empty(): self.raw_malloc_might_sweep.delete() diff --git a/rpython/memory/gc/minimarkpage.py b/rpython/memory/gc/minimarkpage.py --- a/rpython/memory/gc/minimarkpage.py +++ b/rpython/memory/gc/minimarkpage.py @@ -280,7 +280,7 @@ # # Maybe we are incrementally collecting, in which case an arena # could have more free pages thrown into it than arenas_lists[] - # account for. Rehash and retry. + # accounts for. Rehash and retry. self._rehash_arenas_lists() if self._pick_next_arena(): return diff --git a/rpython/memory/gc/minimarktest.py b/rpython/memory/gc/minimarktest.py --- a/rpython/memory/gc/minimarktest.py +++ b/rpython/memory/gc/minimarktest.py @@ -1,3 +1,4 @@ +import sys from rpython.rtyper.lltypesystem import llarena from rpython.rtyper.lltypesystem.llmemory import raw_malloc_usage from rpython.rlib.debug import ll_assert @@ -32,13 +33,26 @@ self.total_memory_used += nsize return result - def mass_free(self, ok_to_free_func): - objs = self.all_objects + def mass_free_prepare(self): + self.old_all_objects = self.all_objects self.all_objects = [] self.total_memory_used = 0 - for rawobj, nsize in objs: + + def mass_free_incremental(self, ok_to_free_func, max_pages): + old = self.old_all_objects + while old: + rawobj, nsize = old.pop() if ok_to_free_func(rawobj): llarena.arena_free(rawobj) else: self.all_objects.append((rawobj, nsize)) self.total_memory_used += nsize + max_pages -= 0.1 + if max_pages <= 0: + return False + return True + + def mass_free(self, ok_to_free_func): + self.mass_free_prepare() + res = self.mass_free_incremental(ok_to_free_func, sys.maxint) + assert res _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit