[Vm-dev] Is it possible to suspend the garbage collector?

John McIntosh johnmci at smalltalkconsulting.com
Mon Jan 11 19:03:31 UTC 2016


Ok as the author of setGCBiasToGrowGCLimit & setGCBiasToGrow I was looking
for a paper I gave at OOPSLA 2005 squeakfest on this. But can't find it.
However the original note from January 18th 2005 explains

Mac 3.8.6b4

Smalltalk setGCBiasToGrowGCLimit: 16*1024*1024. "Set growth limit before
full GC to 16MB"
                                Smalltalk setGCBiasToGrow: 1.
                                Set bias to grow upto GCLimit, this can
avoid a problem where we attempt to avoid growing but results in thousands
of incremental GC events as we approach a knee in a curve of space used
versus the growth/compaction decision.

Plus added this
" A VM change will consider that after a tenure if the young space is less
than 4MB then growth will happen to make young space greater than 4MB plus
a calculated slack. Then after we've tenured N MB we will do a full GC,
versus doing a full GC on every grow operation, this will trigger a shrink
if required.  For example we'll tenure at 75% and be bias to grow to 16MB
before doing full GC."




> The Problem:
>
> Last weekend I built a new VM which has instrumentation to describe
> exactly what the GC is doing, also to
> trigger a semaphore when an GC finishes, and to allow you to poke at more
> interesting things that control GC activity.
>
> What I found was an issue which we hadn't realized is there, well I'm sure
> people have seen it, but don't know why...
> What happens is that as we are tenuring objects we are decreasing the
> young space from 4MB to Zero.
>
> Now as indicated in the table below if conditions are right (a couple of
> cases in the macrobenchmarks) why as you see the
> number of objects we can allocate decreases to zero, and we actually don't
> tenure anymore once the survivors fall below 2000.
> The rate at which young space GC activity occurs goes from say 8 per
> second towards 1000 per second, mind on fast machines
> the young space ms accumulation count doesn't move much because the time
> taken to do this is under 1 millisecond, or 0, skewing
> those statistics and hiding the GC time.
>
> AllocationCount         Survivors
> 4000    5400
> 3209    3459
> 2269    2790
> 1760    1574
> 1592    2299
> 1105    1662
> 427     2355
> 392     2374
> 123     1472
> 89      1478
> 79      2
> 78      2
> 76      2
> 76      2
>
> Note how we allocate 76 objects, do a young space GC, then have two
> survivors, finally we reach the 200K minimum GC
> threshold and do a full GC followed by growing young space. However this
> process is very painful. Also it's why the low space dialog
> doesn't appear in a timely manner because we are attempting to approach
> the 200K limit and trying really hard by doing thousands of
> young space GCed to avoid going over that limit. If conditions are right,
> then we get close but not close enough...
>
> What will change in the future.
>
> a) A GC monitoring class (new) will look at mark/sweep/Root table counts
> and decide when to do a tenure operation if iterating
> over the root table objects takes too many iterations. A better solution
> would be to remember old objects and which slot has the young reference but
> that is harder to do.
>
> b) A VM change will consider that after a tenure if the young space is
> less than 4MB then growth will happen to make young space greater than 4MB
> plus a calculated slack. Then after we've tenured N MB we will do a full
> GC, versus doing a full GC on every grow operation, this will trigger a
> shrink if required.  For example we'll tenure at 75% and be bias to grow to
> 16MB before doing full GC.
>
> c) To solve hitting the hard boundary when we can not allocate more space
> we need to rethink when the low semaphore is signaled and the rate of young
> space GC activity, signaling the semaphore earlier will allow a user to
> take action before things grind to a halt. I'm not quite sure how to do
> that yet.
>


On Mon, Jan 11, 2016 at 3:21 AM, Max Leske <maxleske at gmail.com> wrote:

