-
Notifications
You must be signed in to change notification settings - Fork 858
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Lower exclusive exponential histogram bounds (#4700)
* Switch exponential histograms to use lower exclusive boundaries * Cache ExponentialHistogramIndexers * Update javadoc to reflect lower exlusive boundaries * Spotless * Fix typo * Add tests and stop rounding subnormal values * spotless * Add explanatory comments
- Loading branch information
Showing
7 changed files
with
348 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
...in/java/io/opentelemetry/sdk/metrics/internal/aggregator/ExponentialHistogramIndexer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.sdk.metrics.internal.aggregator; | ||
|
||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
class ExponentialHistogramIndexer { | ||
|
||
private static final Map<Integer, ExponentialHistogramIndexer> cache = new ConcurrentHashMap<>(); | ||
|
||
/** Bit mask used to isolate exponent of IEEE 754 double precision number. */ | ||
private static final long EXPONENT_BIT_MASK = 0x7FF0000000000000L; | ||
|
||
/** Bit mask used to isolate the significand of IEEE 754 double precision number. */ | ||
private static final long SIGNIFICAND_BIT_MASK = 0xFFFFFFFFFFFFFL; | ||
|
||
/** Bias used in representing the exponent of IEEE 754 double precision number. */ | ||
private static final int EXPONENT_BIAS = 1023; | ||
|
||
/** | ||
* The number of bits used to represent the significand of IEEE 754 double precision number, | ||
* excluding the implicit bit. | ||
*/ | ||
private static final int SIGNIFICAND_WIDTH = 52; | ||
|
||
/** The number of bits used to represent the exponent of IEEE 754 double precision number. */ | ||
private static final int EXPONENT_WIDTH = 11; | ||
|
||
private static final double LOG_BASE2_E = 1D / Math.log(2); | ||
|
||
private final int scale; | ||
private final double scaleFactor; | ||
|
||
private ExponentialHistogramIndexer(int scale) { | ||
this.scale = scale; | ||
this.scaleFactor = computeScaleFactor(scale); | ||
} | ||
|
||
/** Get an indexer for the given scale. Indexers are cached and reused for */ | ||
public static ExponentialHistogramIndexer get(int scale) { | ||
return cache.computeIfAbsent(scale, unused -> new ExponentialHistogramIndexer(scale)); | ||
} | ||
|
||
/** | ||
* Compute the index for the given value. | ||
* | ||
* <p>The algorithm to retrieve the index is specified in the <a | ||
* href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#exponential-buckets">OpenTelemetry | ||
* specification</a>. | ||
* | ||
* @param value Measured value (must be non-zero). | ||
* @return the index of the bucket which the value maps to. | ||
*/ | ||
int computeIndex(double value) { | ||
double absValue = Math.abs(value); | ||
// For positive scales, compute the index by logarithm, which is simpler but may be | ||
// inaccurate near bucket boundaries | ||
if (scale > 0) { | ||
return getIndexByLogarithm(absValue); | ||
} | ||
// For scale zero, compute the exact index by extracting the exponent | ||
if (scale == 0) { | ||
return mapToIndexScaleZero(absValue); | ||
} | ||
// For negative scales, compute the exact index by extracting the exponent and shifting it to | ||
// the right by -scale | ||
return mapToIndexScaleZero(absValue) >> -scale; | ||
} | ||
|
||
/** | ||
* Compute the bucket index using a logarithm based approach. | ||
* | ||
* @see <a | ||
* href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#all-scales-use-the-logarithm-function">All | ||
* Scales: Use the Logarithm Function</a> | ||
*/ | ||
private int getIndexByLogarithm(double value) { | ||
return (int) Math.ceil(Math.log(value) * scaleFactor) - 1; | ||
} | ||
|
||
/** | ||
* Compute the exact bucket index for scale zero by extracting the exponent. | ||
* | ||
* @see <a | ||
* href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#scale-zero-extract-the-exponent">Scale | ||
* Zero: Extract the Exponent</a> | ||
*/ | ||
private static int mapToIndexScaleZero(double value) { | ||
long rawBits = Double.doubleToLongBits(value); | ||
long rawExponent = (rawBits & EXPONENT_BIT_MASK) >> SIGNIFICAND_WIDTH; | ||
long rawSignificand = rawBits & SIGNIFICAND_BIT_MASK; | ||
if (rawExponent == 0) { | ||
rawExponent -= Long.numberOfLeadingZeros(rawSignificand - 1) - EXPONENT_WIDTH - 1; | ||
} | ||
int ieeeExponent = (int) (rawExponent - EXPONENT_BIAS); | ||
if (rawSignificand == 0) { | ||
return ieeeExponent - 1; | ||
} | ||
return ieeeExponent; | ||
} | ||
|
||
private static double computeScaleFactor(int scale) { | ||
return Math.scalb(LOG_BASE2_E, scale); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.