🔬36. Rakudo 2018.01

A new release of Rakudo was just announced. Most of the changes increase Perl 6 performance this time. Let us briefly look at some of them.

I am happy to tell that my blog initiated at least two of the changes.

Removed UInt64 (not to be confused with uint64) [cf154355]

We’ve seen this class in the post about native integers. The UInt64 type remained in the codebase for a long time while it was not actually used. The uint type, though, is still to-be-used as the type of the denominator in Rats:

# XXX: should be Rational[Int, uint]
my class Rat is Cool does Rational[Int, Int] {

Made DateTime creation about 1.6x faster [36d71a39]

As we saw, the DateTime constructor used the in-range method, which was replaced with faster explicit tests:

- (1..12).in-range($month,'Month');
- (1 .. self.DAYS-IN-MONTH($year,$month)).in-range($day,'Day');
- (0..23).in-range($hour,'Hour');
- (0..59).in-range($minute,'Minute');

+ 1 <= $month <= 12
+     || X::OutOfRange.new(:what<Month>,:got($month),:range<1..12>).throw;
+ 1 <= $day <= self.DAYS-IN-MONTH($year,$month)
+     || X::OutOfRange.new(
+         :what<Day>,
+         :got($day),
+         :range("1..{self.DAYS-IN-MONTH($year,$month)}")
+     ).throw;
+ 0 <= $hour <= 23
+     || X::OutOfRange.new(:what<Hour>,:got($hour),:range<0..23>).throw;
+ 0 <= $minute <= 59
+     || X::OutOfRange.new(:what<Minute>,:got($minute),:range<0..59>).throw;

Made adding integers to Rats 22% faster [418fc068]

Creating Rats is an interesting procedure, which I am going to blog about in the future. For now, let me show the changes from this commit:

sub DON'T_DIVIDE_NUMBERS(Int:D \nu, Int:D \de, $t1, $t2) {

-     my $r;
-     if nqp::istype($t1, FatRat) || nqp::istype($t2, FatRat) {
-         $r := nqp::create(FatRat);
-         nqp::bindattr($r, FatRat, '$!numerator', nqp::decont(nu));
-         nqp::bindattr($r, FatRat, '$!denominator', nqp::decont(de));
-     } else {
-         $r := nqp::create(Rat);
-         nqp::bindattr($r, Rat, '$!numerator', nqp::decont(nu));
-         nqp::bindattr($r, Rat, '$!denominator', nqp::decont(de));
-     }
-     $r;

+     nqp::istype($t1, FatRat) || nqp::istype($t2, FatRat)
+         ?? nqp::p6bindattrinvres(
+                nqp::p6bindattrinvres(
+                    nqp::create(FatRat),
+                    FatRat, '$!numerator', nqp::decont(nu)),
+                FatRat, '$!denominator', nqp::decont(de))
+         !! nqp::p6bindattrinvres(
+                nqp::p6bindattrinvres(
+                    nqp::create(Rat),
+                    Rat, '$!numerator', nqp::decont(nu)),
+                Rat, '$!denominator', nqp::decont(de))

This is a routine that is a part of creating a Rat value from two integers. A Rat value internally contains two attributes, the numerator and the denominator. They were bound via the nqp::bindattr method with the help of some temporary variable. Now the Rakudo’s nqp::p6bindattrinvres method is used directly. This method is equivalent to the following code (see docs/ops.markdown in the Rakudo directory):

{
    bindattr($obj, $type, $attr-name, $value);
    $obj;
}

Made use of faster typechecks (7.5x faster) [4c9b84f8][8f71b0e0][10cd405f]

The key idea of this change is to replace the Perl 6 type checks with NQP ones, all changes are in src/Perl6/Actions.nqp, for example:

- if $past.isa(QAST::Var) {
+ if nqp::istype($past, QAST::Var) {

- if $elem ~~ QAST::Op
+ if nqp::istype($elem, QAST::Op)

As a useful exercise, you can trace back the behaviour of both .isa and ~~ in the code and see why it could slow down the check.

Made operator chains up to 2.4x faster [b77d8756]

The change was made in src/Perl6/Optimizer.nqp, and we are not going to read it here, but I wanted to mention this change because it is relevant to a small but very handy feature of Perl 6, chain comparisons such as 1 < $x < 2. It is claimed that now it works almost as fast as 1 < $x && $x < 2.

Made .sum on 2-element Lists about 30% faster [0af3f4d1]

This is an interesting change in the code that, basically, avoids using a loop for adding up two values:

- nqp::stmts(
-   (my $list := $!reified),
-   (my $sum = nqp::ifnull(nqp::atpos($list,0),0)),
-   (my int $i),
-   nqp::while(
-     nqp::islt_i($i = nqp::add_i($i,1),$elems),
-     ($sum = $sum + nqp::ifnull(nqp::atpos($list,$i),0))

+ nqp::if(
+   nqp::isgt_i($elems,2),
+   nqp::stmts(
+     (my $list := $!reified),
+     (my $sum = nqp::ifnull(nqp::atpos($list,0),0)),
+     (my int $i),
+     nqp::while(
+       nqp::islt_i($i = nqp::add_i($i,1),$elems),
+       ($sum = $sum + nqp::ifnull(nqp::atpos($list,$i),0))
+     ),
+     $sum

A lot of NQP code here in src/core/List.pm, but you can understand it if I tell you that nqp::stmts makes a sequence of statements a single statement. Thus, the nqp::isgt_i check has two branches: for arrays that either have one or two, or arrays with more elements.

There are more interesting changes but most of them require deeper understanding of Rakudo.

2 thoughts on “🔬36. Rakudo 2018.01”

Leave a Reply

Your email address will not be published. Required fields are marked *

Retype the CAPTCHA code from the image
Change the CAPTCHA codeSpeak the CAPTCHA code