github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/sys/syncx/rwmutex_test.go (about)

     1  package syncx
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"testing"
     7  
     8  	"github.com/songzhibin97/go-baseutils/sys/fastrand"
     9  )
    10  
    11  func BenchmarkRWMutex100Read(b *testing.B) {
    12  	for nWorker := 1; nWorker <= 256; nWorker <<= 2 {
    13  		b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) {
    14  			benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 0)
    15  		})
    16  
    17  		b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) {
    18  			benchmarkSyncRWMutexNWriteNRead(b, nWorker, 0)
    19  		})
    20  	}
    21  }
    22  
    23  func BenchmarkRWMutex1Write99Read(b *testing.B) {
    24  	for nWorker := 1; nWorker <= 256; nWorker <<= 2 {
    25  		b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) {
    26  			benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 1)
    27  		})
    28  
    29  		b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) {
    30  			benchmarkSyncRWMutexNWriteNRead(b, nWorker, 1)
    31  		})
    32  	}
    33  }
    34  
    35  func BenchmarkRWMutex10Write90Read(b *testing.B) {
    36  	for nWorker := 1; nWorker <= 256; nWorker <<= 2 {
    37  		b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) {
    38  			benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 10)
    39  		})
    40  
    41  		b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) {
    42  			benchmarkSyncRWMutexNWriteNRead(b, nWorker, 10)
    43  		})
    44  	}
    45  }
    46  
    47  func BenchmarkRWMutex50Write50Read(b *testing.B) {
    48  	for nWorker := 1; nWorker <= 256; nWorker <<= 2 {
    49  		b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) {
    50  			benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 50)
    51  		})
    52  
    53  		b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) {
    54  			benchmarkSyncRWMutexNWriteNRead(b, nWorker, 50)
    55  		})
    56  	}
    57  }
    58  
    59  func benchmarkSyncRWMutexNWriteNRead(b *testing.B, nWorker, nWrite int) {
    60  	var res int // A mock resource we contention for
    61  
    62  	var mu sync.RWMutex
    63  	mu.Lock()
    64  
    65  	var wg sync.WaitGroup
    66  	wg.Add(nWorker)
    67  
    68  	n := b.N
    69  	quota := n / nWorker
    70  
    71  	for g := nWorker; g > 0; g-- {
    72  		// Comuse remaining quota
    73  		if g == 1 {
    74  			quota = n
    75  		}
    76  		go func(quota int) {
    77  			for i := 0; i < quota; i++ {
    78  				if fastrand.Intn(100) > nWrite-1 {
    79  					mu.RLock()
    80  					_ = res
    81  					mu.RUnlock()
    82  				} else {
    83  					mu.Lock()
    84  					res++
    85  					mu.Unlock()
    86  				}
    87  			}
    88  			wg.Done()
    89  		}(quota)
    90  
    91  		n -= quota
    92  	}
    93  
    94  	if n != 0 {
    95  		b.Fatalf("Incorrect quota assignments: %v remaining", n)
    96  	}
    97  
    98  	b.ResetTimer()
    99  	mu.Unlock()
   100  	wg.Wait()
   101  }
   102  
   103  func benchmarkSyncxRWMutexNWriteNRead(b *testing.B, nWorker, nWrite int) {
   104  	var res int // A mock resource we contention for
   105  
   106  	mu := NewRWMutex()
   107  	mu.Lock()
   108  
   109  	var wg sync.WaitGroup
   110  	wg.Add(nWorker)
   111  
   112  	n := b.N
   113  	quota := n / nWorker
   114  
   115  	for g := nWorker; g > 0; g-- {
   116  		// Comuse remaining quota
   117  		if g == 1 {
   118  			quota = n
   119  		}
   120  		go func(quota int) {
   121  			rmu := mu.RLocker()
   122  			for i := 0; i < quota; i++ {
   123  				if fastrand.Intn(100) > nWrite-1 {
   124  					rmu.Lock()
   125  					_ = res
   126  					rmu.Unlock()
   127  				} else {
   128  					mu.Lock()
   129  					res++
   130  					mu.Unlock()
   131  				}
   132  			}
   133  			wg.Done()
   134  		}(quota)
   135  
   136  		n -= quota
   137  	}
   138  
   139  	if n != 0 {
   140  		b.Fatalf("Incorrect quota assignments: %v remaining", n)
   141  	}
   142  
   143  	b.ResetTimer()
   144  	mu.Unlock()
   145  	wg.Wait()
   146  }