|
30 | 30 | streams = flag.Int("streams", 1, "Streams per connection")
|
31 | 31 | warmup = flag.Int("warmup", 5, "Warmup in seconds")
|
32 | 32 | duration = flag.Int("duration", 10, "Duration in seconds")
|
33 |
| - wg sync.WaitGroup |
| 33 | + warmupWg sync.WaitGroup |
| 34 | + finishedWg sync.WaitGroup |
34 | 35 | connections []*grpc.ClientConn
|
35 | 36 | connectionLocks []sync.Mutex
|
36 | 37 | requestsPerConnection []int
|
@@ -84,24 +85,29 @@ func main() {
|
84 | 85 | opts = append(opts, grpc.WithInsecure())
|
85 | 86 | }
|
86 | 87 |
|
87 |
| - opts = append(opts, grpc.WithBlock()) |
88 |
| - |
| 88 | + // Create connections and related collections |
89 | 89 | buildConnections(context.Background(), opts)
|
90 | 90 |
|
| 91 | + // Start background thread to track warmup and duration |
91 | 92 | go func() {
|
92 | 93 | warmingUp = true
|
| 94 | + warmupWg.Add(1) |
93 | 95 | time.Sleep(time.Duration(*warmup) * time.Second)
|
94 | 96 | warmingUp = false
|
| 97 | + warmupWg.Done() |
95 | 98 | fmt.Print("Finished warming up\n")
|
96 | 99 | time.Sleep(time.Duration(*duration) * time.Second)
|
97 | 100 | stopped = true
|
98 | 101 | }()
|
99 | 102 |
|
| 103 | + // Start caller threads for each connection + stream |
100 | 104 | for connectionID, cc := range connections {
|
101 | 105 | runWithConn(connectionID, cc)
|
102 | 106 | }
|
103 |
| - wg.Wait() |
| 107 | + // Wait for caller threads to finish |
| 108 | + finishedWg.Wait() |
104 | 109 |
|
| 110 | + // Output results |
105 | 111 | calculateRequestStatistics()
|
106 | 112 | calculateLatencyStatistics()
|
107 | 113 | }
|
@@ -208,44 +214,110 @@ func calculateLatencyStatistics() {
|
208 | 214 | func runWithConn(connectionID int, cc *grpc.ClientConn) {
|
209 | 215 | for i := 0; i < *streams; i++ {
|
210 | 216 | streamID := i
|
211 |
| - wg.Add(1) |
| 217 | + finishedWg.Add(1) |
212 | 218 | go func() {
|
213 |
| - defer wg.Done() |
214 |
| - caller := makeCaller(cc, connectionID, streamID) |
| 219 | + defer finishedWg.Done() |
| 220 | + caller := makeCaller(cc, connectionID, streamID, *scenario) |
| 221 | + if caller == nil { |
| 222 | + log.Fatalf("Unsupported scenario: %s", *scenario) |
| 223 | + } |
215 | 224 | fmt.Printf("Starting %d %d\n", connectionID, streamID)
|
216 | 225 | caller()
|
217 | 226 | fmt.Printf("Finished %d %d\n", connectionID, streamID)
|
218 | 227 | }()
|
219 | 228 | }
|
220 | 229 | }
|
221 | 230 |
|
222 |
| -func makeCaller(cc *grpc.ClientConn, connectionID int, streamID int) func() { |
| 231 | +func makeCaller(cc *grpc.ClientConn, connectionID int, streamID int, scenario string) func() { |
223 | 232 | client := testpb.NewBenchmarkServiceClient(cc)
|
224 |
| - if *scenario != "unary" { |
225 |
| - log.Fatalf("Unsupported scenario: %s", *scenario) |
| 233 | + if scenario == "unary" { |
| 234 | + return func() { |
| 235 | + for { |
| 236 | + request := &testpb.SimpleRequest{ |
| 237 | + Payload: NewPayload(int(*requestSize)), |
| 238 | + ResponseSize: int32(*responseSize), |
| 239 | + } |
| 240 | + |
| 241 | + start := time.Now() |
| 242 | + if _, err := client.UnaryCall(context.Background(), request); err != nil { |
| 243 | + handleFailure(connectionID) |
| 244 | + } else { |
| 245 | + end := time.Now() |
| 246 | + handleSuccess(connectionID, start, end) |
| 247 | + } |
| 248 | + |
| 249 | + if stopped { |
| 250 | + return |
| 251 | + } |
| 252 | + } |
| 253 | + } |
226 | 254 | }
|
227 |
| - return func() { |
228 |
| - for { |
| 255 | + if scenario == "serverstreaming" { |
| 256 | + return func() { |
229 | 257 | request := &testpb.SimpleRequest{
|
230 | 258 | Payload: NewPayload(int(*requestSize)),
|
231 | 259 | ResponseSize: int32(*responseSize),
|
232 | 260 | }
|
233 | 261 |
|
234 |
| - start := time.Now() |
235 |
| - _, err := client.UnaryCall(context.Background(), request) |
236 |
| - end := time.Now() |
237 |
| - |
| 262 | + stream, err := client.StreamingFromServer(context.Background(), request) |
238 | 263 | if err != nil {
|
| 264 | + // Wait for warmup to be finished before reporting the call failed |
| 265 | + warmupWg.Wait() |
239 | 266 | handleFailure(connectionID)
|
240 |
| - } else { |
241 |
| - handleSuccess(connectionID, start, end) |
| 267 | + return |
242 | 268 | }
|
243 | 269 |
|
244 |
| - if stopped { |
| 270 | + for { |
| 271 | + start := time.Now() |
| 272 | + if _, err := stream.Recv(); err != nil { |
| 273 | + handleFailure(connectionID) |
| 274 | + } else { |
| 275 | + end := time.Now() |
| 276 | + handleSuccess(connectionID, start, end) |
| 277 | + } |
| 278 | + |
| 279 | + if stopped { |
| 280 | + return |
| 281 | + } |
| 282 | + } |
| 283 | + } |
| 284 | + } |
| 285 | + if scenario == "pingpongstreaming" { |
| 286 | + return func() { |
| 287 | + stream, err := client.StreamingCall(context.Background()) |
| 288 | + if err != nil { |
| 289 | + // Wait for warmup to be finished before reporting the call failed |
| 290 | + warmupWg.Wait() |
| 291 | + handleFailure(connectionID) |
245 | 292 | return
|
246 | 293 | }
|
| 294 | + |
| 295 | + for { |
| 296 | + request := &testpb.SimpleRequest{ |
| 297 | + Payload: NewPayload(int(*requestSize)), |
| 298 | + ResponseSize: int32(*responseSize), |
| 299 | + } |
| 300 | + |
| 301 | + start := time.Now() |
| 302 | + if err := stream.Send(request); err != nil { |
| 303 | + handleFailure(connectionID) |
| 304 | + } else { |
| 305 | + if _, err := stream.Recv(); err != nil { |
| 306 | + handleFailure(connectionID) |
| 307 | + } else { |
| 308 | + end := time.Now() |
| 309 | + handleSuccess(connectionID, start, end) |
| 310 | + } |
| 311 | + } |
| 312 | + |
| 313 | + if stopped { |
| 314 | + return |
| 315 | + } |
| 316 | + } |
247 | 317 | }
|
248 | 318 | }
|
| 319 | + |
| 320 | + return nil |
249 | 321 | }
|
250 | 322 |
|
251 | 323 | func handleFailure(connectionID int) {
|
|
0 commit comments