2016-07-04 追記:

解決しているということで、再度同じバージョンで確認しようとしたところ、そもそも再現できませんでした。 なにかおかしな設定をしてしまったのかもしれません。 十分に調査せずに嘘情報を流してしまったようです。お詫びします。

環境:

  • Windows 7
  • GNU Emacs 24.2.1 (i386-mingw-nt6.1.7601) of 2012-12-08 on GNUPACK
  • git version 1.8.5.2.msysgit.0

elp-instrument-package で magit を指定して g (magit-refresh) を実行した結果

Function Name                                   Call Count  Elapsed Time  Average Time
magit-refresh-status                            1           16.226        16.226
magit-mode-refresh-buffer                       1           16.226        16.226
magit-refresh                                   1           16.226        16.226
magit-git-string                                26          11.213999999  0.4313076923
magit-get-tracked-branch                        3           4.7490000000  1.5830000000
magit-get                                       9           3.882         0.4313333333
magit-git-dir                                   8           3.443         0.430375
magit-insert-status-remote-line                 1           3.019         3.019
magit-git-lines                                 5           2.4010000000  0.4802000000
magit-insert-unpushed-commits                   1           2.162         2.162
magit-insert-unpulled-commits                   1           2.16          2.16
magit-get-ref                                   4           1.7309999999  0.4327499999
magit-get-current-branch                        4           1.7309999999  0.4327499999
magit-git-exit-code                             3           1.31          0.4366666666
magit-get-all                                   3           1.292         0.4306666666
magit-bisecting-p                               3           1.291         0.4303333333
magit-insert-status-head-line                   1           0.867         0.867
magit-insert-untracked-files                    1           0.866         0.866
magit-insert-staged-changes                     1           0.863         0.863
magit-insert-status-tags-line                   1           0.863         0.863
magit-format-tracked-line                       1           0.863         0.863
magit-git-success                               2           0.863         0.4315
magit-read-rewrite-info                         2           0.861         0.4305
magit-rebase-info                               1           0.86          0.86
magit-insert-status-rebase-lines                1           0.86          0.86
magit-insert-stashes                            1           0.674         0.674
magit-get-next-tag                              1           0.432         0.432
magit-insert-bisect-rest                        1           0.432         0.432
magit-insert-status-merge-line                  1           0.432         0.432
magit-get-boolean                               1           0.431         0.431
magit-insert-unstaged-changes                   1           0.431         0.431
magit-insert-pending-changes                    1           0.431         0.431
magit-get-current-tag                           1           0.431         0.431
magit-anything-staged-p                         1           0.43          0.43
magit-format-rev-summary                        1           0.43          0.43
magit-insert-bisect-output                      1           0.43          0.43
magit-insert-status-local-line                  1           0.43          0.43
magit-insert-pending-commits                    1           0.43          0.43
magit-insert-bisect-log                         1           0.429         0.429
magit-file-lines                                1           0.001         0.001
magit-remember-point                            2           0.0           0.0
magit-map-sections                              6           0.0           0.0
magit-insert-empty-line                         1           0.0           0.0
magit-wash-raw-diffs                            1           0.0           0.0
magit-find-section                              16          0.0           0.0
magit-refresh-marked-commits-in-buffer          1           0.0           0.0
magit-find-section-at                           5           0.0           0.0
magit-wash-sequence                             3           0.0           0.0
magit-diff-abbrev-arg                           3           0.0           0.0
magit-current-section                           5           0.0           0.0
magit-correct-point-after-command               2           0.0           0.0
magit-wash-log                                  2           0.0           0.0
magit-section-set-hidden                        6           0.0           0.0
magit-section-path                              19          0.0           0.0
magit-decode-git-path                           1           0.0           0.0
magit-highlight-section                         3           0.0           0.0
magit-flatten-onelevel                          3           0.0           0.0

magit-refresh に 16.2秒かかり、 magit-git-string は 26回呼ばれ 11.2 秒、 magit-git-lines は 5回呼ばれ 2.4 秒掛かっている。

magit-git-exit-code, magit-git-string, magit-git-insert, magit-git-lines の process-file を process-file-shell-command に置き換える。

(defun magit-git-exit-code (&rest args)
  "Execute Git with ARGS, returning its exit code."
  (apply #'process-file-shell-command magit-git-executable nil nil nil
         (append magit-git-standard-options args)))

(defun magit-git-string (&rest args)
  "Execute Git with ARGS, returning the first line of its output.
If there is no output return nil.  If the output begins with a
newline return an empty string."
  (with-temp-buffer
    (apply #'process-file-shell-command magit-git-executable nil (list t nil) nil
           (append magit-git-standard-options args))
    (unless (= (point-min) (point-max))
      (goto-char (point-min))
      (buffer-substring-no-properties
       (line-beginning-position)
       (line-end-position)))))

