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 7package sync_test 8 9import ( 10 "runtime" 11 . "sync" 12 "sync/atomic" 13 "testing" 14) 15 16func HammerSemaphore(s *uint32, loops int, cdone chan bool) { 17 for i := 0; i < loops; i++ { 18 Runtime_Semacquire(s) 19 Runtime_Semrelease(s) 20 } 21 cdone <- true 22} 23 24func TestSemaphore(t *testing.T) { 25 s := new(uint32) 26 *s = 1 27 c := make(chan bool) 28 for i := 0; i < 10; i++ { 29 go HammerSemaphore(s, 1000, c) 30 } 31 for i := 0; i < 10; i++ { 32 <-c 33 } 34} 35 36func BenchmarkUncontendedSemaphore(b *testing.B) { 37 s := new(uint32) 38 *s = 1 39 HammerSemaphore(s, b.N, make(chan bool, 2)) 40} 41 42func BenchmarkContendedSemaphore(b *testing.B) { 43 b.StopTimer() 44 s := new(uint32) 45 *s = 1 46 c := make(chan bool) 47 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) 48 b.StartTimer() 49 50 go HammerSemaphore(s, b.N/2, c) 51 go HammerSemaphore(s, b.N/2, c) 52 <-c 53 <-c 54} 55 56func HammerMutex(m *Mutex, loops int, cdone chan bool) { 57 for i := 0; i < loops; i++ { 58 m.Lock() 59 m.Unlock() 60 } 61 cdone <- true 62} 63 64func TestMutex(t *testing.T) { 65 m := new(Mutex) 66 c := make(chan bool) 67 for i := 0; i < 10; i++ { 68 go HammerMutex(m, 1000, c) 69 } 70 for i := 0; i < 10; i++ { 71 <-c 72 } 73} 74 75func TestMutexPanic(t *testing.T) { 76 defer func() { 77 if recover() == nil { 78 t.Fatalf("unlock of unlocked mutex did not panic") 79 } 80 }() 81 82 var mu Mutex 83 mu.Lock() 84 mu.Unlock() 85 mu.Unlock() 86} 87 88func BenchmarkMutexUncontended(b *testing.B) { 89 type PaddedMutex struct { 90 Mutex 91 pad [128]uint8 92 } 93 const CallsPerSched = 1000 94 procs := runtime.GOMAXPROCS(-1) 95 N := int32(b.N / CallsPerSched) 96 c := make(chan bool, procs) 97 for p := 0; p < procs; p++ { 98 go func() { 99 var mu PaddedMutex 100 for atomic.AddInt32(&N, -1) >= 0 { 101 runtime.Gosched() 102 for g := 0; g < CallsPerSched; g++ { 103 mu.Lock() 104 mu.Unlock() 105 } 106 } 107 c <- true 108 }() 109 } 110 for p := 0; p < procs; p++ { 111 <-c 112 } 113} 114 115func benchmarkMutex(b *testing.B, slack, work bool) { 116 const ( 117 CallsPerSched = 1000 118 LocalWork = 100 119 GoroutineSlack = 10 120 ) 121 procs := runtime.GOMAXPROCS(-1) 122 if slack { 123 procs *= GoroutineSlack 124 } 125 N := int32(b.N / CallsPerSched) 126 c := make(chan bool, procs) 127 var mu Mutex 128 for p := 0; p < procs; p++ { 129 go func() { 130 foo := 0 131 for atomic.AddInt32(&N, -1) >= 0 { 132 runtime.Gosched() 133 for g := 0; g < CallsPerSched; g++ { 134 mu.Lock() 135 mu.Unlock() 136 if work { 137 for i := 0; i < LocalWork; i++ { 138 foo *= 2 139 foo /= 2 140 } 141 } 142 } 143 } 144 c <- foo == 42 145 }() 146 } 147 for p := 0; p < procs; p++ { 148 <-c 149 } 150} 151 152func BenchmarkMutex(b *testing.B) { 153 benchmarkMutex(b, false, false) 154} 155 156func BenchmarkMutexSlack(b *testing.B) { 157 benchmarkMutex(b, true, false) 158} 159 160func BenchmarkMutexWork(b *testing.B) { 161 benchmarkMutex(b, false, true) 162} 163 164func BenchmarkMutexWorkSlack(b *testing.B) { 165 benchmarkMutex(b, true, true) 166} 167