sschwarzer
2021-8-29 12:02:38

In my experience, there’s a modest reduction in startup time. Still, the minimum startup time even for a “Hello world” program using #lang racket/base, compiled with raco exe, is 110 ms on my system (a five-year-old Core i5).


sschwarzer
2021-8-29 12:04:48

In comparison, compiled binaries for other languages typically have a startup time of 3 to 5 ms on my system.


sorawee
2021-8-29 12:15:12

I think the reduction that you noticed is not due to compiling to executable, but is due to compiling to “bytecode”


sorawee
2021-8-29 12:15:32

I.e., raco make would suffice to make you see the speedup.


sschwarzer
2021-8-29 12:20:21

When I use raco make, I get between about 100 or 120 ms startup time. I don’t know what causes the bimodal(?) distribution.

Last time I tried actual programs with raco make vs. raco exe, there was little difference.


sschwarzer
2021-8-29 12:23:44

Often, I want to generate standalone executables (with raco exe --orig-exe), so raco make doesn’t help here. But I agree, if you don’t need the standalone functionality, raco make can make startup a bit faster (but not much).


sschwarzer
2021-8-29 12:26:07

Unfortunately, the startup times can be much higher if you require a few more modules. So “typical” startup times for me are over 200 ms. A “Hello world” program with #lang racket , compiled with raco make, takes about 260 ms here.


sschwarzer
2021-8-29 12:28:19

(all measurements with Racket 8.2 cs)


sschwarzer
2021-8-29 12:32:14

That said, execution time beyond startup is pretty fast in my opinion, which I find impressive for code without static typing (not considering typed Racket here). :+1:

But still, if you rather need/want faster startup times, Racket is rather slow.


sehoongim
2021-8-29 12:34:55

@sehoongim has joined the channel


greg
2021-8-29 13:02:02

raco make fully expands programs. Which can be quite slow when your program (or any not-yet-raco-made modules it requires, transitively) have non-trivial macros.


greg
2021-8-29 13:02:49

If you had a project using say typed/racket and your main.rkt required foo.rkt which required bar.rkt — you’d probably see a bigger difference between startup having to fully expand all 3 every time you run, vs. reusing that work that raco make had done/saved.


greg
2021-8-29 13:06:13

A “fun” experiment is to delete all .zo files in the entire Racket installation, enter racket at the command line, and start your timer…. :slightly_smiling_face:


greg
2021-8-29 13:07:12

Most of that time will be spent fully-expanding modules, not “compiling” to bytecode or machine code, IIUC.


sschwarzer
2021-8-29 14:07:10

I was still curious about the fun experiment. Starting racket that way takes about 30 s on my computer. :smile:


samth
2021-8-29 14:07:55

To simulate that without making permanent changes, you can use the -c command line argument


sschwarzer
2021-8-29 14:10:18

@samth You should have told me that a minute ago. :wink: Seriously though, I had made a copy of the installation directory, so it took me only a few seconds to restore the directory with the zo files.


greg
2021-8-29 14:51:39

I’m actually surprised it took “only” 30 seconds. Maybe instead I should have suggested something like starting Dr Racket. :slightly_smiling_face:


greg
2021-8-29 14:53:40

btw above I forgot about the raco expand command. Maybe a TL;DR would have been, “For some programs, raco make takes hardly longer than raco expand


jestarray
2021-8-29 16:23:58

does racket do any dead code elimination? e.g importing a library and only using a few functions will have it so it only pulls in those functions and not the entire lib and bloating your runtime?


jestarray
2021-8-29 16:53:32

what do you mates think of commonlisp and why do you prefer racket over it(assuming you do)


samth
2021-8-29 16:54:25

In general dead code elimination is not sound in racket


samth
2021-8-29 16:54:57

But there are tools to do this, eg raco demod


badkins
2021-8-29 17:33:31

• I prefer (foo arg ...)over (funcall foo arg ...) • I prefer the requirement to support tail call optimization • I feel Racket has better supported libraries • I prefer Racket’s macro system • The lack of the standard, and associated bureaucracy allows Racket to evolve more easily • etc.


sschwarzer
2021-8-29 17:37:42

I just tried raco demod on my <https://git.sr.ht/~sschwarzer/sudoku-solver|Sudoku solver>.

racket games/sudoku-solver.rkt --help shows the help text as expected, however raco demod -o sudoku-solver-demod.zo games/sudoku-solver.rkt racket sudoku-solver-demod.zo --help shows nothing despite the https://docs.racket-lang.org/raco/demod.html\|documentation saying > The demodularized ".zo" file can be run by passing it as an argument to the racket command-line program, or it can be turned into an executable with <https://docs.racket-lang.org/raco/exe.html|raco exe>. I also tried raco exe -o sudoku-solver sudoku-solver-demod.zo and running sudoku-solver neither gives any output.


