github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/src/sync/rwmutex_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // GOMAXPROCS=10 go test
     6  
     7  package sync_test
     8  
     9  import (
    10  	"fmt"
    11  	"runtime"
    12  	. "sync"
    13  	"sync/atomic"
    14  	"testing"
    15  )
    16  
    17  // There is a modified copy of this file in runtime/rwmutex_test.go.
    18  // If you make any changes here, see if you should make them there.
    19  
    20  func parallelReader(m *RWMutex, clocked, cunlock, cdone chan bool) {
    21  	m.RLock()
    22  	clocked <- true
    23  	<-cunlock
    24  	m.RUnlock()
    25  	cdone <- true
    26  }
    27  
    28  func doTestParallelReaders(numReaders, gomaxprocs int) {
    29  	runtime.GOMAXPROCS(gomaxprocs)
    30  	var m RWMutex
    31  	clocked := make(chan bool)
    32  	cunlock := make(chan bool)
    33  	cdone := make(chan bool)
    34  	for i := 0; i < numReaders; i++ {
    35  		go parallelReader(&m, clocked, cunlock, cdone)
    36  	}
    37  	// Wait for all parallel RLock()s to succeed.
    38  	for i := 0; i < numReaders; i++ {
    39  		<-clocked
    40  	}
    41  	for i := 0; i < numReaders; i++ {
    42  		cunlock <- true
    43  	}
    44  	// Wait for the goroutines to finish.
    45  	for i := 0; i < numReaders; i++ {
    46  		<-cdone
    47  	}
    48  }
    49  
    50  func TestParallelReaders(t *testing.T) {
    51  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
    52  	doTestParallelReaders(1, 4)
    53  	doTestParallelReaders(3, 4)
    54  	doTestParallelReaders(4, 2)
    55  }
    56  
    57  func reader(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) {
    58  	for i := 0; i < num_iterations; i++ {
    59  		rwm.RLock()
    60  		n := atomic.AddInt32(activity, 1)
    61  		if n < 1 || n >= 10000 {
    62  			panic(fmt.Sprintf("wlock(%d)\n", n))
    63  		}
    64  		for i := 0; i < 100; i++ {
    65  		}
    66  		atomic.AddInt32(activity, -1)
    67  		rwm.RUnlock()
    68  	}
    69  	cdone <- true
    70  }
    71  
    72  func writer(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) {
    73  	for i := 0; i < num_iterations; i++ {
    74  		rwm.Lock()
    75  		n := atomic.AddInt32(activity, 10000)
    76  		if n != 10000 {
    77  			panic(fmt.Sprintf("wlock(%d)\n", n))
    78  		}
    79  		for i := 0; i < 100; i++ {
    80  		}
    81  		atomic.AddInt32(activity, -10000)
    82  		rwm.Unlock()
    83  	}
    84  	cdone <- true
    85  }
    86  
    87  func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) {
    88  	runtime.GOMAXPROCS(gomaxprocs)
    89  	// Number of active readers + 10000 * number of active writers.
    90  	var activity int32
    91  	var rwm RWMutex
    92  	cdone := make(chan bool)
    93  	go writer(&rwm, num_iterations, &activity, cdone)
    94  	var i int
    95  	for i = 0; i < numReaders/2; i++ {
    96  		go reader(&rwm, num_iterations, &activity, cdone)
    97  	}
    98  	go writer(&rwm, num_iterations, &activity, cdone)
    99  	for ; i < numReaders; i++ {
   100  		go reader(&rwm, num_iterations, &activity, cdone)
   101  	}
   102  	// Wait for the 2 writers and all readers to finish.
   103  	for i := 0; i < 2+numReaders; i++ {
   104  		<-cdone
   105  	}
   106  }
   107  
   108  func TestRWMutex(t *testing.T) {
   109  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
   110  	n := 1000
   111  	if testing.Short() {
   112  		n = 5
   113  	}
   114  	HammerRWMutex(1, 1, n)
   115  	HammerRWMutex(1, 3, n)
   116  	HammerRWMutex(1, 10, n)
   117  	HammerRWMutex(4, 1, n)
   118  	HammerRWMutex(4, 3, n)
   119  	HammerRWMutex(4, 10, n)
   120  	HammerRWMutex(10, 1, n)
   121  	HammerRWMutex(10, 3, n)
   122  	HammerRWMutex(10, 10, n)
   123  	HammerRWMutex(10, 5, n)
   124  }
   125  
   126  func TestRLocker(t *testing.T) {
   127  	var wl RWMutex
   128  	var rl Locker
   129  	wlocked := make(chan bool, 1)
   130  	rlocked := make(chan bool, 1)
   131  	rl = wl.RLocker()
   132  	n := 10
   133  	go func() {
   134  		for i := 0; i < n; i++ {
   135  			rl.Lock()
   136  			rl.Lock()
   137  			rlocked <- true
   138  			wl.Lock()
   139  			wlocked <- true
   140  		}
   141  	}()
   142  	for i := 0; i < n; i++ {
   143  		<-rlocked
   144  		rl.Unlock()
   145  		select {
   146  		case <-wlocked:
   147  			t.Fatal("RLocker() didn't read-lock it")
   148  		default:
   149  		}
   150  		rl.Unlock()
   151  		<-wlocked
   152  		select {
   153  		case <-rlocked:
   154  			t.Fatal("RLocker() didn't respect the write lock")
   155  		default:
   156  		}
   157  		wl.Unlock()
   158  	}
   159  }
   160  
   161  func BenchmarkRWMutexUncontended(b *testing.B) {
   162  	type PaddedRWMutex struct {
   163  		RWMutex
   164  		pad [32]uint32
   165  	}
   166  	b.RunParallel(func(pb *testing.PB) {
   167  		var rwm PaddedRWMutex
   168  		for pb.Next() {
   169  			rwm.RLock()
   170  			rwm.RLock()
   171  			rwm.RUnlock()
   172  			rwm.RUnlock()
   173  			rwm.Lock()
   174  			rwm.Unlock()
   175  		}
   176  	})
   177  }
   178  
   179  func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) {
   180  	var rwm RWMutex
   181  	b.RunParallel(func(pb *testing.PB) {
   182  		foo := 0
   183  		for pb.Next() {
   184  			foo++
   185  			if foo%writeRatio == 0 {
   186  				rwm.Lock()
   187  				rwm.Unlock()
   188  			} else {
   189  				rwm.RLock()
   190  				for i := 0; i != localWork; i += 1 {
   191  					foo *= 2
   192  					foo /= 2
   193  				}
   194  				rwm.RUnlock()
   195  			}
   196  		}
   197  		_ = foo
   198  	})
   199  }
   200  
   201  func BenchmarkRWMutexWrite100(b *testing.B) {
   202  	benchmarkRWMutex(b, 0, 100)
   203  }
   204  
   205  func BenchmarkRWMutexWrite10(b *testing.B) {
   206  	benchmarkRWMutex(b, 0, 10)
   207  }
   208  
   209  func BenchmarkRWMutexWorkWrite100(b *testing.B) {
   210  	benchmarkRWMutex(b, 100, 100)
   211  }
   212  
   213  func BenchmarkRWMutexWorkWrite10(b *testing.B) {
   214  	benchmarkRWMutex(b, 100, 10)
   215  }