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

Eliot Miranda eliot.miranda at gmail.com
Wed Nov 17 00:13:08 UTC 2010


On Tue, Nov 16, 2010 at 3:32 PM, Levente Uzonyi <leves at elte.hu> wrote:

> On Tue, 16 Nov 2010, Juan Vuletich wrote:
>
>  Hi Levente,
>>
>> Levente Uzonyi wrote:
>>
>>> Hi,
>>>
>>> I'm mostly ready with this cleanup, only a few methods left in the image
>>> that use #== for integer comparison. Some of them must use #==, others may
>>> be changed, but I wasn't sure if the code will work if it's changed or not.
>>> If you'd like to check these methods, then evaluate the following in a
>>> workspace:
>>>
>>> ... code here...
>>>
>>> Cheers,
>>> Levente
>>>
>>
>> Thanks for the snippet! It is now a method in Cuis. I also checked a bit
>> on trunk. In all senders of #nextObject you can apply the pattern in
>> #allObjectsDo:. Instead of assuming == 0 for last #nextObject, it assumes
>> that Object new will go at the end. If that ever changed, a few places would
>> need fixing...
>>
>
> I'm not sure if it's ok to use that pattern in ImageSegment. Even if it's
> ok, the code is so messy, that it seems to be hard to apply the pattern
> without breaking the code.
>
>
>> As an experiment, in #allObjectsDo: I tried to remove the Object new stuff
>> and replace with '[ 0 = object and: [ object isMemberOf: SmallInteger ]]
>> whileFalse: ', but my test became extremely slow. I suspect #= is sending
>> the message even if it has its own bytecode... So, the only method that
>> remains with the '0 ==' pattern in Cuis is #critical:ifLocked: , as I'm not
>> sure if we can clean it.
>>
>
> #= is a special selector, so I'm sure it won't send a message if it doesn't
> have to.


Um, on Cog it sends a message if the method containing the #= has been
jitted.  But the issue is /not/ whether there is a send or not.  The issue
is what the behaviour of the primitive code is.  In the interpreter #= will
short-circuit (avoid the send) if both the receiver and the argument are
either a SmallInteger or a Float.  In the JIT the primitive will not fail if
the receiver and argument are both SmallIntegers or Floats or if the
receiver is a Float and the argument is an Integer, but will fail if the
receiver is a SmallInteger and the argument is a Float.

In general the VM is free to fail for non-matching numeric types (this is
historical, derived from the blue book) so I don't feel Cog is at fault
here.  Certainly it is not answering incorrect results; it is simply taking
more sends to produce the result in some circumstances. I think in cases
like this (where you're enumerating over all objects) using #== is a wiser
choice.

HTH


It's possible that #= is a bit slower than #== because it has to do some
> extra checks, but the difference is probably neglible. Here's a benchmark:
>
> | offset equality identity |
> Smalltalk garbageCollect.
> offset := [ 1 to: 1000000 do: [ :i | ] ] timeToRun.
> equality := [ :x | [ 1 to: 1000000 do: [ :i | 0 = x ] ] timeToRun ].
> identity := [ :x | [ 1 to: 1000000 do: [ :i | 0 == x ] ] timeToRun ].
> { 0. 1. SmallInteger maxVal. SmallInteger maxVal + 1. nil. Object new. 0.0.
> Array new. 1/2 } collect: [ :each |
>        each -> ({
>                equality value: each.
>                identity value: each.
>                equality value: each.
>                identity value: each.
>                equality value: each.
>                identity value: each } - offset) ].
>
> And my results on CogVM:
>
> {
>        0->#(3 2 3 1 3 2).
>        1->#(2 4 3 0 3 4).
>        1073741823->#(3 3 2 1 3 5).
>        1073741824->#(221 4 223 1 223 4).
>        nil->#(14 4 14 0 15 4).
>        an Object->#(14 5 13 1 14 4).
>        0.0->#(622 5 623 2 624 4).
>        #()->#(16 5 14 1 16 4).
>        (1/2)->#(260 4 259 1 258 5)
> }
>

I'd do many more iterations.  I wouldn't put any faith any millisecond
numbers that are less than 3 digits (100 ms).


>
> So the cause of the slowdown in your #allObjectsDo: implementation is that
> #= is only fast if both the receiver and the argument are SmallIntegers,
> otherwise there will be message sends.
>
> Another way to implement #allObjectsDo: without the marker object is to
> replace the loop condition with: object class == SmallInteger. It's actually
> the same as your implementation without the #= check. #isMemberOf: is
> optimized to non-real sends. This is as fast as the current implementation
> on my pc.
>
>
> Levente
>
>
>> Cheers,
>> Juan Vuletich
>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20101116/1a838c92/attachment.htm


More information about the Squeak-dev mailing list