github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/sync/waitgroup_test.go (about)

     1  // Copyright 2011 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 sync_test
     6  
     7  import (
     8  	"runtime"
     9  	. "sync"
    10  	"sync/atomic"
    11  	"testing"
    12  )
    13  
    14  func testWaitGroup(t *testing.T, wg1 *WaitGroup, wg2 *WaitGroup) {
    15  	n := 16
    16  	wg1.Add(n)
    17  	wg2.Add(n)
    18  	exited := make(chan bool, n)
    19  	for i := 0; i != n; i++ {
    20  		go func(i int) {
    21  			wg1.Done()
    22  			wg2.Wait()
    23  			exited <- true
    24  		}(i)
    25  	}
    26  	wg1.Wait()
    27  	for i := 0; i != n; i++ {
    28  		select {
    29  		case <-exited:
    30  			t.Fatal("WaitGroup released group too soon")
    31  		default:
    32  		}
    33  		wg2.Done()
    34  	}
    35  	for i := 0; i != n; i++ {
    36  		<-exited // Will block if barrier fails to unlock someone.
    37  	}
    38  }
    39  
    40  func TestWaitGroup(t *testing.T) {
    41  	wg1 := &WaitGroup{}
    42  	wg2 := &WaitGroup{}
    43  
    44  	// Run the same test a few times to ensure barrier is in a proper state.
    45  	for i := 0; i != 8; i++ {
    46  		testWaitGroup(t, wg1, wg2)
    47  	}
    48  }
    49  
    50  func TestWaitGroupMisuse(t *testing.T) {
    51  	defer func() {
    52  		err := recover()
    53  		if err != "sync: negative WaitGroup counter" {
    54  			t.Fatalf("Unexpected panic: %#v", err)
    55  		}
    56  	}()
    57  	wg := &WaitGroup{}
    58  	wg.Add(1)
    59  	wg.Done()
    60  	wg.Done()
    61  	t.Fatal("Should panic")
    62  }
    63  
    64  func BenchmarkWaitGroupUncontended(b *testing.B) {
    65  	type PaddedWaitGroup struct {
    66  		WaitGroup
    67  		pad [128]uint8
    68  	}
    69  	const CallsPerSched = 1000
    70  	procs := runtime.GOMAXPROCS(-1)
    71  	N := int32(b.N / CallsPerSched)
    72  	c := make(chan bool, procs)
    73  	for p := 0; p < procs; p++ {
    74  		go func() {
    75  			var wg PaddedWaitGroup
    76  			for atomic.AddInt32(&N, -1) >= 0 {
    77  				runtime.Gosched()
    78  				for g := 0; g < CallsPerSched; g++ {
    79  					wg.Add(1)
    80  					wg.Done()
    81  					wg.Wait()
    82  				}
    83  			}
    84  			c <- true
    85  		}()
    86  	}
    87  	for p := 0; p < procs; p++ {
    88  		<-c
    89  	}
    90  }
    91  
    92  func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
    93  	const CallsPerSched = 1000
    94  	procs := runtime.GOMAXPROCS(-1)
    95  	N := int32(b.N / CallsPerSched)
    96  	c := make(chan bool, procs)
    97  	var wg WaitGroup
    98  	for p := 0; p < procs; p++ {
    99  		go func() {
   100  			foo := 0
   101  			for atomic.AddInt32(&N, -1) >= 0 {
   102  				runtime.Gosched()
   103  				for g := 0; g < CallsPerSched; g++ {
   104  					wg.Add(1)
   105  					for i := 0; i < localWork; i++ {
   106  						foo *= 2
   107  						foo /= 2
   108  					}
   109  					wg.Done()
   110  				}
   111  			}
   112  			c <- foo == 42
   113  		}()
   114  	}
   115  	for p := 0; p < procs; p++ {
   116  		<-c
   117  	}
   118  }
   119  
   120  func BenchmarkWaitGroupAddDone(b *testing.B) {
   121  	benchmarkWaitGroupAddDone(b, 0)
   122  }
   123  
   124  func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
   125  	benchmarkWaitGroupAddDone(b, 100)
   126  }
   127  
   128  func benchmarkWaitGroupWait(b *testing.B, localWork int) {
   129  	const CallsPerSched = 1000
   130  	procs := runtime.GOMAXPROCS(-1)
   131  	N := int32(b.N / CallsPerSched)
   132  	c := make(chan bool, procs)
   133  	var wg WaitGroup
   134  	wg.Add(procs)
   135  	for p := 0; p < procs; p++ {
   136  		go wg.Done()
   137  	}
   138  	for p := 0; p < procs; p++ {
   139  		go func() {
   140  			foo := 0
   141  			for atomic.AddInt32(&N, -1) >= 0 {
   142  				runtime.Gosched()
   143  				for g := 0; g < CallsPerSched; g++ {
   144  					wg.Wait()
   145  					for i := 0; i < localWork; i++ {
   146  						foo *= 2
   147  						foo /= 2
   148  					}
   149  				}
   150  			}
   151  			c <- foo == 42
   152  		}()
   153  	}
   154  	for p := 0; p < procs; p++ {
   155  		<-c
   156  	}
   157  }
   158  
   159  func BenchmarkWaitGroupWait(b *testing.B) {
   160  	benchmarkWaitGroupWait(b, 0)
   161  }
   162  
   163  func BenchmarkWaitGroupWaitWork(b *testing.B) {
   164  	benchmarkWaitGroupWait(b, 100)
   165  }