github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/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 "github.com/x04/go/src/internal/testenv" 9 "github.com/x04/go/src/math" 10 "github.com/x04/go/src/runtime" 11 "github.com/x04/go/src/sync" 12 "github.com/x04/go/src/sync/atomic" 13 "github.com/x04/go/src/testing" 14 "github.com/x04/go/src/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 six nines is 4.891676 / (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.891676/(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 runtime.Gosched() 723 } 724 t.Fatal("failed to trigger concurrent GC") 725 done: 726 selectSink = nil 727 728 // Wake selects. 729 close(d) 730 <-ready1 731 <-ready2 732 } 733 734 type struct0 struct{} 735 736 func BenchmarkMakeChan(b *testing.B) { 737 b.Run("Byte", func(b *testing.B) { 738 var x chan byte 739 for i := 0; i < b.N; i++ { 740 x = make(chan byte, 8) 741 } 742 close(x) 743 }) 744 b.Run("Int", func(b *testing.B) { 745 var x chan int 746 for i := 0; i < b.N; i++ { 747 x = make(chan int, 8) 748 } 749 close(x) 750 }) 751 b.Run("Ptr", func(b *testing.B) { 752 var x chan *byte 753 for i := 0; i < b.N; i++ { 754 x = make(chan *byte, 8) 755 } 756 close(x) 757 }) 758 b.Run("Struct", func(b *testing.B) { 759 b.Run("0", func(b *testing.B) { 760 var x chan struct0 761 for i := 0; i < b.N; i++ { 762 x = make(chan struct0, 8) 763 } 764 close(x) 765 }) 766 b.Run("32", func(b *testing.B) { 767 var x chan struct32 768 for i := 0; i < b.N; i++ { 769 x = make(chan struct32, 8) 770 } 771 close(x) 772 }) 773 b.Run("40", func(b *testing.B) { 774 var x chan struct40 775 for i := 0; i < b.N; i++ { 776 x = make(chan struct40, 8) 777 } 778 close(x) 779 }) 780 }) 781 } 782 783 func BenchmarkChanNonblocking(b *testing.B) { 784 myc := make(chan int) 785 b.RunParallel(func(pb *testing.PB) { 786 for pb.Next() { 787 select { 788 case <-myc: 789 default: 790 } 791 } 792 }) 793 } 794 795 func BenchmarkSelectUncontended(b *testing.B) { 796 b.RunParallel(func(pb *testing.PB) { 797 myc1 := make(chan int, 1) 798 myc2 := make(chan int, 1) 799 myc1 <- 0 800 for pb.Next() { 801 select { 802 case <-myc1: 803 myc2 <- 0 804 case <-myc2: 805 myc1 <- 0 806 } 807 } 808 }) 809 } 810 811 func BenchmarkSelectSyncContended(b *testing.B) { 812 myc1 := make(chan int) 813 myc2 := make(chan int) 814 myc3 := make(chan int) 815 done := make(chan int) 816 b.RunParallel(func(pb *testing.PB) { 817 go func() { 818 for { 819 select { 820 case myc1 <- 0: 821 case myc2 <- 0: 822 case myc3 <- 0: 823 case <-done: 824 return 825 } 826 } 827 }() 828 for pb.Next() { 829 select { 830 case <-myc1: 831 case <-myc2: 832 case <-myc3: 833 } 834 } 835 }) 836 close(done) 837 } 838 839 func BenchmarkSelectAsyncContended(b *testing.B) { 840 procs := runtime.GOMAXPROCS(0) 841 myc1 := make(chan int, procs) 842 myc2 := make(chan int, procs) 843 b.RunParallel(func(pb *testing.PB) { 844 myc1 <- 0 845 for pb.Next() { 846 select { 847 case <-myc1: 848 myc2 <- 0 849 case <-myc2: 850 myc1 <- 0 851 } 852 } 853 }) 854 } 855 856 func BenchmarkSelectNonblock(b *testing.B) { 857 myc1 := make(chan int) 858 myc2 := make(chan int) 859 myc3 := make(chan int, 1) 860 myc4 := make(chan int, 1) 861 b.RunParallel(func(pb *testing.PB) { 862 for pb.Next() { 863 select { 864 case <-myc1: 865 default: 866 } 867 select { 868 case myc2 <- 0: 869 default: 870 } 871 select { 872 case <-myc3: 873 default: 874 } 875 select { 876 case myc4 <- 0: 877 default: 878 } 879 } 880 }) 881 } 882 883 func BenchmarkChanUncontended(b *testing.B) { 884 const C = 100 885 b.RunParallel(func(pb *testing.PB) { 886 myc := make(chan int, C) 887 for pb.Next() { 888 for i := 0; i < C; i++ { 889 myc <- 0 890 } 891 for i := 0; i < C; i++ { 892 <-myc 893 } 894 } 895 }) 896 } 897 898 func BenchmarkChanContended(b *testing.B) { 899 const C = 100 900 myc := make(chan int, C*runtime.GOMAXPROCS(0)) 901 b.RunParallel(func(pb *testing.PB) { 902 for pb.Next() { 903 for i := 0; i < C; i++ { 904 myc <- 0 905 } 906 for i := 0; i < C; i++ { 907 <-myc 908 } 909 } 910 }) 911 } 912 913 func benchmarkChanSync(b *testing.B, work int) { 914 const CallsPerSched = 1000 915 procs := 2 916 N := int32(b.N / CallsPerSched / procs * procs) 917 c := make(chan bool, procs) 918 myc := make(chan int) 919 for p := 0; p < procs; p++ { 920 go func() { 921 for { 922 i := atomic.AddInt32(&N, -1) 923 if i < 0 { 924 break 925 } 926 for g := 0; g < CallsPerSched; g++ { 927 if i%2 == 0 { 928 <-myc 929 localWork(work) 930 myc <- 0 931 localWork(work) 932 } else { 933 myc <- 0 934 localWork(work) 935 <-myc 936 localWork(work) 937 } 938 } 939 } 940 c <- true 941 }() 942 } 943 for p := 0; p < procs; p++ { 944 <-c 945 } 946 } 947 948 func BenchmarkChanSync(b *testing.B) { 949 benchmarkChanSync(b, 0) 950 } 951 952 func BenchmarkChanSyncWork(b *testing.B) { 953 benchmarkChanSync(b, 1000) 954 } 955 956 func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) { 957 const CallsPerSched = 1000 958 procs := runtime.GOMAXPROCS(-1) 959 N := int32(b.N / CallsPerSched) 960 c := make(chan bool, 2*procs) 961 myc := make(chan int, chanSize) 962 for p := 0; p < procs; p++ { 963 go func() { 964 foo := 0 965 for atomic.AddInt32(&N, -1) >= 0 { 966 for g := 0; g < CallsPerSched; g++ { 967 for i := 0; i < localWork; i++ { 968 foo *= 2 969 foo /= 2 970 } 971 myc <- 1 972 } 973 } 974 myc <- 0 975 c <- foo == 42 976 }() 977 go func() { 978 foo := 0 979 for { 980 v := <-myc 981 if v == 0 { 982 break 983 } 984 for i := 0; i < localWork; i++ { 985 foo *= 2 986 foo /= 2 987 } 988 } 989 c <- foo == 42 990 }() 991 } 992 for p := 0; p < procs; p++ { 993 <-c 994 <-c 995 } 996 } 997 998 func BenchmarkChanProdCons0(b *testing.B) { 999 benchmarkChanProdCons(b, 0, 0) 1000 } 1001 1002 func BenchmarkChanProdCons10(b *testing.B) { 1003 benchmarkChanProdCons(b, 10, 0) 1004 } 1005 1006 func BenchmarkChanProdCons100(b *testing.B) { 1007 benchmarkChanProdCons(b, 100, 0) 1008 } 1009 1010 func BenchmarkChanProdConsWork0(b *testing.B) { 1011 benchmarkChanProdCons(b, 0, 100) 1012 } 1013 1014 func BenchmarkChanProdConsWork10(b *testing.B) { 1015 benchmarkChanProdCons(b, 10, 100) 1016 } 1017 1018 func BenchmarkChanProdConsWork100(b *testing.B) { 1019 benchmarkChanProdCons(b, 100, 100) 1020 } 1021 1022 func BenchmarkSelectProdCons(b *testing.B) { 1023 const CallsPerSched = 1000 1024 procs := runtime.GOMAXPROCS(-1) 1025 N := int32(b.N / CallsPerSched) 1026 c := make(chan bool, 2*procs) 1027 myc := make(chan int, 128) 1028 myclose := make(chan bool) 1029 for p := 0; p < procs; p++ { 1030 go func() { 1031 // Producer: sends to myc. 1032 foo := 0 1033 // Intended to not fire during benchmarking. 1034 mytimer := time.After(time.Hour) 1035 for atomic.AddInt32(&N, -1) >= 0 { 1036 for g := 0; g < CallsPerSched; g++ { 1037 // Model some local work. 1038 for i := 0; i < 100; i++ { 1039 foo *= 2 1040 foo /= 2 1041 } 1042 select { 1043 case myc <- 1: 1044 case <-mytimer: 1045 case <-myclose: 1046 } 1047 } 1048 } 1049 myc <- 0 1050 c <- foo == 42 1051 }() 1052 go func() { 1053 // Consumer: receives from myc. 1054 foo := 0 1055 // Intended to not fire during benchmarking. 1056 mytimer := time.After(time.Hour) 1057 loop: 1058 for { 1059 select { 1060 case v := <-myc: 1061 if v == 0 { 1062 break loop 1063 } 1064 case <-mytimer: 1065 case <-myclose: 1066 } 1067 // Model some local work. 1068 for i := 0; i < 100; i++ { 1069 foo *= 2 1070 foo /= 2 1071 } 1072 } 1073 c <- foo == 42 1074 }() 1075 } 1076 for p := 0; p < procs; p++ { 1077 <-c 1078 <-c 1079 } 1080 } 1081 1082 func BenchmarkChanCreation(b *testing.B) { 1083 b.RunParallel(func(pb *testing.PB) { 1084 for pb.Next() { 1085 myc := make(chan int, 1) 1086 myc <- 0 1087 <-myc 1088 } 1089 }) 1090 } 1091 1092 func BenchmarkChanSem(b *testing.B) { 1093 type Empty struct{} 1094 myc := make(chan Empty, runtime.GOMAXPROCS(0)) 1095 b.RunParallel(func(pb *testing.PB) { 1096 for pb.Next() { 1097 myc <- Empty{} 1098 <-myc 1099 } 1100 }) 1101 } 1102 1103 func BenchmarkChanPopular(b *testing.B) { 1104 const n = 1000 1105 c := make(chan bool) 1106 var a []chan bool 1107 var wg sync.WaitGroup 1108 wg.Add(n) 1109 for j := 0; j < n; j++ { 1110 d := make(chan bool) 1111 a = append(a, d) 1112 go func() { 1113 for i := 0; i < b.N; i++ { 1114 select { 1115 case <-c: 1116 case <-d: 1117 } 1118 } 1119 wg.Done() 1120 }() 1121 } 1122 for i := 0; i < b.N; i++ { 1123 for _, d := range a { 1124 d <- true 1125 } 1126 } 1127 wg.Wait() 1128 } 1129 1130 var ( 1131 alwaysFalse = false 1132 workSink = 0 1133 ) 1134 1135 func localWork(w int) { 1136 foo := 0 1137 for i := 0; i < w; i++ { 1138 foo /= (foo + 1) 1139 } 1140 if alwaysFalse { 1141 workSink += foo 1142 } 1143 }