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  }