1
0
mirror of https://github.com/golang/go synced 2024-10-01 01:18:32 -06:00

expvar: Add benchmarks for perf sensitive operations

These benchmarks are only for functions commonly used in loops. The
other functions are typically used for inspection or setup and thus are
not performance sensitive.

Change-Id: I8d0a0ba2d8234ecacb40fa3aa9077bf93c8fe89c
Reviewed-on: https://go-review.googlesource.com/3680
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
This commit is contained in:
Evan Phoenix 2015-01-30 15:31:47 -08:00 committed by Dmitry Vyukov
parent cb4b28e013
commit fc22fb8f0c

View File

@ -7,8 +7,11 @@ package expvar
import (
"bytes"
"encoding/json"
"net"
"net/http/httptest"
"runtime"
"strconv"
"sync"
"testing"
)
@ -47,6 +50,26 @@ func TestInt(t *testing.T) {
}
}
func BenchmarkIntAdd(b *testing.B) {
var v Int
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
v.Add(1)
}
})
}
func BenchmarkIntSet(b *testing.B) {
var v Int
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
v.Set(1)
}
})
}
func TestFloat(t *testing.T) {
RemoveAll()
reqs := NewFloat("requests-float")
@ -73,6 +96,26 @@ func TestFloat(t *testing.T) {
}
}
func BenchmarkFloatAdd(b *testing.B) {
var f Float
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
f.Add(1.0)
}
})
}
func BenchmarkFloatSet(b *testing.B) {
var f Float
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
f.Set(1.0)
}
})
}
func TestString(t *testing.T) {
RemoveAll()
name := NewString("my-name")
@ -90,6 +133,16 @@ func TestString(t *testing.T) {
}
}
func BenchmarkStringSet(b *testing.B) {
var s String
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
s.Set("red")
}
})
}
func TestMapCounter(t *testing.T) {
RemoveAll()
colors := NewMap("bike-shed-colors")
@ -130,6 +183,38 @@ func TestMapCounter(t *testing.T) {
}
}
func BenchmarkMapSet(b *testing.B) {
m := new(Map).Init()
v := new(Int)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
m.Set("red", v)
}
})
}
func BenchmarkMapAddSame(b *testing.B) {
for i := 0; i < b.N; i++ {
m := new(Map).Init()
m.Add("red", 1)
m.Add("red", 1)
m.Add("red", 1)
m.Add("red", 1)
}
}
func BenchmarkMapAddDifferent(b *testing.B) {
for i := 0; i < b.N; i++ {
m := new(Map).Init()
m.Add("red", 1)
m.Add("blue", 1)
m.Add("green", 1)
m.Add("yellow", 1)
}
}
func TestFunc(t *testing.T) {
RemoveAll()
var x interface{} = []string{"a", "b"}
@ -165,3 +250,135 @@ func TestHandler(t *testing.T) {
t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
}
}
func BenchmarkRealworldExpvarUsage(b *testing.B) {
var (
bytesSent Int
bytesRead Int
)
// The benchmark creates GOMAXPROCS client/server pairs.
// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
// The benchmark stresses concurrent reading and writing to the same connection.
// Such pattern is used in net/http and net/rpc.
b.StopTimer()
P := runtime.GOMAXPROCS(0)
N := b.N / P
W := 1000
// Setup P client/server connections.
clients := make([]net.Conn, P)
servers := make([]net.Conn, P)
ln, err := net.Listen("tcp", laddr)
if err != nil {
b.Fatalf("Listen failed: %v", err)
}
defer ln.Close()
done := make(chan bool)
go func() {
for p := 0; p < P; p++ {
s, err := ln.Accept()
if err != nil {
b.Errorf("Accept failed: %v", err)
return
}
servers[p] = s
}
done <- true
}()
for p := 0; p < P; p++ {
c, err := net.Dial("tcp", ln.Addr().String())
if err != nil {
b.Fatalf("Dial failed: %v", err)
}
clients[p] = c
}
<-done
b.StartTimer()
var wg sync.WaitGroup
wg.Add(4 * P)
for p := 0; p < P; p++ {
// Client writer.
go func(c net.Conn) {
defer wg.Done()
var buf [1]byte
for i := 0; i < N; i++ {
v := byte(i)
for w := 0; w < W; w++ {
v *= v
}
buf[0] = v
n, err := c.Write(buf[:])
if err != nil {
b.Errorf("Write failed: %v", err)
return
}
bytesSent.Add(int64(n))
}
}(clients[p])
// Pipe between server reader and server writer.
pipe := make(chan byte, 128)
// Server reader.
go func(s net.Conn) {
defer wg.Done()
var buf [1]byte
for i := 0; i < N; i++ {
n, err := s.Read(buf[:])
if err != nil {
b.Errorf("Read failed: %v", err)
return
}
bytesRead.Add(int64(n))
pipe <- buf[0]
}
}(servers[p])
// Server writer.
go func(s net.Conn) {
defer wg.Done()
var buf [1]byte
for i := 0; i < N; i++ {
v := <-pipe
for w := 0; w < W; w++ {
v *= v
}
buf[0] = v
n, err := s.Write(buf[:])
if err != nil {
b.Errorf("Write failed: %v", err)
return
}
bytesSent.Add(int64(n))
}
s.Close()
}(servers[p])
// Client reader.
go func(c net.Conn) {
defer wg.Done()
var buf [1]byte
for i := 0; i < N; i++ {
n, err := c.Read(buf[:])
if err != nil {
b.Errorf("Read failed: %v", err)
return
}
bytesRead.Add(int64(n))
}
c.Close()
}(clients[p])
}
wg.Wait()
}