diff options
| author | Austin Clements <austin@google.com> | 2017-10-24 11:56:00 -0400 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2017-10-30 18:12:41 +0000 |
| commit | 1e8ab99b37dd67aaf7b188be743bdb938005df7a (patch) | |
| tree | 3c4415b1be5d406725dccc27c57423fbec378403 /src | |
| parent | 15d6ab69fbd8c84cde109def59c7e002296c19e8 (diff) | |
| download | go-1e8ab99b37dd67aaf7b188be743bdb938005df7a.tar.xz | |
runtime: add benchmark for write barriers
For #22460.
Change-Id: I798f26d45bbe1efd16b632e201413cb26cb3e6c7
Reviewed-on: https://go-review.googlesource.com/73811
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rick Hudson <rlh@golang.org>
Diffstat (limited to 'src')
| -rw-r--r-- | src/runtime/gc_test.go | 81 |
1 files changed, 81 insertions, 0 deletions
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) +} |
