Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fd1e91c

Browse files
net/http: add client benchmark for gzip response
For #61353
1 parent 54f78cf commit fd1e91c

File tree

1 file changed

+87
-18
lines changed

1 file changed

+87
-18
lines changed

‎src/net/http/serve_test.go

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"compress/gzip"
1313
"compress/zlib"
1414
"context"
15+
crand "crypto/rand"
1516
"crypto/tls"
1617
"encoding/json"
1718
"errors"
@@ -5075,12 +5076,44 @@ func getNoBody(urlStr string) (*Response, error) {
50755076

50765077
// A benchmark for profiling the client without the HTTP server code.
50775078
// The server code runs in a subprocess.
5079+
//
5080+
// For use like:
5081+
//
5082+
// $ go test -c
5083+
// $ ./http.test -test.run=XX -test.bench=BenchmarkClient$ -test.benchtime=15s -test.cpuprofile=http.prof
5084+
// $ go tool pprof http.test http.prof
5085+
// (pprof) web
50785086
func BenchmarkClient(b *testing.B) {
5087+
var data = []byte("Hello world.\n")
5088+
5089+
url := startBenchmarkServer(b, func(w ResponseWriter, r *Request) {
5090+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
5091+
w.Write(data)
5092+
})
5093+
5094+
// Do b.N requests to the server.
5095+
b.StartTimer()
5096+
for i := 0; i < b.N; i++ {
5097+
res, err := Get(url)
5098+
if err != nil {
5099+
b.Fatalf("Get: %v", err)
5100+
}
5101+
body, err := io.ReadAll(res.Body)
5102+
res.Body.Close()
5103+
if err != nil {
5104+
b.Fatalf("ReadAll: %v", err)
5105+
}
5106+
if !bytes.Equal(body, data) {
5107+
b.Fatalf("Got body: %q", body)
5108+
}
5109+
}
5110+
b.StopTimer()
5111+
}
5112+
5113+
func startBenchmarkServer(b *testing.B, handler func(ResponseWriter, *Request)) string {
50795114
b.ReportAllocs()
50805115
b.StopTimer()
5081-
defer afterTest(b)
50825116

5083-
var data = []byte("Hello world.\n")
50845117
if server := os.Getenv("TEST_BENCH_SERVER"); server != "" {
50855118
// Server process mode.
50865119
port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user
@@ -5093,21 +5126,33 @@ func BenchmarkClient(b *testing.B) {
50935126
os.Exit(1)
50945127
}
50955128
fmt.Println(ln.Addr().String())
5129+
50965130
HandleFunc("/", func(w ResponseWriter, r *Request) {
50975131
r.ParseForm()
50985132
if r.Form.Get("stop") != "" {
50995133
os.Exit(0)
51005134
}
5101-
w.Header().Set("Content-Type", "text/html; charset=utf-8")
5102-
w.Write(data)
5135+
handler(w, r)
51035136
})
51045137
var srv Server
51055138
log.Fatal(srv.Serve(ln))
51065139
}
51075140

5141+
var benchmarkName string
5142+
if pc, _, _, ok := runtime.Caller(1); ok {
5143+
details := runtime.FuncForPC(pc)
5144+
name := details.Name()
5145+
_, benchmarkName, _ = strings.Cut(name, ".")
5146+
if !strings.HasPrefix(benchmarkName, "Benchmark") {
5147+
b.Fatalf("Expected to be called from BenchmarkXxx function, called from %s", name)
5148+
}
5149+
} else {
5150+
b.Fatal("Failed to get caller name")
5151+
}
5152+
51085153
// Start server process.
51095154
ctx, cancel := context.WithCancel(context.Background())
5110-
cmd := testenv.CommandContext(b, ctx, os.Args[0], "-test.run=^$", "-test.bench=^BenchmarkClient$")
5155+
cmd := testenv.CommandContext(b, ctx, os.Args[0], "-test.run=^$", "-test.bench="+benchmarkName+"$")
51115156
cmd.Env = append(cmd.Environ(), "TEST_BENCH_SERVER=yes")
51125157
cmd.Stderr = os.Stderr
51135158
stdout, err := cmd.StdoutPipe()
@@ -5123,10 +5168,6 @@ func BenchmarkClient(b *testing.B) {
51235168
done <- cmd.Wait()
51245169
close(done)
51255170
}()
5126-
defer func() {
5127-
cancel()
5128-
<-done
5129-
}()
51305171

51315172
// Wait for the server in the child process to respond and tell us
51325173
// its listening address, once it's started listening:
@@ -5139,29 +5180,57 @@ func BenchmarkClient(b *testing.B) {
51395180
b.Fatalf("initial probe of child process failed: %v", err)
51405181
}
51415182

5183+
// Instruct server process to stop.
5184+
b.Cleanup(func() {
5185+
getNoBody(url + "?stop=yes")
5186+
if err := <-done; err != nil {
5187+
b.Fatalf("subprocess failed: %v", err)
5188+
}
5189+
5190+
cancel()
5191+
<-done
5192+
5193+
afterTest(b)
5194+
})
5195+
5196+
return url
5197+
}
5198+
5199+
func BenchmarkClientGzip(b *testing.B) {
5200+
const nRandBytes = 1024 * 1024
5201+
5202+
var buf bytes.Buffer
5203+
gz := gzip.NewWriter(&buf)
5204+
if _, err := io.CopyN(gz, crand.Reader, nRandBytes); err != nil {
5205+
fmt.Fprintln(os.Stderr, err.Error())
5206+
os.Exit(1)
5207+
}
5208+
gz.Close()
5209+
5210+
data := buf.Bytes()
5211+
5212+
url := startBenchmarkServer(b, func(w ResponseWriter, r *Request) {
5213+
w.Header().Set("Content-Encoding", "gzip")
5214+
w.Write(data)
5215+
})
5216+
51425217
// Do b.N requests to the server.
51435218
b.StartTimer()
51445219
for i := 0; i < b.N; i++ {
51455220
res, err := Get(url)
51465221
if err != nil {
51475222
b.Fatalf("Get: %v", err)
51485223
}
5149-
body, err := io.ReadAll(res.Body)
5224+
n, err := io.Copy(io.Discard, res.Body)
51505225
res.Body.Close()
51515226
if err != nil {
51525227
b.Fatalf("ReadAll: %v", err)
51535228
}
5154-
if !bytes.Equal(body, data) {
5155-
b.Fatalf("Got body: %q", body)
5229+
if n!=nRandBytes {
5230+
b.Fatalf("ReadAll: expected %d, got %d", nRandBytes, n)
51565231
}
51575232
}
51585233
b.StopTimer()
5159-
5160-
// Instruct server process to stop.
5161-
getNoBody(url + "?stop=yes")
5162-
if err := <-done; err != nil {
5163-
b.Fatalf("subprocess failed: %v", err)
5164-
}
51655234
}
51665235

51675236
func BenchmarkServerFakeConnNoKeepAlive(b *testing.B) {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /