package io.airlift.stats;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.OperationsPerInvocation;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.profile.GCProfiler;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.VerboseMode;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@OutputTimeUnit(TimeUnit.SECONDS)
@Fork(3)
@Warmup(iterations = 10)
@Measurement(iterations = 10)
public class BenchmarkQuantileDigest
{
private static final int NUMBER_OF_ENTRIES = 10_000;
@State(Scope.Thread)
public static class Data
{
private long[] values1;
private long[] values2;
@Setup
public void setup()
{
values1 = makeValues(NUMBER_OF_ENTRIES);
values2 = makeValues(NUMBER_OF_ENTRIES);
}
private long[] makeValues(int size)
{
long[] values = new long[size];
for (int i = 0; i < size; i++) {
// generate values from a large domain but not many distinct values
long value = Math.abs((long) (ThreadLocalRandom.current().nextGaussian() * 1_000_000_000));
values[i] = (value / 1_000_000) * 1_000_000;
}
return values;
}
}
@State(Scope.Thread)
public static class Digest
{
private QuantileDigest digest1;
private QuantileDigest digest2;
@Setup
public void setup(Data data)
{
digest1 = makeDigest(data.values1);
digest2 = makeDigest(data.values2);
}
private QuantileDigest makeDigest(long[] values)
{
QuantileDigest result = new QuantileDigest(0.01);
for (long value : values) {
result.add(value);
}
return result;
}
}
@Benchmark
@OperationsPerInvocation(NUMBER_OF_ENTRIES)
public QuantileDigest benchmarkInserts(Data data)
{
QuantileDigest digest = new QuantileDigest(0.01);
for (long value : data.values1) {
digest.add(value);
}
return digest;
}
@Benchmark
public QuantileDigest benchmarkCopy(Digest data)
{
return new QuantileDigest(data.digest1);
}
@Benchmark
public QuantileDigest benchmarkMerge(Digest data)
{
QuantileDigest merged = new QuantileDigest(data.digest1);
merged.merge(data.digest2);
return merged;
}
public static void main(String[] args)
throws RunnerException
{
Options options = new OptionsBuilder()
.verbosity(VerboseMode.NORMAL)
.include(".*" + BenchmarkQuantileDigest.class.getSimpleName() + ".*")
.addProfiler(GCProfiler.class)
.build();
new Runner(options).run();
}
}