001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020package org.apache.hadoop.hbase.util; 021 022import org.apache.yetus.audience.InterfaceAudience; 023 024/** 025 * This class maintains mean and variation for any sequence of input provided to it. 026 * It is initialized with number of rolling periods which basically means the number of past 027 * inputs whose data will be considered to maintain mean and variation. 028 * It will use O(N) memory to maintain these statistics, where N is number of look up periods it 029 * was initialized with. 030 * If zero is passed during initialization then it will maintain mean and variance from the 031 * start. It will use O(1) memory only. But note that since it will maintain mean / variance 032 * from the start the statistics may behave like constants and may ignore short trends. 033 * All operations are O(1) except the initialization which is O(N). 034 */ 035@InterfaceAudience.Private 036public class RollingStatCalculator { 037 private double currentSum; 038 private double currentSqrSum; 039 // Total number of data values whose statistic is currently present 040 private long numberOfDataValues; 041 private int rollingPeriod; 042 private int currentIndexPosition; 043 // to be used only if we have non-zero rolling period 044 private long [] dataValues; 045 046 /** 047 * Creates a RollingStatCalculator with given number of rolling periods. 048 * @param rollingPeriod 049 */ 050 public RollingStatCalculator(int rollingPeriod) { 051 this.rollingPeriod = rollingPeriod; 052 this.dataValues = fillWithZeros(rollingPeriod); 053 this.currentSum = 0.0; 054 this.currentSqrSum = 0.0; 055 this.currentIndexPosition = 0; 056 this.numberOfDataValues = 0; 057 } 058 059 /** 060 * Inserts given data value to array of data values to be considered for statistics calculation 061 * @param data 062 */ 063 public void insertDataValue(long data) { 064 // if current number of data points already equals rolling period and rolling period is 065 // non-zero then remove one data and update the statistics 066 if(numberOfDataValues >= rollingPeriod && rollingPeriod > 0) { 067 this.removeData(dataValues[currentIndexPosition]); 068 } 069 numberOfDataValues++; 070 currentSum = currentSum + (double)data; 071 currentSqrSum = currentSqrSum + ((double)data * data); 072 if (rollingPeriod >0) 073 { 074 dataValues[currentIndexPosition] = data; 075 currentIndexPosition = (currentIndexPosition + 1) % rollingPeriod; 076 } 077 } 078 079 /** 080 * Update the statistics after removing the given data value 081 * @param data 082 */ 083 private void removeData(long data) { 084 currentSum = currentSum - (double)data; 085 currentSqrSum = currentSqrSum - ((double)data * data); 086 numberOfDataValues--; 087 } 088 089 /** 090 * @return mean of the data values that are in the current list of data values 091 */ 092 public double getMean() { 093 return this.currentSum / (double)numberOfDataValues; 094 } 095 096 /** 097 * @return deviation of the data values that are in the current list of data values 098 */ 099 public double getDeviation() { 100 double variance = (currentSqrSum - (currentSum*currentSum)/(double)(numberOfDataValues))/ 101 numberOfDataValues; 102 return Math.sqrt(variance); 103 } 104 105 /** 106 * @param size 107 * @return an array of given size initialized with zeros 108 */ 109 private long [] fillWithZeros(int size) { 110 long [] zeros = new long [size]; 111 for (int i=0; i<size; i++) { 112 zeros[i] = 0L; 113 } 114 return zeros; 115 } 116}