(defun magit-git-insert (&rest args)
  "Execute Git with ARGS, inserting its output at point."
  (apply #'process-file-shell-command magit-git-executable nil (list t nil) nil
         (append magit-git-standard-options args)))

(defun magit-git-lines (&rest args)
  "Execute Git with ARGS, returning its output as a list of lines.
Empty lines anywhere in the output are omitted."
  (with-temp-buffer
    (apply #'process-file-shell-command magit-git-executable nil (list t nil) nil
           (append magit-git-standard-options args))
    (split-string (buffer-string) "\n" 'omit-nulls)))

結果は

Function Name                                   Call Count  Elapsed Time  Average Time
magit-refresh-status                            1           2.771         2.771
magit-mode-refresh-buffer                       1           2.771         2.771
magit-refresh                                   1           2.771         2.771
magit-git-string                                26          0.9370000000  0.0360384615
magit-insert-unpushed-commits                   1           0.574         0.574
magit-insert-unpulled-commits                   1           0.572         0.572
magit-insert-unstaged-changes                   1           0.433         0.433
magit-git-lines                                 5           0.424         0.0848
magit-get-tracked-branch                        3           0.388         0.1293333333
magit-get                                       9           0.3170000000  0.0352222222
magit-git-dir                                   8           0.2850000000  0.0356250000
magit-insert-stashes                            1           0.279         0.279
magit-insert-status-remote-line                 1           0.247         0.247
magit-get-ref                                   4           0.1420000000  0.0355000000
magit-get-current-branch                        4           0.1420000000  0.0355000000
magit-git-exit-code                             3           0.1099999999  0.0366666666
magit-bisecting-p                               3           0.1070000000  0.0356666666
magit-get-all                                   3           0.1060000000  0.0353333333
magit-insert-status-head-line                   1           0.085         0.085
magit-insert-untracked-files                    1           0.075         0.075
magit-insert-staged-changes                     1           0.074         0.074
magit-git-success                               2           0.074         0.037
magit-insert-status-tags-line                   1           0.073         0.073
magit-read-rewrite-info                         2           0.072         0.036
magit-rebase-info                               1           0.071         0.071
magit-insert-status-rebase-lines                1           0.071         0.071
magit-format-tracked-line                       1           0.07          0.07
magit-format-rev-summary                        1           0.05          0.05
magit-get-next-tag                              1           0.038         0.038
magit-anything-staged-p                         1           0.037         0.037
magit-insert-bisect-log                         1           0.036         0.036
magit-insert-status-local-line                  1           0.036         0.036
magit-insert-bisect-rest                        1           0.036         0.036
magit-insert-pending-commits                    1           0.036         0.036
magit-insert-pending-changes                    1           0.036         0.036
magit-insert-status-merge-line                  1           0.036         0.036
magit-get-boolean                               1           0.035         0.035
magit-insert-bisect-output                      1           0.035         0.035
magit-get-current-tag                           1           0.035         0.035
magit-remember-point                            2           0.0           0.0
magit-map-sections                              6           0.0           0.0
magit-insert-empty-line                         1           0.0           0.0
magit-wash-raw-diffs                            1           0.0           0.0
magit-find-section                              16          0.0           0.0
magit-refresh-marked-commits-in-buffer          1           0.0           0.0
magit-find-section-at                           5           0.0           0.0
magit-file-lines                                1           0.0           0.0
magit-wash-sequence                             3           0.0           0.0
magit-diff-abbrev-arg                           3           0.0           0.0
magit-current-section                           5           0.0           0.0
magit-correct-point-after-command               2           0.0           0.0
magit-wash-log                                  2           0.0           0.0
magit-section-set-hidden                        6           0.0           0.0
magit-section-path                              19          0.0           0.0
magit-decode-git-path                           1           0.0           0.0
magit-highlight-section                         3           0.0           0.0
magit-flatten-onelevel                          3           0.0           0.0

magit-refresh は 2.7 秒になった。

process-file と process-file-shell-command の違いは cmdproxy.exe を経由することのようである。

benchmark 関数を使うと簡単に試せる。

(benchmark 10 '(process-file magit-git-executable nil nil nil))
=> "Elapsed time: 4.309000s"

(benchmark 10 '(process-file-shell-command magit-git-executable nil nil nil))
=> "Elapsed time: 0.351000s"

Cygwin Git を試しても違いはない。

(setq magit-git-executable "c:/cygwin/bin/git.exe")

(benchmark 10 '(process-file magit-git-executable nil nil nil))
=> "Elapsed time: 5.583000s"

(benchmark 10 '(process-file-shell-command magit-git-executable nil nil nil))
=> "Elapsed time: 0.371000s"
  • なぜ cmdproxy.exe を経由すると速くなるのか?
  • cmdproxy.exe を真似して gitproxy.exe を作っても解決するか?

参考