blob: cfb0ff9dc4f241950ba5875348e48da12590e6bf [file] [log] [blame]
Jan Tattermusche81adf32016-04-04 15:59:50 -07001#region Copyright notice and license
2
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003// Copyright 2016 gRPC authors.
Jan Tattermusche81adf32016-04-04 15:59:50 -07004//
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
Jan Tattermusche81adf32016-04-04 15:59:50 -07008//
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009// http://www.apache.org/licenses/LICENSE-2.0
Jan Tattermusche81adf32016-04-04 15:59:50 -070010//
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
Jan Tattermusche81adf32016-04-04 15:59:50 -070016
17#endregion
18
19using System;
20using System.Collections.Generic;
21using System.Diagnostics;
22using System.IO;
23using System.Linq;
24using System.Text.RegularExpressions;
25using System.Threading;
26using System.Threading.Tasks;
27using Google.Protobuf;
28using Grpc.Core;
29using Grpc.Core.Utils;
30using Grpc.Testing;
31
32namespace Grpc.IntegrationTesting
33{
34 public interface IInterarrivalTimer
35 {
36 void WaitForNext();
37
38 Task WaitForNextAsync();
39 }
40
41 /// <summary>
42 /// Interarrival timer that doesn't wait at all.
43 /// </summary>
44 public class ClosedLoopInterarrivalTimer : IInterarrivalTimer
45 {
46 public ClosedLoopInterarrivalTimer()
47 {
48 }
49
50 public void WaitForNext()
51 {
52 // NOP
53 }
54
55 public Task WaitForNextAsync()
56 {
Jan Tattermusch5fe5eba2016-10-21 10:54:21 +020057 return TaskUtils.CompletedTask;
Jan Tattermusche81adf32016-04-04 15:59:50 -070058 }
59 }
60
61 /// <summary>
62 /// Interarrival timer that generates Poisson process load.
63 /// </summary>
64 public class PoissonInterarrivalTimer : IInterarrivalTimer
65 {
Jan Tattermusche81adf32016-04-04 15:59:50 -070066 readonly ExponentialDistribution exponentialDistribution;
67 DateTime? lastEventTime;
68
69 public PoissonInterarrivalTimer(double offeredLoad)
70 {
71 this.exponentialDistribution = new ExponentialDistribution(new Random(), offeredLoad);
72 this.lastEventTime = DateTime.UtcNow;
73 }
74
75 public void WaitForNext()
76 {
77 var waitDuration = GetNextWaitDuration();
78 int millisTimeout = (int) Math.Round(waitDuration.TotalMilliseconds);
79 if (millisTimeout > 0)
80 {
81 // TODO(jtattermusch): probably only works well for a relatively low interarrival rate
82 Thread.Sleep(millisTimeout);
83 }
84 }
85
86 public async Task WaitForNextAsync()
87 {
88 var waitDuration = GetNextWaitDuration();
89 int millisTimeout = (int) Math.Round(waitDuration.TotalMilliseconds);
90 if (millisTimeout > 0)
91 {
92 // TODO(jtattermusch): probably only works well for a relatively low interarrival rate
93 await Task.Delay(millisTimeout);
94 }
95 }
96
97 private TimeSpan GetNextWaitDuration()
98 {
99 if (!lastEventTime.HasValue)
100 {
101 this.lastEventTime = DateTime.Now;
102 }
103
104 var origLastEventTime = this.lastEventTime.Value;
Jan Tattermuscheff9cf02016-04-05 10:37:35 -0700105 this.lastEventTime = origLastEventTime + TimeSpan.FromSeconds(exponentialDistribution.Next());
Jan Tattermusche81adf32016-04-04 15:59:50 -0700106 return this.lastEventTime.Value - origLastEventTime;
107 }
108
109 /// <summary>
110 /// Exp generator.
111 /// </summary>
112 private class ExponentialDistribution
113 {
114 readonly Random random;
115 readonly double lambda;
116 readonly double lambdaReciprocal;
117
118 public ExponentialDistribution(Random random, double lambda)
119 {
120 this.random = random;
121 this.lambda = lambda;
122 this.lambdaReciprocal = 1.0 / lambda;
123 }
124
125 public double Next()
126 {
127 double uniform = random.NextDouble();
128 // Use 1.0-uni above to avoid NaN if uni is 0
129 return lambdaReciprocal * (-Math.Log(1.0 - uniform));
130 }
131 }
132 }
133}