37

Opening a file (either by typing Ctrl-x f, AKA Find File) or by typing f on that file in Dired mode), is painfully slow in working directories that have a .git subdirectory.

Even the simplest file (50 lines with mostly comments) could take up to 8 seconds to open.

The same file, in a different directory not managed by Git, opens in a jiffy, immediately.

Why is this happening and how can I fix this without disabling vc-mode? (since one of the main reasons I use Emacs is its M-x ediff-revision)

UPDATE 1: Thanks to @sanityinc's answer below, I ran ELP Profiling and this is what I received (for a very small file, 69 lines, 59 of which are plain comments):

Function Name                       Call Count   Elapsed Time  Average Time
-------------                       ----------   ------------  ------------
vc-call-backend                      11          23.023        2.093
vc-find-file-hook                    1           8.757         8.757
vc-mode-line                         1           7.812         7.812
vc-default-mode-line-string          1           7.345         7.345
vc-state-refresh                     1           6.921         6.921
vc-state                             1           6.921         6.921
vc-default-state-heuristic           1           6.921         6.921
vc-registered                        1           0.945         0.945
vc-backend                           1           0.945         0.945
vc-git-registered                    1           0.912         0.912
vc-working-revision                  1           0.4240000000  0.4240000000
vc-find-root                         4           0.0990000000  0.0247500000
vconcat                              623         0.0220000000  3.53...e-005
vc-bzr-registered                    1           0.016         0.016
vc-check-master-templates            2           0.014         0.007
vc-default-registered                2           0.014         0.007
vc-rcs-registered                    1           0.008         0.008
vc-sccs-registered                   1           0.006         0.006
vc-svn-registered                    1           0.002         0.002
vc-cvs-registered                    1           0.001         0.001
vc-sccs-search-project-dir           1           0.0           0.0
vc-kill-buffer-hook                  6           0.0           0.0
vc-find-backend-function             11          0.0           0.0
vc-default-find-file-hook            1           0.0           0.0
vc-possible-master                   6           0.0           0.0
vc-file-clearprops                   1           0.0           0.0
vc-file-setprop                      3           0.0           0.0
vc-file-getprop                      5           0.0           0.0
vc-make-backend-sym                  15          0.0           0.0

This is great information but I am not an Emacs/elisp expert, so how where do I go from here?

UPDATE 2: After putting this problem on the back burner for a while, I came across this great blog post: Cygwin slow start up: the culprit discovered! which essentially suggests starting bash completion in the background. I quickly implemented it and re-ran the ELP profiling test:

vc-call-backend                      11          14.489        1.317
vc-find-file-hook                    1           5.488         5.488
vc-mode-line                         1           5.118         5.118
vc-default-mode-line-string          1           4.719         4.719
vc-state-refresh                     1           4.282         4.282
vc-state                             1           4.282         4.282
vc-default-state-heuristic           1           4.282         4.282
vc-working-revision                  1           0.437         0.437
vc-registered                        1           0.37          0.37
vc-backend                           1           0.37          0.37
vc-git-registered                    1           0.34          0.34
vc-find-root                         4           0.088         0.022
vc-bzr-registered                    1           0.015         0.015
vc-check-master-templates            2           0.013         0.0065 
vc-default-registered                2           0.013         0.0065 
vc-rcs-registered                    1           0.007         0.007
vc-sccs-registered                   1           0.006         0.006
vc-cvs-registered                    1           0.001         0.001
vconcat                              623         0.001         1.60...e-006
vc-svn-registered                    1           0.001         0.001
vc-sccs-search-project-dir           1           0.0           0.0
vc-kill-buffer-hook                  6           0.0           0.0
vc-find-backend-function             11          0.0           0.0
vc-default-find-file-hook            1           0.0           0.0
vc-possible-master                   6           0.0           0.0
vc-file-clearprops                   1           0.0           0.0
vc-file-setprop                      3           0.0           0.0
vc-file-getprop                      5           0.0           0.0
vc-make-backend-sym                  15          0.0           0.0

It's great to see vc-call-backend going down from 23 seconds to 14 seconds, but this is still unacceptable (finding a CVS-controlled file takes less than a split-second!).

UPDATE 3: Unable to solve the mystery, I tried my luck by upgrading to the latest cygwin (1.7.9-1). That didn't help.

