github.com/matrixorigin/matrixone@v1.2.0/pkg/common/reuse/pool_test.go (about)

     1  // Copyright 2023 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package reuse
    16  
    17  import (
    18  	"reflect"
    19  	"runtime/debug"
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  var (
    26  	providers = map[string]SPI{
    27  		"sync-pool": SyncBased,
    28  		"mpool":     MpoolBased,
    29  	}
    30  )
    31  
    32  func TestGetAndFree(t *testing.T) {
    33  	for name, spi := range providers {
    34  		t.Run(name, func(t *testing.T) {
    35  			for key := range pools {
    36  				delete(pools, key)
    37  			}
    38  			use(spi)
    39  			CreatePool[person](
    40  				func() *person { return &person{} },
    41  				func(p *person) {
    42  					names := p.names[:0]
    43  					*p = person{}
    44  					p.names = names
    45  				},
    46  				DefaultOptions[person](),
    47  			)
    48  
    49  			p := Alloc[person](nil)
    50  			assert.Empty(t, p.names)
    51  			assert.Equal(t, 0, p.age)
    52  			p.names = append(p.names, "hello")
    53  			p.age = 10
    54  			Free(p, nil)
    55  
    56  			p2 := Alloc[person](nil)
    57  			assert.Empty(t, p2.names)
    58  			assert.Equal(t, 0, p2.age)
    59  			Free(p2, nil)
    60  		})
    61  	}
    62  }
    63  
    64  func TestCheckDoubleFree(t *testing.T) {
    65  	RunReuseTests(func() {
    66  		for name, spi := range providers {
    67  			t.Run(name, func(t *testing.T) {
    68  				for key := range pools {
    69  					delete(pools, key)
    70  				}
    71  				use(spi)
    72  				CreatePool[person](
    73  					func() *person { return &person{} },
    74  					func(p *person) {
    75  						names := p.names[:0]
    76  						*p = person{}
    77  						p.names = names
    78  					},
    79  					DefaultOptions[person]().WithEnableChecker(),
    80  				)
    81  
    82  				p := Alloc[person](nil)
    83  				assert.Empty(t, p.names)
    84  				assert.Equal(t, 0, p.age)
    85  				p.names = append(p.names, "hello")
    86  				p.age = 10
    87  				Free(p, nil)
    88  
    89  				defer func() {
    90  					assert.NotNil(t, recover())
    91  				}()
    92  				Free(p, nil)
    93  			})
    94  		}
    95  	})
    96  }
    97  
    98  func TestCheckLeakFree(t *testing.T) {
    99  	RunReuseTests(func() {
   100  		for name, spi := range providers {
   101  			// mpool not support leak free check
   102  			if spi == MpoolBased {
   103  				continue
   104  			}
   105  
   106  			t.Run(name, func(t *testing.T) {
   107  				for key := range pools {
   108  					delete(pools, key)
   109  				}
   110  				use(spi)
   111  				CreatePool[person](
   112  					func() *person { return &person{} },
   113  					func(p *person) {
   114  						names := p.names[:0]
   115  						*p = person{}
   116  						p.names = names
   117  					},
   118  					DefaultOptions[person]().
   119  						WithEnableChecker().
   120  						withGCRecover(func() {
   121  							assert.NotNil(t, recover())
   122  						}),
   123  				)
   124  
   125  				p := Alloc[person](nil)
   126  				assert.Empty(t, p.names)
   127  				assert.Equal(t, 0, p.age)
   128  				p = nil
   129  				debug.FreeOSMemory()
   130  			})
   131  		}
   132  	})
   133  }
   134  
   135  func BenchmarkGet(b *testing.B) {
   136  	fn := func(spi SPI, b *testing.B) {
   137  		for key := range pools {
   138  			delete(pools, key)
   139  		}
   140  		use(SyncBased)
   141  		CreatePool[person](
   142  			func() *person { return &person{} },
   143  			func(p *person) {
   144  				names := p.names[:0]
   145  				*p = person{}
   146  				p.names = names
   147  			},
   148  			DefaultOptions[person](),
   149  		)
   150  		b.ResetTimer()
   151  
   152  		sum := uint64(0)
   153  		for i := 0; i < b.N; i++ {
   154  			p := Alloc[person](nil)
   155  			Free(p, nil)
   156  			sum++
   157  		}
   158  		_ = sum
   159  	}
   160  
   161  	b.Run("sync-pool", func(b *testing.B) {
   162  		fn(SyncBased, b)
   163  	})
   164  	b.Run("mpool", func(b *testing.B) {
   165  		fn(MpoolBased, b)
   166  	})
   167  }
   168  
   169  func BenchmarkGetParallel(b *testing.B) {
   170  	fn := func(spi SPI, b *testing.B) {
   171  		for key := range pools {
   172  			delete(pools, key)
   173  		}
   174  		use(SyncBased)
   175  		CreatePool[person](
   176  			func() *person { return &person{} },
   177  			func(p *person) {
   178  				names := p.names[:0]
   179  				*p = person{}
   180  				p.names = names
   181  			},
   182  			DefaultOptions[person](),
   183  		)
   184  		b.ResetTimer()
   185  
   186  		b.RunParallel(func(pb *testing.PB) {
   187  			sum := uint64(0)
   188  			for {
   189  				if pb.Next() {
   190  					p := Alloc[person](nil)
   191  					Free(p, nil)
   192  					sum++
   193  				} else {
   194  					break
   195  				}
   196  			}
   197  			_ = sum
   198  		})
   199  	}
   200  
   201  	b.Run("sync-pool", func(b *testing.B) {
   202  		fn(SyncBased, b)
   203  	})
   204  	b.Run("mpool", func(b *testing.B) {
   205  		fn(MpoolBased, b)
   206  	})
   207  }
   208  
   209  type person struct {
   210  	names []string
   211  	age   int
   212  }
   213  
   214  func (p person) TypeName() string {
   215  	return "person"
   216  }
   217  
   218  func TestTypeOf(t *testing.T) {
   219  	rt := reflect.TypeOf((*person)(nil))
   220  	want := reflect.ValueOf(rt).Pointer()
   221  	got := uintptr(typeOf[person]())
   222  	assert.Equal(t, want, got)
   223  }