001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.metrics.impl;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertTrue;
022
023import java.util.Arrays;
024import java.util.Random;
025import java.util.concurrent.ThreadLocalRandom;
026import org.apache.hadoop.hbase.testclassification.MiscTests;
027import org.apache.hadoop.hbase.testclassification.SmallTests;
028import org.junit.jupiter.api.Tag;
029import org.junit.jupiter.api.Test;
030
031/**
032 * Testcases for FastLongHistogram.
033 */
034@Tag(MiscTests.TAG)
035@Tag(SmallTests.TAG)
036public class TestFastLongHistogram {
037
038  private static void doTestUniform(FastLongHistogram hist) {
039    long[] VALUES = { 0, 10, 20, 30, 40, 50 };
040    double[] qs = new double[VALUES.length];
041    for (int i = 0; i < qs.length; i++) {
042      qs[i] = (double) VALUES[i] / VALUES[VALUES.length - 1];
043    }
044
045    for (int i = 0; i < 10; i++) {
046      for (long v : VALUES) {
047        hist.add(v, 1);
048      }
049      long[] vals = hist.getQuantiles(qs);
050      System.out.println(Arrays.toString(vals));
051      for (int j = 0; j < qs.length; j++) {
052        assertTrue(Math.abs(vals[j] - VALUES[j]) <= 10,
053          j + "-th element org: " + VALUES[j] + ", act: " + vals[j]);
054      }
055      hist.snapshotAndReset();
056    }
057  }
058
059  @Test
060  public void testUniform() {
061    FastLongHistogram hist = new FastLongHistogram(100, 0, 50);
062    doTestUniform(hist);
063  }
064
065  @Test
066  public void testAdaptionOfChange() {
067    // assumes the uniform distribution
068    FastLongHistogram hist = new FastLongHistogram(100, 0, 100);
069
070    Random rand = ThreadLocalRandom.current();
071
072    for (int n = 0; n < 10; n++) {
073      for (int i = 0; i < 900; i++) {
074        hist.add(rand.nextInt(100), 1);
075      }
076
077      // add 10% outliers, this breaks the assumption, hope bin10xMax works
078      for (int i = 0; i < 100; i++) {
079        hist.add(1000 + rand.nextInt(100), 1);
080      }
081
082      long[] vals = hist.getQuantiles(new double[] { 0.25, 0.75, 0.95 });
083      System.out.println(Arrays.toString(vals));
084      if (n == 0) {
085        assertTrue(vals[0] >= 0 && vals[0] <= 50, "Out of possible value");
086        assertTrue(vals[1] >= 50 && vals[1] <= 100, "Out of possible value");
087        assertTrue(vals[2] >= 900 && vals[2] <= 1100, "Out of possible value");
088      }
089
090      hist.snapshotAndReset();
091    }
092  }
093
094  @Test
095  public void testGetNumAtOrBelow() {
096    long[] VALUES = { 1, 10, 20, 30, 40, 50 };
097
098    FastLongHistogram h = new FastLongHistogram();
099    for (long v : VALUES) {
100      for (int i = 0; i < 100; i++) {
101        h.add(v, 1);
102      }
103    }
104
105    h.add(Integer.MAX_VALUE, 1);
106
107    h.snapshotAndReset();
108
109    for (long v : VALUES) {
110      for (int i = 0; i < 100; i++) {
111        h.add(v, 1);
112      }
113    }
114    // Add something way out there to make sure it doesn't throw off the counts.
115    h.add(Integer.MAX_VALUE, 1);
116
117    assertEquals(100, h.getNumAtOrBelow(1));
118    assertEquals(200, h.getNumAtOrBelow(11));
119    assertEquals(601, h.getNumAtOrBelow(Long.MAX_VALUE));
120  }
121
122  @Test
123  public void testSameValues() {
124    FastLongHistogram hist = new FastLongHistogram(100);
125
126    hist.add(50, 100);
127
128    hist.snapshotAndReset();
129    doTestUniform(hist);
130  }
131}