blob: 1f28fd7141086422a943188d989a2691b8190fd6 [file] [log] [blame]
// 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")
}
}