/*
* Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved
* http://www.griddynamics.com
*
* This library is free software; you can redistribute it and/or modify it under the terms of
* the Apache License; either
* version 2.0 of the License, or any later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.griddynamics.jagger.util.statistics.percentiles;
import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
public class PercentilesProcessor {
public enum EstimationStrategy { EXACT, HEURISTIC, AUTO }
private final EstimationStrategy initialStrategy;
private EstimationStrategy currentStrategy;
private DescriptiveStatistics descriptiveStatistics;
private AdaptiveHistogram adaptiveHistogram;
private int exactProcessorMaxCapacity = 100000;
public PercentilesProcessor() {
this(EstimationStrategy.AUTO);
}
/**
* Creates processor with the specifiedVal estimation strategy. See {@link EstimationStrategy}
* If it is expected that samples count will be large (100M or more)
* then {@link EstimationStrategy#HEURISTIC} should be used. In other cases {@link EstimationStrategy#AUTO}
* should be used. {@link EstimationStrategy#EXACT} typically should not be used.
*/
public PercentilesProcessor(EstimationStrategy estimationStrategy) {
initialStrategy = estimationStrategy;
reset();
}
public void addValue(double value) {
switch (currentStrategy) {
case HEURISTIC: adaptiveHistogram.addValue(value); break;
case EXACT: descriptiveStatistics.addValue(value); break;
case AUTO:
if(descriptiveStatistics.getN() >= exactProcessorMaxCapacity) {
adaptiveHistogram = new AdaptiveHistogram();
double[] values = descriptiveStatistics.getValues();
for(int i = 0; i < values.length; i++) {
adaptiveHistogram.addValue(values[i]);
}
adaptiveHistogram.addValue(value);
currentStrategy = EstimationStrategy.HEURISTIC;
} else {
descriptiveStatistics.addValue(value);
}
}
}
public double getPercentile(double p) {
double result = 0;
switch (currentStrategy) {
case HEURISTIC: result = adaptiveHistogram.getValueForPercentile(p); break;
case AUTO:
case EXACT: result = descriptiveStatistics.getPercentile(p);
}
return result;
}
public void reset() {
currentStrategy = initialStrategy;
switch(currentStrategy) {
case HEURISTIC: adaptiveHistogram = new AdaptiveHistogram(); break;
case AUTO:
case EXACT: descriptiveStatistics = new DescriptiveStatistics();
}
}
public void setExactProcessorMaxCapacity(int capacity) {
this.exactProcessorMaxCapacity = capacity;
}
}