Merge "veyron/runtimes/google/ipc: Add Glob benchmarks"
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
 			}