...

Source file src/github.com/launchdarkly/go-server-sdk/v6/event_processor_benchmark_test.go

Documentation: github.com/launchdarkly/go-server-sdk/v6

     1  package ldclient
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/launchdarkly/go-sdk-common/v3/ldcontext"
     8  	"github.com/launchdarkly/go-sdk-common/v3/ldtime"
     9  	"github.com/launchdarkly/go-sdk-common/v3/lduser"
    10  	"github.com/launchdarkly/go-sdk-common/v3/ldvalue"
    11  	ldevents "github.com/launchdarkly/go-sdk-events/v2"
    12  )
    13  
    14  // These benchmarks cover the DefaultEventProcessor logic for digesting analytics event inputs and producing
    15  // output event data, but not actually sending the event data anywhere.
    16  //
    17  // In the current implementation, event processor tasks are divided between several goroutines. Therefore,
    18  // timing of these operations will have more variability than other benchmarks. However, execution time
    19  // should still be roughly proportional to the volume of work, and allocations should be fairly consistent.
    20  
    21  type mockEventSender struct {
    22  	sentCh chan struct{}
    23  }
    24  
    25  func (m *mockEventSender) SendEventData(kind ldevents.EventDataKind, data []byte, eventCount int) ldevents.EventSenderResult {
    26  	m.sentCh <- struct{}{} // allows benchmarks to detect that the event payload has been generated and fake-sent
    27  	return ldevents.EventSenderResult{Success: true}
    28  }
    29  
    30  type eventsBenchmarkEnv struct {
    31  	eventProcessor   ldevents.EventProcessor
    32  	mockEventSender  *mockEventSender
    33  	targetFeatureKey string
    34  	users            []ldcontext.Context
    35  	variations       []ldvalue.Value
    36  }
    37  
    38  func newEventsBenchmarkEnv() *eventsBenchmarkEnv {
    39  	return &eventsBenchmarkEnv{}
    40  }
    41  
    42  func (env *eventsBenchmarkEnv) setUp(bc eventsBenchmarkCase) {
    43  	env.mockEventSender = &mockEventSender{sentCh: make(chan struct{}, 10)}
    44  
    45  	config := ldevents.EventsConfiguration{
    46  		Capacity:    bc.bufferSize,
    47  		EventSender: env.mockEventSender,
    48  	}
    49  	env.eventProcessor = ldevents.NewDefaultEventProcessor(config)
    50  
    51  	env.targetFeatureKey = "flag-key"
    52  
    53  	env.variations = make([]ldvalue.Value, bc.numVariations)
    54  	for i := 0; i < bc.numVariations; i++ {
    55  		env.variations[i] = ldvalue.Int(i)
    56  	}
    57  
    58  	env.users = make([]ldcontext.Context, bc.numUsers)
    59  	for i := 0; i < bc.numUsers; i++ {
    60  		env.users[i] = lduser.NewUser(makeEvalBenchmarkTargetUserKey(i))
    61  	}
    62  }
    63  
    64  func (env *eventsBenchmarkEnv) tearDown() {
    65  	env.eventProcessor.Close()
    66  	env.eventProcessor = nil
    67  }
    68  
    69  func (env *eventsBenchmarkEnv) waitUntilEventsSent() {
    70  	<-env.mockEventSender.sentCh
    71  }
    72  
    73  type eventsBenchmarkCase struct {
    74  	bufferSize    int
    75  	numEvents     int
    76  	numVariations int
    77  	numUsers      int
    78  }
    79  
    80  var eventsBenchmarkCases = []eventsBenchmarkCase{
    81  	{
    82  		bufferSize:    1000,
    83  		numEvents:     100,
    84  		numVariations: 2,
    85  		numUsers:      10,
    86  	},
    87  	{
    88  		bufferSize:    1000,
    89  		numEvents:     100,
    90  		numVariations: 2,
    91  		numUsers:      100,
    92  	},
    93  	{
    94  		bufferSize:    1000,
    95  		numEvents:     1000,
    96  		numVariations: 2,
    97  		numUsers:      10,
    98  	},
    99  	{
   100  		bufferSize:    1000,
   101  		numEvents:     1000,
   102  		numVariations: 2,
   103  		numUsers:      100,
   104  	},
   105  }
   106  
   107  func benchmarkEvents(b *testing.B, cases []eventsBenchmarkCase, action func(*eventsBenchmarkEnv, eventsBenchmarkCase)) {
   108  	env := newEventsBenchmarkEnv()
   109  	for _, bc := range cases {
   110  		env.setUp(bc)
   111  
   112  		b.Run(fmt.Sprintf("%+v", bc), func(b *testing.B) {
   113  			for i := 0; i < b.N; i++ {
   114  				action(env, bc)
   115  			}
   116  		})
   117  		env.tearDown()
   118  	}
   119  }
   120  
   121  func BenchmarkFeatureRequestEventsSummaryOnly(b *testing.B) {
   122  	benchmarkEvents(b, eventsBenchmarkCases, func(env *eventsBenchmarkEnv, bc eventsBenchmarkCase) {
   123  		for i := 0; i < bc.numEvents; i++ {
   124  			user := env.users[i%bc.numUsers]
   125  			variation := i % bc.numVariations
   126  			value := env.variations[variation]
   127  			event := ldevents.EvaluationData{
   128  				BaseEvent: ldevents.BaseEvent{
   129  					CreationDate: ldtime.UnixMillisNow(),
   130  					Context:      ldevents.Context(user),
   131  				},
   132  				Key:       env.targetFeatureKey,
   133  				Variation: ldvalue.NewOptionalInt(variation),
   134  				Value:     value,
   135  			}
   136  			env.eventProcessor.RecordEvaluation(event)
   137  		}
   138  		env.eventProcessor.Flush()
   139  		env.waitUntilEventsSent()
   140  	})
   141  }
   142  
   143  func BenchmarkFeatureRequestEventsWithFullTracking(b *testing.B) {
   144  	benchmarkEvents(b, eventsBenchmarkCases, func(env *eventsBenchmarkEnv, bc eventsBenchmarkCase) {
   145  		for i := 0; i < bc.numEvents; i++ {
   146  			user := env.users[i%bc.numUsers]
   147  			variation := i % bc.numVariations
   148  			value := env.variations[variation]
   149  			event := ldevents.EvaluationData{
   150  				BaseEvent: ldevents.BaseEvent{
   151  					CreationDate: ldtime.UnixMillisNow(),
   152  					Context:      ldevents.Context(user),
   153  				},
   154  				Key:              env.targetFeatureKey,
   155  				Variation:        ldvalue.NewOptionalInt(variation),
   156  				Value:            value,
   157  				RequireFullEvent: true,
   158  			}
   159  			env.eventProcessor.RecordEvaluation(event)
   160  		}
   161  		env.eventProcessor.Flush()
   162  		env.waitUntilEventsSent()
   163  	})
   164  }
   165  
   166  func BenchmarkCustomEvents(b *testing.B) {
   167  	data := ldvalue.ObjectBuild().SetString("eventData", "value").Build()
   168  	benchmarkEvents(b, eventsBenchmarkCases, func(env *eventsBenchmarkEnv, bc eventsBenchmarkCase) {
   169  		for i := 0; i < bc.numEvents; i++ {
   170  			user := env.users[i%bc.numUsers]
   171  			event := ldevents.CustomEventData{
   172  				BaseEvent: ldevents.BaseEvent{
   173  					CreationDate: ldtime.UnixMillisNow(),
   174  					Context:      ldevents.Context(user),
   175  				},
   176  				Key:  "event-key",
   177  				Data: data,
   178  			}
   179  			env.eventProcessor.RecordCustomEvent(event)
   180  		}
   181  		env.eventProcessor.Flush()
   182  		env.waitUntilEventsSent()
   183  	})
   184  }
   185  

View as plain text