internal/span: optimise URI.Filename to avoid allocation
This change adds a fast-path check for the common case:
"file:", lowercase, followed by a simple POSIX absolute
file name without special characters.
This function used to account for 1% of CPU on the DidChange
benchmark (and I'm sure I've seen higher fractions on other
tests--but perhaps that was before the clone optimizations?).
It was tested by adding an assertion that it agrees with the
slow path and running all our tests.
Change-Id: I15492b8a317715468870b00041bf8f6b0bb53bb2
Reviewed-on: https://go-review.googlesource.com/c/tools/+/411900
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Run-TryBot: Alan Donovan <adonovan@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
diff --git a/internal/span/uri.go b/internal/span/uri.go
index f2b39ca..8132665 100644
--- a/internal/span/uri.go
+++ b/internal/span/uri.go
@@ -35,13 +35,29 @@
}
func filename(uri URI) (string, error) {
- // This function is frequently called and its cost is
- // dominated by the allocation of a net.URL.
- // TODO(adonovan): opt: replace by a bespoke parseFileURI
- // function that doesn't allocate.
if uri == "" {
return "", nil
}
+
+ // This conservative check for the common case
+ // of a simple non-empty absolute POSIX filename
+ // avoids the allocation of a net.URL.
+ if strings.HasPrefix(string(uri), "file:///") {
+ rest := string(uri)[len("file://"):] // leave one slash
+ for i := 0; i < len(rest); i++ {
+ b := rest[i]
+ // Reject these cases:
+ if b < ' ' || b == 0x7f || // control character
+ b == '%' || b == '+' || // URI escape
+ b == ':' || // Windows drive letter
+ b == '@' || b == '&' || b == '?' { // authority or query
+ goto slow
+ }
+ }
+ return rest, nil
+ }
+slow:
+
u, err := url.ParseRequestURI(string(uri))
if err != nil {
return "", err
@@ -54,6 +70,7 @@
if isWindowsDriveURIPath(u.Path) {
u.Path = strings.ToUpper(string(u.Path[1])) + u.Path[2:]
}
+
return u.Path, nil
}