aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2017-10-24 11:56:00 -0400
committerAustin Clements <austin@google.com>2017-10-30 18:12:41 +0000
commit1e8ab99b37dd67aaf7b188be743bdb938005df7a (patch)
tree3c4415b1be5d406725dccc27c57423fbec378403 /src/runtime
parent15d6ab69fbd8c84cde109def59c7e002296c19e8 (diff)
downloadgo-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/runtime')
-rw-r--r--src/runtime/gc_test.go81
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)
+}