alda-lang / alda

A music programming language for musicians. :notes:
https://alda.io
Eclipse Public License 2.0
5.59k stars 286 forks source link

`alda version` is extremely slow #368

Closed firmart closed 3 years ago

firmart commented 3 years ago

For comparison purposes:

$ time alda version
alda 2.0.0
alda version  1,79s user 0,06s system 240% cpu 0,767 total
$ time emacs --version
GNU Emacs 28.0.50
...
emacs --version  0,03s user 0,02s system 98% cpu 0,047 total
$ time apt --version
apt 2.0.5 (amd64)
apt --version  0,02s user 0,01s system 11% cpu 0,184 total
$ time npm --version
7.6.0
npm --version  0,25s user 0,04s system 116% cpu 0,253 total

Especially now that Alda 2 is out, plugins will have to check Alda version to be backward compatible or to warn the user to upgrade Alda.

daveyarwood commented 3 years ago

Good point. We're doing something a little bit sneaky in Alda 2, which is that we're taking any opportunity we can to preemptively spawn player processes. The idea is that when you first install Alda, you're likely to try running a few exploratory commands like:

alda
alda version
alda --help
alda doctor
alda play --help

Meanwhile, when each of those commands is run, Alda is checking in the background to make sure that there are a handful of player processes available for when you eventually run an alda play command. Then, when you do run that alda play command, the playback is instantaneous.

You can observe the difference by deliberately shutting down all of the player processes and then running an alda play command:

# `alda ps` output shows me that I have 2 player processes available...
$ alda ps
id  port    state   expiry
pzf 35079   ready   3 minutes from now
wwh 33463   ready   1 minute from now

# ...so I shut them down to demo a "cold start".
$ alda shutdown

$ alda ps
id  port    state   expiry

# Cold start. Notice the "Starting player processes..." message
# and the fact that it takes almost 8 seconds!
$ time alda play -c 'alto-sax: d8 e f g e4 c8 d4.'
Starting player processes...
Playing...

real    0m7.845s
user    0m2.881s
sys 0m0.532s

# We can see now that there are some player processes available.
$ alda ps
id  port    state   expiry
ezk 46447   ready   5 minutes from now
hbl 38285   ready   6 minutes from now

# Now playback is immediate.
$ time alda play -c 'alto-sax: d8 e f g e4 c8 d4.'
Playing...

real    0m1.050s
user    0m2.465s
sys 0m0.350s

$ time alda play -c 'alto-sax: d8 e f g e4 c8 d4.'
Playing...

real    0m1.032s
user    0m2.341s
sys 0m0.372s

1 second is still a long time to wait, especially for a simple command like alda --help or alda version. I did some debugging just now and I saw that even if there are already enough player processes available and it doesn't need to start any more, it still takes some time for Alda to check on the state of the player processes.

The good news is that I built in an escape hatch: if you set the ALDA_DISABLE_SPAWNING environment variable to yes, it turns off the player spawning behavior altogether, which speeds things up considerably:

$ time alda version
alda 2.0.0

real    0m1.251s
user    0m2.715s
sys 0m0.541s

$ ALDA_DISABLE_SPAWNING=yes time alda version
alda 2.0.0
0.04user 0.04system 0:00.22elapsed 38%CPU (0avgtext+0avgdata 15520maxresident)k
0inputs+0outputs (0major+2263minor)pagefaults 0swaps

I would advise against exporting this in your bashrc or similar, because then playback won't work! But it's useful to set ALDA_DISABLE_SPAWNING=yes on a per-command basis if you want the result to come back quickly, e.g. if you're building tooling on top of the Alda CLI.

daveyarwood commented 3 years ago

Closing this for now - feel free to reopen if you're still having issues!

UlyssesZh commented 3 years ago

@jgkamat pointed out that the ALDA_DISABLE_SPAWNING=yes workaround doesn't improve enough.

That workaround dosen't seem to improve much for me:

Alda 1

[jay@eve ~]$ time ALDA_DISABLE_SPAWNING=yes alda version
Client version: 1.1.0
Server version: [27713] ERROR Alda server is down. To start the server, run `alda up`.
ALDA_DISABLE_SPAWNING=yes alda version  0.43s user 0.04s system 7% cpu 6.037 total

Alda 2

[jay@eve ~]$ time ALDA_DISABLE_SPAWNING=yes alda version
alda 2.0.1
ALDA_DISABLE_SPAWNING=yes alda version  0.06s user 0.02s system 13% cpu 0.560 total

For me, 100ms is the absolute slowest anything should ever cause a user to wait (such a delay is perceived as "instant") - even on alda 2 we are 5x slower than that. For alda 1, that would be a 6 second wait - which is completely unusable in my mind.

While normally this could be hand-waved away by just saying "alda itself is slow", in this case this would be added latency, on top of the alda commands.

The only solution that seems acceptable to me is trying the new api and falling back to alda 1 if that won't work. But this still means added latency on Alda 1, which is exactly what I'm trying to avoid (and if we cache it or let the user supply it, it will break completely on alda upgrade/downgrades).

daveyarwood commented 3 years ago

@UlyssesZh @jgkamat I took some more measurements and I found that telemetry also takes (on my machine) about 100-300ms. There is also an environment variable that you can use to disable telemetry on a per-command basis, ALDA_DISABLE_TELEMETRY=yes.

For comparison:

$ time alda version
alda 2.0.1

________________________________________________________
Executed in    1.23 secs   fish           external 
   usr time    2.70 secs    0.00 micros    2.70 secs 
   sys time    0.47 secs  1085.00 micros    0.47 secs 

$ ALDA_DISABLE_SPAWNING=yes time alda version
alda 2.0.1
0.07user 0.02system 0:00.23elapsed 41%CPU (0avgtext+0avgdata 15884maxresident)k
0inputs+0outputs (0major+2360minor)pagefaults 0swaps

$ ALDA_DISABLE_SPAWNING=yes ALDA_DISABLE_TELEMETRY=yes time alda version
alda 2.0.1
0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 8396maxresident)k
0inputs+0outputs (0major+612minor)pagefaults 0swaps

As you can see, if you disable both player spawning and telemetry, alda version can be extremely fast!

By the way, you can also disable telemetry altogether by running alda telemetry --disable, but that's something that each user should decide for themselves whether or not they want to do. For the purposes of building editor plugins, I would recommend using ALDA_DISABLE_TELEMETRY=yes instead, and only for purposes like this, where you really need the command to return immediately.

For more information about telemetry (what information we collect, etc.) see alda telemetry --help.