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

pyenv init slows down the shell startup a bunch (by about ~100 ms!) #2918

Open
13 tasks done
VorpalBlade opened this issue Feb 29, 2024 · 3 comments
Open
13 tasks done

Comments

@VorpalBlade
Copy link

VorpalBlade commented Feb 29, 2024

Too many issues will kill our team's development velocity, drastically.
Make sure you have checked all steps below.

Prerequisite

  • Make sure your problem is not listed in the common build problems.
  • Make sure no duplicated issue has already been reported in the pyenv issues. You should look for closed issues, too.
  • Make sure you are not asking us to help solving your specific issue.
    • GitHub issues is opened mainly for development purposes. If you want to ask someone to help solving your problem, go to some community site like Gitter, StackOverflow, etc.
  • Make sure your problem is not derived from packaging (e.g. Homebrew).
    • Please refer to the package documentation for the installation issues, etc.
  • Make sure your problem is not derived from plugins.
    • This repository is maintaining pyenv and the default python-build plugin only. Please refrain from reporting issues of other plugins here.

Description

  • Platform information (e.g. Ubuntu Linux 16.04): Arch Linux
  • OS architecture (e.g. amd64): amd64
  • pyenv version: 2.3.36
  • Python version: 3.11.7 (on host)
  • C Compiler information (e.g. gcc 7.3): 13.2.1 20230801
  • Please attach the debug trace of the failing command as a gist: https://gist.github.com/VorpalBlade/608f04c2234f187c2cd9fad652b72137
  • If you have a problem with installing Python, please also attach config.log from the build directory: Not the issue at hand
  • If the build succeeds but the problem is still with the build process (e.g. the resulting Python is missing a feature), please attach
    • the debug trace from reinstalling the faulty version with env PYENV_DEBUG=1 pyenv install -f -k -v <version> 2>&1 | tee trace.log
    • config.log from the build directory. When using pyenv install with -k as per above, the build directory will be under $PYENV_ROOT/sources.

pyenv init is really slow. I have been profiling zsh startup time, and commenting out eval "$(pyenv init -)" reduces startup time from 111.7 ms to just 11.2 ms. I have been using hyperfine for statistical rigour in the measurement (full output below).

  • I could possibly just inline the output of pyenv init - directly into my .zshrc. But that only reduces the startup time by about ~25 ms (down to 86 ms). And it also risks breaking if pyenv updates.
  • The output of pyenv init --path is just as slow to process as the output of pyenv init - by the way. So that makes absolutely no difference.
  • pyenv init in itself takes 30 ms, but since ditching it and inlining only saved 25 ms I suspect that the shell is able to start processing the output of eval as pyenv is writing it (I guess pyenv writes it kind of slowly line by line rather than a single write()?).

I believe a large part of the problem is that the pyenv output starts a bash sub-process to process some code. This is known to be slow, and is why /bin/sh on Debian for example is dash not bash. Since I'm on Arch it wouldn't help to switch to /bin/sh (which is bash here). Really you should do all your logic directly in the shell you are running in, not another one.

Ideally I would suggest that instead of a command like this, pyenv should install a file you can source (and that doesn't call so many commands, and definitely no subshells). Possibly you need one such installed file per shell you support. I'm not sure about this.

Here are how I measured the shell startup (time to first accepted command for an interactive shell):

$ # With pyenv init in .zshrc
$ hyperfine -i -N --warmup 1 "zsh -i -c exit"          
Benchmark 1: zsh -i -c exit
  Time (mean ± σ):     111.7 ms ±   1.0 ms    [User: 85.4 ms, System: 42.1 ms]
  Range (min … max):   110.1 ms … 115.3 ms    27 runs

$ # With pyenv commented out
$ hyperfine -i -N --warmup 1 "zsh -i -c exit"
Benchmark 1: zsh -i -c exit
  Time (mean ± σ):      11.2 ms ±   0.2 ms    [User: 6.0 ms, System: 5.2 ms]
  Range (min … max):    10.8 ms …  12.2 ms    251 runs
@VorpalBlade
Copy link
Author

Just checked on my laptop. There the difference is larger (it is a slower and older computer): 160.4 ms down to 16.5 ms.

@aalbaali
Copy link

aalbaali commented Mar 4, 2024

I have the same issue as well on zsh. Running pyenv init - or $(pyenv init --path) adds around 300 ms (I go from 80 ms to 380).

@VorpalBlade
Copy link
Author

I figured out a workaround:

pyenv() {
    eval "$(command pyenv init -)"

    pyenv "$@"
}

This will initialise itself on first use and overwrite with the slow implementation. As I don't use pyenv very often (I mostly do Rust these days) this works for me. For even less overhead, put that in a zsh autoloadable file so it isn't even parsed until it is needed.

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