codeberg.org/gruf/go-pools@v1.1.0/pool_test.go (about)

     1  package pools_test
     2  
     3  import (
     4  	"sync"
     5  	"sync/atomic"
     6  	"testing"
     7  	"time"
     8  
     9  	"codeberg.org/gruf/go-pools"
    10  )
    11  
    12  type badPool struct {
    13  	New   func() interface{}
    14  	Evict func(interface{})
    15  	pool  []interface{}
    16  	mu    sync.Mutex
    17  }
    18  
    19  func (p *badPool) startEvicts() {
    20  	for {
    21  		time.Sleep(time.Second)
    22  		p.mu.Lock()
    23  		if len(p.pool) > 1 {
    24  			l := len(p.pool) - 1
    25  			v := p.pool[l]
    26  			p.pool = p.pool[:l-1]
    27  			p.Evict(v)
    28  		}
    29  		p.mu.Unlock()
    30  	}
    31  }
    32  
    33  func (p *badPool) Get() interface{} {
    34  	p.mu.Lock()
    35  	if len(p.pool) < 1 {
    36  		p.mu.Unlock()
    37  		return p.New()
    38  	}
    39  	l := len(p.pool) - 1
    40  	v := p.pool[l]
    41  	p.pool = p.pool[:l]
    42  	p.mu.Unlock()
    43  	return v
    44  }
    45  
    46  func (p *badPool) Put(v interface{}) {
    47  	if v == nil {
    48  		return
    49  	}
    50  	p.mu.Lock()
    51  	p.pool = append(p.pool, v)
    52  	p.mu.Unlock()
    53  }
    54  
    55  type testItem struct {
    56  	i int32
    57  }
    58  
    59  func (i *testItem) check() bool {
    60  	defer atomic.StoreInt32(&i.i, 0)
    61  	return atomic.CompareAndSwapInt32(&i.i, 0, 1)
    62  }
    63  
    64  func BenchmarkPool(b *testing.B) {
    65  	p := &pools.Pool{}
    66  
    67  	p.New = func() interface{} {
    68  		return &testItem{}
    69  	}
    70  
    71  	p.Evict = func(i interface{}) {
    72  		if !i.(*testItem).check() {
    73  			panic("in use during eviction")
    74  		}
    75  	}
    76  
    77  	b.ResetTimer()
    78  	b.ReportAllocs()
    79  	b.RunParallel(func(pb *testing.PB) {
    80  		for pb.Next() {
    81  			i := p.Get().(*testItem)
    82  			if !i.check() {
    83  				panic("in use after get")
    84  			}
    85  			p.Put(i)
    86  		}
    87  	})
    88  }
    89  
    90  func BenchmarkSyncPool(b *testing.B) {
    91  	p := sync.Pool{}
    92  
    93  	p.New = func() interface{} {
    94  		return &testItem{}
    95  	}
    96  
    97  	b.ResetTimer()
    98  	b.ReportAllocs()
    99  	b.RunParallel(func(pb *testing.PB) {
   100  		for pb.Next() {
   101  			i := p.Get().(*testItem)
   102  			if !i.check() {
   103  				panic("in use after get")
   104  			}
   105  			p.Put(i)
   106  		}
   107  	})
   108  }
   109  
   110  func BenchmarkBadPool(b *testing.B) {
   111  	p := badPool{}
   112  	go p.startEvicts()
   113  
   114  	p.New = func() interface{} {
   115  		return &testItem{}
   116  	}
   117  
   118  	p.Evict = func(i interface{}) {
   119  		if !i.(*testItem).check() {
   120  			panic("in use during eviction")
   121  		}
   122  	}
   123  
   124  	b.ResetTimer()
   125  	b.ReportAllocs()
   126  	b.RunParallel(func(pb *testing.PB) {
   127  		for pb.Next() {
   128  			i := p.Get().(*testItem)
   129  			if !i.check() {
   130  				panic("in use after get")
   131  			}
   132  			p.Put(i)
   133  		}
   134  	})
   135  }