Life is too short for a slow terminal
24 points by npiazza
24 points by npiazza
I sometimes wonder whether all this work ("non-blocking prompts" and OpenGL-based terminals especially) are worth it compared to just doing xterm & PS1="\W: "…
I hadn't used xterm on purpose for years, but then I reviewed a whole bunch of terminal emulators and was quite surprised to discover that xterm fully supports:
and has the dual advantages of being very fast and "the standard", so any bugs remaining are likely inconsequential or considered normal behavior by all programs running in it.
So now I use xterm again.
Only thing about xterm is it doesn’t reflow text on resize. When using a tiled WM that can get very annoying quickly.
What is it about using a tiled WM that makes you change terminal sizes often?
(I don't use a tiled WM, I use a conventional WM with a large number of workspaces, each dedicated to a particular task, and with keyboard shortcuts for each.)
Depends on the setup, but I usually go with the default layout in i3, which makes all windows share the same space (i.e. existing windows shrink then a new window is opened, 100% horizontal w for 1 window, 50 for two, etc.), until you start splitting or changing layout to stacked (maybe i3 terminology, unsure).
What the others said doesn’t really apply to my workflow. For me I like to toggle between fullscreen and half width a lot (using i3)
every time you spawn new window - most of other windows are resized to fit your display. Lack of reflow is especially painful when you don't use any terminal multiplexer (e.g. because it's just another window manager and you don't want to end up with 3 layers of them, counting (neo)vim/emacs)
I recently had my zsh startup slow to a crawl. I didn't pinpoint the root cause, but I did discover that compinit was dominating the critical path, and I implemented caching in approximately the same way as suggested in the post in order to eliminate the slowness.
I am going to have to improve mine with that amazing glob qualifier. I did not even know that was possible. It honestly seems like a questionable feature, but I'll still use it. I was using the comparatively unrefined date -Id approach for constructing the target path.
I love tools like zsh that are configured with a full power programming language. There is no need for the author to add caching features because we can implement it ourselves.
In my nearly 20 years of using zsh, I have never used a framework or plugin manager. It seems like one of the main reasons these are used is for styling. I guess am lucky that I do not care about aesthetics in my computing environment. I have a hand-rolled custom prompt that is pretty basic, compact, informative, and not at all sexy. I use the default terminal theme with a black background.
time zsh -i -c exit
I hate how this broken "benchmark" command is still so commonly used. It measures the completely wrong thing, and some zsh plugin managers have been even optimized for this useless metric, often at the cost of actual shell startup latency.
The zsh-bench utility has a whole section on why this benchmark is useless: https://github.com/romkatv/zsh-bench#how-not-to-benchmark
The metrics that zsh-bench measures are far more useful, such as first prompt lag and input latency.
I though this would be about GPU accelerated terminal bug happy to see it's not.
Caching completions
Great tip. I only use zsh in my work machine which happens to be a Mac. For reasons unknown, this machine will show the beach ball even when thinking about opening a new tab, so hopefully this will make a difference.
Lazy-loading Same idea for kubectl completions, which shell out to the kubectl binary to generate the completion script.
What is the slow thing here? Generating the completitions, or sourcing them? Cause if it's the former, would saving them to a file and then sourcing it help with start up time? Cause hat's what I do with jj for example.
A prompt that runs git status
I ditched it when moved to jj. :D
Measuring your own shell performance
I wish author had shared their times; maybe I'm on the average or maybe I'm on the slow.
real 0m0.287s
user 0m0.136s
sys 0m0.195s
Edit: I tried to cut some time and these were results:
A mostly empty .bashrc only setting some options and the prompt.
real 0m0.007s
user 0m0.003s
sys 0m0.004s
After enabling skim keybindings
real 0m0.043s
user 0m0.019s
sys 0m0.049s
After enabling mise
real 0m0.115s
user 0m0.054s
sys 0m0.097s
After enabling jj completitions (even for bookmarks)
real 0m0.186s
user 0m0.086s
sys 0m0.138s
After adding source /etc/bashrc to my bashrc
real 0m0.294s
user 0m0.146s
sys 0m0.192s
So there seems to be room for improvement. I highly doubt I need the global /etc/bashrc. Maybe I can manually add mise executables to my $PATH and call mise activate when I'm in a project folder. And author also mentions defering completitions until the first time a command is called; I should do that for jj.
Author said 30 ms for the shell itself up front. Mine comes in at about 50ms doing the same time shell -c exit test.
When I have to use other people's linux setups, the thing that drives me the most nuts are the stupid pointless animations all over the place. On my computer, I hit the hotkey, the terminal window is open almost instantly. Sometimes I can see a brief blink between the window and the prompt but it even that not always.
So doing a full end-to-end test, opening new window with shell, doing something in it, and closing it is what I care about. So i did time myterm and hit ctrl+d in the window to make it disappear all consistently in under 0.120s
Amazing how many things just not having pointless animations and compositions open up to me. I had to look for difference between two spreadsheets a few months ago... I just maximized both in separate windows and hit the window shade hotkey a couple times to flip-o-rama them. The difference was instantly visible. Trying to do the same thing on Windows with Excel doing the weird animations were just too distracting.
I wish author had shared their times; maybe I'm on the average or maybe I'm on the slow.
yeah, sub-100ms seems like a no-go for me :D
$ ls -lsha; ZDOTDIR=$(pwd) hyperfine -i --warmup 3 'zsh -i -c exit'
total 0
0 drwx------. 2 pg pg 40 Jun 6 17:20 .
0 drwxrwxrwt. 35 root root 820 Jun 6 17:20 ..
Benchmark 1: zsh -i -c exit
Time (mean ± σ): 129.8 ms ± 3.5 ms [User: 51.2 ms, System: 83.3 ms]
Range (min … max): 123.6 ms … 135.9 ms 23 runs
and my "full" config takes about the same as yours to load - about 250ms (I've managed to shave off like ~5ms on average, mostly with compinit caching, but it's not worth the effort in my opinion, as it may cause missing completions)
for a long time what I've done in emacs is initialize a background "staging shell" - then opening a terminal == open a new window with that buffer and rename it - then fork off a thread for re-staging a shell for next time. no startup delay yipeeeeee
edit: I recall trying to finagle a non-emacs solution with reptyr[1] at some point, but ended up not committing to that route, I don't remember why.
I went through some of this and found out that my zsh-abbr is eating ~100ms of startup time, but I'm perfectly okay with that. I can shave off ~10ms here and there, but none of it seems like it's worth it for the functionality I lose.
I'll live with the ~300ms startup time, as it's fast enough and I don't tend to need to throw open terminals in rapid succession, or need to type immediately.
Great post, though. Taught me about hyperfine and I dug into some of the startup files for zsh.