Post by Patrick R. Michaud..when we're allocating a new PMC, how can we know in advance
that it will end up being a child of a methuselah PMC? Or do we
not need to know this (if we don't need to know it, how does
the requirement get met)?
They would have to be purely internal and only used when we can
guarantee parents and children are from the same pool.
It's a compromise solution, and like most compromises involves...
compromises. But, it's worth exploring some partial solutions if they
might help you before 2.0.
Post by Patrick R. MichaudPmichaud is hinting at my primary concern.
Intergenerational pointer invariants should not be enforced manually.
Constant PMCS are a headache. We have had lots of "GC bugs" because
developers hung non-constant objects off of a constant pmc.
Agreed, and would eventually like to get rid of them.
Post by Patrick R. Michaud1. You can't separate objects into separate generations unless you can
track intergenerational pointers.
2. Tracking (or eliminating) intergenerational pointers based on
"developer coding policy invariants" (ie Constant PMCs can ONLY contain
or point to constant PMCS) is essentially reverting memory management
responsibilities back to the developer.
Coding policy based intergenerational management will be violated
(creating GC bugs) by adding new features and refactoring old code.
Unless I'm missing something obvious this seems likely to multiply the
types of bugs that constant PMCS introduce.
The key question in weighing the compromise is whether the majority of
the short-lived or long-lived PMCs are leaves or containers. Leaves work
well in separate pools, containers fall afoul of intergenerational
management, which could cost more than the gain of separate pools. From
chromatic's list we've got
Leaves:
* 208,173 FixedIntegerArray (contains non-GC elements)
187,444 Integer
313,394 String
Containers:
* 916,675 Context
* 890,230 CallSignature
* 879,236 RetContinuation
* 851,059 CallSignatureReturns
249,716 ResizablePMCArray
109,101 Hash
Of those, Context and RetContinuation could likely have all their
elements allocated from a short-lived pool. There's no way of knowing
from this list what ResizablePMCArray and Hash are used for.
CallSignature and CallSignatureReturns are explicitly short-lived
containers for user-space variables (in this model, user-space variables
are always the "general" pool), so heavily intergenerational. And if we
merge Context, CallSignature, CallSignatureReturns, and RetContinuation,
that leaves one heavily intergenerational container PMC at the top of
the chart.
Post by Patrick R. MichaudI'm also becoming very enamored with the idea of allowing stack-based
allocations for items that have very finite lifespans (think about
where we use constant_pmc_new now). Some macros to allocate simple,
short-lived PMCs and their attributes on the stack would take off a
lot of GC pressure in these cases. We wouldn't even need to call
VTABLE_destroy in most cases. I suspect that a relatively large number
of PMC allocations could be transformed in this way for a major
performance savings.
Again, this works okay for leaves, but not so well for containers (which
may have GC-able children). I don't immediately see advantages in purely
stack-based allocations over a young generation. Did you have more
thoughts on that?
Post by Patrick R. MichaudExplicitly merging PMCs is a good idea, but I also am liking the idea
of implicitly merging them into "super objects". If we can take a PMC
and lump it together into a memory block with the complete tree of all
it's delegate PMCs and STRINGs, we could get away with only marking
the block as a whole (not all the individual parts). Barring the
ability to store the complete tree in one place, we could store groups
of related PMCs together along with an array of escape pointers. The
mark process would be simplified to marking the block as a whole and
the array of escape pointers only. This idea is similar to generations
and inter-generational pointer lists, but uses locality to group items
together that are used together, instead of grouping by the number of
mark phases survived (which will tend to have the same result for
stable groups, but with worse performance).
It has potential... It would require careful analysis of how often we'll
see a gain from the grouping. We wouldn't see a benefit in the
CallSignature case, because it's specifically a container for non-local
children (from user-space). There's a certain amount of complexity
involved in deciding which PMCs can be grouped.
Context/CallSignature/RetContinuation could be manually grouped, but
then, would we get the same gains (and ultimately a cleaner
implementation of the behavior of those PMCs) by merging them into a
single PMC anyway?
Do people have other thoughts on part-way solutions we might implement
before full generational GC? We're just in the initial green-lighting
phase here, doesn't have to be a fully-formed idea.
Allison