Skip to content

Instantly share code, notes, and snippets.

@riannucci
Created March 1, 2016 02:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save riannucci/4bbf625872d33648ed49 to your computer and use it in GitHub Desktop.
Save riannucci/4bbf625872d33648ed49 to your computer and use it in GitHub Desktop.
A simple benchmark for the default context implementation vs. a bogus caching one.
package bench
import (
"sync"
"testing"
"time"
"golang.org/x/net/context"
)
type key int
func setupLL(depth int) context.Context {
c := context.Background()
for i := key(0); int(i) < depth; i++ {
c = context.WithValue(c, i, i)
}
return c
}
func innerLL(b *testing.B, depth int) {
c := setupLL(depth)
for i := 0; i < b.N; i++ {
if c.Value(key(0)) != key(0) {
b.FailNow()
}
}
}
type cachingContext struct {
inner context.Context
mu sync.RWMutex
cache map[interface{}]interface{}
}
func (c *cachingContext) Value(key interface{}) interface{} {
c.mu.RLock()
if ret, ok := c.cache[key]; ok {
c.mu.RUnlock()
return ret
}
c.mu.RUnlock()
ret := c.inner.Value(key)
c.mu.Lock()
if c.cache == nil {
c.cache = map[interface{}]interface{}{}
}
c.cache[key] = ret
c.mu.Unlock()
return ret
}
func (c *cachingContext) Deadline() (time.Time, bool) {
return c.inner.Deadline()
}
func (c *cachingContext) Err() error {
return c.inner.Err()
}
func (c *cachingContext) Done() <-chan struct{} {
return c.inner.Done()
}
var _ context.Context = (*cachingContext)(nil)
func setupCache(depth int) context.Context {
c := context.Background()
for i := key(0); int(i) < depth; i++ {
c = context.WithValue(c, i, i)
}
c = &cachingContext{inner: c}
return c
}
func innerCache(b *testing.B, depth int) {
c := setupCache(depth)
for i := 0; i < b.N; i++ {
if c.Value(key(0)) != key(0) {
b.FailNow()
}
}
}
func BenchmarkContextLL10(b *testing.B) {
innerLL(b, 10)
}
func BenchmarkContextLL100(b *testing.B) {
innerLL(b, 100)
}
func BenchmarkContextLL1000(b *testing.B) {
innerLL(b, 1000)
}
func BenchmarkContextC10(b *testing.B) {
innerCache(b, 10)
}
func BenchmarkContextC100(b *testing.B) {
innerCache(b, 100)
}
func BenchmarkContextC1000(b *testing.B) {
innerCache(b, 1000)
}
func BenchmarkOverLL1000(b *testing.B) {
for i := 0; i < b.N; i++ {
if setupLL(1000).Value(key(0)) != key(0) {
b.FailNow()
}
}
}
func BenchmarkOverC1000(b *testing.B) {
for i := 0; i < b.N; i++ {
if setupCache(1000).Value(key(0)) != key(0) {
b.FailNow()
}
}
}
// PASS
// BenchmarkContextLL10 10000000 188 ns/op
// BenchmarkContextLL100 1000000 1062 ns/op
// BenchmarkContextLL1000 200000 9772 ns/op
// BenchmarkContextC10 20000000 122 ns/op
// BenchmarkContextC100 10000000 122 ns/op
// BenchmarkContextC1000 20000000 117 ns/op
// BenchmarkOverLL1000 5000 309584 ns/op
// BenchmarkOverC1000 5000 314663 ns/op
// ok github.com/luci/luci-go/bench 14.805s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment