From 2ce295e9542c104110a050bf809dd0a37e191eb7 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 5 Jun 2018 21:06:17 +0000 Subject: [PATCH] net/http: remove an allocation in ServeMux MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Also, add a benchmark variant ("SkipServe") that only benchmarks the ServeMux handler selection path. name old time/op new time/op delta ServeMux_SkipServe-4 74.2µs ± 2% 60.6µs ± 1% -18.31% (p=0.000 n=10+9) name old alloc/op new alloc/op delta ServeMux_SkipServe-4 2.62kB ± 0% 0.00kB ±NaN% -100.00% (p=0.000 n=10+10) name old allocs/op new allocs/op delta ServeMux_SkipServe-4 180 ± 0% 0 ±NaN% -100.00% (p=0.000 n=10+10) Updates #25383 Change-Id: Icfbb3b977e309093d032e922d1b4f254df6f5955 Reviewed-on: https://go-review.googlesource.com/116378 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Emmanuel Odeke --- src/net/http/serve_test.go | 13 ++++++++----- src/net/http/server.go | 7 ++++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index c14d87dcf9..10651fff7c 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -608,8 +608,9 @@ func TestShouldRedirectConcurrency(t *testing.T) { mux.HandleFunc("/", func(w ResponseWriter, r *Request) {}) } -func BenchmarkServeMux(b *testing.B) { - +func BenchmarkServeMux(b *testing.B) { benchmarkServeMux(b, true) } +func BenchmarkServeMux_SkipServe(b *testing.B) { benchmarkServeMux(b, false) } +func benchmarkServeMux(b *testing.B, runHandler bool) { type test struct { path string code int @@ -641,9 +642,11 @@ func BenchmarkServeMux(b *testing.B) { for _, tt := range tests { *rw = httptest.ResponseRecorder{} h, pattern := mux.Handler(tt.req) - h.ServeHTTP(rw, tt.req) - if pattern != tt.path || rw.Code != tt.code { - b.Fatalf("got %d, %q, want %d, %q", rw.Code, pattern, tt.code, tt.path) + if runHandler { + h.ServeHTTP(rw, tt.req) + if pattern != tt.path || rw.Code != tt.code { + b.Fatalf("got %d, %q, want %d, %q", rw.Code, pattern, tt.code, tt.path) + } } } } diff --git a/src/net/http/server.go b/src/net/http/server.go index 0ac7c96de7..407546d6c9 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -2182,7 +2182,12 @@ func cleanPath(p string) string { // path.Clean removes trailing slash except for root; // put the trailing slash back if necessary. if p[len(p)-1] == '/' && np != "/" { - np += "/" + // Fast path for common case of p being the string we want: + if len(p) == len(np)+1 && strings.HasPrefix(p, np) { + np = p + } else { + np += "/" + } } return np } -- 2.48.1