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 TestPoolNumGC(t *testing.T) { | |
14 var n1, n2 uint32 | |
15 runtime.GC() | |
16 Sync_readNumGC(&n1) | |
17 runtime.GC() | |
18 Sync_readNumGC(&n2) | |
19 if n2 <= n1 { | |
20 t.Errorf("gc count didn't increment: %d -> %d", n1, n2) | |
21 } | |
22 } | |
23 | |
24 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)) |
25 var p Pool | 20 var p Pool |
26 if p.Get() != nil { | 21 if p.Get() != nil { |
27 t.Fatal("expected empty") | 22 t.Fatal("expected empty") |
28 } | 23 } |
29 p.Put("a") | 24 p.Put("a") |
30 p.Put("b") | 25 p.Put("b") |
31 if g := p.Get(); g != "b" { | 26 if g := p.Get(); g != "b" { |
32 t.Fatalf("got %#v; want b", g) | 27 t.Fatalf("got %#v; want b", g) |
33 } | 28 } |
34 if g := p.Get(); g != "a" { | 29 if g := p.Get(); g != "a" { |
35 t.Fatalf("got %#v; want a", g) | 30 t.Fatalf("got %#v; want a", g) |
36 } | 31 } |
37 if g := p.Get(); g != nil { | 32 if g := p.Get(); g != nil { |
38 t.Fatalf("got %#v; want nil", g) | 33 t.Fatalf("got %#v; want nil", g) |
39 } | 34 } |
40 | 35 |
41 p.Put("c") | 36 p.Put("c") |
| 37 debug.SetGCPercent(100) // to allow following GC to actually run |
42 runtime.GC() | 38 runtime.GC() |
43 if g := p.Get(); g != nil { | 39 if g := p.Get(); g != nil { |
44 t.Fatalf("got %#v; want nil after GC", g) | 40 t.Fatalf("got %#v; want nil after GC", g) |
45 } | 41 } |
46 } | 42 } |
47 | 43 |
48 func BenchmarkPool1(b *testing.B) { | 44 func TestPoolNew(t *testing.T) { |
49 » var p Pool | 45 » // disable GC so we can control when it happens. |
50 » for i := 0; i < b.N; i++ { | 46 » defer debug.SetGCPercent(debug.SetGCPercent(-1)) |
51 » » p.Put(1) | 47 |
52 » » 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) |
53 } | 67 } |
54 } | 68 } |
55 | 69 |
56 func BenchmarkPool2(b *testing.B) { | 70 // Test that Pool does not hold pointers to previously cached |
57 » 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 » } |
58 var p Pool | 141 var p Pool |
59 var wg WaitGroup | 142 var wg WaitGroup |
60 » for i := 0; i < 2; i++ { | 143 » for i := 0; i < procs; i++ { |
61 wg.Add(1) | 144 wg.Add(1) |
62 go func() { | 145 go func() { |
63 defer wg.Done() | 146 defer wg.Done() |
64 » » » for i := 0; i < b.N; i += 2 { | 147 » » » for dec() { |
65 p.Put(1) | 148 p.Put(1) |
66 p.Get() | 149 p.Get() |
67 } | 150 } |
68 }() | 151 }() |
69 } | 152 } |
70 wg.Wait() | 153 wg.Wait() |
71 } | 154 } |
LEFT | RIGHT |