github.com/lrita/cache@v1.0.1/cache_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 TestAlign(t *testing.T) { 15 if unsafe.Sizeof(cacheShard{})%128 != 0 { 16 t.Fatal("cacheShard is not aligned with 128") 17 } 18 if unsafe.Sizeof(cacheLocal{})%128 != 0 { 19 t.Fatal("cacheLocal is not aligned with 128") 20 } 21 } 22 23 func TestCacheConcurrent(t *testing.T) { 24 type obj struct { 25 x int 26 } 27 var ( 28 wg sync.WaitGroup 29 n = 2 * runtime.GOMAXPROCS(0) 30 c = &Cache{New: func() interface{} { return new(obj) }} 31 ) 32 33 for i := 0; i < n; i++ { 34 wg.Add(1) 35 go func() { 36 defer wg.Done() 37 for j := 0; j < 100; j++ { 38 o := c.Get().(*obj) 39 o.x = 1 40 runtime.Gosched() 41 c.Put(o) 42 runtime.Gosched() 43 } 44 }() 45 } 46 wg.Wait() 47 } 48 49 func TestPool(t *testing.T) { 50 var c Cache 51 if c.Get() != nil { 52 t.Fatal("expected empty") 53 } 54 55 // Make sure that the goroutine doesn't migrate to another P 56 // between Put and Get calls. 57 runtime_procPin() 58 c.Put("a") 59 c.Put("b") 60 if g := c.Get(); g != "b" { 61 t.Fatalf("got %#v; want b", g) 62 } 63 if g := c.Get(); g != "a" { 64 t.Fatalf("got %#v; want a", g) 65 } 66 if g := c.Get(); g != nil { 67 t.Fatalf("got %#v; want nil", g) 68 } 69 70 for i := 0; i < cacheShardSize; i++ { 71 c.Put(i) 72 } 73 for i := 0; i < cacheShardSize; i++ { 74 if x := c.Get(); x == nil { 75 t.Fatal("expected empty") 76 } 77 } 78 79 for i := 0; i < cacheShardSize*2; i++ { 80 c.Put(i) 81 } 82 for i := 0; i < cacheShardSize*2; i++ { 83 x := c.Get() 84 if i < cacheShardSize { 85 if x == nil { 86 t.Fatal("unexpected empty") 87 } 88 } else if x != nil { 89 t.Fatal("expected empty") 90 } 91 } 92 runtime_procUnpin() 93 } 94 95 // improve test coverage... 96 func TestCacheFillFull(t *testing.T) { 97 c := Cache{Size: cacheShardSize} 98 for i := 0; i < cacheShardSize*4; i++ { 99 c.Put(1) 100 } 101 for i := 0; i < cacheShardSize*4; i++ { 102 c.Get() 103 } 104 for i := 0; i < cacheShardSize*4; i++ { 105 c.Put(1) 106 } 107 for i := 0; i < cacheShardSize*4; i++ { 108 c.Get() 109 } 110 } 111 112 func TestPoolNew(t *testing.T) { 113 i := 0 114 p := Cache{ 115 New: func() interface{} { 116 i++ 117 return i 118 }, 119 } 120 if v := p.Get(); v != 1 { 121 t.Fatalf("got %v; want 1", v) 122 } 123 if v := p.Get(); v != 2 { 124 t.Fatalf("got %v; want 2", v) 125 } 126 127 // Make sure that the goroutine doesn't migrate to another P 128 // between Put and Get calls. 129 runtime_procPin() 130 p.Put(42) 131 if v := p.Get(); v != 42 { 132 t.Fatalf("got %v; want 42", v) 133 } 134 runtime_procUnpin() 135 136 if v := p.Get(); v != 3 { 137 t.Fatalf("got %v; want 3", v) 138 } 139 } 140 141 func TestCacheStress(t *testing.T) { 142 const P = 10 143 N := int(1e6) 144 if testing.Short() { 145 N /= 100 146 } 147 var c Cache 148 done := make(chan bool) 149 for i := 0; i < P; i++ { 150 go func() { 151 var v interface{} = 0 152 for j := 0; j < N; j++ { 153 if v == nil { 154 v = 0 155 } 156 c.Put(v) 157 v = c.Get() 158 if v != nil && v.(int) != 0 { 159 t.Errorf("expect 0, got %v", v) 160 break 161 } 162 } 163 done <- true 164 }() 165 } 166 for i := 0; i < P; i++ { 167 <-done 168 } 169 } 170 171 func BenchmarkCache(b *testing.B) { 172 var c Cache 173 b.RunParallel(func(pb *testing.PB) { 174 for pb.Next() { 175 c.Put(1) 176 c.Get() 177 } 178 }) 179 } 180 181 func BenchmarkCacheOverflow(b *testing.B) { 182 var c Cache 183 b.RunParallel(func(pb *testing.PB) { 184 for pb.Next() { 185 for b := 0; b < 100; b++ { 186 c.Put(1) 187 } 188 for b := 0; b < 100; b++ { 189 c.Get() 190 } 191 } 192 }) 193 } 194 195 func BenchmarkCacheUnderflowUnbalanced(b *testing.B) { 196 var p Cache 197 b.RunParallel(func(pb *testing.PB) { 198 for pb.Next() { 199 p.Put(1) 200 p.Get() 201 p.Get() 202 } 203 }) 204 } 205 206 func BenchmarkCacheOverflowUnbalanced(b *testing.B) { 207 var p Cache 208 b.RunParallel(func(pb *testing.PB) { 209 for pb.Next() { 210 p.Put(1) 211 p.Put(1) 212 p.Get() 213 } 214 }) 215 } 216 217 func BenchmarkCacheSize100(b *testing.B) { 218 c := Cache{Size: 100} 219 b.RunParallel(func(pb *testing.PB) { 220 for pb.Next() { 221 c.Put(1) 222 c.Get() 223 } 224 }) 225 } 226 227 func BenchmarkCacheSize100Overflow(b *testing.B) { 228 c := Cache{Size: 100} 229 b.RunParallel(func(pb *testing.PB) { 230 for pb.Next() { 231 for b := 0; b < 100; b++ { 232 c.Put(1) 233 } 234 for b := 0; b < 100; b++ { 235 c.Get() 236 } 237 } 238 }) 239 } 240 241 func BenchmarkCacheSize100UnderflowUnbalanced(b *testing.B) { 242 p := Cache{Size: 100} 243 b.RunParallel(func(pb *testing.PB) { 244 for pb.Next() { 245 p.Put(1) 246 p.Get() 247 p.Get() 248 } 249 }) 250 } 251 252 func BenchmarkCacheSize100OverflowUnbalanced(b *testing.B) { 253 p := Cache{Size: 100} 254 b.RunParallel(func(pb *testing.PB) { 255 for pb.Next() { 256 p.Put(1) 257 p.Put(1) 258 p.Get() 259 } 260 }) 261 } 262 263 func BenchmarkCacheSize1K(b *testing.B) { 264 c := Cache{Size: 1024} 265 b.RunParallel(func(pb *testing.PB) { 266 for pb.Next() { 267 c.Put(1) 268 c.Get() 269 } 270 }) 271 } 272 273 func BenchmarkCacheSize1KOverflow(b *testing.B) { 274 c := Cache{Size: 1024} 275 b.RunParallel(func(pb *testing.PB) { 276 for pb.Next() { 277 for b := 0; b < 100; b++ { 278 c.Put(1) 279 } 280 for b := 0; b < 100; b++ { 281 c.Get() 282 } 283 } 284 }) 285 } 286 287 func BenchmarkCacheSize1KUnderflowUnbalanced(b *testing.B) { 288 p := Cache{Size: 1024} 289 b.RunParallel(func(pb *testing.PB) { 290 for pb.Next() { 291 p.Put(1) 292 p.Get() 293 p.Get() 294 } 295 }) 296 } 297 298 func BenchmarkCacheSize1KOverflowUnbalanced(b *testing.B) { 299 p := Cache{Size: 1024} 300 b.RunParallel(func(pb *testing.PB) { 301 for pb.Next() { 302 p.Put(1) 303 p.Put(1) 304 p.Get() 305 } 306 }) 307 } 308 309 func BenchmarkSyncPool(b *testing.B) { 310 var c sync.Pool 311 b.RunParallel(func(pb *testing.PB) { 312 for pb.Next() { 313 c.Put(1) 314 c.Get() 315 } 316 }) 317 } 318 319 func BenchmarkSyncPoolOverflow(b *testing.B) { 320 var c sync.Pool 321 b.RunParallel(func(pb *testing.PB) { 322 for pb.Next() { 323 for b := 0; b < 100; b++ { 324 c.Put(1) 325 } 326 for b := 0; b < 100; b++ { 327 c.Get() 328 } 329 } 330 }) 331 } 332 333 func BenchmarkSyncPoolUnderflowUnbalanced(b *testing.B) { 334 var p sync.Pool 335 b.RunParallel(func(pb *testing.PB) { 336 for pb.Next() { 337 p.Put(1) 338 p.Get() 339 p.Get() 340 } 341 }) 342 } 343 344 func BenchmarkSyncPoolOverflowUnbalanced(b *testing.B) { 345 var p sync.Pool 346 b.RunParallel(func(pb *testing.PB) { 347 for pb.Next() { 348 p.Put(1) 349 p.Put(1) 350 p.Get() 351 } 352 }) 353 }