Skip to content

rbenv-gemset hooks adding ~700ms to every ruby execution #84

@nrser

Description

@nrser

Using rbenv-gem version 0.5.9 on macOS 10.12.6 and started to notice running ruby was much slower:

$ time ruby -e "puts 'yo'"
yo

real	0m0.821s
user	0m0.419s
sys	0m0.207s

Ran with RBENV_DEBUG=1 and noticed calls in the gemset.bash scripts. I went into etc/rbenv.d/*/gemset.bash and commented out all three files:

$ time ruby -e "puts 'yo'"
yo

real	0m0.108s
user	0m0.066s
sys	0m0.015s

Which isn't great, but I can live with 100ms. The 800ms start time with the rbenv-gemset hooks enabled is quite noticeable to me though. Is this a standard amount of delay? If not, about how much time should I expect the plugin to add?

I'm running Ruby 2.5.0, but similar results across the board. I have no active gemset, I'm not in a directory that has a gemset, and I have no gemsets for Ruby 2.5.0... so it doesn't seem like the hooks should really have to do anything as soon as they can figure that stuff out?

I toyed around with the hook code a bit; it doesn't seems like there's any one super-slow operation, just a bunch of small ones adding up. Maybe I have something in my setup that is considerably slowing down shell spawning, causing me to feel a lot more pain from the hook code.

Anyways, the hook code is short and clean, and don't totally understand it yet but it seems like it could be optimized considerably... I don't see any short-circuiting. It seems like it should be able to quickly figure out if it doesn't need to do anything and bail out.

Also, it looks like there are places where work is duplicated across the various scripts in the hooks execution path, like the sub-shell to rbenv-gemset file here:

https://github.com/jf/rbenv-gemset/blob/master/etc/rbenv.d/which/gemset.bash#L7

then four lines later sub-shelling rbenv-gemset active

https://github.com/jf/rbenv-gemset/blob/master/etc/rbenv.d/which/gemset.bash#L11

which looks like one of the first things it does is sub-shell rbenv-gem-set-file:

https://github.com/jf/rbenv-gemset/blob/master/etc/rbenv.d/which/gemset.bash#L11

Seems like that stuff could be cached in variables or passed as extra arguments to avoid the duplicate effort.

Sub-shells aren't super cheap... it's a full process spawn. /bin/bash -c exit is around 5-6ms on my system, which really adds up.

Additionally, is there a reason those shells in which/gemset.bash (which is the slowest hook on my system btw) are spawning rbenv-gemset instead of going directly to the libexec/rbenv-gemset-*? It seems like they probably have enough info available to just directly invoke the end-executables and skip going through the user interface entry point and all the commands (many of which are again sub-shells).

I forked the repo and am going to hack in and see if I can get the latency down at least in the case where there's no need to load a gemset, because I've now used the plugin to isolate some gems I use as system utils and it's been really useful and wonderful for that (thanks!). Let me know if you're interested in checking out my changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions