github.com/userpro/linearpool@v0.5.3-0.20231115092206-0ca073169b71/memorypool_test.go (about)

     1  package memorypool
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"runtime"
     7  	"strconv"
     8  	"testing"
     9  	"unsafe"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  )
    13  
    14  type testNewF struct {
    15  	t  []*testNew
    16  	t1 [16]int
    17  }
    18  
    19  type testNew struct {
    20  	a string
    21  	b int
    22  }
    23  
    24  func TestNew(t *testing.T) {
    25  	ac := NewAlloctorFromPool(0)
    26  	a := New[testNew](ac)
    27  	a.a = ac.NewString("hello")
    28  	a.b = 12
    29  	t.Logf("%s %d\n", a.a, a.b)
    30  	ac.Debug()
    31  	runtime.GC()
    32  	ac.Debug()
    33  	assert.EqualValues(t, a.a, "hello")
    34  	assert.EqualValues(t, a.b, 12)
    35  	runtime.KeepAlive(ac)
    36  }
    37  
    38  func TestNewSlice(t *testing.T) {
    39  	ac := NewAlloctorFromPool(0)
    40  	tmpInt := rand.Int31()
    41  	f := func(tmpstr []byte) *testNewF {
    42  		tf := New[testNewF](ac)
    43  		a := NewSlice[*testNew](ac, 1, 1)
    44  
    45  		t1 := New[testNew](ac)
    46  		t1.a = "anihao" // 常量字符串可以这么操作
    47  		t1.b = 12
    48  
    49  		t2 := New[testNew](ac)
    50  		t2.a = "anihao2" + string(tmpstr)
    51  		t2.b = 122
    52  
    53  		a = AppendMulti[*testNew](ac, a, t1, t2)
    54  		tf.t = a
    55  		return tf
    56  	}
    57  	tf := f([]byte(strconv.Itoa(int(tmpInt))))
    58  
    59  	b := NewSlice[testNew](ac, 0, 100)
    60  	b = AppendMulti[testNew](ac, b, []testNew{{a: "bnihaob", b: 123}}...)
    61  
    62  	runtime.GC()
    63  
    64  	assert.EqualValues(t, "anihao", tf.t[1].a)
    65  	assert.EqualValues(t, 12, tf.t[1].b)
    66  	assert.EqualValues(t, "anihao2"+strconv.Itoa(int(tmpInt)), tf.t[2].a)
    67  	assert.EqualValues(t, 122, tf.t[2].b)
    68  
    69  	assert.EqualValues(t, "bnihaob", b[0].a)
    70  	assert.EqualValues(t, 123, b[0].b)
    71  	runtime.KeepAlive(ac)
    72  }
    73  
    74  func TestSliceAppend(t *testing.T) {
    75  	maxn := 50_000
    76  	ac := NewAlloctorFromPool(0)
    77  	a := NewSlice[testNew](ac, 0, 1)
    78  	for i := 0; i < maxn; i++ {
    79  		a = AppendMulti[testNew](ac, a, []testNew{{a: "nihao", b: 12}, {a: "nihao2", b: 21}}...)
    80  	}
    81  	t.Logf("%s %d\n", a[0].a, a[0].b)
    82  	t.Logf("[first] bidx: %d, blocks: %d\n", ac.bidx, len(ac.blocks))
    83  	assert.EqualValues(t, len(a), maxn*2)
    84  
    85  	for i := 0; i < maxn; i++ {
    86  		if i%2 != 0 {
    87  			assert.EqualValues(t, a[i].a, "nihao2")
    88  			assert.EqualValues(t, a[i].b, 21)
    89  		} else {
    90  			assert.EqualValues(t, a[i].a, "nihao")
    91  			assert.EqualValues(t, a[i].b, 12)
    92  		}
    93  	}
    94  
    95  	ac.ReturnAlloctorToPool()
    96  
    97  	ac = NewAlloctorFromPool(0)
    98  	a = NewSlice[testNew](ac, 0, 1)
    99  	for i := 0; i < maxn; i++ {
   100  		a = AppendMulti[testNew](ac, a, []testNew{{a: "nihao", b: 12}, {a: "nihao2", b: 21}}...)
   101  	}
   102  	t.Logf("[second] bidx: %d, blocks: %d\n", ac.bidx, len(ac.blocks))
   103  	runtime.KeepAlive(ac)
   104  }
   105  
   106  // TestSliceAppend1 交错slice append
   107  func TestSliceAppend1(t *testing.T) {
   108  	ac := NewAlloctorFromPool(0)
   109  	a1 := NewSlice[int](ac, 0, 1)
   110  	a1 = AppendMulti[int](ac, a1, []int{1, 2}...) // 扩容
   111  	a2 := NewSlice[int](ac, 0, 2)
   112  	a2 = AppendMulti[int](ac, a2, []int{3, 4}...) // 不扩容
   113  	a3 := NewSlice[int](ac, 0, 1)
   114  	a3 = AppendMulti[int](ac, a3, []int{5, 6}...) // 扩容
   115  
   116  	assert.EqualValues(t, 1, a1[0])
   117  	assert.EqualValues(t, 2, a1[1])
   118  	assert.EqualValues(t, 3, a2[0])
   119  	assert.EqualValues(t, 4, a2[1])
   120  	assert.EqualValues(t, 5, a3[0])
   121  	assert.EqualValues(t, 6, a3[1])
   122  
   123  	runtime.KeepAlive(ac)
   124  }
   125  
   126  // TestSliceAppend2 slice 扩容机制
   127  func TestSliceAppend2(t *testing.T) {
   128  	ac := NewAlloctorFromPool(0)
   129  	a1 := NewSlice[int](ac, 0, 1)
   130  	for i := 0; i < 10_000; i++ {
   131  		a1 = AppendMulti[int](ac, a1, []int{1, 2}...) // 扩容
   132  		// t.Log(len(a1), cap(a1))
   133  		assert.EqualValues(t, roundupsize(uintptr(len(a1))), cap(a1))
   134  	}
   135  	for i := 0; i < 10_000; i++ {
   136  		if i&1 == 0 {
   137  			assert.EqualValues(t, 1, a1[i])
   138  		} else {
   139  			assert.EqualValues(t, 2, a1[i])
   140  		}
   141  	}
   142  
   143  	runtime.KeepAlive(ac)
   144  }
   145  
   146  // TestSliceAppendInplace3 slice 原地扩容机制
   147  func TestSliceAppendInplace3(t *testing.T) {
   148  	ac := NewAlloctorFromPool(0)
   149  	a1 := NewSlice[int](ac, 0, 1)
   150  	for i := 0; i < 100_000; i++ {
   151  		a1 = AppendInplaceMulti[int](ac, a1, []int{1, 2}...) // 扩容
   152  		assert.EqualValues(t, roundupsize(uintptr(len(a1))), cap(a1))
   153  	}
   154  	for i := 0; i < 100_000; i++ {
   155  		if i&1 == 0 {
   156  			assert.EqualValues(t, 1, a1[i])
   157  		} else {
   158  			assert.EqualValues(t, 2, a1[i])
   159  		}
   160  	}
   161  
   162  	runtime.KeepAlive(ac)
   163  }
   164  
   165  func TestAllocPoolReuse(t *testing.T) {
   166  	ac := NewAlloctorFromPool(128)
   167  	for _, block := range ac.blocks {
   168  		b := (*(*[]byte)(unsafe.Pointer(block)))
   169  		for _, bt := range b {
   170  			assert.EqualValues(t, byte('0'), bt)
   171  		}
   172  	}
   173  	a := New[testNew](ac)
   174  	a.a = ac.NewString("hello")
   175  	a.b = 12
   176  	t.Logf("%s %d\n", a.a, a.b)
   177  	assert.EqualValues(t, a.a, "hello")
   178  	assert.EqualValues(t, a.b, 12)
   179  	ac.ReturnAlloctorToPool()
   180  
   181  	ac = NewAlloctorFromPool(128)
   182  	for _, block := range ac.blocks {
   183  		b := (*(*[]byte)(unsafe.Pointer(block)))
   184  		for _, bt := range b {
   185  			assert.EqualValues(t, byte('0'), bt)
   186  		}
   187  	}
   188  	a = New[testNew](ac)
   189  	a.a = ac.NewString("ni")
   190  	a.b = 1123
   191  	t.Logf("%s %d\n", a.a, a.b)
   192  	assert.EqualValues(t, a.a, "ni")
   193  	assert.EqualValues(t, a.b, 1123)
   194  	ac.ReturnAlloctorToPool()
   195  
   196  	ac = NewAlloctorFromPool(128)
   197  	for _, block := range ac.blocks {
   198  		b := (*(*[]byte)(unsafe.Pointer(block)))
   199  		for _, bt := range b {
   200  			assert.EqualValues(t, byte('0'), bt)
   201  		}
   202  	}
   203  	a = New[testNew](ac)
   204  	a.a = ac.NewString("ni")
   205  	a.b = 1123
   206  	t.Logf("%s %d\n", a.a, a.b)
   207  	assert.EqualValues(t, a.a, "ni")
   208  	assert.EqualValues(t, a.b, 1123)
   209  
   210  	runtime.KeepAlive(ac)
   211  }
   212  
   213  func TestPoolAlloc(t *testing.T) {
   214  	maxn := 5_000
   215  	ac := NewAlloctorFromPool(0)
   216  	for i := 0; i < maxn; i++ {
   217  		a := New[testNew](ac)
   218  		assert.EqualValues(t, "", a.a)
   219  		assert.EqualValues(t, 0, a.b)
   220  	}
   221  	t.Logf("[first] bidx: %d, blocks: %d\n", ac.bidx, len(ac.blocks))
   222  
   223  	ac.ReturnAlloctorToPool()
   224  	ac = NewAlloctorFromPool(0)
   225  	for i := 0; i < maxn; i++ {
   226  		a := New[testNew](ac)
   227  		assert.EqualValues(t, "", a.a)
   228  		assert.EqualValues(t, 0, a.b)
   229  	}
   230  	t.Logf("[second] bidx: %d, blocks: %d\n", ac.bidx, len(ac.blocks))
   231  
   232  	ac.ReturnAlloctorToPool()
   233  	ac = NewAlloctorFromPool(0)
   234  	for i := 0; i < maxn; i++ {
   235  		a := New[testNew](ac)
   236  		assert.EqualValues(t, "", a.a)
   237  		assert.EqualValues(t, 0, a.b)
   238  	}
   239  	t.Logf("[third] bidx: %d, blocks: %d\n", ac.bidx, len(ac.blocks))
   240  
   241  	runtime.KeepAlive(ac)
   242  }
   243  
   244  func TestAllocPoolMerge(t *testing.T) {
   245  	ac := NewAlloctorFromPool(0)
   246  	a := New[testNew](ac)
   247  	a.a = ac.NewString("hello")
   248  	a.b = 12
   249  	assert.EqualValues(t, a.a, "hello")
   250  	assert.EqualValues(t, a.b, 12)
   251  
   252  	// 新内存池1
   253  	ac1 := NewAlloctorFromPool(ac.BlockSize())
   254  	a1 := New[testNew](ac)
   255  	a1.a = ac1.NewString("ni1")
   256  	a1.b = 1123
   257  	ac.Merge(ac1)
   258  	runtime.KeepAlive(ac1)
   259  	assert.EqualValues(t, a1.a, "ni1")
   260  	assert.EqualValues(t, a1.b, 1123)
   261  
   262  	// 新内存池2
   263  	ac2 := NewAlloctorFromPool(ac.BlockSize())
   264  	a2 := New[testNew](ac)
   265  	a2.a = ac2.NewString("ni2")
   266  	a2.b = 1123
   267  	ac.Merge(ac2)
   268  	runtime.KeepAlive(ac2)
   269  	assert.EqualValues(t, a2.a, "ni2")
   270  	assert.EqualValues(t, a2.b, 1123)
   271  
   272  	// 合并后内存信息
   273  	assert.EqualValues(t, len(ac.blocks), 3)
   274  	assert.EqualValues(t, ac.bidx, 2)
   275  
   276  	a = New[testNew](ac)
   277  	a.a = ac.NewString("hello3")
   278  	a.b = 12
   279  	assert.EqualValues(t, a.a, "hello3")
   280  	assert.EqualValues(t, a.b, 12)
   281  
   282  	// 再次check内存信息
   283  	assert.EqualValues(t, len(ac.blocks), 3)
   284  	assert.EqualValues(t, ac.bidx, 2)
   285  
   286  	runtime.KeepAlive(ac)
   287  }
   288  
   289  type allocKeepTest1 struct {
   290  	ac *Allocator
   291  	b  string
   292  }
   293  
   294  func TestKeepAlivePool(t *testing.T) {
   295  	ac := NewAlloctorFromPool(0)
   296  	a := New[allocKeepTest1](ac)
   297  	a.ac = NewAlloctorFromPool(0)
   298  	a.b = "123"
   299  
   300  	ac.KeepAlive(a.ac) // !
   301  	runtime.GC()
   302  
   303  	e := []byte(fmt.Sprintf("nihaocai %d", 1))
   304  	c := NewSlice[*allocKeepTest1](a.ac, 0, 8)
   305  	for i := 0; i < 1000000; i++ {
   306  		b := New[allocKeepTest1](a.ac)
   307  		b.b = a.ac.NewString(string(e)) // e 需要使用 NewString 来保留
   308  		c = Append[*allocKeepTest1](a.ac, c, b)
   309  	}
   310  	runtime.GC()
   311  
   312  	for i := 0; i < 1000000; i++ {
   313  		assert.EqualValues(t, c[i].b, "nihaocai 1")
   314  	}
   315  
   316  	runtime.KeepAlive(ac)
   317  }
   318  
   319  func TestNewString(t *testing.T) {
   320  	ac := NewAlloctorFromPool(0)
   321  	a := ac.NewString("")
   322  	b := ac.NewString("b")
   323  
   324  	runtime.GC()
   325  
   326  	assert.EqualValues(t, "", a)
   327  	assert.EqualValues(t, "b", b)
   328  	ac.KeepAlive(ac)
   329  }
   330  
   331  func TestSubAlloctor(t *testing.T) {
   332  	ac := NewAlloctorFromPool(0)
   333  	a := ac.NewString("123")
   334  	ac1 := NewAlloctorFromPool(0)
   335  	b := ac1.NewString("123")
   336  	ac.AddSubAlloctor(ac1)
   337  
   338  	runtime.GC()
   339  
   340  	assert.EqualValues(t, "123", a)
   341  	assert.EqualValues(t, "123", b)
   342  
   343  	ac.ReturnAlloctorToPool()
   344  
   345  	ac.KeepAlive(ac)
   346  	ac.KeepAlive(ac1)
   347  }