raoul.schorer
2021-8-29 17:52:55

Racket is built for and by people who want to explore new things, while still keeping practical (fast implementation, and all that…). CL is much more geared towards people who “just want to make <thing>”.


seanbunderwood
2021-8-29 18:03:52

To all that, I’d add that I prefer Racket’s more functional flavor.


ben.knoble
2021-8-29 18:16:10

Also, the ability to evolve a macro dsl into a lang.


shu--hung
2021-8-29 18:36:49

I’m also having roughly ~0.15s (0.10user + 0.05sys) startup time on my Mac 2015, this is roughly on par with Racket BC (!) which is implemented in C.

In comparison, python3 takes about ~0.04s.

I think this partly has to do with the architecture of Racket. In Python, Python is the language implemented by the compiler/interpreter. However, racket/base is still many layers of languages on top of the core. The bytecode loading time and all the module name resolution time may affect performance.

If I directly load racket/kernel/init, the startup time becomes ~0.10s (0.05user + 0.04sys). Half of the time spent in the user space is gone.


shu--hung
2021-8-29 18:38:38

However, starting the GUI system takes way more time. Loading racket/gui/base alone takes ~1.20s (0.91user + 0.18sys)


shu--hung
2021-8-29 18:42:57

But I suspect it’s probably never going to be comparable to a compiled C/C++ binary, though. After all, compiled C/C++ binaries don’t carry a copy of GCC in it but eval and expand are in Racket kernel.


sschwarzer
2021-8-29 20:03:14

> but eval and expand are in Racket kernel. I’d say the problem isn’t to have them in the kernel, but how much they’re used/needed to execute during startup. (For comparison, Python also can load new code at runtime but still has a shorter startup time.) Ideally (from a startup perspective) a raco exe d executable should do already as much as possible of what’s done when starting a Racket file from source code. If I understand correctly, there may be some expansions that need to be deferred to startup time, maybe depending on the runtime environment, but I guess there shouldn’t be too many of these.


sschwarzer
2021-8-29 20:09:23

By the way, here’s some information I recorded from an earlier discussion of startup time: https://gist.github.com/sschwarzer/5aaf9f203c552f1bf13a167dd08ded11#racket-startup-time


shu--hung
2021-8-29 20:10:35

Yes, I agree is that. Currently there isn’t much staging done in those eval and expand thing. It ought to be possible — though not an easy task because of the current design — but requires someone to work on it.


sschwarzer
2021-8-29 20:17:23

But then, I’m unsure by how much the startup time can be reduced and if it’s worth it. Depending on the application, even something like 50 ms may still be too long. But I think for a general perception of “snappyness” (if that’s a goal) it would probably be something like 50 ms for a “normal” command line program, maybe something that currently takes 250 ms to start. Of course, these times depend on the hardware, so something that might be “snappy” for me may still be quite slow for someone else.


sschwarzer
2021-8-29 20:26:50

For the record, here are some other circumstances where a fast startup time is or may be important: • Programs that are run repeatedly, for each keypress. For example, if you press a volume down/up key on the keyboard, you want an immediate reaction. You don’t want repeated keypresses to be delayed and the sound volume to “overshoot” (in neither direction, but especially if you turn the volume up). • Programs that are called repeatedly from shell skripts in a loop. • Similarly, programs that are called on several nesting levels, like in makefiles. • Programs that are run as part of shell prompt rendering. If the program is too slow (and you may even have several), repeated presses of <enter> would cause newlines between prompt lines. That’s probably not a big deal but it just looks “wrong.” Actually this is an application I had to deal with recently, and I coded the program in Nim; even Python was a bit too slow here.


samth
2021-8-29 20:26:56

The biggest difference between Racket and Python startup is that the compiler and core library is not already machine code that can just be mmapped in. Even the parts that are part of the executable, like expand, are in a form that requires relocation upon loading.


jestarray
2021-8-29 21:56:28

Yeah, for video games especially…. the golden standard is 60fps or whatever the refresh rate of the monitor is… that’s 16MS to simulate your world, test and resolve collisions, physics, etc, and on top of that you have to render pretty graphics while syncing and playing sound ques


jestarray
2021-8-29 22:01:09

we’re quite lucky that modern hardware is super fast and somewhat spoiled at the same time lol


samth
2021-8-29 22:02:05

That seems different, in that you probably wouldn’t start a new instance of the runtime in your display loop