github.com/yukk001/go1.10.8@v0.0.0-20190813125351-6df2d3982e20/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 }