Skip to content

Commit 1719681

Browse files
Change parameter names and javadoc to make it the API agnostic about the time units and origin
1 parent 2c5474a commit 1719681

File tree

1 file changed

+52
-48
lines changed

1 file changed

+52
-48
lines changed

server/src/main/java/org/elasticsearch/common/metrics/ExponentiallyWeightedMovingRate.java

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
* {@code lambda} is a constant and {@code time} specifies how long ago the increment happened. A <i>moving</i> rate is simply a rate
2525
* calculated for an every-growing series of increments (typically by updating the previous rate rather than recalculating from scratch).
2626
*
27+
* <p>The times involved in the API of this class can use the caller's choice of units and origin, e.g. they can be millis since the
28+
* epoch as returned by {@link System#currentTimeMillis}, nanos since an arbitrary origin as returned by {@link System#nanoTime, or anything
29+
* else. The only requirement is that the same convention must be used consistently.
30+
*
2731
* <p>This class is thread-safe.
2832
*/
2933
public class ExponentiallyWeightedMovingRate {
@@ -35,108 +39,108 @@ public class ExponentiallyWeightedMovingRate {
3539
// we can do up to tens of millions of QPS before the lock risks becoming a bottleneck.
3640

3741
private final double lambda;
38-
private final long startTimeInMillis;
42+
private final long startTime;
3943
private double rate;
40-
long lastTimeInMillis;
44+
long lastTime;
4145

4246
/**
4347
* Constructor.
4448
*
4549
* @param lambda A parameter which dictates how quickly the average "forgets" older increments. The weight given to an increment which
46-
* happened a time {@code timeAgo} milliseconds ago will be proportional to {@code exp(-1.0 * lambda * timeAgo)}. The half-life
47-
* (measured in milliseconds) is related to this parameter by the equation {@code exp(-1.0 * lambda * halfLife)} = 0.5}, so
48-
* {@code lambda = log(2.0) / halfLife)}. This may be zero, but must not be negative.
49-
* @param startTimeInMillis The time, in milliseconds since the epoch, to consider the start time for the rate calculation. This must be
50-
* greater than zero.
50+
* happened time {@code timeAgo} ago will be proportional to {@code exp(-1.0 * lambda * timeAgo)}. The half-life is related to this
51+
* parameter by the equation {@code exp(-1.0 * lambda * halfLife)} = 0.5}, so {@code lambda = log(2.0) / halfLife)}. This may be
52+
* zero, but must not be negative. The units of this value are the inverse of the units being used for time.
53+
* @param startTime The time to consider the start time for the rate calculation. This must be greater than zero. The units and origin
54+
* of this value must match all other calls to this instance.
5155
*/
52-
public ExponentiallyWeightedMovingRate(double lambda, long startTimeInMillis) {
56+
public ExponentiallyWeightedMovingRate(double lambda, long startTime) {
5357
if (lambda < 0.0) {
5458
throw new IllegalArgumentException("lambda must be non-negative but was " + lambda);
5559
}
56-
if (startTimeInMillis <= 0.0) {
57-
throw new IllegalArgumentException("startTimeInMillis must be non-negative but was " + startTimeInMillis);
60+
if (startTime <= 0.0) {
61+
throw new IllegalArgumentException("startTime must be non-negative but was " + startTime);
5862
}
5963
synchronized (this) {
6064
this.lambda = lambda;
6165
this.rate = Double.NaN; // should never be used
62-
this.startTimeInMillis = startTimeInMillis;
63-
this.lastTimeInMillis = 0; // after an increment, this must be positive, so a zero value indicates we're waiting for the first
66+
this.startTime = startTime;
67+
this.lastTime = 0; // after an increment, this must be positive, so a zero value indicates we're waiting for the first
6468
}
6569
}
6670

6771
/**
68-
* Returns the EWMR at the given time, in millis since the epoch.
72+
* Returns the EWMR at the given time. The units and origin of this time must match all other calls to this instance. The units
73+
* of the returned rate are the ratio of the increment units to the time units as used for {@link #addIncrement}.
6974
*
7075
* <p>If there have been no increments yet, this returns zero.
7176
*
72-
* <p>Otherwise, we require the time to be no earlier than the time of the previous increment, i.e. the value of {@code timeInMillis}
73-
* for this call must not be less than the value of {@code timeInMillis} for the last call to {@link #addIncrement}. If this is not the
77+
* <p>Otherwise, we require the time to be no earlier than the time of the previous increment, i.e. the value of {@code time}
78+
* for this call must not be less than the value of {@code time} for the last call to {@link #addIncrement}. If this is not the
7479
* case, the method behaves as if it had that minimum value.
7580
*/
76-
public double getRate(long timeInMillis) {
81+
public double getRate(long time) {
7782
synchronized (this) {
78-
if (lastTimeInMillis == 0) { // indicates that no increment has happened yet
83+
if (lastTime == 0) { // indicates that no increment has happened yet
7984
return 0.0;
80-
} else if (timeInMillis <= lastTimeInMillis) {
85+
} else if (time <= lastTime) {
8186
return rate;
8287
} else {
8388
// This is the formula for R(t) given in subsection 2.6 of the document referenced above:
84-
return expHelper(lastTimeInMillis - startTimeInMillis) * exp(-1.0 * lambda * (timeInMillis - lastTimeInMillis)) * rate
85-
/ expHelper(timeInMillis - startTimeInMillis);
89+
return expHelper(lastTime - startTime) * exp(-1.0 * lambda * (time - lastTime)) * rate / expHelper(time - startTime);
8690
}
8791
}
8892
}
8993

9094
/**
91-
* Given the EWMR {@code currentRate} at time {@code currentTimeMillis} and the EWMR {@code oldRate} at time {@code oldTimeMillis},
92-
* returns the EWMR that would be calculated at {@code currentTimeMillis} if the start time was {@code oldTimeMillis} rather than the
93-
* {@code startTimeMillis} passed to the parameter. This rate incorporates all the increments that contributed to {@code currentRate}
94-
* but not to {@code oldRate}. The increments that contributed to {@code oldRate} are effectively 'forgotten'. All times are in millis
95-
* since the epoch.
95+
* Given the EWMR {@code currentRate} at time {@code currentTime} and the EWMR {@code oldRate} at time {@code oldTime}, returns the EWMR
96+
* that would be calculated at {@code currentTime} if the start time was {@code oldTime} rather than the {@code startTime} passed to the
97+
* parameter. This rate incorporates all the increments that contributed to {@code currentRate} but not to {@code oldRate}. The
98+
* increments that contributed to {@code oldRate} are effectively 'forgotten'. The units and origin of the times and rates must match
99+
* all other calls to this instance.
96100
*
97-
* <p>Normally, {@code currentTimeMillis} should be after {@code oldTimeMillis}. If it is not, this method returns zero.
101+
* <p>Normally, {@code currentTime} should be after {@code oldTime}. If it is not, this method returns zero.
98102
*
99103
* <p>Note that this method does <i>not</i> depend on any of the increments made to this {@link ExponentiallyWeightedMovingRate}
100-
* instance, or on its {@code startTimeMillis}. It is only non-static because it uses this instance's {@code lambda}.
104+
* instance, or on its {@code startTime}. It is only non-static because it uses this instance's {@code lambda}.
101105
*/
102-
public double calculateRateSince(long currentTimeMillis, double currentRate, long oldTimeMillis, double oldRate) {
103-
if (currentTimeMillis <= oldTimeMillis) {
106+
public double calculateRateSince(long currentTime, double currentRate, long oldTime, double oldRate) {
107+
if (currentTime <= oldTime) {
104108
return 0.0;
105109
}
106110
// This is the formula for R'(t, T) given in subsection 2.7 of the document referenced above:
107-
return (expHelper(currentTimeMillis - startTimeInMillis) * currentRate - expHelper(oldTimeMillis - startTimeInMillis) * exp(
108-
-1.0 * lambda * (currentTimeMillis - oldTimeMillis)
109-
) * oldRate) / expHelper(currentTimeMillis - oldTimeMillis);
111+
return (expHelper(currentTime - startTime) * currentRate - expHelper(oldTime - startTime) * exp(
112+
-1.0 * lambda * (currentTime - oldTime)
113+
) * oldRate) / expHelper(currentTime - oldTime);
110114
}
111115

112116
/**
113-
* Updates the rate to reflect that the gauge has been incremented by an amount {@code increment} at a time {@code timeInMillis} in
114-
* milliseconds since the epoch.
117+
* Updates the rate to reflect that the gauge has been incremented by an amount {@code increment} at a time {@code time}. The unit and
118+
* offset of the time must match all other calls to this instance. The units of the increment are arbitrary but must also be consistent.
115119
*
116120
* <p>If this is the first increment, we require it to occur after the start time for the rate calculation, i.e. the value of
117-
* {@code timeInMillis} must be greater than {@code startTimeInMillis} passed to the constructor. If this is not the case, the method
118-
* behaves as if {@code timeInMillis} is {@code startTimeInMillis + 1} to prevent a division by zero error.
121+
* {@code time} must be greater than {@code startTime} passed to the constructor. If this is not the case, the method behaves as if
122+
* {@code time} is {@code startTime + 1} to prevent a division by zero error.
119123
*
120-
* <p>If this is not the first increment, we require it not to occur before the previous increment, i.e. the value of
121-
* {@code timeInMillis} for this call must be greater than or equal to the value for the previous call. If this is not the case, the
122-
* method behaves as if this call's {@code timeInMillis} is the same as the previous call's.
124+
* <p>If this is not the first increment, we require it not to occur before the previous increment, i.e. the value of {@code time} for
125+
* this call must be greater than or equal to the value for the previous call. If this is not the case, the method behaves as if this
126+
* call's {@code time} is the same as the previous call's.
123127
*/
124-
public void addIncrement(double increment, long timeInMillis) {
128+
public void addIncrement(double increment, long time) {
125129
synchronized (this) {
126-
if (lastTimeInMillis == 0) { // indicates that this is the first increment
127-
if (timeInMillis <= startTimeInMillis) {
128-
timeInMillis = startTimeInMillis + 1;
130+
if (lastTime == 0) { // indicates that this is the first increment
131+
if (time <= startTime) {
132+
time = startTime + 1;
129133
}
130134
// This is the formula for R(t_1) given in subsection 2.6 of the document referenced above:
131-
rate = increment / expHelper(timeInMillis - startTimeInMillis);
135+
rate = increment / expHelper(time - startTime);
132136
} else {
133-
if (timeInMillis < lastTimeInMillis) {
134-
timeInMillis = lastTimeInMillis;
137+
if (time < lastTime) {
138+
time = lastTime;
135139
}
136140
// This is the formula for R(t_j+1) given in subsection 2.6 of the document referenced above:
137-
rate += (increment - expHelper(timeInMillis - lastTimeInMillis) * rate) / expHelper(timeInMillis - startTimeInMillis);
141+
rate += (increment - expHelper(time - lastTime) * rate) / expHelper(time - startTime);
138142
}
139-
lastTimeInMillis = timeInMillis;
143+
lastTime = time;
140144
}
141145
}
142146

0 commit comments

Comments
 (0)