blob: 9e5132bb18e168dfdb4dee96238f6150b5178202 [file] [log] [blame]
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -08001// 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
Dmitriy Vyukovce8045f2014-01-25 20:11:16 +04005// Pool is no-op under race detector, so all these tests do not work.
6// +build !race
7
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -08008package sync_test
9
10import (
11 "runtime"
12 "runtime/debug"
13 . "sync"
14 "sync/atomic"
15 "testing"
16 "time"
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -080017)
18
19func 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 }
Aliaksandr Valialkin3ea53cb2017-05-26 01:14:30 +030026
27 // Make sure that the goroutine doesn't migrate to another P
28 // between Put and Get calls.
29 Runtime_procPin()
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -080030 p.Put("a")
31 p.Put("b")
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -080032 if g := p.Get(); g != "a" {
33 t.Fatalf("got %#v; want a", g)
34 }
Dmitriy Vyukov8fc6ed42014-04-14 21:13:32 +040035 if g := p.Get(); g != "b" {
36 t.Fatalf("got %#v; want b", g)
37 }
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -080038 if g := p.Get(); g != nil {
39 t.Fatalf("got %#v; want nil", g)
40 }
Aliaksandr Valialkin3ea53cb2017-05-26 01:14:30 +030041 Runtime_procUnpin()
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -080042
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
51func 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 }
Aliaksandr Valialkin3ea53cb2017-05-26 01:14:30 +030068
69 // Make sure that the goroutine doesn't migrate to another P
70 // between Put and Get calls.
71 Runtime_procPin()
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -080072 p.Put(42)
73 if v := p.Get(); v != 42 {
74 t.Fatalf("got %v; want 42", v)
75 }
Aliaksandr Valialkin3ea53cb2017-05-26 01:14:30 +030076 Runtime_procUnpin()
77
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -080078 if v := p.Get(); v != 3 {
79 t.Fatalf("got %v; want 3", v)
80 }
81}
82
Dmitriy Vyukovaf3868f2014-10-22 20:23:49 +040083// Test that Pool does not hold pointers to previously cached resources.
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -080084func TestPoolGC(t *testing.T) {
Dmitriy Vyukovaf3868f2014-10-22 20:23:49 +040085 testPool(t, true)
86}
87
88// Test that Pool releases resources on GC.
89func TestPoolRelease(t *testing.T) {
90 testPool(t, false)
91}
92
93func testPool(t *testing.T, drain bool) {
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -080094 var p Pool
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -080095 const N = 100
Dmitriy Vyukovaf3868f2014-10-22 20:23:49 +040096loop:
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)
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -0800105 }
Dmitriy Vyukovaf3868f2014-10-22 20:23:49 +0400106 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)
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -0800120 }
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -0800121}
122
123func 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 {
Ian Lance Taylora1458902016-11-14 21:34:58 -0800141 t.Errorf("expect 0, got %v", v)
142 break
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -0800143 }
144 }
145 done <- true
146 }()
147 }
148 for i := 0; i < P; i++ {
149 <-done
150 }
151}
152
153func BenchmarkPool(b *testing.B) {
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -0800154 var p Pool
Dmitriy Vyukovec0c9f22014-02-25 14:39:12 +0400155 b.RunParallel(func(pb *testing.PB) {
156 for pb.Next() {
157 p.Put(1)
158 p.Get()
159 }
160 })
Dmitriy Vyukovf8e00572014-01-24 22:29:53 +0400161}
162
Josh Bleecher Snyder6b2aabe2014-07-17 12:50:56 -0700163func BenchmarkPoolOverflow(b *testing.B) {
Dmitriy Vyukovf8e00572014-01-24 22:29:53 +0400164 var p Pool
Dmitriy Vyukovec0c9f22014-02-25 14:39:12 +0400165 b.RunParallel(func(pb *testing.PB) {
166 for pb.Next() {
167 for b := 0; b < 100; b++ {
168 p.Put(1)
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -0800169 }
Dmitriy Vyukovec0c9f22014-02-25 14:39:12 +0400170 for b := 0; b < 100; b++ {
171 p.Get()
172 }
173 }
174 })
Brad Fitzpatrick8c6ef062013-12-18 11:08:34 -0800175}