package org.spotter.ext.detection.ramp.strategies;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
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.Parameter;
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.config.GlobalConfiguration;
import org.lpe.common.util.LpeNumericUtils;
import org.lpe.common.util.NumericPairList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spotter.core.ProgressManager;
import org.spotter.core.chartbuilder.AnalysisChartBuilder;
import org.spotter.core.detection.AbstractDetectionController;
import org.spotter.core.workload.LoadConfig;
import org.spotter.exceptions.WorkloadException;
import org.spotter.ext.detection.ramp.IRampDetectionStrategy;
import org.spotter.ext.detection.ramp.RampDetectionController;
import org.spotter.ext.detection.ramp.RampExtension;
import org.spotter.shared.configuration.ConfigKeys;
import org.spotter.shared.result.model.SpotterResult;
import org.spotter.shared.status.DiagnosisStatus;
/**
* Utilizie stimulation phases to trigger the Ramp.
*
* @author Alexander Wert
*
*/
public class TimeWindowsStrategy implements IRampDetectionStrategy {
private static final Logger LOGGER = LoggerFactory.getLogger(TimeWindowsStrategy.class);
private static final String STEP = "step";
private static int stimulationPhaseDuration;
private static int experimentSteps;
private static int reuiqredSignificanceSteps;
private static double requiredSignificanceLevel;
private RampDetectionController mainDetectionController;
@Override
public void setProblemDetectionConfiguration(Properties problemDetectionConfiguration) {
String warmupPhaseStr = problemDetectionConfiguration
.getProperty(RampExtension.KEY_STIMULATION_PHASE_DURATION_FACTOR);
stimulationPhaseDuration = (int) ((warmupPhaseStr != null ? Double.parseDouble(warmupPhaseStr)
: RampExtension.STIMULATION_PHASE_DURATION_DEFAULT) * GlobalConfiguration.getInstance()
.getPropertyAsDouble(ConfigKeys.EXPERIMENT_DURATION));
String experimentStepsStr = problemDetectionConfiguration.getProperty(RampExtension.KEY_EXPERIMENT_STEPS);
experimentSteps = experimentStepsStr != null ? Integer.parseInt(experimentStepsStr)
: RampExtension.EXPERIMENT_STEPS_DEFAULT;
String significanceStepsStr = problemDetectionConfiguration
.getProperty(RampExtension.KEY_REQUIRED_SIGNIFICANT_STEPS);
reuiqredSignificanceSteps = significanceStepsStr != null ? Integer.parseInt(significanceStepsStr)
: RampExtension.REQUIRED_SIGNIFICANT_STEPS_DEFAULT;
String significanceLevelStr = problemDetectionConfiguration
.getProperty(RampExtension.KEY_REQUIRED_SIGNIFICANCE_LEVEL);
requiredSignificanceLevel = significanceLevelStr != null ? Double.parseDouble(significanceLevelStr)
: RampExtension.REQUIRED_SIGNIFICANCE_LEVEL_DEFAULT;
}
@Override
public void executeExperiments() throws InstrumentationException, MeasurementException {
try {
mainDetectionController.instrument(getInstrumentationDescription());
for (int i = 1; i <= experimentSteps; i++) {
if (i > 1) {
LOGGER.info("RampDetectionController step count ----{}----.", i);
LOGGER.info("RampDetectionController started to stimulate the SUT with {} users.",
GlobalConfiguration.getInstance().getPropertyAsInteger(ConfigKeys.WORKLOAD_MAXUSERS));
stimulateSystem(stimulationPhaseDuration);
LOGGER.info("RampDetectionController finalized to stimulate the SUT.");
}
LOGGER.info("RampDetectionController started to run a single user experiment.");
runExperiment(1, i);
LOGGER.info("RampDetectionController finalized to run a single user experiment.");
}
mainDetectionController.uninstrument();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void runExperiment(int numUsers, int stepNumber) throws WorkloadException, MeasurementException {
LOGGER.info("Ramp Detection (TimeWindowStrategy) started experiment with {} users ...", numUsers);
LoadConfig lConfig = new LoadConfig();
lConfig.setNumUsers(numUsers);
lConfig.setRampUpIntervalLength(GlobalConfiguration.getInstance().getPropertyAsInteger(
ConfigKeys.EXPERIMENT_RAMP_UP_INTERVAL_LENGTH));
lConfig.setRampUpUsersPerInterval(GlobalConfiguration.getInstance().getPropertyAsInteger(
ConfigKeys.EXPERIMENT_RAMP_UP_NUM_USERS_PER_INTERVAL));
lConfig.setCoolDownIntervalLength(GlobalConfiguration.getInstance().getPropertyAsInteger(
ConfigKeys.EXPERIMENT_COOL_DOWN_INTERVAL_LENGTH));
lConfig.setCoolDownUsersPerInterval(GlobalConfiguration.getInstance().getPropertyAsInteger(
ConfigKeys.EXPERIMENT_COOL_DOWN_NUM_USERS_PER_INTERVAL));
lConfig.setExperimentDuration(GlobalConfiguration.getInstance().getPropertyAsInteger(
ConfigKeys.EXPERIMENT_DURATION));
ProgressManager.getInstance().updateProgressStatus(mainDetectionController.getProblemId(),
DiagnosisStatus.EXPERIMENTING_RAMP_UP);
mainDetectionController.workloadAdapter().startLoad(lConfig);
mainDetectionController.workloadAdapter().waitForWarmupPhaseTermination();
ProgressManager.getInstance().updateProgressStatus(mainDetectionController.getProblemId(),
DiagnosisStatus.EXPERIMENTING_STABLE_PHASE);
mainDetectionController.measurementAdapter().enableMonitoring();
mainDetectionController.workloadAdapter().waitForExperimentPhaseTermination();
ProgressManager.getInstance().updateProgressStatus(mainDetectionController.getProblemId(),
DiagnosisStatus.EXPERIMENTING_COOL_DOWN);
mainDetectionController.measurementAdapter().disableMonitoring();
mainDetectionController.workloadAdapter().waitForFinishedLoad();
ProgressManager.getInstance().updateProgressStatus(mainDetectionController.getProblemId(),
DiagnosisStatus.COLLECTING_DATA);
LOGGER.info("Storing data ...");
long dataCollectionStart = System.currentTimeMillis();
Parameter numOfUsersParameter = new Parameter(STEP, stepNumber);
Set<Parameter> parameters = new TreeSet<>();
parameters.add(numOfUsersParameter);
mainDetectionController.getResultManager().storeResults(parameters,
mainDetectionController.measurementAdapter());
ProgressManager.getInstance().addAdditionalDuration(
(System.currentTimeMillis() - dataCollectionStart) / AbstractDetectionController.SECOND);
LOGGER.info("Data stored!");
}
private void stimulateSystem(int duration) throws WorkloadException {
LoadConfig lConfig = new LoadConfig();
lConfig.setNumUsers(GlobalConfiguration.getInstance().getPropertyAsInteger(ConfigKeys.WORKLOAD_MAXUSERS));
lConfig.setRampUpIntervalLength(GlobalConfiguration.getInstance().getPropertyAsInteger(
ConfigKeys.EXPERIMENT_RAMP_UP_INTERVAL_LENGTH));
lConfig.setRampUpUsersPerInterval(GlobalConfiguration.getInstance().getPropertyAsInteger(
ConfigKeys.EXPERIMENT_RAMP_UP_NUM_USERS_PER_INTERVAL));
lConfig.setCoolDownIntervalLength(GlobalConfiguration.getInstance().getPropertyAsInteger(
ConfigKeys.EXPERIMENT_COOL_DOWN_INTERVAL_LENGTH));
lConfig.setCoolDownUsersPerInterval(GlobalConfiguration.getInstance().getPropertyAsInteger(
ConfigKeys.EXPERIMENT_COOL_DOWN_NUM_USERS_PER_INTERVAL));
lConfig.setExperimentDuration(duration);
mainDetectionController.workloadAdapter().startLoad(lConfig);
mainDetectionController.workloadAdapter().waitForFinishedLoad();
}
public InstrumentationDescription getInstrumentationDescription() {
InstrumentationDescriptionBuilder idBuilder = new InstrumentationDescriptionBuilder();
idBuilder.newAPIScopeEntity(EntryPointScope.class.getName()).addProbe(ResponsetimeProbe.MODEL_PROBE)
.entityDone();
return idBuilder.build();
}
@Override
public long getExperimentSeriesDuration() {
long experimentDuration = ProgressManager.getInstance().calculateExperimentDuration(1,
GlobalConfiguration.getInstance().getPropertyAsInteger(ConfigKeys.EXPERIMENT_DURATION));
long stimulationDuration = ProgressManager.getInstance().calculateExperimentDuration(
GlobalConfiguration.getInstance().getPropertyAsInteger(ConfigKeys.WORKLOAD_MAXUSERS),
stimulationPhaseDuration);
return ((long) experimentSteps) * (stimulationDuration + experimentDuration);
}
@Override
public void setMainDetectionController(RampDetectionController mainDetectionController) {
this.mainDetectionController = mainDetectionController;
}
@Override
public SpotterResult analyze(DatasetCollection data) {
SpotterResult result = new SpotterResult();
Dataset rtDataset = data.getDataSets(ResponseTimeRecord.class).get(0);
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)) {
boolean operationDetected = analyseOperationResponseTimes(rtDataset, operation, result);
if (operationDetected) {
result.setDetected(true);
result.addMessage("Ramp detected in operation: " + operation);
}
}
return result;
}
private boolean analyseOperationResponseTimes(Dataset rtDataset, String operation, SpotterResult result) {
try {
int prevStep = -1;
int firstSignificantStep = -1;
int significantSteps = 0;
NumericPairList<Integer, Double> chartData = new NumericPairList<>();
NumericPairList<Integer, Double> chartDataMeans = new NumericPairList<>();
List<Number> confidenceIntervals = new ArrayList<>();
for (Integer step : rtDataset.getValueSet(STEP, Integer.class)) {
if (prevStep > 0) {
ParameterSelection selectionCurrent = new ParameterSelection().select(STEP, step).select(
ResponseTimeRecord.PAR_OPERATION, operation);
ParameterSelection selectionPrev = new ParameterSelection().select(STEP, prevStep).select(
ResponseTimeRecord.PAR_OPERATION, operation);
Dataset datasetCurrent = selectionCurrent.applyTo(rtDataset);
Dataset datasetPrev = selectionPrev.applyTo(rtDataset);
double prevMean = LpeNumericUtils.average(datasetPrev.getValues(
ResponseTimeRecord.PAR_RESPONSE_TIME, Long.class));
double currentMean = LpeNumericUtils.average(datasetCurrent.getValues(
ResponseTimeRecord.PAR_RESPONSE_TIME, Long.class));
// maybe the operation could not be found in one of the
// current
// selections
if (datasetCurrent == null || datasetPrev == null) {
prevStep = step;
continue;
}
List<Double> sums1 = new ArrayList<>();
List<Double> sums2 = new ArrayList<>();
double pValue = 0.0;
LpeNumericUtils.createNormalDistributionByBootstrapping(
datasetPrev.getValues(ResponseTimeRecord.PAR_RESPONSE_TIME, Long.class),
datasetCurrent.getValues(ResponseTimeRecord.PAR_RESPONSE_TIME, Long.class), sums1, sums2);
pValue = LpeNumericUtils.tTest(sums2, sums1);
if (pValue <= requiredSignificanceLevel && currentMean > prevMean) {
if (firstSignificantStep < 0) {
firstSignificantStep = prevStep;
}
significantSteps++;
} else {
firstSignificantStep = -1;
significantSteps = 0;
}
// create data for chart
if (prevStep == 1) {
for (Double value : sums1) {
chartData.add(prevStep, value);
}
chartDataMeans.add(prevStep, LpeNumericUtils.average(sums1));
double stdDev = LpeNumericUtils.stdDev(sums1);
double width = LpeNumericUtils.getConfidenceIntervalWidth(sums1.size(), stdDev,
requiredSignificanceLevel);
confidenceIntervals.add(width / 2.0);
}
for (Double value : sums2) {
chartData.add(step, value);
}
chartDataMeans.add(step, LpeNumericUtils.average(sums2));
double stdDev = LpeNumericUtils.stdDev(sums2);
double width = LpeNumericUtils.getConfidenceIntervalWidth(sums2.size(), stdDev,
requiredSignificanceLevel);
confidenceIntervals.add(width / 2.0);
}
prevStep = step;
}
createChart(operation, result, chartData, chartDataMeans, confidenceIntervals);
if (firstSignificantStep > 0 && significantSteps >= reuiqredSignificanceSteps) {
return true;
}
return false;
} catch (Exception e) {
return false;
}
}
private void createChart(String operation, SpotterResult result, NumericPairList<Integer, Double> chartData,
NumericPairList<Integer, Double> chartDataMeans, List<Number> confidenceIntervals) {
AnalysisChartBuilder chartBuilder = AnalysisChartBuilder.getChartBuilder();
String operationName = operation.contains("(")?operation.substring(0, operation.indexOf("(")):operation;
chartBuilder.startChart(operationName, "experiment", "response time [ms]");
// chartBuilder.addTimeSeries(chartData, "Response Times");
chartBuilder.addScatterSeriesWithErrorBars(chartDataMeans, confidenceIntervals, "avg. response times");
mainDetectionController.getResultManager().storeImageChartResource(chartBuilder, "Ramp Detection (TW)", result);
}
}