package org.spotter.ext.detection.ramp.strategies;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.aim.api.exceptions.InstrumentationException;
import org.aim.api.exceptions.MeasurementException;
import org.aim.api.measurement.dataset.Dataset;
import org.aim.api.measurement.dataset.DatasetCollection;
import org.aim.api.measurement.dataset.ParameterSelection;
import org.aim.artifacts.probes.ResponsetimeProbe;
import org.aim.artifacts.records.ResponseTimeRecord;
import org.aim.artifacts.scopes.EntryPointScope;
import org.aim.description.InstrumentationDescription;
import org.aim.description.builder.InstrumentationDescriptionBuilder;
import org.lpe.common.util.LpeNumericUtils;
import org.lpe.common.util.NumericPair;
import org.lpe.common.util.NumericPairList;
import org.spotter.core.ProgressManager;
import org.spotter.core.chartbuilder.AnalysisChartBuilder;
import org.spotter.ext.detection.ramp.IRampDetectionStrategy;
import org.spotter.ext.detection.ramp.RampDetectionController;
import org.spotter.ext.detection.ramp.RampExtension;
import org.spotter.ext.detection.utils.Utils;
import org.spotter.shared.result.model.SpotterResult;
/**
* Conducts analysis by means of a single experiment.
*
* @author Alexander Wert
*
*/
public class DirectGrowthStrategy implements IRampDetectionStrategy {
private RampDetectionController mainDetectionController;
private static double requiredSignificanceLevel;
@Override
public void setProblemDetectionConfiguration(Properties problemDetectionConfiguration) {
String significanceLevelStr = problemDetectionConfiguration
.getProperty(RampExtension.KEY_REQUIRED_SIGNIFICANCE_LEVEL);
requiredSignificanceLevel = significanceLevelStr != null ? Double.parseDouble(significanceLevelStr)
: RampExtension.REQUIRED_SIGNIFICANCE_LEVEL_DEFAULT;
}
@Override
public void setMainDetectionController(RampDetectionController mainDetectionController) {
this.mainDetectionController = mainDetectionController;
}
@Override
public void executeExperiments() throws InstrumentationException, MeasurementException {
mainDetectionController.executeHighLoadExperiment(getInstrumentationDescription());
}
@Override
public SpotterResult analyze(DatasetCollection data) {
SpotterResult result = new SpotterResult();
result.setDetected(false);
Dataset rtDataset = data.getDataSet(ResponseTimeRecord.class);
if (rtDataset == null || rtDataset.size() == 0) {
result.setDetected(false);
result.addMessage("Instrumentation achieved no results for the given scope!");
return result;
}
for (String operation : rtDataset.getValueSet(ResponseTimeRecord.PAR_OPERATION, String.class)) {
ParameterSelection selectOperation = new ParameterSelection().select(ResponseTimeRecord.PAR_OPERATION,
operation);
Dataset operationSpecificDataset = selectOperation.applyTo(rtDataset);
NumericPairList<Long, Double> responseTimeSeries = Utils.toTimestampRTPairs(operationSpecificDataset);
// sort chronologically
responseTimeSeries.sort();
long minTimestamp = responseTimeSeries.getKeyMin();
long diff = responseTimeSeries.getKeyMax() - responseTimeSeries.getKeyMin();
long midTimestamp = minTimestamp + (diff) / 2L;
List<Double> firstHalf = new ArrayList<>();
List<Double> secondHalf = new ArrayList<>();
for (NumericPair<Long, Double> valuePair : responseTimeSeries) {
if (valuePair.getKey() < midTimestamp) {
firstHalf.add(valuePair.getValue());
} else {
secondHalf.add(valuePair.getValue());
}
}
List<Double> sums1 = new ArrayList<>();
List<Double> sums2 = new ArrayList<>();
LpeNumericUtils.createNormalDistributionByBootstrapping(firstHalf, secondHalf, sums1, sums2);
double firstMean = LpeNumericUtils.average(sums1);
double secondMean = LpeNumericUtils.average(sums2);
double pValue = LpeNumericUtils.tTest(sums1, sums2);
if (pValue <= requiredSignificanceLevel && firstMean < secondMean) {
result.addMessage("Ramp detected in operation: " + operation);
result.setDetected(true);
}
createChart(result, operation, responseTimeSeries, minTimestamp, diff, sums1, sums2, firstMean, secondMean);
}
return result;
}
private void createChart(SpotterResult result, String operation, NumericPairList<Long, Double> responseTimeSeries,
long minTimestamp, long diff, List<Double> sums1, List<Double> sums2, double firstMean, double secondMean) {
double firstStdDev = LpeNumericUtils.stdDev(sums1);
double firstCIWidth = LpeNumericUtils.getConfidenceIntervalWidth(sums1.size(), firstStdDev,
requiredSignificanceLevel);
double secondStdDev = LpeNumericUtils.stdDev(sums2);
double secondCIWidth = LpeNumericUtils.getConfidenceIntervalWidth(sums2.size(), secondStdDev,
requiredSignificanceLevel);
AnalysisChartBuilder chartBuilder = AnalysisChartBuilder.getChartBuilder();
chartBuilder.startChart(operation, "Experiment Time [ms]", "Response Time [ms]");
// chartBuilder.addTimeSeries(responseTimeSeries, "Response Times");
NumericPairList<Long, Double> means = new NumericPairList<>();
List<Number> ci = new ArrayList<>();
means.add(minTimestamp + diff / 4L, firstMean);
ci.add(firstCIWidth / 2.0);
means.add(minTimestamp + (3L * diff) / 4L, secondMean);
ci.add(secondCIWidth / 2.0);
chartBuilder.addTimeSeriesWithErrorBars(means, ci, "Confidence Intervals");
mainDetectionController.getResultManager().storeImageChartResource(chartBuilder, "Ramp Detection (DG)",
result);
}
@Override
public long getExperimentSeriesDuration() {
return ProgressManager.getInstance().calculateDefaultExperimentSeriesDuration(1);
}
public InstrumentationDescription getInstrumentationDescription() {
InstrumentationDescriptionBuilder idBuilder = new InstrumentationDescriptionBuilder();
idBuilder.newAPIScopeEntity(EntryPointScope.class.getName()).addProbe(ResponsetimeProbe.MODEL_PROBE)
.entityDone();
return idBuilder.build();
}
}