Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 // Copyright 2013 The Go Authors. All rights reserved. | 1 // Copyright 2013 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package sync_test | 5 package sync_test |
6 | 6 |
7 import ( | 7 import ( |
8 "runtime" | 8 "runtime" |
9 "runtime/debug" | |
9 . "sync" | 10 . "sync" |
11 "sync/atomic" | |
10 "testing" | 12 "testing" |
13 "time" | |
14 "unsafe" | |
11 ) | 15 ) |
12 | 16 |
13 func TestPool(t *testing.T) { | 17 func TestPool(t *testing.T) { |
18 // disable GC so we can control when it happens. | |
19 defer debug.SetGCPercent(debug.SetGCPercent(-1)) | |
14 var p Pool | 20 var p Pool |
15 if p.Get() != nil { | 21 if p.Get() != nil { |
16 t.Fatal("expected empty") | 22 t.Fatal("expected empty") |
17 } | 23 } |
18 p.Put("a") | 24 p.Put("a") |
19 p.Put("b") | 25 p.Put("b") |
20 if g := p.Get(); g != "b" { | 26 if g := p.Get(); g != "b" { |
rsc
2013/12/18 02:01:30
i think you must accept nil here too, or else garb
bradfitz
2013/12/18 02:15:50
Fixed with: defer debug.SetGCPercent(debug.SetGCP
| |
21 t.Fatalf("got %#v; want b", g) | 27 t.Fatalf("got %#v; want b", g) |
22 } | 28 } |
23 if g := p.Get(); g != "a" { | 29 if g := p.Get(); g != "a" { |
24 t.Fatalf("got %#v; want a", g) | 30 t.Fatalf("got %#v; want a", g) |
25 } | 31 } |
26 if g := p.Get(); g != nil { | 32 if g := p.Get(); g != nil { |
27 t.Fatalf("got %#v; want nil", g) | 33 t.Fatalf("got %#v; want nil", g) |
28 } | 34 } |
29 | 35 |
30 p.Put("c") | 36 p.Put("c") |
37 debug.SetGCPercent(100) // to allow following GC to actually run | |
31 runtime.GC() | 38 runtime.GC() |
32 if g := p.Get(); g != nil { | 39 if g := p.Get(); g != nil { |
33 t.Fatalf("got %#v; want nil after GC", g) | 40 t.Fatalf("got %#v; want nil after GC", g) |
34 } | 41 } |
35 } | 42 } |
36 | 43 |
37 func BenchmarkPool1(b *testing.B) { | 44 func TestPoolNew(t *testing.T) { |
38 » var p Pool | 45 » // disable GC so we can control when it happens. |
39 » for i := 0; i < b.N; i++ { | 46 » defer debug.SetGCPercent(debug.SetGCPercent(-1)) |
40 » » p.Put(1) | 47 |
41 » » p.Get() | 48 » i := 0 |
49 » p := Pool{ | |
50 » » New: func() interface{} { | |
51 » » » i++ | |
52 » » » return i | |
53 » » }, | |
54 » } | |
55 » if v := p.Get(); v != 1 { | |
56 » » t.Fatalf("got %v; want 1", v) | |
57 » } | |
58 » if v := p.Get(); v != 2 { | |
59 » » t.Fatalf("got %v; want 2", v) | |
60 » } | |
61 » p.Put(42) | |
62 » if v := p.Get(); v != 42 { | |
63 » » t.Fatalf("got %v; want 42", v) | |
64 » } | |
65 » if v := p.Get(); v != 3 { | |
66 » » t.Fatalf("got %v; want 3", v) | |
42 } | 67 } |
43 } | 68 } |
44 | 69 |
45 func BenchmarkPool2(b *testing.B) { | 70 // Test that Pool does not hold pointers to previously cached |
46 » defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) | 71 // resources |
72 func TestPoolGC(t *testing.T) { | |
73 » var p Pool | |
74 » var fin uint32 | |
75 » const N = 100 | |
76 » for i := 0; i < N; i++ { | |
77 » » v := new(int) | |
78 » » runtime.SetFinalizer(v, func(vv *int) { | |
79 » » » atomic.AddUint32(&fin, 1) | |
80 » » }) | |
81 » » p.Put(v) | |
82 » } | |
83 » for i := 0; i < N; i++ { | |
84 » » p.Get() | |
85 » } | |
86 » for i := 0; i < 5; i++ { | |
87 » » runtime.GC() | |
88 » » time.Sleep(time.Millisecond) | |
89 » » // 1 pointer can remain on stack or elsewhere | |
90 » » if atomic.LoadUint32(&fin) >= N-1 { | |
91 » » » return | |
92 » » } | |
93 » } | |
94 » t.Fatalf("only %v out of %v resources are finalized", | |
95 » » atomic.LoadUint32(&fin), N) | |
96 } | |
97 | |
98 func TestPoolStress(t *testing.T) { | |
99 » const P = 10 | |
100 » N := int(1e6) | |
101 » if testing.Short() { | |
102 » » N /= 100 | |
103 » } | |
104 » var p Pool | |
105 » done := make(chan bool) | |
106 » for i := 0; i < P; i++ { | |
107 » » go func() { | |
108 » » » var v interface{} = 0 | |
109 » » » for j := 0; j < N; j++ { | |
110 » » » » if v == nil { | |
111 » » » » » v = 0 | |
112 » » » » } | |
113 » » » » p.Put(v) | |
114 » » » » v = p.Get() | |
115 » » » » if v != nil && v.(int) != 0 { | |
116 » » » » » t.Fatalf("expect 0, got %v", v) | |
117 » » » » } | |
118 » » » } | |
119 » » » done <- true | |
120 » » }() | |
121 » } | |
122 » for i := 0; i < P; i++ { | |
123 » » <-done | |
124 » } | |
125 } | |
126 | |
127 func BenchmarkPool(b *testing.B) { | |
128 » procs := runtime.GOMAXPROCS(-1) | |
129 » var dec func() bool | |
130 » if unsafe.Sizeof(b.N) == 8 { | |
131 » » n := int64(b.N) | |
132 » » dec = func() bool { | |
133 » » » return atomic.AddInt64(&n, -1) >= 0 | |
134 » » } | |
135 » } else { | |
136 » » n := int32(b.N) | |
137 » » dec = func() bool { | |
138 » » » return atomic.AddInt32(&n, -1) >= 0 | |
139 » » } | |
140 » } | |
47 var p Pool | 141 var p Pool |
48 var wg WaitGroup | 142 var wg WaitGroup |
49 » for i := 0; i < 2; i++ { | 143 » for i := 0; i < procs; i++ { |
50 wg.Add(1) | 144 wg.Add(1) |
51 go func() { | 145 go func() { |
52 defer wg.Done() | 146 defer wg.Done() |
53 » » » for i := 0; i < b.N; i += 2 { | 147 » » » for dec() { |
54 p.Put(1) | 148 p.Put(1) |
55 p.Get() | 149 p.Get() |
56 } | 150 } |
57 }() | 151 }() |
58 } | 152 } |
59 wg.Wait() | 153 wg.Wait() |
60 } | 154 } |
LEFT | RIGHT |