Last active
January 12, 2016 00:05
-
-
Save bprosnitz/67219a1ad61f39fdd860 to your computer and use it in GitHub Desktop.
Go benchmarks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Put this file in $GOPATH/perfbench/perfbench_test.go | |
//go test -bench . -v perfbench/... | |
// | |
//go version go1.5.1 linux/amd64 | |
// | |
//noop: 0 | |
//var x interface{} = <int8>: 1 | |
//var x interface{} = <*int8>: 0 | |
//var x interface{} = <[]int16>: 1 | |
//var x interface{} = <typedInterface(ptr)>: 0 | |
//func(consts,in,vararg,list): 1 | |
//func(preallocVarArgs...): 0 | |
//local escape analysis (pass pointer to int as arg): 0 | |
//local escape analysis (return pointer to int as out arg): 0 | |
//return &int(5): 1 | |
//return &slice[0]: 0 | |
//return &(xint8)slice[0]: 1 | |
//return &array[0]: 0 | |
//return &astruct.field: 0 | |
//return &map[1]: 1 | |
//call with closure: 0 | |
// | |
//BenchmarkLoopOverTypes-12 2000000000 0.03 ns/op | |
//BenchmarkTypeSwitch-12 2000000000 0.07 ns/op | |
//BenchmarkReflectTypeSwitch-12 2000000000 0.29 ns/op | |
//BenchmarkStructPtrFunctionCall-12 2000000000 0.02 ns/op | |
//BenchmarkInterfaceFunctionCall-12 2000000000 0.09 ns/op | |
//BenchmarkSingleArgFunctionCall-12 1000000000 0.03 ns/op | |
//BenchmarkMultiArgFunctionCall-12 1000000000 0.03 ns/op | |
//BenchmarkStructArgFunctionCall-12 2000000000 0.05 ns/op | |
//BenchmarkMultiOutArgFunctionCall-12 2000000000 0.07 ns/op | |
//BenchmarkStructOutArgFunctionCall-12 2000000000 0.08 ns/op | |
//BenchmarkReturnNumberThroughInterfaceFunctionCall-12 1 6271513094 ns/op | |
//BenchmarkSingleUseIntInInterface-12 1 1242256449 ns/op | |
//BenchmarkReuseIntInInterface-12 1 5751215766 ns/op | |
// | |
package perfbench_test | |
import ( | |
"testing" | |
"os" | |
"fmt" | |
"reflect" | |
"text/tabwriter" | |
) | |
type typedInterface interface{} | |
type astruct struct { | |
A int | |
} | |
type xint8 int8 | |
func TestAllocations(t *testing.T) { | |
a := astruct{4} | |
var v int8 | |
ptr := &v | |
slc := []int16{9} | |
var z []int8 | |
prealloc := []int8{3,4,5} | |
mmap := map[int]string{1:"one"} | |
var arr [4]int8 | |
var setIndex func(int) | |
tests := []struct{ | |
name string | |
f func() interface{} | |
}{ | |
{ | |
"noop", | |
func () interface{} { return nil }, | |
}, | |
{ | |
"var x interface{} = <int8>", | |
func () interface{} { | |
return 1 | |
}, | |
}, | |
{ | |
"var x interface{} = <*int8>", | |
func () interface{} { | |
return ptr | |
}, | |
}, | |
{ | |
"var x interface{} = <[]int16>", | |
func () interface{} { | |
return slc | |
}, | |
}, | |
{ | |
"var x interface{} = <typedInterface(ptr)>", | |
func () interface{} { | |
return typedInterface(ptr) | |
}, | |
}, | |
{ | |
"func(consts,in,vararg,list)", | |
func () interface{} { | |
z = va(1,2,3,4) | |
return nil | |
}, | |
}, | |
{ | |
"func(preallocVarArgs...)", | |
func () interface{} { | |
z = va(prealloc...) | |
return nil | |
}, | |
}, | |
{ | |
"local escape analysis (pass pointer to int as arg)", | |
func () interface{} { | |
x := 9 | |
SetX(&x) | |
return nil | |
}, | |
}, | |
{ | |
"local escape analysis (return pointer to int as out arg)", | |
func () interface{} { | |
x := GetX() | |
v = int8(*x) | |
return nil | |
}, | |
}, | |
{ | |
"return &int(5)", | |
func () interface{} { | |
var x int = 5 | |
return &x | |
}, | |
}, | |
{ | |
"return &slice[0]", | |
func () interface{} { | |
return &prealloc[0] | |
}, | |
}, | |
{ | |
"return &(xint8)slice[0]", | |
func () interface{} { | |
x := (xint8)(prealloc[0]) // can't take the address without a new variable | |
return &x | |
}, | |
}, | |
{ | |
"return &array[0]", | |
func () interface{} { | |
return &arr[0] | |
}, | |
}, | |
{ | |
"return &astruct.field", | |
func () interface{} { | |
return &a.A | |
}, | |
}, | |
{ | |
// note: we can't get a pointer to the map key | |
"return &map[1]", | |
func () interface{} { | |
mapval := mmap[1] // illegal to do &mmap[1] | |
return &mapval | |
}, | |
}, | |
{ | |
"call with closure", | |
func () interface{} { | |
return closureHandler(func(x int) interface{} { | |
v = int8(x) | |
return &v | |
}) | |
}, | |
}, | |
{ | |
"assign function var to method", | |
func () interface{} { | |
return closureHandler(func(x int) interface{} { | |
setIndex = intSettable(prealloc).set | |
return nil | |
}) | |
}, | |
}, | |
} | |
w := &tabwriter.Writer{} | |
w.Init(os.Stdout, 0, 8, 0, '\t', 0) | |
for _, test := range tests { | |
allocs := testing.AllocsPerRun(10, func() { test.f() }) | |
fmt.Fprintf(w, "%s:\t%d\n", test.name, int(allocs)) | |
} | |
w.Flush() | |
} | |
type intSettable []int8 | |
func (is intSettable) set(x int) { | |
is[0] = int8(x) | |
} | |
//go:noinline | |
func SetX(x *int) { | |
*x = 1 | |
} | |
//go:noinline | |
func GetX() (x *int) { | |
y := 9 | |
return &y | |
} | |
//go:noinline | |
func va(v ...int8) []int8 { | |
return v | |
} | |
//go:noinline | |
func closureHandler(z func (int) interface{}) interface{} { | |
return z(4) | |
} | |
var vals []interface{} = []interface{}{1, "x", 0.4} | |
var z int | |
func BenchmarkLoopOverTypes(b *testing.B) { | |
for i := 0; i < 10000000; i++ { | |
for range vals { | |
z += 4 | |
} | |
} | |
} | |
func BenchmarkTypeSwitch(b *testing.B) { | |
for i := 0; i < 10000000; i++ { | |
for _, val := range vals { | |
switch val.(type){ | |
case int: | |
z += 4 | |
case string: | |
z += 6 | |
case float64: | |
z += 12 | |
} | |
} | |
} | |
} | |
var rtInt = reflect.TypeOf(int(1)) | |
var rtStr = reflect.TypeOf("") | |
var rtFloat64 = reflect.TypeOf(float64(0)) | |
func BenchmarkReflectTypeSwitch(b *testing.B) { | |
for i := 0; i < 10000000; i++ { | |
for _, val := range vals { | |
switch x := reflect.TypeOf(val); { | |
case x == rtInt: | |
z += 4 | |
case x == rtStr: | |
z += 6 | |
case x == rtFloat64: | |
z += 12 | |
} | |
} | |
} | |
} | |
type X struct{a int} | |
//go:noinline | |
func (x *X) A(v int) (int){return v+x.a} | |
var xInst *X = &X{1} | |
type XIface interface{A(int)int} | |
var xIfaceInst XIface = xInst | |
func BenchmarkStructPtrFunctionCall(b *testing.B) { | |
v := 0 | |
for i := 0; i < 100000000; i++ { | |
v = xInst.A(v) | |
} | |
z = v | |
} | |
func BenchmarkInterfaceFunctionCall(b *testing.B) { | |
v := 0 | |
for i := 0; i < 100000000; i++ { | |
v = xIfaceInst.A(i) | |
} | |
z = v | |
} | |
//go:noinline | |
func a1(x int) int { | |
return x + 1 | |
} | |
func BenchmarkSingleArgFunctionCall(b *testing.B) { | |
v := 0 | |
for i := 0; i < 100000000; i++ { | |
v = a1(v) | |
} | |
z = v | |
} | |
//go:noinline | |
func a2(a, b, c, d, e, f, g int) int { | |
return a + 1 | |
} | |
func BenchmarkMultiArgFunctionCall(b *testing.B) { | |
v := 0 | |
for i := 0; i < 100000000; i++ { | |
v = a2(v, 1, 2, 3, 4, 5, 6) | |
} | |
z = v | |
} | |
type argStruct struct{ | |
a, b, c, d, e, f, g int | |
} | |
//go:noinline | |
func a3(x argStruct) int { | |
return x.a + 1 | |
} | |
func BenchmarkStructArgFunctionCall(b *testing.B) { | |
v := 0 | |
for i := 0; i < 100000000; i++ { | |
v = a3(argStruct{v, 1, 2, 3, 4, 5, 6}) | |
} | |
z = v | |
} | |
//go:noinline | |
func a4(x int) (a, b, c, d, e, f, g int) { | |
return x + 1, x + 2, x + 3, x + 4, x + 5, x + 6, x + 7 | |
} | |
func BenchmarkMultiOutArgFunctionCall(b *testing.B) { | |
g := 0 | |
for i := 0; i < 100000000; i++ { | |
_, _, _, _, _, _, g = a4(g) | |
} | |
z = g | |
} | |
//go:noinline | |
func a5(x int) (a argStruct) { | |
return argStruct{x + 1, x + 2, x + 3, x + 4, x + 5, x + 6, x + 7} | |
} | |
func BenchmarkStructOutArgFunctionCall(b *testing.B) { | |
s := argStruct{} | |
for i := 0; i < 100000000; i++ { | |
s = a5(s.g) | |
} | |
z = s.g | |
} | |
//go:noinline | |
func a6(x int) (interface{}) { | |
return x + 1 | |
} | |
func BenchmarkReturnNumberThroughInterfaceFunctionCall(b *testing.B) { | |
s := 0 | |
for i := 0; i < 100000000; i++ { | |
s = a6(s).(int) | |
} | |
z = s | |
} | |
func BenchmarkReuseIntInInterface(b *testing.B) { | |
var x interface{} = 0 | |
for i := 0; i < 100000000; i++ { | |
x = x.(int) + 1 | |
} | |
z = x.(int) | |
} | |
func BenchmarkSingleUseIntInInterface(b *testing.B) { | |
var x interface{} = 0 | |
var q = 0 | |
for i := 0; i < 100000000; i++ { | |
q = q + x.(int) + 1 | |
} | |
x = q | |
z = x.(int) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment