1 // Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
14 // broadcastBench allows to run broadcast benchmarks.
15 // In every broadcast benchmark we create many connections, then send the same
16 // message into every connection and wait for all writes complete. This emulates
17 // an application where many connections listen to the same data - i.e. PUB/SUB
18 // scenarios with many subscribers in one channel.
19 type broadcastBench struct {
21 message *broadcastMessage
25 conns []*broadcastConn
30 type broadcastMessage struct {
32 prepared *PreparedMessage
35 type broadcastConn struct {
37 msgCh chan *broadcastMessage
40 func newBroadcastConn(c *Conn) *broadcastConn {
41 return &broadcastConn{
43 msgCh: make(chan *broadcastMessage, 1),
47 func newBroadcastBench(usePrepared, compression bool) *broadcastBench {
48 bench := &broadcastBench{
50 doneCh: make(chan struct{}),
51 closeCh: make(chan struct{}),
52 usePrepared: usePrepared,
53 compression: compression,
55 msg := &broadcastMessage{
56 payload: textMessages(1)[0],
59 pm, _ := NewPreparedMessage(TextMessage, msg.payload)
63 bench.makeConns(10000)
67 func (b *broadcastBench) makeConns(numConns int) {
68 conns := make([]*broadcastConn, numConns)
70 for i := 0; i < numConns; i++ {
71 c := newTestConn(nil, b.w, true)
73 c.enableWriteCompression = true
74 c.newCompressionWriter = compressNoContextTakeover
76 conns[i] = newBroadcastConn(c)
77 go func(c *broadcastConn) {
80 case msg := <-c.msgCh:
82 c.conn.WritePreparedMessage(msg.prepared)
84 c.conn.WriteMessage(TextMessage, msg.payload)
86 val := atomic.AddInt32(&b.count, 1)
87 if val%int32(numConns) == 0 {
88 b.doneCh <- struct{}{}
99 func (b *broadcastBench) close() {
103 func (b *broadcastBench) runOnce() {
104 for _, c := range b.conns {
110 func BenchmarkBroadcast(b *testing.B) {
111 benchmarks := []struct {
116 {"NoCompression", false, false},
117 {"WithCompression", false, true},
118 {"NoCompressionPrepared", true, false},
119 {"WithCompressionPrepared", true, true},
121 for _, bm := range benchmarks {
122 b.Run(bm.name, func(b *testing.B) {
123 bench := newBroadcastBench(bm.usePrepared, bm.compression)
126 for i := 0; i < b.N; i++ {