package org.spotter.ext.detection.continuousViolation; 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.config.GlobalConfiguration; import org.lpe.common.extension.IExtension; import org.lpe.common.util.NumericPairList; import org.spotter.core.ProgressManager; import org.spotter.core.chartbuilder.AnalysisChartBuilder; import org.spotter.core.detection.AbstractDetectionController; import org.spotter.core.detection.IDetectionController; import org.spotter.core.detection.IExperimentReuser; import org.spotter.exceptions.WorkloadException; import org.spotter.ext.detection.continuousViolation.strategies.BucketStrategy; import org.spotter.ext.detection.continuousViolation.strategies.DBSCANStrategy; import org.spotter.ext.detection.continuousViolation.strategies.MovingPercentileStrategy; import org.spotter.ext.detection.continuousViolation.util.AnalysisConfig; import org.spotter.ext.detection.utils.Utils; import org.spotter.shared.configuration.ConfigKeys; import org.spotter.shared.result.model.SpotterResult; /** * Det4ection controller for continuous violation of performance requirements. * * @author Alexander Wert * */ public class ContinuousViolationController extends AbstractDetectionController implements IExperimentReuser { private String analysisStrategy; private AnalysisConfig analysisConfig = new AnalysisConfig(); private IViolationAnalysisStrategy analysisStrategyImpl; /** * Constructor. * * @param provider * extension provider */ public ContinuousViolationController(IExtension<IDetectionController> provider) { super(provider); } @Override public void loadProperties() { analysisStrategy = getProblemDetectionConfiguration().getProperty( ContinuousViolationExtension.VIOLATION_DETECTION_STRATEGY_KEY, ContinuousViolationExtension.DBSCAN_STRATEGY); String mvaWindowSize = getProblemDetectionConfiguration().getProperty( AnalysisConfig.MOVING_AVERAGE_WINDOW_SIZE_KEY, String.valueOf(AnalysisConfig.MOVING_AVERAGE_WINDOW_SIZE_DEFAULT)); analysisConfig.setMvaWindowSize(Integer.parseInt(mvaWindowSize)); String minBucketTimeProportionStr = getProblemDetectionConfiguration().getProperty( AnalysisConfig.MIN_BUCKET_TIME_PROPORTION_KEY, String.valueOf(AnalysisConfig.MIN_BUCKET_TIME_PROPORTION_DEFAULT)); analysisConfig.setMinBucketTimeProportion(Double.parseDouble(minBucketTimeProportionStr)); switch (analysisStrategy) { case ContinuousViolationExtension.DBSCAN_STRATEGY: analysisStrategyImpl = new DBSCANStrategy(); break; case ContinuousViolationExtension.PERCENTILE_STRATEGY: analysisStrategyImpl = new MovingPercentileStrategy(); break; case ContinuousViolationExtension.BUCKET_STRATEGY: analysisStrategyImpl = new BucketStrategy(); break; default: analysisStrategyImpl = new DBSCANStrategy(); } } @Override protected SpotterResult analyze(DatasetCollection data) { double perfReqThreshold = GlobalConfiguration.getInstance().getPropertyAsInteger( ConfigKeys.PERFORMANCE_REQUIREMENT_THRESHOLD, ConfigKeys.DEFAULT_PERFORMANCE_REQUIREMENT_THRESHOLD); double perfReqConfidence = GlobalConfiguration.getInstance().getPropertyAsDouble( ConfigKeys.PERFORMANCE_REQUIREMENT_CONFIDENCE, ConfigKeys.DEFAULT_PERFORMANCE_REQUIREMENT_CONFIDENCE); 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); if (responseTimeSeries.size() <= 5) { continue; } // sort chronologically responseTimeSeries.sort(); boolean detected = analysisStrategyImpl.analyze(responseTimeSeries, analysisConfig, perfReqThreshold, perfReqConfidence); if (detected) { result.addMessage("Detected continuous violation of performance requirements in operation: " + operation); result.setDetected(true); } createChart(perfReqThreshold, result, operation, responseTimeSeries); } return result; } private void createChart(double perfReqThreshold, SpotterResult result, String operation, NumericPairList<Long, Double> responseTimeSeries) { AnalysisChartBuilder chartBuilder = AnalysisChartBuilder.getChartBuilder(); String operationName = operation.contains("(")?operation.substring(0, operation.indexOf("(")):operation; chartBuilder.startChart(operationName, "experiment time [ms]", "response time [ms]"); chartBuilder.addTimeSeries(responseTimeSeries, "response times"); chartBuilder.addHorizontalLine(perfReqThreshold, "requirements threshold"); getResultManager().storeImageChartResource(chartBuilder, "Response Times", result); } @Override public void executeExperiments() throws InstrumentationException, MeasurementException, WorkloadException { executeDefaultExperimentSeries(this, 1, createInstrumentationDescription()); } @Override public InstrumentationDescription getInstrumentationDescription() { // no additional instrumentation required return null; } private InstrumentationDescription createInstrumentationDescription() { InstrumentationDescriptionBuilder idBuilder = new InstrumentationDescriptionBuilder(); idBuilder.newAPIScopeEntity(EntryPointScope.class.getName()).addProbe(ResponsetimeProbe.MODEL_PROBE) .entityDone(); return idBuilder.build(); } @Override public long getExperimentSeriesDuration() { return ProgressManager.getInstance().calculateDefaultExperimentSeriesDuration(1); } }