2011-07-20 09:51:25 -06:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
package runtime_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"runtime"
|
2011-08-15 00:51:51 -06:00
|
|
|
"sync"
|
2011-07-20 09:51:25 -06:00
|
|
|
"sync/atomic"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
2011-07-25 10:25:37 -06:00
|
|
|
func TestChanSendInterface(t *testing.T) {
|
|
|
|
type mt struct{}
|
|
|
|
m := &mt{}
|
|
|
|
c := make(chan interface{}, 1)
|
|
|
|
c <- m
|
|
|
|
select {
|
|
|
|
case c <- m:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
select {
|
|
|
|
case c <- m:
|
|
|
|
case c <- &mt{}:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-15 00:51:51 -06:00
|
|
|
func TestPseudoRandomSend(t *testing.T) {
|
|
|
|
n := 100
|
|
|
|
c := make(chan int)
|
|
|
|
l := make([]int, n)
|
|
|
|
var m sync.Mutex
|
|
|
|
m.Lock()
|
|
|
|
go func() {
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
runtime.Gosched()
|
|
|
|
l[i] = <-c
|
|
|
|
}
|
|
|
|
m.Unlock()
|
|
|
|
}()
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
select {
|
|
|
|
case c <- 0:
|
|
|
|
case c <- 1:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m.Lock() // wait
|
|
|
|
n0 := 0
|
|
|
|
n1 := 0
|
|
|
|
for _, i := range l {
|
|
|
|
n0 += (i + 1) % 2
|
|
|
|
n1 += i
|
|
|
|
if n0 > n/10 && n1 > n/10 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t.Errorf("Want pseudo random, got %d zeros and %d ones", n0, n1)
|
|
|
|
}
|
|
|
|
|
2011-09-05 05:40:50 -06:00
|
|
|
func TestMultiConsumer(t *testing.T) {
|
|
|
|
const nwork = 23
|
|
|
|
const niter = 271828
|
|
|
|
|
|
|
|
pn := []int{2, 3, 7, 11, 13, 17, 19, 23, 27, 31}
|
|
|
|
|
|
|
|
q := make(chan int, nwork*3)
|
|
|
|
r := make(chan int, nwork*3)
|
|
|
|
|
|
|
|
// workers
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
for i := 0; i < nwork; i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
go func(w int) {
|
|
|
|
for v := range q {
|
|
|
|
// mess with the fifo-ish nature of range
|
|
|
|
if pn[w%len(pn)] == v {
|
|
|
|
runtime.Gosched()
|
|
|
|
}
|
|
|
|
r <- v
|
|
|
|
}
|
|
|
|
wg.Done()
|
|
|
|
}(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
// feeder & closer
|
|
|
|
expect := 0
|
|
|
|
go func() {
|
|
|
|
for i := 0; i < niter; i++ {
|
|
|
|
v := pn[i%len(pn)]
|
|
|
|
expect += v
|
|
|
|
q <- v
|
|
|
|
}
|
|
|
|
close(q) // no more work
|
|
|
|
wg.Wait() // workers done
|
|
|
|
close(r) // ... so there can be no more results
|
|
|
|
}()
|
|
|
|
|
|
|
|
// consume & check
|
|
|
|
n := 0
|
|
|
|
s := 0
|
|
|
|
for v := range r {
|
|
|
|
n++
|
|
|
|
s += v
|
|
|
|
}
|
|
|
|
if n != niter || s != expect {
|
|
|
|
t.Errorf("Expected sum %d (got %d) from %d iter (saw %d)",
|
|
|
|
expect, s, niter, n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-20 09:51:25 -06:00
|
|
|
func BenchmarkSelectUncontended(b *testing.B) {
|
|
|
|
const CallsPerSched = 1000
|
|
|
|
procs := runtime.GOMAXPROCS(-1)
|
|
|
|
N := int32(b.N / CallsPerSched)
|
|
|
|
c := make(chan bool, procs)
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
go func() {
|
|
|
|
myc1 := make(chan int, 1)
|
|
|
|
myc2 := make(chan int, 1)
|
|
|
|
myc1 <- 0
|
|
|
|
for atomic.AddInt32(&N, -1) >= 0 {
|
|
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
|
|
select {
|
|
|
|
case <-myc1:
|
|
|
|
myc2 <- 0
|
|
|
|
case <-myc2:
|
|
|
|
myc1 <- 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c <- true
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
<-c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSelectContended(b *testing.B) {
|
|
|
|
const CallsPerSched = 1000
|
|
|
|
procs := runtime.GOMAXPROCS(-1)
|
|
|
|
N := int32(b.N / CallsPerSched)
|
|
|
|
c := make(chan bool, procs)
|
|
|
|
myc1 := make(chan int, procs)
|
|
|
|
myc2 := make(chan int, procs)
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
myc1 <- 0
|
|
|
|
go func() {
|
|
|
|
for atomic.AddInt32(&N, -1) >= 0 {
|
|
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
|
|
select {
|
|
|
|
case <-myc1:
|
|
|
|
myc2 <- 0
|
|
|
|
case <-myc2:
|
|
|
|
myc1 <- 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c <- true
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
<-c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSelectNonblock(b *testing.B) {
|
|
|
|
const CallsPerSched = 1000
|
|
|
|
procs := runtime.GOMAXPROCS(-1)
|
|
|
|
N := int32(b.N / CallsPerSched)
|
|
|
|
c := make(chan bool, procs)
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
go func() {
|
|
|
|
myc1 := make(chan int)
|
|
|
|
myc2 := make(chan int)
|
|
|
|
myc3 := make(chan int, 1)
|
|
|
|
myc4 := make(chan int, 1)
|
|
|
|
for atomic.AddInt32(&N, -1) >= 0 {
|
|
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
|
|
select {
|
|
|
|
case <-myc1:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
select {
|
|
|
|
case myc2 <- 0:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
select {
|
|
|
|
case <-myc3:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
select {
|
|
|
|
case myc4 <- 0:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c <- true
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
<-c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkChanUncontended(b *testing.B) {
|
|
|
|
const CallsPerSched = 1000
|
|
|
|
procs := runtime.GOMAXPROCS(-1)
|
|
|
|
N := int32(b.N / CallsPerSched)
|
|
|
|
c := make(chan bool, procs)
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
go func() {
|
|
|
|
myc := make(chan int, CallsPerSched)
|
|
|
|
for atomic.AddInt32(&N, -1) >= 0 {
|
|
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
|
|
myc <- 0
|
|
|
|
}
|
|
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
|
|
<-myc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c <- true
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
<-c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkChanContended(b *testing.B) {
|
|
|
|
const CallsPerSched = 1000
|
|
|
|
procs := runtime.GOMAXPROCS(-1)
|
|
|
|
N := int32(b.N / CallsPerSched)
|
|
|
|
c := make(chan bool, procs)
|
|
|
|
myc := make(chan int, procs*CallsPerSched)
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
go func() {
|
|
|
|
for atomic.AddInt32(&N, -1) >= 0 {
|
|
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
|
|
myc <- 0
|
|
|
|
}
|
|
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
|
|
<-myc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c <- true
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
<-c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkChanSync(b *testing.B) {
|
|
|
|
const CallsPerSched = 1000
|
|
|
|
procs := 2
|
|
|
|
N := int32(b.N / CallsPerSched / procs * procs)
|
|
|
|
c := make(chan bool, procs)
|
|
|
|
myc := make(chan int)
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
i := atomic.AddInt32(&N, -1)
|
|
|
|
if i < 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
|
|
if i%2 == 0 {
|
|
|
|
<-myc
|
|
|
|
myc <- 0
|
|
|
|
} else {
|
|
|
|
myc <- 0
|
|
|
|
<-myc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c <- true
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
<-c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) {
|
|
|
|
const CallsPerSched = 1000
|
|
|
|
procs := runtime.GOMAXPROCS(-1)
|
|
|
|
N := int32(b.N / CallsPerSched)
|
|
|
|
c := make(chan bool, 2*procs)
|
|
|
|
myc := make(chan int, chanSize)
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
go func() {
|
|
|
|
foo := 0
|
|
|
|
for atomic.AddInt32(&N, -1) >= 0 {
|
|
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
|
|
for i := 0; i < localWork; i++ {
|
|
|
|
foo *= 2
|
|
|
|
foo /= 2
|
|
|
|
}
|
|
|
|
myc <- 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
myc <- 0
|
|
|
|
c <- foo == 42
|
|
|
|
}()
|
|
|
|
go func() {
|
|
|
|
foo := 0
|
|
|
|
for {
|
|
|
|
v := <-myc
|
|
|
|
if v == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
for i := 0; i < localWork; i++ {
|
|
|
|
foo *= 2
|
|
|
|
foo /= 2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c <- foo == 42
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
<-c
|
|
|
|
<-c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkChanProdCons0(b *testing.B) {
|
|
|
|
benchmarkChanProdCons(b, 0, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkChanProdCons10(b *testing.B) {
|
|
|
|
benchmarkChanProdCons(b, 10, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkChanProdCons100(b *testing.B) {
|
|
|
|
benchmarkChanProdCons(b, 100, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkChanProdConsWork0(b *testing.B) {
|
|
|
|
benchmarkChanProdCons(b, 0, 100)
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkChanProdConsWork10(b *testing.B) {
|
|
|
|
benchmarkChanProdCons(b, 10, 100)
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkChanProdConsWork100(b *testing.B) {
|
|
|
|
benchmarkChanProdCons(b, 100, 100)
|
|
|
|
}
|
2011-08-04 06:31:03 -06:00
|
|
|
|
|
|
|
func BenchmarkChanCreation(b *testing.B) {
|
|
|
|
const CallsPerSched = 1000
|
|
|
|
procs := runtime.GOMAXPROCS(-1)
|
|
|
|
N := int32(b.N / CallsPerSched)
|
|
|
|
c := make(chan bool, procs)
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
go func() {
|
|
|
|
for atomic.AddInt32(&N, -1) >= 0 {
|
|
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
|
|
myc := make(chan int, 1)
|
|
|
|
myc <- 0
|
|
|
|
<-myc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c <- true
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for p := 0; p < procs; p++ {
|
|
|
|
<-c
|
|
|
|
}
|
|
|
|
}
|
2012-01-19 23:32:55 -07:00
|
|
|
|
|
|
|
func BenchmarkChanSem(b *testing.B) {
|
|
|
|
type Empty struct{}
|
|
|
|
c := make(chan Empty, 1)
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
c <- Empty{}
|
|
|
|
<-c
|
|
|
|
}
|
|
|
|
}
|