<div dir="ltr">Ok as the author of <span style="font-size:13px">setGCBiasToGrowGCLimit &amp; </span>setGCBiasToGrow I was looking for a paper I gave at OOPSLA 2005 squeakfest on this. But can&#39;t find it.  However the original note from January 18th 2005 explains<div><br></div><div><span style="font-size:18px">Mac 3.8.6b4</span></div><div><span style="font-size:13px"><br></span></div><div><span style="font-size:13px">Smalltalk </span><span class="" style="font-size:13px">setGCBiasToGrowGCLimit</span><span style="font-size:13px">: 16*1024*1024. &quot;Set growth limit before full GC to 16MB&quot;</span><br style="font-size:13px"><span style="font-size:13px">                                Smalltalk setGCBiasToGrow: 1.</span><br style="font-size:13px"><span style="font-size:13px">                                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 </span><span style="font-size:13px">we approach a knee in a curve of space used versus the growth/compaction decision.</span><br></div><div><span style="font-size:13px"><br></span></div><div><span style="font-size:13px">Plus added this</span><br style="font-size:13px"><span style="font-size:13px">&quot; 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&#39;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&#39;ll tenure at 75% and be bias to grow to 16MB before doing full GC.&quot;</span><br style="font-size:13px"><br><br style="font-size:13px"><br style="font-size:13px"><blockquote class="gmail_quote" style="font-size:13px;margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><br>The Problem:<br><br>Last weekend I built a new VM which has instrumentation to describe exactly what the GC is doing, also to<br>trigger a semaphore when an GC finishes, and to allow you to poke at more interesting things that control GC activity.<br><br>What I found was an issue which we hadn&#39;t realized is there, well I&#39;m sure people have seen it, but don&#39;t know why...<br>What happens is that as we are tenuring objects we are decreasing the young space from 4MB to Zero.<br><br>Now as indicated in the table below if conditions are right (a couple of cases in the macrobenchmarks) why as you see the<br>number of objects we can allocate decreases to zero, and we actually don&#39;t tenure anymore once the survivors fall below 2000.<br>The rate at which young space GC activity occurs goes from say 8 per second towards 1000 per second, mind on fast machines<br>the young space ms accumulation count doesn&#39;t move much because the time taken to do this is under 1 millisecond, or 0, skewing<br>those statistics and hiding the GC time.<br><br>AllocationCount         Survivors<br>4000    5400<br>3209    3459<br>2269    2790<br>1760    1574<br>1592    2299<br>1105    1662<br>427     2355<br>392     2374<br>123     1472<br>89      1478<br>79      2<br>78      2<br>76      2<br>76      2<br><br>Note how we allocate 76 objects, do a young space GC, then have two survivors, finally we reach the 200K minimum GC<br>threshold and do a full GC followed by growing young space. However this process is very painful. Also it&#39;s why the low space dialog<br>doesn&#39;t appear in a timely manner because we are attempting to approach the 200K limit and trying really hard by doing thousands of<br>young space GCed to avoid going over that limit. If conditions are right, then we get close but not close enough...<br><br>What will change in the future.<br><br>a) A GC monitoring class (new) will look at mark/sweep/Root table counts and decide when to do a tenure operation if iterating<br>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.<br><br>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&#39;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&#39;ll tenure at 75% and be bias to grow to 16MB before doing full GC.<br><br>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&#39;m not quite sure how to do that yet.<br></blockquote><div><br></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Jan 11, 2016 at 3:21 AM, Max Leske <span dir="ltr">&lt;<a href="mailto:maxleske@gmail.com" target="_blank">maxleske@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> <br><div style="word-wrap:break-word"><br><div><blockquote type="cite"><div>On 10 Jan 2016, at 20:22, <a href="mailto:vm-dev-request@lists.squeakfoundation.org" target="_blank">vm-dev-request@lists.squeakfoundation.org</a> wrote:</div><br><div><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">Hi Max,</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">   pre-Spur to avoid GC one has to a) grow memory by enough to do all the</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">processing you&#39;re going to do and b) change the shrinkage parameter so the</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">Vm won&#39;t shrink the heap back down before the processing is complete.  To</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">do b) I suggest you modify setGCParameters.  vm parameters 24 sets the</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">shrinkage threshold; see vmParameterAt:put:: &quot;24 memory threshold above</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">whichto shrink object memory (read-write)&quot;.  growMemory.  Hmmm, I had</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">thoguht that there&#39;s a growMemoryBy: primitive in v3, but it appears there</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">isn&#39;t.  So simply allocate a ByteArray of the desired size and then GC to</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">get rid of it.  That should leave that much free space and then your load</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">should proceed without needing to GC.</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">Anyway, it&#39;s worth a try.</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"></div></blockquote><div><br></div><div>Thanks Eliot.</div><div><br></div><div>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. </div><div>#setGCBiasToGrow: seems to turn memory growth on and off. But if this is turned off, how can the VM then allocate more memory?</div><div>#setGCBiasToGrowGCLimit: seems to control if the growth should trigger a full GC, which seems pretty much like what I need.</div><div><br></div><div>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?</div><div><br></div><div>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?</div><div><br></div><div><br></div><div>Here’s the code I use experimentally:</div><div><br></div><div><div><div>MessageTally spyOn: [</div></div></div></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div><div><div>| size shrinkThreshold |</div></div></div></div><div><div><div><div>size := (self settings segmentsDirectory fileNamed: &#39;snapshot.bin&#39;) size.</div></div></div></div><div><div><div><div>shrinkThreshold := (Smalltalk vmParameterAt: 24).</div></div></div></div><div><div><div><div>Smalltalk vmParameterAt: 24 put: shrinkThreshold +  (size*2). &quot;(8MB + twice file size)&quot;</div></div></div></div><div><div><div><div>Smalltalk setGCBiasToGrowGCLimit: shrinkThreshold +  (size*2).</div></div></div></div><div><div><div><div>Smalltalk setGCBiasToGrow: 1. “enable growth??&quot;</div></div></div></div><div><div><div><div>ByteArray new: size*2.</div></div></div></div><div><div><div><div><br></div><div>&quot;incremental GC should take care of collecting the ByteArray, so I’m not doing anything</div></div></div></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div><div><div>manually here&quot;</div></div></div></div></blockquote><div><div><div><div><br></div></div></div></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div><div>&lt;load snapshot&gt; ].</div></div></div></blockquote><div><div><br></div><div><br></div><div><br></div><div>Cheers,</div><div>Max</div><div><br></div><div><br></div><div><br></div><div>Output from current MessageTally:</div><div><br></div><div><div><div> - 1123 tallies, 1125 msec.</div><div><br></div><div>**Tree**</div><div>--------------------------------</div><div>Process: (40s)  123994112: nil</div><div>--------------------------------</div><div>12.7% {143ms} CBImageSegment class(NSImageSegment class)&gt;&gt;basicSnapshot:from:do:</div><div>  12.6% {141ms} CBImageSegment class(NSImageSegment class)&gt;&gt;installSegmentFrom:andDo:</div><div>    12.6% {141ms} CBImageSegment class(NSImageSegment class)&gt;&gt;readSegmentFrom:</div><div>      12.6% {141ms} NSSegmentStream&gt;&gt;readObject</div><div>        12.6% {141ms} SmartRefStream&gt;&gt;nextAndClose</div><div>          12.6% {141ms} SmartRefStream&gt;&gt;next</div><div>            12.3% {138ms} SmartRefStream(ReferenceStream)&gt;&gt;next</div><div>              12.3% {138ms} SmartRefStream(DataStream)&gt;&gt;next</div><div>                10.6% {119ms} CBImageSegment(ImageSegment)&gt;&gt;comeFullyUpOnReload:</div><div>                  |10.6% {119ms} CBImageSegment(NSImageSegment)&gt;&gt;restoreEndiannessAndRehash</div><div>                  |  5.5% {62ms} Dictionary&gt;&gt;rehash</div><div>                  |    |2.8% {31ms} Dictionary&gt;&gt;associationsDo:</div><div>                  |    |  |2.2% {25ms} Array(SequenceableCollection)&gt;&gt;do:</div><div>                  |    |1.7% {19ms} Dictionary&gt;&gt;noCheckAdd:</div><div>                  |    |  1.7% {19ms} Dictionary(HashedCollection)&gt;&gt;findElementOrNil:</div><div>                  |    |    1.2% {13ms} Dictionary&gt;&gt;scanFor:</div><div>                  |  4.5% {51ms} primitives</div><div>                1.2% {13ms} SmartRefStream(DataStream)&gt;&gt;readArray</div><div>                  1.2% {13ms} SmartRefStream&gt;&gt;next</div><div>                    1.2% {13ms} SmartRefStream(ReferenceStream)&gt;&gt;next</div><div>                      1.2% {13ms} SmartRefStream(DataStream)&gt;&gt;next</div><div> </div><div>**Leaves**</div><div><br></div><div>**Memory**</div><div><span style="white-space:pre-wrap">        </span>old<span style="white-space:pre-wrap">                        </span>+94,031,228 bytes</div><div><span style="white-space:pre-wrap">        </span>young<span style="white-space:pre-wrap">                </span>-9,207,660 bytes</div><div><span style="white-space:pre-wrap">        </span>used<span style="white-space:pre-wrap">                </span>+84,823,568 bytes</div><div><span style="white-space:pre-wrap">        </span>free<span style="white-space:pre-wrap">                </span>+90,024,824 bytes</div><div><br></div><div>**GCs**</div><div><span style="white-space:pre-wrap">        </span>full<span style="white-space:pre-wrap">                        </span>1 totalling 85ms (8.0% uptime), avg 85.0ms</div><div><span style="white-space:pre-wrap">        </span>incr<span style="white-space:pre-wrap">                </span>15 totalling 271ms (24.0% uptime), avg 18.0ms</div><div><span style="white-space:pre-wrap">        </span>tenures<span style="white-space:pre-wrap">                </span>10 (avg 1 GCs/tenure)</div><div><span style="white-space:pre-wrap">        </span>root table<span style="white-space:pre-wrap">        </span>0 overflows</div><div><br></div></div></div><br><blockquote type="cite"><div><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">On Sat, Jan 9, 2016 at 3:03 AM, Max Leske </span><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">wrote:</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><blockquote type="cite" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br>Hi,<br><br>I have a rather annoying problem. I’m running a time critical piece of<br>code that reads a big (~90MB) image segment from a file. I’ve optimized<br>loading as far as possible and now GC takes far longer than the loading<br>itself (see the MessageTally output below).<br>I’m wondering if there’s any possibility to defer garbage collection<br>during the load.<br><br>For completeness, here’s the use case: the process is socket activated,<br>which means that the first request coming in will start the process. When<br>the image starts it will load the segment to restore the last state of the<br>application and, once that’s done, serve the request. The critical time<br>includes vm startup, image startup, starting the server in the image and<br>loading the snapshot. With a big snapshot the loading time of the snapshot<br>is the most significant contributor.<br><br>Maybe I could preallocate the needed memory to prevent the garbage<br>collector from running?<br><br>I’d appreciate any ideas you have.<br><br><br>Cheers,<br>Max<br><br><br>PS: This needs to run on a Squeak 4.0.3 VM (no JIT)<br><br><br><br><br>Output from MessageTally:<br><br>- 1624 tallies, 1624 msec.<br><br>**Tree**<br>--------------------------------<br>Process: (40s)  592969728: nil<br>--------------------------------<br>4.4% {72ms} CBImageSegment class(NSImageSegment<br>class)&gt;&gt;basicSnapshot:from:do:<br> 4.4% {72ms} CBImageSegment class(NSImageSegment<br>class)&gt;&gt;installSegmentFrom:andDo:<br>   4.4% {72ms} CBImageSegment class(NSImageSegment<br>class)&gt;&gt;readSegmentFrom:<br>     4.4% {72ms} NSSegmentStream&gt;&gt;readObject<br>       4.4% {72ms} SmartRefStream&gt;&gt;nextAndClose<br>         4.4% {72ms} SmartRefStream&gt;&gt;next<br>           4.3% {70ms} SmartRefStream(ReferenceStream)&gt;&gt;next<br>             4.3% {70ms} SmartRefStream(DataStream)&gt;&gt;next<br>               3.2% {52ms}<br>NSImageSegment(ImageSegment)&gt;&gt;comeFullyUpOnReload:<br>                 3.2% {52ms} NSImageSegment&gt;&gt;restoreEndiannessAndRehash<br>**Leaves**<br>3.2% {52ms} NSImageSegment&gt;&gt;restoreEndiannessAndRehash<br><br>**Memory**<br>       old                     +92,704,656 bytes<br>       young           -8,008,252 bytes<br>       used            +84,696,404 bytes<br>       free            +1,287,768 bytes<br><br>**GCs**<br>       full                    2 totalling 954ms (59.0% uptime), avg<br>477.0ms<br>       incr            5 totalling 165ms (10.0% uptime), avg 33.0ms<br>       tenures         1 (avg 5 GCs/tenure)<br>       root table      0 overflows<br></blockquote><br></div></blockquote></div><br></div><br></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div><div dir="ltr">===========================================================================<br>John M. McIntosh. Corporate Smalltalk Consulting Ltd <a href="https://www.linkedin.com/in/smalltalk" target="_blank">https://www.linkedin.com/in/smalltalk</a><br>===========================================================================<br></div></div></div></div>
</div>