diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/pkg/runtime/chan_test.go | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/pkg/runtime/chan_test.go')
-rw-r--r-- | src/pkg/runtime/chan_test.go | 711 |
1 files changed, 0 insertions, 711 deletions
diff --git a/src/pkg/runtime/chan_test.go b/src/pkg/runtime/chan_test.go deleted file mode 100644 index ce4b39627..000000000 --- a/src/pkg/runtime/chan_test.go +++ /dev/null @@ -1,711 +0,0 @@ -// 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" - "time" -) - -func TestChan(t *testing.T) { - defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) - N := 200 - if testing.Short() { - N = 20 - } - for chanCap := 0; chanCap < N; chanCap++ { - { - // Ensure that receive from empty chan blocks. - c := make(chan int, chanCap) - recv1 := false - go func() { - _ = <-c - recv1 = true - }() - recv2 := false - go func() { - _, _ = <-c - recv2 = true - }() - time.Sleep(time.Millisecond) - if recv1 || recv2 { - t.Fatalf("chan[%d]: receive from empty chan", chanCap) - } - // Ensure that non-blocking receive does not block. - select { - case _ = <-c: - t.Fatalf("chan[%d]: receive from empty chan", chanCap) - default: - } - select { - case _, _ = <-c: - t.Fatalf("chan[%d]: receive from empty chan", chanCap) - default: - } - c <- 0 - c <- 0 - } - - { - // Ensure that send to full chan blocks. - c := make(chan int, chanCap) - for i := 0; i < chanCap; i++ { - c <- i - } - sent := uint32(0) - go func() { - c <- 0 - atomic.StoreUint32(&sent, 1) - }() - time.Sleep(time.Millisecond) - if atomic.LoadUint32(&sent) != 0 { - t.Fatalf("chan[%d]: send to full chan", chanCap) - } - // Ensure that non-blocking send does not block. - select { - case c <- 0: - t.Fatalf("chan[%d]: send to full chan", chanCap) - default: - } - <-c - } - - { - // Ensure that we receive 0 from closed chan. - c := make(chan int, chanCap) - for i := 0; i < chanCap; i++ { - c <- i - } - close(c) - for i := 0; i < chanCap; i++ { - v := <-c - if v != i { - t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i) - } - } - if v := <-c; v != 0 { - t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, 0) - } - if v, ok := <-c; v != 0 || ok { - t.Fatalf("chan[%d]: received %v/%v, expected %v/%v", chanCap, v, ok, 0, false) - } - } - - { - // Ensure that close unblocks receive. - c := make(chan int, chanCap) - done := make(chan bool) - go func() { - v, ok := <-c - done <- v == 0 && ok == false - }() - time.Sleep(time.Millisecond) - close(c) - if !<-done { - t.Fatalf("chan[%d]: received non zero from closed chan", chanCap) - } - } - - { - // Send 100 integers, - // ensure that we receive them non-corrupted in FIFO order. - c := make(chan int, chanCap) - go func() { - for i := 0; i < 100; i++ { - c <- i - } - }() - for i := 0; i < 100; i++ { - v := <-c - if v != i { - t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i) - } - } - - // Same, but using recv2. - go func() { - for i := 0; i < 100; i++ { - c <- i - } - }() - for i := 0; i < 100; i++ { - v, ok := <-c - if !ok { - t.Fatalf("chan[%d]: receive failed, expected %v", chanCap, i) - } - if v != i { - t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i) - } - } - - // Send 1000 integers in 4 goroutines, - // ensure that we receive what we send. - const P = 4 - const L = 1000 - for p := 0; p < P; p++ { - go func() { - for i := 0; i < L; i++ { - c <- i - } - }() - } - done := make(chan map[int]int) - for p := 0; p < P; p++ { - go func() { - recv := make(map[int]int) - for i := 0; i < L; i++ { - v := <-c - recv[v] = recv[v] + 1 - } - done <- recv - }() - } - recv := make(map[int]int) - for p := 0; p < P; p++ { - for k, v := range <-done { - recv[k] = recv[k] + v - } - } - if len(recv) != L { - t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, len(recv), L) - } - for _, v := range recv { - if v != P { - t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, v, P) - } - } - } - - { - // Test len/cap. - c := make(chan int, chanCap) - if len(c) != 0 || cap(c) != chanCap { - t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, 0, chanCap, len(c), cap(c)) - } - for i := 0; i < chanCap; i++ { - c <- i - } - if len(c) != chanCap || cap(c) != chanCap { - t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, chanCap, chanCap, len(c), cap(c)) - } - } - - } -} - -func TestSelfSelect(t *testing.T) { - // Ensure that send/recv on the same chan in select - // does not crash nor deadlock. - defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) - for _, chanCap := range []int{0, 10} { - var wg sync.WaitGroup - wg.Add(2) - c := make(chan int, chanCap) - for p := 0; p < 2; p++ { - p := p - go func() { - defer wg.Done() - for i := 0; i < 1000; i++ { - if p == 0 || i%2 == 0 { - select { - case c <- p: - case v := <-c: - if chanCap == 0 && v == p { - t.Fatalf("self receive") - } - } - } else { - select { - case v := <-c: - if chanCap == 0 && v == p { - t.Fatalf("self receive") - } - case c <- p: - } - } - } - }() - } - wg.Wait() - } -} - -func TestSelectStress(t *testing.T) { - defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(10)) - var c [4]chan int - c[0] = make(chan int) - c[1] = make(chan int) - c[2] = make(chan int, 2) - c[3] = make(chan int, 3) - N := int(1e5) - if testing.Short() { - N /= 10 - } - // There are 4 goroutines that send N values on each of the chans, - // + 4 goroutines that receive N values on each of the chans, - // + 1 goroutine that sends N values on each of the chans in a single select, - // + 1 goroutine that receives N values on each of the chans in a single select. - // All these sends, receives and selects interact chaotically at runtime, - // but we are careful that this whole construct does not deadlock. - var wg sync.WaitGroup - wg.Add(10) - for k := 0; k < 4; k++ { - k := k - go func() { - for i := 0; i < N; i++ { - c[k] <- 0 - } - wg.Done() - }() - go func() { - for i := 0; i < N; i++ { - <-c[k] - } - wg.Done() - }() - } - go func() { - var n [4]int - c1 := c - for i := 0; i < 4*N; i++ { - select { - case c1[3] <- 0: - n[3]++ - if n[3] == N { - c1[3] = nil - } - case c1[2] <- 0: - n[2]++ - if n[2] == N { - c1[2] = nil - } - case c1[0] <- 0: - n[0]++ - if n[0] == N { - c1[0] = nil - } - case c1[1] <- 0: - n[1]++ - if n[1] == N { - c1[1] = nil - } - } - } - wg.Done() - }() - go func() { - var n [4]int - c1 := c - for i := 0; i < 4*N; i++ { - select { - case <-c1[0]: - n[0]++ - if n[0] == N { - c1[0] = nil - } - case <-c1[1]: - n[1]++ - if n[1] == N { - c1[1] = nil - } - case <-c1[2]: - n[2]++ - if n[2] == N { - c1[2] = nil - } - case <-c1[3]: - n[3]++ - if n[3] == N { - c1[3] = nil - } - } - } - wg.Done() - }() - wg.Wait() -} - -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 - for _, chanCap := range []int{0, n} { - c := make(chan int, chanCap) - 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 <- 1: - case c <- 0: - } - } - m.Lock() // wait - n0 := 0 - n1 := 0 - for _, i := range l { - n0 += (i + 1) % 2 - n1 += i - } - if n0 <= n/10 || n1 <= n/10 { - t.Errorf("Want pseudorandom, got %d zeros and %d ones (chan cap %d)", n0, n1, chanCap) - } - } -} - -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 BenchmarkChanNonblocking(b *testing.B) { - myc := make(chan int) - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - select { - case <-myc: - default: - } - } - }) -} - -func BenchmarkSelectUncontended(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - myc1 := make(chan int, 1) - myc2 := make(chan int, 1) - myc1 <- 0 - for pb.Next() { - select { - case <-myc1: - myc2 <- 0 - case <-myc2: - myc1 <- 0 - } - } - }) -} - -func BenchmarkSelectContended(b *testing.B) { - procs := runtime.GOMAXPROCS(0) - myc1 := make(chan int, procs) - myc2 := make(chan int, procs) - b.RunParallel(func(pb *testing.PB) { - myc1 <- 0 - for pb.Next() { - select { - case <-myc1: - myc2 <- 0 - case <-myc2: - myc1 <- 0 - } - } - }) -} - -func BenchmarkSelectNonblock(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - myc1 := make(chan int) - myc2 := make(chan int) - myc3 := make(chan int, 1) - myc4 := make(chan int, 1) - for pb.Next() { - select { - case <-myc1: - default: - } - select { - case myc2 <- 0: - default: - } - select { - case <-myc3: - default: - } - select { - case myc4 <- 0: - default: - } - } - }) -} - -func BenchmarkChanUncontended(b *testing.B) { - const C = 100 - b.RunParallel(func(pb *testing.PB) { - myc := make(chan int, C) - for pb.Next() { - for i := 0; i < C; i++ { - myc <- 0 - } - for i := 0; i < C; i++ { - <-myc - } - } - }) -} - -func BenchmarkChanContended(b *testing.B) { - const C = 100 - myc := make(chan int, C*runtime.GOMAXPROCS(0)) - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - for i := 0; i < C; i++ { - myc <- 0 - } - for i := 0; i < C; i++ { - <-myc - } - } - }) -} - -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 BenchmarkSelectProdCons(b *testing.B) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, 2*procs) - myc := make(chan int, 128) - myclose := make(chan bool) - for p := 0; p < procs; p++ { - go func() { - // Producer: sends to myc. - foo := 0 - // Intended to not fire during benchmarking. - mytimer := time.After(time.Hour) - for atomic.AddInt32(&N, -1) >= 0 { - for g := 0; g < CallsPerSched; g++ { - // Model some local work. - for i := 0; i < 100; i++ { - foo *= 2 - foo /= 2 - } - select { - case myc <- 1: - case <-mytimer: - case <-myclose: - } - } - } - myc <- 0 - c <- foo == 42 - }() - go func() { - // Consumer: receives from myc. - foo := 0 - // Intended to not fire during benchmarking. - mytimer := time.After(time.Hour) - loop: - for { - select { - case v := <-myc: - if v == 0 { - break loop - } - case <-mytimer: - case <-myclose: - } - // Model some local work. - for i := 0; i < 100; i++ { - foo *= 2 - foo /= 2 - } - } - c <- foo == 42 - }() - } - for p := 0; p < procs; p++ { - <-c - <-c - } -} - -func BenchmarkChanCreation(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - myc := make(chan int, 1) - myc <- 0 - <-myc - } - }) -} - -func BenchmarkChanSem(b *testing.B) { - type Empty struct{} - myc := make(chan Empty, runtime.GOMAXPROCS(0)) - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - myc <- Empty{} - <-myc - } - }) -} |