asdf-vm / asdf

Extendable version manager with support for Ruby, Node.js, Elixir, Erlang & more
https://asdf-vm.com/
MIT License
21.66k stars 774 forks source link

asdf shims adding too much time to use them in a shell prompt #290

Open stevenocchipinti opened 6 years ago

stevenocchipinti commented 6 years ago

Hello,

Not sure if this is the right place to report this issue but I've noticed using asdf is quite slow for executing commands.

This is ruby using chruby:

$> time ~/.rubies/ruby-2.5.0/bin/ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin16]

real    0m0.019s
user    0m0.009s
sys 0m0.006s

and node using nvm:

$> time ~/.nvm/versions/node/v9.1.0/bin/node -v
v9.1.0

real    0m0.015s
user    0m0.007s
sys 0m0.005s

Steps to reproduce

This is ruby using asdf:

$> time /usr/local/opt/asdf/shims/ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin16]

real    0m0.305s
user    0m0.130s
sys 0m0.126s

and node using asdf:

$> time /usr/local/opt/asdf/shims/node -v
v8.9.4

real    0m0.272s
user    0m0.119s
sys 0m0.109s

When having a shell prompt that prints the version number of ruby and node, this adds half a second to each command!

I love the idea of asdf but I don't want to give up version numbers in my prompt so I won't be using asdf in its current state unless I can find a workaround.

Any ideas or advice would be welcome - thanks

Environment

OS: OSX

asdf version: v0.4.2

stephanGarland commented 1 year ago

but we'll want to do more testing to validate those changes improve performance across the board

Agreed; I've opened a Draft PR here to capture everything, and @jthegedus mentioned using hyperfine to benchmark changes.

Also, performance isn't everything

No, but I think for a tool like asdf it's the first priority. I want shell commands to execute at the speed of thought. Adding 50-100 ms is noticeable, and for me, it was enough to stop using asdf (until I started poking around, which has been fun).

we have to weigh the cost of more complicated code

I mean, the same is true as re-writing into another language. I'd also argue that some of the previous shell included in asdf, like the sort_versions sed which was taken from a Ruby repo, was extremely abstruse.

such as re-writing in Go or Rust

Personally I hate the entire Go ecosystem, but you do you 😛

Given that the overwhelming the majority of the calls are due to waiting on child processes to return, re-writing in any language where everything is inside a single process would have performance benefits.

Fire-Dragon-DoL commented 1 year ago

I'm just a number, but for what is worth, I use chruby and chnode due to the incredible performance and simpler environment setup (there aren't many proxies), I had to stop using asdf due to the performance penalties.

For Go, I just install the last version due to backward compatibility.

I haven't found an alternative to asdf for Elixir, but I'm not using the language nowdays.

jordan-brough commented 1 year ago

Same here, fwiw. I would prefer asdf but switched back to rbenv and nvm because of the startup lag.

jdx commented 1 year ago

I also found asdf's performance to be unusable. It made my shell prompt take seconds longer to start with just a few plugins. That's every time I ran a shell command.

I wrote an alternative to asdf. It's written in rust so it's extremely fast, but more importantly it doesn't use shims at all so launching runtimes is exactly as fast as calling them directly—because you are. It still uses asdf plugins which is definitely the best part of asdf.

It also has a few more features that I really wanted out of asdf (fuzzy-matching and aliases to name a couple). Let me know what you think.

Fire-Dragon-DoL commented 1 year ago

I also found asdf's performance to be unusable. It made my shell prompt take seconds longer to start with just a few runtimes. That's every time I ran a shell command.

I wrote an alternative to asdf. It's written in rust so it's extremely fast, but more importantly it doesn't use shims at all so launching runtimes is exactly as fast as calling them directly (because you are). It still uses asdf plugins though.

It's also got a couple more features that I really wanted out of asdf (fuzzy-matching and aliases). Let me know what you think.

That sounds amazing, I was looking for a non-shims solution that would achieve this type of performance. I'll give it a review tomorrow!

jordan-brough commented 1 year ago

I wrote an alternative to asdf.

@jdxcode great to hear! I'm giving it a spin. So far so good!

time ruby --version
ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c5) [arm64-darwin22]

real    0m0.019s

🏎️ 🚀

pedropombeiro commented 1 year ago

On a MacBook Air M2:

image

🥇

jdx commented 1 year ago

@pedropombeiro it's worth noting that the performance of rtx exec doesn't matter in the same way that asdf exec does. Because asdf is shim-based, it uses asdf exec under the hood any time you call ruby.

Since rtx doesn't use shims, if you call ruby then rtx isn't involved.

Of course if rtx did use shims the overhead is so small it wouldn't matter. Performance isn't the only reason I wanted to avoid shims, I also didn't want to break which ruby, and I wanted it where rtx would not mess with runtimes unless they were explicitly specified.

So in asdf when you might want to set ruby system to use the homebrew version of ruby in your global .tool-versions, in asdf you can just not include it at all and ruby will point to whatever the system ruby is by default.

jthegedus commented 1 year ago

For those not reading the entire comment thread, there is a plugin for Direnv (https://github.com/asdf-community/asdf-direnv) which modifies asdf to avoid the "Shims model". Thanks for sharing @jdxcode

jdx commented 1 year ago

I wasn't happy with asdf-direnv because while it made launching runtimes faster, it just made it so changing project directories was slow.

vsviridov commented 1 year ago

I wasn't happy with asdf-direnv because while it made launching runtimes faster, it just made it so changing project directories was slow.

I'm a regular workflow I imagine one runs the commands orders of magnitude more times than changing into the project folder...

pprotas commented 1 year ago

I wrote an alternative to asdf

Seeing as this thread is form 2018, the chance that asdf will fix this problem anytime soon is pretty low. rtx seems to fix this problem!

stephanGarland commented 1 year ago

@pprotas I am addressing it here.

pesterhazy commented 1 year ago

I ran into this issue this week when using asdf in a test runner. The test runner is composed of multiple tools that call each other (like clojure and java). Each call incurs the asdf penalty of 450ms, and because of multiple nested calls, this adds up.

One fix I discovered was to put the binaries explicitly on the PATH

export PATH="$(asdf where watchexec)/bin:$(asdf where java)/bin:$(asdf where babashka)/bin:$(asdf where clojure)/bin:$PATH"

which shows a dramatic improvement in cycle time (from 8s to 2s per test run, for me). I will investigate alternative solutions (asdf-direnv, rtx) as well.

pesterhazy commented 1 year ago

(This may be a good occasion to say thanks for asdf - a wonderful tool that has made working in a team with consistent tool versions a breeze, and boosted productivity in my company)

munim commented 4 hours ago

It feels significantly slow for me. I prefer to live with it.

image

StevenACoffman commented 28 minutes ago

Awhile back, someone ported ASDF to Rust and made the whole experience lightning-fast. It uses all the same asdf plugins, but if you find ASDF sluggish, try mise.