| // Copyright 2014 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // HTTP is a benchmark that examines client/server http performance. |
| package main |
| |
| import ( |
| "fmt" |
| "io" |
| "log" |
| "net" |
| "net/http" |
| "os" |
| "runtime" |
| "time" |
| |
| "golang.org/x/benchmarks/driver" |
| ) |
| |
| func main() { |
| driver.Main("HTTP", benchmark) |
| } |
| |
| func benchmark() driver.Result { |
| return driver.Benchmark(benchmarkHTTPImpl) |
| } |
| |
| const procs = 4 |
| |
| func benchmarkHTTPImpl(N uint64) { |
| driver.Parallel(N, procs, func() { |
| t0 := time.Now() |
| makeOneRequest() |
| driver.LatencyNote(t0) |
| }) |
| } |
| |
| func makeOneRequest() bool { |
| res, err := client.Get(server.Addr) |
| if err != nil { |
| // Under heavy load with GOMAXPROCS>>1, it frequently fails |
| // with transient failures like: |
| // "dial tcp: cannot assign requested address" |
| // or: |
| // "ConnectEx tcp: Only one usage of each socket address |
| // (protocol/network address/port) is normally permitted". |
| // So we just log and continue, |
| // otherwise significant fraction of benchmarks will fail. |
| log.Printf("Get: %v", err) |
| return false |
| } |
| defer res.Body.Close() |
| b, err := io.ReadAll(res.Body) |
| if err != nil { |
| log.Fatalf("ReadAll: %v", err) |
| } |
| if s := string(b); s != "Hello world.\n" { |
| log.Fatalf("Got body: %q", s) |
| } |
| return true |
| } |
| |
| var ( |
| server *http.Server |
| client *http.Client |
| ) |
| |
| func init() { |
| // These environment variables affect net/http behavior, |
| // ensure that we get predictable results regardless of environment on the machine. |
| os.Setenv("HTTP_PROXY", "") |
| os.Setenv("http_proxy", "") |
| os.Setenv("NO_PROXY", "") |
| os.Setenv("no_proxy", "") |
| |
| l, err := net.Listen("tcp", "127.0.0.1:0") |
| if err != nil { |
| if l, err = net.Listen("tcp6", "[::1]:0"); err != nil { |
| log.Fatalf("failed to listen: %v", err) |
| } |
| } |
| server = &http.Server{ |
| Addr: "http://" + l.Addr().String(), |
| ReadTimeout: 10 * time.Second, |
| WriteTimeout: 10 * time.Second, |
| MaxHeaderBytes: 1 << 20, |
| Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| fmt.Fprintf(w, "Hello world.\n") |
| }), |
| } |
| go server.Serve(l) |
| |
| client = &http.Client{ |
| Transport: &http.Transport{ |
| // just what default client uses |
| Proxy: http.ProxyFromEnvironment, |
| // this leads to more stable numbers |
| MaxIdleConnsPerHost: procs * runtime.GOMAXPROCS(0), |
| }, |
| } |
| |
| if !makeOneRequest() { |
| log.Fatalf("server is not listening") |
| } |
| } |