middle-end/116891 - fix (negate (IFN_FNMS@3 @0 @1 @2)) -> (IFN_FMA @0 @1 @2)
[official-gcc.git] / libgo / go / sync / mutex_test.go
blobcca0986a30975ebd9c51cf37d97037b43b666dae
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.
5 // GOMAXPROCS=10 go test
7 package sync_test
9 import (
10 "fmt"
11 "internal/testenv"
12 "os"
13 "os/exec"
14 "runtime"
15 "strings"
16 . "sync"
17 "testing"
18 "time"
21 func HammerSemaphore(s *uint32, loops int, cdone chan bool) {
22 for i := 0; i < loops; i++ {
23 Runtime_Semacquire(s)
24 Runtime_Semrelease(s, false, 0)
26 cdone <- true
29 func TestSemaphore(t *testing.T) {
30 s := new(uint32)
31 *s = 1
32 c := make(chan bool)
33 for i := 0; i < 10; i++ {
34 go HammerSemaphore(s, 1000, c)
36 for i := 0; i < 10; i++ {
37 <-c
41 func BenchmarkUncontendedSemaphore(b *testing.B) {
42 s := new(uint32)
43 *s = 1
44 HammerSemaphore(s, b.N, make(chan bool, 2))
47 func BenchmarkContendedSemaphore(b *testing.B) {
48 b.StopTimer()
49 s := new(uint32)
50 *s = 1
51 c := make(chan bool)
52 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
53 b.StartTimer()
55 go HammerSemaphore(s, b.N/2, c)
56 go HammerSemaphore(s, b.N/2, c)
57 <-c
58 <-c
61 func HammerMutex(m *Mutex, loops int, cdone chan bool) {
62 for i := 0; i < loops; i++ {
63 if i%3 == 0 {
64 if m.TryLock() {
65 m.Unlock()
67 continue
69 m.Lock()
70 m.Unlock()
72 cdone <- true
75 func TestMutex(t *testing.T) {
76 if n := runtime.SetMutexProfileFraction(1); n != 0 {
77 t.Logf("got mutexrate %d expected 0", n)
79 defer runtime.SetMutexProfileFraction(0)
81 m := new(Mutex)
83 m.Lock()
84 if m.TryLock() {
85 t.Fatalf("TryLock succeeded with mutex locked")
87 m.Unlock()
88 if !m.TryLock() {
89 t.Fatalf("TryLock failed with mutex unlocked")
91 m.Unlock()
93 c := make(chan bool)
94 for i := 0; i < 10; i++ {
95 go HammerMutex(m, 1000, c)
97 for i := 0; i < 10; i++ {
98 <-c
102 var misuseTests = []struct {
103 name string
104 f func()
107 "Mutex.Unlock",
108 func() {
109 var mu Mutex
110 mu.Unlock()
114 "Mutex.Unlock2",
115 func() {
116 var mu Mutex
117 mu.Lock()
118 mu.Unlock()
119 mu.Unlock()
123 "RWMutex.Unlock",
124 func() {
125 var mu RWMutex
126 mu.Unlock()
130 "RWMutex.Unlock2",
131 func() {
132 var mu RWMutex
133 mu.RLock()
134 mu.Unlock()
138 "RWMutex.Unlock3",
139 func() {
140 var mu RWMutex
141 mu.Lock()
142 mu.Unlock()
143 mu.Unlock()
147 "RWMutex.RUnlock",
148 func() {
149 var mu RWMutex
150 mu.RUnlock()
154 "RWMutex.RUnlock2",
155 func() {
156 var mu RWMutex
157 mu.Lock()
158 mu.RUnlock()
162 "RWMutex.RUnlock3",
163 func() {
164 var mu RWMutex
165 mu.RLock()
166 mu.RUnlock()
167 mu.RUnlock()
172 func init() {
173 if len(os.Args) == 3 && os.Args[1] == "TESTMISUSE" {
174 for _, test := range misuseTests {
175 if test.name == os.Args[2] {
176 func() {
177 defer func() { recover() }()
178 test.f()
180 fmt.Printf("test completed\n")
181 os.Exit(0)
184 fmt.Printf("unknown test\n")
185 os.Exit(0)
189 func TestMutexMisuse(t *testing.T) {
190 testenv.MustHaveExec(t)
191 for _, test := range misuseTests {
192 out, err := exec.Command(os.Args[0], "TESTMISUSE", test.name).CombinedOutput()
193 if err == nil || !strings.Contains(string(out), "unlocked") {
194 t.Errorf("%s: did not find failure with message about unlocked lock: %s\n%s\n", test.name, err, out)
199 func TestMutexFairness(t *testing.T) {
200 var mu Mutex
201 stop := make(chan bool)
202 defer close(stop)
203 go func() {
204 for {
205 mu.Lock()
206 time.Sleep(100 * time.Microsecond)
207 mu.Unlock()
208 select {
209 case <-stop:
210 return
211 default:
215 done := make(chan bool, 1)
216 go func() {
217 for i := 0; i < 10; i++ {
218 time.Sleep(100 * time.Microsecond)
219 mu.Lock()
220 mu.Unlock()
222 done <- true
224 select {
225 case <-done:
226 case <-time.After(10 * time.Second):
227 t.Fatalf("can't acquire Mutex in 10 seconds")
231 func BenchmarkMutexUncontended(b *testing.B) {
232 type PaddedMutex struct {
233 Mutex
234 pad [128]uint8
236 b.RunParallel(func(pb *testing.PB) {
237 var mu PaddedMutex
238 for pb.Next() {
239 mu.Lock()
240 mu.Unlock()
245 func benchmarkMutex(b *testing.B, slack, work bool) {
246 var mu Mutex
247 if slack {
248 b.SetParallelism(10)
250 b.RunParallel(func(pb *testing.PB) {
251 foo := 0
252 for pb.Next() {
253 mu.Lock()
254 mu.Unlock()
255 if work {
256 for i := 0; i < 100; i++ {
257 foo *= 2
258 foo /= 2
262 _ = foo
266 func BenchmarkMutex(b *testing.B) {
267 benchmarkMutex(b, false, false)
270 func BenchmarkMutexSlack(b *testing.B) {
271 benchmarkMutex(b, true, false)
274 func BenchmarkMutexWork(b *testing.B) {
275 benchmarkMutex(b, false, true)
278 func BenchmarkMutexWorkSlack(b *testing.B) {
279 benchmarkMutex(b, true, true)
282 func BenchmarkMutexNoSpin(b *testing.B) {
283 // This benchmark models a situation where spinning in the mutex should be
284 // non-profitable and allows to confirm that spinning does not do harm.
285 // To achieve this we create excess of goroutines most of which do local work.
286 // These goroutines yield during local work, so that switching from
287 // a blocked goroutine to other goroutines is profitable.
288 // As a matter of fact, this benchmark still triggers some spinning in the mutex.
289 var m Mutex
290 var acc0, acc1 uint64
291 b.SetParallelism(4)
292 b.RunParallel(func(pb *testing.PB) {
293 c := make(chan bool)
294 var data [4 << 10]uint64
295 for i := 0; pb.Next(); i++ {
296 if i%4 == 0 {
297 m.Lock()
298 acc0 -= 100
299 acc1 += 100
300 m.Unlock()
301 } else {
302 for i := 0; i < len(data); i += 4 {
303 data[i]++
305 // Elaborate way to say runtime.Gosched
306 // that does not put the goroutine onto global runq.
307 go func() {
308 c <- true
316 func BenchmarkMutexSpin(b *testing.B) {
317 // This benchmark models a situation where spinning in the mutex should be
318 // profitable. To achieve this we create a goroutine per-proc.
319 // These goroutines access considerable amount of local data so that
320 // unnecessary rescheduling is penalized by cache misses.
321 var m Mutex
322 var acc0, acc1 uint64
323 b.RunParallel(func(pb *testing.PB) {
324 var data [16 << 10]uint64
325 for i := 0; pb.Next(); i++ {
326 m.Lock()
327 acc0 -= 100
328 acc1 += 100
329 m.Unlock()
330 for i := 0; i < len(data); i += 4 {
331 data[i]++