What performance increases can we expect as the Perl 6 implementations mature?

Each time I have downloaded a new copy of Rakudo Perl 6, I have run the following expression just to get an idea of its current performance:

say [+] 1 .. 100000;

And the speeds have been increasing, but each time, there is a noticeable delay (several seconds) for the calculation. As a comparison, something like this in Perl 5 (or other interpreted languages) returns almost instantly:

use List::Util 'sum';

print sum(1 .. 100000), "\n";

or in Ruby (also nearly instant):

(1 .. 100000).inject(0) {|sum,x| sum+x}

Rewriting the expression as a Perl6 loop ends up being about twice as fast as reducing the range, but it is still a very noticeable delay (more than a second) for the simple calculation:

my $sum;
loop (my $x = 1; $x <= 100000; $x++) {$sum += $x}

So my question is, what aspects of the Perl6 implementation are causing these performance issues? And should this improve with time, or is this overhead an unfortunate side effect of the "everything is an object" model that Perl6 is using?

And lastly, what about the loop construct is faster than the [+] reduction operator? I would think that the loop would result in more total ops than the reduction.

EDIT:

I'd accept both mortiz's and hobbs's answers if I could. That everything is a being handled as a method call more directly answers why [+] is being slow, so that one gets it.

Answers


Another thing you have to understand about the lack of optimization is that it's compounded. A large portion of Rakudo is written in Perl 6. So for example the [+] operator is implemented by the method Any.reduce (called with $expression set to &infix:<+>), which has as its inner loop

for @.list {
    @args.push($_);
    if (@args == $arity) {
        my $res = $expression.(@args[0], @args[1]);
        @args = ($res);
    }
}

in other words, a pure-perl implementation of reduce, which itself is being run by Rakudo. So not only is the code you can see not getting optimized, the code that you don't see that's making your code run is also not getting optimized. Even instances of the + operator are actually method calls, since although the + operator on Num is implemented by Parrot, there's nothing yet in Rakudo to recognize that you've got two Nums and optimize away the method call, so there's a full dynamic dispatch before Rakudo finds multi sub infix:<+>(Num $a, Num $b) and realizes that all it's really doing is an 'add' opcode. It's a reasonable excuse for being 100-1000x slower than Perl 5 :)

Update 8/23/2010

