/**
* Copyright 2014 SAP AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.spotter.core;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import org.aim.api.exceptions.InstrumentationException;
import org.aim.api.exceptions.MeasurementException;
import org.lpe.common.config.GlobalConfiguration;
import org.lpe.common.util.LpeFileUtils;
import org.lpe.common.util.LpeNumericUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spotter.core.config.interpretation.HierarchyFactory;
import org.spotter.core.config.interpretation.HierarchyModelInterpreter;
import org.spotter.core.config.interpretation.MeasurementEnvironmentFactory;
import org.spotter.core.config.interpretation.PerformanceProblem;
import org.spotter.core.detection.AbstractDetectionController;
import org.spotter.core.detection.IDetectionController;
import org.spotter.core.instrumentation.IInstrumentationAdapter;
import org.spotter.core.instrumentation.InstrumentationBroker;
import org.spotter.core.measurement.IMeasurementAdapter;
import org.spotter.core.measurement.MeasurementBroker;
import org.spotter.core.result.ResultBlackboard;
import org.spotter.core.workload.IWorkloadAdapter;
import org.spotter.core.workload.WorkloadAdapterBroker;
import org.spotter.exceptions.WorkloadException;
import org.spotter.shared.configuration.ConfigCheck;
import org.spotter.shared.configuration.ConfigKeys;
import org.spotter.shared.hierarchy.model.XPerformanceProblem;
import org.spotter.shared.result.ResultsLocationConstants;
import org.spotter.shared.result.model.ResultsContainer;
import org.spotter.shared.result.model.SpotterResult;
import org.spotter.shared.status.DiagnosisStatus;
import org.spotter.shared.status.SpotterProgress;
/**
* Main Controller for Performance Problem Diagnostics.
*
* @author Alexander Wert
*
*/
public final class Spotter {
private static final Logger LOGGER = LoggerFactory.getLogger(Spotter.class);
private static Spotter instance;
private ResultsContainer resultsContainer;
private String diagnosisResultFolder;
/**
*
* @return singleton instance
*/
public static synchronized Spotter getInstance() {
if (instance == null) {
instance = new Spotter();
}
return instance;
}
/**
* Constructor.
*/
private Spotter() {
resultsContainer = new ResultsContainer();
diagnosisResultFolder = null;
}
/**
* Executes diagnostics process.
*
* @param configurationFile
* path to the configuration file
* @throws WorkloadException
* thrown if a problem with workload generation occurs
* @throws MeasurementException
* thrown if a problem with measurement data retrieval occurs
* @throws InstrumentationException
* thrown if a problem with instrumentation occurs
*/
public void startDiagnosis(String configurationFile) throws InstrumentationException, MeasurementException,
WorkloadException {
long startTime = System.currentTimeMillis();
startDiagnosis(configurationFile, startTime);
}
/**
* Executes diagnostics process.
*
* @param configurationFile
* path to the configuration file
* @param timestamp
* timestamp of that run
* @throws WorkloadException
* if workload generation fails
* @throws MeasurementException
* if retrieving measurement data fails
* @throws InstrumentationException
* if instrumentation fails
*/
public synchronized void startDiagnosis(String configurationFile, long timestamp) throws InstrumentationException,
MeasurementException, WorkloadException {
resultsContainer = new ResultsContainer();
GlobalConfiguration.reinitialize(configurationFile);
try {
GlobalConfiguration.getInstance().putProperty(ConfigKeys.PPD_RUN_TIMESTAMP, String.valueOf(timestamp));
ConfigCheck.checkConfiguration();
diagnosisResultFolder = GlobalConfiguration.getInstance().getProperty(ConfigKeys.RESULT_DIR);
if (!GlobalConfiguration.getInstance().getPropertyAsBoolean(ConfigKeys.OMIT_EXPERIMENTS, false)) {
initializeMeasurementEnvironment();
}
PerformanceProblem problem = retrieveRootPerformanceProblem(resultsContainer);
HierarchyModelInterpreter hierarchyModelInterpreter = new HierarchyModelInterpreter(problem);
problem = hierarchyModelInterpreter.next();
AbstractDetectionController.sutWarmedUp = false;
ProgressManager.getInstance().reset();
ProgressManager.getInstance().start();
while (problem != null) {
IDetectionController detectionController = problem.getDetectionController();
ProgressManager.getInstance().setController((AbstractDetectionController) detectionController);
SpotterResult result = detectionController.analyzeProblem();
if (result.isDetected()) {
ProgressManager.getInstance().updateProgressStatus(problem.getUniqueId(), DiagnosisStatus.DETECTED);
} else {
ProgressManager.getInstance().updateProgressStatus(problem.getUniqueId(),
DiagnosisStatus.NOT_DETECTED);
}
ResultBlackboard.getInstance().putResult(problem, result);
problem = hierarchyModelInterpreter.next();
}
long durationMillis = ((System.currentTimeMillis() - timestamp));
resultsContainer.setResultsMap(ResultBlackboard.getInstance().getResults());
String report = printResults(durationMillis);
resultsContainer.setReport(report);
serializeResults(resultsContainer);
} finally {
ProgressManager.getInstance().stop();
ResultBlackboard.getInstance().reset();
resultsContainer.reset();
}
}
/**
* Reads the performance problem hierarchy file and returns the root
* performance problem of that hierarchy.
*
* @param resultsContainer
* container in which to store the original root problem
* @return the root problem
*/
private PerformanceProblem retrieveRootPerformanceProblem(ResultsContainer resultsContainer) {
String hierarchyFileName = GlobalConfiguration.getInstance()
.getProperty(ConfigKeys.CONF_PROBLEM_HIERARCHY_FILE);
if (hierarchyFileName == null || !new File(hierarchyFileName).exists()) {
throw new IllegalArgumentException(
"Please provide a proper configuration for the performance problem hierarchy file!");
}
PerformanceProblem problem = HierarchyFactory.getInstance().createPerformanceProblemHierarchy(
hierarchyFileName, resultsContainer);
if (problem.getChildren().isEmpty()) {
throw new IllegalArgumentException(
"The performance problem hierarchy file does not contain at least one problem!");
}
return problem;
}
/**
* Writes the Spotter report and returns the text that was printed.
*
* @param durationMillis
* time in milli seconds the diagnostics took
* @return the printed text
*/
private String printResults(long durationMillis) {
StringBuilder builder = new StringBuilder();
builder.append("PPD analysis took ");
builder.append(LpeNumericUtils.formatTimeMillis(durationMillis));
builder.append(System.getProperty("line.separator"));
builder.append(System.getProperty("line.separator"));
builder.append(ResultBlackboard.getInstance().toString());
String resultString = builder.toString();
String outputFile = diagnosisResultFolder + ResultsLocationConstants.TXT_REPORT_FILE_NAME;
try {
FileWriter fstream = new FileWriter(outputFile);
BufferedWriter out = new BufferedWriter(fstream);
out.write(resultString);
out.close();
} catch (Exception e) {
LOGGER.error("Failed writing result report to file {}! ", outputFile);
}
LOGGER.info("Spotter analysis finished! Report is written to the following file: {}", outputFile);
return resultString;
}
/**
* Serializes the results to file.
*
* @param resultsContainer
* container with the collected results to serialize
*/
private void serializeResults(ResultsContainer resultsContainer) {
String outputFile = diagnosisResultFolder + ResultsLocationConstants.RESULTS_SERIALIZATION_FILE_NAME;
try {
LpeFileUtils.writeObject(outputFile, resultsContainer);
LOGGER.info("Serialized results to the following file: {}", outputFile);
} catch (IOException e) {
LOGGER.error("Failed serializing results to file {}! Cause: {}", outputFile, e.getMessage());
}
}
/**
* @return the progress
*/
public SpotterProgress getProgress() {
return ProgressManager.getInstance().getSpotterProgress();
}
/**
* @return the current diagnosis result folder
*/
public String getDiagnosisResultFolder() {
return diagnosisResultFolder;
}
/**
* @return the current root problem, may be <code>null</code>
*/
public XPerformanceProblem getCurrentRootProblem() {
return resultsContainer.getRootProblem();
}
/**
* Initializes the measurement environment. Reads the environment
* description from XML file and creates corresponding Java objects
*/
private void initializeMeasurementEnvironment() throws InstrumentationException, MeasurementException,
WorkloadException {
if (!GlobalConfiguration.getInstance().getPropertyAsBoolean(ConfigKeys.OMIT_EXPERIMENTS, false)) {
initInstrumentationController();
initMeasurementController();
initWorkloadAdapter();
}
}
private void initWorkloadAdapter() throws WorkloadException {
String measurementEnvironmentFile = GlobalConfiguration.getInstance().getProperty(
ConfigKeys.MEASUREMENT_ENVIRONMENT_FILE);
if (measurementEnvironmentFile == null) {
throw new WorkloadException("Measurement Environment File has not been specified!");
}
List<IWorkloadAdapter> wlAdapters = MeasurementEnvironmentFactory.getInstance().createWorkloadAdapters(
measurementEnvironmentFile);
WorkloadAdapterBroker workloadAdapter = WorkloadAdapterBroker.getInstance();
workloadAdapter.setControllers(wlAdapters);
workloadAdapter.initialize();
}
private void initMeasurementController() throws InstrumentationException, MeasurementException {
String measurementEnvironmentFile = GlobalConfiguration.getInstance().getProperty(
ConfigKeys.MEASUREMENT_ENVIRONMENT_FILE);
if (measurementEnvironmentFile == null) {
throw new InstrumentationException("Measurement Environment File has not been specified!");
}
List<IMeasurementAdapter> controllers = MeasurementEnvironmentFactory.getInstance()
.createMeasurementControllers(measurementEnvironmentFile);
MeasurementBroker measurementController = MeasurementBroker.getInstance();
measurementController.setControllers(controllers);
measurementController.initialize();
}
private void initInstrumentationController() throws InstrumentationException {
String measurementEnvironmentFile = GlobalConfiguration.getInstance().getProperty(
ConfigKeys.MEASUREMENT_ENVIRONMENT_FILE);
if (measurementEnvironmentFile == null) {
throw new InstrumentationException("Measurement Environment File has not been specified!");
}
List<IInstrumentationAdapter> instrumentations = MeasurementEnvironmentFactory.getInstance()
.createInstrumentationControllers(measurementEnvironmentFile);
InstrumentationBroker instrumentationController = InstrumentationBroker.getInstance();
instrumentationController.setControllers(instrumentations);
instrumentationController.initialize();
}
}