1 | package de.uka.ipd.sdq.pcmsolver.visitors; |
2 | |
3 | import java.util.List; |
4 | |
5 | import org.eclipse.emf.ecore.EObject; |
6 | |
7 | import de.uka.ipd.sdq.context.aggregatedUsageContext.AggregatedCommunication; |
8 | import de.uka.ipd.sdq.context.aggregatedUsageContext.AggregatedResourceDemand; |
9 | import de.uka.ipd.sdq.context.aggregatedUsageContext.AggregatedUsageContextFactory; |
10 | import de.uka.ipd.sdq.context.aggregatedUsageContext.ComputedAggregatedUsage; |
11 | import de.uka.ipd.sdq.context.aggregatedUsageContext.ServiceExecutionContext; |
12 | import de.uka.ipd.sdq.context.computed_usage.BranchProbability; |
13 | import de.uka.ipd.sdq.context.computed_usage.LoopIteration; |
14 | import de.uka.ipd.sdq.pcm.allocation.Allocation; |
15 | import de.uka.ipd.sdq.pcm.allocation.AllocationContext; |
16 | import de.uka.ipd.sdq.pcm.core.composition.AssemblyContext; |
17 | import de.uka.ipd.sdq.pcm.repository.CompositeComponent; |
18 | import de.uka.ipd.sdq.pcm.repository.RepositoryComponent; |
19 | import de.uka.ipd.sdq.pcm.resourceenvironment.CommunicationLinkResourceSpecification; |
20 | import de.uka.ipd.sdq.pcm.resourceenvironment.LinkingResource; |
21 | import de.uka.ipd.sdq.pcm.resourceenvironment.ResourceContainer; |
22 | import de.uka.ipd.sdq.pcm.resourcetype.ResourceType; |
23 | import de.uka.ipd.sdq.pcm.seff.AbstractAction; |
24 | import de.uka.ipd.sdq.pcm.seff.AbstractBranchTransition; |
25 | import de.uka.ipd.sdq.pcm.seff.AbstractLoopAction; |
26 | import de.uka.ipd.sdq.pcm.seff.ExternalCallAction; |
27 | import de.uka.ipd.sdq.pcm.seff.InternalAction; |
28 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingBehaviour; |
29 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingSEFF; |
30 | import de.uka.ipd.sdq.pcm.seff.ServiceEffectSpecification; |
31 | import de.uka.ipd.sdq.pcm.seff.seff_performance.ParametricResourceDemand; |
32 | import de.uka.ipd.sdq.pcm.usagemodel.BranchTransition; |
33 | import de.uka.ipd.sdq.pcm.usagemodel.UsageScenario; |
34 | import de.uka.ipd.sdq.pcmsolver.handler.AggregatedContextExternalCallActionHandler; |
35 | import de.uka.ipd.sdq.pcmsolver.handler.ExternalCallActionHandler; |
36 | import de.uka.ipd.sdq.pcmsolver.transformations.ContextWrapper; |
37 | import de.uka.ipd.sdq.stoex.Expression; |
38 | |
39 | /** |
40 | * Visitor that builds up the context model including the aggregated usage context. |
41 | * Extends the {@link SeffVisitor} and adds the calculation of execution frequencies. |
42 | * Uses the {@link AggregatedContextExternalCallActionHandler} instead of the {@link ExternalCallActionHandler}. |
43 | * @author martens |
44 | * |
45 | */ |
46 | public class AggregatedContextSEFFVisitor extends SeffVisitor { |
47 | |
48 | private double currentFrequency; |
49 | private ServiceExecutionContext computedAggregatedUsage; |
50 | private UsageScenario usageScenario; |
51 | |
52 | public AggregatedContextSEFFVisitor(ContextWrapper ctxWrp, double frequency, ServiceEffectSpecification seff, UsageScenario currentScenario) { |
53 | super(ctxWrp); |
54 | this.currentFrequency = frequency; |
55 | this.usageScenario = currentScenario; |
56 | |
57 | if (seff instanceof ResourceDemandingSEFF){ |
58 | ResourceDemandingSEFF rdSEFF = (ResourceDemandingSEFF)seff; |
59 | //AssemblyContext assemblyContext = ctxWrp.getAssCtx(); |
60 | AllocationContext allocationContext = ctxWrp.getAllCtx(); |
61 | ctxWrp.getAllCtx(); |
62 | //check if context is already there for this system. If yes, use it |
63 | this.computedAggregatedUsage = createOrReuseExecutionContext(rdSEFF, allocationContext, this.usageScenario, this.currentFrequency); |
64 | } |
65 | |
66 | |
67 | |
68 | } |
69 | |
70 | /** |
71 | * Extends {@link SeffVisitor#caseResourceDemandingSEFF(ResourceDemandingSEFF)}: stores the described SEFF |
72 | * in the {@link ComputedAggregatedUsage}. |
73 | * Then calls {@link SeffVisitor#caseResourceDemandingSEFF(ResourceDemandingSEFF)}. |
74 | * |
75 | * {@inheritDoc}. |
76 | */ |
77 | @Override |
78 | public Object caseResourceDemandingSEFF(ResourceDemandingSEFF seff) { |
79 | this.computedAggregatedUsage.setDescribedSEFF_ServiceExecutionContext(seff); |
80 | Object object = super.caseResourceDemandingSEFF(seff); |
81 | |
82 | return object; |
83 | } |
84 | |
85 | /** |
86 | * Overwrites the {@link SeffVisitor#caseExternalCallAction(ExternalCallAction)}. |
87 | * Does the same, but uses an {@link AggregatedContextExternalCallActionHandler} to handle the call, |
88 | * which in turn will instantiate an {@link AggregatedContextSEFFVisitor} for the next SEFF. |
89 | */ |
90 | @Override |
91 | public Object caseExternalCallAction(ExternalCallAction call) { |
92 | |
93 | |
94 | AggregatedContextExternalCallActionHandler extCallAH = new AggregatedContextExternalCallActionHandler(this, this.usageScenario); |
95 | extCallAH.handle(call); |
96 | |
97 | ServiceEffectSpecification seff = extCallAH.getCalledSEFF(); |
98 | if (seff instanceof ResourceDemandingSEFF){ |
99 | ResourceDemandingSEFF rdSEFF = (ResourceDemandingSEFF)seff; |
100 | |
101 | //AssemblyContext assemblyContext = extCallAH.getCalledAssemblyCtxt(); |
102 | AllocationContext allocationContext = extCallAH.getCalledAllocationContext(); |
103 | |
104 | //frequency will be set by the next seff visitor that visits that seff. |
105 | ServiceExecutionContext calleeComputedAggregatedUsage = createOrReuseExecutionContext(rdSEFF, allocationContext, this.usageScenario, 0.0); |
106 | |
107 | //the new usage is a communication partner, add communication info. |
108 | AggregatedCommunication communication = createOrReuseAggregatedCommunication(this.computedAggregatedUsage, calleeComputedAggregatedUsage); |
109 | |
110 | double oldFrequency = communication.getAverageMessageFrequency(); |
111 | communication.setAverageMessageFrequency(oldFrequency + this.currentFrequency); |
112 | |
113 | // get link on which the message is sent |
114 | CommunicationLinkResourceSpecification link = findCommunicationLink(this.computedAggregatedUsage, calleeComputedAggregatedUsage); |
115 | |
116 | //link is null if this is a local |
117 | if (link != null){ |
118 | communication.setUsedCommunicationLinkResourceSpecification_AggregatedCommunication(link); |
119 | } |
120 | |
121 | //TODO add message size |
122 | //XXX consider return call? there always is a return call so far. |
123 | } |
124 | |
125 | doSwitch(call.getSuccessor_AbstractAction()); |
126 | return call; |
127 | } |
128 | |
129 | /** |
130 | * Returns null if communication is local. |
131 | * @param callerComputedAggregatedUsage |
132 | * @param calleeComputedAggregatedUsage |
133 | * @return |
134 | */ |
135 | private CommunicationLinkResourceSpecification findCommunicationLink( |
136 | ServiceExecutionContext callerComputedAggregatedUsage, |
137 | ServiceExecutionContext calleeComputedAggregatedUsage) { |
138 | |
139 | //AssemblyContext assemblyFrom = callerComputedAggregatedUsage.getAssemblyContext_ServiceExecutionContext(); |
140 | //AssemblyContext assemblyTo = calleeComputedAggregatedUsage.getAssemblyContext_ServiceExecutionContext(); |
141 | AllocationContext to = calleeComputedAggregatedUsage.getAllocationContext_ServiceExecutionContext(); |
142 | |
143 | AllocationContext from = this.contextWrapper.getAllCtx(); |
144 | |
145 | Allocation allocation = this.contextWrapper.getPcmInstance().getAllocation(); |
146 | |
147 | /*AllocationContext to = null; |
148 | for (AllocationContext allocationContext : allocation.getAllocationContexts_Allocation()) { |
149 | |
150 | AssemblyContext currentAssemblyContext = allocationContext.getAssemblyContext_AllocationContext(); |
151 | // look inside assembled component to see whether the search assembly context assemblyTo in contained |
152 | if (isOrContainsAssemblyContext(currentAssemblyContext, assemblyTo)){ |
153 | to = allocationContext; |
154 | } |
155 | if (to != null) |
156 | break; |
157 | }*/ |
158 | |
159 | if (to != null){ |
160 | |
161 | ResourceContainer fromResourceContainer = from.getResourceContainer_AllocationContext(); |
162 | ResourceContainer toResourceContainer = to.getResourceContainer_AllocationContext(); |
163 | |
164 | //local communication? then return null. |
165 | if (fromResourceContainer == toResourceContainer) |
166 | return null; |
167 | |
168 | List<LinkingResource> linkingResourceList = this.contextWrapper.getPcmInstance().getResourceEnvironment().getLinkingResources__ResourceEnvironment(); |
169 | for (LinkingResource linkingResource : linkingResourceList) { |
170 | if (linkingResource.getConnectedResourceContainers_LinkingResource().contains(fromResourceContainer) |
171 | && linkingResource.getConnectedResourceContainers_LinkingResource().contains(toResourceContainer)){ |
172 | return linkingResource.getCommunicationLinkResourceSpecifications_LinkingResource(); |
173 | } |
174 | } |
175 | throw new RuntimeException("The communication between allocation contexts "+to.getEntityName()+" and "+from.getEntityName()+" is remote, but there is no linking resource between them. Add a linking resource."); |
176 | |
177 | } |
178 | throw new RuntimeException(this.getClass().getName()+": Could not determine allocation of "+calleeComputedAggregatedUsage.getDescribedSEFF_ServiceExecutionContext().getDescribedService__SEFF().getEntityName()+" to determine communication partners."); |
179 | |
180 | } |
181 | |
182 | private boolean isOrContainsAssemblyContext(AssemblyContext currenAssemblyContext, AssemblyContext targetAssembly) { |
183 | |
184 | if (currenAssemblyContext == targetAssembly) |
185 | return true; |
186 | |
187 | RepositoryComponent component = currenAssemblyContext.getEncapsulatedComponent__AssemblyContext(); |
188 | if (component instanceof CompositeComponent){ |
189 | CompositeComponent composite = (CompositeComponent)component; |
190 | for (AssemblyContext containedAssemblyContext : composite.getAssemblyContexts__ComposedStructure()) { |
191 | boolean contained = isOrContainsAssemblyContext(containedAssemblyContext, targetAssembly); |
192 | if (contained) |
193 | return true; |
194 | } |
195 | } |
196 | return false; |
197 | } |
198 | |
199 | /** |
200 | * Extends {@link SeffVisitor#caseInternalAction(InternalAction)}. Adds the calculation |
201 | * of a mean resource demand weighted by frequency of execution. Adds this information to the |
202 | * {@link AggregatedResourceDemand}. Then calls {@link SeffVisitor#caseInternalAction(InternalAction)}. |
203 | * |
204 | * {@inheritDoc} |
205 | */ |
206 | @Override |
207 | public Object caseInternalAction(InternalAction action) { |
208 | // add all types of resource demands. |
209 | for (ParametricResourceDemand demand : action.getResourceDemand_Action()) { |
210 | String specification = demand.getSpecification_ParametericResourceDemand().getSpecification(); |
211 | |
212 | Expression solvedExpr = ExpressionHelper.getSolvedExpression(specification, this.contextWrapper); |
213 | |
214 | ResourceType resourceType = demand.getRequiredResource_ParametricResourceDemand(); |
215 | |
216 | double meanDemand = ExpressionHelper.meanValue(solvedExpr); |
217 | |
218 | addToAggregatedUsage(resourceType, meanDemand); |
219 | |
220 | } |
221 | |
222 | //to get the successor right and also fill the computed allocation. |
223 | Object object = super.caseInternalAction(action); |
224 | //Object object = action.getSuccessor_AbstractAction(); |
225 | return object; |
226 | } |
227 | |
228 | |
229 | |
230 | /** |
231 | * Weight the demand by frequency and add it to the {@link AggregatedResourceDemand}. |
232 | * @param resourceType |
233 | * @param demand |
234 | */ |
235 | private void addToAggregatedUsage(ResourceType resourceType, double demand) { |
236 | |
237 | //weight by probability |
238 | double weightedDemand = demand * this.currentFrequency; |
239 | |
240 | AggregatedResourceDemand resourceDemandForType = null; |
241 | |
242 | List<AggregatedResourceDemand> existingResourceDemands = this.computedAggregatedUsage.getAggregatedResourceDemands_ServiceExecutionContext(); |
243 | for (AggregatedResourceDemand aggregatedResourceDemand : existingResourceDemands) { |
244 | if (aggregatedResourceDemand.getResourceType_AggregatedResourceDemand().equals(resourceType)){ |
245 | resourceDemandForType = aggregatedResourceDemand; |
246 | break; |
247 | } |
248 | } |
249 | |
250 | if (resourceDemandForType == null){ |
251 | resourceDemandForType = AggregatedUsageContextFactory.eINSTANCE.createAggregatedResourceDemand(); |
252 | resourceDemandForType.setResourceType_AggregatedResourceDemand(resourceType); |
253 | this.computedAggregatedUsage.getAggregatedResourceDemands_ServiceExecutionContext().add(resourceDemandForType); |
254 | } |
255 | |
256 | double newAggregatedValue = resourceDemandForType.getAggregatedResourceDemand()+weightedDemand; |
257 | resourceDemandForType.setAggregatedResourceDemand(newAggregatedValue); |
258 | |
259 | } |
260 | |
261 | /** |
262 | * Gets the frequency to execute this {@link ResourceDemandingBehaviour} by checking the container. |
263 | * If it is a {@link BranchTransition} or {@link AbstractLoopAction}, update the frequency before calling |
264 | * {@link SeffVisitor#caseExternalCallAction(ExternalCallAction)}. Then resets the frequency for the next action or trasition. |
265 | * Then calls {@link SeffVisitor#caseResourceDemandingBehaviour(ResourceDemandingBehaviour)}. |
266 | * |
267 | * {@inheritDoc}. |
268 | */ |
269 | @Override |
270 | public Object caseResourceDemandingBehaviour( |
271 | ResourceDemandingBehaviour behaviour) { |
272 | |
273 | |
274 | // to avoid rounding errors, reset probability after the call. |
275 | double oldProbability = this.currentFrequency; |
276 | |
277 | |
278 | //determine container type |
279 | EObject container = behaviour.eContainer(); |
280 | |
281 | if (container instanceof AbstractBranchTransition){ |
282 | AbstractBranchTransition branchTransition = (AbstractBranchTransition)container; |
283 | |
284 | double branchProb = -1; |
285 | List<BranchProbability> branchProbabilities = this.contextWrapper.getCompUsgCtx().getBranchProbabilities_ComputedUsageContext(); |
286 | for (BranchProbability branchProbability : branchProbabilities) { |
287 | if (branchTransition.equals(branchProbability.getBranchtransition_BranchProbability())){ |
288 | branchProb = branchProbability.getProbability(); |
289 | break; |
290 | } |
291 | } |
292 | if (branchProb == -1){ |
293 | throw new RuntimeException("Internal error: Found no branch transition probability for branch "+branchTransition.getEntityName()+" "+branchTransition.getId()); |
294 | } |
295 | this.currentFrequency = this.currentFrequency * branchProb; |
296 | |
297 | } else if (container instanceof AbstractLoopAction){ |
298 | AbstractLoopAction loop = (AbstractLoopAction)container; |
299 | double avgLoopIterationNumber = -1; |
300 | List<LoopIteration> loopIterations = this.contextWrapper.getCompUsgCtx().getLoopiterations_ComputedUsageContext(); |
301 | for (LoopIteration loopIteration : loopIterations) { |
302 | if (loop.equals(loopIteration.getLoopaction_LoopIteration())){ |
303 | avgLoopIterationNumber = ExpressionHelper.meanValue(ExpressionHelper.getSolvedExpression(loopIteration.getSpecification_LoopIteration().getSpecification(), this.contextWrapper)); |
304 | } |
305 | } |
306 | if (avgLoopIterationNumber == -1){ |
307 | throw new RuntimeException("Internal error: Found no branch transition probability for loop "+loop.getEntityName()+" "+loop.getId()); |
308 | } |
309 | this.currentFrequency = this.currentFrequency * avgLoopIterationNumber; |
310 | } |
311 | |
312 | Object result = super.caseResourceDemandingBehaviour(behaviour); |
313 | |
314 | this.currentFrequency = oldProbability; |
315 | |
316 | return result; |
317 | |
318 | } |
319 | |
320 | /** |
321 | * Get the current frequency of this object. This is <i>not</i> equal to the frequency |
322 | * of this {@link ServiceEffectSpecification}, because the current frequency |
323 | * reflects the frequency of the currently handled {@link AbstractAction}. |
324 | */ |
325 | public double getCurrentFrequency() { |
326 | return this.currentFrequency; |
327 | } |
328 | |
329 | private ServiceExecutionContext createOrReuseExecutionContext(ResourceDemandingSEFF rdSEFF, AllocationContext allocationContext, UsageScenario usageScenario, double frequency){ |
330 | |
331 | ServiceExecutionContext computedAggregatedUsage = null; |
332 | |
333 | List<ServiceExecutionContext> aggrUsageContext = this.contextWrapper.getPcmInstance().getComputedAggregatedUsage().getServiceExecutionContexts_ComputedAggregatedUsage(); |
334 | for (ServiceExecutionContext serviceExecutionContext : aggrUsageContext) { |
335 | if (serviceExecutionContext.getDescribedSEFF_ServiceExecutionContext() == rdSEFF |
336 | && serviceExecutionContext.getAllocationContext_ServiceExecutionContext() == allocationContext |
337 | && serviceExecutionContext.getUsageScenario_ServiceExecutionContext() == usageScenario){ |
338 | computedAggregatedUsage = serviceExecutionContext; |
339 | double oldFrequency = computedAggregatedUsage.getGlobalExecutionFrequency(); |
340 | computedAggregatedUsage.setGlobalExecutionFrequency(frequency+oldFrequency); |
341 | break; |
342 | } |
343 | } |
344 | |
345 | //If no context is yet there for this seff in this assembly context, create a new one. |
346 | if (computedAggregatedUsage == null){ |
347 | |
348 | computedAggregatedUsage = AggregatedUsageContextFactory.eINSTANCE.createServiceExecutionContext(); |
349 | computedAggregatedUsage.setGlobalExecutionFrequency(currentFrequency); |
350 | |
351 | computedAggregatedUsage.setAllocationContext_ServiceExecutionContext(allocationContext); |
352 | computedAggregatedUsage.setUsageScenario_ServiceExecutionContext(this.usageScenario); |
353 | computedAggregatedUsage.setDescribedSEFF_ServiceExecutionContext(rdSEFF); |
354 | |
355 | this.contextWrapper.getPcmInstance().getComputedAggregatedUsage().getServiceExecutionContexts_ComputedAggregatedUsage().add(computedAggregatedUsage); |
356 | } |
357 | |
358 | return computedAggregatedUsage; |
359 | } |
360 | |
361 | private AggregatedCommunication createOrReuseAggregatedCommunication(ServiceExecutionContext fromService, ServiceExecutionContext toService){ |
362 | |
363 | AggregatedCommunication communication = null; |
364 | |
365 | List<AggregatedCommunication> communications = fromService.getSentAggregatedCommunications_ServiceExecutionContext(); |
366 | for (AggregatedCommunication aggregatedCommunication : communications) { |
367 | if (aggregatedCommunication.getReceiver_AggregatedCommunication() == toService){ |
368 | communication = aggregatedCommunication; |
369 | break; |
370 | } |
371 | } |
372 | |
373 | if (communication == null){ |
374 | communication = AggregatedUsageContextFactory.eINSTANCE.createAggregatedCommunication(); |
375 | communication.setReceiver_AggregatedCommunication(toService); |
376 | communications.add(communication); |
377 | } |
378 | |
379 | return communication; |
380 | |
381 | } |
382 | |
383 | |
384 | |
385 | |
386 | } |