[squeak-dev] Re: Using #= for integer comparison instead of #==

Andreas Raab andreas.raab at gmx.de
Wed Nov 17 09:36:41 UTC 2010


On 11/16/2010 9:52 PM, Levente Uzonyi wrote:
> On Tue, 16 Nov 2010, Andreas Raab wrote:
>
>> On 11/16/2010 8:05 PM, Levente Uzonyi wrote:
>>> I wasn't clear when I said atomic code. I expected #= (and #<, #>, etc)
>>> to _not_ be a real message send when both the receiver and the argument
>>> are SmallIntegers. Otherwise what's the point of having separate
>>> bytecodes for them?
>>
>> Space. It makes a big difference for the most common selectors (#at:,
>> #at:put:, #size, #+ etc) to be be encoded as bytecodes. It avoids
>> having to allocate a literal every time you see the selector. Often,
>> the special
>
> I just evaluated this:
>
> | count specialSelectors |
> count := 0.
> specialSelectors := Smalltalk specialSelectors select: [ :each | each
> isSymbol ].
> CompiledMethod allInstancesDo: [ :method |
> | messages |
> messages := method messages.
> count := count + (specialSelectors count: [ :selector |
> messages includes: selector ]) ].
> count
>
> The result is 50947 for a slightly modified Trunk image. This means that
> this technique saves less than 200kB (assuming 32-bit slots in the
> literal frame), but it uses 32 bytecodes.

Heh, heh. Yes, I realized that after I sent my messages. My comment 
applies to the "old days" when memory was at a prime and such 
optimizations made sense. Nowadays for all practical purposes that 
arguments holds no water.

> 200 kB is not much compared to the size of the image (about 1-2%).
>
> Also the 32 most frequently used methods are not the 32 special selectors.

Yup. That changes too over time.

> | b mostFrequentSelectors specialSelectors |
> b := Bag new.
> CompiledMethod allInstancesDo: [ :method | b addAll: method messages ].
> mostFrequentSelectors := (b sortedCounts first: 32) replace: #value.
> specialSelectors := Smalltalk specialSelectors select: #isSymbol.
> {
> specialSelectors difference: mostFrequentSelectors. "Shouldn't be special"
> mostFrequentSelectors difference: specialSelectors. "Should be special"
> }.
>
> #(
> #(#'>=' #'~=' #/ #'\\' #bitShift: #'//' #bitAnd: #bitOr: #next #atEnd
> #blockCopy: #value #value: #x #y)
> #(#, #assert: #first #name #add: #nextPutAll: #isEmpty #error: #asString
> #includes: #default #translated #not #on: #collect:))
>
> Another 40kB could be saved by changing these.
>
> Btw, there's a "free" bytecode: 200 - #blockCopy:.

Indeed, it's no longer used for closures (but it is part of the ST80 spec).

Cheers,
   - Andreas

>> selector bytecodes look like this:
>>
>> Interpreter>>bytecodePrimNextPut
>> messageSelector := self specialSelector: 20.
>> argumentCount := 1.
>> self normalSend.
>>
>> I.e., it just dispatches to normalSend where the regular lookup takes
>> place. Of course, that also means it's a prime place for an
>> optimization that will evaluate eagerly for known receiver types and
>> so (over time) optimizations were added, but many of the optimizations
>> that may make sense in an interpreter have very different tradeoffs in
>> the jit. For a jit to generate the level of optimization makes no
>> sense because the code size simply explodes at no benefit if the
>> inline caches are any good (ours *are* the best Eliot knows how to do
>> and that is a meaningful statement).
>>
>> On to a finer point. The terminology "real message send" is
>> misleading. Generally, we (the VM hackers) mean by "real" send a send
>> that requires a method activation, i.e., the creation of a context,
>> but *not* the lookup of the method. That excludes for example all
>> (successful) primitives from being "real sends", and as a consequence
>> writing "1 + 2" is not a real send by that measure (with or without
>> the bytecode present) since the primitive will be executed
>> successfully and no "real" send (method activation) has taken place.
>>
>> To make matters more complicated, when we talk about "real" sends in
>> the context of thread switches, semaphores and critical sections, what
>> we mean is whether there is a suspension point in the send or not.
>> Obviously, some primitives (#suspend, #yield) must have suspension
>> points so not all activation-free methods are also
>> suspension-point-free. I am not entirely sure what the current set of
>> rules for suspension points in Cog is; in the interpreter it was part
>> of the activation sequence so any primitive that isn't process related
>> would not have a suspension point but I don't know if that's still
>> true in Cog.
>
> Thanks, this was very informative.
>
>
> Levente
>
>>
>> Cheers,
>> - Andreas
>>
>>
>
>




More information about the Squeak-dev mailing list