1 | package de.uka.ipd.sdq.dsexplore.analysis.lqn; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.HashMap; |
5 | import java.util.Iterator; |
6 | import java.util.LinkedList; |
7 | import java.util.List; |
8 | import java.util.Map; |
9 | |
10 | import org.apache.log4j.Logger; |
11 | import org.eclipse.core.runtime.CoreException; |
12 | import org.eclipse.core.runtime.IProgressMonitor; |
13 | import org.eclipse.debug.core.ILaunchConfiguration; |
14 | import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; |
15 | import org.eclipse.debug.core.ILaunchManager; |
16 | import org.opt4j.core.Criterion; |
17 | import org.opt4j.core.InfeasibilityConstraint; |
18 | import org.opt4j.core.Objective; |
19 | import org.opt4j.core.SatisfactionConstraint; |
20 | |
21 | import LqnCore.LqnModelType; |
22 | import de.uka.ipd.sdq.dsexplore.analysis.AnalysisFailedException; |
23 | import de.uka.ipd.sdq.dsexplore.analysis.IAnalysis; |
24 | import de.uka.ipd.sdq.dsexplore.analysis.IAnalysisResult; |
25 | import de.uka.ipd.sdq.dsexplore.analysis.PCMPhenotype; |
26 | import de.uka.ipd.sdq.dsexplore.launch.DSEWorkflowConfiguration; |
27 | import de.uka.ipd.sdq.dsexplore.launch.DSEConstantsContainer.QualityAttribute; |
28 | import de.uka.ipd.sdq.dsexplore.qml.contract.QMLContract.EvaluationAspect; |
29 | import de.uka.ipd.sdq.dsexplore.qml.contracttype.QMLContractType.Dimension; |
30 | import de.uka.ipd.sdq.dsexplore.qml.pcm.datastructures.EvaluationAspectWithContext; |
31 | import de.uka.ipd.sdq.dsexplore.qml.pcm.datastructures.UsageScenarioBasedObjective; |
32 | import de.uka.ipd.sdq.dsexplore.qml.pcm.datastructures.builder.EntryLevelSystemCallInfeasibilityConstraintBuilder; |
33 | import de.uka.ipd.sdq.dsexplore.qml.pcm.datastructures.builder.EntryLevelSystemCallObjectiveBuilder; |
34 | import de.uka.ipd.sdq.dsexplore.qml.pcm.datastructures.builder.EntryLevelSystemCallSatisfactionConstraintBuilder; |
35 | import de.uka.ipd.sdq.dsexplore.qml.pcm.datastructures.builder.UsageScenarioBasedInfeasibilityConstraintBuilder; |
36 | import de.uka.ipd.sdq.dsexplore.qml.pcm.datastructures.builder.UsageScenarioBasedObjectiveBuilder; |
37 | import de.uka.ipd.sdq.dsexplore.qml.pcm.datastructures.builder.UsageScenarioBasedSatisfactionConstraintBuilder; |
38 | import de.uka.ipd.sdq.dsexplore.qml.pcm.reader.PCMDeclarationsReader; |
39 | import de.uka.ipd.sdq.dsexplore.qml.profile.QMLProfile.EntryLevelSystemCallRequirement; |
40 | import de.uka.ipd.sdq.dsexplore.qml.profile.QMLProfile.UsageScenarioRequirement; |
41 | import de.uka.ipd.sdq.pcm.usagemodel.EntryLevelSystemCall; |
42 | import de.uka.ipd.sdq.pcm.usagemodel.UsageModel; |
43 | import de.uka.ipd.sdq.pcm.usagemodel.UsageScenario; |
44 | import de.uka.ipd.sdq.pcmsolver.RunPCMAnalysisJob; |
45 | import de.uka.ipd.sdq.pcmsolver.models.PCMInstance; |
46 | import de.uka.ipd.sdq.pcmsolver.runconfig.MessageStrings; |
47 | import de.uka.ipd.sdq.pcmsolver.runconfig.PCMSolverConfigurationBasedConfigBuilder; |
48 | import de.uka.ipd.sdq.pcmsolver.runconfig.PCMSolverWorkflowRunConfiguration; |
49 | import de.uka.ipd.sdq.pcmsolver.transformations.SolverStrategy; |
50 | import de.uka.ipd.sdq.pcmsolver.transformations.pcm2lqn.LqnXmlHandler; |
51 | import de.uka.ipd.sdq.pcmsolver.transformations.pcm2lqn.Pcm2LqnStrategy; |
52 | import de.uka.ipd.sdq.workflow.exceptions.JobFailedException; |
53 | import de.uka.ipd.sdq.workflow.exceptions.UserCanceledException; |
54 | import de.uka.ipd.sdq.workflow.launchconfig.AbstractWorkflowConfigurationBuilder; |
55 | import de.uka.ipd.sdq.workflow.mdsd.blackboard.MDSDBlackboard; |
56 | import de.uka.ipd.sdq.workflow.pcm.blackboard.PCMResourceSetPartition; |
57 | import de.uka.ipd.sdq.workflow.pcm.configurations.PCMWorkflowConfigurationBuilder; |
58 | import de.uka.ipd.sdq.workflow.pcm.jobs.LoadPCMModelsIntoBlackboardJob; |
59 | |
60 | public abstract class AbstractLQNAnalysis implements IAnalysis { |
61 | |
62 | /** Logger for log4j. */ |
63 | protected static Logger logger = |
64 | Logger.getLogger("de.uka.ipd.sdq.dsexplore.analysis.lqn.LQNSolverAnalysis"); |
65 | |
66 | |
67 | /** |
68 | * Store the launch parameters so that we do not have to pass them all the |
69 | * time. |
70 | */ |
71 | private ILaunchConfiguration config; |
72 | |
73 | protected int iteration = -1; |
74 | |
75 | private MDSDBlackboard blackboard; |
76 | |
77 | protected LQNQualityAttributeDeclaration lQNQualityAttribute = new LQNQualityAttributeDeclaration(); |
78 | |
79 | //Criteria handling |
80 | private List<Criterion> criteriaList = new ArrayList<Criterion>(); |
81 | protected Map<Criterion, EvaluationAspectWithContext> criterionToAspect = new HashMap<Criterion, EvaluationAspectWithContext>(); //This is needed to determine, what THE result is (Mean, Variance, ...) |
82 | |
83 | |
84 | private Map<Long, String> previousResultFileName = new HashMap<Long, String>(); |
85 | |
86 | // cache for LQN models so that they do not have to be loaded so often. Limited capacity (below) to not store too many models. |
87 | private LinkedList<LqnModelType> recentModels = new LinkedList<LqnModelType>(); |
88 | private static int RECENT_MODEL_CAPACITY = 10; |
89 | |
90 | /** |
91 | * {@inheritDoc} |
92 | * @throws UserCanceledException |
93 | */ |
94 | public void analyse(PCMPhenotype pheno, IProgressMonitor monitor) |
95 | throws AnalysisFailedException, CoreException, UserCanceledException { |
96 | |
97 | ILaunchConfigurationWorkingCopy wcopy = this.config.getWorkingCopy(); |
98 | wcopy.setAttribute(MessageStrings.SOLVER, |
99 | this.getSolverMessageString()); |
100 | this.config = wcopy.doSave(); |
101 | |
102 | iteration++; |
103 | |
104 | PCMInstance pcm = new PCMInstance((PCMResourceSetPartition)this.blackboard.getPartition(LoadPCMModelsIntoBlackboardJob.PCM_MODELS_PARTITION_ID)); |
105 | |
106 | try { |
107 | launchLQNSolver(pheno, monitor); |
108 | //IAnalysisResult result = retrieveLQNSolverResults(pcm); |
109 | //return result; |
110 | } catch (RuntimeException e){ |
111 | handleException(e, pcm); |
112 | } |
113 | |
114 | |
115 | } |
116 | |
117 | /** |
118 | * FIXME: Make this method independent of the blackboard state. |
119 | */ |
120 | public IAnalysisResult retrieveResultsFor(PCMPhenotype pheno, Criterion criterion) throws AnalysisFailedException{ |
121 | PCMInstance pcm = new PCMInstance((PCMResourceSetPartition)this.blackboard.getPartition(LoadPCMModelsIntoBlackboardJob.PCM_MODELS_PARTITION_ID)); |
122 | IAnalysisResult result = retrieveLQNSolverResults(pheno, pcm,criterion); |
123 | return result; |
124 | } |
125 | |
126 | /** |
127 | * try to handle the exception or throw it back. |
128 | * @param e |
129 | * @param pcm |
130 | * @return |
131 | */ |
132 | protected abstract IAnalysisResult handleException(RuntimeException e, PCMInstance pcm); |
133 | |
134 | protected abstract String getSolverMessageString(); |
135 | |
136 | ILQNResult retrieveLQNSolverResults(PCMPhenotype pheno, PCMInstance pcm, Criterion criterion) throws AnalysisFailedException { |
137 | |
138 | String xmlFileName = this.previousResultFileName.get(pheno.getNumericID()); |
139 | |
140 | // check recent models if the one is in there |
141 | LqnModelType model = null; |
142 | for (LqnModelType recentModel : this.recentModels) { |
143 | if (isFileNameBelongsToModel(xmlFileName, recentModel)){ |
144 | model = recentModel; |
145 | } |
146 | } |
147 | |
148 | // if not, read in from file. |
149 | if (model == null){ |
150 | // Read XML output file generated by LQNSolver |
151 | model = LqnXmlHandler.loadModelFromXMI(xmlFileName); |
152 | } |
153 | |
154 | if (model == null){ |
155 | throw new AnalysisFailedException("LQN model "+xmlFileName+" could not be loaded. See previous logging entries for details."); |
156 | } |
157 | |
158 | // delete the oldest model from the recent model list; and add the current one. |
159 | if (this.recentModels.size() >= RECENT_MODEL_CAPACITY){ |
160 | this.recentModels.pollLast(); |
161 | } |
162 | |
163 | this.recentModels.push(model); |
164 | |
165 | ILQNResult result = retrieveResult(pcm, model, criterion); |
166 | return result; |
167 | |
168 | } |
169 | |
170 | private boolean isFileNameBelongsToModel(String xmlFileName, |
171 | LqnModelType recentModel) { |
172 | String modelString = recentModel.eResource().getURI().toString(); |
173 | modelString = modelString.substring(modelString.lastIndexOf("/")+1); |
174 | return xmlFileName.contains(modelString); |
175 | } |
176 | |
177 | protected abstract ILQNResult retrieveResult(PCMInstance pcm, |
178 | LqnModelType model, Criterion criterion) throws AnalysisFailedException; |
179 | |
180 | /** |
181 | * Launches the LQN Solver. |
182 | * @param monitor |
183 | * |
184 | * @param pcmInstance the instance of PCM |
185 | * @return |
186 | * @throws AnalysisFailedException |
187 | * @throws CoreException |
188 | * @throws UserCanceledException |
189 | */ |
190 | private void launchLQNSolver(PCMPhenotype pheno, IProgressMonitor monitor) |
191 | throws AnalysisFailedException, CoreException, UserCanceledException { |
192 | |
193 | if (monitor == null){ |
194 | throw new AnalysisFailedException(this.getClass().getName()+" was not correctly initialised."); |
195 | } |
196 | |
197 | |
198 | PCMSolverWorkflowRunConfiguration solverConfiguration = new PCMSolverWorkflowRunConfiguration(); |
199 | AbstractWorkflowConfigurationBuilder builder; |
200 | |
201 | builder = new PCMWorkflowConfigurationBuilder(this.config, ILaunchManager.RUN_MODE); |
202 | builder.fillConfiguration(solverConfiguration); |
203 | |
204 | builder = new PCMSolverConfigurationBasedConfigBuilder(this.config, |
205 | ILaunchManager.RUN_MODE); |
206 | builder.fillConfiguration(solverConfiguration); |
207 | solverConfiguration.setInteractive(false); |
208 | |
209 | |
210 | // Create a new Analysis job |
211 | RunPCMAnalysisJob solverJob = new RunPCMAnalysisJob(solverConfiguration); |
212 | |
213 | solverJob.setBlackboard(blackboard); |
214 | SolverStrategy strategy = solverJob.getStrategy(); |
215 | if (strategy instanceof Pcm2LqnStrategy){ |
216 | this.previousResultFileName.put(pheno.getNumericID(), ((Pcm2LqnStrategy)strategy).getFilenameResultXML()); |
217 | } |
218 | |
219 | try { |
220 | |
221 | //TODO catch exceptions due to convergence problems and handle them nicely. For example, set the response time to MAXINT or similar. |
222 | |
223 | //execute the job |
224 | solverJob.execute(monitor); |
225 | |
226 | logger.debug("Finished PCMSolver LQN analysis"); |
227 | |
228 | } catch (JobFailedException e) { |
229 | logger.error(e.getMessage()); |
230 | throw new AnalysisFailedException(e); |
231 | } |
232 | |
233 | |
234 | } |
235 | |
236 | /** |
237 | * {@inheritDoc} |
238 | * @throws CoreException |
239 | * @see de.uka.ipd.sdq.dsexplore.analysis.IAnalysis#initialise(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor) |
240 | */ |
241 | @Override |
242 | public void initialise(DSEWorkflowConfiguration configuration) throws CoreException { |
243 | this.config = configuration.getRawConfiguration(); |
244 | |
245 | PCMInstance pcmInstance = new PCMInstance((PCMResourceSetPartition)this.blackboard.getPartition(LoadPCMModelsIntoBlackboardJob.PCM_MODELS_PARTITION_ID)); |
246 | List<UsageScenario> scenarios = pcmInstance.getUsageModel().getUsageScenario_UsageModel(); |
247 | |
248 | initialiseCriteria(this.config, scenarios); |
249 | |
250 | // this.objectives = new ArrayList<Objective>(scenarios.size()); |
251 | // for (UsageScenario usageScenario : scenarios) { |
252 | // //FIXME: hardcoded usage scenario selection |
253 | // String scenName = usageScenario.getEntityName(); |
254 | // if (!scenName.contains("AlarmRetrieve") |
255 | // && !scenName.contains("Wrapper") |
256 | // && !scenName.contains("HistoryRetrieve")){ |
257 | // objectives.add(new UsageScenarioBasedObjective(this.getQualityAttribute(), Objective.Sign.MIN, usageScenario)); |
258 | // } |
259 | // } |
260 | |
261 | |
262 | } |
263 | |
264 | private void initialiseCriteria(ILaunchConfiguration configuration, List<UsageScenario> scenarios) throws CoreException{ |
265 | PCMInstance pcm = new PCMInstance((PCMResourceSetPartition)this.blackboard.getPartition(LoadPCMModelsIntoBlackboardJob.PCM_MODELS_PARTITION_ID)); |
266 | UsageModel usageModel = pcm.getUsageModel(); |
267 | |
268 | PCMDeclarationsReader reader = new PCMDeclarationsReader( |
269 | configuration.getAttribute("qmlDefinitionFile", "")); |
270 | |
271 | List<Dimension> dimensions = this.lQNQualityAttribute.getDimensions(); |
272 | |
273 | List<EvaluationAspectWithContext> responseTimeAspect = new ArrayList<EvaluationAspectWithContext>(6); |
274 | for (Dimension dimension : dimensions) { |
275 | responseTimeAspect.addAll(reader.getDimensionConstraintContextsForUsageModel(usageModel, dimension.getId())); |
276 | responseTimeAspect.addAll(reader.getDimensionObjectiveContextsForUsageModel(usageModel, dimension.getId())); |
277 | } |
278 | |
279 | //Check constraint aspects and create Constraint-Objects for every Aspect |
280 | for (Iterator<EvaluationAspectWithContext> iterator = responseTimeAspect.iterator(); iterator.hasNext();) { |
281 | EvaluationAspectWithContext aspectContext = iterator |
282 | .next(); |
283 | //handle possible aspects here |
284 | if (canEvaluateAspect(aspectContext.getEvaluationAspect(), aspectContext.getDimension())) { |
285 | |
286 | if(aspectContext.getRequirement() instanceof UsageScenarioRequirement) { |
287 | |
288 | if(((UsageScenarioRequirement)aspectContext.getRequirement()).getUsageScenario() == null) { |
289 | //The criterion refers to EVERY US since none is explicitly specified |
290 | for (Iterator<UsageScenario> iterator2 = scenarios.iterator(); iterator2.hasNext();) { |
291 | UsageScenario usageScenario = (UsageScenario) iterator2 |
292 | .next(); |
293 | |
294 | //FIXME: hardcoded usage scenario selection. Delete after a while |
295 | String scenName = usageScenario.getEntityName(); |
296 | if (scenName.contains("AlarmRetrieve") |
297 | || scenName.contains("Wrapper") |
298 | || scenName.contains("HistoryRetrieve")){ |
299 | // continue; |
300 | logger.warn("ABB usage scenarios encountered that used to be ignored, but this special case has been removed again. Check whether this is ok."); |
301 | } |
302 | |
303 | if(aspectContext.getCriterion() instanceof de.uka.ipd.sdq.dsexplore.qml.contract.QMLContract.Constraint) { |
304 | UsageScenarioBasedInfeasibilityConstraintBuilder builder = new UsageScenarioBasedInfeasibilityConstraintBuilder(usageScenario); |
305 | InfeasibilityConstraint c = |
306 | reader.translateEvalAspectToInfeasibilityConstraint(aspectContext, builder); |
307 | |
308 | criteriaList.add(c); |
309 | criterionToAspect.put(c, aspectContext); |
310 | } else { |
311 | //instanceof Objective |
312 | UsageScenarioBasedObjectiveBuilder objectiveBuilder = new UsageScenarioBasedObjectiveBuilder(usageScenario); |
313 | Objective o = reader.translateEvalAspectToObjective(this.getQualityAttribute().getName(), aspectContext, objectiveBuilder); |
314 | criteriaList.add(o); |
315 | criterionToAspect.put(o, aspectContext); |
316 | |
317 | UsageScenarioBasedSatisfactionConstraintBuilder builder = new UsageScenarioBasedSatisfactionConstraintBuilder(usageScenario); |
318 | SatisfactionConstraint c = |
319 | reader.translateEvalAspectToSatisfactionConstraint(aspectContext, o, builder); |
320 | criteriaList.add(c); |
321 | criterionToAspect.put(c, aspectContext); |
322 | } |
323 | } |
324 | } else { |
325 | if(aspectContext.getCriterion() instanceof de.uka.ipd.sdq.dsexplore.qml.contract.QMLContract.Constraint) { |
326 | UsageScenarioBasedInfeasibilityConstraintBuilder builder = new UsageScenarioBasedInfeasibilityConstraintBuilder(((UsageScenarioRequirement)aspectContext.getRequirement()).getUsageScenario()); |
327 | |
328 | InfeasibilityConstraint c = |
329 | reader.translateEvalAspectToInfeasibilityConstraint(aspectContext, builder); |
330 | criteriaList.add(c); |
331 | criterionToAspect.put(c, aspectContext); |
332 | } else { |
333 | //instanceof Objective |
334 | UsageScenarioBasedObjectiveBuilder objectiveBuilder = new UsageScenarioBasedObjectiveBuilder(((UsageScenarioRequirement)aspectContext.getRequirement()).getUsageScenario()); |
335 | Objective o = reader.translateEvalAspectToObjective(this.getQualityAttribute().getName(), aspectContext, objectiveBuilder); |
336 | criteriaList.add(o); |
337 | criterionToAspect.put(o, aspectContext); |
338 | |
339 | UsageScenarioBasedSatisfactionConstraintBuilder builder = new UsageScenarioBasedSatisfactionConstraintBuilder(((UsageScenarioRequirement)aspectContext.getRequirement()).getUsageScenario()); |
340 | |
341 | SatisfactionConstraint c = |
342 | reader.translateEvalAspectToSatisfactionConstraint(aspectContext, o, builder); |
343 | criteriaList.add(c); |
344 | criterionToAspect.put(c, aspectContext); |
345 | } |
346 | } |
347 | |
348 | } else if (aspectContext.getRequirement() instanceof EntryLevelSystemCallRequirement) { |
349 | if(aspectContext.getCriterion() instanceof de.uka.ipd.sdq.dsexplore.qml.contract.QMLContract.Constraint) { |
350 | EntryLevelSystemCallInfeasibilityConstraintBuilder builder = new EntryLevelSystemCallInfeasibilityConstraintBuilder(((EntryLevelSystemCallRequirement)aspectContext.getRequirement()).getEntryLevelSystemCall()); |
351 | InfeasibilityConstraint c = |
352 | reader.translateEvalAspectToInfeasibilityConstraint(aspectContext, builder); |
353 | criteriaList.add(c); |
354 | criterionToAspect.put(c, aspectContext); |
355 | } else { |
356 | //instanceof Objective |
357 | EntryLevelSystemCall entryLevelSystemCall = ((EntryLevelSystemCallRequirement)aspectContext.getRequirement()).getEntryLevelSystemCall(); |
358 | EntryLevelSystemCallObjectiveBuilder builder = new EntryLevelSystemCallObjectiveBuilder(entryLevelSystemCall); |
359 | |
360 | Objective o = reader.translateEvalAspectToObjective(this.getQualityAttribute().getName(), aspectContext, builder); |
361 | criteriaList.add(o); |
362 | criterionToAspect.put(o, aspectContext); |
363 | |
364 | EntryLevelSystemCallSatisfactionConstraintBuilder satisBuilder = new EntryLevelSystemCallSatisfactionConstraintBuilder(entryLevelSystemCall); |
365 | SatisfactionConstraint c = |
366 | reader.translateEvalAspectToSatisfactionConstraint(aspectContext, o, satisBuilder); |
367 | criteriaList.add(c); |
368 | criterionToAspect.put(c, aspectContext); |
369 | } |
370 | |
371 | } else { |
372 | throw new RuntimeException("Unsupported Requirement!"); |
373 | } |
374 | } else { |
375 | //XXX: This should never be the case if the optimization is started with the LaunchConfig the aspect is checked there as well |
376 | throw new RuntimeException("Evaluation aspect not supported("+aspectContext.getEvaluationAspect()+")!"); |
377 | } |
378 | } |
379 | } |
380 | |
381 | private boolean canEvaluateAspect(EvaluationAspect aspect, Dimension dimension){ |
382 | return lQNQualityAttribute.canEvaluateAspectForDimension(aspect, dimension); |
383 | } |
384 | |
385 | //MOVED to PCMDeclarationsReader |
386 | // public UsageScenarioBasedObjective translateEvalAspectToObjective(EvaluationAspectWithContext aspect, UsageScenario usageScenario){ |
387 | // //Make sure, the aspect IS an objective |
388 | // try { |
389 | // if(aspect.getDimension().getType().getRelationSemantics().getRelSem() == EnumRelationSemantics.DECREASING) { |
390 | // return new UsageScenarioBasedObjective(this.getQualityAttribute(), Objective.Sign.MIN, usageScenario); |
391 | // } else { |
392 | // //INCREASING |
393 | // return new UsageScenarioBasedObjective(this.getQualityAttribute(), Objective.Sign.MAX, usageScenario); |
394 | // } |
395 | // } catch (CoreException e) { |
396 | // e.printStackTrace(); |
397 | // throw new RuntimeException("Could not get response time quality attribute!"); |
398 | // } |
399 | // } |
400 | |
401 | public QualityAttribute getQualityAttribute() throws CoreException { |
402 | //return DSEConstantsContainer.MEAN_RESPONSE_TIME_QUALITY; |
403 | return lQNQualityAttribute.getQualityAttribute(); |
404 | } |
405 | |
406 | public abstract boolean hasStatisticResults() throws CoreException; |
407 | |
408 | @Override |
409 | public List<Criterion> getCriterions() throws CoreException { |
410 | List<Criterion> list = new ArrayList<Criterion>(); |
411 | list.addAll(this.criteriaList); |
412 | return list; |
413 | } |
414 | |
415 | @Override |
416 | public void setBlackboard(MDSDBlackboard blackboard){ |
417 | this.blackboard = blackboard; |
418 | } |
419 | |
420 | } |