github.com/aaabigfish/gopkg@v1.1.0/syncx/rwmutex_test.go (about)

     1  // Copyright 2021 ByteDance Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package syncx
    16  
    17  import (
    18  	"fmt"
    19  	"math/rand"
    20  	"sync"
    21  	"testing"
    22  )
    23  
    24  func BenchmarkRWMutex100Read(b *testing.B) {
    25  	for nWorker := 1; nWorker <= 256; nWorker <<= 2 {
    26  		b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) {
    27  			benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 0)
    28  		})
    29  
    30  		b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) {
    31  			benchmarkSyncRWMutexNWriteNRead(b, nWorker, 0)
    32  		})
    33  	}
    34  }
    35  
    36  func BenchmarkRWMutex1Write99Read(b *testing.B) {
    37  	for nWorker := 1; nWorker <= 256; nWorker <<= 2 {
    38  		b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) {
    39  			benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 1)
    40  		})
    41  
    42  		b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) {
    43  			benchmarkSyncRWMutexNWriteNRead(b, nWorker, 1)
    44  		})
    45  	}
    46  }
    47  
    48  func BenchmarkRWMutex10Write90Read(b *testing.B) {
    49  	for nWorker := 1; nWorker <= 256; nWorker <<= 2 {
    50  		b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) {
    51  			benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 10)
    52  		})
    53  
    54  		b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) {
    55  			benchmarkSyncRWMutexNWriteNRead(b, nWorker, 10)
    56  		})
    57  	}
    58  }
    59  
    60  func BenchmarkRWMutex50Write50Read(b *testing.B) {
    61  	for nWorker := 1; nWorker <= 256; nWorker <<= 2 {
    62  		b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) {
    63  			benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 50)
    64  		})
    65  
    66  		b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) {
    67  			benchmarkSyncRWMutexNWriteNRead(b, nWorker, 50)
    68  		})
    69  	}
    70  }
    71  
    72  func benchmarkSyncRWMutexNWriteNRead(b *testing.B, nWorker, nWrite int) {
    73  	var res int // A mock resource we contention for
    74  
    75  	var mu sync.RWMutex
    76  	mu.Lock()
    77  
    78  	var wg sync.WaitGroup
    79  	wg.Add(nWorker)
    80  
    81  	n := b.N
    82  	quota := n / nWorker
    83  
    84  	for g := nWorker; g > 0; g-- {
    85  		// Comuse remaining quota
    86  		if g == 1 {
    87  			quota = n
    88  		}
    89  		go func(quota int) {
    90  			for i := 0; i < quota; i++ {
    91  				if rand.Intn(100) > nWrite-1 {
    92  					mu.RLock()
    93  					_ = res
    94  					mu.RUnlock()
    95  				} else {
    96  					mu.Lock()
    97  					res++
    98  					mu.Unlock()
    99  				}
   100  			}
   101  			wg.Done()
   102  		}(quota)
   103  
   104  		n -= quota
   105  	}
   106  
   107  	if n != 0 {
   108  		b.Fatalf("Incorrect quota assignments: %v remaining", n)
   109  	}
   110  
   111  	b.ResetTimer()
   112  	mu.Unlock()
   113  	wg.Wait()
   114  }
   115  
   116  func benchmarkSyncxRWMutexNWriteNRead(b *testing.B, nWorker, nWrite int) {
   117  	var res int // A mock resource we contention for
   118  
   119  	mu := NewRWMutex()
   120  	mu.Lock()
   121  
   122  	var wg sync.WaitGroup
   123  	wg.Add(nWorker)
   124  
   125  	n := b.N
   126  	quota := n / nWorker
   127  
   128  	for g := nWorker; g > 0; g-- {
   129  		// Comuse remaining quota
   130  		if g == 1 {
   131  			quota = n
   132  		}
   133  		go func(quota int) {
   134  			rmu := mu.RLocker()
   135  			for i := 0; i < quota; i++ {
   136  				if rand.Intn(100) > nWrite-1 {
   137  					rmu.Lock()
   138  					_ = res
   139  					rmu.Unlock()
   140  				} else {
   141  					mu.Lock()
   142  					res++
   143  					mu.Unlock()
   144  				}
   145  			}
   146  			wg.Done()
   147  		}(quota)
   148  
   149  		n -= quota
   150  	}
   151  
   152  	if n != 0 {
   153  		b.Fatalf("Incorrect quota assignments: %v remaining", n)
   154  	}
   155  
   156  	b.ResetTimer()
   157  	mu.Unlock()
   158  	wg.Wait()
   159  }