github.com/ergo-services/ergo@v1.999.224/lib/mpsc_test.go (about) 1 package lib 2 3 import ( 4 "math/rand" 5 "runtime" 6 "strconv" 7 "sync" 8 "sync/atomic" 9 "testing" 10 ) 11 12 func TestMPSCsequential(t *testing.T) { 13 14 type vv struct { 15 v int64 16 } 17 l := int64(10) 18 queue := NewQueueLimitMPSC(l) 19 // append to the queue 20 for i := int64(0); i < l; i++ { 21 v := vv{v: i + 100} 22 if queue.Push(v) == false { 23 t.Fatal("can't push value into the queue") 24 } 25 } 26 if queue.Len() != l { 27 t.Fatal("queue length must be 10") 28 } 29 30 if queue.Push("must be failed") == true { 31 t.Fatal("must be false: exceeded the limit", queue.Len()) 32 } 33 34 // walking through the queue 35 item := queue.Item() 36 for i := int64(0); i < l; i++ { 37 v, ok := item.Value().(vv) 38 if ok == false || v.v != i+100 { 39 t.Fatal("incorrect value. expected", i+100, "got", v) 40 } 41 42 item = item.Next() 43 44 } 45 if item != nil { 46 t.Fatal("there is something else in the queue", item.Value()) 47 } 48 49 // popping from the queue 50 for i := int64(0); i < l; i++ { 51 value, ok := queue.Pop() 52 if ok == false { 53 t.Fatal("there must be value") 54 } 55 v, ok := value.(vv) 56 if ok == false || v.v != i+100 { 57 t.Fatal("incorrect value. expected", i+100, "got", v) 58 } 59 } 60 61 // must be empty 62 if queue.Len() != 0 { 63 t.Fatal("queue length must be 0") 64 } 65 66 // check Clear method 67 if ok := queue.Push(vv{v: 100}); ok == false { 68 t.Fatal("must be true here") 69 } 70 71 item = queue.Item() 72 if item == nil { 73 t.Fatal("item is nil") 74 } 75 item.Clear() 76 value, ok := queue.Pop() 77 if ok == false { 78 t.Fatal("must be true here") 79 } 80 if value != nil { 81 t.Fatal("must be nil here") 82 } 83 } 84 85 func TestMPSCparallel(t *testing.T) { 86 87 type vv struct { 88 v int64 89 } 90 l := int64(100000) 91 queue := NewQueueLimitMPSC(l) 92 sum := int64(0) 93 // append to the queue 94 var wg sync.WaitGroup 95 for i := int64(0); i < l; i++ { 96 v := vv{v: i + 100} 97 sum += v.v 98 wg.Add(1) 99 go func(v vv) { 100 if queue.Push(v) == false { 101 t.Fatal("can't push value into the queue") 102 } 103 wg.Done() 104 }(v) 105 } 106 wg.Wait() 107 if x := queue.Len(); x != l { 108 t.Fatal("queue length must be", l, "have", x) 109 } 110 111 if queue.Push("must be failed") == true { 112 t.Fatal("must be false: exceeded the limit", queue.Len()) 113 } 114 115 // walking through the queue 116 item := queue.Item() 117 sum1 := int64(0) 118 for i := int64(0); i < l; i++ { 119 v, ok := item.Value().(vv) 120 sum1 += v.v 121 if ok == false { 122 t.Fatal("incorrect value. got", v) 123 } 124 125 item = item.Next() 126 127 } 128 if item != nil { 129 t.Fatal("there is something else in the queue", item.Value()) 130 } 131 if sum != sum1 { 132 t.Fatal("wrong value. exp", sum, "got", sum1) 133 } 134 135 sum1 = 0 136 // popping from the queue 137 for i := int64(0); i < l; i++ { 138 value, ok := queue.Pop() 139 if ok == false { 140 t.Fatal("there must be value") 141 } 142 v, ok := value.(vv) 143 sum1 += v.v 144 if ok == false { 145 t.Fatal("incorrect value. got", v) 146 } 147 } 148 149 // must be empty 150 if queue.Len() != 0 { 151 t.Fatal("queue length must be 0") 152 } 153 if sum != sum1 { 154 t.Fatal("wrong value. exp", sum, "got", sum1) 155 } 156 } 157 158 type chanQueue struct { 159 q chan interface{} 160 } 161 162 type testQueue interface { 163 Push(v interface{}) bool 164 Pop() (interface{}, bool) 165 } 166 167 func newChanQueue() *chanQueue { 168 chq := &chanQueue{ 169 q: make(chan interface{}, 100000000), 170 } 171 return chq 172 } 173 174 // Enqueue puts the given value v at the tail of the queue. 175 func (cq *chanQueue) Push(v interface{}) bool { 176 select { 177 case cq.q <- v: 178 return true 179 default: 180 panic("channel is full") 181 } 182 } 183 184 func (cq *chanQueue) Pop() (interface{}, bool) { 185 v := <-cq.q 186 return v, true 187 } 188 func BenchmarkMPSC(b *testing.B) { 189 queues := map[string]testQueue{ 190 "Chan queue ": newChanQueue(), 191 "MPSC queue ": NewQueueMPSC(), 192 "MPSC with limit queue": NewQueueLimitMPSC(0), 193 } 194 195 length := 1 << 12 196 inputs := make([]int, length) 197 for i := 0; i < length; i++ { 198 inputs = append(inputs, rand.Int()) 199 } 200 201 for _, cpus := range []int{4, 32, 1024} { 202 runtime.GOMAXPROCS(cpus) 203 for name, q := range queues { 204 b.Run(name+"#"+strconv.Itoa(cpus), func(b *testing.B) { 205 b.ResetTimer() 206 207 var c int64 208 b.RunParallel(func(pb *testing.PB) { 209 for pb.Next() { 210 i := int(atomic.AddInt64(&c, 1)-1) % length 211 v := inputs[i] 212 if v >= 0 { 213 q.Push(v) 214 } else { 215 q.Pop() 216 } 217 } 218 }) 219 }) 220 } 221 } 222 }