github.com/zeebo/mon@v0.0.0-20211012163247-13d39bdb54fa/internal/tests/helpers.go (about)

     1  package tests
     2  
     3  import (
     4  	"fmt"
     5  	"runtime"
     6  	"sync"
     7  	"testing"
     8  	"unsafe"
     9  
    10  	"github.com/zeebo/pcg"
    11  )
    12  
    13  var Value = unsafe.Pointer(new(int))
    14  
    15  func Empty() unsafe.Pointer { return Value }
    16  
    17  const (
    18  	Size = 1 << 14
    19  	Mask = Size - 1
    20  )
    21  
    22  var (
    23  	ptrs = make([]unsafe.Pointer, Size)
    24  	keys = make([]string, Size)
    25  )
    26  
    27  func init() {
    28  	for i := range ptrs {
    29  		ptrs[i&Mask] = unsafe.Pointer(new(int))
    30  		keys[i&Mask] = fmt.Sprintf("%064d", i)
    31  	}
    32  }
    33  
    34  func Ptr(i uint32) (p unsafe.Pointer) { return ptrs[i&Mask] }
    35  
    36  func Key(i uint32) (s string) { return keys[i&Mask] }
    37  
    38  type Type interface {
    39  	Upsert(string, func() unsafe.Pointer) unsafe.Pointer
    40  	Lookup(string) unsafe.Pointer
    41  }
    42  
    43  func RunBenchmarks(b *testing.B, fn func() Type) {
    44  	rng := pcg.New(0)
    45  
    46  	b.Run("UpsertFull", func(b *testing.B) {
    47  		b.ReportAllocs()
    48  
    49  		for i := 0; i < b.N; i++ {
    50  			t := fn()
    51  			for i := 0; i < Size; i++ {
    52  				t.Upsert(Key(rng.Uint32n(Size)), Empty)
    53  			}
    54  		}
    55  	})
    56  
    57  	b.Run("Upsert", func(b *testing.B) {
    58  		t := fn()
    59  		b.ReportAllocs()
    60  
    61  		for i := 0; i < b.N; i++ {
    62  			t.Upsert(Key(rng.Uint32n(Size)), Empty)
    63  		}
    64  	})
    65  
    66  	b.Run("Lookup", func(b *testing.B) {
    67  		var sink unsafe.Pointer
    68  		t := fn()
    69  		for i := uint32(0); i < Size; i++ {
    70  			t.Upsert(Key(i), Empty)
    71  		}
    72  		b.ReportAllocs()
    73  		b.ResetTimer()
    74  
    75  		for i := 0; i < b.N; i++ {
    76  			sink = t.Lookup(Key(rng.Uint32n(Size)))
    77  		}
    78  
    79  		runtime.KeepAlive(sink)
    80  	})
    81  
    82  	b.Run("UpsertParallel", func(b *testing.B) {
    83  		t := fn()
    84  		b.ReportAllocs()
    85  		b.ResetTimer()
    86  
    87  		b.RunParallel(func(pb *testing.PB) {
    88  			rng := pcg.New(pcg.Uint64())
    89  			for pb.Next() {
    90  				t.Upsert(Key(rng.Uint32n(Size)), Empty)
    91  			}
    92  		})
    93  	})
    94  
    95  	b.Run("UpsertFullParallel", func(b *testing.B) {
    96  		procs := runtime.GOMAXPROCS(-1)
    97  		iters := Size / procs
    98  		b.ReportAllocs()
    99  
   100  		for i := 0; i < b.N; i++ {
   101  			t := fn()
   102  			var wg sync.WaitGroup
   103  
   104  			for i := 0; i < procs; i++ {
   105  				wg.Add(1)
   106  				go func() {
   107  					rng := pcg.New(pcg.Uint64())
   108  					for i := 0; i < iters; i++ {
   109  						t.Upsert(Key(rng.Uint32n(Size)), Empty)
   110  					}
   111  					wg.Done()
   112  				}()
   113  			}
   114  			wg.Wait()
   115  		}
   116  	})
   117  }