]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add benchmark for write barriers
authorAustin Clements <austin@google.com>
Tue, 24 Oct 2017 15:56:00 +0000 (11:56 -0400)
committerAustin Clements <austin@google.com>
Mon, 30 Oct 2017 18:12:41 +0000 (18:12 +0000)
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>
src/runtime/gc_test.go

index 0620f2d61e8f64ed919ad266052d08039b9e08f8..a5c4c3bb04b64d1d0e727e342b6636e45798db67 100644 (file)
@@ -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)
+}