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 }