package com.twitter.common.metrics;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import com.twitter.common.quantity.Amount;
import com.twitter.common.quantity.Data;
import com.twitter.common.stats.Precision;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Tests Histogram.
*/
public class HistogramTest {
private static final double EPS = 1e-8;
private String name = "hist";
private Metrics metrics;
@Before
public void setUp() {
metrics = Metrics.createDetached();
}
@Test
public void testEmptyHistogram() {
Histogram hist = new Histogram(name, metrics);
Map<String, Number> sample = metrics.sample();
assertEquals(0L, sample.get(name + "_min"));
assertEquals(0L, sample.get(name + "_max"));
long[] expected = {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L};
checkQuantiles(expected, sample);
}
@Test
public void testHistogram() {
int n = 10000;
Histogram hist = new Histogram(name, new Precision(0.0001, n), metrics);
for (int i = 1; i <= n; ++i) {
hist.add(i);
}
Map<String, Number> sample = metrics.sample();
assertEquals(1L, sample.get(name + "_min"));
assertEquals((long) n, sample.get(name + "_max"));
long[] expected = new long[Histogram.DEFAULT_QUANTILES.length];
for (int i = 0; i < Histogram.DEFAULT_QUANTILES.length; i++) {
expected[i] = (long) (Histogram.DEFAULT_QUANTILES[i] * n);
}
checkQuantiles(expected, sample);
}
@Test
public void testHistogramWithMemoryConstraints() {
int n = 10000;
Histogram hist = new Histogram(name, Amount.of(4L, Data.KB), metrics);
for (int i = 1; i <= n; ++i) {
hist.add(i);
}
Map<String, Number> sample = metrics.sample();
assertEquals(1L, sample.get(name + "_min"));
assertEquals((long) n, sample.get(name + "_max"));
double errorInPercent = 0.0;
for (double q : Histogram.DEFAULT_QUANTILES) {
String gName = name + "_" + Histogram.gaugeName(q);
errorInPercent += Math.abs(((q * n) - sample.get(gName).doubleValue()) / (q * n));
}
assertTrue(errorInPercent / Histogram.DEFAULT_QUANTILES.length < 0.01);
}
@Test
public void testAveragePrecision() {
int n = 1000 * 1000;
Histogram hist = new Histogram(name, Amount.of(4L, Data.KB), metrics);
long sum = 0L;
for (int i = 0; i <= 2 * n; ++i) {
sum += i;
hist.add(i);
}
Map<String, Number> sample = metrics.sample();
}
@Test
public void testNegative() {
Histogram hist = new Histogram(name, metrics);
for (int i = -100; i <= 100; ++i) {
hist.add(i);
}
Map<String, Number> sample = metrics.sample();
assertEquals(-100L, sample.get(name + "_min"));
assertEquals(100L, sample.get(name + "_max"));
long[] expected = {-51L, -1L, 49L, 79L, 89L, 97L, 99L, 99L};
checkQuantiles(expected, sample);
}
private void checkQuantiles(long[] expectedQuantiles, Map<String, Number> sample) {
assertEquals(expectedQuantiles.length, Histogram.DEFAULT_QUANTILES.length);
for (int i = 0; i < Histogram.DEFAULT_QUANTILES.length; i++) {
double q = Histogram.DEFAULT_QUANTILES[i];
String gName = Histogram.gaugeName(q);
assertEquals(expectedQuantiles[i], sample.get(name + "_" + gName));
}
}
}