diff options
author | Josh Bleecher Snyder <josharian@gmail.com> | 2015-06-25 14:04:55 -0700 |
---|---|---|
committer | Josh Bleecher Snyder <josharian@gmail.com> | 2015-06-29 04:07:11 +0000 |
commit | 1746e711ad7429248af4d17a57413aeaab0c2095 (patch) | |
tree | 1c70d83dbaf87fd4ee857dc6d96bc267fb1fd25a /src/cmd/compile/internal/ssa/nilcheck_test.go | |
parent | d9a704cd40e8d248b473a831f099d8d4ca4c409b (diff) | |
download | go-1746e711ad7429248af4d17a57413aeaab0c2095.tar.gz go-1746e711ad7429248af4d17a57413aeaab0c2095.zip |
[dev.ssa] cmd/compile/ssa: add nilcheckelim benchmarks
These benchmarks demonstrate that
the nilcheckelim pass is roughly O(n^2):
BenchmarkNilCheckDeep1 2000000 741 ns/op 1.35 MB/s
BenchmarkNilCheckDeep10 1000000 2237 ns/op 4.47 MB/s
BenchmarkNilCheckDeep100 20000 60713 ns/op 1.65 MB/s
BenchmarkNilCheckDeep1000 200 7925198 ns/op 0.13 MB/s
BenchmarkNilCheckDeep10000 1 1220104252 ns/op 0.01 MB/s
Profiling suggests that building the
dominator tree is also O(n^2),
and before size factors take over,
considerably more expensive than nilcheckelim.
Change-Id: If966b38ec52243a25f355dab871300d29db02e16
Reviewed-on: https://go-review.googlesource.com/11520
Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/ssa/nilcheck_test.go')
-rw-r--r-- | src/cmd/compile/internal/ssa/nilcheck_test.go | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go new file mode 100644 index 0000000000..2d60957d49 --- /dev/null +++ b/src/cmd/compile/internal/ssa/nilcheck_test.go @@ -0,0 +1,56 @@ +package ssa + +import ( + "strconv" + "testing" +) + +func BenchmarkNilCheckDeep1(b *testing.B) { benchmarkNilCheckDeep(b, 1) } +func BenchmarkNilCheckDeep10(b *testing.B) { benchmarkNilCheckDeep(b, 10) } +func BenchmarkNilCheckDeep100(b *testing.B) { benchmarkNilCheckDeep(b, 100) } +func BenchmarkNilCheckDeep1000(b *testing.B) { benchmarkNilCheckDeep(b, 1000) } +func BenchmarkNilCheckDeep10000(b *testing.B) { benchmarkNilCheckDeep(b, 10000) } + +// benchmarkNilCheckDeep is a stress test of nilcheckelim. +// It uses the worst possible input: A linear string of +// nil checks, none of which can be eliminated. +// Run with multiple depths to observe big-O behavior. +func benchmarkNilCheckDeep(b *testing.B, depth int) { + ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing + + var blocs []bloc + blocs = append(blocs, + Bloc("entry", + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Goto(blockn(0)), + ), + ) + for i := 0; i < depth; i++ { + blocs = append(blocs, + Bloc(blockn(i), + Valu(ptrn(i), OpGlobal, ptrType, 0, nil), + Valu(booln(i), OpIsNonNil, TypeBool, 0, nil, ptrn(i)), + If(booln(i), blockn(i+1), "exit"), + ), + ) + } + blocs = append(blocs, + Bloc(blockn(depth), Goto("exit")), + Bloc("exit", Exit("mem")), + ) + + c := NewConfig("amd64", DummyFrontend{b}) + fun := Fun(c, "entry", blocs...) + + CheckFunc(fun.f) + b.SetBytes(int64(depth)) // helps for eyeballing linearity + b.ResetTimer() + + for i := 0; i < b.N; i++ { + nilcheckelim(fun.f) + } +} + +func blockn(n int) string { return "b" + strconv.Itoa(n) } +func ptrn(n int) string { return "p" + strconv.Itoa(n) } +func booln(n int) string { return "c" + strconv.Itoa(n) } |