github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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  	p.Put("a")
    27  	p.Put("b")
    28  	if g := p.Get(); g != "a" {
    29  		t.Fatalf("got %#v; want a", g)
    30  	}
    31  	if g := p.Get(); g != "b" {
    32  		t.Fatalf("got %#v; want b", g)
    33  	}
    34  	if g := p.Get(); g != nil {
    35  		t.Fatalf("got %#v; want nil", g)
    36  	}
    37  
    38  	p.Put("c")
    39  	debug.SetGCPercent(100) // to allow following GC to actually run
    40  	runtime.GC()
    41  	if g := p.Get(); g != nil {
    42  		t.Fatalf("got %#v; want nil after GC", g)
    43  	}
    44  }
    45  
    46  func TestPoolNew(t *testing.T) {
    47  	// disable GC so we can control when it happens.
    48  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
    49  
    50  	i := 0
    51  	p := Pool{
    52  		New: func() interface{} {
    53  			i++
    54  			return i
    55  		},
    56  	}
    57  	if v := p.Get(); v != 1 {
    58  		t.Fatalf("got %v; want 1", v)
    59  	}
    60  	if v := p.Get(); v != 2 {
    61  		t.Fatalf("got %v; want 2", v)
    62  	}
    63  	p.Put(42)
    64  	if v := p.Get(); v != 42 {
    65  		t.Fatalf("got %v; want 42", v)
    66  	}
    67  	if v := p.Get(); v != 3 {
    68  		t.Fatalf("got %v; want 3", v)
    69  	}
    70  }
    71  
    72  // Test that Pool does not hold pointers to previously cached resources.
    73  func TestPoolGC(t *testing.T) {
    74  	testPool(t, true)
    75  }
    76  
    77  // Test that Pool releases resources on GC.
    78  func TestPoolRelease(t *testing.T) {
    79  	testPool(t, false)
    80  }
    81  
    82  func testPool(t *testing.T, drain bool) {
    83  	var p Pool
    84  	const N = 100
    85  loop:
    86  	for try := 0; try < 3; try++ {
    87  		var fin, fin1 uint32
    88  		for i := 0; i < N; i++ {
    89  			v := new(string)
    90  			runtime.SetFinalizer(v, func(vv *string) {
    91  				atomic.AddUint32(&fin, 1)
    92  			})
    93  			p.Put(v)
    94  		}
    95  		if drain {
    96  			for i := 0; i < N; i++ {
    97  				p.Get()
    98  			}
    99  		}
   100  		for i := 0; i < 5; i++ {
   101  			runtime.GC()
   102  			time.Sleep(time.Duration(i*100+10) * time.Millisecond)
   103  			// 1 pointer can remain on stack or elsewhere
   104  			if fin1 = atomic.LoadUint32(&fin); fin1 >= N-1 {
   105  				continue loop
   106  			}
   107  		}
   108  		t.Fatalf("only %v out of %v resources are finalized on try %v", fin1, N, try)
   109  	}
   110  }
   111  
   112  func TestPoolStress(t *testing.T) {
   113  	const P = 10
   114  	N := int(1e6)
   115  	if testing.Short() {
   116  		N /= 100
   117  	}
   118  	var p Pool
   119  	done := make(chan bool)
   120  	for i := 0; i < P; i++ {
   121  		go func() {
   122  			var v interface{} = 0
   123  			for j := 0; j < N; j++ {
   124  				if v == nil {
   125  					v = 0
   126  				}
   127  				p.Put(v)
   128  				v = p.Get()
   129  				if v != nil && v.(int) != 0 {
   130  					t.Errorf("expect 0, got %v", v)
   131  					break
   132  				}
   133  			}
   134  			done <- true
   135  		}()
   136  	}
   137  	for i := 0; i < P; i++ {
   138  		<-done
   139  	}
   140  }
   141  
   142  func BenchmarkPool(b *testing.B) {
   143  	var p Pool
   144  	b.RunParallel(func(pb *testing.PB) {
   145  		for pb.Next() {
   146  			p.Put(1)
   147  			p.Get()
   148  		}
   149  	})
   150  }
   151  
   152  func BenchmarkPoolOverflow(b *testing.B) {
   153  	var p Pool
   154  	b.RunParallel(func(pb *testing.PB) {
   155  		for pb.Next() {
   156  			for b := 0; b < 100; b++ {
   157  				p.Put(1)
   158  			}
   159  			for b := 0; b < 100; b++ {
   160  				p.Get()
   161  			}
   162  		}
   163  	})
   164  }