github.com/alphadose/zenq/v2@v2.8.4/benchmarks/e2e/benchsuite_test.go (about) 1 package zenq_test 2 3 import ( 4 "sync" 5 "testing" 6 7 "github.com/alphadose/zenq/v2" 8 ) 9 10 // wrapper for chan to have exactly the same api as zenq. 11 type Chan[T any] struct { 12 ch chan T 13 } 14 15 func NewChan[T any]() Chan[T] { 16 return Chan[T]{ch: make(chan T, bufferSize)} 17 } 18 19 func (ch Chan[T]) Read() T { return <-ch.ch } 20 func (ch Chan[T]) Write(v T) { ch.ch <- v } 21 22 func BenchmarkChan_Suite(b *testing.B) { 23 type Queue = Chan[int] 24 ctor := NewChan[int] 25 26 b.Run("Single", func(b *testing.B) { 27 q := ctor() 28 b.ResetTimer() 29 for i := 0; i < b.N; i++ { 30 q.Write(i) 31 _ = q.Read() 32 } 33 }) 34 35 b.Run("Uncontended/x100", func(b *testing.B) { 36 b.RunParallel(func(pb *testing.PB) { 37 q := ctor() 38 for pb.Next() { 39 for i := 0; i < 100; i++ { 40 q.Write(i) 41 _ = q.Read() 42 } 43 } 44 }) 45 }) 46 47 b.Run("Contended/x100", func(b *testing.B) { 48 q := ctor() 49 b.RunParallel(func(pb *testing.PB) { 50 for pb.Next() { 51 for i := 0; i < 100; i++ { 52 q.Write(i) 53 _ = q.Read() 54 } 55 } 56 }) 57 }) 58 59 b.Run("Multiple/x100", func(b *testing.B) { 60 const P = 1000 61 qs := [P]Queue{} 62 for i := range qs { 63 qs[i] = ctor() 64 } 65 66 b.ResetTimer() 67 68 var wg sync.WaitGroup 69 wg.Add(P * 2) 70 for i := 0; i < P; i++ { 71 go func(q Queue) { 72 defer wg.Done() 73 for i := 0; i < b.N; i++ { 74 var v int 75 q.Write(v) 76 } 77 }(qs[i]) 78 go func(q Queue) { 79 defer wg.Done() 80 for i := 0; i < b.N; i++ { 81 _ = q.Read() 82 } 83 84 }(qs[i]) 85 } 86 wg.Wait() 87 }) 88 89 b.Run("ProducerConsumer/x1", func(b *testing.B) { 90 q := ctor() 91 b.ResetTimer() 92 var wg sync.WaitGroup 93 wg.Add(2) 94 go func() { 95 defer wg.Done() 96 for i := 0; i < b.N; i++ { 97 var v int 98 q.Write(v) 99 work() 100 } 101 }() 102 103 go func() { 104 defer wg.Done() 105 for i := 0; i < b.N; i++ { 106 _ = q.Read() 107 work() 108 } 109 }() 110 wg.Wait() 111 }) 112 113 b.Run("ProducerConsumer/x100", func(b *testing.B) { 114 q := ctor() 115 b.ResetTimer() 116 var wg sync.WaitGroup 117 wg.Add(2) 118 119 go func() { 120 b.RunParallel(func(pb *testing.PB) { 121 for pb.Next() { 122 for i := 0; i < 100; i++ { 123 q.Write(0) 124 work() 125 } 126 } 127 }) 128 wg.Done() 129 }() 130 131 go func() { 132 b.RunParallel(func(pb *testing.PB) { 133 for pb.Next() { 134 for i := 0; i < 100; i++ { 135 _ = q.Read() 136 work() 137 } 138 } 139 }) 140 wg.Done() 141 }() 142 wg.Wait() 143 }) 144 145 b.Run("PingPong/x1", func(b *testing.B) { 146 q1 := ctor() 147 q2 := ctor() 148 b.ResetTimer() 149 var wg sync.WaitGroup 150 wg.Add(2) 151 152 go func() { 153 for i := 0; i < b.N; i++ { 154 var v int 155 q1.Write(v) 156 work() 157 _ = q2.Read() 158 } 159 wg.Done() 160 }() 161 162 go func() { 163 for i := 0; i < b.N; i++ { 164 var v int 165 _ = q1.Read() 166 work() 167 q2.Write(v) 168 } 169 wg.Done() 170 }() 171 wg.Wait() 172 }) 173 } 174 175 func BenchmarkZenq_Suite(b *testing.B) { 176 type Queue = zenq.ZenQ[int] 177 ctor := zenq.New[int] 178 179 b.Run("Single", func(b *testing.B) { 180 q := ctor(bufferSize) 181 b.ResetTimer() 182 for i := 0; i < b.N; i++ { 183 q.Write(i) 184 _, _ = q.Read() 185 } 186 }) 187 188 b.Run("Uncontended/x100", func(b *testing.B) { 189 b.RunParallel(func(pb *testing.PB) { 190 q := ctor(bufferSize) 191 for pb.Next() { 192 for i := 0; i < 100; i++ { 193 q.Write(i) 194 _, _ = q.Read() 195 } 196 } 197 }) 198 }) 199 200 b.Run("Contended/x100", func(b *testing.B) { 201 q := ctor(bufferSize) 202 b.RunParallel(func(pb *testing.PB) { 203 for pb.Next() { 204 for i := 0; i < 100; i++ { 205 q.Write(i) 206 _, _ = q.Read() 207 } 208 } 209 }) 210 }) 211 212 b.Run("Multiple/x100", func(b *testing.B) { 213 const P = 1000 214 qs := [P]*Queue{} 215 for i := range qs { 216 qs[i] = ctor(bufferSize) 217 } 218 219 b.ResetTimer() 220 221 var wg sync.WaitGroup 222 wg.Add(P * 2) 223 for i := 0; i < P; i++ { 224 go func(q *Queue) { 225 defer wg.Done() 226 for i := 0; i < b.N; i++ { 227 var v int 228 q.Write(v) 229 } 230 }(qs[i]) 231 go func(q *Queue) { 232 defer wg.Done() 233 for i := 0; i < b.N; i++ { 234 _, _ = q.Read() 235 } 236 237 }(qs[i]) 238 } 239 wg.Wait() 240 }) 241 242 b.Run("ProducerConsumer/x1", func(b *testing.B) { 243 q := ctor(bufferSize) 244 b.ResetTimer() 245 var wg sync.WaitGroup 246 wg.Add(2) 247 go func() { 248 defer wg.Done() 249 for i := 0; i < b.N; i++ { 250 var v int 251 q.Write(v) 252 work() 253 } 254 }() 255 256 go func() { 257 defer wg.Done() 258 for i := 0; i < b.N; i++ { 259 _, _ = q.Read() 260 work() 261 } 262 }() 263 wg.Wait() 264 }) 265 266 b.Run("ProducerConsumer/x100", func(b *testing.B) { 267 q := ctor(bufferSize) 268 b.ResetTimer() 269 var wg sync.WaitGroup 270 wg.Add(2) 271 272 go func() { 273 b.RunParallel(func(pb *testing.PB) { 274 for pb.Next() { 275 for i := 0; i < 100; i++ { 276 q.Write(0) 277 work() 278 } 279 } 280 }) 281 wg.Done() 282 }() 283 284 go func() { 285 b.RunParallel(func(pb *testing.PB) { 286 for pb.Next() { 287 for i := 0; i < 100; i++ { 288 _, _ = q.Read() 289 work() 290 } 291 } 292 }) 293 wg.Done() 294 }() 295 wg.Wait() 296 }) 297 298 b.Run("PingPong/x1", func(b *testing.B) { 299 q1 := ctor(bufferSize) 300 q2 := ctor(bufferSize) 301 b.ResetTimer() 302 var wg sync.WaitGroup 303 wg.Add(2) 304 305 go func() { 306 for i := 0; i < b.N; i++ { 307 var v int 308 q1.Write(v) 309 work() 310 _, _ = q2.Read() 311 } 312 wg.Done() 313 }() 314 315 go func() { 316 for i := 0; i < b.N; i++ { 317 var v int 318 _, _ = q1.Read() 319 work() 320 q2.Write(v) 321 } 322 wg.Done() 323 }() 324 wg.Wait() 325 }) 326 } 327 328 //go:noinline 329 func work() { 330 // really tiny amount of work 331 }