mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			383 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			383 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
| // 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"
 | |
| )
 | |
| 
 | |
| 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
 | |
| 	c := make(chan int)
 | |
| 	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 <- 0:
 | |
| 		case c <- 1:
 | |
| 		}
 | |
| 	}
 | |
| 	m.Lock() // wait
 | |
| 	n0 := 0
 | |
| 	n1 := 0
 | |
| 	for _, i := range l {
 | |
| 		n0 += (i + 1) % 2
 | |
| 		n1 += i
 | |
| 		if n0 > n/10 && n1 > n/10 {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	t.Errorf("Want pseudo random, got %d zeros and %d ones", n0, n1)
 | |
| }
 | |
| 
 | |
| 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 BenchmarkSelectUncontended(b *testing.B) {
 | |
| 	const CallsPerSched = 1000
 | |
| 	procs := runtime.GOMAXPROCS(-1)
 | |
| 	N := int32(b.N / CallsPerSched)
 | |
| 	c := make(chan bool, procs)
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		go func() {
 | |
| 			myc1 := make(chan int, 1)
 | |
| 			myc2 := make(chan int, 1)
 | |
| 			myc1 <- 0
 | |
| 			for atomic.AddInt32(&N, -1) >= 0 {
 | |
| 				for g := 0; g < CallsPerSched; g++ {
 | |
| 					select {
 | |
| 					case <-myc1:
 | |
| 						myc2 <- 0
 | |
| 					case <-myc2:
 | |
| 						myc1 <- 0
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			c <- true
 | |
| 		}()
 | |
| 	}
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		<-c
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func BenchmarkSelectContended(b *testing.B) {
 | |
| 	const CallsPerSched = 1000
 | |
| 	procs := runtime.GOMAXPROCS(-1)
 | |
| 	N := int32(b.N / CallsPerSched)
 | |
| 	c := make(chan bool, procs)
 | |
| 	myc1 := make(chan int, procs)
 | |
| 	myc2 := make(chan int, procs)
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		myc1 <- 0
 | |
| 		go func() {
 | |
| 			for atomic.AddInt32(&N, -1) >= 0 {
 | |
| 				for g := 0; g < CallsPerSched; g++ {
 | |
| 					select {
 | |
| 					case <-myc1:
 | |
| 						myc2 <- 0
 | |
| 					case <-myc2:
 | |
| 						myc1 <- 0
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			c <- true
 | |
| 		}()
 | |
| 	}
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		<-c
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func BenchmarkSelectNonblock(b *testing.B) {
 | |
| 	const CallsPerSched = 1000
 | |
| 	procs := runtime.GOMAXPROCS(-1)
 | |
| 	N := int32(b.N / CallsPerSched)
 | |
| 	c := make(chan bool, procs)
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		go func() {
 | |
| 			myc1 := make(chan int)
 | |
| 			myc2 := make(chan int)
 | |
| 			myc3 := make(chan int, 1)
 | |
| 			myc4 := make(chan int, 1)
 | |
| 			for atomic.AddInt32(&N, -1) >= 0 {
 | |
| 				for g := 0; g < CallsPerSched; g++ {
 | |
| 					select {
 | |
| 					case <-myc1:
 | |
| 					default:
 | |
| 					}
 | |
| 					select {
 | |
| 					case myc2 <- 0:
 | |
| 					default:
 | |
| 					}
 | |
| 					select {
 | |
| 					case <-myc3:
 | |
| 					default:
 | |
| 					}
 | |
| 					select {
 | |
| 					case myc4 <- 0:
 | |
| 					default:
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			c <- true
 | |
| 		}()
 | |
| 	}
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		<-c
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func BenchmarkChanUncontended(b *testing.B) {
 | |
| 	const CallsPerSched = 1000
 | |
| 	procs := runtime.GOMAXPROCS(-1)
 | |
| 	N := int32(b.N / CallsPerSched)
 | |
| 	c := make(chan bool, procs)
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		go func() {
 | |
| 			myc := make(chan int, CallsPerSched)
 | |
| 			for atomic.AddInt32(&N, -1) >= 0 {
 | |
| 				for g := 0; g < CallsPerSched; g++ {
 | |
| 					myc <- 0
 | |
| 				}
 | |
| 				for g := 0; g < CallsPerSched; g++ {
 | |
| 					<-myc
 | |
| 				}
 | |
| 			}
 | |
| 			c <- true
 | |
| 		}()
 | |
| 	}
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		<-c
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func BenchmarkChanContended(b *testing.B) {
 | |
| 	const CallsPerSched = 1000
 | |
| 	procs := runtime.GOMAXPROCS(-1)
 | |
| 	N := int32(b.N / CallsPerSched)
 | |
| 	c := make(chan bool, procs)
 | |
| 	myc := make(chan int, procs*CallsPerSched)
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		go func() {
 | |
| 			for atomic.AddInt32(&N, -1) >= 0 {
 | |
| 				for g := 0; g < CallsPerSched; g++ {
 | |
| 					myc <- 0
 | |
| 				}
 | |
| 				for g := 0; g < CallsPerSched; g++ {
 | |
| 					<-myc
 | |
| 				}
 | |
| 			}
 | |
| 			c <- true
 | |
| 		}()
 | |
| 	}
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		<-c
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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 BenchmarkChanCreation(b *testing.B) {
 | |
| 	const CallsPerSched = 1000
 | |
| 	procs := runtime.GOMAXPROCS(-1)
 | |
| 	N := int32(b.N / CallsPerSched)
 | |
| 	c := make(chan bool, procs)
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		go func() {
 | |
| 			for atomic.AddInt32(&N, -1) >= 0 {
 | |
| 				for g := 0; g < CallsPerSched; g++ {
 | |
| 					myc := make(chan int, 1)
 | |
| 					myc <- 0
 | |
| 					<-myc
 | |
| 				}
 | |
| 			}
 | |
| 			c <- true
 | |
| 		}()
 | |
| 	}
 | |
| 	for p := 0; p < procs; p++ {
 | |
| 		<-c
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func BenchmarkChanSem(b *testing.B) {
 | |
| 	type Empty struct{}
 | |
| 	c := make(chan Empty, 1)
 | |
| 	for i := 0; i < b.N; i++ {
 | |
| 		c <- Empty{}
 | |
| 		<-c
 | |
| 	}
 | |
| }
 |