I try to dig deeper into this problem by setting (setq tramp-verbose 10)
.
Here is one possible step for reproducing the slowness:
git clone https://github.com/openjdk-mirror/jdk7u-hotspot.git
on server A and create a test
branch base on master
branch.
- using tramp to visit a file in above project
- run
magit-checkout test
And find the slowness is caused by that tramp tries to find the end of remote command's output by searching some pattern in tramp-wait-for-output
function's line (tramp-wait-for-regexp proc timeout regexp1)
. In this case:
regexp1
is "\\(^\\|\000\\)[^#$\n]*///deab18b5e34aa7487addb2439bbab2a9#\\$\r?$"
proc
's buffer string is the output of command: git "--no-pager" "--literal-pathspecs" "-c" "core.preloadindex=true" ls-tree -z -r --name-only HEAD
in above git repository. Which is one quite huge line. In my test case, it is a line with 226383
character and split by null. Here is part of it: .hgignore^@.hgtags^@.jcheck/conf^@ASSEMBLY_EXCEPTION^@LICENSE^@README^@
timeout
argument is nil
So I walk around this issue by modifying tramp-check-for-regexp
to below:
(defun tramp-check-for-regexp (proc regexp)
"Check, whether REGEXP is contained in process buffer of PROC.
Erase echoed commands if exists."
(with-current-buffer (process-buffer proc)
(if (> (point-max) 1000)
(progn
(goto-char (point-max))
(ignore-errors (re-search-backward regexp (- (point-max) 1000) t)))
(progn
(goto-char (point-min))
;; Check whether we need to remove echo output.
(when (and (tramp-get-connection-property proc "check-remote-echo" nil)
(re-search-forward tramp-echoed-echo-mark-regexp nil t))
(let ((begin (match-beginning 0)))
(when (re-search-forward tramp-echoed-echo-mark-regexp nil t)
;; Discard echo from remote output.
(tramp-set-connection-property proc "check-remote-echo" nil)
(tramp-message proc 5 "echo-mark found")
(forward-line 1)
(delete-region begin (point))
(goto-char (point-min)))))
(when (or (not (tramp-get-connection-property proc "check-remote-echo" nil))
;; Sometimes, the echo string is suppressed on the remote side.
(not (string-equal
(tramp-compat-funcall
'substring-no-properties tramp-echo-mark-marker
0 (min tramp-echo-mark-marker-length (1- (point-max))))
(tramp-compat-funcall
'buffer-substring-no-properties
(point-min)
(min (+ (point-min) tramp-echo-mark-marker-length)
(point-max))))))
;; No echo to be handled, now we can look for the regexp.
;; Sometimes, lines are much to long, and we run into a "Stack
;; overflow in regexp matcher". For example, //DIRED// lines of
;; directory listings with some thousand files. Therefore, we
;; look from the end.
(goto-char (point-max))
(ignore-errors (re-search-backward regexp nil t)))))))
I add checking whether the buffer is larger than 1000 point, if yes, add "bound" to re-search-backward
and ignore other checking and processing. This is really a dirty hack without any considering of other case using tramp-check-for-regexp
.
However, it reduces the magit-checkout
time from 25s
to 3s
.
Hope tramp could fix this issue in the future.