Skip to content

Commit b08edb6

Browse files
authored
Add MaxScale config parameter to ExponentialHistogram (open-telemetry#5044)
1 parent 49f4cf0 commit b08edb6

File tree

10 files changed

+62
-32
lines changed

10 files changed

+62
-32
lines changed

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfig.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ static Aggregation toAggregation(String aggregationName, Map<String, Object> agg
207207
throw new ConfigurationException("max_buckets must be an integer", e);
208208
}
209209
if (maxBuckets != null) {
210-
return ExponentialHistogramAggregation.create(maxBuckets);
210+
return ExponentialHistogramAggregation.create(maxBuckets, 20);
211211
}
212212
}
213213
return aggregation;

sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/internal/aggregator/HistogramCollectBenchmark.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ public void recordAndCollect(ThreadState threadState) {
113113
@SuppressWarnings("ImmutableEnumChecker")
114114
public enum AggregationGenerator {
115115
EXPLICIT_BUCKET_HISTOGRAM(Aggregation.explicitBucketHistogram()),
116-
EXPONENTIAL_BUCKET_HISTOGRAM(ExponentialHistogramAggregation.getDefault());
116+
DEFAULT_EXPONENTIAL_BUCKET_HISTOGRAM(ExponentialHistogramAggregation.getDefault()),
117+
ZERO_MAX_SCALE_EXPONENTIAL_BUCKET_HISTOGRAM(ExponentialHistogramAggregation.create(160, 0));
117118

118119
private final Aggregation aggregation;
119120

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/aggregator/DoubleExponentialHistogramAggregator.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public final class DoubleExponentialHistogramAggregator
3535

3636
private final Supplier<ExemplarReservoir<DoubleExemplarData>> reservoirSupplier;
3737
private final int maxBuckets;
38-
private final int startingScale;
38+
private final int maxScale;
3939

4040
/**
4141
* Constructs an exponential histogram aggregator.
@@ -45,15 +45,15 @@ public final class DoubleExponentialHistogramAggregator
4545
public DoubleExponentialHistogramAggregator(
4646
Supplier<ExemplarReservoir<DoubleExemplarData>> reservoirSupplier,
4747
int maxBuckets,
48-
int startingScale) {
48+
int maxScale) {
4949
this.reservoirSupplier = reservoirSupplier;
5050
this.maxBuckets = maxBuckets;
51-
this.startingScale = startingScale;
51+
this.maxScale = maxScale;
5252
}
5353

5454
@Override
5555
public AggregatorHandle<ExponentialHistogramAccumulation, DoubleExemplarData> createHandle() {
56-
return new Handle(reservoirSupplier.get(), maxBuckets, startingScale);
56+
return new Handle(reservoirSupplier.get(), maxBuckets, maxScale);
5757
}
5858

5959
/**
@@ -187,15 +187,15 @@ static final class Handle
187187
private long count;
188188
private int scale;
189189

190-
Handle(ExemplarReservoir<DoubleExemplarData> reservoir, int maxBuckets, int startingScale) {
190+
Handle(ExemplarReservoir<DoubleExemplarData> reservoir, int maxBuckets, int maxScale) {
191191
super(reservoir);
192192
this.maxBuckets = maxBuckets;
193193
this.sum = 0;
194194
this.zeroCount = 0;
195195
this.min = Double.MAX_VALUE;
196196
this.max = -1;
197197
this.count = 0;
198-
this.scale = startingScale;
198+
this.scale = maxScale;
199199
}
200200

201201
@Override

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/aggregator/DoubleExponentialHistogramBuckets.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ final class DoubleExponentialHistogramBuckets implements ExponentialHistogramBuc
2525
private ExponentialHistogramIndexer exponentialHistogramIndexer;
2626
private long totalCount;
2727

28-
DoubleExponentialHistogramBuckets(int startingScale, int maxBuckets) {
28+
DoubleExponentialHistogramBuckets(int scale, int maxBuckets) {
2929
this.counts = new AdaptingCircularBufferCounter(maxBuckets);
30-
this.scale = startingScale;
31-
this.exponentialHistogramIndexer = ExponentialHistogramIndexer.get(scale);
30+
this.scale = scale;
31+
this.exponentialHistogramIndexer = ExponentialHistogramIndexer.get(this.scale);
3232
this.totalCount = 0;
3333
}
3434

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ExponentialHistogramAggregation.java

+26-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.opentelemetry.sdk.internal.RandomSupplier;
1212
import io.opentelemetry.sdk.metrics.Aggregation;
1313
import io.opentelemetry.sdk.metrics.data.ExemplarData;
14+
import io.opentelemetry.sdk.metrics.data.MetricDataType;
1415
import io.opentelemetry.sdk.metrics.internal.aggregator.Aggregator;
1516
import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory;
1617
import io.opentelemetry.sdk.metrics.internal.aggregator.DoubleExponentialHistogramAggregator;
@@ -27,24 +28,38 @@
2728
public final class ExponentialHistogramAggregation implements Aggregation, AggregatorFactory {
2829

2930
private static final int DEFAULT_MAX_BUCKETS = 160;
30-
private static final int DEFAULT_STARTING_SCALE = 20;
31+
private static final int DEFAULT_MAX_SCALE = 20;
3132

3233
private static final Aggregation DEFAULT =
33-
new ExponentialHistogramAggregation(DEFAULT_MAX_BUCKETS);
34+
new ExponentialHistogramAggregation(DEFAULT_MAX_BUCKETS, DEFAULT_MAX_SCALE);
3435

3536
private final int maxBuckets;
37+
private final int maxScale;
3638

37-
private ExponentialHistogramAggregation(int maxBuckets) {
39+
private ExponentialHistogramAggregation(int maxBuckets, int maxScale) {
3840
this.maxBuckets = maxBuckets;
41+
this.maxScale = maxScale;
3942
}
4043

4144
public static Aggregation getDefault() {
4245
return DEFAULT;
4346
}
4447

45-
public static Aggregation create(int maxBuckets) {
48+
/**
49+
* Aggregations measurements into an {@link MetricDataType#EXPONENTIAL_HISTOGRAM}.
50+
*
51+
* @param maxBuckets the max number of positive buckets and negative buckets (max total buckets is
52+
* 2 * {@code maxBuckets} + 1 zero bucket).
53+
* @param maxScale the maximum and initial scale. If measurements can't fit in a particular scale
54+
* given the {@code maxBuckets}, the scale is reduced until the measurements can be
55+
* accommodated. Setting maxScale may reduce the number of downscales. Additionally, the
56+
* performance of computing bucket index is improved when scale is <= 0.
57+
* @return the aggregation
58+
*/
59+
public static Aggregation create(int maxBuckets, int maxScale) {
4660
checkArgument(maxBuckets >= 1, "maxBuckets must be > 0");
47-
return new ExponentialHistogramAggregation(maxBuckets);
61+
checkArgument(maxScale <= 20 && maxScale >= -10, "maxScale must be -10 <= x <= 20");
62+
return new ExponentialHistogramAggregation(maxBuckets, maxScale);
4863
}
4964

5065
@Override
@@ -61,7 +76,7 @@ public <T, U extends ExemplarData> Aggregator<T, U> createAggregator(
6176
Runtime.getRuntime().availableProcessors(),
6277
RandomSupplier.platformDefault())),
6378
maxBuckets,
64-
DEFAULT_STARTING_SCALE);
79+
maxScale);
6580
}
6681

