aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssa/nilcheck_test.go
diff options
context:
space:
mode:
authorJosh Bleecher Snyder <josharian@gmail.com>2015-06-25 14:04:55 -0700
committerJosh Bleecher Snyder <josharian@gmail.com>2015-06-29 04:07:11 +0000
commit1746e711ad7429248af4d17a57413aeaab0c2095 (patch)
tree1c70d83dbaf87fd4ee857dc6d96bc267fb1fd25a /src/cmd/compile/internal/ssa/nilcheck_test.go
parentd9a704cd40e8d248b473a831f099d8d4ca4c409b (diff)
downloadgo-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.go56
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) }