So, I decided to try moving the sandbox (along with its .git subdirectory) from the Samba share to local storage (C:\Users\WinWin\Documents). I then re-ran the ELP profiling test:

vc-call-backend                           11          2.082         0.1892727272
vc-find-file-hook                         1           0.897         0.897
vc-git--call                              7           0.8929999999  0.1275714285
vc-git-mode-line-string                   1           0.78          0.78
vc-mode-line                              1           0.78          0.78
vc-default-mode-line-string               1           0.655         0.655
vc-git--out-ok                            5           0.6519999999  0.1304
vc-git-state                              1           0.53          0.53
vc-state-refresh                          1           0.53          0.53
vc-state                                  1           0.53          0.53
vc-default-state-heuristic                1           0.53          0.53
vc-git-working-revision                   2           0.25          0.125
vc-git-registered                         2           0.2239999999  0.1119999999
vc-git--run-command-string                1           0.18          0.18
vc-working-revision                       1           0.125         0.125
vc-registered                             1           0.1169999999  0.1169999999
vc-backend                                2           0.1169999999  0.0584999999
vc-git--empty-db-p                        1           0.11          0.11
vc-find-root                              3           0.003         0.001
vc-git-root                               2           0.002         0.001
vc-check-master-templates                 2           0.001         0.0005
vc-sccs-registered                        1           0.001         0.001
vc-default-registered                     2           0.001         0.0005
vc-bzr-registered                         1           0.001         0.001
vc-rcs-registered                         1           0.0           0.0
vc-sccs-search-project-dir                1           0.0           0.0
vc-kill-buffer-hook                       5           0.0           0.0
vc-default-find-file-hook                 1           0.0           0.0
vc-possible-master                        6           0.0           0.0
vc-cvs-registered                         1           0.0           0.0
vc-file-clearprops                        1           0.0           0.0
vc-file-setprop                           3           0.0           0.0
vc-file-getprop                           5           0.0           0.0
vc-svn-registered                         1           0.0           0.0
vc-make-backend-sym                       2           0.0           0.0

Wow! That lowered vc-call-backend from 14 seconds to 2 seconds. This is great but not wonderful, because with Emacs/CVS I am able to visit a file in less than 35ms -- on the same Samba share where the sandbox originally resides:

vc-call-backend                           5           0.031         0.0062
vc-find-file-hook                         1           0.031         0.031
vc-registered                             1           0.031         0.031
vc-backend                                1           0.031         0.031
vc-rcs-registered                         1           0.016         0.016
vc-check-master-templates                 1           0.016         0.016
vc-default-registered                     1           0.016         0.016
vc-insert-file                            1           0.015         0.015
vc-cvs-get-entries                        1           0.015         0.015
vc-cvs-registered                         1           0.015         0.015
vc-cvs-state-heuristic                    1           0.0           0.0
vc-cvs-parse-sticky-tag                   1           0.0           0.0
vc-kill-buffer-hook                       1           0.0           0.0
vc-find-backend-function                  1           0.0           0.0
vc-cvs-parse-entry                        1           0.0           0.0
vc-mode-line                              1           0.0           0.0
vc-default-find-file-hook                 1           0.0           0.0
vc-possible-master                        3           0.0           0.0
vc-cvs-mode-line-string                   1           0.0           0.0
vc-default-mode-line-string               1           0.0           0.0
vc-state-refresh                          1           0.0           0.0
vc-working-revision                       1           0.0           0.0
vc-state                                  1           0.0           0.0
vc-file-clearprops                        1           0.0           0.0
vc-file-setprop                           5           0.0           0.0
vc-file-getprop                           7           0.0           0.0
vc-make-backend-sym                       2           0.0           0.0

This raises 2 questions:

  1. What in the combination of git+cygwin makes it so sensitive to network speed?
  2. How can I make git go down to less than 50ms? After all, it is call "the fast version control system"

Update when using msysgit 1.7.8:

