veyron/runtimes/google/ipc: Add Glob benchmarks
This change adds benchmarks for Glob__ and GlobChildren__ and attempts
to provide guidance for the size of the queue of the channels returned
by these methods.
The conclusion so far is that the queue size has very little impact
compared to the overhead of the IPC stack.
Change-Id: Iedd9aa73659f0213cf162a4f646bcdb8b5bf6728
diff --git a/runtimes/google/ipc/benchmarks/glob/README.txt b/runtimes/google/ipc/benchmarks/glob/README.txt
new file mode 100644
index 0000000..0103cd2
--- /dev/null
+++ b/runtimes/google/ipc/benchmarks/glob/README.txt
@@ -0,0 +1,120 @@
+Glob Benchmarks
+
+The benchmarks in this directory attempt to provide some guidance for the amount
+of buffering to use with the channels returned by Glob__ and GlobChildren__.
+
+The first set of benchmarks (BenchmarkChanN) shows the relationship between the
+buffer size and the latency of a very simple channel with one writer and one
+reader doing nothing else.
+
+The second set of benchmarks (BenchmarkGlobN) does the same thing but with a
+Glob__ server and a Glob client. The third set (BenchmarkGlobChildrenN) uses
+GlobChildren__.
+
+As of 2014-12-03, the conclusion is that the queue size has very little impact
+on performance.
+
+The BenchmarkChanN set shows that increasing the queue size improves latency for
+the very simple case, but not for Glob__ or GlobChildren__.
+
+An interesting observation is that all the benchmarks get slower as the number
+of cpus increases.
+
+Below are the test results for 1, 2, and 4 cpus on a HP Z420 workstation with
+2 × 6 cpu cores (Intel(R) Xeon(R) CPU E5-1650 v2 @ 3.50GHz).
+
+$ ./glob.test -test.bench=. -test.benchtime=5s -test.cpu=1
+BenchmarkChan0 20000000 464 ns/op
+BenchmarkChan1 20000000 585 ns/op
+BenchmarkChan2 20000000 484 ns/op
+BenchmarkChan4 20000000 425 ns/op
+BenchmarkChan8 50000000 396 ns/op
+BenchmarkChan16 50000000 381 ns/op
+BenchmarkChan32 50000000 371 ns/op
+BenchmarkChan64 50000000 365 ns/op
+BenchmarkChan128 50000000 363 ns/op
+BenchmarkChan256 50000000 362 ns/op
+BenchmarkGlob0 500000 35029 ns/op
+BenchmarkGlob1 500000 63536 ns/op
+BenchmarkGlob2 500000 34753 ns/op
+BenchmarkGlob4 500000 26379 ns/op
+BenchmarkGlob8 500000 19293 ns/op
+BenchmarkGlob16 1000000 18149 ns/op
+BenchmarkGlob32 500000 52364 ns/op
+BenchmarkGlob64 500000 83879 ns/op
+BenchmarkGlob128 100000 88448 ns/op
+BenchmarkGlob256 100000 57922 ns/op
+BenchmarkGlobChildren0 100000 118448 ns/op
+BenchmarkGlobChildren1 100000 123274 ns/op
+BenchmarkGlobChildren2 100000 116110 ns/op
+BenchmarkGlobChildren4 100000 134175 ns/op
+BenchmarkGlobChildren8 100000 118776 ns/op
+BenchmarkGlobChildren16 100000 123191 ns/op
+BenchmarkGlobChildren32 100000 132195 ns/op
+BenchmarkGlobChildren64 100000 126004 ns/op
+BenchmarkGlobChildren128 100000 135072 ns/op
+BenchmarkGlobChildren256 100000 127399 ns/op
+
+$ ./glob.test -test.bench=. -test.benchtime=5s -test.cpu=2
+BenchmarkChan0-2 5000000 1595 ns/op
+BenchmarkChan1-2 5000000 1649 ns/op
+BenchmarkChan2-2 10000000 1245 ns/op
+BenchmarkChan4-2 10000000 1299 ns/op
+BenchmarkChan8-2 10000000 982 ns/op
+BenchmarkChan16-2 10000000 929 ns/op
+BenchmarkChan32-2 10000000 916 ns/op
+BenchmarkChan64-2 10000000 903 ns/op
+BenchmarkChan128-2 10000000 907 ns/op
+BenchmarkChan256-2 10000000 914 ns/op
+BenchmarkGlob0-2 500000 61455 ns/op
+BenchmarkGlob1-2 500000 46890 ns/op
+BenchmarkGlob2-2 200000 56462 ns/op
+BenchmarkGlob4-2 500000 22783 ns/op
+BenchmarkGlob8-2 200000 64783 ns/op
+BenchmarkGlob16-2 1000000 68119 ns/op
+BenchmarkGlob32-2 200000 78611 ns/op
+BenchmarkGlob64-2 500000 82180 ns/op
+BenchmarkGlob128-2 1000000 81548 ns/op
+BenchmarkGlob256-2 100000 88278 ns/op
+BenchmarkGlobChildren0-2 100000 83188 ns/op
+BenchmarkGlobChildren1-2 100000 81751 ns/op
+BenchmarkGlobChildren2-2 100000 81896 ns/op
+BenchmarkGlobChildren4-2 100000 81857 ns/op
+BenchmarkGlobChildren8-2 100000 81531 ns/op
+BenchmarkGlobChildren16-2 100000 89915 ns/op
+BenchmarkGlobChildren32-2 100000 81112 ns/op
+BenchmarkGlobChildren64-2 100000 80997 ns/op
+BenchmarkGlobChildren128-2 100000 81350 ns/op
+BenchmarkGlobChildren256-2 100000 81344 ns/op
+
+$ ./glob.test -test.bench=. -test.benchtime=5s -test.cpu=4
+BenchmarkChan0-4 5000000 2012 ns/op
+BenchmarkChan1-4 5000000 3149 ns/op
+BenchmarkChan2-4 5000000 1839 ns/op
+BenchmarkChan4-4 10000000 957 ns/op
+BenchmarkChan8-4 20000000 660 ns/op
+BenchmarkChan16-4 20000000 523 ns/op
+BenchmarkChan32-4 20000000 507 ns/op
+BenchmarkChan64-4 20000000 509 ns/op
+BenchmarkChan128-4 20000000 507 ns/op
+BenchmarkChan256-4 20000000 511 ns/op
+BenchmarkGlob0-4 100000 103269 ns/op
+BenchmarkGlob1-4 100000 101222 ns/op
+BenchmarkGlob2-4 100000 102049 ns/op
+BenchmarkGlob4-4 100000 102763 ns/op
+BenchmarkGlob8-4 100000 101939 ns/op
+BenchmarkGlob16-4 100000 102989 ns/op
+BenchmarkGlob32-4 100000 103898 ns/op
+BenchmarkGlob64-4 100000 102838 ns/op
+BenchmarkGlob128-4 100000 101532 ns/op
+BenchmarkGlob256-4 100000 101059 ns/op
+BenchmarkGlobChildren0-4 100000 106617 ns/op
+BenchmarkGlobChildren1-4 100000 102576 ns/op
+BenchmarkGlobChildren2-4 100000 106313 ns/op
+BenchmarkGlobChildren4-4 100000 102774 ns/op
+BenchmarkGlobChildren8-4 100000 102886 ns/op
+BenchmarkGlobChildren16-4 100000 106771 ns/op
+BenchmarkGlobChildren32-4 100000 103309 ns/op
+BenchmarkGlobChildren64-4 100000 105112 ns/op
+BenchmarkGlobChildren128-4 100000 102295 ns/op
+BenchmarkGlobChildren256-4 100000 102951 ns/op
diff --git a/runtimes/google/ipc/benchmarks/glob/glob_test.go b/runtimes/google/ipc/benchmarks/glob/glob_test.go
new file mode 100644
index 0000000..9168796
--- /dev/null
+++ b/runtimes/google/ipc/benchmarks/glob/glob_test.go
@@ -0,0 +1,252 @@
+package glob_test
+
+import (
+ "fmt"
+ "testing"
+
+ "veyron.io/veyron/veyron2"
+ "veyron.io/veyron/veyron2/ipc"
+ "veyron.io/veyron/veyron2/naming"
+ "veyron.io/veyron/veyron2/rt"
+ "veyron.io/veyron/veyron2/security"
+
+ "veyron.io/veyron/veyron/profiles"
+)
+
+func RunBenchmarkChan(b *testing.B, bufferSize int) {
+ ch := make(chan string, bufferSize)
+ go func() {
+ for i := 0; i < b.N; i++ {
+ ch <- fmt.Sprintf("%09d", i)
+ }
+ close(ch)
+ }()
+ for _ = range ch {
+ continue
+ }
+}
+
+func BenchmarkChan0(b *testing.B) {
+ RunBenchmarkChan(b, 0)
+}
+
+func BenchmarkChan1(b *testing.B) {
+ RunBenchmarkChan(b, 1)
+}
+
+func BenchmarkChan2(b *testing.B) {
+ RunBenchmarkChan(b, 2)
+}
+
+func BenchmarkChan4(b *testing.B) {
+ RunBenchmarkChan(b, 4)
+}
+
+func BenchmarkChan8(b *testing.B) {
+ RunBenchmarkChan(b, 8)
+}
+
+func BenchmarkChan16(b *testing.B) {
+ RunBenchmarkChan(b, 16)
+}
+
+func BenchmarkChan32(b *testing.B) {
+ RunBenchmarkChan(b, 32)
+}
+
+func BenchmarkChan64(b *testing.B) {
+ RunBenchmarkChan(b, 64)
+}
+
+func BenchmarkChan128(b *testing.B) {
+ RunBenchmarkChan(b, 128)
+}
+
+func BenchmarkChan256(b *testing.B) {
+ RunBenchmarkChan(b, 256)
+}
+
+type disp struct {
+ obj interface{}
+}
+
+func (d *disp) Lookup(suffix string) (interface{}, security.Authorizer, error) {
+ return d.obj, nil, nil
+}
+
+func startServer(b *testing.B, rt veyron2.Runtime, obj interface{}) (string, func(), error) {
+ server, err := rt.NewServer()
+ if err != nil {
+ return "", nil, fmt.Errorf("failed to start server: %v", err)
+ }
+ endpoints, err := server.Listen(profiles.LocalListenSpec)
+ if err != nil {
+ return "", nil, fmt.Errorf("failed to listen: %v", err)
+ }
+ if err := server.ServeDispatcher("", &disp{obj}); err != nil {
+ return "", nil, err
+ }
+ addr := naming.JoinAddressName(endpoints[0].String(), "")
+ return addr, func() { server.Stop() }, nil
+}
+
+type globObject struct {
+ b *testing.B
+ bufferSize int
+}
+
+func (o *globObject) Glob__(ctx ipc.ServerContext, pattern string) (<-chan naming.VDLMountEntry, error) {
+ if pattern != "*" {
+ panic("this benchmark only works with pattern='*'")
+ }
+ ch := make(chan naming.VDLMountEntry, o.bufferSize)
+ go func() {
+ for i := 0; i < o.b.N; i++ {
+ name := fmt.Sprintf("%09d", i)
+ ch <- naming.VDLMountEntry{Name: name}
+ }
+ close(ch)
+ }()
+ return ch, nil
+}
+
+type globChildrenObject struct {
+ b *testing.B
+ bufferSize int
+}
+
+func (o *globChildrenObject) GlobChildren__(ctx ipc.ServerContext) (<-chan string, error) {
+ if ctx.Suffix() != "" {
+ return nil, nil
+ }
+ ch := make(chan string, o.bufferSize)
+ go func() {
+ for i := 0; i < o.b.N; i++ {
+ ch <- fmt.Sprintf("%09d", i)
+ }
+ close(ch)
+ }()
+ return ch, nil
+}
+
+func globClient(b *testing.B, rt veyron2.Runtime, name string) (int, error) {
+ call, err := rt.Client().StartCall(rt.NewContext(), name, ipc.GlobMethod, []interface{}{"*"})
+ if err != nil {
+ return 0, err
+ }
+ var me naming.VDLMountEntry
+ b.ResetTimer()
+ count := 0
+ for {
+ if err := call.Recv(&me); err != nil {
+ break
+ }
+ count++
+ }
+ b.StopTimer()
+ if ferr := call.Finish(&err); ferr != nil {
+ err = ferr
+ }
+ return count, err
+}
+
+func RunBenchmarkGlob(b *testing.B, obj interface{}) {
+ runtime, err := rt.New()
+ if err != nil {
+ panic(err)
+ }
+ defer runtime.Cleanup()
+ addr, stop, err := startServer(b, runtime, obj)
+ if err != nil {
+ b.Fatalf("startServer failed: %v", err)
+ }
+ defer stop()
+
+ count, err := globClient(b, runtime, addr)
+ if err != nil {
+ b.Fatalf("globClient failed: %v", err)
+ }
+ if count != b.N {
+ b.Fatalf("unexpected number of results: got %d, expected %d", count, b.N)
+ }
+}
+
+func BenchmarkGlob0(b *testing.B) {
+ RunBenchmarkGlob(b, &globObject{b, 0})
+}
+
+func BenchmarkGlob1(b *testing.B) {
+ RunBenchmarkGlob(b, &globObject{b, 1})
+}
+
+func BenchmarkGlob2(b *testing.B) {
+ RunBenchmarkGlob(b, &globObject{b, 2})
+}
+
+func BenchmarkGlob4(b *testing.B) {
+ RunBenchmarkGlob(b, &globObject{b, 4})
+}
+
+func BenchmarkGlob8(b *testing.B) {
+ RunBenchmarkGlob(b, &globObject{b, 8})
+}
+
+func BenchmarkGlob16(b *testing.B) {
+ RunBenchmarkGlob(b, &globObject{b, 16})
+}
+
+func BenchmarkGlob32(b *testing.B) {
+ RunBenchmarkGlob(b, &globObject{b, 32})
+}
+
+func BenchmarkGlob64(b *testing.B) {
+ RunBenchmarkGlob(b, &globObject{b, 64})
+}
+
+func BenchmarkGlob128(b *testing.B) {
+ RunBenchmarkGlob(b, &globObject{b, 128})
+}
+
+func BenchmarkGlob256(b *testing.B) {
+ RunBenchmarkGlob(b, &globObject{b, 256})
+}
+
+func BenchmarkGlobChildren0(b *testing.B) {
+ RunBenchmarkGlob(b, &globChildrenObject{b, 0})
+}
+
+func BenchmarkGlobChildren1(b *testing.B) {
+ RunBenchmarkGlob(b, &globChildrenObject{b, 1})
+}
+
+func BenchmarkGlobChildren2(b *testing.B) {
+ RunBenchmarkGlob(b, &globChildrenObject{b, 2})
+}
+
+func BenchmarkGlobChildren4(b *testing.B) {
+ RunBenchmarkGlob(b, &globChildrenObject{b, 4})
+}
+
+func BenchmarkGlobChildren8(b *testing.B) {
+ RunBenchmarkGlob(b, &globChildrenObject{b, 8})
+}
+
+func BenchmarkGlobChildren16(b *testing.B) {
+ RunBenchmarkGlob(b, &globChildrenObject{b, 16})
+}
+
+func BenchmarkGlobChildren32(b *testing.B) {
+ RunBenchmarkGlob(b, &globChildrenObject{b, 32})
+}
+
+func BenchmarkGlobChildren64(b *testing.B) {
+ RunBenchmarkGlob(b, &globChildrenObject{b, 64})
+}
+
+func BenchmarkGlobChildren128(b *testing.B) {
+ RunBenchmarkGlob(b, &globChildrenObject{b, 128})
+}
+
+func BenchmarkGlobChildren256(b *testing.B) {
+ RunBenchmarkGlob(b, &globChildrenObject{b, 256})
+}
diff --git a/services/mgmt/binary/impl/service.go b/services/mgmt/binary/impl/service.go
index e7cfc9d..149a69d 100644
--- a/services/mgmt/binary/impl/service.go
+++ b/services/mgmt/binary/impl/service.go
@@ -334,7 +334,7 @@
if n == nil {
return nil, verror.Make(errOperationFailed, context)
}
- ch := make(chan string, 100)
+ ch := make(chan string)
go func() {
for k, _ := range n.children {
ch <- k
diff --git a/services/mgmt/device/impl/app_service.go b/services/mgmt/device/impl/app_service.go
index dc61c02..b07ab26 100644
--- a/services/mgmt/device/impl/app_service.go
+++ b/services/mgmt/device/impl/app_service.go
@@ -1226,7 +1226,7 @@
if n == nil {
return nil, verror2.Make(ErrInvalidSuffix, nil)
}
- ch := make(chan string, 100)
+ ch := make(chan string)
go func() {
for child, _ := range n.children {
ch <- child
diff --git a/services/mgmt/logreader/impl/logfile.go b/services/mgmt/logreader/impl/logfile.go
index 280e5d3..a79df13 100644
--- a/services/mgmt/logreader/impl/logfile.go
+++ b/services/mgmt/logreader/impl/logfile.go
@@ -129,8 +129,7 @@
return nil, nil
}
- const batchSize = 100
- ch := make(chan string, batchSize)
+ ch := make(chan string)
go func() {
defer close(ch)
f, err := os.Open(dirName)
@@ -139,7 +138,7 @@
}
defer f.Close()
for {
- fi, err := f.Readdir(batchSize)
+ fi, err := f.Readdir(100)
if err != nil {
return
}