@@ -517,6 +517,32 @@ func TestUserForcedGC(t *testing.T) {
517
517
}
518
518
}
519
519
520
+ func writeBarrierBenchmark (b * testing.B , f func ()) {
521
+ runtime .GC ()
522
+ var ms runtime.MemStats
523
+ runtime .ReadMemStats (& ms )
524
+ //b.Logf("heap size: %d MB", ms.HeapAlloc>>20)
525
+
526
+ // Keep GC running continuously during the benchmark, which in
527
+ // turn keeps the write barrier on continuously.
528
+ var stop uint32
529
+ done := make (chan bool )
530
+ go func () {
531
+ for atomic .LoadUint32 (& stop ) == 0 {
532
+ runtime .GC ()
533
+ }
534
+ close (done )
535
+ }()
536
+ defer func () {
537
+ atomic .StoreUint32 (& stop , 1 )
538
+ <- done
539
+ }()
540
+
541
+ b .ResetTimer ()
542
+ f ()
543
+ b .StopTimer ()
544
+ }
545
+
520
546
func BenchmarkWriteBarrier (b * testing.B ) {
521
547
if runtime .GOMAXPROCS (- 1 ) < 2 {
522
548
// We don't want GC to take our time.
@@ -546,53 +572,70 @@ func BenchmarkWriteBarrier(b *testing.B) {
546
572
const depth = 22 // 64 MB
547
573
root := mkTree (22 )
548
574
549
- runtime .GC ()
550
- var ms runtime.MemStats
551
- runtime .ReadMemStats (& ms )
552
- //b.Logf("heap size: %d MB", ms.HeapAlloc>>20)
575
+ writeBarrierBenchmark (b , func () {
576
+ var stack [depth ]* node
577
+ tos := - 1
553
578
554
- // Keep GC running continuously during the benchmark.
555
- var stop uint32
556
- done := make (chan bool )
557
- go func () {
558
- for atomic .LoadUint32 (& stop ) == 0 {
559
- runtime .GC ()
579
+ // There are two write barriers per iteration, so i+=2.
580
+ for i := 0 ; i < b .N ; i += 2 {
581
+ if tos == - 1 {
582
+ stack [0 ] = root
583
+ tos = 0
584
+ }
585
+
586
+ // Perform one step of reversing the tree.
587
+ n := stack [tos ]
588
+ if n .l == nil {
589
+ tos --
590
+ } else {
591
+ n .l , n .r = n .r , n .l
592
+ stack [tos ] = n .l
593
+ stack [tos + 1 ] = n .r
594
+ tos ++
595
+ }
596
+
597
+ if i % (1 << 12 ) == 0 {
598
+ // Avoid non-preemptible loops (see issue #10958).
599
+ runtime .Gosched ()
600
+ }
560
601
}
561
- close (done )
562
- }()
602
+ })
563
603
564
- b .ResetTimer ()
604
+ runtime .KeepAlive (wbRoots )
605
+ }
565
606
566
- var stack [depth ]* node
567
- tos := - 1
607
+ func BenchmarkBulkWriteBarrier (b * testing.B ) {
608
+ if runtime .GOMAXPROCS (- 1 ) < 2 {
609
+ // We don't want GC to take our time.
610
+ b .Skip ("need GOMAXPROCS >= 2" )
611
+ }
568
612
569
- // There are two write barriers per iteration, so i+=2.
570
- for i := 0 ; i < b .N ; i += 2 {
571
- if tos == - 1 {
572
- stack [0 ] = root
573
- tos = 0
574
- }
613
+ // Construct a large set of objects we can copy around.
614
+ const heapSize = 64 << 20
615
+ type obj [16 ]* byte
616
+ ptrs := make ([]* obj , heapSize / unsafe .Sizeof (obj {}))
617
+ for i := range ptrs {
618
+ ptrs [i ] = new (obj )
619
+ }
575
620
576
- // Perform one step of reversing the tree.
577
- n := stack [tos ]
578
- if n .l == nil {
579
- tos --
580
- } else {
581
- n .l , n .r = n .r , n .l
582
- stack [tos ] = n .l
583
- stack [tos + 1 ] = n .r
584
- tos ++
585
- }
621
+ writeBarrierBenchmark (b , func () {
622
+ const blockSize = 1024
623
+ var pos int
624
+ for i := 0 ; i < b .N ; i += blockSize {
625
+ // Rotate block.
626
+ block := ptrs [pos : pos + blockSize ]
627
+ first := block [0 ]
628
+ copy (block , block [1 :])
629
+ block [blockSize - 1 ] = first
630
+
631
+ pos += blockSize
632
+ if pos + blockSize > len (ptrs ) {
633
+ pos = 0
634
+ }
586
635
587
- if i % (1 << 12 ) == 0 {
588
- // Avoid non-preemptible loops (see issue #10958).
589
636
runtime .Gosched ()
590
637
}
591
- }
638
+ })
592
639
593
- b .StopTimer ()
594
- atomic .StoreUint32 (& stop , 1 )
595
- <- done
596
-
597
- runtime .KeepAlive (wbRoots )
640
+ runtime .KeepAlive (ptrs )
598
641
}
0 commit comments