...

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