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  }