Sampling.java
Home
/
tigris /
src /
main /
java /
br /
ufrgs /
inf /
prosoft /
tigris /
sampling /
Sampling.java
package br.ufrgs.inf.prosoft.tigris.sampling;
import org.apache.commons.collections4.queue.CircularFifoQueue;
import org.apache.commons.math3.distribution.BinomialDistribution;
import org.apache.commons.math3.ml.neuralnet.sofm.util.ExponentialDecayFunction;
import org.apache.commons.math3.stat.inference.TestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
/**
* The type Sampling decision.
*/
public class Sampling implements Runnable {
private boolean samplingEnabled = true;
private boolean performanceBaselineEnabled = false;
private double samplingRate = 0.5; // in percentage, 0 to 1
private FrequencyDataSet population = new FrequencyDataSet(), sample = new FrequencyDataSet();
private PerformanceBaselineDataSet performanceBaselineDataSet = new PerformanceBaselineDataSet();
private Queue<PerformanceBaselineDataSet> lastFourPerformanceBaselineDataSets = new CircularFifoQueue<>(4);
private ExponentialDecayFunction decayingPrecision;
Logger logger = LoggerFactory.getLogger(Sampling.class);
/**
* z confidence value, ex: 1.96 for 95%
* p proportion of the population, 0.5 is default
* e margin of error, ex: 0.05 for 5%
*/
private double z = 1.96, p = 0.5, e = 0.05;
public Sampling(double initialSamplingRate, int cycleLengthInSeconds) {
samplingRate = initialSamplingRate;
//3600 seconds = 1h
decayingPrecision = new ExponentialDecayFunction(100, 0.01, cycleLengthInSeconds);
}
public boolean samplingDecision(Granularity granularity) {
population.addItem(granularity);
if(performanceBaselineEnabled) {
return false;
}
boolean decision = samplingEnabled
&& new BinomialDistribution(1, samplingRate).sample() == 1 // sampling rate evaluation
&& population.getProportion(granularity) > sample.getProportion(granularity); // sample has not enough items of that granularity compared to the population
if (decision)
sample.addItem(granularity);
return decision;
}
public void setSamplingRate(double samplingRate){
this.samplingRate = samplingRate;
}
public boolean isReady() {
return
// margin of error is lower than threshold
getSampleSizeErrorMargin() < e
// the sample has the min sample size based on the population
&& sample.getTotalItems() > getMinimumSampleSize()
// proportion test
&& isSameProportion()
// t-test
&& tTestEvaluation();
}
private double decayingConfidence(int timeInSeconds){
return decayingPrecision.value(timeInSeconds);
}
private boolean tTestEvaluation() {
//To test the (one-sample t-test - compare with the population mean)
// hypothesis sample mean = mu at the 95% level
return TestUtils.tTest(population.getAsDescriptiveStatistics().getMean(),
sample.getAsDescriptiveStatistics(),
0.05);
}
//sample proportion is the same as population
public boolean isSameProportion() {
return population.getGranularities().stream().allMatch(granularity -> population.getProportion(granularity) == sample.getProportion(granularity));
}
/**
* @return the minimum sample size for the population
*/
public long getMinimumSampleSize() {
long n_inf = (long) ((Math.pow(z, 2) * p * (1 - p)) / Math.pow(e, 2));
return n_inf / (1 + ((n_inf - 1) / population.getTotalItems()));
}
public long getMinimumSampleSize(long n) {
long n_inf = (long) ((Math.pow(z, 2) * p * (1 - p)) / Math.pow(e, 2));
return n_inf / (1 + ((n_inf - 1) / n));
}
public double getSampleSizeErrorMargin() {
double e_n_inf = Math.sqrt((Math.pow(z, 2) * p * (1 - p)) / sample.getTotalItems());
return e_n_inf * Math.sqrt((population.getTotalItems() - sample.getTotalItems()) / (population.getTotalItems() - 1));
}
public void disable() {
samplingEnabled = false;
}
public void enable() {
samplingEnabled = true;
}
public boolean isSamplingEnabled() {
return samplingEnabled;
}
public double getSamplingRate() {
return samplingRate;
}
public void startMonitoringCycle() {
}
public void endMonitoringCycle() {
}
public boolean shouldCollectPerformanceBaseline() {
return new BinomialDistribution(1, 0.1).sample() == 1;
}
public void adaptSamplingRate() {
//TODO
}
@Override
public void run() {
logger.info("Running sampling adaptation.");
if (isReady()) {
logger.info("Sample is ready, releasing for analysis and resetting...");
//TODO
releaseForAnalysis();
reset();
return;
}
if (shouldCollectPerformanceBaseline()) {
enablePerformanceBaseline();
return;
}
adaptSamplingRate();
}
private void enablePerformanceBaseline() {
performanceBaselineEnabled = true;
}
public void releaseForAnalysis() {
}
public void reset() {
}
public boolean isPerformanceBaselineEnabled() {
return performanceBaselineEnabled;
}
public void addPerformanceBaselineItem(Granularity granularity, long executionTime) {
this.performanceBaselineDataSet.addItem(granularity, executionTime);
if(this.performanceBaselineDataSet.getTotalItems() >=
getMinimumSampleSize(this.performanceBaselineDataSet.getTotalItems())) {
enable();
this.performanceBaselineEnabled = false;
lastFourPerformanceBaselineDataSets.add(this.performanceBaselineDataSet);
this.performanceBaselineDataSet = new PerformanceBaselineDataSet();
}
}
}