Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ExponentialHistogramIndexerBenchmark #4989

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,64 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.metrics.internal.aggregator;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;

/** Measures runtime cost of computing bucket indexes for exponential histograms. */
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Measurement(iterations = 5, time = 1)
@Warmup(iterations = 5, time = 1)
@Fork(1)
public class ExponentialHistogramIndexerBenchmark {

@State(Scope.Thread)
public static class ThreadState {
@Param(value = {"1", "0", "-1"})
int scale;

private double[] values;
private final AtomicLong valueIndex = new AtomicLong();
private ExponentialHistogramIndexer indexer;

@Setup(Level.Trial)
public final void setup() {
Random random = new Random();
int numValues = 2000;
values = new double[numValues];
for (int i = 0; i < numValues; i++) {
values[i] = random.nextDouble() * 1000;
}
indexer = ExponentialHistogramIndexer.get(scale);
}

public void compute() {
// Compute a number of samples
for (int i = 0; i < 2000; i++) {
indexer.computeIndex(values[(int) (valueIndex.incrementAndGet() % values.length)]);
}
}
}

@Benchmark
public void computeIndex(ThreadState threadState) {
threadState.compute();
}
}
Expand Up @@ -25,16 +25,16 @@ public enum HistogramAggregationParam {
new DoubleExponentialHistogramAggregator(
ExemplarReservoir::doubleNoSamples,
ExponentialBucketStrategy.newStrategy(
20, ExponentialCounterFactory.circularBufferCounter()))),
20, ExponentialCounterFactory.circularBufferCounter(), 0))),
EXPONENTIAL_CIRCULAR_BUFFER(
new DoubleExponentialHistogramAggregator(
ExemplarReservoir::doubleNoSamples,
ExponentialBucketStrategy.newStrategy(
160, ExponentialCounterFactory.circularBufferCounter()))),
160, ExponentialCounterFactory.circularBufferCounter(), 0))),
EXPONENTIAL_MAP_COUNTER(
new DoubleExponentialHistogramAggregator(
ExemplarReservoir::doubleNoSamples,
ExponentialBucketStrategy.newStrategy(160, ExponentialCounterFactory.mapCounter())));
ExponentialBucketStrategy.newStrategy(160, ExponentialCounterFactory.mapCounter(), 0)));

private final Aggregator<?, ?> aggregator;

Expand Down
Expand Up @@ -10,26 +10,35 @@
/** The configuration for how to create exponential histogram buckets. */
final class ExponentialBucketStrategy {

private static final int STARTING_SCALE = 20;
private static final int DEFAULT_STARTING_SCALE = 20;

private final int startingScale;
/** The maximum number of buckets that will be used for positive or negative recordings. */
private final int maxBuckets;
/** The mechanism of constructing and copying buckets. */
private final ExponentialCounterFactory counterFactory;

private ExponentialBucketStrategy(int maxBuckets, ExponentialCounterFactory counterFactory) {
private ExponentialBucketStrategy(
int startingScale, int maxBuckets, ExponentialCounterFactory counterFactory) {
this.startingScale = startingScale;
this.maxBuckets = maxBuckets;
this.counterFactory = counterFactory;
}

/** Constructs fresh new buckets with default settings. */
DoubleExponentialHistogramBuckets newBuckets() {
return new DoubleExponentialHistogramBuckets(STARTING_SCALE, maxBuckets, counterFactory);
return new DoubleExponentialHistogramBuckets(startingScale, maxBuckets, counterFactory);
}

/** Create a new strategy for generating Exponential Buckets. */
static ExponentialBucketStrategy newStrategy(
int maxBuckets, ExponentialCounterFactory counterFactory) {
return new ExponentialBucketStrategy(maxBuckets, counterFactory);
return new ExponentialBucketStrategy(DEFAULT_STARTING_SCALE, maxBuckets, counterFactory);
}

/** Create a new strategy for generating Exponential Buckets. */
static ExponentialBucketStrategy newStrategy(
int maxBuckets, ExponentialCounterFactory counterFactory, int startingScale) {
return new ExponentialBucketStrategy(startingScale, maxBuckets, counterFactory);
}
}