github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/runtime/chan_test.go (about) 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 "internal/testenv" 9 "math" 10 "runtime" 11 "sync" 12 "sync/atomic" 13 "testing" 14 "time" 15 ) 16 17 func TestChan(t *testing.T) { 18 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 19 N := 200 20 if testing.Short() { 21 N = 20 22 } 23 for chanCap := 0; chanCap < N; chanCap++ { 24 { 25 // Ensure that receive from empty chan blocks. 26 c := make(chan int, chanCap) 27 recv1 := false 28 go func() { 29 _ = <-c 30 recv1 = true 31 }() 32 recv2 := false 33 go func() { 34 _, _ = <-c 35 recv2 = true 36 }() 37 time.Sleep(time.Millisecond) 38 if recv1 || recv2 { 39 t.Fatalf("chan[%d]: receive from empty chan", chanCap) 40 } 41 // Ensure that non-blocking receive does not block. 42 select { 43 case _ = <-c: 44 t.Fatalf("chan[%d]: receive from empty chan", chanCap) 45 default: 46 } 47 select { 48 case _, _ = <-c: 49 t.Fatalf("chan[%d]: receive from empty chan", chanCap) 50 default: 51 } 52 c <- 0 53 c <- 0 54 } 55 56 { 57 // Ensure that send to full chan blocks. 58 c := make(chan int, chanCap) 59 for i := 0; i < chanCap; i++ { 60 c <- i 61 } 62 sent := uint32(0) 63 go func() { 64 c <- 0 65 atomic.StoreUint32(&sent, 1) 66 }() 67 time.Sleep(time.Millisecond) 68 if atomic.LoadUint32(&sent) != 0 { 69 t.Fatalf("chan[%d]: send to full chan", chanCap) 70 } 71 // Ensure that non-blocking send does not block. 72 select { 73 case c <- 0: 74 t.Fatalf("chan[%d]: send to full chan", chanCap) 75 default: 76 } 77 <-c 78 } 79 80 { 81 // Ensure that we receive 0 from closed chan. 82 c := make(chan int, chanCap) 83 for i := 0; i < chanCap; i++ { 84 c <- i 85 } 86 close(c) 87 for i := 0; i < chanCap; i++ { 88 v := <-c 89 if v != i { 90 t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i) 91 } 92 } 93 if v := <-c; v != 0 { 94 t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, 0) 95 } 96 if v, ok := <-c; v != 0 || ok { 97 t.Fatalf("chan[%d]: received %v/%v, expected %v/%v", chanCap, v, ok, 0, false) 98 } 99 } 100 101 { 102 // Ensure that close unblocks receive. 103 c := make(chan int, chanCap) 104 done := make(chan bool) 105 go func() { 106 v, ok := <-c 107 done <- v == 0 && ok == false 108 }() 109 time.Sleep(time.Millisecond) 110 close(c) 111 if !<-done { 112 t.Fatalf("chan[%d]: received non zero from closed chan", chanCap) 113 } 114 } 115 116 { 117 // Send 100 integers, 118 // ensure that we receive them non-corrupted in FIFO order. 119 c := make(chan int, chanCap) 120 go func() { 121 for i := 0; i < 100; i++ { 122 c <- i 123 } 124 }() 125 for i := 0; i < 100; i++ { 126 v := <-c 127 if v != i { 128 t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i) 129 } 130 } 131 132 // Same, but using recv2. 133 go func() { 134 for i := 0; i < 100; i++ { 135 c <- i 136 } 137 }() 138 for i := 0; i < 100; i++ { 139 v, ok := <-c 140 if !ok { 141 t.Fatalf("chan[%d]: receive failed, expected %v", chanCap, i) 142 } 143 if v != i { 144 t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i) 145 } 146 } 147 148 // Send 1000 integers in 4 goroutines, 149 // ensure that we receive what we send. 150 const P = 4 151 const L = 1000 152 for p := 0; p < P; p++ { 153 go func() { 154 for i := 0; i < L; i++ { 155 c <- i 156 } 157 }() 158 } 159 done := make(chan map[int]int) 160 for p := 0; p < P; p++ { 161 go func() { 162 recv := make(map[int]int) 163 for i := 0; i < L; i++ { 164 v := <-c 165 recv[v] = recv[v] + 1 166 } 167 done <- recv 168 }() 169 } 170 recv := make(map[int]int) 171 for p := 0; p < P; p++ { 172 for k, v := range <-done { 173 recv[k] = recv[k] + v 174 } 175 } 176 if len(recv) != L { 177 t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, len(recv), L) 178 } 179 for _, v := range recv { 180 if v != P { 181 t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, v, P) 182 } 183 } 184 } 185 186 { 187 // Test len/cap. 188 c := make(chan int, chanCap) 189 if len(c) != 0 || cap(c) != chanCap { 190 t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, 0, chanCap, len(c), cap(c)) 191 } 192 for i := 0; i < chanCap; i++ { 193 c <- i 194 } 195 if len(c) != chanCap || cap(c) != chanCap { 196 t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, chanCap, chanCap, len(c), cap(c)) 197 } 198 } 199 200 } 201 } 202 203 func TestNonblockRecvRace(t *testing.T) { 204 n := 10000 205 if testing.Short() { 206 n = 100 207 } 208 for i := 0; i < n; i++ { 209 c := make(chan int, 1) 210 c <- 1 211 go func() { 212 select { 213 case <-c: 214 default: 215 t.Error("chan is not ready") 216 } 217 }() 218 close(c) 219 <-c 220 if t.Failed() { 221 return 222 } 223 } 224 } 225 226 // This test checks that select acts on the state of the channels at one 227 // moment in the execution, not over a smeared time window. 228 // In the test, one goroutine does: 229 // create c1, c2 230 // make c1 ready for receiving 231 // create second goroutine 232 // make c2 ready for receiving 233 // make c1 no longer ready for receiving (if possible) 234 // The second goroutine does a non-blocking select receiving from c1 and c2. 235 // From the time the second goroutine is created, at least one of c1 and c2 236 // is always ready for receiving, so the select in the second goroutine must 237 // always receive from one or the other. It must never execute the default case. 238 func TestNonblockSelectRace(t *testing.T) { 239 n := 100000 240 if testing.Short() { 241 n = 1000 242 } 243 done := make(chan bool, 1) 244 for i := 0; i < n; i++ { 245 c1 := make(chan int, 1) 246 c2 := make(chan int, 1) 247 c1 <- 1 248 go func() { 249 select { 250 case <-c1: 251 case <-c2: 252 default: 253 done <- false 254 return 255 } 256 done <- true 257 }() 258 c2 <- 1 259 select { 260 case <-c1: 261 default: 262 } 263 if !<-done { 264 t.Fatal("no chan is ready") 265 } 266 } 267 } 268 269 // Same as TestNonblockSelectRace, but close(c2) replaces c2 <- 1. 270 func TestNonblockSelectRace2(t *testing.T) { 271 n := 100000 272 if testing.Short() { 273 n = 1000 274 } 275 done := make(chan bool, 1) 276 for i := 0; i < n; i++ { 277 c1 := make(chan int, 1) 278 c2 := make(chan int) 279 c1 <- 1 280 go func() { 281 select { 282 case <-c1: 283 case <-c2: 284 default: 285 done <- false 286 return 287 } 288 done <- true 289 }() 290 close(c2) 291 select { 292 case <-c1: 293 default: 294 } 295 if !<-done { 296 t.Fatal("no chan is ready") 297 } 298 } 299 } 300 301 func TestSelfSelect(t *testing.T) { 302 // Ensure that send/recv on the same chan in select 303 // does not crash nor deadlock. 304 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) 305 for _, chanCap := range []int{0, 10} { 306 var wg sync.WaitGroup 307 wg.Add(2) 308 c := make(chan int, chanCap) 309 for p := 0; p < 2; p++ { 310 p := p 311 go func() { 312 defer wg.Done() 313 for i := 0; i < 1000; i++ { 314 if p == 0 || i%2 == 0 { 315 select { 316 case c <- p: 317 case v := <-c: 318 if chanCap == 0 && v == p { 319 t.Errorf("self receive") 320 return 321 } 322 } 323 } else { 324 select { 325 case v := <-c: 326 if chanCap == 0 && v == p { 327 t.Errorf("self receive") 328 return 329 } 330 case c <- p: 331 } 332 } 333 } 334 }() 335 } 336 wg.Wait() 337 } 338 } 339 340 func TestSelectStress(t *testing.T) { 341 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(10)) 342 var c [4]chan int 343 c[0] = make(chan int) 344 c[1] = make(chan int) 345 c[2] = make(chan int, 2) 346 c[3] = make(chan int, 3) 347 N := int(1e5) 348 if testing.Short() { 349 N /= 10 350 } 351 // There are 4 goroutines that send N values on each of the chans, 352 // + 4 goroutines that receive N values on each of the chans, 353 // + 1 goroutine that sends N values on each of the chans in a single select, 354 // + 1 goroutine that receives N values on each of the chans in a single select. 355 // All these sends, receives and selects interact chaotically at runtime, 356 // but we are careful that this whole construct does not deadlock. 357 var wg sync.WaitGroup 358 wg.Add(10) 359 for k := 0; k < 4; k++ { 360 k := k 361 go func() { 362 for i := 0; i < N; i++ { 363 c[k] <- 0 364 } 365 wg.Done() 366 }() 367 go func() { 368 for i := 0; i < N; i++ { 369 <-c[k] 370 } 371 wg.Done() 372 }() 373 } 374 go func() { 375 var n [4]int 376 c1 := c 377 for i := 0; i < 4*N; i++ { 378 select { 379 case c1[3] <- 0: 380 n[3]++ 381 if n[3] == N { 382 c1[3] = nil 383 } 384 case c1[2] <- 0: 385 n[2]++ 386 if n[2] == N { 387 c1[2] = nil 388 } 389 case c1[0] <- 0: 390 n[0]++ 391 if n[0] == N { 392 c1[0] = nil 393 } 394 case c1[1] <- 0: 395 n[1]++ 396 if n[1] == N { 397 c1[1] = nil 398 } 399 } 400 } 401 wg.Done() 402 }() 403 go func() { 404 var n [4]int 405 c1 := c 406 for i := 0; i < 4*N; i++ { 407 select { 408 case <-c1[0]: 409 n[0]++ 410 if n[0] == N { 411 c1[0] = nil 412 } 413 case <-c1[1]: 414 n[1]++ 415 if n[1] == N { 416 c1[1] = nil 417 } 418 case <-c1[2]: 419 n[2]++ 420 if n[2] == N { 421 c1[2] = nil 422 } 423 case <-c1[3]: 424 n[3]++ 425 if n[3] == N { 426 c1[3] = nil 427 } 428 } 429 } 430 wg.Done() 431 }() 432 wg.Wait() 433 } 434 435 func TestSelectFairness(t *testing.T) { 436 const trials = 10000 437 if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" { 438 testenv.SkipFlaky(t, 22047) 439 } 440 c1 := make(chan byte, trials+1) 441 c2 := make(chan byte, trials+1) 442 for i := 0; i < trials+1; i++ { 443 c1 <- 1 444 c2 <- 2 445 } 446 c3 := make(chan byte) 447 c4 := make(chan byte) 448 out := make(chan byte) 449 done := make(chan byte) 450 var wg sync.WaitGroup 451 wg.Add(1) 452 go func() { 453 defer wg.Done() 454 for { 455 var b byte 456 select { 457 case b = <-c3: 458 case b = <-c4: 459 case b = <-c1: 460 case b = <-c2: 461 } 462 select { 463 case out <- b: 464 case <-done: 465 return 466 } 467 } 468 }() 469 cnt1, cnt2 := 0, 0 470 for i := 0; i < trials; i++ { 471 switch b := <-out; b { 472 case 1: 473 cnt1++ 474 case 2: 475 cnt2++ 476 default: 477 t.Fatalf("unexpected value %d on channel", b) 478 } 479 } 480 // If the select in the goroutine is fair, 481 // cnt1 and cnt2 should be about the same value. 482 // With 10,000 trials, the expected margin of error at 483 // a confidence level of five nines is 4.4172 / (2 * Sqrt(10000)). 484 r := float64(cnt1) / trials 485 e := math.Abs(r - 0.5) 486 t.Log(cnt1, cnt2, r, e) 487 if e > 4.4172/(2*math.Sqrt(trials)) { 488 t.Errorf("unfair select: in %d trials, results were %d, %d", trials, cnt1, cnt2) 489 } 490 close(done) 491 wg.Wait() 492 } 493 494 func TestChanSendInterface(t *testing.T) { 495 type mt struct{} 496 m := &mt{} 497 c := make(chan interface{}, 1) 498 c <- m 499 select { 500 case c <- m: 501 default: 502 } 503 select { 504 case c <- m: 505 case c <- &mt{}: 506 default: 507 } 508 } 509 510 func TestPseudoRandomSend(t *testing.T) { 511 n := 100 512 for _, chanCap := range []int{0, n} { 513 c := make(chan int, chanCap) 514 l := make([]int, n) 515 var m sync.Mutex 516 m.Lock() 517 go func() { 518 for i := 0; i < n; i++ { 519 runtime.Gosched() 520 l[i] = <-c 521 } 522 m.Unlock() 523 }() 524 for i := 0; i < n; i++ { 525 select { 526 case c <- 1: 527 case c <- 0: 528 } 529 } 530 m.Lock() // wait 531 n0 := 0 532 n1 := 0 533 for _, i := range l { 534 n0 += (i + 1) % 2 535 n1 += i 536 } 537 if n0 <= n/10 || n1 <= n/10 { 538 t.Errorf("Want pseudorandom, got %d zeros and %d ones (chan cap %d)", n0, n1, chanCap) 539 } 540 } 541 } 542 543 func TestMultiConsumer(t *testing.T) { 544 const nwork = 23 545 const niter = 271828 546 547 pn := []int{2, 3, 7, 11, 13, 17, 19, 23, 27, 31} 548 549 q := make(chan int, nwork*3) 550 r := make(chan int, nwork*3) 551 552 // workers 553 var wg sync.WaitGroup 554 for i := 0; i < nwork; i++ { 555 wg.Add(1) 556 go func(w int) { 557 for v := range q { 558 // mess with the fifo-ish nature of range 559 if pn[w%len(pn)] == v { 560 runtime.Gosched() 561 } 562 r <- v 563 } 564 wg.Done() 565 }(i) 566 } 567 568 // feeder & closer 569 expect := 0 570 go func() { 571 for i := 0; i < niter; i++ { 572 v := pn[i%len(pn)] 573 expect += v 574 q <- v 575 } 576 close(q) // no more work 577 wg.Wait() // workers done 578 close(r) // ... so there can be no more results 579 }() 580 581 // consume & check 582 n := 0 583 s := 0 584 for v := range r { 585 n++ 586 s += v 587 } 588 if n != niter || s != expect { 589 t.Errorf("Expected sum %d (got %d) from %d iter (saw %d)", 590 expect, s, niter, n) 591 } 592 } 593 594 func TestShrinkStackDuringBlockedSend(t *testing.T) { 595 // make sure that channel operations still work when we are 596 // blocked on a channel send and we shrink the stack. 597 // NOTE: this test probably won't fail unless stack1.go:stackDebug 598 // is set to >= 1. 599 const n = 10 600 c := make(chan int) 601 done := make(chan struct{}) 602 603 go func() { 604 for i := 0; i < n; i++ { 605 c <- i 606 // use lots of stack, briefly. 607 stackGrowthRecursive(20) 608 } 609 done <- struct{}{} 610 }() 611 612 for i := 0; i < n; i++ { 613 x := <-c 614 if x != i { 615 t.Errorf("bad channel read: want %d, got %d", i, x) 616 } 617 // Waste some time so sender can finish using lots of stack 618 // and block in channel send. 619 time.Sleep(1 * time.Millisecond) 620 // trigger GC which will shrink the stack of the sender. 621 runtime.GC() 622 } 623 <-done 624 } 625 626 func TestSelectDuplicateChannel(t *testing.T) { 627 // This test makes sure we can queue a G on 628 // the same channel multiple times. 629 c := make(chan int) 630 d := make(chan int) 631 e := make(chan int) 632 633 // goroutine A 634 go func() { 635 select { 636 case <-c: 637 case <-c: 638 case <-d: 639 } 640 e <- 9 641 }() 642 time.Sleep(time.Millisecond) // make sure goroutine A gets queued first on c 643 644 // goroutine B 645 go func() { 646 <-c 647 }() 648 time.Sleep(time.Millisecond) // make sure goroutine B gets queued on c before continuing 649 650 d <- 7 // wake up A, it dequeues itself from c. This operation used to corrupt c.recvq. 651 <-e // A tells us it's done 652 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) 653 } 654 655 var selectSink interface{} 656 657 func TestSelectStackAdjust(t *testing.T) { 658 // Test that channel receive slots that contain local stack 659 // pointers are adjusted correctly by stack shrinking. 660 c := make(chan *int) 661 d := make(chan *int) 662 ready1 := make(chan bool) 663 ready2 := make(chan bool) 664 665 f := func(ready chan bool, dup bool) { 666 // Temporarily grow the stack to 10K. 667 stackGrowthRecursive((10 << 10) / (128 * 8)) 668 669 // We're ready to trigger GC and stack shrink. 670 ready <- true 671 672 val := 42 673 var cx *int 674 cx = &val 675 676 var c2 chan *int 677 var d2 chan *int 678 if dup { 679 c2 = c 680 d2 = d 681 } 682 683 // Receive from d. cx won't be affected. 684 select { 685 case cx = <-c: 686 case <-c2: 687 case <-d: 688 case <-d2: 689 } 690 691 // Check that pointer in cx was adjusted correctly. 692 if cx != &val { 693 t.Error("cx no longer points to val") 694 } else if val != 42 { 695 t.Error("val changed") 696 } else { 697 *cx = 43 698 if val != 43 { 699 t.Error("changing *cx failed to change val") 700 } 701 } 702 ready <- true 703 } 704 705 go f(ready1, false) 706 go f(ready2, true) 707 708 // Let the goroutines get into the select. 709 <-ready1 710 <-ready2 711 time.Sleep(10 * time.Millisecond) 712 713 // Force concurrent GC a few times. 714 var before, after runtime.MemStats 715 runtime.ReadMemStats(&before) 716 for i := 0; i < 100; i++ { 717 selectSink = new([1 << 20]byte) 718 runtime.ReadMemStats(&after) 719 if after.NumGC-before.NumGC >= 2 { 720 goto done 721 } 722 } 723 t.Fatal("failed to trigger concurrent GC") 724 done: 725 selectSink = nil 726 727 // Wake selects. 728 close(d) 729 <-ready1 730 <-ready2 731 } 732 733 type struct0 struct{} 734 735 func BenchmarkMakeChan(b *testing.B) { 736 b.Run("Byte", func(b *testing.B) { 737 var x chan byte 738 for i := 0; i < b.N; i++ { 739 x = make(chan byte, 8) 740 } 741 close(x) 742 }) 743 b.Run("Int", func(b *testing.B) { 744 var x chan int 745 for i := 0; i < b.N; i++ { 746 x = make(chan int, 8) 747 } 748 close(x) 749 }) 750 b.Run("Ptr", func(b *testing.B) { 751 var x chan *byte 752 for i := 0; i < b.N; i++ { 753 x = make(chan *byte, 8) 754 } 755 close(x) 756 }) 757 b.Run("Struct", func(b *testing.B) { 758 b.Run("0", func(b *testing.B) { 759 var x chan struct0 760 for i := 0; i < b.N; i++ { 761 x = make(chan struct0, 8) 762 } 763 close(x) 764 }) 765 b.Run("32", func(b *testing.B) { 766 var x chan struct32 767 for i := 0; i < b.N; i++ { 768 x = make(chan struct32, 8) 769 } 770 close(x) 771 }) 772 b.Run("40", func(b *testing.B) { 773 var x chan struct40 774 for i := 0; i < b.N; i++ { 775 x = make(chan struct40, 8) 776 } 777 close(x) 778 }) 779 }) 780 } 781 782 func BenchmarkChanNonblocking(b *testing.B) { 783 myc := make(chan int) 784 b.RunParallel(func(pb *testing.PB) { 785 for pb.Next() { 786 select { 787 case <-myc: 788 default: 789 } 790 } 791 }) 792 } 793 794 func BenchmarkSelectUncontended(b *testing.B) { 795 b.RunParallel(func(pb *testing.PB) { 796 myc1 := make(chan int, 1) 797 myc2 := make(chan int, 1) 798 myc1 <- 0 799 for pb.Next() { 800 select { 801 case <-myc1: 802 myc2 <- 0 803 case <-myc2: 804 myc1 <- 0 805 } 806 } 807 }) 808 } 809 810 func BenchmarkSelectSyncContended(b *testing.B) { 811 myc1 := make(chan int) 812 myc2 := make(chan int) 813 myc3 := make(chan int) 814 done := make(chan int) 815 b.RunParallel(func(pb *testing.PB) { 816 go func() { 817 for { 818 select { 819 case myc1 <- 0: 820 case myc2 <- 0: 821 case myc3 <- 0: 822 case <-done: 823 return 824 } 825 } 826 }() 827 for pb.Next() { 828 select { 829 case <-myc1: 830 case <-myc2: 831 case <-myc3: 832 } 833 } 834 }) 835 close(done) 836 } 837 838 func BenchmarkSelectAsyncContended(b *testing.B) { 839 procs := runtime.GOMAXPROCS(0) 840 myc1 := make(chan int, procs) 841 myc2 := make(chan int, procs) 842 b.RunParallel(func(pb *testing.PB) { 843 myc1 <- 0 844 for pb.Next() { 845 select { 846 case <-myc1: 847 myc2 <- 0 848 case <-myc2: 849 myc1 <- 0 850 } 851 } 852 }) 853 } 854 855 func BenchmarkSelectNonblock(b *testing.B) { 856 myc1 := make(chan int) 857 myc2 := make(chan int) 858 myc3 := make(chan int, 1) 859 myc4 := make(chan int, 1) 860 b.RunParallel(func(pb *testing.PB) { 861 for pb.Next() { 862 select { 863 case <-myc1: 864 default: 865 } 866 select { 867 case myc2 <- 0: 868 default: 869 } 870 select { 871 case <-myc3: 872 default: 873 } 874 select { 875 case myc4 <- 0: 876 default: 877 } 878 } 879 }) 880 } 881 882 func BenchmarkChanUncontended(b *testing.B) { 883 const C = 100 884 b.RunParallel(func(pb *testing.PB) { 885 myc := make(chan int, C) 886 for pb.Next() { 887 for i := 0; i < C; i++ { 888 myc <- 0 889 } 890 for i := 0; i < C; i++ { 891 <-myc 892 } 893 } 894 }) 895 } 896 897 func BenchmarkChanContended(b *testing.B) { 898 const C = 100 899 myc := make(chan int, C*runtime.GOMAXPROCS(0)) 900 b.RunParallel(func(pb *testing.PB) { 901 for pb.Next() { 902 for i := 0; i < C; i++ { 903 myc <- 0 904 } 905 for i := 0; i < C; i++ { 906 <-myc 907 } 908 } 909 }) 910 } 911 912 func benchmarkChanSync(b *testing.B, work int) { 913 const CallsPerSched = 1000 914 procs := 2 915 N := int32(b.N / CallsPerSched / procs * procs) 916 c := make(chan bool, procs) 917 myc := make(chan int) 918 for p := 0; p < procs; p++ { 919 go func() { 920 for { 921 i := atomic.AddInt32(&N, -1) 922 if i < 0 { 923 break 924 } 925 for g := 0; g < CallsPerSched; g++ { 926 if i%2 == 0 { 927 <-myc 928 localWork(work) 929 myc <- 0 930 localWork(work) 931 } else { 932 myc <- 0 933 localWork(work) 934 <-myc 935 localWork(work) 936 } 937 } 938 } 939 c <- true 940 }() 941 } 942 for p := 0; p < procs; p++ { 943 <-c 944 } 945 } 946 947 func BenchmarkChanSync(b *testing.B) { 948 benchmarkChanSync(b, 0) 949 } 950 951 func BenchmarkChanSyncWork(b *testing.B) { 952 benchmarkChanSync(b, 1000) 953 } 954 955 func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) { 956 const CallsPerSched = 1000 957 procs := runtime.GOMAXPROCS(-1) 958 N := int32(b.N / CallsPerSched) 959 c := make(chan bool, 2*procs) 960 myc := make(chan int, chanSize) 961 for p := 0; p < procs; p++ { 962 go func() { 963 foo := 0 964 for atomic.AddInt32(&N, -1) >= 0 { 965 for g := 0; g < CallsPerSched; g++ { 966 for i := 0; i < localWork; i++ { 967 foo *= 2 968 foo /= 2 969 } 970 myc <- 1 971 } 972 } 973 myc <- 0 974 c <- foo == 42 975 }() 976 go func() { 977 foo := 0 978 for { 979 v := <-myc 980 if v == 0 { 981 break 982 } 983 for i := 0; i < localWork; i++ { 984 foo *= 2 985 foo /= 2 986 } 987 } 988 c <- foo == 42 989 }() 990 } 991 for p := 0; p < procs; p++ { 992 <-c 993 <-c 994 } 995 } 996 997 func BenchmarkChanProdCons0(b *testing.B) { 998 benchmarkChanProdCons(b, 0, 0) 999 } 1000 1001 func BenchmarkChanProdCons10(b *testing.B) { 1002 benchmarkChanProdCons(b, 10, 0) 1003 } 1004 1005 func BenchmarkChanProdCons100(b *testing.B) { 1006 benchmarkChanProdCons(b, 100, 0) 1007 } 1008 1009 func BenchmarkChanProdConsWork0(b *testing.B) { 1010 benchmarkChanProdCons(b, 0, 100) 1011 } 1012 1013 func BenchmarkChanProdConsWork10(b *testing.B) { 1014 benchmarkChanProdCons(b, 10, 100) 1015 } 1016 1017 func BenchmarkChanProdConsWork100(b *testing.B) { 1018 benchmarkChanProdCons(b, 100, 100) 1019 } 1020 1021 func BenchmarkSelectProdCons(b *testing.B) { 1022 const CallsPerSched = 1000 1023 procs := runtime.GOMAXPROCS(-1) 1024 N := int32(b.N / CallsPerSched) 1025 c := make(chan bool, 2*procs) 1026 myc := make(chan int, 128) 1027 myclose := make(chan bool) 1028 for p := 0; p < procs; p++ { 1029 go func() { 1030 // Producer: sends to myc. 1031 foo := 0 1032 // Intended to not fire during benchmarking. 1033 mytimer := time.After(time.Hour) 1034 for atomic.AddInt32(&N, -1) >= 0 { 1035 for g := 0; g < CallsPerSched; g++ { 1036 // Model some local work. 1037 for i := 0; i < 100; i++ { 1038 foo *= 2 1039 foo /= 2 1040 } 1041 select { 1042 case myc <- 1: 1043 case <-mytimer: 1044 case <-myclose: 1045 } 1046 } 1047 } 1048 myc <- 0 1049 c <- foo == 42 1050 }() 1051 go func() { 1052 // Consumer: receives from myc. 1053 foo := 0 1054 // Intended to not fire during benchmarking. 1055 mytimer := time.After(time.Hour) 1056 loop: 1057 for { 1058 select { 1059 case v := <-myc: 1060 if v == 0 { 1061 break loop 1062 } 1063 case <-mytimer: 1064 case <-myclose: 1065 } 1066 // Model some local work. 1067 for i := 0; i < 100; i++ { 1068 foo *= 2 1069 foo /= 2 1070 } 1071 } 1072 c <- foo == 42 1073 }() 1074 } 1075 for p := 0; p < procs; p++ { 1076 <-c 1077 <-c 1078 } 1079 } 1080 1081 func BenchmarkChanCreation(b *testing.B) { 1082 b.RunParallel(func(pb *testing.PB) { 1083 for pb.Next() { 1084 myc := make(chan int, 1) 1085 myc <- 0 1086 <-myc 1087 } 1088 }) 1089 } 1090 1091 func BenchmarkChanSem(b *testing.B) { 1092 type Empty struct{} 1093 myc := make(chan Empty, runtime.GOMAXPROCS(0)) 1094 b.RunParallel(func(pb *testing.PB) { 1095 for pb.Next() { 1096 myc <- Empty{} 1097 <-myc 1098 } 1099 }) 1100 } 1101 1102 func BenchmarkChanPopular(b *testing.B) { 1103 const n = 1000 1104 c := make(chan bool) 1105 var a []chan bool 1106 var wg sync.WaitGroup 1107 wg.Add(n) 1108 for j := 0; j < n; j++ { 1109 d := make(chan bool) 1110 a = append(a, d) 1111 go func() { 1112 for i := 0; i < b.N; i++ { 1113 select { 1114 case <-c: 1115 case <-d: 1116 } 1117 } 1118 wg.Done() 1119 }() 1120 } 1121 for i := 0; i < b.N; i++ { 1122 for _, d := range a { 1123 d <- true 1124 } 1125 } 1126 wg.Wait() 1127 } 1128 1129 var ( 1130 alwaysFalse = false 1131 workSink = 0 1132 ) 1133 1134 func localWork(w int) { 1135 foo := 0 1136 for i := 0; i < w; i++ { 1137 foo /= (foo + 1) 1138 } 1139 if alwaysFalse { 1140 workSink += foo 1141 } 1142 }