github.com/mongodb/grip@v0.0.0-20240213223901-f906268d82b9/send/benchmark/harness.go (about) 1 package send 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "strings" 10 "time" 11 12 "github.com/mongodb/grip/level" 13 "github.com/mongodb/grip/message" 14 "github.com/mongodb/grip/send" 15 ) 16 17 const ( 18 one = 1 19 five = 5 20 ten = 2 * five 21 hundred = ten * ten 22 23 executionTimeout = five * time.Minute 24 minRuntime = five * time.Second 25 minIterations = hundred 26 ) 27 28 func defaultLevelInfo() send.LevelInfo { 29 return send.LevelInfo{Default: level.Trace, Threshold: level.Trace} 30 } 31 32 func makeMessages(numMsgs int, size int, priority level.Priority) []message.Composer { 33 messages := make([]message.Composer, numMsgs) 34 for i := 0; i < numMsgs; i++ { 35 text := strings.Repeat("a", size) 36 messages[i] = message.NewDefaultMessage(priority, text) 37 } 38 return messages 39 } 40 41 func messageSizes() []int { 42 return []int{100, 10000} 43 } 44 45 func messageCounts() []int { 46 return []int{100, 1000, 10000} 47 } 48 49 func senderCases() map[string]benchCase { 50 return map[string]benchCase{ 51 "BufferedSender": bufferedSenderCase, 52 "BufferedAsyncSender": bufferedAsyncSenderCase, 53 "CallSiteFileLogger": callSiteFileLoggerCase, 54 "FileLogger": fileLoggerCase, 55 "InMemorySender": inMemorySenderCase, 56 "JSONFileLoggerCase": jsonFileLoggerCase, 57 "StreamLogger": streamLoggerCase, 58 } 59 } 60 61 func sendMessages(ctx context.Context, tm TimerManager, iters int, s send.Sender, msgs []message.Composer) error { 62 tm.ResetTimer() 63 defer tm.StopTimer() 64 for n := 0; n < iters; n++ { 65 for _, msg := range msgs { 66 select { 67 case <-ctx.Done(): 68 return ctx.Err() 69 default: 70 s.Send(msg) 71 } 72 } 73 } 74 return nil 75 } 76 77 func bufferedSenderCase(ctx context.Context, tm TimerManager, iters int, size int, numMsgs int) (err error) { 78 internal, err := send.NewInternalLogger("buffered", defaultLevelInfo()) 79 if err != nil { 80 return err 81 } 82 s, err := send.NewBufferedSender(ctx, internal, send.BufferedSenderOptions{FlushInterval: 5 * time.Second, BufferSize: 100000}) 83 if err != nil { 84 return err 85 } 86 87 defer func(s send.Sender) { 88 if e := s.Close(); e != nil { 89 err = e 90 } 91 }(s) 92 93 msgs := makeMessages(numMsgs, size, defaultLevelInfo().Default) 94 return sendMessages(ctx, tm, iters, s, msgs) 95 } 96 97 func bufferedAsyncSenderCase(ctx context.Context, tm TimerManager, iters int, size int, numMsgs int) (err error) { 98 internal, err := send.NewInternalLogger("buffered-async", defaultLevelInfo()) 99 if err != nil { 100 return err 101 } 102 opts := send.BufferedAsyncSenderOptions{} 103 opts.FlushInterval = 5 * time.Second 104 opts.BufferSize = 100000 105 106 s, err := send.NewBufferedAsyncSender(ctx, internal, opts) 107 if err != nil { 108 return err 109 } 110 111 defer func(s send.Sender) { 112 if e := s.Close(); e != nil { 113 err = e 114 } 115 }(s) 116 117 msgs := makeMessages(numMsgs, size, defaultLevelInfo().Default) 118 return sendMessages(ctx, tm, iters, s, msgs) 119 } 120 121 func callSiteFileLoggerCase(ctx context.Context, tm TimerManager, iters int, size int, numMsgs int) error { 122 file, err := ioutil.TempFile("", "bench_out.txt") 123 if err != nil { 124 return err 125 } 126 defer os.Remove(file.Name()) 127 s, err := send.NewCallSiteFileLogger("callsite", file.Name(), 1, defaultLevelInfo()) 128 if err != nil { 129 return err 130 } 131 msgs := makeMessages(numMsgs, size, defaultLevelInfo().Default) 132 return sendMessages(ctx, tm, iters, s, msgs) 133 } 134 135 func fileLoggerCase(ctx context.Context, tm TimerManager, iters int, size int, numMsgs int) error { 136 file, err := ioutil.TempFile("", "bench_out.txt") 137 if err != nil { 138 return err 139 } 140 defer os.Remove(file.Name()) 141 s, err := send.NewPlainFileLogger("plain", file.Name(), defaultLevelInfo()) 142 if err != nil { 143 return err 144 } 145 err = s.SetFormatter(send.MakePlainFormatter()) 146 if err != nil { 147 return err 148 } 149 msgs := makeMessages(numMsgs, size, defaultLevelInfo().Default) 150 return sendMessages(ctx, tm, iters, s, msgs) 151 } 152 153 func inMemorySenderCase(ctx context.Context, tm TimerManager, iters int, size int, numMsgs int) error { 154 s, err := send.NewInMemorySender("inmemory", defaultLevelInfo(), 10000) 155 if err != nil { 156 return err 157 } 158 msgs := makeMessages(numMsgs, size, defaultLevelInfo().Default) 159 return sendMessages(ctx, tm, iters, s, msgs) 160 } 161 162 func internalSenderCase(ctx context.Context, tm TimerManager, iters int, size int, numMsgs int) error { 163 s, err := send.NewInternalLogger("internal", defaultLevelInfo()) 164 if err != nil { 165 return err 166 } 167 msgs := makeMessages(numMsgs, size, defaultLevelInfo().Default) 168 return sendMessages(ctx, tm, iters, s, msgs) 169 } 170 171 func jsonFileLoggerCase(ctx context.Context, tm TimerManager, iters int, size int, numMsgs int) error { 172 file, err := ioutil.TempFile("", "bench_out.txt") 173 if err != nil { 174 return err 175 } 176 defer os.Remove(file.Name()) 177 s, err := send.NewJSONFileLogger("json", file.Name(), defaultLevelInfo()) 178 if err != nil { 179 return err 180 } 181 msgs := makeMessages(numMsgs, size, defaultLevelInfo().Default) 182 return sendMessages(ctx, tm, iters, s, msgs) 183 } 184 185 func streamLoggerCase(ctx context.Context, tm TimerManager, iters int, size int, numMsgs int) error { 186 s, err := send.NewStreamLogger("stream", &bytes.Buffer{}, defaultLevelInfo()) 187 if err != nil { 188 return err 189 } 190 msgs := makeMessages(numMsgs, size, defaultLevelInfo().Default) 191 return sendMessages(ctx, tm, iters, s, msgs) 192 } 193 194 type benchCase func(ctx context.Context, tm TimerManager, iters int, size int, numOps int) error 195 196 func getAllCases() []*caseDefinition { 197 cases := make([]*caseDefinition, 0) 198 for senderName, senderCase := range senderCases() { 199 for _, msgSize := range messageSizes() { 200 for _, msgCount := range messageCounts() { 201 cases = append(cases, 202 &caseDefinition{ 203 name: fmt.Sprintf("%s/%dBytesPerMessage/Send%dMessages", senderName, msgSize, msgCount), 204 bench: senderCase, 205 count: one, 206 numOps: msgCount, 207 size: msgSize, 208 runtime: minRuntime, 209 iterations: minIterations, 210 }, 211 ) 212 } 213 } 214 } 215 return cases 216 }