Home | History | Annotate | Download | only in runtime
      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.
      4 
      5 package runtime_test
      6 
      7 import (
      8 	"runtime"
      9 	"sync"
     10 	"sync/atomic"
     11 	"testing"
     12 	"time"
     13 )
     14 
     15 func TestChan(t *testing.T) {
     16 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
     17 	N := 200
     18 	if testing.Short() {
     19 		N = 20
     20 	}
     21 	for chanCap := 0; chanCap < N; chanCap++ {
     22 		{
     23 			// Ensure that receive from empty chan blocks.
     24 			c := make(chan int, chanCap)
     25 			recv1 := false
     26 			go func() {
     27 				_ = <-c
     28 				recv1 = true
     29 			}()
     30 			recv2 := false
     31 			go func() {
     32 				_, _ = <-c
     33 				recv2 = true
     34 			}()
     35 			time.Sleep(time.Millisecond)
     36 			if recv1 || recv2 {
     37 				t.Fatalf("chan[%d]: receive from empty chan", chanCap)
     38 			}
     39 			// Ensure that non-blocking receive does not block.
     40 			select {
     41 			case _ = <-c:
     42 				t.Fatalf("chan[%d]: receive from empty chan", chanCap)
     43 			default:
     44 			}
     45 			select {
     46 			case _, _ = <-c:
     47 				t.Fatalf("chan[%d]: receive from empty chan", chanCap)
     48 			default:
     49 			}
     50 			c <- 0
     51 			c <- 0
     52 		}
     53 
     54 		{
     55 			// Ensure that send to full chan blocks.
     56 			c := make(chan int, chanCap)
     57 			for i := 0; i < chanCap; i++ {
     58 				c <- i
     59 			}
     60 			sent := uint32(0)
     61 			go func() {
     62 				c <- 0
     63 				atomic.StoreUint32(&sent, 1)
     64 			}()
     65 			time.Sleep(time.Millisecond)
     66 			if atomic.LoadUint32(&sent) != 0 {
     67 				t.Fatalf("chan[%d]: send to full chan", chanCap)
     68 			}
     69 			// Ensure that non-blocking send does not block.
     70 			select {
     71 			case c <- 0:
     72 				t.Fatalf("chan[%d]: send to full chan", chanCap)
     73 			default:
     74 			}
     75 			<-c
     76 		}
     77 
     78 		{
     79 			// Ensure that we receive 0 from closed chan.
     80 			c := make(chan int, chanCap)
     81 			for i := 0; i < chanCap; i++ {
     82 				c <- i
     83 			}
     84 			close(c)
     85 			for i := 0; i < chanCap; i++ {
     86 				v := <-c
     87 				if v != i {
     88 					t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
     89 				}
     90 			}
     91 			if v := <-c; v != 0 {
     92 				t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, 0)
     93 			}
     94 			if v, ok := <-c; v != 0 || ok {
     95 				t.Fatalf("chan[%d]: received %v/%v, expected %v/%v", chanCap, v, ok, 0, false)
     96 			}
     97 		}
     98 
     99 		{
    100 			// Ensure that close unblocks receive.
    101 			c := make(chan int, chanCap)
    102 			done := make(chan bool)
    103 			go func() {
    104 				v, ok := <-c
    105 				done <- v == 0 && ok == false
    106 			}()
    107 			time.Sleep(time.Millisecond)
    108 			close(c)
    109 			if !<-done {
    110 				t.Fatalf("chan[%d]: received non zero from closed chan", chanCap)
    111 			}
    112 		}
    113 
    114 		{
    115 			// Send 100 integers,
    116 			// ensure that we receive them non-corrupted in FIFO order.
    117 			c := make(chan int, chanCap)
    118 			go func() {
    119 				for i := 0; i < 100; i++ {
    120 					c <- i
    121 				}
    122 			}()
    123 			for i := 0; i < 100; i++ {
    124 				v := <-c
    125 				if v != i {
    126 					t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
    127 				}
    128 			}
    129 
    130 			// Same, but using recv2.
    131 			go func() {
    132 				for i := 0; i < 100; i++ {
    133 					c <- i
    134 				}
    135 			}()
    136 			for i := 0; i < 100; i++ {
    137 				v, ok := <-c
    138 				if !ok {
    139 					t.Fatalf("chan[%d]: receive failed, expected %v", chanCap, i)
    140 				}
    141 				if v != i {
    142 					t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
    143 				}
    144 			}
    145 
    146 			// Send 1000 integers in 4 goroutines,
    147 			// ensure that we receive what we send.
    148 			const P = 4
    149 			const L = 1000
    150 			for p := 0; p < P; p++ {
    151 				go func() {
    152 					for i := 0; i < L; i++ {
    153 						c <- i
    154 					}
    155 				}()
    156 			}
    157 			done := make(chan map[int]int)
    158 			for p := 0; p < P; p++ {
    159 				go func() {
    160 					recv := make(map[int]int)
    161 					for i := 0; i < L; i++ {
    162 						v := <-c
    163 						recv[v] = recv[v] + 1
    164 					}
    165 					done <- recv
    166 				}()
    167 			}
    168 			recv := make(map[int]int)
    169 			for p := 0; p < P; p++ {
    170 				for k, v := range <-done {
    171 					recv[k] = recv[k] + v
    172 				}
    173 			}
    174 			if len(recv) != L {
    175 				t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, len(recv), L)
    176 			}
    177 			for _, v := range recv {
    178 				if v != P {
    179 					t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, v, P)
    180 				}
    181 			}
    182 		}
    183 
    184 		{
    185 			// Test len/cap.
    186 			c := make(chan int, chanCap)
    187 			if len(c) != 0 || cap(c) != chanCap {
    188 				t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, 0, chanCap, len(c), cap(c))
    189 			}
    190 			for i := 0; i < chanCap; i++ {
    191 				c <- i
    192 			}
    193 			if len(c) != chanCap || cap(c) != chanCap {
    194 				t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, chanCap, chanCap, len(c), cap(c))
    195 			}
    196 		}
    197 
    198 	}
    199 }
    200 
    201 func TestNonblockRecvRace(t *testing.T) {
    202 	n := 10000
    203 	if testing.Short() {
    204 		n = 100
    205 	}
    206 	for i := 0; i < n; i++ {
    207 		c := make(chan int, 1)
    208 		c <- 1
    209 		go func() {
    210 			select {
    211 			case <-c:
    212 			default:
    213 				t.Fatal("chan is not ready")
    214 			}
    215 		}()
    216 		close(c)
    217 		<-c
    218 	}
    219 }
    220 
    221 // This test checks that select acts on the state of the channels at one
    222 // moment in the execution, not over a smeared time window.
    223 // In the test, one goroutine does:
    224 //	create c1, c2
    225 //	make c1 ready for receiving
    226 //	create second goroutine
    227 //	make c2 ready for receiving
    228 //	make c1 no longer ready for receiving (if possible)
    229 // The second goroutine does a non-blocking select receiving from c1 and c2.
    230 // From the time the second goroutine is created, at least one of c1 and c2
    231 // is always ready for receiving, so the select in the second goroutine must
    232 // always receive from one or the other. It must never execute the default case.
    233 func TestNonblockSelectRace(t *testing.T) {
    234 	n := 100000
    235 	if testing.Short() {
    236 		n = 1000
    237 	}
    238 	done := make(chan bool, 1)
    239 	for i := 0; i < n; i++ {
    240 		c1 := make(chan int, 1)
    241 		c2 := make(chan int, 1)
    242 		c1 <- 1
    243 		go func() {
    244 			select {
    245 			case <-c1:
    246 			case <-c2:
    247 			default:
    248 				done <- false
    249 				return
    250 			}
    251 			done <- true
    252 		}()
    253 		c2 <- 1
    254 		select {
    255 		case <-c1:
    256 		default:
    257 		}
    258 		if !<-done {
    259 			t.Fatal("no chan is ready")
    260 		}
    261 	}
    262 }
    263 
    264 // Same as TestNonblockSelectRace, but close(c2) replaces c2 <- 1.
    265 func TestNonblockSelectRace2(t *testing.T) {
    266 	n := 100000
    267 	if testing.Short() {
    268 		n = 1000
    269 	}
    270 	done := make(chan bool, 1)
    271 	for i := 0; i < n; i++ {
    272 		c1 := make(chan int, 1)
    273 		c2 := make(chan int)
    274 		c1 <- 1
    275 		go func() {
    276 			select {
    277 			case <-c1:
    278 			case <-c2:
    279 			default:
    280 				done <- false
    281 				return
    282 			}
    283 			done <- true
    284 		}()
    285 		close(c2)
    286 		select {
    287 		case <-c1:
    288 		default:
    289 		}
    290 		if !<-done {
    291 			t.Fatal("no chan is ready")
    292 		}
    293 	}
    294 }
    295 
    296 func TestSelfSelect(t *testing.T) {
    297 	// Ensure that send/recv on the same chan in select
    298 	// does not crash nor deadlock.
    299 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
    300 	for _, chanCap := range []int{0, 10} {
    301 		var wg sync.WaitGroup
    302 		wg.Add(2)
    303 		c := make(chan int, chanCap)
    304 		for p := 0; p < 2; p++ {
    305 			p := p
    306 			go func() {
    307 				defer wg.Done()
    308 				for i := 0; i < 1000; i++ {
    309 					if p == 0 || i%2 == 0 {
    310 						select {
    311 						case c <- p:
    312 						case v := <-c:
    313 							if chanCap == 0 && v == p {
    314 								t.Fatalf("self receive")
    315 							}
    316 						}
    317 					} else {
    318 						select {
    319 						case v := <-c:
    320 							if chanCap == 0 && v == p {
    321 								t.Fatalf("self receive")
    322 							}
    323 						case c <- p:
    324 						}
    325 					}
    326 				}
    327 			}()
    328 		}
    329 		wg.Wait()
    330 	}
    331 }
    332 
    333 func TestSelectStress(t *testing.T) {
    334 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(10))
    335 	var c [4]chan int
    336 	c[0] = make(chan int)
    337 	c[1] = make(chan int)
    338 	c[2] = make(chan int, 2)
    339 	c[3] = make(chan int, 3)
    340 	N := int(1e5)
    341 	if testing.Short() {
    342 		N /= 10
    343 	}
    344 	// There are 4 goroutines that send N values on each of the chans,
    345 	// + 4 goroutines that receive N values on each of the chans,
    346 	// + 1 goroutine that sends N values on each of the chans in a single select,
    347 	// + 1 goroutine that receives N values on each of the chans in a single select.
    348 	// All these sends, receives and selects interact chaotically at runtime,
    349 	// but we are careful that this whole construct does not deadlock.
    350 	var wg sync.WaitGroup
    351 	wg.Add(10)
    352 	for k := 0; k < 4; k++ {
    353 		k := k
    354 		go func() {
    355 			for i := 0; i < N; i++ {
    356 				c[k] <- 0
    357 			}
    358 			wg.Done()
    359 		}()
    360 		go func() {
    361 			for i := 0; i < N; i++ {
    362 				<-c[k]
    363 			}
    364 			wg.Done()
    365 		}()
    366 	}
    367 	go func() {
    368 		var n [4]int
    369 		c1 := c
    370 		for i := 0; i < 4*N; i++ {
    371 			select {
    372 			case c1[3] <- 0:
    373 				n[3]++
    374 				if n[3] == N {
    375 					c1[3] = nil
    376 				}
    377 			case c1[2] <- 0:
    378 				n[2]++
    379 				if n[2] == N {
    380 					c1[2] = nil
    381 				}
    382 			case c1[0] <- 0:
    383 				n[0]++
    384 				if n[0] == N {
    385 					c1[0] = nil
    386 				}
    387 			case c1[1] <- 0:
    388 				n[1]++
    389 				if n[1] == N {
    390 					c1[1] = nil
    391 				}
    392 			}
    393 		}
    394 		wg.Done()
    395 	}()
    396 	go func() {
    397 		var n [4]int
    398 		c1 := c
    399 		for i := 0; i < 4*N; i++ {
    400 			select {
    401 			case <-c1[0]:
    402 				n[0]++
    403 				if n[0] == N {
    404 					c1[0] = nil
    405 				}
    406 			case <-c1[1]:
    407 				n[1]++
    408 				if n[1] == N {
    409 					c1[1] = nil
    410 				}
    411 			case <-c1[2]:
    412 				n[2]++
    413 				if n[2] == N {
    414 					c1[2] = nil
    415 				}
    416 			case <-c1[3]:
    417 				n[3]++
    418 				if n[3] == N {
    419 					c1[3] = nil
    420 				}
    421 			}
    422 		}
    423 		wg.Done()
    424 	}()
    425 	wg.Wait()
    426 }
    427 
    428 func TestChanSendInterface(t *testing.T) {
    429 	type mt struct{}
    430 	m := &mt{}
    431 	c := make(chan interface{}, 1)
    432 	c <- m
    433 	select {
    434 	case c <- m:
    435 	default:
    436 	}
    437 	select {
    438 	case c <- m:
    439 	case c <- &mt{}:
    440 	default:
    441 	}
    442 }
    443 
    444 func TestPseudoRandomSend(t *testing.T) {
    445 	n := 100
    446 	for _, chanCap := range []int{0, n} {
    447 		c := make(chan int, chanCap)
    448 		l := make([]int, n)
    449 		var m sync.Mutex
    450 		m.Lock()
    451 		go func() {
    452 			for i := 0; i < n; i++ {
    453 				runtime.Gosched()
    454 				l[i] = <-c
    455 			}
    456 			m.Unlock()
    457 		}()
    458 		for i := 0; i < n; i++ {
    459 			select {
    460 			case c <- 1:
    461 			case c <- 0:
    462 			}
    463 		}
    464 		m.Lock() // wait
    465 		n0 := 0
    466 		n1 := 0
    467 		for _, i := range l {
    468 			n0 += (i + 1) % 2
    469 			n1 += i
    470 		}
    471 		if n0 <= n/10 || n1 <= n/10 {
    472 			t.Errorf("Want pseudorandom, got %d zeros and %d ones (chan cap %d)", n0, n1, chanCap)
    473 		}
    474 	}
    475 }
    476 
    477 func TestMultiConsumer(t *testing.T) {
    478 	const nwork = 23
    479 	const niter = 271828
    480 
    481 	pn := []int{2, 3, 7, 11, 13, 17, 19, 23, 27, 31}
    482 
    483 	q := make(chan int, nwork*3)
    484 	r := make(chan int, nwork*3)
    485 
    486 	// workers
    487 	var wg sync.WaitGroup
    488 	for i := 0; i < nwork; i++ {
    489 		wg.Add(1)
    490 		go func(w int) {
    491 			for v := range q {
    492 				// mess with the fifo-ish nature of range
    493 				if pn[w%len(pn)] == v {
    494 					runtime.Gosched()
    495 				}
    496 				r <- v
    497 			}
    498 			wg.Done()
    499 		}(i)
    500 	}
    501 
    502 	// feeder & closer
    503 	expect := 0
    504 	go func() {
    505 		for i := 0; i < niter; i++ {
    506 			v := pn[i%len(pn)]
    507 			expect += v
    508 			q <- v
    509 		}
    510 		close(q)  // no more work
    511 		wg.Wait() // workers done
    512 		close(r)  // ... so there can be no more results
    513 	}()
    514 
    515 	// consume & check
    516 	n := 0
    517 	s := 0
    518 	for v := range r {
    519 		n++
    520 		s += v
    521 	}
    522 	if n != niter || s != expect {
    523 		t.Errorf("Expected sum %d (got %d) from %d iter (saw %d)",
    524 			expect, s, niter, n)
    525 	}
    526 }
    527 
    528 func TestShrinkStackDuringBlockedSend(t *testing.T) {
    529 	// make sure that channel operations still work when we are
    530 	// blocked on a channel send and we shrink the stack.
    531 	// NOTE: this test probably won't fail unless stack1.go:stackDebug
    532 	// is set to >= 1.
    533 	const n = 10
    534 	c := make(chan int)
    535 	done := make(chan struct{})
    536 
    537 	go func() {
    538 		for i := 0; i < n; i++ {
    539 			c <- i
    540 			// use lots of stack, briefly.
    541 			stackGrowthRecursive(20)
    542 		}
    543 		done <- struct{}{}
    544 	}()
    545 
    546 	for i := 0; i < n; i++ {
    547 		x := <-c
    548 		if x != i {
    549 			t.Errorf("bad channel read: want %d, got %d", i, x)
    550 		}
    551 		// Waste some time so sender can finish using lots of stack
    552 		// and block in channel send.
    553 		time.Sleep(1 * time.Millisecond)
    554 		// trigger GC which will shrink the stack of the sender.
    555 		runtime.GC()
    556 	}
    557 	<-done
    558 }
    559 
    560 func TestSelectDuplicateChannel(t *testing.T) {
    561 	// This test makes sure we can queue a G on
    562 	// the same channel multiple times.
    563 	c := make(chan int)
    564 	d := make(chan int)
    565 	e := make(chan int)
    566 
    567 	// goroutine A
    568 	go func() {
    569 		select {
    570 		case <-c:
    571 		case <-c:
    572 		case <-d:
    573 		}
    574 		e <- 9
    575 	}()
    576 	time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c
    577 
    578 	// goroutine B
    579 	go func() {
    580 		<-c
    581 	}()
    582 	time.Sleep(time.Millisecond) // make sure goroutine B gets queued on c before continuing
    583 
    584 	d <- 7 // wake up A, it dequeues itself from c.  This operation used to corrupt c.recvq.
    585 	<-e    // A tells us it's done
    586 	c <- 8 // wake up B.  This operation used to fail because c.recvq was corrupted (it tries to wake up an already running G instead of B)
    587 }
    588 
    589 func BenchmarkChanNonblocking(b *testing.B) {
    590 	myc := make(chan int)
    591 	b.RunParallel(func(pb *testing.PB) {
    592 		for pb.Next() {
    593 			select {
    594 			case <-myc:
    595 			default:
    596 			}
    597 		}
    598 	})
    599 }
    600 
    601 func BenchmarkSelectUncontended(b *testing.B) {
    602 	b.RunParallel(func(pb *testing.PB) {
    603 		myc1 := make(chan int, 1)
    604 		myc2 := make(chan int, 1)
    605 		myc1 <- 0
    606 		for pb.Next() {
    607 			select {
    608 			case <-myc1:
    609 				myc2 <- 0
    610 			case <-myc2:
    611 				myc1 <- 0
    612 			}
    613 		}
    614 	})
    615 }
    616 
    617 func BenchmarkSelectSyncContended(b *testing.B) {
    618 	myc1 := make(chan int)
    619 	myc2 := make(chan int)
    620 	myc3 := make(chan int)
    621 	done := make(chan int)
    622 	b.RunParallel(func(pb *testing.PB) {
    623 		go func() {
    624 			for {
    625 				select {
    626 				case myc1 <- 0:
    627 				case myc2 <- 0:
    628 				case myc3 <- 0:
    629 				case <-done:
    630 					return
    631 				}
    632 			}
    633 		}()
    634 		for pb.Next() {
    635 			select {
    636 			case <-myc1:
    637 			case <-myc2:
    638 			case <-myc3:
    639 			}
    640 		}
    641 	})
    642 	close(done)
    643 }
    644 
    645 func BenchmarkSelectAsyncContended(b *testing.B) {
    646 	procs := runtime.GOMAXPROCS(0)
    647 	myc1 := make(chan int, procs)
    648 	myc2 := make(chan int, procs)
    649 	b.RunParallel(func(pb *testing.PB) {
    650 		myc1 <- 0
    651 		for pb.Next() {
    652 			select {
    653 			case <-myc1:
    654 				myc2 <- 0
    655 			case <-myc2:
    656 				myc1 <- 0
    657 			}
    658 		}
    659 	})
    660 }
    661 
    662 func BenchmarkSelectNonblock(b *testing.B) {
    663 	myc1 := make(chan int)
    664 	myc2 := make(chan int)
    665 	myc3 := make(chan int, 1)
    666 	myc4 := make(chan int, 1)
    667 	b.RunParallel(func(pb *testing.PB) {
    668 		for pb.Next() {
    669 			select {
    670 			case <-myc1:
    671 			default:
    672 			}
    673 			select {
    674 			case myc2 <- 0:
    675 			default:
    676 			}
    677 			select {
    678 			case <-myc3:
    679 			default:
    680 			}
    681 			select {
    682 			case myc4 <- 0:
    683 			default:
    684 			}
    685 		}
    686 	})
    687 }
    688 
    689 func BenchmarkChanUncontended(b *testing.B) {
    690 	const C = 100
    691 	b.RunParallel(func(pb *testing.PB) {
    692 		myc := make(chan int, C)
    693 		for pb.Next() {
    694 			for i := 0; i < C; i++ {
    695 				myc <- 0
    696 			}
    697 			for i := 0; i < C; i++ {
    698 				<-myc
    699 			}
    700 		}
    701 	})
    702 }
    703 
    704 func BenchmarkChanContended(b *testing.B) {
    705 	const C = 100
    706 	myc := make(chan int, C*runtime.GOMAXPROCS(0))
    707 	b.RunParallel(func(pb *testing.PB) {
    708 		for pb.Next() {
    709 			for i := 0; i < C; i++ {
    710 				myc <- 0
    711 			}
    712 			for i := 0; i < C; i++ {
    713 				<-myc
    714 			}
    715 		}
    716 	})
    717 }
    718 
    719 func BenchmarkChanSync(b *testing.B) {
    720 	const CallsPerSched = 1000
    721 	procs := 2
    722 	N := int32(b.N / CallsPerSched / procs * procs)
    723 	c := make(chan bool, procs)
    724 	myc := make(chan int)
    725 	for p := 0; p < procs; p++ {
    726 		go func() {
    727 			for {
    728 				i := atomic.AddInt32(&N, -1)
    729 				if i < 0 {
    730 					break
    731 				}
    732 				for g := 0; g < CallsPerSched; g++ {
    733 					if i%2 == 0 {
    734 						<-myc
    735 						myc <- 0
    736 					} else {
    737 						myc <- 0
    738 						<-myc
    739 					}
    740 				}
    741 			}
    742 			c <- true
    743 		}()
    744 	}
    745 	for p := 0; p < procs; p++ {
    746 		<-c
    747 	}
    748 }
    749 
    750 func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) {
    751 	const CallsPerSched = 1000
    752 	procs := runtime.GOMAXPROCS(-1)
    753 	N := int32(b.N / CallsPerSched)
    754 	c := make(chan bool, 2*procs)
    755 	myc := make(chan int, chanSize)
    756 	for p := 0; p < procs; p++ {
    757 		go func() {
    758 			foo := 0
    759 			for atomic.AddInt32(&N, -1) >= 0 {
    760 				for g := 0; g < CallsPerSched; g++ {
    761 					for i := 0; i < localWork; i++ {
    762 						foo *= 2
    763 						foo /= 2
    764 					}
    765 					myc <- 1
    766 				}
    767 			}
    768 			myc <- 0
    769 			c <- foo == 42
    770 		}()
    771 		go func() {
    772 			foo := 0
    773 			for {
    774 				v := <-myc
    775 				if v == 0 {
    776 					break
    777 				}
    778 				for i := 0; i < localWork; i++ {
    779 					foo *= 2
    780 					foo /= 2
    781 				}
    782 			}
    783 			c <- foo == 42
    784 		}()
    785 	}
    786 	for p := 0; p < procs; p++ {
    787 		<-c
    788 		<-c
    789 	}
    790 }
    791 
    792 func BenchmarkChanProdCons0(b *testing.B) {
    793 	benchmarkChanProdCons(b, 0, 0)
    794 }
    795 
    796 func BenchmarkChanProdCons10(b *testing.B) {
    797 	benchmarkChanProdCons(b, 10, 0)
    798 }
    799 
    800 func BenchmarkChanProdCons100(b *testing.B) {
    801 	benchmarkChanProdCons(b, 100, 0)
    802 }
    803 
    804 func BenchmarkChanProdConsWork0(b *testing.B) {
    805 	benchmarkChanProdCons(b, 0, 100)
    806 }
    807 
    808 func BenchmarkChanProdConsWork10(b *testing.B) {
    809 	benchmarkChanProdCons(b, 10, 100)
    810 }
    811 
    812 func BenchmarkChanProdConsWork100(b *testing.B) {
    813 	benchmarkChanProdCons(b, 100, 100)
    814 }
    815 
    816 func BenchmarkSelectProdCons(b *testing.B) {
    817 	const CallsPerSched = 1000
    818 	procs := runtime.GOMAXPROCS(-1)
    819 	N := int32(b.N / CallsPerSched)
    820 	c := make(chan bool, 2*procs)
    821 	myc := make(chan int, 128)
    822 	myclose := make(chan bool)
    823 	for p := 0; p < procs; p++ {
    824 		go func() {
    825 			// Producer: sends to myc.
    826 			foo := 0
    827 			// Intended to not fire during benchmarking.
    828 			mytimer := time.After(time.Hour)
    829 			for atomic.AddInt32(&N, -1) >= 0 {
    830 				for g := 0; g < CallsPerSched; g++ {
    831 					// Model some local work.
    832 					for i := 0; i < 100; i++ {
    833 						foo *= 2
    834 						foo /= 2
    835 					}
    836 					select {
    837 					case myc <- 1:
    838 					case <-mytimer:
    839 					case <-myclose:
    840 					}
    841 				}
    842 			}
    843 			myc <- 0
    844 			c <- foo == 42
    845 		}()
    846 		go func() {
    847 			// Consumer: receives from myc.
    848 			foo := 0
    849 			// Intended to not fire during benchmarking.
    850 			mytimer := time.After(time.Hour)
    851 		loop:
    852 			for {
    853 				select {
    854 				case v := <-myc:
    855 					if v == 0 {
    856 						break loop
    857 					}
    858 				case <-mytimer:
    859 				case <-myclose:
    860 				}
    861 				// Model some local work.
    862 				for i := 0; i < 100; i++ {
    863 					foo *= 2
    864 					foo /= 2
    865 				}
    866 			}
    867 			c <- foo == 42
    868 		}()
    869 	}
    870 	for p := 0; p < procs; p++ {
    871 		<-c
    872 		<-c
    873 	}
    874 }
    875 
    876 func BenchmarkChanCreation(b *testing.B) {
    877 	b.RunParallel(func(pb *testing.PB) {
    878 		for pb.Next() {
    879 			myc := make(chan int, 1)
    880 			myc <- 0
    881 			<-myc
    882 		}
    883 	})
    884 }
    885 
    886 func BenchmarkChanSem(b *testing.B) {
    887 	type Empty struct{}
    888 	myc := make(chan Empty, runtime.GOMAXPROCS(0))
    889 	b.RunParallel(func(pb *testing.PB) {
    890 		for pb.Next() {
    891 			myc <- Empty{}
    892 			<-myc
    893 		}
    894 	})
    895 }
    896 
    897 func BenchmarkChanPopular(b *testing.B) {
    898 	const n = 1000
    899 	c := make(chan bool)
    900 	var a []chan bool
    901 	var wg sync.WaitGroup
    902 	wg.Add(n)
    903 	for j := 0; j < n; j++ {
    904 		d := make(chan bool)
    905 		a = append(a, d)
    906 		go func() {
    907 			for i := 0; i < b.N; i++ {
    908 				select {
    909 				case <-c:
    910 				case <-d:
    911 				}
    912 			}
    913 			wg.Done()
    914 		}()
    915 	}
    916 	for i := 0; i < b.N; i++ {
    917 		for _, d := range a {
    918 			d <- true
    919 		}
    920 	}
    921 	wg.Wait()
    922 }
    923