github.com/songzhibin97/gkit@v1.2.13/sys/syncx/rwmutex_test.go (about)

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