Description
Projectile makes extensive use of the shell-command-to-string
elisp function when it uses the 'alien
indexing method. The advantage of this is, I presume, that the appropriate binary will automatically be detected based on the users shell configuration.
However, for people with non-trivial shell startup times there is a somewhat steep performance penalty to this approach. I have an extensive zsh configuration, but I have made an effort to keep it as lean as possible, and I still see a significant performance penalty to shell-command-to-string
.
I used this measure-time macro to investigate this
(defmacro measure-time (&rest body)
"Measure and return the running time of the code block."
(declare (indent defun))
(let ((start (make-symbol "start")))
`(let ((,start (float-time)))
,@body
(- (float-time) ,start))))
Unfortunately, because of the way that git works, we need to invoke the git-ls-files command directly. (supplying the ls-files argument doesnt work.
(measure-time
(call-process "/usr/local/opt/git/libexec/git-core/git-ls-files" nil "git-ls-output" "-zco" "--exclude-standard")) => 0.02278304100036621
(measure-time
(shell-command-to-string projectile-git-command)) => 0.5086848735809326
This is an order of magnitude difference, and because projectile actually invokes MULTIPLE shell commands for each emacs command, this penalty is paid several times.
I realize that rearchitechting this would be somewhat difficult, but would you be open to a change to use call-process
when the path to git subcommands is explicitly specified?
Projectile version information
Projectile version: 0.13
Emacs version
E.g. 25.1
Operating system
OSX Yosemite