]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: benchmark for bulk write barriers
authorAustin Clements <austin@google.com>
Fri, 27 Oct 2017 19:29:05 +0000 (15:29 -0400)
committerAustin Clements <austin@google.com>
Mon, 30 Oct 2017 18:12:49 +0000 (18:12 +0000)
This adds a benchmark of typedslicecopy and its bulk write barriers.

For #22460.

Change-Id: I439ca3b130bb22944468095f8f18b464e5bb43ca
Reviewed-on: https://go-review.googlesource.com/74051
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 a5c4c3bb04b64d1d0e727e342b6636e45798db67..1b1db25b175c35a66d52d1539efb2c2991a1dffa 100644 (file)
@@ -517,6 +517,32 @@ func TestUserForcedGC(t *testing.T) {
        }
 }
 
+func writeBarrierBenchmark(b *testing.B, f func()) {
+       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, which in
+       // turn keeps the write barrier on continuously.
+       var stop uint32
+       done := make(chan bool)
+       go func() {
+               for atomic.LoadUint32(&stop) == 0 {
+                       runtime.GC()
+               }
+               close(done)
+       }()
+       defer func() {
+               atomic.StoreUint32(&stop, 1)
+               <-done
+       }()
+
+       b.ResetTimer()
+       f()
+       b.StopTimer()
+}
+
 func BenchmarkWriteBarrier(b *testing.B) {
        if runtime.GOMAXPROCS(-1) < 2 {
                // We don't want GC to take our time.
@@ -546,53 +572,70 @@ func BenchmarkWriteBarrier(b *testing.B) {
        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)
+       writeBarrierBenchmark(b, func() {
+               var stack [depth]*node
+               tos := -1
 
-       // Keep GC running continuously during the benchmark.
-       var stop uint32
-       done := make(chan bool)
-       go func() {
-               for atomic.LoadUint32(&stop) == 0 {
-                       runtime.GC()
+               // 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()
+                       }
                }
-               close(done)
-       }()
+       })
 
-       b.ResetTimer()
+       runtime.KeepAlive(wbRoots)
+}
 
-       var stack [depth]*node
-       tos := -1
+func BenchmarkBulkWriteBarrier(b *testing.B) {
+       if runtime.GOMAXPROCS(-1) < 2 {
+               // We don't want GC to take our time.
+               b.Skip("need GOMAXPROCS >= 2")
+       }
 
-       // 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
-               }
+       // Construct a large set of objects we can copy around.
+       const heapSize = 64 << 20
+       type obj [16]*byte
+       ptrs := make([]*obj, heapSize/unsafe.Sizeof(obj{}))
+       for i := range ptrs {
+               ptrs[i] = new(obj)
+       }
 
-               // 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++
-               }
+       writeBarrierBenchmark(b, func() {
+               const blockSize = 1024
+               var pos int
+               for i := 0; i < b.N; i += blockSize {
+                       // Rotate block.
+                       block := ptrs[pos : pos+blockSize]
+                       first := block[0]
+                       copy(block, block[1:])
+                       block[blockSize-1] = first
+
+                       pos += blockSize
+                       if pos+blockSize > len(ptrs) {
+                               pos = 0
+                       }
 
-               if i%(1<<12) == 0 {
-                       // Avoid non-preemptible loops (see issue #10958).
                        runtime.Gosched()
                }
-       }
+       })
 
-       b.StopTimer()
-       atomic.StoreUint32(&stop, 1)
-       <-done
-
-       runtime.KeepAlive(wbRoots)
+       runtime.KeepAlive(ptrs)
 }