Home | History | Annotate | Download | only in 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 			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 }
    216