>
>
> On 10 Jan 2016, at 20:22, vm-dev-request at lists.squeakfoundation.org wrote:
>
> Hi Max,
>
>    pre-Spur to avoid GC one has to a) grow memory by enough to do all the
> processing you're going to do and b) change the shrinkage parameter so the
> Vm won't shrink the heap back down before the processing is complete.  To
> do b) I suggest you modify setGCParameters.  vm parameters 24 sets the
> shrinkage threshold; see vmParameterAt:put:: "24 memory threshold above
> whichto shrink object memory (read-write)".  growMemory.  Hmmm, I had
> thoguht that there's a growMemoryBy: primitive in v3, but it appears there
> isn't.  So simply allocate a ByteArray of the desired size and then GC to
> get rid of it.  That should leave that much free space and then your load
> should proceed without needing to GC.
>
> Anyway, it's worth a try.
>
>
> Thanks Eliot.
>
> Setting the memory threshold helped. I’m still seeing one full GC which
> I’m trying to avoid. I’ve experimented with #setGCBiasToGrow: and
> #setGCBiasToGrowGCLimit: but I don’t fully understand what they do.
> #setGCBiasToGrow: seems to turn memory growth on and off. But if this is
> turned off, how can the VM then allocate more memory?
> #setGCBiasToGrowGCLimit: seems to control if the growth should trigger a
> full GC, which seems pretty much like what I need.
>
> Unfortunately, while setting these options seems to have an influence, I
> can’t quite see the pattern, and that one full GC is still there. Maybe you
> could explain how these options work exactly?
>
> One other question: the MessageTally output seems to be missing about 50%
> of the running time. Summing up over full GC + incremental GC + time spent
> in the tree, leaves about 500ms unaccounted for. Do you have any idea where
> that half second goes missing?
>
>
> Here’s the code I use experimentally:
>
> MessageTally spyOn: [
>
> | size shrinkThreshold |
> size := (self settings segmentsDirectory fileNamed: 'snapshot.bin') size.
> shrinkThreshold := (Smalltalk vmParameterAt: 24).
> Smalltalk vmParameterAt: 24 put: shrinkThreshold +  (size*2). "(8MB +
> twice file size)"
> Smalltalk setGCBiasToGrowGCLimit: shrinkThreshold +  (size*2).
> Smalltalk setGCBiasToGrow: 1. “enable growth??"
> ByteArray new: size*2.
>
> "incremental GC should take care of collecting the ByteArray, so I’m not
> doing anything
>
> manually here"
>
>
> <load snapshot> ].
>
>
>
>
> Cheers,
> Max
>
>
>
> Output from current MessageTally:
>
>  - 1123 tallies, 1125 msec.
>
> **Tree**
> --------------------------------
> Process: (40s)  123994112: nil
> --------------------------------
> 12.7% {143ms} CBImageSegment class(NSImageSegment
> class)>>basicSnapshot:from:do:
>   12.6% {141ms} CBImageSegment class(NSImageSegment
> class)>>installSegmentFrom:andDo:
>     12.6% {141ms} CBImageSegment class(NSImageSegment
> class)>>readSegmentFrom:
>       12.6% {141ms} NSSegmentStream>>readObject
>         12.6% {141ms} SmartRefStream>>nextAndClose
>           12.6% {141ms} SmartRefStream>>next
>             12.3% {138ms} SmartRefStream(ReferenceStream)>>next
>               12.3% {138ms} SmartRefStream(DataStream)>>next
>                 10.6% {119ms}
> CBImageSegment(ImageSegment)>>comeFullyUpOnReload:
>                   |10.6% {119ms}
> CBImageSegment(NSImageSegment)>>restoreEndiannessAndRehash
>                   |  5.5% {62ms} Dictionary>>rehash
>                   |    |2.8% {31ms} Dictionary>>associationsDo:
>                   |    |  |2.2% {25ms} Array(SequenceableCollection)>>do:
>                   |    |1.7% {19ms} Dictionary>>noCheckAdd:
>                   |    |  1.7% {19ms}
> Dictionary(HashedCollection)>>findElementOrNil:
>                   |    |    1.2% {13ms} Dictionary>>scanFor:
>                   |  4.5% {51ms} primitives
>                 1.2% {13ms} SmartRefStream(DataStream)>>readArray
>                   1.2% {13ms} SmartRefStream>>next
>                     1.2% {13ms} SmartRefStream(ReferenceStream)>>next
>                       1.2% {13ms} SmartRefStream(DataStream)>>next
> **Leaves**
>
> **Memory**
> old +94,031,228 bytes
> young -9,207,660 bytes
> used +84,823,568 bytes
> free +90,024,824 bytes
>
> **GCs**
> full 1 totalling 85ms (8.0% uptime), avg 85.0ms
> incr 15 totalling 271ms (24.0% uptime), avg 18.0ms
> tenures 10 (avg 1 GCs/tenure)
> root table 0 overflows
>
>
>
> On Sat, Jan 9, 2016 at 3:03 AM, Max Leske wrote:
>
>
> Hi,
>
> I have a rather annoying problem. I’m running a time critical piece of
> code that reads a big (~90MB) image segment from a file. I’ve optimized
> loading as far as possible and now GC takes far longer than the loading
> itself (see the MessageTally output below).
> I’m wondering if there’s any possibility to defer garbage collection
> during the load.
>
> For completeness, here’s the use case: the process is socket activated,
> which means that the first request coming in will start the process. When
> the image starts it will load the segment to restore the last state of the
> application and, once that’s done, serve the request. The critical time
> includes vm startup, image startup, starting the server in the image and
> loading the snapshot. With a big snapshot the loading time of the snapshot
> is the most significant contributor.
>
> Maybe I could preallocate the needed memory to prevent the garbage
> collector from running?
>
> I’d appreciate any ideas you have.
>
>
> Cheers,
> Max
>
>
> PS: This needs to run on a Squeak 4.0.3 VM (no JIT)
>
>
>
>
> Output from MessageTally:
>
> - 1624 tallies, 1624 msec.
>
> **Tree**
> --------------------------------
> Process: (40s)  592969728: nil
> --------------------------------
> 4.4% {72ms} CBImageSegment class(NSImageSegment
> class)>>basicSnapshot:from:do:
>  4.4% {72ms} CBImageSegment class(NSImageSegment
> class)>>installSegmentFrom:andDo:
>    4.4% {72ms} CBImageSegment class(NSImageSegment
> class)>>readSegmentFrom:
>      4.4% {72ms} NSSegmentStream>>readObject
>        4.4% {72ms} SmartRefStream>>nextAndClose
>          4.4% {72ms} SmartRefStream>>next
>            4.3% {70ms} SmartRefStream(ReferenceStream)>>next
>              4.3% {70ms} SmartRefStream(DataStream)>>next
>                3.2% {52ms}
> NSImageSegment(ImageSegment)>>comeFullyUpOnReload:
>                  3.2% {52ms} NSImageSegment>>restoreEndiannessAndRehash
> **Leaves**
> 3.2% {52ms} NSImageSegment>>restoreEndiannessAndRehash
>
> **Memory**
>        old                     +92,704,656 bytes
>        young           -8,008,252 bytes
>        used            +84,696,404 bytes
>        free            +1,287,768 bytes
>
> **GCs**
>        full                    2 totalling 954ms (59.0% uptime), avg
> 477.0ms
>        incr            5 totalling 165ms (10.0% uptime), avg 33.0ms
>        tenures         1 (avg 5 GCs/tenure)
>        root table      0 overflows
>
>
>
>
>


-- 
===========================================================================
John M. McIntosh. Corporate Smalltalk Consulting Ltd
https://www.linkedin.com/in/smalltalk
===========================================================================
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20160111/3afb5376/attachment-0001.htm


More information about the Vm-dev mailing list