From 1e8ab99b37dd67aaf7b188be743bdb938005df7a Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 24 Oct 2017 11:56:00 -0400 Subject: [PATCH] runtime: add benchmark for write barriers For #22460. Change-Id: I798f26d45bbe1efd16b632e201413cb26cb3e6c7 Reviewed-on: https://go-review.googlesource.com/73811 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Rick Hudson --- src/runtime/gc_test.go | 81 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go index 0620f2d61e..a5c4c3bb04 100644 --- a/src/runtime/gc_test.go +++ b/src/runtime/gc_test.go @@ -10,6 +10,7 @@ import ( "reflect" "runtime" "runtime/debug" + "sync/atomic" "testing" "time" "unsafe" @@ -515,3 +516,83 @@ func TestUserForcedGC(t *testing.T) { t.Fatalf("runtime.GC() was not accounted in NumForcedGC") } } + +func BenchmarkWriteBarrier(b *testing.B) { + if runtime.GOMAXPROCS(-1) < 2 { + // We don't want GC to take our time. + b.Skip("need GOMAXPROCS >= 2") + } + + // Construct a large tree both so the GC runs for a while and + // so we have a data structure to manipulate the pointers of. + type node struct { + l, r *node + } + var wbRoots []*node + var mkTree func(level int) *node + mkTree = func(level int) *node { + if level == 0 { + return nil + } + n := &node{mkTree(level - 1), mkTree(level - 1)} + if level == 10 { + // Seed GC with enough early pointers so it + // doesn't accidentally switch to mark 2 when + // it only has the top of the tree. + wbRoots = append(wbRoots, n) + } + return n + } + const depth = 22 // 64 MB + root := mkTree(22) + + runtime.GC() + var ms runtime.MemStats + runtime.ReadMemStats(&ms) + //b.Logf("heap size: %d MB", ms.HeapAlloc>>20) + + // Keep GC running continuously during the benchmark. + var stop uint32 + done := make(chan bool) + go func() { + for atomic.LoadUint32(&stop) == 0 { + runtime.GC() + } + close(done) + }() + + b.ResetTimer() + + var stack [depth]*node + tos := -1 + + // There are two write barriers per iteration, so i+=2. + for i := 0; i < b.N; i += 2 { + if tos == -1 { + stack[0] = root + tos = 0 + } + + // Perform one step of reversing the tree. + n := stack[tos] + if n.l == nil { + tos-- + } else { + n.l, n.r = n.r, n.l + stack[tos] = n.l + stack[tos+1] = n.r + tos++ + } + + if i%(1<<12) == 0 { + // Avoid non-preemptible loops (see issue #10958). + runtime.Gosched() + } + } + + b.StopTimer() + atomic.StoreUint32(&stop, 1) + <-done + + runtime.KeepAlive(wbRoots) +}