From adc3cdde2ae2a78f7d2bb66da47a07545d3e06cf Mon Sep 17 00:00:00 2001 From: Jordan West Date: Wed, 8 Jan 2020 11:09:08 -0800 Subject: [PATCH] Fix DecayingEstimatedHistogramReservoir Inefficiencies Patch by Jordan West; reviewed by Benedict Elliott Smith for CASSANDRA-15213 --- .../DecayingEstimatedHistogramReservoir.java | 217 ++++++++++++++---- ...cayingEstimatedHistogramReservoirTest.java | 188 +++++++++++++-- 2 files changed, 338 insertions(+), 67 deletions(-) diff --git a/src/java/org/apache/cassandra/metrics/DecayingEstimatedHistogramReservoir.java b/src/java/org/apache/cassandra/metrics/DecayingEstimatedHistogramReservoir.java index a3168cf001..60f381cce5 100644 --- a/src/java/org/apache/cassandra/metrics/DecayingEstimatedHistogramReservoir.java +++ b/src/java/org/apache/cassandra/metrics/DecayingEstimatedHistogramReservoir.java @@ -22,9 +22,8 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.LongAdder; +import java.util.concurrent.atomic.AtomicLongArray; import com.google.common.annotations.VisibleForTesting; import com.google.common.primitives.Ints; @@ -34,6 +33,9 @@ import com.codahale.metrics.Reservoir; import com.codahale.metrics.Snapshot; import org.apache.cassandra.utils.EstimatedHistogram; +import static java.lang.Math.max; +import static java.lang.Math.min; + /** * A decaying histogram reservoir where values collected during each minute will be twice as significant as the values * collected in the previous minute. Measured values are collected in variable sized buckets, using small buckets in the @@ -63,30 +65,81 @@ import org.apache.cassandra.utils.EstimatedHistogram; * * Each bucket represents values from (previous bucket offset, current offset]. * + * To reduce contention each logical bucket is striped accross a configurable number of stripes (default: 4). Threads are + * assigned to specific stripes. In addition, logical buckets are distributed across the physical storage to reduce conention + * when logically adjacent buckets are updated. See CASSANDRA-15213. + * * [1]: http://dimacs.rutgers.edu/~graham/pubs/papers/fwddecay.pdf * [2]: https://en.wikipedia.org/wiki/Half-life * [3]: https://github.com/dropwizard/metrics/blob/v3.1.2/metrics-core/src/main/java/com/codahale/metrics/ExponentiallyDecayingReservoir.java */ public class DecayingEstimatedHistogramReservoir implements Reservoir { + /** * The default number of decayingBuckets. Use this bucket count to reduce memory allocation for bucket offsets. */ public static final int DEFAULT_BUCKET_COUNT = 164; + public static final int DEFAULT_STRIPE_COUNT = Integer.parseInt(System.getProperty("cassandra.dehr_stripe_count", "2")); + public static final int MAX_BUCKET_COUNT = 237; public static final boolean DEFAULT_ZERO_CONSIDERATION = false; + private static final int[] DISTRIBUTION_PRIMES = new int[] { 17, 19, 23, 29 }; + // The offsets used with a default sized bucket array without a separate bucket for zero values. public static final long[] DEFAULT_WITHOUT_ZERO_BUCKET_OFFSETS = EstimatedHistogram.newOffsets(DEFAULT_BUCKET_COUNT, false); // The offsets used with a default sized bucket array with a separate bucket for zero values. public static final long[] DEFAULT_WITH_ZERO_BUCKET_OFFSETS = EstimatedHistogram.newOffsets(DEFAULT_BUCKET_COUNT, true); + private static final int TABLE_BITS = 4; + private static final int TABLE_MASK = -1 >>> (32 - TABLE_BITS); + private static final float[] LOG2_TABLE = computeTable(TABLE_BITS); + private static final float log2_12_recp = (float) (1d / slowLog2(1.2d)); + + private static float[] computeTable(int bits) + { + float[] table = new float[1 << bits]; + for (int i = 1 ; i < 1< 2, we must "subtract" these exponents from the logarithm to determine which two buckets + // to consult (as our approximation otherwise produces a value that is within 1 of the true value) + int offset = (value > 2 ? 3 : 1) + (int)bucketOffsets[0]; + + // See DecayingEstimatedHistogramResevoirTest#showEstimationWorks and DecayingEstimatedHistogramResevoirTest#testFindIndex() + // for a runnable "proof" + // + // With this assumption, the estimate is calculated and the furthest offset from the estimation is checked + // if this bucket does not contain the value then the next one will + + int firstCandidate = max(0, min(bucketOffsets.length - 1, ((int) fastLog12(value)) - offset)); + return value <= bucketOffsets[firstCandidate] ? firstCandidate : firstCandidate + 1; } private double forwardDecayWeight(long now) @@ -189,17 +283,24 @@ public class DecayingEstimatedHistogramReservoir implements Reservoir } /** - * Return the number of buckets where recorded values are stored. + * Returns the logical number of buckets where recorded values are stored. The actual number of physical buckets + * is size() * stripeCount() * * This method does not return the number of recorded values as suggested by the {@link Reservoir} interface. * * @return the number of buckets + * @see #stripeCount() */ public int size() { - return decayingBuckets.length; + return bucketOffsets.length + 1; } + + public int stripeCount() + { + return nStripes; + } /** * Returns a snapshot of the decaying values in this reservoir. * @@ -219,7 +320,23 @@ public class DecayingEstimatedHistogramReservoir implements Reservoir @VisibleForTesting boolean isOverflowed() { - return decayingBuckets[decayingBuckets.length - 1].sum() > 0; + return bucketValue(bucketOffsets.length, true) > 0; + } + + private long bucketValue(int index, boolean withDecay) + { + long val = 0; + AtomicLongArray bs = withDecay ? decayingBuckets : buckets; + for (int stripe = 0; stripe < nStripes; stripe++) + val += bs.get(stripedIndex(index, stripe)); + + return val; + } + + @VisibleForTesting + long stripedBucketValue(int i, boolean withDecay) + { + return withDecay ? decayingBuckets.get(i) : buckets.get(i); } private void rescaleIfNeeded() @@ -248,14 +365,12 @@ public class DecayingEstimatedHistogramReservoir implements Reservoir private void rescale(long now) { + // despite striping its safe to rescale each bucket individually final double rescaleFactor = forwardDecayWeight(now); - - final int bucketCount = decayingBuckets.length; - for (int i = 0; i < bucketCount; i++) + for (int i = 0; i < decayingBuckets.length(); i++) { - long storedValue = decayingBuckets[i].sumThenReset(); - storedValue = Math.round(storedValue / rescaleFactor); - decayingBuckets[i].add(storedValue); + long newValue = Math.round(decayingBuckets.get(i) / rescaleFactor); + decayingBuckets.set(i, newValue); } } @@ -267,11 +382,11 @@ public class DecayingEstimatedHistogramReservoir implements Reservoir @VisibleForTesting public void clear() { - final int bucketCount = decayingBuckets.length; + final int bucketCount = decayingBuckets.length(); for (int i = 0; i < bucketCount; i++) { - decayingBuckets[i].reset(); - buckets[i].reset(); + decayingBuckets.set(i, 0L); + buckets.set(i, 0L); } } @@ -281,8 +396,8 @@ public class DecayingEstimatedHistogramReservoir implements Reservoir */ public void rebase(EstimatedHistogramReservoirSnapshot snapshot) { - // Check bucket count - if (decayingBuckets.length != snapshot.decayingBuckets.length) + // Check bucket count (a snapshot always has one stripe so the logical bucket count is used + if (size() != snapshot.decayingBuckets.length) { throw new IllegalStateException("Unable to merge two DecayingEstimatedHistogramReservoirs with different bucket sizes"); } @@ -297,14 +412,18 @@ public class DecayingEstimatedHistogramReservoir implements Reservoir } this.decayLandmark = snapshot.snapshotLandmark; - for (int i = 0; i < decayingBuckets.length; i++) + for (int i = 0; i < size(); i++) { - decayingBuckets[i].reset(); - buckets[i].reset(); - - decayingBuckets[i].add(snapshot.decayingBuckets[i]); - buckets[i].add(snapshot.values[i]); + // set rebased values in the first stripe and clear out all other data + decayingBuckets.set(stripedIndex(i, 0), snapshot.decayingBuckets[i]); + buckets.set(stripedIndex(i, 0), snapshot.values[i]); + for (int stripe = 1; stripe < nStripes; stripe++) + { + decayingBuckets.set(stripedIndex(i, stripe), 0); + buckets.set(stripedIndex(i, stripe), 0); + } } + } /** @@ -328,7 +447,7 @@ public class DecayingEstimatedHistogramReservoir implements Reservoir public EstimatedHistogramReservoirSnapshot(DecayingEstimatedHistogramReservoir reservoir) { - final int length = reservoir.decayingBuckets.length; + final int length = reservoir.size(); final double rescaleFactor = reservoir.forwardDecayWeight(reservoir.clock.getTime()); this.decayingBuckets = new long[length]; @@ -338,8 +457,8 @@ public class DecayingEstimatedHistogramReservoir implements Reservoir for (int i = 0; i < length; i++) { - this.decayingBuckets[i] = Math.round(reservoir.decayingBuckets[i].sum() / rescaleFactor); - this.values[i] = reservoir.buckets[i].sum(); + this.decayingBuckets[i] = Math.round(reservoir.bucketValue(i, true) / rescaleFactor); + this.values[i] = reservoir.bucketValue(i, false); } this.count = count(); this.reservoir = reservoir; diff --git a/test/unit/org/apache/cassandra/metrics/DecayingEstimatedHistogramReservoirTest.java b/test/unit/org/apache/cassandra/metrics/DecayingEstimatedHistogramReservoirTest.java index 4a9d18bbf5..e4289f7fae 100644 --- a/test/unit/org/apache/cassandra/metrics/DecayingEstimatedHistogramReservoirTest.java +++ b/test/unit/org/apache/cassandra/metrics/DecayingEstimatedHistogramReservoirTest.java @@ -18,20 +18,166 @@ package org.apache.cassandra.metrics; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; + +import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import com.codahale.metrics.Clock; import com.codahale.metrics.Snapshot; +import org.apache.cassandra.utils.EstimatedHistogram; +import org.apache.cassandra.utils.Pair; +import org.quicktheories.core.Gen; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; - +import static org.quicktheories.QuickTheory.qt; +import static org.quicktheories.generators.SourceDSL.*; public class DecayingEstimatedHistogramReservoirTest { private static final double DOUBLE_ASSERT_DELTA = 0; + public static final int numExamples = 1000000; + public static final Gen offsets = integers().from(DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT) + .upToAndIncluding(DecayingEstimatedHistogramReservoir.MAX_BUCKET_COUNT - 10) + .zip(booleans().all(), EstimatedHistogram::newOffsets); + + + @Test + public void testFindIndex() + { + qt().withExamples(numExamples) + .forAll(booleans().all() + .flatMap(b -> offsets.flatMap(offs -> this.offsetsAndValue(offs, b, 0)))) + .check(this::checkFindIndex); + } + + private boolean checkFindIndex(Pair offsetsAndValue) + { + long[] offsets = offsetsAndValue.left; + long value = offsetsAndValue.right; + + int model = findIndexModel(offsets, value); + int actual = DecayingEstimatedHistogramReservoir.findIndex(offsets, value); + + return model == actual; + } + + private int findIndexModel(long[] offsets, long value) + { + int modelIndex = Arrays.binarySearch(offsets, value); + if (modelIndex < 0) + modelIndex = -modelIndex - 1; + + return modelIndex; + }; + + @Test + public void showEstimationWorks() + { + qt().withExamples(numExamples) + .forAll(offsets.flatMap(offs -> this.offsetsAndValue(offs, false, 9))) + .check(this::checkEstimation); + } + + public boolean checkEstimation(Pair offsetsAndValue) + { + long[] offsets = offsetsAndValue.left; + long value = offsetsAndValue.right; + boolean considerZeros = offsets[0] == 0; + + int modelIndex = Arrays.binarySearch(offsets, value); + if (modelIndex < 0) + modelIndex = -modelIndex - 1; + + int estimate = (int) DecayingEstimatedHistogramReservoir.fastLog12(value); + + if (considerZeros) + return estimate - 3 == modelIndex || estimate - 2 == modelIndex; + else + return estimate - 4 == modelIndex || estimate - 3 == modelIndex; + } + + + private Gen> offsetsAndValue(long[] offsets, boolean useMaxLong, long minValue) + { + return longs().between(minValue, useMaxLong ? Long.MAX_VALUE : offsets[offsets.length - 1] + 100) + .mix(longs().between(minValue, minValue + 10),50) + .map(value -> Pair.create(offsets, value)); + } + + //shows that the max before overflow is 238 buckets regardless of consider zeros + @Test + @Ignore + public void showHistorgramOffsetOverflow() + { + qt().forAll(integers().from(DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT).upToAndIncluding(1000)) + .check(count -> { + long[] offsets = EstimatedHistogram.newOffsets(count, false); + for (long offset : offsets) + if (offset < 0) + return false; + + return true; + }); + } + + @Test + public void testStriping() throws InterruptedException + { + TestClock clock = new TestClock(); + int nStripes = 4; + DecayingEstimatedHistogramReservoir model = new DecayingEstimatedHistogramReservoir(clock); + DecayingEstimatedHistogramReservoir test = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, + DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, + nStripes, + clock); + + long seed = System.nanoTime(); + System.out.println("DecayingEstimatedHistogramReservoirTest#testStriping.seed = " + seed); + Random valGen = new Random(seed); + ExecutorService executors = Executors.newFixedThreadPool(nStripes * 2); + for (int i = 0; i < 1_000_000; i++) + { + long value = Math.abs(valGen.nextInt()); + executors.submit(() -> { + model.update(value); + LockSupport.parkNanos(2); + test.update(value); + }); + } + + executors.shutdown(); + executors.awaitTermination(10, TimeUnit.SECONDS); + + Snapshot modelSnapshot = model.getSnapshot(); + Snapshot testSnapshot = test.getSnapshot(); + + assertEquals(modelSnapshot.getMean(), testSnapshot.getMean(), DOUBLE_ASSERT_DELTA); + assertEquals(modelSnapshot.getMin(), testSnapshot.getMin(), DOUBLE_ASSERT_DELTA); + assertEquals(modelSnapshot.getMax(), testSnapshot.getMax(), DOUBLE_ASSERT_DELTA); + assertEquals(modelSnapshot.getMedian(), testSnapshot.getMedian(), DOUBLE_ASSERT_DELTA); + for (double i = 0.0; i < 1.0; i += 0.1) + assertEquals(modelSnapshot.getValue(i), testSnapshot.getValue(i), DOUBLE_ASSERT_DELTA); + + + int stripedValues = 0; + for (int i = model.size(); i < model.size() * model.stripeCount(); i++) + { + stripedValues += model.stripedBucketValue(i, true); + } + assertTrue("no striping found", stripedValues > 0); + } + @Test public void testSimple() { @@ -45,7 +191,7 @@ public class DecayingEstimatedHistogramReservoirTest } { // 0 and 1 map to different buckets - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(true, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(true); histogram.update(0); assertEquals(1, histogram.getSnapshot().getValues()[0]); histogram.update(1); @@ -58,7 +204,7 @@ public class DecayingEstimatedHistogramReservoirTest @Test public void testOverflow() { - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, 1); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, 1, 1); histogram.update(100); assert histogram.isOverflowed(); assertEquals(Long.MAX_VALUE, histogram.getSnapshot().getMax()); @@ -80,7 +226,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); for (int i = 0; i < 40; i++) histogram.update(0); for (int i = 0; i < 20; i++) @@ -92,7 +238,10 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(true, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(true, + DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, + DecayingEstimatedHistogramReservoir.DEFAULT_STRIPE_COUNT, + clock); for (int i = 0; i < 40; i++) histogram.update(0); for (int i = 0; i < 20; i++) @@ -109,7 +258,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); for (int i = 0; i < 20; i++) histogram.update(10); for (int i = 0; i < 40; i++) @@ -128,7 +277,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, 90, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, 90, 1, clock); histogram.update(23282687); assertFalse(histogram.isOverflowed()); assertEquals(1, histogram.getSnapshot().getValues()[89]); @@ -149,7 +298,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); // percentile of empty histogram is 0 assertEquals(0D, histogram.getSnapshot().getValue(0.99), DOUBLE_ASSERT_DELTA); @@ -164,7 +313,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); histogram.update(1); histogram.update(2); @@ -182,7 +331,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); for (int i = 11; i <= 20; i++) histogram.update(i); @@ -201,7 +350,10 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(true, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(true, + DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, + DecayingEstimatedHistogramReservoir.DEFAULT_STRIPE_COUNT, + clock); histogram.update(0); histogram.update(0); histogram.update(1); @@ -219,7 +371,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); // percentile of empty histogram is 0 assertEquals(0, histogram.getSnapshot().getValue(1.0), DOUBLE_ASSERT_DELTA); @@ -312,7 +464,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); // percentile of empty histogram is 0 assertEquals(0, histogram.getSnapshot().getValue(0.99), DOUBLE_ASSERT_DELTA); @@ -334,7 +486,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); histogram.update(20); histogram.update(21); @@ -360,7 +512,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); clock.addMillis(DecayingEstimatedHistogramReservoir.LANDMARK_RESET_INTERVAL_IN_MS - 1_000L); @@ -385,8 +537,8 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); - DecayingEstimatedHistogramReservoir another = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); + DecayingEstimatedHistogramReservoir another = new DecayingEstimatedHistogramReservoir(clock); clock.addMillis(DecayingEstimatedHistogramReservoir.LANDMARK_RESET_INTERVAL_IN_MS - 1_000L); @@ -420,7 +572,7 @@ public class DecayingEstimatedHistogramReservoirTest { TestClock clock = new TestClock(); - DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(DecayingEstimatedHistogramReservoir.DEFAULT_ZERO_CONSIDERATION, DecayingEstimatedHistogramReservoir.DEFAULT_BUCKET_COUNT, clock); + DecayingEstimatedHistogramReservoir histogram = new DecayingEstimatedHistogramReservoir(clock); histogram.update(42); histogram.update(42); assertEquals(2, histogram.getSnapshot().size());