github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/queue/ring_buffer_cursor_test.go (about) 1 package queue 2 3 import ( 4 "os" 5 "sync" 6 "sync/atomic" 7 "testing" 8 "time" 9 "unsafe" 10 ) 11 12 func TestXRingBufferCursor(t *testing.T) { 13 cursor := NewXRingBufferCursor() 14 beginIs := time.Now() 15 for i := 0; i < 100000000; i++ { 16 x := cursor.Next() 17 if x%10000000 == 0 { 18 t.Logf("x=%d", x) 19 } 20 } 21 diff := time.Since(beginIs) 22 t.Logf("ts diff=%v", diff) 23 } 24 25 func TestXRingBufferCursorConcurrency(t *testing.T) { 26 _, debugLogDisabled := os.LookupEnv("DISABLE_TEST_DEBUG_LOG") 27 // lower than single goroutine test 28 cursor := NewXRingBufferCursor() 29 t.Logf("cursor size=%v", unsafe.Sizeof(*cursor.(*rbCursor))) 30 beginIs := time.Now() 31 wg := sync.WaitGroup{} 32 wg.Add(10000) 33 for i := 0; i < 10000; i++ { 34 go func(idx int) { 35 for j := 0; j < 10000; j++ { 36 x := cursor.Next() 37 if x%10000000 == 0 { 38 if !debugLogDisabled { 39 t.Logf("gid=%d, x=%d", idx, x) 40 } 41 } 42 } 43 wg.Done() 44 }(i) 45 } 46 wg.Wait() 47 diff := time.Since(beginIs) 48 t.Logf("ts diff=%v", diff) 49 } 50 51 func TestXRingBufferCursorNoPaddingConcurrency(t *testing.T) { 52 _, debugLogDisabled := os.LookupEnv("DISABLE_TEST_DEBUG_LOG") 53 // Better than padding version 54 var cursor uint64 // same address, meaningless for data race 55 beginIs := time.Now() 56 wg := sync.WaitGroup{} 57 wg.Add(10000) 58 for i := 0; i < 10000; i++ { 59 go func(idx int) { 60 for j := 0; j < 10000; j++ { 61 x := atomic.AddUint64(&cursor, 1) 62 if x%10000000 == 0 { 63 if !debugLogDisabled { 64 t.Logf("gid=%d, x=%d", idx, x) 65 } 66 } 67 } 68 wg.Done() 69 }(i) 70 } 71 wg.Wait() 72 diff := time.Since(beginIs) 73 t.Logf("ts diff=%v", diff) 74 } 75 76 type noPaddingObj struct { 77 a, b, c uint64 78 } 79 80 func (o *noPaddingObj) increase() { 81 atomic.AddUint64(&o.a, 1) 82 atomic.AddUint64(&o.b, 1) 83 atomic.AddUint64(&o.c, 1) 84 } 85 86 type paddingObj struct { 87 a uint64 88 _ [8]uint64 89 b uint64 90 _ [8]uint64 91 c uint64 92 _ [8]uint64 93 } 94 95 func (o *paddingObj) increase() { 96 atomic.AddUint64(&o.a, 1) 97 atomic.AddUint64(&o.b, 1) 98 atomic.AddUint64(&o.c, 1) 99 } 100 101 func BenchmarkNoPaddingObj(b *testing.B) { 102 // Lower than padding version 103 obj := &noPaddingObj{} 104 b.RunParallel(func(pb *testing.PB) { 105 for pb.Next() { 106 obj.increase() 107 } 108 }) 109 } 110 111 func BenchmarkPaddingObj(b *testing.B) { 112 obj := &paddingObj{} 113 b.RunParallel(func(pb *testing.PB) { 114 for pb.Next() { 115 obj.increase() 116 } 117 }) 118 } 119 120 func TestFalseSharing(t *testing.T) { 121 // In the same cache line 122 volatileArray := [4]uint64{0, 0, 0, 0} // contiguous memory 123 var wg sync.WaitGroup 124 wg.Add(4) 125 beginIs := time.Now() 126 for i := 0; i < 4; i++ { 127 // Concurrent write to the same cache line 128 // Many cache misses, because of many RFO 129 go func(idx int) { 130 for j := 0; j < 100000000; j++ { 131 atomic.AddUint64(&volatileArray[idx], 1) 132 } 133 wg.Done() 134 }(i) 135 } 136 wg.Wait() 137 diff := time.Since(beginIs) 138 // ts diff=8.423525377s 139 t.Logf("ts diff=%v", diff) 140 } 141 142 func TestNoFalseSharing(t *testing.T) { 143 type padE struct { 144 value uint64 145 _ [cacheLinePadSize - unsafe.Sizeof(*new(uint64))]byte 146 } 147 148 // Each one in a different cache line 149 volatileArray := [4]padE{{}, {}, {}, {}} 150 var wg sync.WaitGroup 151 wg.Add(4) 152 beginIs := time.Now() 153 for i := 0; i < 4; i++ { 154 // No RFO data race 155 go func(idx int) { 156 for j := 0; j < 100000000; j++ { 157 atomic.AddUint64(&volatileArray[idx].value, 1) 158 } 159 wg.Done() 160 }(i) 161 } 162 wg.Wait() 163 diff := time.Since(beginIs) 164 // ts diff=890.219393ms 165 t.Logf("ts diff=%v", diff) 166 }