From 5ff12f6269c5851cfb762357d12e9ed1e3d582e9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Martin=20M=C3=B6hrmann?= Date: Sat, 25 May 2019 14:23:34 +0200 Subject: [PATCH] net/url: use strings.IndexByte instead of strings.Index in split function MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Production profiling shows ~15% of url.Parse time being spend in the overhead of calling strings.IndexByte through strings.Index instead of calling strings.IndexByte directly. name old time/op new time/op delta Split 15.5ns ± 2% 10.7ns ± 3% -30.98% (p=0.000 n=20+19) Change-Id: Ie25dd4afa93539a1335a91ab2a4a367f97bd3df0 Reviewed-on: https://go-review.googlesource.com/c/go/+/178877 Run-TryBot: Martin Möhrmann TryBot-Result: Gobot Gobot Reviewed-by: Daniel Martí Reviewed-by: Brad Fitzpatrick --- src/net/url/url.go | 20 ++++++++++---------- src/net/url/url_test.go | 9 +++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/net/url/url.go b/src/net/url/url.go index 12ea35f0f9..504f5533ce 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -449,16 +449,16 @@ func getscheme(rawurl string) (scheme, path string, err error) { return "", rawurl, nil } -// Maybe s is of the form t c u. -// If so, return t, c u (or t, u if cutc == true). -// If not, return s, "". -func split(s string, c string, cutc bool) (string, string) { - i := strings.Index(s, c) +// split slices s into two substrings separated by the first occurence of +// sep. If cutc is true then sep is included with the second substring. +// If sep does not occur in s then s and the empty string is returned. +func split(s string, sep byte, cutc bool) (string, string) { + i := strings.IndexByte(s, sep) if i < 0 { return s, "" } if cutc { - return s[:i], s[i+len(c):] + return s[:i], s[i+1:] } return s[:i], s[i:] } @@ -471,7 +471,7 @@ func split(s string, c string, cutc bool) (string, string) { // error, due to parsing ambiguities. func Parse(rawurl string) (*URL, error) { // Cut off #frag - u, frag := split(rawurl, "#", true) + u, frag := split(rawurl, '#', true) url, err := parse(u, false) if err != nil { return nil, &Error{"parse", u, err} @@ -531,7 +531,7 @@ func parse(rawurl string, viaRequest bool) (*URL, error) { url.ForceQuery = true rest = rest[:len(rest)-1] } else { - rest, url.RawQuery = split(rest, "?", true) + rest, url.RawQuery = split(rest, '?', true) } if !strings.HasPrefix(rest, "/") { @@ -560,7 +560,7 @@ func parse(rawurl string, viaRequest bool) (*URL, error) { if (url.Scheme != "" || !viaRequest && !strings.HasPrefix(rest, "///")) && strings.HasPrefix(rest, "//") { var authority string - authority, rest = split(rest[2:], "/", false) + authority, rest = split(rest[2:], '/', false) url.User, url.Host, err = parseAuthority(authority) if err != nil { return nil, err @@ -599,7 +599,7 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) { } user = User(userinfo) } else { - username, password := split(userinfo, ":", true) + username, password := split(userinfo, ':', true) if username, err = unescape(username, encodeUserPassword); err != nil { return nil, "", err } diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go index c4875bb197..b2f9746c53 100644 --- a/src/net/url/url_test.go +++ b/src/net/url/url_test.go @@ -1874,3 +1874,12 @@ func BenchmarkPathUnescape(b *testing.B) { }) } } + +var sink string + +func BenchmarkSplit(b *testing.B) { + url := "http://www.google.com/?q=go+language#foo%26bar" + for i := 0; i < b.N; i++ { + sink, sink = split(url, '#', true) + } +} -- 2.50.0