Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 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 | |
Dmitriy Vyukov | ce8045f | 2014-01-25 20:11:16 +0400 | [diff] [blame] | 5 | // Pool is no-op under race detector, so all these tests do not work. |
| 6 | // +build !race |
| 7 | |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 8 | package sync_test |
| 9 | |
| 10 | import ( |
| 11 | "runtime" |
| 12 | "runtime/debug" |
| 13 | . "sync" |
| 14 | "sync/atomic" |
| 15 | "testing" |
| 16 | "time" |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 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 | } |
Aliaksandr Valialkin | 3ea53cb | 2017-05-26 01:14:30 +0300 | [diff] [blame] | 26 | |
| 27 | // Make sure that the goroutine doesn't migrate to another P |
| 28 | // between Put and Get calls. |
| 29 | Runtime_procPin() |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 30 | p.Put("a") |
| 31 | p.Put("b") |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 32 | if g := p.Get(); g != "a" { |
| 33 | t.Fatalf("got %#v; want a", g) |
| 34 | } |
Dmitriy Vyukov | 8fc6ed4 | 2014-04-14 21:13:32 +0400 | [diff] [blame] | 35 | if g := p.Get(); g != "b" { |
| 36 | t.Fatalf("got %#v; want b", g) |
| 37 | } |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 38 | if g := p.Get(); g != nil { |
| 39 | t.Fatalf("got %#v; want nil", g) |
| 40 | } |
Aliaksandr Valialkin | 3ea53cb | 2017-05-26 01:14:30 +0300 | [diff] [blame] | 41 | Runtime_procUnpin() |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 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 | } |
Aliaksandr Valialkin | 3ea53cb | 2017-05-26 01:14:30 +0300 | [diff] [blame] | 68 | |
| 69 | // Make sure that the goroutine doesn't migrate to another P |
| 70 | // between Put and Get calls. |
| 71 | Runtime_procPin() |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 72 | p.Put(42) |
| 73 | if v := p.Get(); v != 42 { |
| 74 | t.Fatalf("got %v; want 42", v) |
| 75 | } |
Aliaksandr Valialkin | 3ea53cb | 2017-05-26 01:14:30 +0300 | [diff] [blame] | 76 | Runtime_procUnpin() |
| 77 | |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 78 | if v := p.Get(); v != 3 { |
| 79 | t.Fatalf("got %v; want 3", v) |
| 80 | } |
| 81 | } |
| 82 | |
Dmitriy Vyukov | af3868f | 2014-10-22 20:23:49 +0400 | [diff] [blame] | 83 | // Test that Pool does not hold pointers to previously cached resources. |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 84 | func TestPoolGC(t *testing.T) { |
Dmitriy Vyukov | af3868f | 2014-10-22 20:23:49 +0400 | [diff] [blame] | 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) { |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 94 | var p Pool |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 95 | const N = 100 |
Dmitriy Vyukov | af3868f | 2014-10-22 20:23:49 +0400 | [diff] [blame] | 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) |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 105 | } |
Dmitriy Vyukov | af3868f | 2014-10-22 20:23:49 +0400 | [diff] [blame] | 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) |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 120 | } |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 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 { |
Ian Lance Taylor | a145890 | 2016-11-14 21:34:58 -0800 | [diff] [blame] | 141 | t.Errorf("expect 0, got %v", v) |
| 142 | break |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 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) { |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 154 | var p Pool |
Dmitriy Vyukov | ec0c9f2 | 2014-02-25 14:39:12 +0400 | [diff] [blame] | 155 | b.RunParallel(func(pb *testing.PB) { |
| 156 | for pb.Next() { |
| 157 | p.Put(1) |
| 158 | p.Get() |
| 159 | } |
| 160 | }) |
Dmitriy Vyukov | f8e0057 | 2014-01-24 22:29:53 +0400 | [diff] [blame] | 161 | } |
| 162 | |
Josh Bleecher Snyder | 6b2aabe | 2014-07-17 12:50:56 -0700 | [diff] [blame] | 163 | func BenchmarkPoolOverflow(b *testing.B) { |
Dmitriy Vyukov | f8e0057 | 2014-01-24 22:29:53 +0400 | [diff] [blame] | 164 | var p Pool |
Dmitriy Vyukov | ec0c9f2 | 2014-02-25 14:39:12 +0400 | [diff] [blame] | 165 | b.RunParallel(func(pb *testing.PB) { |
| 166 | for pb.Next() { |
| 167 | for b := 0; b < 100; b++ { |
| 168 | p.Put(1) |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 169 | } |
Dmitriy Vyukov | ec0c9f2 | 2014-02-25 14:39:12 +0400 | [diff] [blame] | 170 | for b := 0; b < 100; b++ { |
| 171 | p.Get() |
| 172 | } |
| 173 | } |
| 174 | }) |
Brad Fitzpatrick | 8c6ef06 | 2013-12-18 11:08:34 -0800 | [diff] [blame] | 175 | } |