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 }