6782
@Override
@@ -77,6 +92,10 @@ public boolean isCompatibleWithInstrument(InstrumentDescriptor instrumentDescrip
7792

7893
@Override
7994
public String toString() {
80-
return "ExponentialHistogramAggregation{maxBuckets=" + maxBuckets + "}";
95+
return "ExponentialHistogramAggregation{maxBuckets="
96+
+ maxBuckets
97+
+ ",maxScale="
98+
+ maxScale
99+
+ "}";
81100
}
82101
}

sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AggregationTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ void haveToString() {
3131
// TODO(jack-berg): Use Aggregation.exponentialHistogram() when available
3232
assertThat(ExponentialHistogramAggregation.getDefault())
3333
.asString()
34-
.isEqualTo("ExponentialHistogramAggregation{maxBuckets=160}");
35-
assertThat(ExponentialHistogramAggregation.create(1))
34+
.isEqualTo("ExponentialHistogramAggregation{maxBuckets=160,maxScale=20}");
35+
assertThat(ExponentialHistogramAggregation.create(1, 0))
3636
.asString()
37-
.isEqualTo("ExponentialHistogramAggregation{maxBuckets=1}");
37+
.isEqualTo("ExponentialHistogramAggregation{maxBuckets=1,maxScale=0}");
3838
}
3939

4040
@Test

sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogramTest.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,9 @@ void collectMetrics_ExponentialHistogramAggregation() {
208208
.registerMetricReader(sdkMeterReader)
209209
.registerView(
210210
InstrumentSelector.builder().setType(InstrumentType.HISTOGRAM).build(),
211-
View.builder().setAggregation(ExponentialHistogramAggregation.create(5)).build())
211+
View.builder()
212+
.setAggregation(ExponentialHistogramAggregation.create(5, 20))
213+
.build())
212214
.build();
213215
DoubleHistogram doubleHistogram =
214216
sdkMeterProvider

sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkLongHistogramTest.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,9 @@ void collectMetrics_ExponentialHistogramAggregation() {
208208
.registerMetricReader(sdkMeterReader)
209209
.registerView(
210210
InstrumentSelector.builder().setType(InstrumentType.HISTOGRAM).build(),
211-
View.builder().setAggregation(ExponentialHistogramAggregation.create(5)).build())
211+
View.builder()
212+
.setAggregation(ExponentialHistogramAggregation.create(5, 20))
213+
.build())
212214
.build();
213215
LongHistogram longHistogram =
214216
sdkMeterProvider

sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/aggregator/DoubleExponentialHistogramAggregatorTest.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class DoubleExponentialHistogramAggregatorTest {
4949

5050
@Mock ExemplarReservoir<DoubleExemplarData> reservoir;
5151

52-
private static final int STARTING_SCALE = 20;
52+
private static final int MAX_SCALE = 20;
5353
private static final DoubleExponentialHistogramAggregator aggregator =
5454
new DoubleExponentialHistogramAggregator(ExemplarReservoir::doubleNoSamples, 160, 20);
5555
private static final Resource RESOURCE = Resource.getDefault();
@@ -62,7 +62,7 @@ private static Stream<DoubleExponentialHistogramAggregator> provideAggregator()
6262
return Stream.of(
6363
aggregator,
6464
new DoubleExponentialHistogramAggregator(
65-
ExemplarReservoir::doubleNoSamples, 160, STARTING_SCALE));
65+
ExemplarReservoir::doubleNoSamples, 160, MAX_SCALE));
6666
}
6767

6868
private static int valueToIndex(int scale, double value) {
@@ -89,10 +89,10 @@ void createHandle() {
8989
.doAccumulateThenReset(Collections.emptyList());
9090
assertThat(accumulation.getPositiveBuckets())
9191
.isInstanceOf(DoubleExponentialHistogramAggregator.EmptyExponentialHistogramBuckets.class);
92-
assertThat(accumulation.getPositiveBuckets().getScale()).isEqualTo(STARTING_SCALE);
92+
assertThat(accumulation.getPositiveBuckets().getScale()).isEqualTo(MAX_SCALE);
9393
assertThat(accumulation.getNegativeBuckets())
9494
.isInstanceOf(DoubleExponentialHistogramAggregator.EmptyExponentialHistogramBuckets.class);
95-
assertThat(accumulation.getNegativeBuckets().getScale()).isEqualTo(STARTING_SCALE);
95+
assertThat(accumulation.getNegativeBuckets().getScale()).isEqualTo(MAX_SCALE);
9696
}
9797

9898
@Test
@@ -199,7 +199,7 @@ void testRecordingsAtLimits(DoubleExponentialHistogramAggregator aggregator) {
199199
@Test
200200
void testExemplarsInAccumulation() {
201201
DoubleExponentialHistogramAggregator agg =
202-
new DoubleExponentialHistogramAggregator(() -> reservoir, 160, STARTING_SCALE);
202+
new DoubleExponentialHistogramAggregator(() -> reservoir, 160, MAX_SCALE);
203203

204204
Attributes attributes = Attributes.builder().put("test", "value").build();
205205
DoubleExemplarData exemplar =
@@ -437,7 +437,7 @@ void testToMetricData() {
437437
Mockito.when(reservoirSupplier.get()).thenReturn(reservoir);
438438

439439
DoubleExponentialHistogramAggregator cumulativeAggregator =
440-
new DoubleExponentialHistogramAggregator(reservoirSupplier, 160, STARTING_SCALE);
440+
new DoubleExponentialHistogramAggregator(reservoirSupplier, 160, MAX_SCALE);
441441

442442
AggregatorHandle<ExponentialHistogramAccumulation, DoubleExemplarData> aggregatorHandle =
443443
cumulativeAggregator.createHandle();

sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ExponentialHistogramAggregationTest.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,19 @@ class ExponentialHistogramAggregationTest {
1515
@Test
1616
void goodConfig() {
1717
assertThat(ExponentialHistogramAggregation.getDefault()).isNotNull();
18-
assertThat(ExponentialHistogramAggregation.create(10)).isNotNull();
18+
assertThat(ExponentialHistogramAggregation.create(10, 20)).isNotNull();
1919
}
2020

2121
@Test
22-
void badBuckets_throwArgumentException() {
23-
assertThatThrownBy(() -> ExponentialHistogramAggregation.create(0))
22+
void invalidConfig_Throws() {
23+
assertThatThrownBy(() -> ExponentialHistogramAggregation.create(0, 20))
2424
.isInstanceOf(IllegalArgumentException.class)
2525
.hasMessage("maxBuckets must be > 0");
26+
assertThatThrownBy(() -> ExponentialHistogramAggregation.create(1, 21))
27+
.isInstanceOf(IllegalArgumentException.class)
28+
.hasMessage("maxScale must be -10 <= x <= 20");
29+
assertThatThrownBy(() -> ExponentialHistogramAggregation.create(1, -11))
30+
.isInstanceOf(IllegalArgumentException.class)
31+
.hasMessage("maxScale must be -10 <= x <= 20");
2632
}
2733
}

0 commit comments

Comments
 (0)