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  }