<div dir="ltr">Hi,<div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Aug 3, 2018 at 4:28 AM, Ben Coman <span dir="ltr"><<a href="mailto:btc@openinworld.com" target="_blank">btc@openinworld.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> <br>
Just a brain twitch about something I'd like to understand better...<br>
<br>
At <a href="http://www.mirandabanda.org/cogblog/2011/03/01/build-me-a-jit-as-fast-as-you-can/" rel="noreferrer" target="_blank">http://www.mirandabanda.org/co<wbr>gblog/2011/03/01/build-me-a-ji<wbr>t-as-fast-as-you-can/</a><br>
it says... "[Monomorphic] inline caching depends on the fact that in<br>
most programs at most send sites there is no polymorphism and that<br>
most sends bind to *exactly_one* class of receiver over some usefully<br>
long period of time. ... In Cog we implement inline caches in three<br>
forms ... monomorphic inline cache ... closed polymorphic inline cache<br>
... open polymorphic cache.  What’s nice is that while these sends are<br>
increasingly expensive moving from monomorphic to megamorphic they are<br>
also decreasingly common in roughly a 90%, 9% 0.9% ratio, at least for<br>
typical Smalltalk programs"<br></blockquote><div><br></div><div>Note that in my experience the ratio was, each time I measured in the Cog Simulator, 93%, 4%, 3% or something like that. Cliff Click told me recently he had the same feeling with Java code, sends are either mono or megamorphic, but rarely poly (through in the JVM polymorphism is up to 4). </div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
First, I'm curious what is the relative performance of the three<br>
different caches ?<br></blockquote><div><br></div><div>I guess you can measure that with micro benchs. Levente can help with that, I would write complete crap. Note that our polymorphism is up to 6.</div><div><br></div><div>In the Case of Cog, I would expect monomorphic caches to be almost as fast as direct calls, polymorphic caches to be almost as fast as monomorphic, and megamorphic caches to be considerably slower. To be confirmed.</div><div><br></div><div>Note also that for some reason in Cog PICs are called ClosedPICs and megamorphic caches are called OpenPICs.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Second, I'm curious how Booleans are dealt with.  Boolean handling<br>
must be fairly common, and at the Image level these are two different<br>
classes, which pushes out of the monomorphic inline cache, which may<br>
be a significant impact on performance.<br>
<br></blockquote><div><br></div><div>Control flow operations are inlined by the bytecode compiler, and they're the most critical performance wise.</div><div><br></div><div>The VM fixes the addresses of specific objects (nil, true, false). Become and become forward don't work with those objects. The JIT can generate constants in machine code for the addresses of those objects. That allows to quicken inlined control flow operations.</div><div><br></div><div>Non inlined operations are usually dealt with PICs with 2 cases.</div><div><br></div><div>One issue I had in Sista was with early PIC promotion. Currently in Cog if there's already a megamorphic cache for a selector, monomorphic caches are rewritten to the megamorphic cache directly and not to PIC then megamorphic. This is a problem typically with sends such as #isNil. In some cases the isNil is megamorphic and using such cache is relevant. In other case there's just a given type and Undefined object, and there the VM currently uses a megamorphic cache instead of a PIC. This was especially annoying since megamorphic caches don't provide any runtime type feedback. Similar 2 cases issue, non boolean.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I started wondering if under the hood the VM could treat the two<br>
booleans as one class and in the instance store "which-boolean" it<br>
actually is.  Then for example the #ifTrue:ifFalse: method of each<br>
class would be compiled into a single method conditioned at the start<br>
on "which-boolean" as to which path is executed.  How feasible would<br>
that be, and would it make much of a difference in performance of<br>
booleans ?<br>
<br></blockquote><div><br></div><div>Some VMs have boolean as primitive types or as immediate objects. Honestly, given our optimization that the booleans can't move in memory and that we can use their address as a constant, I don't think any of these optimizations would make any significant difference in terms of performance. </div><div><br></div><div>What might make a difference is to add as primitive operations / inlined operations some other boolean methods, such as #not. It's a trade-off between system flexibility, boolean and non boolean performance, etc. </div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Except then I realized that this situation is already bypassed by<br>
common boolean methods being inlined by the compiler.  Still curious,<br>
if there are quick answers to my questions.<br></blockquote><div><br></div><div>..</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
cheers -ben<br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="m_8990572560477080597gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><span style="font-size:12.8px">Clément Béra<br></span><span style="color:rgb(0,0,238)"><a href="https://clementbera.github.io/" target="_blank">https://clementbera.github.io/</a></span><div style="font-size:12.8px"><a href="https://clementbera.wordpress.com/" target="_blank">https://clementbera.wordpress.<wbr>com/</a></div></div></div></div></div></div>
</div></div></div>