[pypy-commit] pypy gc-incminimark-pinning: reworked comments in incminimark
groggi
noreply at buildbot.pypy.org
Tue Aug 19 21:15:55 CEST 2014
Author: Gregor Wegberg <code at gregorwegberg.com>
Branch: gc-incminimark-pinning
Changeset: r72914:93b928f5cf40
Date: 2014-08-19 21:04 +0200
http://bitbucket.org/pypy/pypy/changeset/93b928f5cf40/
Log: reworked comments in incminimark
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
@@ -71,15 +71,15 @@
# * young objects: allocated in the nursery if they are not too large, or
# raw-malloced otherwise. The nursery is a fixed-size memory buffer of
# 4MB by default. When full, we do a minor collection;
-# the surviving objects from the nursery are moved outside, and the
-# non-surviving raw-malloced objects are freed. All surviving objects
-# become old.
+# - surviving objects from the nursery are moved outside and become old,
+# - non-surviving raw-malloced objects are freed,
+# - and pinned objects are kept at their place inside the nursery and stay
+# young.
#
# * old objects: never move again. These objects are either allocated by
# minimarkpage.py (if they are small), or raw-malloced (if they are not
# small). Collected by regular mark-n-sweep during major collections.
#
-# XXX update doc string to contain object pinning (groggi)
WORD = LONG_BIT // 8
@@ -132,8 +132,8 @@
# a minor collection.
GCFLAG_VISITED_RMY = first_gcflag << 8
-# The following flag is set on nursery objects of which we expect not to
-# move. This means that a young object with this flag is not moved out
+# The following flag is set on nursery objects to keep them in the nursery.
+# This means that a young object with this flag is not moved out
# of the nursery during a minor collection. See pin()/unpin() for further
# details.
GCFLAG_PINNED = first_gcflag << 9
@@ -264,7 +264,7 @@
# nursery. Has to fit at least one large object
"nursery_cleanup": 32768 * WORD,
- # Number of objects that are allowed to be pinned in the nursery
+ # Number of objects that are allowed to be pinned in the nursery
# at the same time. Must be lesser than or equal to the chunk size
# of an AddressStack.
"max_number_of_pinned_objects": 100,
@@ -379,21 +379,19 @@
# minor collection.
self.nursery_objects_shadows = self.AddressDict()
#
- # A sorted deque containing all pinned objects *before* the last
- # minor collection. This deque must be consulted when considering
- # next nursery ceiling.
+ # A sorted deque containing addresses of pinned objects.
+ # This collection is used to make sure we don't overwrite pinned objects.
+ # Each minor collection creates a new deque containing the active pinned
+ # objects. The addresses are used to set the next 'nursery_top'.
self.nursery_barriers = self.AddressDeque()
#
# Counter tracking how many pinned objects currently reside inside
# the nursery.
self.pinned_objects_in_nursery = 0
#
- # Keeps track of objects pointing to pinned objects. These objects
- # must be revisited every minor collection. Without this list
- # any old object inside this list would only be visited in case a
- # write barrier was triggered, which would result in not visiting
- # the young pinned object and would therefore result in removing
- # the pinned object.
+ # Keeps track of old objects pointing to pinned objects. These objects
+ # must be traced every minor collection. Without tracing them the
+ # referenced pinned object wouldn't be visited and therefore collected.
self.old_objects_pointing_to_pinned = self.AddressStack()
#
# Allocate a nursery. In case of auto_nursery_size, start by
@@ -708,8 +706,9 @@
is needed."""
# in general we always move 'self.nursery_top' by 'self.nursery_cleanup'.
- # However, because of the presence of pinned objects there are cases where
- # the GC can't move by 'self.nursery_cleanup' without overflowing the arena.
+ # However, because of the presence of pinned objects there are cases
+ # where the GC can't move by 'self.nursery_cleanup' without overflowing
+ # the arena.
# For such a case we use the space left in the nursery.
size = min(self.nursery_cleanup, self.nursery_real_top - self.nursery_top)
if llmemory.raw_malloc_usage(totalsize) > size:
@@ -749,14 +748,14 @@
self.nursery_free = self.nursery_top + pinned_obj_size
self.nursery_top = self.nursery_barriers.popleft()
#
- # because we encountered a barrier, we also have to fix
- # 'prev_result' as the one provided as a method parameter
- # can't be used as there is no space between 'prev_result'
- # and the barrier for 'totalsize'.
+ # because we encountered a barrier, we have to fix 'prev_result'.
+ # The one provided as parameter can't be used further as there
+ # is not enough space between 'prev_result' and and the barrier
+ # for an object of 'totalsize' size.
prev_result = self.nursery_free
else:
#
- # no barriers (i.e. pinned objects) after 'nursery_free'.
+ # no barriers (i.e. no pinned objects) after 'nursery_free'.
# If possible just enlarge the used part of the nursery.
# Otherwise we are forced to clean up the nursery.
if self.try_move_nursery_top(totalsize):
@@ -783,8 +782,8 @@
#
if self.nursery_free + totalsize > self.nursery_real_top:
# still not enough space, we need to collect.
- # maybe nursery contains too many pinned objects (see
- # assert below).
+ # maybe nursery contains too many pinned objects
+ # (see assert below).
self.minor_collection()
else:
# execute loop one more time. This should find
@@ -803,7 +802,6 @@
break
#
if self.debug_tiny_nursery >= 0: # for debugging
- # XXX solution for this assert? (groggi)
ll_assert(not self.nursery_barriers.non_empty(),
"no support for nursery debug and pinning")
if self.nursery_top - self.nursery_free > self.debug_tiny_nursery:
@@ -983,19 +981,18 @@
if self.pinned_objects_in_nursery >= self.max_number_of_pinned_objects:
return False
if not self.is_in_nursery(obj):
- # Old objects are already non-moving, therefore pinning
+ # old objects are already non-moving, therefore pinning
# makes no sense. If you run into this case, you may forgot
- # to check if can_move(obj) already returns True in which
- # case a call to pin() is unnecessary.
+ # to check can_move(obj).
return False
if self.has_gcptr(self.get_type_id(obj)):
# objects containing GC pointers can't be pinned. If we would add
# it, we would have to track all pinned objects and trace them
# every minor collection to make sure the referenced object are
- # kept alive.
+ # kept alive. Right now this is not a use case that's needed.
return False
if self._is_pinned(obj):
- # Already pinned, we do not allow to pin it again.
+ # already pinned, we do not allow to pin it again.
# Reason: It would be possible that the first caller unpins
# while the second caller thinks it's still pinned.
return False
@@ -1193,9 +1190,6 @@
else:
ll_assert(self.is_in_nursery(obj),
"pinned object not in nursery")
- # XXX check if we can support that or if it makes no sense (groggi)
- ll_assert(not self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS,
- "pinned nursery object with GCFLAG_TRACK_YOUNG_PTRS")
if self.gc_state == STATE_SCANNING:
self._debug_check_object_scanning(obj)
@@ -1544,9 +1538,9 @@
# where this stack is filled. Pinning an object only prevents it from
# being moved, not from being collected if it is not reachable anymore.
self.surviving_pinned_objects = self.AddressStack()
- #
- # The following counter keeps track of the amount of alive and pinned
- # objects inside the nursery.
+ # The following counter keeps track of alive and pinned young objects
+ # inside the nursery. We reset it here and increace it in
+ # '_trace_drag_out()'.
self.pinned_objects_in_nursery = 0
#
# Before everything else, remove from 'old_objects_pointing_to_young'
@@ -1578,14 +1572,12 @@
# with pinned object that are (only) visible from an old
# object.
# Additionally we create a new list as it may be that an old object
- # no longer points to a pinned one and we want them to remove from
- # the list.
+ # no longer points to a pinned one. Such old objects won't be added
+ # again to 'old_objects_pointing_to_pinned'.
if self.old_objects_pointing_to_pinned.non_empty():
current_old_objects_pointing_to_pinned = \
self.old_objects_pointing_to_pinned
- #
self.old_objects_pointing_to_pinned = self.AddressStack()
- # visit the ones we know of
current_old_objects_pointing_to_pinned.foreach(
self._visit_old_objects_pointing_to_pinned, None)
current_old_objects_pointing_to_pinned.delete()
@@ -1639,7 +1631,7 @@
self.free_young_rawmalloced_objects()
#
# All live nursery objects are out of the nursery or pinned inside
- # the nursery. Create nursery barriers to protect the pinned object,
+ # the nursery. Create nursery barriers to protect the pinned objects,
# fill the rest of the nursery with zeros and reset the current nursery
# pointer.
size_gc_header = self.gcheaderbuilder.size_gc_header
@@ -1673,10 +1665,11 @@
llarena.arena_reset(prev, self.nursery_real_top - prev, 0)
#
# We assume that there are only a few pinned objects. Therefore, if there
- # is 'self.nursery_cleanup' space between the nursery's start ('self.nursery')
- # and the last pinned object ('prev'), we conclude that there is enough zeroed
- # space inside the arena to use for new allocation. Otherwise we fill
- # the nursery with zeros for 'self.nursery_cleanup' of space.
+ # is 'self.nursery_cleanup' space between the nursery's start
+ # ('self.nursery') and the last pinned object ('prev'), we conclude that
+ # there is enough zeroed space inside the arena to use for new
+ # allocation. Otherwise we fill the nursery with zeros for
+ # 'self.nursery_cleanup' of space.
if prev - self.nursery >= self.nursery_cleanup:
nursery_barriers.append(prev)
else:
@@ -1884,21 +1877,25 @@
#
elif self._is_pinned(obj):
hdr = self.header(obj)
- # track parent of pinned object specially
+ #
+ # track parent of pinned object specially. This mus be done before
+ # checking for GCFLAG_VISITED: it may be that the same pinned object
+ # is reachable from multiple sources (e.g. two old objects pointing
+ # to the same pinned object). In such a case we need all parents
+ # of the pinned object in the list. Otherwise he pinned object could
+ # become dead and be removed just because the first parent of it
+ # is dead and collected.
if parent != llmemory.NULL and \
not self.header(parent).tid & GCFLAG_PINNED_OBJECT_PARENT_KNOWN:
#
self.old_objects_pointing_to_pinned.append(parent)
self.header(parent).tid |= GCFLAG_PINNED
-
+ #
if hdr.tid & GCFLAG_VISITED:
- # already visited and keeping track of the object
return
+ #
hdr.tid |= GCFLAG_VISITED
#
- # XXX add additional checks for unsupported pinned objects (groggi)
- ll_assert(not self.header(obj).tid & GCFLAG_HAS_CARDS,
- "pinned object with GCFLAG_HAS_CARDS not supported")
self.surviving_pinned_objects.append(
llarena.getfakearenaaddress(obj - size_gc_header))
self.pinned_objects_in_nursery += 1
@@ -2124,7 +2121,7 @@
# Light finalizers
if self.old_objects_with_light_finalizers.non_empty():
self.deal_with_old_objects_with_finalizers()
- #objects_to_trace processed fully, can move on to sweeping
+ # objects_to_trace processed fully, can move on to sweeping
self.ac.mass_free_prepare()
self.start_free_rawmalloc_objects()
#
@@ -2136,7 +2133,8 @@
self._sweep_old_objects_pointing_to_pinned,
new_old_objects_pointing_to_pinned)
self.old_objects_pointing_to_pinned.delete()
- self.old_objects_pointing_to_pinned = new_old_objects_pointing_to_pinned
+ self.old_objects_pointing_to_pinned = \
+ new_old_objects_pointing_to_pinned
self.gc_state = STATE_SWEEPING
#END MARKING
elif self.gc_state == STATE_SWEEPING:
@@ -2333,9 +2331,10 @@
# flag set, then the object should be in 'prebuilt_root_objects',
# and the GCFLAG_VISITED will be reset at the end of the
# collection.
+ # Objects with GCFLAG_PINNED can't have gcptrs (see pin()), they can be
+ # ignored.
hdr = self.header(obj)
if hdr.tid & (GCFLAG_VISITED | GCFLAG_NO_HEAP_PTRS | GCFLAG_PINNED):
- # XXX ^^^ update doc in any way because of GCFLAG_PINNED addition? (groggi)
return 0
#
# It's the first time. We set the flag VISITED. The trick is
More information about the pypy-commit
mailing list