| // 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" |
| "sync" |
| "sync/atomic" |
| "testing" |
| ) |
| |
| 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: |
| } |
| } |
| |
| 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) |
| } |
| |
| 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) |
| } |
| } |
| |
| 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) |
| } |
| |
| 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 |
| } |
| } |
| |
| func BenchmarkChanSem(b *testing.B) { |
| type Empty struct{} |
| c := make(chan Empty, 1) |
| for i := 0; i < b.N; i++ { |
| c <- Empty{} |
| <-c |
| } |
| } |