compiler optimizations get in the way?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

compiler optimizations get in the way?

Dave & Vicki Stevenson
I've written the following method:

Date>>to: anObject do: aBlock
     "For each date in the interval from the receiver up to the
argument, incrementing by 1 day, evaluate aBlock.

     Date today to: (Date today addDays: 4) do: [:date | Transcript cr;
show: date displayString]
     "

     ^self asDays
         to: anObject asDate asDays
         do: [:days | aBlock cull: (self class fromDays: days)]

But it raises an exception and I cannot debug it. I suspect it's because
Number>>to:do: is inlined, or some other compiler optimization. But why
should compiler tricks for Number>>to:do: interfere with Date>>to:do:?

--
[hidden email]

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: compiler optimizations get in the way?

Boris Popov, DeepCove Labs (SNN)
Dave,

Throw a breakpoint here when you compile your Date>>to:do: and you'll notice that the node satisfies the requirement for optimization,

transformToDo

        ^(self testLiteralBlock: 1 at: 2)
                ifTrue: [arguments last
                                arithmeticLoopFrom: receiver
                                by: (LiteralNode new value: 1)
                                to: arguments first
                                from: self]
                ifFalse: [nil]

-Boris


-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On Behalf Of Dave
Sent: Monday, February 11, 2013 1:57 PM
To: VWNC
Subject: [vwnc] compiler optimizations get in the way?

I've written the following method:

Date>>to: anObject do: aBlock
     "For each date in the interval from the receiver up to the argument, incrementing by 1 day, evaluate aBlock.

     Date today to: (Date today addDays: 4) do: [:date | Transcript cr;
show: date displayString]
     "

     ^self asDays
         to: anObject asDate asDays
         do: [:days | aBlock cull: (self class fromDays: days)]

But it raises an exception and I cannot debug it. I suspect it's because
Number>>to:do: is inlined, or some other compiler optimization. But why
should compiler tricks for Number>>to:do: interfere with Date>>to:do:?

--
[hidden email]

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: compiler optimizations get in the way?

Martin McClure-3
In reply to this post by Dave & Vicki Stevenson
On 02/11/2013 10:56 AM, Dave wrote:
>  But why
> should compiler tricks for Number>>to:do: interfere with Date>>to:do:?
>

