skip to Main Content

Raku start-up times are notoriously huge.


On my machine (old one but the most modern I own):

time raku -e 'put "Hello, World!"'
495.67 – 567.02 millis
(1.53 secs for the 1st time launch)

time perl -E 'say "Hello, World!"'
13.63 – 19.51 millis

time sh -c 'echo "Hello, World!"'
4.31 – 6.88 millis

c:

#include <stdio.h>

int main(void) {
    puts("Hello, World!");
    return 0;
}

time ./hello
5.03 – 7.67 millis
time clang hello.c -o hello (compile)
126.39 – 195.66 millis


Raku does boast many nifties built-in which make it heavy.
Yet sometimes you need a rather simple script, and you would prefer Raku for its elegance, but launch-time spent waiting brings dissatisfaction and you don’t pick Raku for your next simple script.

Is there a way to help it?
Like starting Raku once and keeping it running, and making it handle all Raku scripts, with and without modules, big and small, and raku -e ... as well?
Something like FastCGI but for local shell?


Even sacrificing permanently huge amount of memory is better for me than wasting time waiting.
In KiloBytes, according to ps:

                                      Virtual size  Resident set size

raku -e 'loop {sleep 1}'                    146704  107200

perl -e 'while (1) {sleep 1}'                 1252    4036

sh -c 'while true; do sleep 1; done'           892     900

#include <unistd.h>
void main(void) { for(;;) {sleep(1);} }        172     780

Update:

Elaborating upon
raku -e 'while prompt "Enter filename: " -> $filename { EVALFILE $filename }'
from https://stackoverflow.com/a/73873471/14812514

Concocted from https://docs.raku.org/type/IO::Socket::INET and https://www.tutorialspoint.com/perl/perl_socket_programming.htm

raku-persistent, heavy server:

#! /usr/bin/env raku

use MONKEY-SEE-NO-EVAL;

my $listen = IO::Socket::INET.new( :listen,
                                   :localhost<localhost>,
                                   :localport(3333) );
loop {
    my $conn = $listen.accept;
    try {
        while my $buf = $conn.recv() {
            put now - (EVAL $buf)[1] - 37;  # also subtract leap seconds
            EVALFILE (EVAL $buf)[0];
        }
    }
    $conn.close;
    CATCH { default {.payload.say} }
}

ra, light client:

#! /usr/bin/env perl

use strict;
use warnings;
use Time::HiRes;
use Socket;

my $file = shift || '/tmp/test.raku';
my $arg1 = shift || Time::HiRes::time;

# initialize host and port
my $host = shift || 'localhost';
my $port = shift || 3333;
my $server = "localhost";  # Host IP running the server

# create the socket, connect to the port
socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2])
   or die "Can't create a socket $!n";
connect(SOCKET, pack_sockaddr_in($port, inet_aton($server)))
   or die "Can't connect to port $port! n";

printf SOCKET '["%s", %f]', $file, $arg1;
close SOCKET or die "close: $!";

/tmp/test.raku:

put "Hello, World!";
run 'notify-send', 'Hello, World!'

raku-persistent in one terminal, once;
ra [script.raku] in another terminal, how many times you want.

Delay ranges 0.008848472 – 1.322056732; in most cases being below 0.07.
0.008848472 must be some kind of a mistake – it is less than perl startup time, which is impossible.

This is still a proof of concept since arguments don’t get into the target script.


Update 2:

As a reaction to https://stackoverflow.com/a/73918912/14812514

Suggested bench suite doesn’t work via Makefile on my machines, even on Debian-based antiX 21, and possible solution was found after I had done all measurements semi-manually. Moreover, on OpenBSD run.c doesn’t even compile. Being zero at c, I resorted to shell time for i in $(seq 1000); do ./<file> >/dev/null; done.
All 4 machines with HDD, no SSD.
My initial configuration is i5-3320M OpenBSD and marked with ^.
Results in seconds for 1K invocations, also for single invocation for Raku only:

 CPU           cores  GHz  OS            via         Raku K     Raku 1    Perl K  C K
 Pentium 4-M i686  1  2.2  OpenBSD i386  shell seq   36m32.479  2.192479  22.368  6.408
 Core 2 Duo T5800  2  2    antiX         c run       10m34.460  0.63446    2.224  0.535
 Core 2 Duo T5800  2  2    antiX         shell seq    7m48.153  0.468153   3.878  1.509
^i5-3320M          2  2.6  OpenBSD       shell seq    8m 0.011  0.480011   8.150  2.258
 i5-3320M          2  2.6  antiX live    c run        4m53.469  0.293469   1.157  0.276
 i5-3320M          2  2.6  antiX live    shell seq    3m37.042  0.217042   1.688  0.615
 i7-3770S          4  3.1  OpenBSD       shell seq    6m44.920  0.40492    7.026  2.340
 i7-3770S          4  3.1  antiX live    c run        4m 5.571  0.245571   0.872  0.268

Some highlights:

  • Raku startup times are unwelcomely regardless of CPU and OS
  • shell for i in $(seq... is slower than custom C run for Perl & C but outperformed it for Raku – 7m+ vs 10m+ on Core 2 Duo and 3m+ vs 4m+ on i5
  • OpenBSD doesn’t prioritize speed
  • 3rd-party software doesn’t prioritize optimization for OpenBSD

2

Answers


  1. Assuming you have a recent version of Rakudo, I can say that you have indeed a very slow machine:

    % time perl -E 'say "Hello, World!"'
    Hello, World!
    real    0.05s
    user    0.00s
    sys 0.03s
    
    % time raku -e 'put "Hello, World!"'
    Hello, World!
    real    0.12s
    user    0.12s
    sys 0.02s
    

    are the numbers I see on a 2-year M1 MacMini. On a 10+ year old MacMini running Debian, I see:

    $ time perl -E 'say "Hello, World!"'
    Hello, World!
    
    real    0m0.009s
    user    0m0.004s
    sys 0m0.005s
    
    $ time raku -e 'put "Hello, World!"'
    Hello, World!
    
    real    0m0.241s
    user    0m0.287s
    sys 0m0.041s
    

    Now to get back to your question: yes, you can have something like FastCGI but for a local shell:

    % raku -e 'while prompt "Enter filename: " -> $filename { EVALFILE $filename }
    

    run this, enter the name of the script to execute and ENTER, and it will run. Now, this is the principle: this only runs scripts without arguments. You can build on this allowing for arguments and such.

    Login or Signup to reply.
  2. The client-server model you describes seems like a really good idea to me! In fact, I’ve been toying with a similar idea myself; I actually gave a lightning talk on the subject at the 2022 Perl and Raku Conference, A Nailgun for Raku.

    As that talk mentions, this is the basic idea behind Nailgun – which implements the same idea but for Java. As you note, it gets a bit more complex than the proof of concept, but definitely seems like a doable Raku project.

    On a different note, I agree with Raiph [edit: with Liz, oops!] that the timings you posted are pretty close to a worst-case scenario in terms of launch speed. My go-to reference for language startup time benchmarks is bdrung/startup-time, which has both a benchmarking framework and the author’s own data. For comparison, that author clocks a "Hello, World!" C program between 0.26 ms (for a 2018 laptop) and 2.19 ms (for a Raspberry Pi 3). Those times might provide some context for the 5.03 to 7.67ms time you measured for a "Hello, World!" C programs.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search