Commit f96b95bc authored by Austin Clements's avatar Austin Clements

runtime: benchmark for bulk write barriers

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: default avatarRick Hudson <rlh@golang.org>
parent 7e343134
...@@ -517,6 +517,32 @@ func TestUserForcedGC(t *testing.T) { ...@@ -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) { func BenchmarkWriteBarrier(b *testing.B) {
if runtime.GOMAXPROCS(-1) < 2 { if runtime.GOMAXPROCS(-1) < 2 {
// We don't want GC to take our time. // We don't want GC to take our time.
...@@ -546,53 +572,70 @@ func BenchmarkWriteBarrier(b *testing.B) { ...@@ -546,53 +572,70 @@ func BenchmarkWriteBarrier(b *testing.B) {
const depth = 22 // 64 MB const depth = 22 // 64 MB
root := mkTree(22) root := mkTree(22)
runtime.GC() writeBarrierBenchmark(b, func() {
var ms runtime.MemStats var stack [depth]*node
runtime.ReadMemStats(&ms) tos := -1
//b.Logf("heap size: %d MB", ms.HeapAlloc>>20)
// Keep GC running continuously during the benchmark. // There are two write barriers per iteration, so i+=2.
var stop uint32 for i := 0; i < b.N; i += 2 {
done := make(chan bool) if tos == -1 {
go func() { stack[0] = root
for atomic.LoadUint32(&stop) == 0 { tos = 0
runtime.GC() }
// 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 func BenchmarkBulkWriteBarrier(b *testing.B) {
tos := -1 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. // Construct a large set of objects we can copy around.
for i := 0; i < b.N; i += 2 { const heapSize = 64 << 20
if tos == -1 { type obj [16]*byte
stack[0] = root ptrs := make([]*obj, heapSize/unsafe.Sizeof(obj{}))
tos = 0 for i := range ptrs {
} ptrs[i] = new(obj)
}
// Perform one step of reversing the tree. writeBarrierBenchmark(b, func() {
n := stack[tos] const blockSize = 1024
if n.l == nil { var pos int
tos-- for i := 0; i < b.N; i += blockSize {
} else { // Rotate block.
n.l, n.r = n.r, n.l block := ptrs[pos : pos+blockSize]
stack[tos] = n.l first := block[0]
stack[tos+1] = n.r copy(block, block[1:])
tos++ 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() runtime.Gosched()
} }
} })
b.StopTimer() runtime.KeepAlive(ptrs)
atomic.StoreUint32(&stop, 1)
<-done
runtime.KeepAlive(wbRoots)
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment