Subject: Re: bug#34343: [PATCH] Make project--find-regexp-in-files work with remote files

From: Michael Albinus <[email-masked]>
Date: Fri, 03 Jan 2020 10:28:07 +0100

Dmitry Gutov <[email-masked]> writes:

> But most importantly for now: tramp-handle-file-remote-p does not take
> up the majority of time spent in
> file-remote-p. tramp-file-name-handler does:
>
> ELISP> (benchmark 10000 '(file-remote-p "/ssh:[email-masked]:/%d"
>                                  nil t))
> "Elapsed time: 3.535115s (2.112970s in 27 GCs)"
>
> ELISP> (benchmark 10000 '(tramp-handle-file-remote-p
> "/ssh:[email-masked]:/%d" nil t))
> "Elapsed time: 0.780867s (0.645621s in 8 GCs)"
>
> ELISP> (benchmark 10000 '(find-file-name-handler "/ssh:[email-masked]:/"
> 'file-remote-p))
> "Elapsed time: 0.070135s"
>
> ELISP> (benchmark 10000 '(tramp-file-name-handler 'file-remote-p
> "/ssh:[email-masked]:/%d"  nil t))
> "Elapsed time: 3.409674s (2.070461s in 27 GCs)"
>
> And that function does a lot of things that I'm not sure we need to
> just get the remote id.

Yes. But in case you want to be generic (handling all possible remote
file names, not only the Tramp implementation), you must use the file
name handler implementation, as it is described in
(info "(elisp) Magic File Names")

In case you want to go your own path, I could provide you an own
tramp-file-local-name function, which bypasses this mechanism:

--8<---------------cut here---------------start------------->8---
;; This function bypasses the file name handler approach.  It is NOT
;; recommended to use it in any package if not absolutely necessary,
;; because it won't work for remote file names not supported by Tramp.
;; However, it is more performant than `file-local-name', and might be
;; useful where performance matters, like in operations over a bulk
;; list of file names.
(defun tramp-file-local-name (file)
  "Return the local name component of FILE.
This function removes from FILE the specification of the remote
host and the method of accessing the host, leaving only the part
that identifies FILE locally on the remote system.  FILE must be
a string that matches `tramp-file-name-regexp'.
The returned file name can be used directly as argument of
‘process-file’, ‘start-file-process’, or ‘shell-command’."
  (and (tramp-tramp-file-p file)
       (string-match (nth 0 tramp-file-name-structure) file)
       (match-string (nth 4 tramp-file-name-structure) file)))
--8<---------------cut here---------------end--------------->8---

Here are the performance figures for local and remote files. I still use
the dolist construct in order to have different file names for every
file-local-name call; this avoids possible caching effects.

--8<---------------cut here---------------start------------->8---
(benchmark-run-compiled
    nil
  (let* ((dir "/path")
	 (remote (file-remote-p  dir)))
    (dotimes (i 10000)
      (if remote
	  (tramp-file-local-name (format "%s/%d" dir i))
	(format "%s/%d" dir i)))))

(0.09890154 1 0.07902910999999996)
--8<---------------cut here---------------end--------------->8---

--8<---------------cut here---------------start------------->8---
(benchmark-run-compiled
    nil
  (let* ((dir "/ssh:[email-masked]:/path")
	 (remote (file-remote-p  dir)))
    (dotimes (i 10000)
      (if remote
	  (tramp-file-local-name (format "%s/%d" dir i))
	(format "%s/%d" dir i)))))

(0.370237273 2 0.05851823899999997)
--8<---------------cut here---------------end--------------->8---

So it is four times slower for remote file names, but I believe the
numbers are acceptable. At least compared with file-local-name.