It's not just compiler tricks, #to:do: and the like are actually
reserved selectors in most Smalltalk implementations and any method
implemented with a reserved selector will never be invoked (except,
typically, through #perform:). This practice dates back to Smalltalk-80
(if not before) but is somewhat unfortunate in that it introduces
inconsistencies into the language that lead to unexpected results like
those you encountered.

Regards,

-Martin
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: compiler optimizations get in the way?

Terry Raymond
In reply to this post by Dave & Vicki Stevenson
Alternatively, you could write your own DateInterval and do;
(Date today to: (Date today addDays: 4)) do: [:date | ... ].

Do (1 to: 4) inspect. This will create an interval. An interval  understands
#do:
You could create a similar Date interval.

Terry

===========================================================
Terry Raymond
Crafted Smalltalk
80 Lazywood Ln.
Tiverton, RI  02878
(401) 624-4517      [hidden email]
===========================================================

> -----Original Message-----
> From: [hidden email] [mailto:[hidden email]] On
> Behalf Of Dave
> Sent: Monday, February 11, 2013 1:57 PM
> To: VWNC
> Subject: [vwnc] compiler optimizations get in the way?
>
> I've written the following method:
>
> Date>>to: anObject do: aBlock
>      "For each date in the interval from the receiver up to the argument,
> incrementing by 1 day, evaluate aBlock.
>
>      Date today to: (Date today addDays: 4) do: [:date | Transcript cr;
> show: date displayString]
>      "
>
>      ^self asDays
>          to: anObject asDate asDays
>          do: [:days | aBlock cull: (self class fromDays: days)]
>
> But it raises an exception and I cannot debug it. I suspect it's because
> Number>>to:do: is inlined, or some other compiler optimization. But why
> should compiler tricks for Number>>to:do: interfere with Date>>to:do:?
>
> --
> [hidden email]
>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc



_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: compiler optimizations get in the way?

Dave Stevenson-3
Thanks to all who replied.

So the problem is not that my implementation of Date>>to:do: is
optimized, but that any code trying to call Date>>to:do: (like the usage
example in the method comment) gets optimized by
#arithmeticLoopFrom:by:to:from:, based solely on the fact that the do:
block has one argument. Too bad the optimization cannot take into
account the type of the receiver, but that's not always known at compile
time.

I've looked at:
     MessageNode class>>initialize
     ImplementationLimits7x.pdf - "Open-coded Blocks" and
"Non-verridable Methods"

and inspecting the optimized client code shows that it gets implemented
as a #whileTrue: loop.

I could override #transformToDo to do nothing if a special
characteristic is found for the do block. I don't think method pragmas
can be used in blocks. A test as to whether '*date*' matches the name of
the block parameter would break blocks with parameters named
'dateIndex', or some such, and any client code that did not remember to
spell the block argument properly would break. So the only reliable way
that comes to mind is to give the block an extra unused argument, which
does not seem desirable at all.

I cannot see a good way to reuse the api (#to:do:), which is unfortunate
since it is so easy to remember. I think I'd be more likely to remember
a different api (Date>>through:do:, or something) than remember the
extra parentheses required by the use of a DateInterval. Still, it would
be nice if there were a way to selectively avoid optimization.

Maybe #toDate:do: would be a good alternative. It should be easy to
remember that any alternate implementations of #to:do: requires the
expected type as part of the first keyword.

Dave

[hidden email]

On 2/11/2013 12:00 PM, Terry Raymond wrote:

> Alternatively, you could write your own DateInterval and do;
> (Date today to: (Date today addDays: 4)) do: [:date | ... ].
>
> Do (1 to: 4) inspect. This will create an interval. An interval  understands
> #do:
> You could create a similar Date interval.
>
> Terry
>
> ===========================================================
> Terry Raymond
> Crafted Smalltalk
> 80 Lazywood Ln.
> Tiverton, RI  02878
> (401) 624-4517      [hidden email]
> ===========================================================
>
>> -----Original Message-----
>> From: [hidden email] [mailto:[hidden email]] On
>> Behalf Of Dave
>> Sent: Monday, February 11, 2013 1:57 PM
>> To: VWNC
>> Subject: [vwnc] compiler optimizations get in the way?
>>
>> I've written the following method:
>>
>> Date>>to: anObject do: aBlock
>>       "For each date in the interval from the receiver up to the argument,
>> incrementing by 1 day, evaluate aBlock.
>>
>>       Date today to: (Date today addDays: 4) do: [:date | Transcript cr;
>> show: date displayString]
>>       "
>>
>>       ^self asDays
>>           to: anObject asDate asDays
>>           do: [:days | aBlock cull: (self class fromDays: days)]
>>
>> But it raises an exception and I cannot debug it. I suspect it's because
>> Number>>to:do: is inlined, or some other compiler optimization. But why
>> should compiler tricks for Number>>to:do: interfere with Date>>to:do:?
>>
>> --
>> [hidden email]
>>
>> _______________________________________________
>> vwnc mailing list
>> [hidden email]
>> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: compiler optimizations get in the way?

Nicolas Cellier
Dave Stevenson <dave.stevenson <at> pacbell.net> writes:

>
> Thanks to all who replied.
>
> So the problem is not that my implementation of Date>>to:do: is
> optimized, but that any code trying to call Date>>to:do: (like the usage
> example in the method comment) gets optimized by
> #arithmeticLoopFrom:by:to:from:, based solely on the fact that the do:
> block has one argument. Too bad the optimization cannot take into
> account the type of the receiver, but that's not always known at compile
> time.
>
> I've looked at:
>      MessageNode class>>initialize
>      ImplementationLimits7x.pdf - "Open-coded Blocks" and
> "Non-verridable Methods"
>
> and inspecting the optimized client code shows that it gets implemented
> as a #whileTrue: loop.
>
> I could override #transformToDo to do nothing if a special
> characteristic is found for the do block. I don't think method pragmas
> can be used in blocks. A test as to whether '*date*' matches the name of
> the block parameter would break blocks with parameters named
> 'dateIndex', or some such, and any client code that did not remember to
> spell the block argument properly would break. So the only reliable way
> that comes to mind is to give the block an extra unused argument, which
> does not seem desirable at all.
>
> I cannot see a good way to reuse the api (#to:do:), which is unfortunate
> since it is so easy to remember. I think I'd be more likely to remember
> a different api (Date>>through:do:, or something) than remember the
> extra parentheses required by the use of a DateInterval. Still, it would
> be nice if there were a way to selectively avoid optimization.
>
> Maybe #toDate:do: would be a good alternative. It should be easy to
> remember that any alternate implementations of #to:do: requires the
> expected type as part of the first keyword.
>
> Dave
>
> dave.stevenson <at> pacbell.net
>

Note that you can also send a message to the block argument, for example

1 to: 4 do: [:i | i inspect] yourself.

will generate a compile-time warning in VW, but then compile a simple
un-optimized #to:do: send.

Instead of #yourself, we could as well define a [ ] unoptimized, which is IMO
not worse than a method annotation (pragma).

I don't especially recommend using this hack, it's far from ideal, but it's
always good to know.

Note that the hack works in Squeak too (and probably Pharo).

Nicolas


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Fwd: compiler optimizations get in the way?

Eliot Miranda-2
In reply to this post by Dave Stevenson-3


---------- Forwarded message ----------
From: Eliot Miranda <[hidden email]>
Date: Mon, Feb 11, 2013 at 1:44 PM
Subject: Re: [vwnc] compiler optimizations get in the way?
To: Dave Stevenson <[hidden email]>


Hi Dave,

    you to:do: loop

     ^self asDays
          to: anObject asDate asDays
          do: [:days | aBlock cull: (self class fromDays: days)]

is being compiled to something equivalent to

    days := tmpresult := self asDays.
    tmplimit := anObject asDate asDays.
    [days <= tmplimit] whileTrue:
        [aBlock cull: (self class fromDays: days).
         days := days + 1].
    ^ tmpresult

where tmplimit and tmpresult are compiler-introduced temporaries.

If you make your asDays object polymorphic with Integer for arithmetic (i.e. that aDay + anInteger is equivalent to aDay addDays: anInteger) then your loop may work.  Anyway, worth a try.


You might also find that the problem is actualy your returning the result of the loop.

What happens if you write
    self asDays
          to: anObject asDate asDays
          do: [:days | aBlock cull: (self class fromDays: days)].
    ^self asDays
?

On Mon, Feb 11, 2013 at 12:47 PM, Dave Stevenson <[hidden email]> wrote:
Thanks to all who replied.

So the problem is not that my implementation of Date>>to:do: is optimized, but that any code trying to call Date>>to:do: (like the usage example in the method comment) gets optimized by #arithmeticLoopFrom:by:to:from:, based solely on the fact that the do: block has one argument. Too bad the optimization cannot take into account the type of the receiver, but that's not always known at compile time.

I've looked at:
    MessageNode class>>initialize
    ImplementationLimits7x.pdf - "Open-coded Blocks" and "Non-verridable Methods"

and inspecting the optimized client code shows that it gets implemented as a #whileTrue: loop.

I could override #transformToDo to do nothing if a special characteristic is found for the do block. I don't think method pragmas can be used in blocks. A test as to whether '*date*' matches the name of the block parameter would break blocks with parameters named 'dateIndex', or some such, and any client code that did not remember to spell the block argument properly would break. So the only reliable way that comes to mind is to give the block an extra unused argument, which does not seem desirable at all.

I cannot see a good way to reuse the api (#to:do:), which is unfortunate since it is so easy to remember. I think I'd be more likely to remember a different api (Date>>through:do:, or something) than remember the extra parentheses required by the use of a DateInterval. Still, it would be nice if there were a way to selectively avoid optimization.

Maybe #toDate:do: would be a good alternative. It should be easy to remember that any alternate implementations of #to:do: requires the expected type as part of the first keyword.

Dave

[hidden email]

On 2/11/2013 12:00 PM, Terry Raymond wrote:
Alternatively, you could write your own DateInterval and do;
(Date today to: (Date today addDays: 4)) do: [:date | ... ].

Do (1 to: 4) inspect. This will create an interval. An interval  understands
#do:
You could create a similar Date interval.

Terry

===========================================================
Terry Raymond
Crafted Smalltalk
80 Lazywood Ln.
Tiverton, RI  02878
<a href="tel:%28401%29%20624-4517" value="+14016244517" target="_blank">(401) 624-4517      [hidden email]
===========================================================

-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On
Behalf Of Dave
Sent: Monday, February 11, 2013 1:57 PM
To: VWNC
Subject: [vwnc] compiler optimizations get in the way?

I've written the following method:

Date>>to: anObject do: aBlock
      "For each date in the interval from the receiver up to the argument,
incrementing by 1 day, evaluate aBlock.

      Date today to: (Date today addDays: 4) do: [:date | Transcript cr;
show: date displayString]
      "

      ^self asDays
          to: anObject asDate asDays
          do: [:days | aBlock cull: (self class fromDays: days)]

But it raises an exception and I cannot debug it. I suspect it's because
Number>>to:do: is inlined, or some other compiler optimization. But why
should compiler tricks for Number>>to:do: interfere with Date>>to:do:?

--
[hidden email]

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc



--
best,
Eliot



--
best,
Eliot

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: compiler optimizations get in the way?

Michael Klein
OK, it's kind of flaky silently coercing Integers and Duartions.
wouldn't it be better to use Chronos?
But, the below code does the trick.

-- Mike


===
workspace
Date today to: (Date today addDays: 2) do: [ :date | Transcript print: date; cr].
===
Core.Integer methods for 'converting'

asDuration
^Duration fromDays: self
===
Core.Date methods for 'arithmetic'

+ aDuration
^self sumFromDuration: aDuration asDuration


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Fwd: Fwd: compiler optimizations get in the way?

Eliot Miranda-2


---------- Forwarded message ----------
From: Eliot Miranda <[hidden email]>
Date: Mon, Feb 11, 2013 at 1:55 PM
Subject: Re: [vwnc] Fwd: compiler optimizations get in the way?
To: Michael Klein <[hidden email]>




On Mon, Feb 11, 2013 at 1:52 PM, Michael Klein <[hidden email]> wrote:
OK, it's kind of flaky silently coercing Integers and Duartions.

Yes, if

     self asDays class = self asYears class

because then + 1 is meaningless.  But if self asDays is a thing that knows its units are days and self asYears (etc) answers a thing that knows its units are years then no, I don't think its flakey, I think its convenient.

But I'm not advocating.  I'm just trying to help Dave understand what's going on.
 
wouldn't it be better to use Chronos?
But, the below code does the trick.

-- Mike


===
workspace
Date today to: (Date today addDays: 2) do: [ :date | Transcript print: date; cr].
===
Core.Integer methods for 'converting'

asDuration
^Duration fromDays: self
===
Core.Date methods for 'arithmetic'

+ aDuration
^self sumFromDuration: aDuration asDuration




--
best,
Eliot



--
best,
Eliot

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc