On Fri, Nov 19, 2010 at 10:15 AM, Mariano Martinez Peck <marianopeck@gmail.com> wrote:


On Wed, Nov 17, 2010 at 1:13 AM, Eliot Miranda <eliot.miranda@gmail.com> wrote:


On Tue, Nov 16, 2010 at 3:32 PM, Levente Uzonyi <leves@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.  

Hi Eliot. I have just read the whole thread, but I wanted to ask you something about this line. Did I understand correct??  If #= has already been jitted, then Gog doesn't use the short-circuit sends (#bytecodePrimEqual) but it does a normal send (a primitive in this case)?  So...suppose I change SmallInteger >> #=   and I put a halt, then if will be halted (and broke everything, of course) once that method was jitted ?

Yes, that's right; since in Cog jitted code #= is always sent if you put a breakpoint in SmallInteger>#= execution will hit the break-point, unlike in the interpreter.  
 
And I guess the same happens with all special selectors.

Thanks

Mariano

 
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