vc-call-backend                      11          0.626         0.0569090909
vc-find-file-hook                    1           0.281         0.281
vc-mode-line                         1           0.2189999999  0.2189999999
vc-default-mode-line-string          1           0.1879999999  0.1879999999
vc-state-refresh                     1           0.157         0.157
vc-state                             1           0.157         0.157
vc-default-state-heuristic           1           0.157         0.157
vc-registered                        1           0.062         0.062
vc-backend                           1           0.062         0.062
vc-git-registered                    1           0.062         0.062
vc-working-revision                  1           0.0310000000  0.0310000000
vc-rcs-registered                    1           0.0           0.0
vc-sccs-search-project-dir           1           0.0           0.0
vc-kill-buffer-hook                  6           0.0           0.0
vc-find-backend-function             11          0.0           0.0
vc-default-find-file-hook            1           0.0           0.0
vc-possible-master                   6           0.0           0.0
vc-check-master-templates            2           0.0           0.0
vc-cvs-registered                    1           0.0           0.0
vc-sccs-registered                   1           0.0           0.0
vc-file-clearprops                   1           0.0           0.0
vconcat                              623         0.0           0.0
vc-default-registered                2           0.0           0.0
vc-file-setprop                      3           0.0           0.0
vc-find-root                         4           0.0           0.0
vc-file-getprop                      5           0.0           0.0
vc-bzr-registered                    1           0.0           0.0
vc-svn-registered                    1           0.0           0.0
vc-make-backend-sym                  15          0.0           0.0

Can you tell the difference? :)

Git under Emacs is way faster now, but it still much much slower than CVS under Emacs. So I have no idea why Git is called the "Fast Version Control System". It may be better than CVS, but faster?

