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

Levente Uzonyi leves at elte.hu
Tue Nov 16 23:32:00 UTC 2010


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. 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)
}

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
>
>



More information about the Squeak-dev mailing list