github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/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  	"runtime"
     9  	"sync"
    10  	"sync/atomic"
    11  	"testing"
    12  )
    13  
    14  func TestChanSendInterface(t *testing.T) {
    15  	type mt struct{}
    16  	m := &mt{}
    17  	c := make(chan interface{}, 1)
    18  	c <- m
    19  	select {
    20  	case c <- m:
    21  	default:
    22  	}
    23  	select {
    24  	case c <- m:
    25  	case c <- &mt{}:
    26  	default:
    27  	}
    28  }
    29  
    30  func TestPseudoRandomSend(t *testing.T) {
    31  	n := 100
    32  	c := make(chan int)
    33  	l := make([]int, n)
    34  	var m sync.Mutex
    35  	m.Lock()
    36  	go func() {
    37  		for i := 0; i < n; i++ {
    38  			runtime.Gosched()
    39  			l[i] = <-c
    40  		}
    41  		m.Unlock()
    42  	}()
    43  	for i := 0; i < n; i++ {
    44  		select {
    45  		case c <- 0:
    46  		case c <- 1:
    47  		}
    48  	}
    49  	m.Lock() // wait
    50  	n0 := 0
    51  	n1 := 0
    52  	for _, i := range l {
    53  		n0 += (i + 1) % 2
    54  		n1 += i
    55  		if n0 > n/10 && n1 > n/10 {
    56  			return
    57  		}
    58  	}
    59  	t.Errorf("Want pseudo random, got %d zeros and %d ones", n0, n1)
    60  }
    61  
    62  func TestMultiConsumer(t *testing.T) {
    63  	const nwork = 23
    64  	const niter = 271828
    65  
    66  	pn := []int{2, 3, 7, 11, 13, 17, 19, 23, 27, 31}
    67  
    68  	q := make(chan int, nwork*3)
    69  	r := make(chan int, nwork*3)
    70  
    71  	// workers
    72  	var wg sync.WaitGroup
    73  	for i := 0; i < nwork; i++ {
    74  		wg.Add(1)
    75  		go func(w int) {
    76  			for v := range q {
    77  				// mess with the fifo-ish nature of range
    78  				if pn[w%len(pn)] == v {
    79  					runtime.Gosched()
    80  				}
    81  				r <- v
    82  			}
    83  			wg.Done()
    84  		}(i)
    85  	}
    86  
    87  	// feeder & closer
    88  	expect := 0
    89  	go func() {
    90  		for i := 0; i < niter; i++ {
    91  			v := pn[i%len(pn)]
    92  			expect += v
    93  			q <- v
    94  		}
    95  		close(q)  // no more work
    96  		wg.Wait() // workers done
    97  		close(r)  // ... so there can be no more results
    98  	}()
    99  
   100  	// consume & check
   101  	n := 0
   102  	s := 0
   103  	for v := range r {
   104  		n++
   105  		s += v
   106  	}
   107  	if n != niter || s != expect {
   108  		t.Errorf("Expected sum %d (got %d) from %d iter (saw %d)",
   109  			expect, s, niter, n)
   110  	}
   111  }
   112  
   113  func BenchmarkSelectUncontended(b *testing.B) {
   114  	const CallsPerSched = 1000
   115  	procs := runtime.GOMAXPROCS(-1)
   116  	N := int32(b.N / CallsPerSched)
   117  	c := make(chan bool, procs)
   118  	for p := 0; p < procs; p++ {
   119  		go func() {
   120  			myc1 := make(chan int, 1)
   121  			myc2 := make(chan int, 1)
   122  			myc1 <- 0
   123  			for atomic.AddInt32(&N, -1) >= 0 {
   124  				for g := 0; g < CallsPerSched; g++ {
   125  					select {
   126  					case <-myc1:
   127  						myc2 <- 0
   128  					case <-myc2:
   129  						myc1 <- 0
   130  					}
   131  				}
   132  			}
   133  			c <- true
   134  		}()
   135  	}
   136  	for p := 0; p < procs; p++ {
   137  		<-c
   138  	}
   139  }
   140  
   141  func BenchmarkSelectContended(b *testing.B) {
   142  	const CallsPerSched = 1000
   143  	procs := runtime.GOMAXPROCS(-1)
   144  	N := int32(b.N / CallsPerSched)
   145  	c := make(chan bool, procs)
   146  	myc1 := make(chan int, procs)
   147  	myc2 := make(chan int, procs)
   148  	for p := 0; p < procs; p++ {
   149  		myc1 <- 0
   150  		go func() {
   151  			for atomic.AddInt32(&N, -1) >= 0 {
   152  				for g := 0; g < CallsPerSched; g++ {
   153  					select {
   154  					case <-myc1:
   155  						myc2 <- 0
   156  					case <-myc2:
   157  						myc1 <- 0
   158  					}
   159  				}
   160  			}
   161  			c <- true
   162  		}()
   163  	}
   164  	for p := 0; p < procs; p++ {
   165  		<-c
   166  	}
   167  }
   168  
   169  func BenchmarkSelectNonblock(b *testing.B) {
   170  	const CallsPerSched = 1000
   171  	procs := runtime.GOMAXPROCS(-1)
   172  	N := int32(b.N / CallsPerSched)
   173  	c := make(chan bool, procs)
   174  	for p := 0; p < procs; p++ {
   175  		go func() {
   176  			myc1 := make(chan int)
   177  			myc2 := make(chan int)
   178  			myc3 := make(chan int, 1)
   179  			myc4 := make(chan int, 1)
   180  			for atomic.AddInt32(&N, -1) >= 0 {
   181  				for g := 0; g < CallsPerSched; g++ {
   182  					select {
   183  					case <-myc1:
   184  					default:
   185  					}
   186  					select {
   187  					case myc2 <- 0:
   188  					default:
   189  					}
   190  					select {
   191  					case <-myc3:
   192  					default:
   193  					}
   194  					select {
   195  					case myc4 <- 0:
   196  					default:
   197  					}
   198  				}
   199  			}
   200  			c <- true
   201  		}()
   202  	}
   203  	for p := 0; p < procs; p++ {
   204  		<-c
   205  	}
   206  }
   207  
   208  func BenchmarkChanUncontended(b *testing.B) {
   209  	const CallsPerSched = 1000
   210  	procs := runtime.GOMAXPROCS(-1)
   211  	N := int32(b.N / CallsPerSched)
   212  	c := make(chan bool, procs)
   213  	for p := 0; p < procs; p++ {
   214  		go func() {
   215  			myc := make(chan int, CallsPerSched)
   216  			for atomic.AddInt32(&N, -1) >= 0 {
   217  				for g := 0; g < CallsPerSched; g++ {
   218  					myc <- 0
   219  				}
   220  				for g := 0; g < CallsPerSched; g++ {
   221  					<-myc
   222  				}
   223  			}
   224  			c <- true
   225  		}()
   226  	}
   227  	for p := 0; p < procs; p++ {
   228  		<-c
   229  	}
   230  }
   231  
   232  func BenchmarkChanContended(b *testing.B) {
   233  	const CallsPerSched = 1000
   234  	procs := runtime.GOMAXPROCS(-1)
   235  	N := int32(b.N / CallsPerSched)
   236  	c := make(chan bool, procs)
   237  	myc := make(chan int, procs*CallsPerSched)
   238  	for p := 0; p < procs; p++ {
   239  		go func() {
   240  			for atomic.AddInt32(&N, -1) >= 0 {
   241  				for g := 0; g < CallsPerSched; g++ {
   242  					myc <- 0
   243  				}
   244  				for g := 0; g < CallsPerSched; g++ {
   245  					<-myc
   246  				}
   247  			}
   248  			c <- true
   249  		}()
   250  	}
   251  	for p := 0; p < procs; p++ {
   252  		<-c
   253  	}
   254  }
   255  
   256  func BenchmarkChanSync(b *testing.B) {
   257  	const CallsPerSched = 1000
   258  	procs := 2
   259  	N := int32(b.N / CallsPerSched / procs * procs)
   260  	c := make(chan bool, procs)
   261  	myc := make(chan int)
   262  	for p := 0; p < procs; p++ {
   263  		go func() {
   264  			for {
   265  				i := atomic.AddInt32(&N, -1)
   266  				if i < 0 {
   267  					break
   268  				}
   269  				for g := 0; g < CallsPerSched; g++ {
   270  					if i%2 == 0 {
   271  						<-myc
   272  						myc <- 0
   273  					} else {
   274  						myc <- 0
   275  						<-myc
   276  					}
   277  				}
   278  			}
   279  			c <- true
   280  		}()
   281  	}
   282  	for p := 0; p < procs; p++ {
   283  		<-c
   284  	}
   285  }
   286  
   287  func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) {
   288  	const CallsPerSched = 1000
   289  	procs := runtime.GOMAXPROCS(-1)
   290  	N := int32(b.N / CallsPerSched)
   291  	c := make(chan bool, 2*procs)
   292  	myc := make(chan int, chanSize)
   293  	for p := 0; p < procs; p++ {
   294  		go func() {
   295  			foo := 0
   296  			for atomic.AddInt32(&N, -1) >= 0 {
   297  				for g := 0; g < CallsPerSched; g++ {
   298  					for i := 0; i < localWork; i++ {
   299  						foo *= 2
   300  						foo /= 2
   301  					}
   302  					myc <- 1
   303  				}
   304  			}
   305  			myc <- 0
   306  			c <- foo == 42
   307  		}()
   308  		go func() {
   309  			foo := 0
   310  			for {
   311  				v := <-myc
   312  				if v == 0 {
   313  					break
   314  				}
   315  				for i := 0; i < localWork; i++ {
   316  					foo *= 2
   317  					foo /= 2
   318  				}
   319  			}
   320  			c <- foo == 42
   321  		}()
   322  	}
   323  	for p := 0; p < procs; p++ {
   324  		<-c
   325  		<-c
   326  	}
   327  }
   328  
   329  func BenchmarkChanProdCons0(b *testing.B) {
   330  	benchmarkChanProdCons(b, 0, 0)
   331  }
   332  
   333  func BenchmarkChanProdCons10(b *testing.B) {
   334  	benchmarkChanProdCons(b, 10, 0)
   335  }
   336  
   337  func BenchmarkChanProdCons100(b *testing.B) {
   338  	benchmarkChanProdCons(b, 100, 0)
   339  }
   340  
   341  func BenchmarkChanProdConsWork0(b *testing.B) {
   342  	benchmarkChanProdCons(b, 0, 100)
   343  }
   344  
   345  func BenchmarkChanProdConsWork10(b *testing.B) {
   346  	benchmarkChanProdCons(b, 10, 100)
   347  }
   348  
   349  func BenchmarkChanProdConsWork100(b *testing.B) {
   350  	benchmarkChanProdCons(b, 100, 100)
   351  }
   352  
   353  func BenchmarkChanCreation(b *testing.B) {
   354  	const CallsPerSched = 1000
   355  	procs := runtime.GOMAXPROCS(-1)
   356  	N := int32(b.N / CallsPerSched)
   357  	c := make(chan bool, procs)
   358  	for p := 0; p < procs; p++ {
   359  		go func() {
   360  			for atomic.AddInt32(&N, -1) >= 0 {
   361  				for g := 0; g < CallsPerSched; g++ {
   362  					myc := make(chan int, 1)
   363  					myc <- 0
   364  					<-myc
   365  				}
   366  			}
   367  			c <- true
   368  		}()
   369  	}
   370  	for p := 0; p < procs; p++ {
   371  		<-c
   372  	}
   373  }
   374  
   375  func BenchmarkChanSem(b *testing.B) {
   376  	type Empty struct{}
   377  	c := make(chan Empty, 1)
   378  	for i := 0; i < b.N; i++ {
   379  		c <- Empty{}
   380  		<-c
   381  	}
   382  }