WinWin
  • 7,493
  • 10
  • 44
  • 53
  • 1
    More info about the state of the repository would be useful, e.g. a) Is the file registered with git? b) are there other unregistered files? c) Are there files in the repo which have large modifications pending? – sanityinc Jul 18 '11 at 21:45
  • @sanityinc (a) Yes, the file is registered with git, relatively new file, only 2 commits so far. (b) All files are registered, except for one "gitignored" subdirectory. (c) All files in the repo are fully committed, no modifications pending. P.S. It's a quad-core 64-bit machine, so there should be no excuses for the slowness of this thing. :) – WinWin Jul 18 '11 at 21:54
  • Does it take a long time to run `M-! git status` while you've got that file open? ie. can Emacs at least execute your git fairly efficiently? – sanityinc Jul 19 '11 at 06:57
  • 1
    @sanityinc It takes **5-6 seconds** to `M-! git status` while that file is open in Emacs. – WinWin Jul 19 '11 at 19:13
  • 1
    And presumably git is much faster on the command line? Are you using git via Cygwin? – sanityinc Jul 21 '11 at 08:04
  • @sanityinc Actually it isn't faster at all, but that's not surprising because `M-!` *is* basically the same as running from the command line. Answering your 2nd question: **Yes, I am using git via Cygwin**. – WinWin Jul 21 '11 at 13:17
  • So I'd guess the underlying issue here is that your git is slow. My advice would be to investigate any known performance issues with git on Windows, or specifically under Cygwin. – sanityinc Jul 22 '11 at 10:32
  • @sanityinc See my latest update 4.5 months later. Additional ideas? Much thanks! – WinWin Dec 04 '11 at 22:18
  • 2
    Windows is weird. My bash prompt takes a few seconds to display under cygwin for no reason I can determine. I imagine some related effect is causing your git invocations to take forever. The problem is with your git binary (or filesystem), not with Emacs. FWIW, I've had fine luck with Windows Emacs and Windows (msys) Git. Why do you need cygwin? – jrockway Dec 05 '11 at 03:42
  • @jrockway I need cygwin because I have the same exact environment regardless whether I work on Windows or Linux/UNIX. This is how I have been working for a very long time and I can't let cygwin go. Many of my productivity scripts depend on it. Now, if you tell me that I can retain cygwin, but get rid of its git implementation and use msys instead, that's a horse of a different color... +1 :) Also, see my update above. Git is definitely doing something nasty to vc-mode (compared to CVS). – WinWin Dec 26 '11 at 02:57
  • If this is caused by git on cygwin but not msysgit, you can ask on the git mailing list to see if there's a specific explanation someone there might very well be able to provide. My guess is that this is related to cygwin's emulation of fork processes – prusswan Dec 26 '11 at 03:24
  • @WinWin: absolutely. Use cygwin for cygwin stuff. Use Windows for Emacs and Git. You can easily have a M-x shell in cygwin and a M-x eshell in Windows, for example. (I don't use Windows anymore, but when I did, I always had cygwin and msys environments set up. cygwin was a "last resort" for me; nice to have, but not something that I use everyday.) – jrockway Dec 27 '11 at 04:23

4 Answers4

43

There's a built-in profiler called ELP. You can try something like M-x elp-instrument-package, enter "vc", and then try finding a file. Afterwards, M-x elp-results will show you a profile report.

(Note that if the time is instead being spent in non-vc-related functions, this technique will not show it, but you can instrument further packages if you like.)

sanityinc
  • 15,002
  • 2
  • 49
  • 43
  • 1
    Accepting as your tip was the most helpful one to getting close to solving the mystery. I tend to accept your observation that the problem may lie in my `git` setup, not Emacs. I will try to address this in a separate thread. Thank again. – WinWin Jul 26 '11 at 17:23
4

You can try to profile the opening of your file to see exactly what takes so much time.

Francois G
  • 11,957
  • 54
  • 59
  • Thanks +1 for bringing the [Emacs Native Profiler](http://cx4a.org/hack/emacs-native-profiler.html) to my attention as I didn't know about it before. Unfortunately, at the bottom it says *"Currently, only Linux is supported"* and I am using Emacs under Windows 7. – WinWin Jul 17 '11 at 22:32
3

I had the same problem with using windows git 2.10 from mingw emacs 25.1.1.

Using the following to test:

(progn
  ;; make sure the buffer is not already open
  (elp-instrument-function 'find-file-other-window)
  (elp-instrument-function 'vc-git-registered)
  (elp-instrument-function 'vc-git-mode-line-string)
  (elp-instrument-function 'vc-git-find-file-hook)
  (find-file-other-window "my-file-in-a-git-repo")
  (elp-results)
  (elp-restore-all))

Gave the following profile:

find-file-other-window   1           1.1076142     1.1076142
vc-git-mode-line-string  1           0.6396082     0.6396082
vc-git-find-file-hook    1           0.2652034     0.2652034
vc-git-registered        1           0.1872024     0.1872024

The vc-git-mode-line-string function takes a while. This shows something like Git:mybranch in the mode line of your window. I don't care enough about that to wait for it every time, so I overwrite the implementation to just return "Git":

(defun vc-git-mode-line-string (file)
  "Overwritten default vc-git-el implementation. Return a string
for `vc-mode-line' to put in the mode line for FILE."
  "Git")

The vc-git-find-file-hook function will open a pretty conflict editing mode if you're opening a conflicted file. The implementation was first calling vc-git-conflicted-files which takes a while, and then doing a rather trivial check whether any lines start with <<<<<<<. I simply swapped the two, and now the implementation takes about 0.0 seconds in most cases.

(defun vc-git-find-file-hook ()
  "Overwritten default vc-git-el implementation. Activate
`smerge-mode' if there is a conflict."
  (when (and buffer-file-name
             ;; FIRST check whether this file looks like a conflicted file
             (save-excursion
               (goto-char (point-min))
               (re-search-forward "^<<<<<<< " nil 'noerror))
             ;; THEN ask git if it really is a conflict
             (vc-git-conflicted-files buffer-file-name))
    (vc-file-setprop buffer-file-name 'vc-state 'conflict)
    (smerge-start-session)
    (when vc-git-resolve-conflicts
      (add-hook 'after-save-hook 'vc-git-resolve-when-done nil 'local))
    (vc-message-unresolved-conflicts buffer-file-name)))

Results:

find-file-other-window   1           0.2838039     0.2838039
vc-git-registered        1           0.2682037     0.2682037
vc-git-find-file-hook    1           0.0           0.0
vc-git-mode-line-string  1           0.0           0.0
Yorick Sijsling
  • 920
  • 1
  • 6
  • 9
2

You can disable vc-mode by setting vc-handled-backends to nil in your .emacs.

robert
  • 33,242
  • 8
  • 53
  • 74
  • @robert & @Alex Ott One of the main reasons I use Emacs is `ediff-revisions`. Isn't there a better way to speed up things? After all, Emacs doesn't do that with files under CVS version control... – WinWin Jul 17 '11 at 16:42