Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rbenv calls taking too much time #804

Closed
pik opened this issue Oct 24, 2015 · 8 comments
Closed

rbenv calls taking too much time #804

pik opened this issue Oct 24, 2015 · 8 comments

Comments

@pik
Copy link

pik commented Oct 24, 2015

Hello,
So this seems to have happened quite recently and I'm not quite sure what to look for to fix this - but recently rbenv calls are taking a particular long time to resolve. This a very noticeable because my shell_prompt uses 3 rbenv calls to generate the prompt if type rbenv >/dev/null 2>&1, set ruby_version (rbenv version-name) and [ "$ruby_version" = (rbenv global) ]; and return.

Here is what I get for a benchmark (~8.7 rbenv calls per second):

> set start (gdate +%s%N); for i in (seq 100); rbenv >/dev/null 2>&1; end; \
math (gdate +%s%N) - $start | ruby -e 'puts $stdin.gets.to_f / 10**9'                        

11.481579
@mislav
Copy link
Member

mislav commented Oct 24, 2015

Is every rbenv command taking a long time, such as rbenv --version? You can turn on RBENV_DEBUG=1 mode via environment variable to have rbenv output verbose information about everything that runs internally. That might help you debug where the slowdown happens. Look for rogue rbenv plugins.

Also, some more information about your system would be helpful: rbenv --version, bash --version, OS type and version. Thanks

@pik
Copy link
Author

pik commented Oct 24, 2015

Thanks for the response. I'm testing on OS X Yosemite 10.10.4.

From my benchmarks rbenv --version and other rbenv commands are about 4x as fast as simply rbenv.

> set start (gdate +%s%N); for i in (seq 100); rbenv global >/dev/null 2>&1; end; \
math (gdate +%s%N) - $start | ruby -e 'puts $stdin.gets.to_f / 10**9'                                       
2.277274

> set start (gdate +%s%N); for i in (seq 100); rbenv --version >/dev/null 2>&1; end; \
 math (gdate +%s%N) - $start | ruby -e 'puts $stdin.gets.to_f / 10**9'                                       
2.529478

This is on fish, version 2.1.2. Bash (GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin14)) appears to give the same speeds if rbenv is present:

> start=$(gdate +%s%N); for i in {1..100}; do rbenv > /dev/null 2>&1; done; \
 expr $(gdate +%s%N) - $start | ruby -e 'puts $stdin.gets.to_f / 10**9';
0.063882
> export PATH=$HOME/.rbenv/bin:$PATH
> start=$(gdate +%s%N); for i in {1..100}; do rbenv > /dev/null 2>&1; done; \ 
expr $(gdate +%s%N) - $start | ruby -e 'puts $stdin.gets.to_f / 10**9';
11.390776

I'm not sure what the normal run times for rbenv are so if someone could help me out by posting those that would be great.

@mislav
Copy link
Member

mislav commented Oct 24, 2015

Now that I compare it against my system, ~8.7 rbenv calls per second sounds about right. This is because plain rbenv command isn't the best thing to measure, since rbenv without arguments is outputting rbenv help-powered docs which is not very fast.

In your shell prompt, however, you seem to be invoking rbenv twice:

  1. rbenv version-name
  2. rbenv global

Both of these commands are much faster than plain rbenv, since they invoke a specific focused operation. On my computer, they clock at around 30ms on average:

TIMEFORMAT=%3R
for i in {1..100}; do time rbenv version-name >/dev/null; done 2>&1 | awk '{ d+=$1 } END { print d/FNR }'

0.02943 # average execution time in seconds

However, these 2 commands can together still take up to 60ms to execute in sequence, and that's unacceptable for a shell prompt in my opinion. Rbenv is going to get faster in the next release due to dynamically loaded C extension, and I've also been toying with a rbenv rewrite in Go which is already silly fast, but in the meantime I suggest that you avoid calling rbenv commands in your prompt.

Here are some alternatives:

  1. Instead of rbenv version-name, display the value of $RBENV_VERSION variable, and if that's empty then cat .ruby-version 2>/dev/null
  2. Instead of rbenv global, simply do cat ${RBENV_ROOT:-~/.rbenv}/version 2>/dev/null || echo "system"

Does that help at all?

pik added a commit to pik/theme-bobthefish that referenced this issue Oct 24, 2015
@pik
Copy link
Author

pik commented Oct 24, 2015

Thanks for the feedback. Not sure about why the normal rbenv needs to be slow since the base help string could be statically allocated?

Your suggestions do make for a great improvement but it would be nice of course if the commands themselves were fast as well :)

@mislav
Copy link
Member

mislav commented Oct 24, 2015

Not sure about why the normal rbenv needs to be slow since the base help string could be statically allocated?

The help string is actually compiled from bits of help text from individual commands. That's why it's slow. It's fine that this is slow, however, since you're not often calling rbenv without arguments, or even rbenv help, and when you do it's fine that it's not super-fast because it's probably not blocking your workflow.

However, yes I want commands like version-name and global to be fast. It's just that rbenv is composed of several small executables that interact with each other, and even though this follows the unix philosophy, I was never happy with its execution time. The slowness mostly comes from iterating through plugin path and executing all the plugin hooks (if applicable), and as a cumulative overhead of individual bash processes starting up.

In the upcoming version of rbenv, for instance, version-name + global would have a total execution time of ~36ms, down from ~60ms that it is now. However, as long as rbenv is implemented in bash, I suggest that you avoid embedding it in your shell prompt unless absolutely necessary.

@mislav
Copy link
Member

mislav commented Oct 24, 2015

Closing because rbenv speed is being actively worked on, and because you've been given alternatives for your shell prompt. Thanks for raising this issue!

@mislav mislav closed this as completed Oct 24, 2015
@pik
Copy link
Author

pik commented Oct 24, 2015

One question - are the speed-ups going into the next version currently in master or in a separate branch? (this is in case I find a few things to speed-up and to avoid making a duplicate PR)

@mislav
Copy link
Member

mislav commented Oct 24, 2015

They are in master. To enable, install rbenv from master branch and run make -C src in its install directory.

pik added a commit to pik/theme-bobthefish that referenced this issue Oct 25, 2015
pik added a commit to pik/theme-bobthefish that referenced this issue Oct 26, 2015
pik added a commit to pik/theme-bobthefish that referenced this issue Oct 26, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants