Black Lives Matter. Support the Equal Justice Initiative.

Source file src/sync/rwmutex_test.go

Documentation: sync

     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  			rwm.RUnlock()
    63  			panic(fmt.Sprintf("wlock(%d)\n", n))
    64  		}
    65  		for i := 0; i < 100; i++ {
    66  		}
    67  		atomic.AddInt32(activity, -1)
    68  		rwm.RUnlock()
    69  	}
    70  	cdone <- true
    71  }
    72  
    73  func writer(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) {
    74  	for i := 0; i < num_iterations; i++ {
    75  		rwm.Lock()
    76  		n := atomic.AddInt32(activity, 10000)
    77  		if n != 10000 {
    78  			rwm.Unlock()
    79  			panic(fmt.Sprintf("wlock(%d)\n", n))
    80  		}
    81  		for i := 0; i < 100; i++ {
    82  		}
    83  		atomic.AddInt32(activity, -10000)
    84  		rwm.Unlock()
    85  	}
    86  	cdone <- true
    87  }
    88  
    89  func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) {
    90  	runtime.GOMAXPROCS(gomaxprocs)
    91  	// Number of active readers + 10000 * number of active writers.
    92  	var activity int32
    93  	var rwm RWMutex
    94  	cdone := make(chan bool)
    95  	go writer(&rwm, num_iterations, &activity, cdone)
    96  	var i int
    97  	for i = 0; i < numReaders/2; i++ {
    98  		go reader(&rwm, num_iterations, &activity, cdone)
    99  	}
   100  	go writer(&rwm, num_iterations, &activity, cdone)
   101  	for ; i < numReaders; i++ {
   102  		go reader(&rwm, num_iterations, &activity, cdone)
   103  	}
   104  	// Wait for the 2 writers and all readers to finish.
   105  	for i := 0; i < 2+numReaders; i++ {
   106  		<-cdone
   107  	}
   108  }
   109  
   110  func TestRWMutex(t *testing.T) {
   111  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
   112  	n := 1000
   113  	if testing.Short() {
   114  		n = 5
   115  	}
   116  	HammerRWMutex(1, 1, n)
   117  	HammerRWMutex(1, 3, n)
   118  	HammerRWMutex(1, 10, n)
   119  	HammerRWMutex(4, 1, n)
   120  	HammerRWMutex(4, 3, n)
   121  	HammerRWMutex(4, 10, n)
   122  	HammerRWMutex(10, 1, n)
   123  	HammerRWMutex(10, 3, n)
   124  	HammerRWMutex(10, 10, n)
   125  	HammerRWMutex(10, 5, n)
   126  }
   127  
   128  func TestRLocker(t *testing.T) {
   129  	var wl RWMutex
   130  	var rl Locker
   131  	wlocked := make(chan bool, 1)
   132  	rlocked := make(chan bool, 1)
   133  	rl = wl.RLocker()
   134  	n := 10
   135  	go func() {
   136  		for i := 0; i < n; i++ {
   137  			rl.Lock()
   138  			rl.Lock()
   139  			rlocked <- true
   140  			wl.Lock()
   141  			wlocked <- true
   142  		}
   143  	}()
   144  	for i := 0; i < n; i++ {
   145  		<-rlocked
   146  		rl.Unlock()
   147  		select {
   148  		case <-wlocked:
   149  			t.Fatal("RLocker() didn't read-lock it")
   150  		default:
   151  		}
   152  		rl.Unlock()
   153  		<-wlocked
   154  		select {
   155  		case <-rlocked:
   156  			t.Fatal("RLocker() didn't respect the write lock")
   157  		default:
   158  		}
   159  		wl.Unlock()
   160  	}
   161  }
   162  
   163  func BenchmarkRWMutexUncontended(b *testing.B) {
   164  	type PaddedRWMutex struct {
   165  		RWMutex
   166  		pad [32]uint32
   167  	}
   168  	b.RunParallel(func(pb *testing.PB) {
   169  		var rwm PaddedRWMutex
   170  		for pb.Next() {
   171  			rwm.RLock()
   172  			rwm.RLock()
   173  			rwm.RUnlock()
   174  			rwm.RUnlock()
   175  			rwm.Lock()
   176  			rwm.Unlock()
   177  		}
   178  	})
   179  }
   180  
   181  func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) {
   182  	var rwm RWMutex
   183  	b.RunParallel(func(pb *testing.PB) {
   184  		foo := 0
   185  		for pb.Next() {
   186  			foo++
   187  			if foo%writeRatio == 0 {
   188  				rwm.Lock()
   189  				rwm.Unlock()
   190  			} else {
   191  				rwm.RLock()
   192  				for i := 0; i != localWork; i += 1 {
   193  					foo *= 2
   194  					foo /= 2
   195  				}
   196  				rwm.RUnlock()
   197  			}
   198  		}
   199  		_ = foo
   200  	})
   201  }
   202  
   203  func BenchmarkRWMutexWrite100(b *testing.B) {
   204  	benchmarkRWMutex(b, 0, 100)
   205  }
   206  
   207  func BenchmarkRWMutexWrite10(b *testing.B) {
   208  	benchmarkRWMutex(b, 0, 10)
   209  }
   210  
   211  func BenchmarkRWMutexWorkWrite100(b *testing.B) {
   212  	benchmarkRWMutex(b, 100, 100)
   213  }
   214  
   215  func BenchmarkRWMutexWorkWrite10(b *testing.B) {
   216  	benchmarkRWMutex(b, 100, 10)
   217  }
   218  

View as plain text