<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Apr 8, 2016 at 9:29 AM, Levente Uzonyi <span dir="ltr">&lt;<a href="mailto:leves@caesar.elte.hu" target="_blank">leves@caesar.elte.hu</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="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>On Fri, 8 Apr 2016, Bert Freudenberg wrote:<br>
<blockquote class="gmail_quote" style="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>
On 08.04.2016, at 00:34, Levente Uzonyi &lt;<a href="mailto:leves@caesar.elte.hu" target="_blank">leves@caesar.elte.hu</a>&gt; wrote:<br>
&gt;<br>
&gt; When the VM runs out of memory primitive 71 in #basicNew: will fail and it&#39;ll send<br>
&gt; #handleFailingBasicNew:. That method will retry primitive 71, which will fail again, and then it&#39;ll do a full gc to make room for the new<br>
object.<br>
<br>
I couldn’t believe regular GC would go through primitive failure code and rely on the image to invoke a full GC.<br>
</blockquote>
<br>
It does. Perhaps it&#39;s worth trying #garbageCollectMost before doing a full GC. It decreases the full GC significantly in cases when larger objects are allocated and thrown away frequently.<br>
<br>
I had replaced<br>
<br>
        Smalltalk garbageCollect &lt; bytesRequested ifTrue:<br>
                [Smalltalk growMemoryByAtLeast: bytesRequested].<br>
<br>
with<br>
<br>
        Smalltalk garbageCollectMost &lt; bytesRequested ifTrue:<br>
                [Smalltalk garbageCollect &lt; bytesRequested ifTrue:<br>
                        [Smalltalk growMemoryByAtLeast: bytesRequested]].<br>
<br>
in #handleFailingBasicNew: and the number of full GCs has never gone above 4 when running this snippet:<br>
<br>
Smalltalk garbageCollect.<br>
x := Smalltalk vmParameterAt: 7. &quot;num full GC since startup&quot;<br>
{ [ActiveWorld imageForm] bench.<br>
(Smalltalk vmParameterAt: 7) - x }<br>
<br>
Doing the same trick in #handleFailingBasicNew has taken the number down to 2.<br>
So I suggest we should use both changes if it has no negative side effects. Eliot? :)<br></blockquote><div><br></div><div>+1.  I had hoped that scavenging would be run automatically, but this won&#39;t happen with huge allocations.  For small allocations, when eden is full, the machine code new primitive will set the &quot;needs scavenge&quot; flag, when <span style="color:rgb(0,0,0);font-size:12.8px">#handleFailingBasicNew: runs the scavenger will run, and so there is no need to do </span>Smalltalk garbageCollectMost, because that has happened implicitly.  But for huge allocations I think the code doesn&#39;t set the scavenge flag, it merely fails the primitive.  But I need to check this.</div><div><br></div><div>What do we prefer, having the machine code for new always set the &quot;needs scavenge&quot; flag if an allocation failed because there was no room, or have <span style="color:rgb(0,0,0);font-size:12.8px">#handleFailingBasicNew: et al calls </span>Smalltalk garbageCollectMost explicitly?  </div><div><br></div><div>The wrinkle here is that Spur will only allocate objects with 64k slots or less in newSpace (I apologise; this is not documented at the image level):</div><div><br></div><div><div>maxSlotsForNewSpaceAlloc</div><div><span class="" style="white-space:pre">        </span>&quot;Almost entirely arbitrary, but we dont want 1Mb bitmaps allocated in eden.</div><div><span class="" style="white-space:pre">        </span> But this choice means no check for numSlots &gt; maxSlotsForNewSpaceAlloc</div><div><span class="" style="white-space:pre">        </span> for non-variable allocations.&quot;</div><div><span class="" style="white-space:pre">        </span>^self fixedFieldsOfClassFormatMask</div><div><br></div><div>fixedFieldsOfClassFormatMask</div><div><span class="" style="white-space:pre">        </span>&lt;api&gt;</div><div><span class="" style="white-space:pre">        </span>^1 &lt;&lt; self fixedFieldsFieldWidth - 1</div><div><span class="" style="white-space:pre">        </span></div><div>fixedFieldsFieldWidth</div><div><span class="" style="white-space:pre">        </span>&lt;api&gt;</div><div><span class="" style="white-space:pre">        </span>&lt;cmacro&gt;</div><div><span class="" style="white-space:pre">        </span>^16</div></div><div><br></div><div>So the &quot;needs scavenge&quot; flag only gets set for &quot;small&quot; allocations, and even more confusingly, &quot;small&quot; is different in 32- and 64-bits since 64k slots is 256k bytes in 32-bits buts 512k bytes in 64-bits.  So I am leaning on having <span style="color:rgb(0,0,0);font-size:12.8px">handleFailingBasicNew: call </span>garbageCollectMost explicitly.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
And in fact, it doesn’t. I put a &quot;BasicNewFailures := BasicNewFailures + <br>
</blockquote>
1.” in basicNew(:) and it never increased. So I think this is invoked<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
only in severe conditions.<br>
</blockquote>
<br>
Try the snippet above. The way I found this was that I also had the #bench send wrapped in #timeProfile, so it appeared in the profiler. Make sure you have only a few windows open, otherwise drawing will take way too long and there won&#39;t be enough allocations to trigger the failure.<br></blockquote><div><br></div><div><br class="">When I saw Bert&#39;s message above, denying that basicNew: ever fails, I immediately repeated Bert&#39;s experiment, /knowing/ that basicNew /does/ fail.  But to my surprise my experiment revealed Bert&#39;s result, that basicNew does not appear to fail :-).  Of course the gotcher is that the backward branch in the loop over allocation checks for events, and runs the scavenger, so a simple loop never shows failures.  It&#39;s difficult to make it fail, but fail it will :-)<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
&gt; Only when it&#39;s not possible to make room for the new object by collecting the garbage will the VM allocate more memory.<br>
<br>
I see that code in Behavior (calling growMemoryByAtLeast:), yes, but in my tests it never got invoked.<br>
<br>
&gt; Forcing the VM to allocate more memory, by tweaking parameter 25, will decrease the number of GCs, though I wasn&#39;t able to get it down to 0,<br>
because the code became way too snappy and it quickly reached the new memory limit.<br>
<br>
Yes, the number of full GCs goes down. But why not to zero? I cannot understand why we cannot find a large-enough “new space size” so that the<br>
working set is fully kept in there. Redrawing a couple windows should not produce any long-lived objects that trigger a full GC every second.<br>
<br>
</blockquote>
<br>
If you replace #bench with #benchFor: 1 seconds, then the number of full GCs will stay zero (using the #garbageCollectMost change I suggested above).<br>
<br>
Levente<br>
<br></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div>
</div></div>