github.com/flyinox/gosm@v0.0.0-20171117061539-16768cb62077/src/sync/pool_test.go (about)

     1  // Copyright 2013 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  // Pool is no-op under race detector, so all these tests do not work.
     6  // +build !race
     7  
     8  package sync_test
     9  
    10  import (
    11  	"runtime"
    12  	"runtime/debug"
    13  	. "sync"
    14  	"sync/atomic"
    15  	"testing"
    16  	"time"
    17  )
    18  
    19  func TestPool(t *testing.T) {
    20  	// disable GC so we can control when it happens.
    21  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
    22  	var p Pool
    23  	if p.Get() != nil {
    24  		t.Fatal("expected empty")
    25  	}
    26  
    27  	// Make sure that the goroutine doesn't migrate to another P
    28  	// between Put and Get calls.
    29  	Runtime_procPin()
    30  	p.Put("a")
    31  	p.Put("b")
    32  	if g := p.Get(); g != "a" {
    33  		t.Fatalf("got %#v; want a", g)
    34  	}
    35  	if g := p.Get(); g != "b" {
    36  		t.Fatalf("got %#v; want b", g)
    37  	}
    38  	if g := p.Get(); g != nil {
    39  		t.Fatalf("got %#v; want nil", g)
    40  	}
    41  	Runtime_procUnpin()
    42  
    43  	p.Put("c")
    44  	debug.SetGCPercent(100) // to allow following GC to actually run
    45  	runtime.GC()
    46  	if g := p.Get(); g != nil {
    47  		t.Fatalf("got %#v; want nil after GC", g)
    48  	}
    49  }
    50  
    51  func TestPoolNew(t *testing.T) {
    52  	// disable GC so we can control when it happens.
    53  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
    54  
    55  	i := 0
    56  	p := Pool{
    57  		New: func() interface{} {
    58  			i++
    59  			return i
    60  		},
    61  	}
    62  	if v := p.Get(); v != 1 {
    63  		t.Fatalf("got %v; want 1", v)
    64  	}
    65  	if v := p.Get(); v != 2 {
    66  		t.Fatalf("got %v; want 2", v)
    67  	}
    68  
    69  	// Make sure that the goroutine doesn't migrate to another P
    70  	// between Put and Get calls.
    71  	Runtime_procPin()
    72  	p.Put(42)
    73  	if v := p.Get(); v != 42 {
    74  		t.Fatalf("got %v; want 42", v)
    75  	}
    76  	Runtime_procUnpin()
    77  
    78  	if v := p.Get(); v != 3 {
    79  		t.Fatalf("got %v; want 3", v)
    80  	}
    81  }
    82  
    83  // Test that Pool does not hold pointers to previously cached resources.
    84  func TestPoolGC(t *testing.T) {
    85  	testPool(t, true)
    86  }
    87  
    88  // Test that Pool releases resources on GC.
    89  func TestPoolRelease(t *testing.T) {
    90  	testPool(t, false)
    91  }
    92  
    93  func testPool(t *testing.T, drain bool) {
    94  	var p Pool
    95  	const N = 100
    96  loop:
    97  	for try := 0; try < 3; try++ {
    98  		var fin, fin1 uint32
    99  		for i := 0; i < N; i++ {
   100  			v := new(string)
   101  			runtime.SetFinalizer(v, func(vv *string) {
   102  				atomic.AddUint32(&fin, 1)
   103  			})
   104  			p.Put(v)
   105  		}
   106  		if drain {
   107  			for i := 0; i < N; i++ {
   108  				p.Get()
   109  			}
   110  		}
   111  		for i := 0; i < 5; i++ {
   112  			runtime.GC()
   113  			time.Sleep(time.Duration(i*100+10) * time.Millisecond)
   114  			// 1 pointer can remain on stack or elsewhere
   115  			if fin1 = atomic.LoadUint32(&fin); fin1 >= N-1 {
   116  				continue loop
   117  			}
   118  		}
   119  		t.Fatalf("only %v out of %v resources are finalized on try %v", fin1, N, try)
   120  	}
   121  }
   122  
   123  func TestPoolStress(t *testing.T) {
   124  	const P = 10
   125  	N := int(1e6)
   126  	if testing.Short() {
   127  		N /= 100
   128  	}
   129  	var p Pool
   130  	done := make(chan bool)
   131  	for i := 0; i < P; i++ {
   132  		go func() {
   133  			var v interface{} = 0
   134  			for j := 0; j < N; j++ {
   135  				if v == nil {
   136  					v = 0
   137  				}
   138  				p.Put(v)
   139  				v = p.Get()
   140  				if v != nil && v.(int) != 0 {
   141  					t.Errorf("expect 0, got %v", v)
   142  					break
   143  				}
   144  			}
   145  			done <- true
   146  		}()
   147  	}
   148  	for i := 0; i < P; i++ {
   149  		<-done
   150  	}
   151  }
   152  
   153  func BenchmarkPool(b *testing.B) {
   154  	var p Pool
   155  	b.RunParallel(func(pb *testing.PB) {
   156  		for pb.Next() {
   157  			p.Put(1)
   158  			p.Get()
   159  		}
   160  	})
   161  }
   162  
   163  func BenchmarkPoolOverflow(b *testing.B) {
   164  	var p Pool
   165  	b.RunParallel(func(pb *testing.PB) {
   166  		for pb.Next() {
   167  			for b := 0; b < 100; b++ {
   168  				p.Put(1)
   169  			}
   170  			for b := 0; b < 100; b++ {
   171  				p.Get()
   172  			}
   173  		}
   174  	})
   175  }