mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			192 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			192 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
// Copyright 2009 The Go Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
// GOMAXPROCS=10 go test
 | 
						|
 | 
						|
package sync_test
 | 
						|
 | 
						|
import (
 | 
						|
	"runtime"
 | 
						|
	. "sync"
 | 
						|
	"testing"
 | 
						|
)
 | 
						|
 | 
						|
func HammerSemaphore(s *uint32, loops int, cdone chan bool) {
 | 
						|
	for i := 0; i < loops; i++ {
 | 
						|
		Runtime_Semacquire(s)
 | 
						|
		Runtime_Semrelease(s)
 | 
						|
	}
 | 
						|
	cdone <- true
 | 
						|
}
 | 
						|
 | 
						|
func TestSemaphore(t *testing.T) {
 | 
						|
	s := new(uint32)
 | 
						|
	*s = 1
 | 
						|
	c := make(chan bool)
 | 
						|
	for i := 0; i < 10; i++ {
 | 
						|
		go HammerSemaphore(s, 1000, c)
 | 
						|
	}
 | 
						|
	for i := 0; i < 10; i++ {
 | 
						|
		<-c
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkUncontendedSemaphore(b *testing.B) {
 | 
						|
	s := new(uint32)
 | 
						|
	*s = 1
 | 
						|
	HammerSemaphore(s, b.N, make(chan bool, 2))
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkContendedSemaphore(b *testing.B) {
 | 
						|
	b.StopTimer()
 | 
						|
	s := new(uint32)
 | 
						|
	*s = 1
 | 
						|
	c := make(chan bool)
 | 
						|
	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
 | 
						|
	b.StartTimer()
 | 
						|
 | 
						|
	go HammerSemaphore(s, b.N/2, c)
 | 
						|
	go HammerSemaphore(s, b.N/2, c)
 | 
						|
	<-c
 | 
						|
	<-c
 | 
						|
}
 | 
						|
 | 
						|
func HammerMutex(m *Mutex, loops int, cdone chan bool) {
 | 
						|
	for i := 0; i < loops; i++ {
 | 
						|
		m.Lock()
 | 
						|
		m.Unlock()
 | 
						|
	}
 | 
						|
	cdone <- true
 | 
						|
}
 | 
						|
 | 
						|
func TestMutex(t *testing.T) {
 | 
						|
	m := new(Mutex)
 | 
						|
	c := make(chan bool)
 | 
						|
	for i := 0; i < 10; i++ {
 | 
						|
		go HammerMutex(m, 1000, c)
 | 
						|
	}
 | 
						|
	for i := 0; i < 10; i++ {
 | 
						|
		<-c
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestMutexPanic(t *testing.T) {
 | 
						|
	defer func() {
 | 
						|
		if recover() == nil {
 | 
						|
			t.Fatalf("unlock of unlocked mutex did not panic")
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	var mu Mutex
 | 
						|
	mu.Lock()
 | 
						|
	mu.Unlock()
 | 
						|
	mu.Unlock()
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkMutexUncontended(b *testing.B) {
 | 
						|
	type PaddedMutex struct {
 | 
						|
		Mutex
 | 
						|
		pad [128]uint8
 | 
						|
	}
 | 
						|
	b.RunParallel(func(pb *testing.PB) {
 | 
						|
		var mu PaddedMutex
 | 
						|
		for pb.Next() {
 | 
						|
			mu.Lock()
 | 
						|
			mu.Unlock()
 | 
						|
		}
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func benchmarkMutex(b *testing.B, slack, work bool) {
 | 
						|
	var mu Mutex
 | 
						|
	if slack {
 | 
						|
		b.SetParallelism(10)
 | 
						|
	}
 | 
						|
	b.RunParallel(func(pb *testing.PB) {
 | 
						|
		foo := 0
 | 
						|
		for pb.Next() {
 | 
						|
			mu.Lock()
 | 
						|
			mu.Unlock()
 | 
						|
			if work {
 | 
						|
				for i := 0; i < 100; i++ {
 | 
						|
					foo *= 2
 | 
						|
					foo /= 2
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		_ = foo
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkMutex(b *testing.B) {
 | 
						|
	benchmarkMutex(b, false, false)
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkMutexSlack(b *testing.B) {
 | 
						|
	benchmarkMutex(b, true, false)
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkMutexWork(b *testing.B) {
 | 
						|
	benchmarkMutex(b, false, true)
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkMutexWorkSlack(b *testing.B) {
 | 
						|
	benchmarkMutex(b, true, true)
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkMutexNoSpin(b *testing.B) {
 | 
						|
	// This benchmark models a situation where spinning in the mutex should be
 | 
						|
	// non-profitable and allows to confirm that spinning does not do harm.
 | 
						|
	// To achieve this we create excess of goroutines most of which do local work.
 | 
						|
	// These goroutines yield during local work, so that switching from
 | 
						|
	// a blocked goroutine to other goroutines is profitable.
 | 
						|
	// As a matter of fact, this benchmark still triggers some spinning in the mutex.
 | 
						|
	var m Mutex
 | 
						|
	var acc0, acc1 uint64
 | 
						|
	b.SetParallelism(4)
 | 
						|
	b.RunParallel(func(pb *testing.PB) {
 | 
						|
		c := make(chan bool)
 | 
						|
		var data [4 << 10]uint64
 | 
						|
		for i := 0; pb.Next(); i++ {
 | 
						|
			if i%4 == 0 {
 | 
						|
				m.Lock()
 | 
						|
				acc0 -= 100
 | 
						|
				acc1 += 100
 | 
						|
				m.Unlock()
 | 
						|
			} else {
 | 
						|
				for i := 0; i < len(data); i += 4 {
 | 
						|
					data[i]++
 | 
						|
				}
 | 
						|
				// Elaborate way to say runtime.Gosched
 | 
						|
				// that does not put the goroutine onto global runq.
 | 
						|
				go func() {
 | 
						|
					c <- true
 | 
						|
				}()
 | 
						|
				<-c
 | 
						|
			}
 | 
						|
		}
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkMutexSpin(b *testing.B) {
 | 
						|
	// This benchmark models a situation where spinning in the mutex should be
 | 
						|
	// profitable. To achieve this we create a goroutine per-proc.
 | 
						|
	// These goroutines access considerable amount of local data so that
 | 
						|
	// unnecessary rescheduling is penalized by cache misses.
 | 
						|
	var m Mutex
 | 
						|
	var acc0, acc1 uint64
 | 
						|
	b.RunParallel(func(pb *testing.PB) {
 | 
						|
		var data [16 << 10]uint64
 | 
						|
		for i := 0; pb.Next(); i++ {
 | 
						|
			m.Lock()
 | 
						|
			acc0 -= 100
 | 
						|
			acc1 += 100
 | 
						|
			m.Unlock()
 | 
						|
			for i := 0; i < len(data); i += 4 {
 | 
						|
				data[i]++
 | 
						|
			}
 | 
						|
		}
 | 
						|
	})
 | 
						|
}
 |