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
 			}