blob: 4a12cc017f7642baa04e5896b9a8dd9ec9a95997 [file] [log] [blame]
// A simple command-line tool to run IPC benchmarks.
package main
import (
"flag"
"fmt"
"os"
"runtime"
"strconv"
"strings"
"testing"
"v.io/core/veyron/lib/testutil"
"v.io/core/veyron/profiles"
"v.io/core/veyron/runtimes/google/ipc/benchmarks"
"v.io/core/veyron2"
"v.io/core/veyron2/rt"
)
var (
vrt veyron2.Runtime
address string
cpuList []int
histogram = flag.Bool("histogram", false, "If ture, output histogram of the benchmark results.")
)
func runBenchmarkEcho() {
payloadSizes := []int{1, 10, 100, 1000, 10000, 100000}
for _, size := range payloadSizes {
name := fmt.Sprintf("%sB", formatNum(size))
runBenchmark(name, func(b *testing.B, stats *testutil.BenchStats) {
benchmarks.CallEcho(b, vrt.NewContext(), address, b.N, size, stats)
})
}
}
func runBenchmarkEchoStream() {
chunkCnts := []int{1, 10, 100, 1000}
payloadSizes := []int{1, 10, 100, 1000, 10000, 100000}
for _, cnt := range chunkCnts {
for _, size := range payloadSizes {
name := formatNum(cnt)
if cnt == 1 {
name += "_chunk_"
} else {
name += "_chunks"
}
name += fmt.Sprintf("%sB", formatNum(size))
runBenchmark(name, func(b *testing.B, stats *testutil.BenchStats) {
benchmarks.CallEchoStream(b, vrt.NewContext(), address, b.N, cnt, size, stats)
})
}
}
}
func runBenchmarkEchoStreamPerChunk() {
payloadSizes := []int{1, 10, 100, 1000, 10000, 100000}
for _, size := range payloadSizes {
name := fmt.Sprintf("__per_chunk%sB", formatNum(size))
runBenchmark(name, func(b *testing.B, stats *testutil.BenchStats) {
benchmarks.CallEchoStream(b, vrt.NewContext(), address, 1, b.N, size, stats)
})
}
}
func runBenchmarkMux() {
payloadSizes := []int{10, 100}
chunkCntsB := []int{100, 1000}
payloadSizesB := []int{10, 100, 1000}
for _, size := range payloadSizes {
for _, cntB := range chunkCntsB {
for _, sizeB := range payloadSizesB {
name := fmt.Sprintf("%sB_mux%s", formatNum(size), formatNum(cntB))
if cntB == 1 {
name += "_chunk_"
} else {
name += "_chunks"
}
name += fmt.Sprintf("%sB", formatNum(sizeB))
runBenchmark(name, func(b *testing.B, stats *testutil.BenchStats) {
dummyB := testing.B{}
_, stop := benchmarks.StartEchoStream(&dummyB, vrt.NewContext(), address, 0, cntB, sizeB, nil)
b.ResetTimer()
benchmarks.CallEcho(b, vrt.NewContext(), address, b.N, size, stats)
b.StopTimer()
stop()
})
}
}
}
}
// runBenchmark runs a single bencmark function 'f'.
func runBenchmark(name string, f func(*testing.B, *testutil.BenchStats)) {
for _, cpu := range cpuList {
runtime.GOMAXPROCS(cpu)
benchName := "Benchmark" + name
if cpu != 1 {
benchName += fmt.Sprintf("-%d", cpu)
}
var stats *testutil.BenchStats
if *histogram {
stats = testutil.NewBenchStats(16)
}
r := testing.Benchmark(func(b *testing.B) {
f(b, stats)
})
fmt.Printf("%s\t%s\n", benchName, r)
if stats != nil {
stats.Print(os.Stdout)
}
}
}
// formatNum formats the given number n with an optional metric prefix
// and padding with underscores if necessary.
func formatNum(n int) string {
value := float32(n)
var prefix string
for _, p := range []string{"", "K", "M", "G", "T"} {
if value < 1000 {
prefix = p
break
}
value /= 1000
}
return strings.Replace(fmt.Sprintf("%*.0f%s", 5-len(prefix), value, prefix), " ", "_", -1)
}
// parseCpuList looks up the existing '-test.cpu' flag value and parses it into
// the list of cpus.
func parseCpuList() {
for _, v := range strings.Split(flag.Lookup("test.cpu").Value.String(), ",") {
v = strings.TrimSpace(v)
if v == "" {
continue
}
cpu, err := strconv.Atoi(v)
if err != nil || cpu <= 0 {
fmt.Fprintf(os.Stderr, "invalid -test.cpu %q\n", v)
os.Exit(1)
}
cpuList = append(cpuList, cpu)
}
if cpuList == nil {
cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
}
}
func main() {
flag.Parse()
parseCpuList()
var err error
vrt, err = rt.New()
if err != nil {
panic(err)
}
defer vrt.Cleanup()
var stop func()
address, stop = benchmarks.StartServer(vrt, profiles.LocalListenSpec)
benchmarks.CallEcho(&testing.B{}, vrt.NewContext(), address, 1, 0, nil) // Create VC.
runBenchmarkEcho()
runBenchmarkEchoStream()
runBenchmarkEchoStreamPerChunk()
runBenchmarkMux()
stop()
}