github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/list/x_skl_rand_test.go (about) 1 package list 2 3 import ( 4 "math" 5 "math/bits" 6 "math/rand" 7 "sync" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 ) 12 13 func randomLevelV1(maxLevel int, currentElements int32) int32 { 14 // Call function maxLevels to get total? 15 // maxLevel => n, 2^n -1, there will be 2^n-1 elements in the skip list 16 var total uint64 17 if maxLevel == sklMaxLevel { 18 total = uint64(math.MaxUint32) 19 } else { 20 total = uint64(1)<<maxLevel - 1 21 } 22 // golang math random (math.Float64()) contains global mutex lock 23 // Ref 24 // https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:src/math/rand/rand.go 25 // https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:src/math/bits/bits.go 26 // 1. Avoid to use global mutex lock 27 // 2. Avoid to generate random number each time 28 rest := rand.Uint64() & total 29 // Bits right shift equal to manipulate a high-level bit 30 // Calculate the minimum bits of the random number 31 tmp := bits.Len64(rest) // Lookup table. 32 level := maxLevel - tmp + 1 33 // Avoid the value of randomly generated level deviates 34 // far from the number of elements within the skip-list. 35 // level should be greater than but approximate to log(currentElements) 36 for level > 1 && uint64(1)<<(level-1) > uint64(currentElements) { 37 level-- 38 } 39 return int32(level) 40 } 41 42 func TestMaxLevel(t *testing.T) { 43 levels := maxLevels(math.MaxInt32, 0.25) // 30 44 assert.GreaterOrEqual(t, 32, levels) 45 46 levels = maxLevels(int64(1), 0.25) // 0 47 assert.GreaterOrEqual(t, 0, levels) 48 49 levels = maxLevels(int64(2), 0.25) // 1 50 assert.GreaterOrEqual(t, 1, levels) 51 } 52 53 func TestRandomLevel(t *testing.T) { 54 loop := 10 55 for i := 0; i < loop; i++ { 56 t.Log(randomLevel(sklMaxLevel, int32(i))) 57 } 58 } 59 60 func TestRandomLevelV1(t *testing.T) { 61 var wg sync.WaitGroup 62 wg.Add(10) 63 for i := 0; i < 10; i++ { 64 go func(id int) { 65 loop := 1000 66 for j := 0; j < loop; j++ { 67 t.Logf("randv1 id: %d; rand: %d\n", id, randomLevelV1(sklMaxLevel, int32(j))) 68 } 69 wg.Done() 70 }(i) 71 } 72 wg.Wait() 73 } 74 75 func TestRandomLevelV2(t *testing.T) { 76 var wg sync.WaitGroup 77 wg.Add(10) 78 for i := 0; i < 10; i++ { 79 go func(id int) { 80 loop := 1000 81 for j := 0; j < loop; j++ { 82 t.Logf("randv2 id: %d; rand: %d\n", id, randomLevelV2(sklMaxLevel, int64(j))) 83 } 84 wg.Done() 85 }(i) 86 } 87 wg.Wait() 88 } 89 90 func TestRandomLevelV3(t *testing.T) { 91 var wg sync.WaitGroup 92 wg.Add(10) 93 for i := 0; i < 10; i++ { 94 go func(id int) { 95 loop := 1000 96 for j := 0; j < loop; j++ { 97 t.Logf("randv3 id: %d; rand: %d\n", id, randomLevelV3(sklMaxLevel, int64(j))) 98 } 99 wg.Done() 100 }(i) 101 } 102 wg.Wait() 103 } 104 105 func BenchmarkRandomLevel(b *testing.B) { 106 for i := 0; i < b.N; i++ { 107 randomLevel(sklMaxLevel, int32(i)) 108 } 109 b.ReportAllocs() 110 } 111 112 func BenchmarkRandomLevelV2(b *testing.B) { 113 for i := 0; i < b.N; i++ { 114 randomLevelV2(sklMaxLevel, int64(i)) 115 } 116 b.ReportAllocs() 117 }