[Pharo-project] x4 difference between #to:do: and #timesRepeat - bug ?
Hi, I noticed quite a difference between the two method who "looks" the same to me. Is it normal ? I use a rc image (haven't tested in squeak). And it's the same on windows and linux. count := 0. [1 to: 10000000 do: [:i | count :=count + 1]] timeToRun." 677" count := 0. [10000000 timesRepeat: [count := count + 1]] timeToRun" 2571" If not normal, I'll open a issue. Thanks -- Cédrick
On Nov 13, 2009, at 9:51 AM, Cédrick Béler wrote:
Hi,
I noticed quite a difference between the two method who "looks" the same to me. Is it normal ?
Normal. to:do: is lnlined (compiled as jumps in the bytecode), whereas timesRepeat: is a message send with a closure activation. Marcus fun is the difference between: (1 to : 10000) do: and 1 to: 10000 do: one is compiled to jumps, the other not and in addition creates a temp collection. Marcus
I use a rc image (haven't tested in squeak). And it's the same on windows and linux.
count := 0. [1 to: 10000000 do: [:i | count :=count + 1]] timeToRun." 677" count := 0. [10000000 timesRepeat: [count := count + 1]] timeToRun" 2571"
If not normal, I'll open a issue.
Thanks
-- Cédrick _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Results for VisualAge (just FYI): | count | count := 0. [1 to: 10000000 do: [:i | count :=count + 1]] timeToRun. "151702" | count | count := 0. [10000000 timesRepeat: [count := count + 1]] timeToRun. "139971" (results are in microseconds) So maybe there's a case for inlining #timesRepeat: (or making a clear comment that it is much slower in Pharo) Just my $0:02 -- Cheers, Peter On Fri, Nov 13, 2009 at 9:59 AM, Marcus Denker <denker@acm.org> wrote:
On Nov 13, 2009, at 9:51 AM, Cédrick Béler wrote:
Hi,
I noticed quite a difference between the two method who "looks" the same to me. Is it normal ?
Normal. to:do: is lnlined (compiled as jumps in the bytecode), whereas timesRepeat: is a message send with a closure activation.
Marcus
fun is the difference between:
(1 to : 10000) do: and 1 to: 10000 do:
one is compiled to jumps, the other not and in addition creates a temp collection.
Marcus
I use a rc image (haven't tested in squeak). And it's the same on windows and linux.
count := 0. [1 to: 10000000 do: [:i | count :=count + 1]] timeToRun." 677" count := 0. [10000000 timesRepeat: [count := count + 1]] timeToRun" 2571"
If not normal, I'll open a issue.
Thanks
-- Cédrick _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
On Nov 13, 2009, at 10:05 AM, Peter Hugosson-Miller wrote:
Results for VisualAge (just FYI):
| count | count := 0. [1 to: 10000000 do: [:i | count :=count + 1]] timeToRun. "151702"
| count | count := 0. [10000000 timesRepeat: [count := count + 1]] timeToRun. "139971"
(results are in microseconds)
So maybe there's a case for inlining #timesRepeat: (or making a clear comment that it is much slower in Pharo)
In general inlining is evil ;-) timesRepeat for the special case of being send to an int, detected statically... maybe I could be convinced of that. But in general, what would be much nicer would be to do it based on type-feedback information nicely hidden so nobody sees it. Marcus
There is also a difference between: [self atEnd ifTrue: [^nil]. self next. true] whileTrue. and: [self atEnd ifTrue: [^nil] self next] repeat. Warning: it's quite easy to add Compiler inlining rules, a bit tougher to add corresponding Decompiler tricks. 2009/11/13 Marcus Denker <denker@acm.org>:
On Nov 13, 2009, at 9:51 AM, Cédrick Béler wrote:
Hi,
I noticed quite a difference between the two method who "looks" the same to me. Is it normal ?
Normal. to:do: is lnlined (compiled as jumps in the bytecode), whereas timesRepeat: is a message send with a closure activation.
    Marcus
fun is the difference between:
    (1 to : 10000) do: and     1 to: 10000 do:
one is compiled to jumps, the other not and in addition creates a temp collection.
    Marcus
I use a rc image (haven't tested in squeak). And it's the same on windows and linux.
count := 0. [1 to: 10000000 do: [:i | count :=count + 1]] timeToRun." 677" count := 0. [10000000 timesRepeat: [count := count + 1]] timeToRun" 2571"
If not normal, I'll open a issue.
Thanks
-- Cédrick _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
No, please no more inilining hacks. :) If someone wants to run everything at light speed - just code in C, but leave smalltalk honoring the message passing. And besides, these tricks won't make any difference when having good inlining JIT. In bytecode, they just add a complexity to compiler and headache to developers. 2009/11/13 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
There is also a difference between:
[self atEnd ifTrue: [^nil]. self next. true] whileTrue.
and:
[self atEnd ifTrue: [^nil] self next] repeat.
Warning: it's quite easy to add Compiler inlining rules, a bit tougher to add corresponding Decompiler tricks.
2009/11/13 Marcus Denker <denker@acm.org>:
On Nov 13, 2009, at 9:51 AM, Cédrick Béler wrote:
Hi,
I noticed quite a difference between the two method who "looks" the same to me. Is it normal ?
Normal. to:do: is lnlined (compiled as jumps in the bytecode), whereas timesRepeat: is a message send with a closure activation.
    Marcus
fun is the difference between:
    (1 to : 10000) do: and     1 to: 10000 do:
one is compiled to jumps, the other not and in addition creates a temp collection.
    Marcus
I use a rc image (haven't tested in squeak). And it's the same on windows and linux.
count := 0. [1 to: 10000000 do: [:i | count :=count + 1]] timeToRun." 677" count := 0. [10000000 timesRepeat: [count := count + 1]] timeToRun" 2571"
If not normal, I'll open a issue.
Thanks
-- Cédrick _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- Best regards, Igor Stasenko AKA sig.
No, please no more inilining hacks. :)
If someone wants to run everything at light speed - just code in C, but leave smalltalk honoring the message passing. And besides, these tricks won't make any difference when having good inlining JIT. In bytecode, they just add a complexity to compiler and headache to developers.
I agree but I asked beacause I'll make student use this method and wasn't sure of the explanation. Also, some asked me about the performance of Pharo/Smalltalk in general. I did this counter in C++ and Smalltalk. I get a 10x difference between C++ and Pharo, the inlined version, and therefore a 40x whith the other one. So does this number seems reasonnably true to you ? What would be the order of magnitude with a JIT ? TIA, Cédrick
2009/11/13 Cédrick Béler <cdrick65@gmail.com>:
No, please no more inilining hacks. :) If someone wants to run everything at light speed - just code in C, but leave smalltalk honoring the message passing. And besides, these tricks won't make any difference when having good inlining JIT. In bytecode, they just add a complexity to compiler and headache to developers.
I agree but I asked beacause I'll make student use this method and wasn't sure of the explanation.
Also, some asked me about the performance of Pharo/Smalltalk in general.
I did this counter in C++ and Smalltalk.
I get a 10x difference between C++ and Pharo, the inlined version, and therefore a 40x whith the other one.
So does this number seems reasonnably true to you ?
You are counting wrong numbers. Please count the time you have to spend to interpret closures in C++, and then using them run arbitrary code in the loop, then we will talk again when you done :)
What would be the order of magnitude with a JIT ?
TIA,
Cédrick
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- Best regards, Igor Stasenko AKA sig.
"Igor" == Igor Stasenko <siguctua@gmail.com> writes:
Igor> You are counting wrong numbers. Please count the time you have to spend Igor> to interpret closures in C++, and then using them run arbitrary code Igor> in the loop, Igor> then we will talk again when you done :) As we used to say in the C vs Perl debate: "Compared to Perl, C will give you the answer faster, but far later." :-) -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/> Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc. See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion
Igor Stasenko wrote:
No, please no more inilining hacks. :) If someone wants to run everything at light speed - just code in C, but leave smalltalk honoring the message passing. And besides, these tricks won't make any difference when having good inlining JIT. In bytecode, they just add a complexity to compiler and headache to developers.
+64 to banning bytecode compiler hacks and instead concentrate on producing an inlining JIT. -Martin
2009/11/13 Martin McClure <martin@hand2mouse.com>:
Igor Stasenko wrote:
No, please no more inilining hacks. :) If someone wants to run everything at light speed - just code in C, but leave smalltalk honoring the message passing. And besides, these tricks won't make any difference when having good inlining JIT. In bytecode, they just add a complexity to compiler and headache to developers.
+64 to banning bytecode compiler hacks and instead concentrate on producing an inlining JIT.
-Martin
The former is very easy, ugly and cheap. The later neither is easy nor cheap, and i doubt many of us will concentrate on this. Unless "concentrate" means "wait for Eliot's changes and pray". This can be reformulated as "don't bother on such details untill then". ;) Nicolas
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
On Nov 13, 2009, at 7:24 PM, Nicolas Cellier wrote:
The former is very easy, ugly and cheap.
yes. Ugly. And even wrong. I remember when I tried to explain a die-hard compiler researcher how the "optimizations" of #ifTrue: and friends work in Smalltalk...
The later neither is easy nor cheap, and i doubt many of us will concentrate on this. Unless "concentrate" means "wait for Eliot's changes and pray".
:-) I did once do some work on Eliot's AOStA. I plan to work on resurrecting that, soon. Marcus -- Marcus Denker -- denker@acm.org http://www.marcusdenker.de
On Fri, 2009-11-13 at 09:13 -0800, Martin McClure wrote:
Igor Stasenko wrote:
No, please no more inilining hacks. :) If someone wants to run everything at light speed - just code in C, but leave smalltalk honoring the message passing. And besides, these tricks won't make any difference when having good inlining JIT. In bytecode, they just add a complexity to compiler and headache to developers.
+64 to banning bytecode compiler hacks and instead concentrate on producing an inlining JIT.
I'm working on inlining in Exupery now. The first three basic tests pass. Bryce
Thanks all. Interesting. I saw by using tallySends that: timesRepeat: This simulation took 6.0 seconds. **Tree** 1 SmallInteger(Integer)>>timesRepeat: **Leaves** 100001 UndefinedObject>>DoIt 1 SmallInteger(Integer)>>timesRepeat: 1 UndefinedObject>>DoIt to:do: This simulation took 3.0 seconds. **Tree** **Leaves** 1 UndefinedObject>>DoIt I guess this is one consequence of being inlined. This makes ask another questions: -how to know what's inlined, what method have suche properties (a comment would be cool, so if we had to choose...) ? -how to add Compiler inlining rules (as it's easy ;) ) ? -why not inlining timesRepeat: (as I guess we don't really change it often) ? Thanks. ps: the result is slow because I used a 5 year old (at least) computer :). I think I got a 10x difference in a 2 year one... 2009/11/13 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>
There is also a difference between:
[self atEnd ifTrue: [^nil]. self next. true] whileTrue.
and:
[self atEnd ifTrue: [^nil] self next] repeat.
Warning: it's quite easy to add Compiler inlining rules, a bit tougher to add corresponding Decompiler tricks.
2009/11/13 Marcus Denker <denker@acm.org>:
On Nov 13, 2009, at 9:51 AM, Cédrick Béler wrote:
Hi,
I noticed quite a difference between the two method who "looks" the same
to me. Is it normal ?
Normal. to:do: is lnlined (compiled as jumps in the bytecode), whereas timesRepeat: is a message send with a closure activation.
Marcus
fun is the difference between:
(1 to : 10000) do: and 1 to: 10000 do:
one is compiled to jumps, the other not and in addition creates a temp collection.
Marcus
I use a rc image (haven't tested in squeak). And it's the same on windows and linux.
count := 0. [1 to: 10000000 do: [:i | count :=count + 1]] timeToRun." 677" count := 0. [10000000 timesRepeat: [count := count + 1]] timeToRun" 2571"
If not normal, I'll open a issue.
Thanks
-- Cédrick _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- Cédrick
+1 for making an inlined version of #timesRepeat: Sometimes speed matters, and for someone coming from an environment where it's faster than #to:do: it might not be so easy to detect where the unexpected time penalty came from. Unfortunately, I'm not sufficiently familiar with the Compiler/Decompiler to volunteer to do it myself :-p And to answer Cédrick's question, browsing senders of a method should tell you if it's inlined of not. In VA there are no senders of #timesRepeat: or #to:do, although both are used extensively. In case anyone is interested, here is the complete list of inlined methods in VA #== #~~ #and: #ifFalse: #ifFalse:ifTrue: #ifTrue: #ifTrue:ifFalse: #isNil #not #notNil #or: #timesRepeat: #to:do: #whileFalse: #whileTrue: How does it compare to Pharo? -- Cheers, Peter 2009/11/13 Cédrick Béler <cdrick65@gmail.com>
Thanks all.
Interesting. I saw by using tallySends that:
timesRepeat: This simulation took 6.0 seconds. **Tree** 1 SmallInteger(Integer)>>timesRepeat:
**Leaves** 100001 UndefinedObject>>DoIt 1 SmallInteger(Integer)>>timesRepeat: 1 UndefinedObject>>DoIt
to:do: This simulation took 3.0 seconds. **Tree**
**Leaves** 1 UndefinedObject>>DoIt
I guess this is one consequence of being inlined.
This makes ask another questions:
-how to know what's inlined, what method have suche properties (a comment would be cool, so if we had to choose...) ? -how to add Compiler inlining rules (as it's easy ;) ) ? -why not inlining timesRepeat: (as I guess we don't really change it often) ?
Thanks.
ps: the result is slow because I used a 5 year old (at least) computer :). I think I got a 10x difference in a 2 year one...
2009/11/13 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>
There is also a difference between:
[self atEnd ifTrue: [^nil]. self next. true] whileTrue.
and:
[self atEnd ifTrue: [^nil] self next] repeat.
Warning: it's quite easy to add Compiler inlining rules, a bit tougher to add corresponding Decompiler tricks.
2009/11/13 Marcus Denker <denker@acm.org>:
On Nov 13, 2009, at 9:51 AM, Cédrick Béler wrote:
Hi,
I noticed quite a difference between the two method who "looks" the
same to me. Is it normal ?
Normal. to:do: is lnlined (compiled as jumps in the bytecode), whereas timesRepeat: is a message send with a closure activation.
Marcus
fun is the difference between:
(1 to : 10000) do: and 1 to: 10000 do:
one is compiled to jumps, the other not and in addition creates a temp collection.
Marcus
I use a rc image (haven't tested in squeak). And it's the same on windows and linux.
count := 0. [1 to: 10000000 do: [:i | count :=count + 1]] timeToRun." 677" count := 0. [10000000 timesRepeat: [count := count + 1]] timeToRun" 2571"
If not normal, I'll open a issue.
Thanks
-- Cédrick _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- Cédrick
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- Cheers, Peter
How does it compare to Pharo?
ifTrue: ifFalse: ifTrue:ifFalse: ifFalse:ifTrue: and: or: whileFalse: whileTrue: whileFalse whileTrue to:do: to:by:do: caseOf: caseOf:otherwise: ifNil: ifNotNil: ifNil:ifNotNil: ifNotNil:ifNil: See MessageNode for details. Lukas -- Lukas Renggli http://www.lukas-renggli.ch
participants (9)
-
Bryce Kampjes -
Cédrick Béler -
Igor Stasenko -
Lukas Renggli -
Marcus Denker -
Martin McClure -
merlyn@stonehenge.com -
Nicolas Cellier -
Peter Hugosson-Miller