/*
* Copyright 2013 Proofpoint, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.airlift.stats;
import io.airlift.stats.TimeStat.BlockTimer;
import io.airlift.testing.TestingTicker;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import static com.google.common.math.DoubleMath.fuzzyEquals;
import static java.lang.Math.min;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
@Test(singleThreaded = true)
public class TestTimeStat
{
private static final int VALUES = 1000;
private TestingTicker ticker;
@BeforeMethod
public void setup()
{
ticker = new TestingTicker();
}
@Test
public void testBasic()
{
TimeStat stat = new TimeStat();
List<Long> values = new ArrayList<>(VALUES);
for (long i = 0; i < VALUES; i++) {
values.add(i);
}
Collections.shuffle(values);
for (Long value : values) {
stat.add(value, TimeUnit.MILLISECONDS);
}
Collections.sort(values);
TimeDistribution allTime = stat.getAllTime();
assertEquals(allTime.getCount(), (double) values.size());
assertTrue(fuzzyEquals(allTime.getMax(), values.get(values.size() - 1) * 0.001, 0.000_000_000_1));
assertEquals(allTime.getMin(), values.get(0) * 0.001);
assertEquals(allTime.getUnit(), TimeUnit.SECONDS);
assertPercentile("tp50", allTime.getP50(), values, 0.50);
assertPercentile("tp75", allTime.getP75(), values, 0.75);
assertPercentile("tp90", allTime.getP90(), values, 0.90);
assertPercentile("tp99", allTime.getP99(), values, 0.99);
}
@Test
public void testEmpty()
{
TimeStat stat = new TimeStat();
TimeDistribution allTime = stat.getAllTime();
assertEquals(allTime.getMin(), Double.NaN);
assertEquals(allTime.getMax(), Double.NaN);
assertEquals(allTime.getP50(), Double.NaN);
assertEquals(allTime.getP75(), Double.NaN);
assertEquals(allTime.getP90(), Double.NaN);
assertEquals(allTime.getP99(), Double.NaN);
}
@Test
public void time()
throws Exception
{
TimeStat stat = new TimeStat(ticker);
stat.time(new Callable<Void>()
{
@Override
public Void call()
{
ticker.increment(10, TimeUnit.MILLISECONDS);
return null;
}
});
TimeDistribution allTime = stat.getAllTime();
assertEquals(allTime.getCount(), 1.0);
assertEquals(allTime.getMin(), 0.010);
assertEquals(allTime.getMax(), 0.010);
}
@Test
public void timeTry()
throws Exception
{
TimeStat stat = new TimeStat(ticker);
try (BlockTimer ignored = stat.time()) {
ticker.increment(10, TimeUnit.MILLISECONDS);
}
TimeDistribution allTime = stat.getAllTime();
assertEquals(allTime.getCount(), 1.0);
assertEquals(allTime.getMin(), 0.010);
assertEquals(allTime.getMax(), 0.010);
}
@Test
public void testUnit()
{
TimeStat stat = new TimeStat(ticker, TimeUnit.MILLISECONDS);
stat.add(1, TimeUnit.SECONDS);
TimeDistribution allTime = stat.getAllTime();
assertEquals(allTime.getMin(), 1000.0);
assertEquals(allTime.getMax(), 1000.0);
}
private static void assertPercentile(String name, double value, List<Long> values, double percentile)
{
int index = (int) (values.size() * percentile);
assertBounded(name, value, values.get(index - 1) * 0.001, values.get(min(index + 1, values.size() - 1)) * 0.001);
}
private static void assertBounded(String name, double value, double minValue, double maxValue)
{
if (value >= minValue && value <= maxValue) {
return;
}
fail(String.format("%s expected:<%s> to be between <%s> and <%s>", name, value, minValue, maxValue));
}
}