Optimising tig's bash completion by a factor of 1000
Has this ever happened to you?
~/linux.git (master) $ tig log v5.4-<tab> [swearing] [fetching another cup of tea] [some more swearing] [coworkers looking funny at you] [1 minute later] ~/linux.git (master) $ tig log v5.4-rc1
Until yesterday, the bash completion for tig, the ncurses git viewer, was horribly slow in large Git repositories. This mostly stemmed from the fact that it was forked off from the upstream git bash completion a few years ago, and never updated since. Back then, the git bash completion itself was slow in those cases, but since then upstream had more eyeballs and people power to optimise its completion for those large repos, like the linux repo.
The problem gets worse once you consider that bash completions can not be aborted by a Ctrl-C, which means that your current shell is basically unusable for a minute while you wait for the completion to complete. On a heavily loaded build server, the runtime can easily exceed 2 minutes. Add to that the frustration when you realise you shouldn't have accidentally pressed Tab…
The corresponding bug report for tig has been existing since March 2018, and that tab has been open in my browser for some time now… so let's see how to solve this. (A quick look on the corresponding xkcd shows I can spend about 4 hours on that topic… :-))
A preliminary evaluation already shows how much faster we can be. Compare the runtime of tig's file completion function with the one from git:
linux.git (master) $ time __tig_complete_file real 0m29.363s user 0m27.805s sys 0m1.600s linux.git (master) $ time __git_complete_file real 0m0.063s user 0m0.051s sys 0m0.012s
Holy cow, that's already a factor of 466! And these times are mostly reproducible, so caching issues can be ruled out.
Since tig takes basically the same command line options as git-log and git-diff, the easiest solution is to reuse git's own completion here, so that's what I did in Pull Request #960. With that, we also don't need to fix tig's completion whenever git commands get shiny new options, and we also pull in all other optimisations from git's completion.
That being said, here is a comparison of the old and new version of the full completion function in an extreme case, showing a speedup of 1863:
linux.git (master) $ uptime 16:45:52 up 36 days, 3:33, 224 users, load average: 24.17, 38.87, 31.21 # The old completion: linux.git (master) $ time COMP_WORDS=("tig log") COMP_CWORD=2 _tig real 2m1.145s user 1m40.379s sys 0m1.347s # The new completion: linux.git (master) $ time COMP_WORDS=("tig log") COMP_CWORD=2 __git_wrap_tig real 0m0.127s user 0m0.085s sys 0m0.024s