github.com/lrita/cache@v1.0.1/bufcache_test.go (about) 1 // Copyright 2018 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 package cache 6 7 import ( 8 "runtime" 9 "sync" 10 "testing" 11 "unsafe" 12 ) 13 14 func TestAlignBufCache(t *testing.T) { 15 if unsafe.Sizeof(bufCacheShard{})%128 != 0 { 16 t.Fatal("bufCacheShard is not aligned with 128") 17 } 18 if unsafe.Sizeof(bufCacheLocal{})%128 != 0 { 19 t.Fatal("bufCacheLocal is not aligned with 128") 20 } 21 } 22 23 func TestBufCacheConcurrent(t *testing.T) { 24 var ( 25 wg sync.WaitGroup 26 n = 2 * runtime.GOMAXPROCS(0) 27 c = &BufCache{New: func() []byte { return make([]byte, 8) }} 28 ) 29 30 for i := 0; i < n; i++ { 31 wg.Add(1) 32 go func() { 33 defer wg.Done() 34 for j := 0; j < 100; j++ { 35 o := c.Get() 36 o[0] = 'a' 37 runtime.Gosched() 38 c.Put(o) 39 runtime.Gosched() 40 } 41 }() 42 } 43 wg.Wait() 44 } 45 46 func TestBufCache(t *testing.T) { 47 var c BufCache 48 if c.Get() != nil { 49 t.Fatal("expected empty") 50 } 51 52 // Make sure that the goroutine doesn't migrate to another P 53 // between Put and Get calls. 54 runtime_procPin() 55 c.Put([]byte("a")) 56 c.Put([]byte("b")) 57 if g := string(c.Get()); g != "b" { 58 t.Fatalf("got %#v; want b", g) 59 } 60 if g := string(c.Get()); g != "a" { 61 t.Fatalf("got %#v; want a", g) 62 } 63 if g := string(c.Get()); g != "" { 64 t.Fatalf("got %#v; want nil", g) 65 } 66 67 a := []byte("aa") 68 for i := 0; i < bufCacheShardSize; i++ { 69 c.Put(a) 70 } 71 for i := 0; i < bufCacheShardSize; i++ { 72 if x := c.Get(); x == nil { 73 t.Fatal("expected empty") 74 } 75 } 76 77 for i := 0; i < bufCacheShardSize*2; i++ { 78 c.Put(a) 79 } 80 for i := 0; i < bufCacheShardSize*2; i++ { 81 x := c.Get() 82 if i < bufCacheShardSize { 83 if x == nil { 84 t.Fatal("unexpected empty") 85 } 86 } else if x != nil { 87 t.Fatal("expected empty") 88 } 89 } 90 runtime_procUnpin() 91 } 92 93 func TestBufCacheNew(t *testing.T) { 94 i := 0 95 p := BufCache{ 96 New: func() []byte { 97 i++ 98 return []byte{byte(i)} 99 }, 100 } 101 if v := p.Get(); v[0] != 1 { 102 t.Fatalf("got %v; want 1", v) 103 } 104 if v := p.Get(); v[0] != 2 { 105 t.Fatalf("got %v; want 2", v) 106 } 107 108 // Make sure that the goroutine doesn't migrate to another P 109 // between Put and Get calls. 110 runtime_procPin() 111 p.Put([]byte{byte(42)}) 112 if v := p.Get(); v[0] != 42 { 113 t.Fatalf("got %v; want 42", v) 114 } 115 runtime_procUnpin() 116 117 if v := p.Get(); v[0] != 3 { 118 t.Fatalf("got %v; want 3", v) 119 } 120 } 121 122 func TestBufCacheStress(t *testing.T) { 123 const P = 10 124 N := int(1e6) 125 if testing.Short() { 126 N /= 100 127 } 128 var c BufCache 129 done := make(chan bool) 130 for i := 0; i < P; i++ { 131 go func() { 132 v := []byte("aa") 133 for j := 0; j < N; j++ { 134 c.Put(v) 135 vv := c.Get() 136 if vv != nil && string(vv) != "aa" { 137 t.Errorf("expect aa, got %v", vv) 138 break 139 } 140 } 141 done <- true 142 }() 143 } 144 for i := 0; i < P; i++ { 145 <-done 146 } 147 } 148 149 // improve test coverage... 150 func TestBufCacheFillFull(t *testing.T) { 151 c := BufCache{Size: bufCacheShardSize} 152 d := make([]byte, 8) 153 for i := 0; i < bufCacheShardSize*4; i++ { 154 c.Put(d) 155 } 156 for i := 0; i < bufCacheShardSize*4; i++ { 157 c.Get() 158 } 159 for i := 0; i < bufCacheShardSize*4; i++ { 160 c.Put(d) 161 } 162 for i := 0; i < bufCacheShardSize*4; i++ { 163 c.Get() 164 } 165 } 166 167 func BenchmarkBufCache(b *testing.B) { 168 var c BufCache 169 a := make([]byte, 8) 170 b.RunParallel(func(pb *testing.PB) { 171 for pb.Next() { 172 c.Put(a) 173 c.Get() 174 } 175 }) 176 } 177 178 func BenchmarkBufCacheOverflow(b *testing.B) { 179 var c BufCache 180 a := make([]byte, 8) 181 b.RunParallel(func(pb *testing.PB) { 182 for pb.Next() { 183 for b := 0; b < 100; b++ { 184 c.Put(a) 185 } 186 for b := 0; b < 100; b++ { 187 c.Get() 188 } 189 } 190 }) 191 } 192 193 func BenchmarkBufCacheUnderflowUnbalanced(b *testing.B) { 194 var p BufCache 195 a := make([]byte, 8) 196 b.RunParallel(func(pb *testing.PB) { 197 for pb.Next() { 198 p.Put(a) 199 p.Get() 200 p.Get() 201 } 202 }) 203 } 204 205 func BenchmarkBufCacheOverflowUnbalanced(b *testing.B) { 206 var p BufCache 207 a := make([]byte, 8) 208 b.RunParallel(func(pb *testing.PB) { 209 for pb.Next() { 210 p.Put(a) 211 p.Put(a) 212 p.Get() 213 } 214 }) 215 } 216 217 func BenchmarkBufCacheSize100(b *testing.B) { 218 c := BufCache{Size: 100} 219 a := make([]byte, 8) 220 b.RunParallel(func(pb *testing.PB) { 221 for pb.Next() { 222 c.Put(a) 223 c.Get() 224 } 225 }) 226 } 227 228 func BenchmarkBufCacheSize100Overflow(b *testing.B) { 229 c := BufCache{Size: 100} 230 a := make([]byte, 8) 231 b.RunParallel(func(pb *testing.PB) { 232 for pb.Next() { 233 for b := 0; b < 100; b++ { 234 c.Put(a) 235 } 236 for b := 0; b < 100; b++ { 237 c.Get() 238 } 239 } 240 }) 241 } 242 243 func BenchmarkBufCacheSize100UnderflowUnbalanced(b *testing.B) { 244 p := BufCache{Size: 100} 245 a := make([]byte, 8) 246 b.RunParallel(func(pb *testing.PB) { 247 for pb.Next() { 248 p.Put(a) 249 p.Get() 250 p.Get() 251 } 252 }) 253 } 254 255 func BenchmarkBufCacheSize100OverflowUnbalanced(b *testing.B) { 256 p := BufCache{Size: 100} 257 a := make([]byte, 8) 258 b.RunParallel(func(pb *testing.PB) { 259 for pb.Next() { 260 p.Put(a) 261 p.Put(a) 262 p.Get() 263 } 264 }) 265 } 266 267 func BenchmarkBufCacheSize1K(b *testing.B) { 268 c := Cache{Size: 1024} 269 a := make([]byte, 8) 270 b.RunParallel(func(pb *testing.PB) { 271 for pb.Next() { 272 c.Put(a) 273 c.Get() 274 } 275 }) 276 } 277 278 func BenchmarkBufCacheSize1KOverflow(b *testing.B) { 279 c := BufCache{Size: 1024} 280 a := make([]byte, 8) 281 b.RunParallel(func(pb *testing.PB) { 282 for pb.Next() { 283 for b := 0; b < 100; b++ { 284 c.Put(a) 285 } 286 for b := 0; b < 100; b++ { 287 c.Get() 288 } 289 } 290 }) 291 } 292 293 func BenchmarkBufCacheSize1KUnderflowUnbalanced(b *testing.B) { 294 p := BufCache{Size: 1024} 295 a := make([]byte, 8) 296 b.RunParallel(func(pb *testing.PB) { 297 for pb.Next() { 298 p.Put(a) 299 p.Get() 300 p.Get() 301 } 302 }) 303 } 304 305 func BenchmarkBufCacheSize1KOverflowUnbalanced(b *testing.B) { 306 p := BufCache{Size: 1024} 307 a := make([]byte, 8) 308 b.RunParallel(func(pb *testing.PB) { 309 for pb.Next() { 310 p.Put(a) 311 p.Put(a) 312 p.Get() 313 } 314 }) 315 }