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}