More information from Jonathan Worthington on the kinds of changes that need to happen with the Perl 6 object model (or at least Rakudo's conception of it) to make things fast while retaining Perl 6's "everything is method calls" nature.

Update 1/10/2019

Since I can see that this is still getting attention... over the years, Rakudo/MoarVM have gotten JIT, inlining, dynamic specialization, and tons of work by many people optimizing every part of the system. The result is that most of those method calls can be "compiled out" and have nearly zero runtime cost. Perl 6 scores hundreds or thousands of times faster on many benchmarks than it did in 2010, and in some cases it's faster than Perl 5.

In the case of the sum-to-100,000 problem that the question started with, Rakudo 2018.06 is still a bit slower than perl 5.26.2:

$ time perl -e 'use List::Util 'sum'; print sum(1 .. 100000), "\n";' >/dev/null

real    0m0.023s
user    0m0.015s
sys     0m0.008s

$ time perl6 -e 'say [+] 1 .. 100000;' >/dev/null

real    0m0.089s
user    0m0.107s
sys     0m0.022s

But if we amortize out startup cost by running the code 10,000 times, we see a different story:

$ time perl -e 'use List::Util 'sum'; for (1 .. 10000) { print sum(1 .. 100000), "\n"; }' > /dev/null

real    0m16.320s
user    0m16.317s
sys     0m0.004s

$ time perl6 -e 'for 1 .. 10000 { say [+] 1 .. 100000; }' >/dev/null

real    0m0.214s
user    0m0.245s
sys     0m0.021s

perl6 uses a few hundred more milliseconds than perl5 on startup and compilation, but then it figures out how to do the actual summation around 70 times faster.


There are really various reasons why Rakudo is so slow.

The first and maybe most important reason is that Rakudo doesn't do any optimizations yet. The current goals are more explore new features, and to become more robust. You know, they say "first make it run, then make it right, then make it fast".

The second reason is that parrot doesn't offer any JIT compilation yet, and the garbage collector isn't the fastest. There are plans for a JIT compiler, and people are working on it (the previous one was ripped out because it was i386 only and a maintenance nightmare). There are also thoughts of porting Rakudo to other VMs, but that'll surely wait till after end of July.

In the end, nobody can really tell how fast a complete, well-optimized Perl 6 implementation will be until we have one, but I do expect it to be much better than now.

BTW the case you cited [+] 1..$big_number could be made to run in O(1), because 1..$big_number returns a Range, which is introspectable. So you can use a sum formula for the [+] Range case. Again it's something that could be done, but that hasn't been done yet.


It certainly isn't because everything is an object, because that's true in a number of other languages too (like Ruby). There's no reason why Perl 6 would have to be magnitudes slower than other languages like Perl 5 or Ruby, but the fact is that Rakudo is not as mature as perl or CRuby. There hasn't been much speed optimization yet.


Considering that now your test case is optimized to an O(1) algorithm that returns nearly instantly, and that it seems almost like there are several optimizations a week; I expect quite an performance improvement all around.

$ perl6 -e 'say [+] 1..10**1000; say now - INIT now'
5000000000000000000000000000000000000000000000 ...
0.007447

Even if that wasn't special-cased for ranges it is still quite a bit faster than it was. It now does your test calculation in less than a fifth of a second.

$ perl6 -e 'say [+] (1..100000).list; say now - INIT now'
5000050000
0.13052975

I submitted these to Fefe's language competition in December 2008. wp.pugs.pl is a literal translation of the Perl 5 example, wp.rakudo.pl is far more sixier. I have two programs because the two implement a different subset of the spec. Build information is outdated meanwhile. The sources:

#!/usr/bin/env pugs
# Pugs: <http://pugs.blogs.com/> <http://pugscode.org/>
# prerequisite: ghc-6.8.x, not 6.10.x
# svn co http://svn.pugscode.org/pugs/
# perl Makefile.PL
# make
# if build stops because of haskeline, do:
#   $HOME/.cabal/bin/cabal update ; $HOME/.cabal/bin/cabal install haskeline

# learn more: <http://jnthn.net/papers/2008-tcpw-perl64danoob-slides.pdf>

my %words;

for =<> {
    for .split {
        %words{$_}++
    }
}

for (sort { %words{$^b} <=> %words{$^a} }, %words.keys) {
    say "$_ %words{$_}"
}

#!/usr/bin/env perl6
# Rakudo: <http://rakudo.org/> <http://www.parrot.org/download>
# svn co http://svn.perl.org/parrot/trunk parrot
# perl Configure.pl
# make perl6

# Solution contributed by Frank W. & Moritz Lenz
# <http://use.perl.org/~fw/journal/38055>
# learn more: <http://jnthn.net/papers/2008-tcpw-perl64danoob-slides.pdf>

my %words;

$*IN.lines.split(/\s+/).map: { %words{$_}++ };

for %words.pairs.sort: { $^b.value <=> $^a.value } -> $pair {
    say $pair
}

These were the results in 2008:

$ time ./wp.pugs.pl < /usr/src/linux/COPYING > foo

real    0m2.529s
user    0m2.464s
sys     0m0.064s

$ time ./wp.rakudo.pl < /usr/src/linux/COPYING > foo

real    0m32.544s
user    0m1.920s
sys     0m0.248s

Today:

$ time ./wp.pugs.pl < /usr/src/linux/COPYING > foo

real    0m5.105s
user    0m4.898s
sys     0m0.096s

$ time ./wp.rakudo.pl < /usr/src/linux/COPYING > foo
Divide by zero
current instr.: '' pc -1 ((unknown file):-1)
Segmentation fault

real    0m3.236s
user    0m0.447s
sys     0m0.080s

Late additions: The crash has been dealt with at Why do I get 'divide by zero` errors when I try to run my script with Rakudo?. The Rakudo program is inefficient, see comments below and http://justrakudoit.wordpress.com/2010/06/30/rakudo-and-speed/.


Need Your Help

Angular JS identify an digest complete event and removing # from url in angular js during viewchange

javascript angularjs kineticjs

1) Is there any digest complete event which I can use to update my canvas. I have an angular app which has view for different properties of the canvas object. Whenever I change the property, once the

Is it bad design to use table tags when displaying forms in html?

html css forms layout

I keep hearing that div tags should be used for layout purposes and not table tags. So does that also apply to form layout? I know a form layout is still a layout, but it seems like creating form l...