github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/list/x_skl_utils_test.go (about)

     1  package list
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"runtime"
     7  	"runtime/debug"
     8  	"strconv"
     9  	"sync"
    10  	"testing"
    11  	"time"
    12  	"unsafe"
    13  
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestOptimisticLock(t *testing.T) {
    18  	lock := new(spinMutex)
    19  	wg := sync.WaitGroup{}
    20  	wg.Add(2)
    21  	go func() {
    22  		startTime := time.Now()
    23  		lock.lock(1)
    24  		defer wg.Done()
    25  		defer lock.unlock(1)
    26  		defer func() {
    27  			t.Logf("1 elapsed: %d\n", time.Since(startTime).Milliseconds())
    28  		}()
    29  		ms := cryptoRandUint32() % 11
    30  		t.Logf("id: 1, obtain spin lock, sleep ms : %d\n", ms)
    31  		time.Sleep(time.Duration(ms) * time.Millisecond)
    32  	}()
    33  	go func() {
    34  		startTime := time.Now()
    35  		lock.lock(1)
    36  		defer wg.Done()
    37  		defer lock.unlock(1)
    38  		defer func() {
    39  			t.Logf("2 elapsed: %d\n", time.Since(startTime).Milliseconds())
    40  		}()
    41  		ms := cryptoRandUint32() % 11
    42  		t.Logf("id: 2, obtain spin lock, sleep ms : %d\n", ms)
    43  		time.Sleep(time.Duration(ms) * time.Millisecond)
    44  	}()
    45  	wg.Wait()
    46  }
    47  
    48  func TestFlagBitSetBitsAs(t *testing.T) {
    49  	type testcase struct {
    50  		name        string
    51  		targetBits  uint32
    52  		value       uint32
    53  		fb          uint32
    54  		expectValue uint32
    55  	}
    56  	testcases := []testcase{
    57  		{
    58  			name:        "0x0000 set 0x0001 to 0x00FF as 0x0001",
    59  			targetBits:  0x00FF,
    60  			value:       0x0001,
    61  			fb:          0,
    62  			expectValue: 0x0001,
    63  		}, {
    64  			name:        "0x0000 set 0x00FF to 0x00FF as 0x00FF",
    65  			targetBits:  0x00FF,
    66  			value:       0x00FF,
    67  			fb:          0,
    68  			expectValue: 0x00FF,
    69  		}, {
    70  			name:        "0x01FF set 0x00FF to 0x00FF as 0x01FF",
    71  			targetBits:  0x00FF,
    72  			value:       0x00FF,
    73  			fb:          0x01FF,
    74  			expectValue: 0x01FF,
    75  		}, {
    76  			name:        "0x01FF set 0x00FF to 0x0000 as 0x0100",
    77  			targetBits:  0x00FF,
    78  			value:       0x0000,
    79  			fb:          0x01FF,
    80  			expectValue: 0x0100,
    81  		}, {
    82  			name:        "0x03FF set 0x0300 to 0x0001 as 0x01FF",
    83  			targetBits:  0x0300,
    84  			value:       0x0001,
    85  			fb:          0x03FF,
    86  			expectValue: 0x01FF,
    87  		}, {
    88  			name:        "0x00FF set 0x0300 to 0x0003 as 0x03FF",
    89  			targetBits:  0x0300,
    90  			value:       0x0003,
    91  			fb:          0x00FF,
    92  			expectValue: 0x03FF,
    93  		},
    94  	}
    95  	for _, tc := range testcases {
    96  		t.Run(tc.name, func(tt *testing.T) {
    97  			tc.fb = setBitsAs(tc.fb, tc.targetBits, tc.value)
    98  			require.Equal(tt, tc.expectValue, tc.fb)
    99  		})
   100  	}
   101  }
   102  
   103  func TestFlagBitBitsAreEqualTo(t *testing.T) {
   104  	type testcase struct {
   105  		name        string
   106  		targetBits  uint32
   107  		value       uint32
   108  		fb          uint32
   109  		expectValue bool
   110  	}
   111  	testcases := []testcase{
   112  		{
   113  			name:        "0x0001 get 0x00FF are equal to 0x0001",
   114  			targetBits:  0x00FF,
   115  			value:       0x0001,
   116  			fb:          0x0001,
   117  			expectValue: true,
   118  		}, {
   119  			name:        "0x0301 get 0x0700 are equal to 0x0003",
   120  			targetBits:  0x0700,
   121  			value:       0x0003,
   122  			fb:          0x0301,
   123  			expectValue: true,
   124  		},
   125  	}
   126  	for _, tc := range testcases {
   127  		t.Run(tc.name, func(tt *testing.T) {
   128  			res := areEqual(tc.fb, tc.targetBits, tc.value)
   129  			require.True(tt, res)
   130  		})
   131  	}
   132  }
   133  
   134  func TestArenaBuffer(t *testing.T) {
   135  	obj := xSklObject{}
   136  	buffer := newArenaBuffer(100, unsafe.Sizeof(obj), unsafe.Alignof(obj))
   137  	optr, ok := buffer.allocate()
   138  	require.True(t, ok)
   139  	(*xSklObject)(optr).id = "abc"
   140  	o := *(*xSklObject)(optr)
   141  	t.Log(o)
   142  	op := &o
   143  	op2 := (*xSklObject)(optr)
   144  	t.Logf("%p, %p, %p\n", op, op2, (*xSklObject)(optr))
   145  
   146  	optr2, ok := buffer.allocate()
   147  	require.True(t, ok)
   148  	(*xSklObject)(optr2).id = "bcd"
   149  	o2 := *(*xSklObject)(optr2)
   150  	t.Log(o2)
   151  	op_2 := &o2
   152  	op_2_1 := (*xSklObject)(optr2)
   153  	t.Logf("%p, %p, %p\n", op_2, op_2_1, (*xSklObject)(optr2))
   154  }
   155  
   156  func TestAutoGrowthArena_xConcSklNode(t *testing.T) {
   157  	arenaCap, total := 10, 101
   158  
   159  	require.Panics(t, func() {
   160  		newAutoGrowthArena[*xConcSklNode[uint64, []string]](uint32(arenaCap), 128)
   161  	})
   162  
   163  	arena := newAutoGrowthArena[xConcSklNode[uint64, []string]](uint32(arenaCap), 128)
   164  	defer arena.free()
   165  	rand := cryptoRandUint32() % uint32(total)
   166  	for i := 0; i < total; i++ {
   167  		obj, ok := arena.allocate()
   168  		require.True(t, ok)
   169  		require.NotNil(t, obj)
   170  		if i == int(rand) {
   171  			arena.recycle(obj)
   172  		}
   173  	}
   174  	require.Equal(t, 10, arena.bufLen())
   175  	require.Equal(t, 0, arena.recLen())
   176  	require.Equal(t, uint64(100), arena.objLen())
   177  }
   178  
   179  func TestAutoGrowthArena_sliceGCRelease(t *testing.T) {
   180  	type testObj struct {
   181  		arr []byte
   182  	}
   183  
   184  	// If we access the recycled arr mem, occur fatal throw, unable to catch!
   185  	// Without the holder, here must be panic.
   186  	// unexpected fault address 0xc000168000
   187  	// fatal error: fault
   188  	// [signal 0xc0000005 code=0x0 addr=0xc000168000 pc=0xd76f0e]
   189  	type testObjWrapper struct {
   190  		arrRef []byte // attempt to hold arr lifecycle for testObj
   191  		obj    *testObj
   192  	}
   193  
   194  	arenaCap, total := 100, 1001
   195  
   196  	require.Panics(t, func() {
   197  		newAutoGrowthArena[*testObj](uint32(arenaCap), 128)
   198  	})
   199  
   200  	arena := newAutoGrowthArena[testObj](uint32(arenaCap), 128)
   201  	defer arena.free()
   202  
   203  	objs := make([]*testObjWrapper, 0, total)
   204  	for i := 0; i < total; i++ {
   205  		obj, ok := arena.allocate()
   206  		require.True(t, ok)
   207  		require.NotNil(t, obj)
   208  		x := int32(i + 100)
   209  		buf := bytes.NewBuffer([]byte{})
   210  		binary.Write(buf, binary.BigEndian, x)
   211  
   212  		w := &testObjWrapper{
   213  			arrRef: buf.Bytes(),
   214  		}
   215  		obj.arr = w.arrRef
   216  		w.obj = obj
   217  		objs = append(objs, w)
   218  	}
   219  
   220  	for i := 0; i < 10; i++ {
   221  		runtime.GC()
   222  		time.Sleep(2 * time.Millisecond)
   223  	}
   224  	i := 0
   225  	for ; i < total; i++ {
   226  		t.Logf("after gc, i: %d; arr len: %d; arr value: %v\n", i, len(objs[i].obj.arr), objs[i].obj.arr) // maybe exit(1)
   227  	}
   228  }
   229  
   230  func TestAutoGrowthArena_unsafe_sliceGCRelease(t *testing.T) {
   231  	type testObj struct {
   232  		arr unsafe.Pointer
   233  	}
   234  	t.Logf("size of unsafe arr pointer: %d\n", unsafe.Sizeof(testObj{}.arr))
   235  
   236  	type testObjWrapper struct {
   237  		arrRef []byte // attempt to hold arr lifecycle for testObj
   238  		obj    *testObj
   239  	}
   240  
   241  	arenaCap, total := 100, 1001
   242  
   243  	require.Panics(t, func() {
   244  		newAutoGrowthArena[*testObj](uint32(arenaCap), 128)
   245  	})
   246  
   247  	arena := newAutoGrowthArena[testObj](uint32(arenaCap), 128)
   248  	defer arena.free()
   249  
   250  	objs := make([]*testObjWrapper, 0, total)
   251  	for i := 0; i < total; i++ {
   252  		obj, ok := arena.allocate()
   253  		require.True(t, ok)
   254  		require.NotNil(t, obj)
   255  		x := i + 100
   256  		b := bytes.NewBufferString(strconv.Itoa(x)).Bytes()
   257  		t.Log(b)
   258  		w := &testObjWrapper{
   259  			arrRef: b,
   260  		}
   261  		obj.arr = unsafe.Pointer(unsafe.SliceData(w.arrRef))
   262  		w.obj = obj
   263  		objs = append(objs, w)
   264  	}
   265  
   266  	for i := 0; i < 10; i++ {
   267  		runtime.GC()
   268  		time.Sleep(2 * time.Millisecond)
   269  	}
   270  	i := 0
   271  	for ; i < total; i++ {
   272  		arr := unsafe.Slice((*byte)(objs[i].obj.arr), 4)
   273  		t.Logf("after gc, i: %d; arr len: %d; arr value: %v\n", i, len(arr), arr)
   274  	}
   275  }
   276  
   277  func TestSklErrorStack(t *testing.T) {
   278  	errFn := func() error {
   279  		return ErrXSklIsEmpty
   280  	}
   281  	err := errFn()
   282  	require.Error(t, err)
   283  	stack := debug.Stack()
   284  	t.Logf("%s\n", stack)
   285  }
   286  
   287  func BenchmarkXConcSklBuffer_xConcSklNode(b *testing.B) {
   288  	n := b.N
   289  	node := xConcSklNode[uint64, []byte]{}
   290  	buffer := newArenaBuffer(uintptr(n), unsafe.Sizeof(node), unsafe.Alignof(node))
   291  	defer buffer.free()
   292  
   293  	b.ResetTimer()
   294  	for i := 0; i < b.N; i++ {
   295  		_, _ = buffer.allocate()
   296  	}
   297  	b.StopTimer()
   298  	b.ReportAllocs()
   299  }
   300  
   301  func BenchmarkXConcSklBuffer_xNode(b *testing.B) {
   302  	n := b.N
   303  	node := xNode[[]byte]{}
   304  	buffer := newArenaBuffer(uintptr(n), unsafe.Sizeof(node), unsafe.Alignof(node))
   305  	defer buffer.free()
   306  
   307  	b.ResetTimer()
   308  	for i := 0; i < b.N; i++ {
   309  		_, _ = buffer.allocate()
   310  	}
   311  	b.StopTimer()
   312  	b.ReportAllocs()
   313  }