From a66aa77c2d54c1c543ea3107ed8aeca1c1beef57 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 22 Jan 2015 22:54:18 +0300 Subject: [PATCH] net/http: add client benchmark BenchmarkClient is intended for profiling the client without the HTTP server code. The server code runs in a subprocess. Change-Id: I9aa128604d0d4e94dc5c0372dc86f962282ed6e8 Reviewed-on: https://go-review.googlesource.com/3164 Reviewed-by: Brad Fitzpatrick --- src/net/http/serve_test.go | 79 +++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index eb695e2549d..8086ef08007 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -2891,7 +2891,7 @@ func BenchmarkServer(b *testing.B) { defer ts.Close() b.StartTimer() - cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer") + cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer$") cmd.Env = append([]string{ fmt.Sprintf("TEST_BENCH_CLIENT_N=%d", b.N), fmt.Sprintf("TEST_BENCH_SERVER_URL=%s", ts.URL), @@ -2902,6 +2902,83 @@ func BenchmarkServer(b *testing.B) { } } +// A benchmark for profiling the client without the HTTP server code. +// The server code runs in a subprocess. +func BenchmarkClient(b *testing.B) { + b.ReportAllocs() + b.StopTimer() + port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user + if port == "" { + port = "39207" + } + var data = []byte("Hello world.\n") + if server := os.Getenv("TEST_BENCH_SERVER"); server != "" { + // Server process mode. + HandleFunc("/", func(w ResponseWriter, r *Request) { + r.ParseForm() + if r.Form.Get("stop") != "" { + os.Exit(0) + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write(data) + }) + log.Fatal(ListenAndServe(":"+port, nil)) + } + + // Start server process. + cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkClient$") + cmd.Env = append(os.Environ(), "TEST_BENCH_SERVER=yes") + if err := cmd.Start(); err != nil { + b.Fatalf("subprocess failed to start: %v", err) + } + defer cmd.Process.Kill() + done := make(chan error) + go func() { + done <- cmd.Wait() + }() + + // Wait for the server process to respond. + url := "http://localhost:" + port + "/" + for i := 0; i < 100; i++ { + time.Sleep(50 * time.Millisecond) + if _, err := Get(url); err == nil { + break + } + if i == 99 { + b.Fatalf("subprocess does not respond") + } + } + + // Do b.N requests to the server. + b.StartTimer() + for i := 0; i < b.N; i++ { + res, err := Get(url) + if err != nil { + b.Fatalf("Get: %v", err) + } + body, err := ioutil.ReadAll(res.Body) + res.Body.Close() + if err != nil { + b.Fatalf("ReadAll: %v", err) + } + if bytes.Compare(body, data) != 0 { + b.Fatalf("Got body: %q", body) + } + } + b.StopTimer() + + // Instruct server process to stop. + Get(url + "?stop=yes") + select { + case err := <-done: + if err != nil { + b.Fatalf("subprocess failed: %v", err) + } + case <-time.After(5 * time.Second): + b.Fatalf("subprocess did not stop") + } +} + func BenchmarkServerFakeConnNoKeepAlive(b *testing.B) { b.ReportAllocs() req := reqBytes(`GET / HTTP/1.0