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
20 func HammerSemaphore(s
*uint32, loops
int, cdone
chan bool) {
21 for i
:= 0; i
< loops
; i
++ {
28 func TestSemaphore(t
*testing
.T
) {
32 for i
:= 0; i
< 10; i
++ {
33 go HammerSemaphore(s
, 1000, c
)
35 for i
:= 0; i
< 10; i
++ {
40 func BenchmarkUncontendedSemaphore(b
*testing
.B
) {
43 HammerSemaphore(s
, b
.N
, make(chan bool, 2))
46 func BenchmarkContendedSemaphore(b
*testing
.B
) {
51 defer runtime
.GOMAXPROCS(runtime
.GOMAXPROCS(2))
54 go HammerSemaphore(s
, b
.N
/2, c
)
55 go HammerSemaphore(s
, b
.N
/2, c
)
60 func HammerMutex(m
*Mutex
, loops
int, cdone
chan bool) {
61 for i
:= 0; i
< loops
; i
++ {
68 func TestMutex(t
*testing
.T
) {
69 if n
:= runtime
.SetMutexProfileFraction(1); n
!= 0 {
70 t
.Logf("got mutexrate %d expected 0", n
)
72 defer runtime
.SetMutexProfileFraction(0)
75 for i
:= 0; i
< 10; i
++ {
76 go HammerMutex(m
, 1000, c
)
78 for i
:= 0; i
< 10; i
++ {
83 var misuseTests
= []struct {
154 if len(os
.Args
) == 3 && os
.Args
[1] == "TESTMISUSE" {
155 for _
, test
:= range misuseTests
{
156 if test
.name
== os
.Args
[2] {
158 fmt
.Printf("test completed\n")
162 fmt
.Printf("unknown test\n")
167 func TestMutexMisuse(t
*testing
.T
) {
168 testenv
.MustHaveExec(t
)
169 for _
, test
:= range misuseTests
{
170 out
, err
:= exec
.Command(os
.Args
[0], "TESTMISUSE", test
.name
).CombinedOutput()
171 if err
== nil ||
!strings
.Contains(string(out
), "unlocked") {
172 t
.Errorf("%s: did not find failure with message about unlocked lock: %s\n%s\n", test
.name
, err
, out
)
177 func BenchmarkMutexUncontended(b
*testing
.B
) {
178 type PaddedMutex
struct {
182 b
.RunParallel(func(pb
*testing
.PB
) {
191 func benchmarkMutex(b
*testing
.B
, slack
, work
bool) {
196 b
.RunParallel(func(pb
*testing
.PB
) {
202 for i
:= 0; i
< 100; i
++ {
212 func BenchmarkMutex(b
*testing
.B
) {
213 benchmarkMutex(b
, false, false)
216 func BenchmarkMutexSlack(b
*testing
.B
) {
217 benchmarkMutex(b
, true, false)
220 func BenchmarkMutexWork(b
*testing
.B
) {
221 benchmarkMutex(b
, false, true)
224 func BenchmarkMutexWorkSlack(b
*testing
.B
) {
225 benchmarkMutex(b
, true, true)
228 func BenchmarkMutexNoSpin(b
*testing
.B
) {
229 // This benchmark models a situation where spinning in the mutex should be
230 // non-profitable and allows to confirm that spinning does not do harm.
231 // To achieve this we create excess of goroutines most of which do local work.
232 // These goroutines yield during local work, so that switching from
233 // a blocked goroutine to other goroutines is profitable.
234 // As a matter of fact, this benchmark still triggers some spinning in the mutex.
236 var acc0
, acc1
uint64
238 b
.RunParallel(func(pb
*testing
.PB
) {
240 var data
[4 << 10]uint64
241 for i
:= 0; pb
.Next(); i
++ {
248 for i
:= 0; i
< len(data
); i
+= 4 {
251 // Elaborate way to say runtime.Gosched
252 // that does not put the goroutine onto global runq.
262 func BenchmarkMutexSpin(b
*testing
.B
) {
263 // This benchmark models a situation where spinning in the mutex should be
264 // profitable. To achieve this we create a goroutine per-proc.
265 // These goroutines access considerable amount of local data so that
266 // unnecessary rescheduling is penalized by cache misses.
268 var acc0
, acc1
uint64
269 b
.RunParallel(func(pb
*testing
.PB
) {
270 var data
[16 << 10]uint64
271 for i
:= 0; pb
.Next(); i
++ {
276 for i
:= 0; i
< len(data
); i
+= 4 {