1 | package de.uka.ipd.sdq.pcmsolver.transformations.pcm2lqn; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.HashMap; |
5 | import java.util.List; |
6 | import java.util.Map; |
7 | |
8 | import org.apache.log4j.Logger; |
9 | import org.eclipse.emf.common.util.EList; |
10 | |
11 | import LqnCore.ActivityDefType; |
12 | import LqnCore.ActivityMakingCallType; |
13 | import LqnCore.ActivityPhasesType; |
14 | import LqnCore.CallOrderType; |
15 | import LqnCore.EntryType; |
16 | import LqnCore.PhaseActivities; |
17 | import LqnCore.PrecedenceType; |
18 | import LqnCore.ProcessorType; |
19 | import LqnCore.TaskType; |
20 | import LqnCore.TypeType; |
21 | import de.uka.ipd.sdq.pcm.allocation.AllocationContext; |
22 | import de.uka.ipd.sdq.pcm.resourceenvironment.CommunicationLinkResourceSpecification; |
23 | import de.uka.ipd.sdq.pcm.resourceenvironment.ProcessingResourceSpecification; |
24 | import de.uka.ipd.sdq.pcm.resourceenvironment.ResourceContainer; |
25 | import de.uka.ipd.sdq.pcm.resourcetype.ProcessingResourceType; |
26 | import de.uka.ipd.sdq.pcm.seff.AbstractAction; |
27 | import de.uka.ipd.sdq.pcm.seff.AbstractBranchTransition; |
28 | import de.uka.ipd.sdq.pcm.seff.AbstractLoopAction; |
29 | import de.uka.ipd.sdq.pcm.seff.AcquireAction; |
30 | import de.uka.ipd.sdq.pcm.seff.BranchAction; |
31 | import de.uka.ipd.sdq.pcm.seff.CollectionIteratorAction; |
32 | import de.uka.ipd.sdq.pcm.seff.ExternalCallAction; |
33 | import de.uka.ipd.sdq.pcm.seff.ForkAction; |
34 | import de.uka.ipd.sdq.pcm.seff.ForkedBehaviour; |
35 | import de.uka.ipd.sdq.pcm.seff.InternalAction; |
36 | import de.uka.ipd.sdq.pcm.seff.LoopAction; |
37 | import de.uka.ipd.sdq.pcm.seff.ReleaseAction; |
38 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingBehaviour; |
39 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingSEFF; |
40 | import de.uka.ipd.sdq.pcm.seff.SetVariableAction; |
41 | import de.uka.ipd.sdq.pcm.seff.StartAction; |
42 | import de.uka.ipd.sdq.pcm.seff.StopAction; |
43 | import de.uka.ipd.sdq.pcm.seff.SynchronisationPoint; |
44 | import de.uka.ipd.sdq.pcm.seff.seff_performance.ParametricResourceDemand; |
45 | import de.uka.ipd.sdq.pcm.seff.util.SeffSwitch; |
46 | import de.uka.ipd.sdq.pcmsolver.transformations.ContextWrapper; |
47 | import de.uka.ipd.sdq.pcmsolver.transformations.EMFHelper; |
48 | import de.uka.ipd.sdq.pcmsolver.visitors.EMFQueryHelper; |
49 | import de.uka.ipd.sdq.pcmsolver.visitors.ExpressionHelper; |
50 | import de.uka.ipd.sdq.probfunction.math.IContinousPDF; |
51 | import de.uka.ipd.sdq.probfunction.math.IProbabilityDensityFunction; |
52 | import de.uka.ipd.sdq.probfunction.math.ManagedPDF; |
53 | import de.uka.ipd.sdq.probfunction.math.ManagedPMF; |
54 | import de.uka.ipd.sdq.probfunction.math.exception.DomainNotNumbersException; |
55 | import de.uka.ipd.sdq.probfunction.math.exception.FunctionNotInTimeDomainException; |
56 | |
57 | /** |
58 | * Visits one SEFF. An {@link Rdseff2Lqn} instance creates a new |
59 | * {@link Rdseff2Lqn} instance when visiting an external call, this new one |
60 | * is responsible for the other SEFF. |
61 | * |
62 | * Thus, only information local to this SEFF could be stored as member variables here. |
63 | * |
64 | * Each visitor method (case*) returns the id of the first generated LQN model element, |
65 | * so that it can be used by the handler of the previous model element |
66 | * to connect itself to this successor. |
67 | * |
68 | * @author koziolek, martens |
69 | * |
70 | */ |
71 | public class Rdseff2Lqn extends SeffSwitch<String> { |
72 | |
73 | private static Logger logger = Logger.getLogger(Rdseff2Lqn.class.getName()); |
74 | |
75 | private ContextWrapper myContextWrapper; |
76 | private LqnBuilder lqnBuilder; |
77 | |
78 | public Rdseff2Lqn(LqnBuilder aLqnBuilder, ContextWrapper aContextWrapper) { |
79 | lqnBuilder = aLqnBuilder; |
80 | myContextWrapper = aContextWrapper; |
81 | } |
82 | |
83 | /** |
84 | * Does nothing yet, is ignored and the visitor continues with the successor. |
85 | * Can be implemented with a Semaphore task in LQN. |
86 | * |
87 | * Excerpt from LQN 4.3 documentation: |
88 | * |
89 | * Semaphore Task: Semaphore tasks are used to model passive resources such as buffers. They always have two entries |
90 | * which are used to signal and wait the semaphore. The wait entry must be called using a synchronous request |
91 | * whereas the signal entry can be called using any type of request. Once a request is accepted by the wait entry, |
92 | * no further requests will be accepted until a request is processed by the signal entry. The signal and wait entries |
93 | * do not have to called from a common task. However, the two entries must share a common call graph, and the |
94 | * call graph must be deterministic. The entries themselves can be defined using phases or activies and can make |
95 | * requests to other tasks. Counting semaphores can be modeled using a multiserver. |
96 | * |
97 | */ |
98 | @Override |
99 | public String caseAcquireAction(AcquireAction object) { |
100 | |
101 | String successorId; |
102 | if (lqnBuilder.isLQSimAnalysis()) { |
103 | String id = Pcm2LqnHelper.getId(object, myContextWrapper); |
104 | String passiveResourceId = Pcm2LqnHelper.getIdForPassiveResource(object.getPassiveresource_AcquireAction(), myContextWrapper.getAllCtx()); |
105 | |
106 | ProcessorType pt = lqnBuilder.addProcessor(passiveResourceId); |
107 | |
108 | lqnBuilder.addSemaphoreTask(passiveResourceId, pt, Integer.valueOf(object |
109 | .getPassiveresource_AcquireAction() |
110 | .getCapacity_PassiveResource().getSpecification())); |
111 | |
112 | ActivityDefType adt = lqnBuilder.addActivityDef(id); |
113 | adt.setCallOrder(CallOrderType.DETERMINISTIC); |
114 | |
115 | lqnBuilder.addActivityMakingCall(id, Pcm2LqnHelper.getWaitEntryId(passiveResourceId), CallType.SYNCH); |
116 | successorId = (String) doSwitch(object |
117 | .getSuccessor_AbstractAction()); |
118 | lqnBuilder.addSequencePrecedence(id, successorId); |
119 | return id; |
120 | } else { |
121 | if (object.getPassiveresource_AcquireAction().getEntityName().toLowerCase().contains("pool")){ |
122 | logger.warn("Passive resource pool found. Support by PCM2LQN is limited. Please analyze the results carefully."); |
123 | Integer poolCapacity = Integer.valueOf(object.getPassiveresource_AcquireAction().getCapacity_PassiveResource().getSpecification()); |
124 | lqnBuilder.setPoolCapacity(poolCapacity); |
125 | } else { |
126 | logger.warn("Ignored release action because it is not supported by LQNS. Be aware that the passive resource is not analysed."); |
127 | } |
128 | successorId = (String) doSwitch(object |
129 | .getSuccessor_AbstractAction()); |
130 | return successorId; |
131 | } |
132 | |
133 | |
134 | } |
135 | |
136 | /** |
137 | * Does nothing yet, is ignored and the visitor continues with the successor. |
138 | */ |
139 | @Override |
140 | public String caseReleaseAction(ReleaseAction object) { |
141 | |
142 | String successorId; |
143 | if (lqnBuilder.isLQSimAnalysis()) { |
144 | String id = Pcm2LqnHelper.getId(object, myContextWrapper); |
145 | |
146 | ActivityDefType adt = lqnBuilder.addActivityDef(id); |
147 | adt.setCallOrder(CallOrderType.DETERMINISTIC); |
148 | |
149 | String passiveResourceId = Pcm2LqnHelper.getIdForPassiveResource(object.getPassiveResource_ReleaseAction(), myContextWrapper.getAllCtx()); |
150 | |
151 | lqnBuilder.addActivityMakingCall(id, Pcm2LqnHelper.getSignalEntryId(passiveResourceId), CallType.SYNCH); |
152 | successorId = (String) doSwitch(object.getSuccessor_AbstractAction()); |
153 | lqnBuilder.addSequencePrecedence(id, successorId); |
154 | return id; |
155 | |
156 | } else { |
157 | logger.warn("Ignored release action because it is not supported by LQNS. Be aware that the passive resource is not analysed."); |
158 | successorId = (String) doSwitch(object |
159 | .getSuccessor_AbstractAction()); |
160 | return successorId; |
161 | } |
162 | |
163 | } |
164 | |
165 | @Override |
166 | public String caseResourceDemandingSEFF(ResourceDemandingSEFF object) { |
167 | String id = Pcm2LqnHelper.getId(object, myContextWrapper); |
168 | |
169 | ProcessorType pt = lqnBuilder.addProcessor(id); |
170 | |
171 | TaskType tt = lqnBuilder.addTask(id, pt); |
172 | //tt.setMultiplicity(new BigInteger("1")); |
173 | //tt.setScheduling(TaskSchedulingType.INF); |
174 | |
175 | EntryType et = lqnBuilder.addEntry(id, tt); |
176 | lqnBuilder.addTaskActivityGraph(tt); |
177 | |
178 | ResourceDemandingBehaviour rdb = (ResourceDemandingBehaviour)object; |
179 | String startId = (String)doSwitch(getStartAction(rdb)); |
180 | String stopId = Pcm2LqnHelper.getId(getStopAction(rdb), myContextWrapper); |
181 | lqnBuilder.addReplyActivity(id, startId, stopId); |
182 | |
183 | lqnBuilder.restoreFormerTaskActivityGraph(); |
184 | |
185 | return et.getName(); |
186 | } |
187 | |
188 | @Override |
189 | public String caseLoopAction(LoopAction object) { |
190 | String id = Pcm2LqnHelper.getId(object, myContextWrapper); |
191 | handleLoop(object, id); |
192 | return id; |
193 | |
194 | } |
195 | |
196 | private void handleLoop(AbstractLoopAction object, String id) { |
197 | String startId = handleLoopBody(object,id); |
198 | lqnBuilder.addActivityDef(id); // for the loop action |
199 | // makes an external call to the task representing the loop body: |
200 | ActivityMakingCallType amct = lqnBuilder.addActivityMakingCall(id, |
201 | startId, CallType.SYNCH); |
202 | amct.setCallsMean(getLoopIterations(object)); |
203 | |
204 | String successorId = (String)doSwitch(object.getSuccessor_AbstractAction()); |
205 | lqnBuilder.addSequencePrecedence(id, successorId); |
206 | } |
207 | |
208 | private String handleLoopBody(AbstractLoopAction loop,String id) { |
209 | ProcessorType pt = lqnBuilder.addProcessor(id); |
210 | TaskType tt = lqnBuilder.addTask(id,pt); |
211 | EntryType et = lqnBuilder.addEntry(id,tt); |
212 | lqnBuilder.addTaskActivityGraph(tt); |
213 | |
214 | ResourceDemandingBehaviour rdb = loop.getBodyBehaviour_Loop(); |
215 | String startId = (String) doSwitch(getStartAction(rdb)); |
216 | String stopId = Pcm2LqnHelper.getId(getStopAction(rdb), myContextWrapper); |
217 | lqnBuilder.addReplyActivity(id, startId, stopId); |
218 | |
219 | lqnBuilder.restoreFormerTaskActivityGraph(); |
220 | |
221 | return startId; |
222 | } |
223 | |
224 | private String getLoopIterations(AbstractLoopAction loop) { |
225 | ManagedPMF pmf = myContextWrapper.getLoopIterations(loop); |
226 | if (pmf != null) { |
227 | try { |
228 | return pmf.getPmfTimeDomain().getArithmeticMeanValue() + ""; |
229 | } catch (DomainNotNumbersException e) { |
230 | return "0.0"; |
231 | } catch (FunctionNotInTimeDomainException e) { |
232 | return "0.0"; |
233 | } |
234 | } else { |
235 | return "0.0"; |
236 | } |
237 | } |
238 | |
239 | @Override |
240 | public String caseCollectionIteratorAction(CollectionIteratorAction object) { |
241 | String id = Pcm2LqnHelper.getId(object, myContextWrapper); |
242 | handleLoop(object, id); |
243 | return id; |
244 | } |
245 | |
246 | @Override |
247 | public String caseResourceDemandingBehaviour(ResourceDemandingBehaviour object) { |
248 | return doSwitch(getStartAction(object)); |
249 | } |
250 | |
251 | @Override |
252 | public String caseStartAction(StartAction object) { |
253 | String id = Pcm2LqnHelper.getId(object, myContextWrapper); |
254 | String entryId = ""; |
255 | |
256 | if (object.eContainer() instanceof ResourceDemandingSEFF){ |
257 | ResourceDemandingSEFF rdseff = (ResourceDemandingSEFF)object.eContainer(); |
258 | ActivityDefType adt = lqnBuilder.addActivityDef(id); |
259 | entryId = Pcm2LqnHelper.getId(rdseff, myContextWrapper)+"_Entry"; |
260 | adt.setBoundToEntry(entryId); |
261 | } else if (object.eContainer().eContainer() instanceof LoopAction){ |
262 | LoopAction la = (LoopAction)object.eContainer().eContainer(); |
263 | ActivityDefType adt = lqnBuilder.addActivityDef(id); |
264 | entryId = Pcm2LqnHelper.getId(la, myContextWrapper)+"_Entry"; |
265 | adt.setBoundToEntry(entryId); |
266 | } else if (object.eContainer().eContainer() instanceof CollectionIteratorAction){ |
267 | CollectionIteratorAction cia = (CollectionIteratorAction)object.eContainer().eContainer(); |
268 | ActivityDefType adt = lqnBuilder.addActivityDef(id); |
269 | entryId = Pcm2LqnHelper.getId(cia, myContextWrapper)+"_Entry"; |
270 | adt.setBoundToEntry(entryId); |
271 | } else if (object.eContainer().eContainer() instanceof SynchronisationPoint){ |
272 | lqnBuilder.addActivityDef(id); |
273 | } else if (object.eContainer() instanceof ForkedBehaviour){ |
274 | ForkedBehaviour fb = (ForkedBehaviour)object.eContainer(); |
275 | ActivityDefType adt = lqnBuilder.addActivityDef(id); |
276 | entryId = Pcm2LqnHelper.getIdForForkedBehaviour(fb, myContextWrapper)+"_Entry"; |
277 | adt.setBoundToEntry(entryId); |
278 | } else { //nested resource demanding behaviour |
279 | lqnBuilder.addActivityDef(id); |
280 | } |
281 | |
282 | String successorId = (String) doSwitch(object.getSuccessor_AbstractAction()); |
283 | lqnBuilder.addSequencePrecedence(id, successorId); |
284 | |
285 | if (entryId.equals("")) return id; |
286 | else return entryId; |
287 | } |
288 | |
289 | |
290 | @Override |
291 | public String caseBranchAction(BranchAction object) { |
292 | String id = Pcm2LqnHelper.getId(object, myContextWrapper); |
293 | |
294 | lqnBuilder.addActivityDef(id); |
295 | PrecedenceType ptBegin = lqnBuilder.addBeginBranchPrecedence(id); |
296 | PrecedenceType ptEnd = lqnBuilder.addEndBranchPrecedence(); |
297 | |
298 | EList<AbstractBranchTransition> btList = object.getBranches_Branch(); |
299 | for (AbstractBranchTransition bt : btList) { |
300 | ResourceDemandingBehaviour rdb = bt.getBranchBehaviour_BranchTransition(); |
301 | |
302 | // the lqn solver complains if a branch has zero probability |
303 | // if(contextWrapper.getBranchProbability(bt)!=0.0){ |
304 | Double branchProbNumeric = myContextWrapper.getBranchProbability(bt); |
305 | if (branchProbNumeric > 0){ |
306 | String startId = (String) doSwitch(rdb); |
307 | |
308 | String branchProb = branchProbNumeric.toString(); |
309 | |
310 | lqnBuilder.addActivityOrType(startId,branchProb, ptBegin); |
311 | |
312 | String stopId = Pcm2LqnHelper.getId(getStopAction(rdb), myContextWrapper); |
313 | lqnBuilder.addActivityType(stopId, ptEnd); |
314 | } |
315 | } |
316 | |
317 | String successorId = (String) doSwitch(object.getSuccessor_AbstractAction()); |
318 | ptEnd.getPost().getActivity().setName(successorId); |
319 | |
320 | //If a precedence with exactly the same activities is already there, |
321 | //this one needs to be deleted. |
322 | //This can happen if this SEFF is called from multiple contexts. |
323 | //TODO: should we not be able to distinguish multiple contexts? |
324 | // -> I have put the deletion of duplicate precedences in the LQNBuilder. |
325 | |
326 | |
327 | return id; |
328 | } |
329 | |
330 | @Override |
331 | public String caseSetVariableAction(SetVariableAction object) { |
332 | Pcm2LqnHelper.getId(object, myContextWrapper); |
333 | return doSwitch(object.getSuccessor_AbstractAction()); |
334 | } |
335 | |
336 | @Override |
337 | public String caseExternalCallAction(ExternalCallAction object) { |
338 | return handleExternalCallAction(object, CallType.SYNCH, object.getSuccessor_AbstractAction()); |
339 | } |
340 | |
341 | /** |
342 | * Handle an {@link ExternalCallAction} |
343 | * @param object The {@link ExternalCallAction} |
344 | * @param callType |
345 | * @param successor The successor action is determined by the caller, so that it does not necessarily have to be |
346 | * object.getSuccessor_AbstractAction(). For example, when simplifying a fork with internal ExternalCalls |
347 | * to asynchronous LQN calls, the proper successor is the successor of the ForkAction, not of the |
348 | * ExternalCall (which is a StopAction that is pruned in that case) |
349 | * @return The id of the first generated LQN model element, to be connected with the successor. |
350 | */ |
351 | private String handleExternalCallAction(ExternalCallAction object, CallType callType, AbstractAction successor){ |
352 | String callId = Pcm2LqnHelper.getId(object, myContextWrapper); |
353 | |
354 | AllocationContext callerAllocationContext = myContextWrapper.getAllCtx(); |
355 | |
356 | ResourceDemandingSEFF seff = (ResourceDemandingSEFF)myContextWrapper.getNextSEFF(object); |
357 | if (seff == null){ |
358 | // this is a system external call |
359 | // we continue with the internal action added after this action |
360 | //logger.warn("Call "+object.getId()+" does not call a seff, ignoring it. Note that time required for system external calls are not supported by PCM2LQN yet."); |
361 | return doSwitch(object.getSuccessor_AbstractAction()); |
362 | } else { |
363 | ContextWrapper oldContextWrapper = (ContextWrapper)myContextWrapper.clone(); |
364 | |
365 | |
366 | List<ContextWrapper> contextWrapperList = myContextWrapper.getContextWrapperFor(object); |
367 | List<AllocationContext> calledAllocationContextList = new ArrayList<AllocationContext>(contextWrapperList.size()); |
368 | |
369 | // if one of the contextWrappers refers to the same allocation context than the current one, then |
370 | // then direct all calls to only this one |
371 | // assume there is at most component instance per resource container (more should be prohibited by the metamodel) |
372 | boolean localComponentInstanceAvailable = false; |
373 | ContextWrapper localContextWrapper = null; |
374 | for (ContextWrapper contextWrapper : contextWrapperList) { |
375 | if (contextWrapper.getAllCtx().getId().equals(oldContextWrapper.getAllCtx().getId())){ |
376 | localComponentInstanceAvailable = true; |
377 | localContextWrapper = contextWrapper; |
378 | break; |
379 | } |
380 | } |
381 | |
382 | if (localComponentInstanceAvailable || contextWrapperList.size() == 1){ |
383 | // only one component instance is called (either there is only one, or there is a local one). |
384 | if (localContextWrapper != null){ |
385 | myContextWrapper = localContextWrapper; |
386 | } else { |
387 | myContextWrapper = contextWrapperList.get(0); |
388 | } |
389 | AllocationContext toAllocationContext = myContextWrapper.getAllCtx(); |
390 | calledAllocationContextList.add(toAllocationContext); |
391 | |
392 | // create LQN call |
393 | createCallActivity(callId, seff, callType); |
394 | |
395 | } else { |
396 | // need to create a branch because several remote component instances are called |
397 | // thus, iterate over all context wrappers and call the following SEFF for them. |
398 | |
399 | double branchProb = 1.0/contextWrapperList.size(); |
400 | |
401 | for (ContextWrapper contextWrapper : contextWrapperList) { |
402 | myContextWrapper = contextWrapper; |
403 | |
404 | AllocationContext toAllocationContext = myContextWrapper.getAllCtx(); |
405 | calledAllocationContextList.add(toAllocationContext); |
406 | |
407 | // create LQN call |
408 | createCallActivity(callId, seff, callType, branchProb); |
409 | |
410 | // the ends of the branches are connected below after it has been decided whether to include network calls. |
411 | } |
412 | |
413 | } |
414 | |
415 | myContextWrapper = oldContextWrapper; |
416 | |
417 | String successorId = (String) doSwitch(successor); |
418 | |
419 | // Handle network calls. |
420 | // Just create a network call before the call created above that calls any network, |
421 | // and another one for the response afterwards. |
422 | // this is inaccurate, because the network of replica 1 may be called before replica 2 is called now, |
423 | // the proper dependency is lost. |
424 | // For the LQNS MVA analysis, it does not matter, though, because the mean values will stay the same |
425 | |
426 | for (AllocationContext targetAllocationContext : calledAllocationContextList) { |
427 | |
428 | // Add linking resource demand if this is a remote call. |
429 | // careful: The linking resource processor is only generated if the latency is != 0. |
430 | if (callerAllocationContext.getResourceContainer_AllocationContext() != targetAllocationContext.getResourceContainer_AllocationContext()){ |
431 | // call latency entry of linking resource before and after call. |
432 | |
433 | // get resource that connects the two |
434 | CommunicationLinkResourceSpecification link = oldContextWrapper.getConcreteLinkingResource(object, targetAllocationContext); |
435 | |
436 | // only create a call if latency is larger than 0 |
437 | if (link != null && ExpressionHelper.getMeanValue(link.getLatency_CommunicationLinkResourceSpecification()) > 0){ |
438 | |
439 | String linkId = Pcm2LqnHelper.getIdForCommResource(link.getLinkingResource_CommunicationLinkResourceSpecification(), link.getCommunicationLinkResourceType_CommunicationLinkResourceSpecification()); |
440 | String latencyId = Pcm2LqnHelper.getIdForLatency(linkId, callType); |
441 | |
442 | String networkCallId = "LAN_"+callId+"_"+callType; |
443 | String networkResponseId = "LAN_"+callId+"_return"; |
444 | |
445 | lqnBuilder.addActivityDef(networkCallId); |
446 | lqnBuilder.addActivityMakingCall(networkCallId, latencyId+"_Entry", callType); |
447 | |
448 | // only response if it is a synch call |
449 | if (callType == CallType.SYNCH){ |
450 | lqnBuilder.addActivityDef(networkResponseId); |
451 | lqnBuilder.addActivityMakingCall(networkResponseId, latencyId+"_Entry", callType); |
452 | } |
453 | |
454 | // TODO: call throughput entry if bytesize characterization is available |
455 | // there is same very initial implementation at |
456 | // contextWrapper.getDelayOnLinkingResource(eca, clrs); |
457 | // pay attention to use the right context wraper (old or new?) |
458 | |
459 | // first LAN call(s), then external call(s), then LAN call(s), then successor |
460 | // no response for asynchronous call |
461 | lqnBuilder.addSequencePrecedence(networkCallId, callId); |
462 | if (callType == CallType.SYNCH){ |
463 | lqnBuilder.addSequencePrecedence(callId, networkResponseId); |
464 | lqnBuilder.addSequencePrecedence(networkResponseId, successorId); |
465 | } else { |
466 | lqnBuilder.addSequencePrecedence(callId, successorId); |
467 | } |
468 | |
469 | return networkCallId; |
470 | |
471 | |
472 | } else { |
473 | if (link == null){ |
474 | logger.warn("No link found between "+callerAllocationContext.getEntityName()+" <"+callerAllocationContext.getId()+"> and "+targetAllocationContext.getEntityName()+" <"+targetAllocationContext.getId()+"> , ignoring this."); |
475 | } |
476 | } |
477 | // else go to return statement below and return the id of the external call itself. |
478 | } |
479 | } |
480 | |
481 | //only come here if no linking resource calls have been created, e.g. because there is no latency defined. |
482 | lqnBuilder.addSequencePrecedence(callId, successorId); |
483 | |
484 | |
485 | |
486 | // all possible communication paths are thus the following |
487 | // replication and LAN: branch, LAN, external, LAN, branch, successor |
488 | // no replication and LAN: LAN, external, LAN, successor |
489 | // no replication and local: external, successor |
490 | // |
491 | // The last combination, namely |
492 | // replication and no LAN: branch, external, branch, successor |
493 | // is usually not used because two replicas cannot be on the same node, so branch is always combined with remote. |
494 | // However, if a remote call has no latency specified, then this will be generated, ignoring the link. |
495 | // |
496 | |
497 | return callId; // for predecessor |
498 | } |
499 | } |
500 | |
501 | private void createCallActivity(String callerId, ResourceDemandingSEFF sefftoBeCalled, CallType callType) { |
502 | createCallActivity(callerId, sefftoBeCalled, callType, 1.0); |
503 | } |
504 | |
505 | private void createCallActivity(String callerId, ResourceDemandingSEFF sefftoBeCalled, CallType callType, double callMeans) { |
506 | String entryId = ""; |
507 | try { |
508 | Rdseff2Lqn seffVisitor = new Rdseff2Lqn(lqnBuilder, myContextWrapper); |
509 | entryId = (String)seffVisitor.doSwitch(sefftoBeCalled); |
510 | } catch (RuntimeException e) { |
511 | logger.error("Error while visiting RDSEFF "+sefftoBeCalled.getId()); |
512 | e.printStackTrace(); |
513 | throw e; |
514 | } |
515 | |
516 | lqnBuilder.addActivityDef(callerId); |
517 | lqnBuilder.addActivityMakingCall(callerId, entryId, callType, callMeans); |
518 | } |
519 | |
520 | @Override |
521 | public String caseInternalAction(InternalAction object) { |
522 | String id = Pcm2LqnHelper.getId(object, myContextWrapper); |
523 | |
524 | EList<ParametricResourceDemand> resDemList = object.getResourceDemand_Action(); |
525 | int counter = 0; // for the number of resource demands (mapped to entry name) |
526 | for (ParametricResourceDemand resourceDemand : resDemList){ |
527 | String processorId = getProcessorName(resourceDemand); |
528 | |
529 | // // create a new task for the resource demand |
530 | // ProcessorType pt = lqnBuilder.getProcessor(processorId); |
531 | // TaskType tt = lqnBuilder.addTaskForResourceDemand(id+counter, pt); |
532 | // EntryType et = lqnBuilder.addEntry(id+counter, tt); |
533 | // et.setType(TypeType.PH1PH2); |
534 | |
535 | // first a new entry for the resource demand |
536 | TaskType tt = lqnBuilder.getTaskForProcessor(processorId); |
537 | EntryType et = lqnBuilder.addEntry(id+counter, tt); |
538 | et.setType(TypeType.PH1PH2); |
539 | |
540 | // the entry makes a call to the processor |
541 | ActivityPhasesType apt = lqnBuilder.addActivityPhases(id+counter); |
542 | Double demand = myContextWrapper.getMeanTimeConsumption(resourceDemand); |
543 | String hostDemand = demand.toString(); |
544 | apt.setHostDemandMean(hostDemand); |
545 | |
546 | //if continuous function, get coefficient of variance |
547 | //TODO: also get this for stepwise defined functions! |
548 | //Check whether this has been a distribution originally |
549 | if (myContextWrapper.getIsOriginalPDFFor(resourceDemand)){ |
550 | ManagedPDF pdf = myContextWrapper.getTimeConsumptionAsPDF(resourceDemand); |
551 | IProbabilityDensityFunction innerPDF = pdf.getPdfTimeDomain(); |
552 | if (innerPDF instanceof IContinousPDF){ |
553 | IContinousPDF innerContPDF = (IContinousPDF)innerPDF; |
554 | double coeffv = innerContPDF.getCoefficientOfVariance(); |
555 | Double squaredcv = coeffv * coeffv; |
556 | apt.setHostDemandCvsq(squaredcv.toString()); |
557 | } |
558 | } |
559 | |
560 | PhaseActivities pa = lqnBuilder.addPhaseActivities(apt); |
561 | et.setEntryPhaseActivities(pa); |
562 | |
563 | // now another activity in the current task graph making the |
564 | // call to the entry created for the resource demand |
565 | lqnBuilder.addActivityDef(id+counter); |
566 | lqnBuilder.addActivityMakingCall(id+counter, et.getName(), CallType.SYNCH); |
567 | if (counter<resDemList.size()-1){ |
568 | lqnBuilder.addSequencePrecedence(id+counter, id+(counter+1)); |
569 | } |
570 | |
571 | counter++; |
572 | } |
573 | |
574 | String successorId = (String) doSwitch(object.getSuccessor_AbstractAction()); |
575 | if ( resDemList.size() > 0){ |
576 | //Only add a sequence predecence if there actually was a resource demand in the list, i.e. if an activity etc. has been created |
577 | lqnBuilder.addSequencePrecedence(id+(counter-1), successorId); |
578 | return id+0; // for predecessor |
579 | } else { |
580 | //If no resource demands were there, just let the predecessor connect itself to this action's successor (action disappears) |
581 | return successorId; |
582 | } |
583 | |
584 | |
585 | } |
586 | |
587 | private String getProcessorName(ParametricResourceDemand resourceDemand) { |
588 | ProcessingResourceSpecification prs = myContextWrapper.getConcreteProcessingResource(resourceDemand); |
589 | if (prs == null){ |
590 | throw new RuntimeException("Could not find "+ProcessingResourceSpecification.class.getName() |
591 | +"of type "+resourceDemand.getRequiredResource_ParametricResourceDemand().getEntityName()+"(id:"+resourceDemand.getRequiredResource_ParametricResourceDemand().getId()+")" |
592 | +" adressed by resource demand of action "+resourceDemand.getAction_ParametricResourceDemand().getEntityName()+" ("+resourceDemand.getAction_ParametricResourceDemand().getId()+"). Check your model that the required resources are available on the server."); |
593 | } |
594 | ResourceContainer rc = (ResourceContainer)prs.eContainer(); |
595 | ProcessingResourceType prt = prs.getActiveResourceType_ActiveResourceSpecification(); |
596 | String name = Pcm2LqnHelper.getIdForProcResource(rc, prt); |
597 | return name; |
598 | } |
599 | |
600 | @Override |
601 | public String caseStopAction(StopAction object) { |
602 | String id = Pcm2LqnHelper.getId(object, myContextWrapper); |
603 | lqnBuilder.addActivityDef(id); |
604 | // Precedence has already been created by predecessor |
605 | return id; |
606 | } |
607 | |
608 | private StartAction getStartAction(ResourceDemandingBehaviour behaviour) { |
609 | StartAction startAction = (StartAction) EMFQueryHelper.getObjectByType( |
610 | behaviour.getSteps_Behaviour(), StartAction.class); |
611 | return startAction; |
612 | } |
613 | |
614 | |
615 | private StopAction getStopAction(ResourceDemandingBehaviour behaviour) { |
616 | StopAction stopAction = (StopAction) EMFQueryHelper.getObjectByType( |
617 | behaviour.getSteps_Behaviour(), StopAction.class); |
618 | return stopAction; |
619 | } |
620 | |
621 | |
622 | public String caseForkActionOld(ForkAction object) { |
623 | // if this fork action is asynchronous and only contains an external call, |
624 | // it can be modelled in LQN by just changing the call to send-no-reply |
625 | // TODO: for now only support one forked behaviour. TODO add several ones, |
626 | // should be possible to map them to the same constructs, too. |
627 | if (object.getAsynchronousForkedBehaviours_ForkAction().size() == 1 |
628 | && (object.getSynchronisingBehaviours_ForkAction() == null |
629 | || object.getSynchronisingBehaviours_ForkAction().getSynchronousForkedBehaviours_SynchronisationPoint().size() == 0)){ |
630 | ForkedBehaviour innerFork = object.getAsynchronousForkedBehaviours_ForkAction().get(0); |
631 | // if there is only an external call, that means there are three steps (start, call, stop) and one is an external call |
632 | if (innerFork.getSteps_Behaviour().size() == 3){ |
633 | // find the external call action, the other two have to be start and stop in a valid model |
634 | ExternalCallAction eca = null; |
635 | for (AbstractAction action : innerFork.getSteps_Behaviour()) { |
636 | if (action instanceof ExternalCallAction){ |
637 | eca = (ExternalCallAction)action; |
638 | break; |
639 | } |
640 | } |
641 | if (eca != null){ |
642 | // we have the preconditions for using an LQN send-no-response call |
643 | return handleExternalCallAction(eca, CallType.ASYNCH, object.getSuccessor_AbstractAction()); |
644 | } |
645 | // else return super.caseFork (i.e. go to end of method) |
646 | } |
647 | |
648 | } |
649 | logger.warn("No arbitrary Fork action supported yet, only asnychronous Forks containing a single ExternalCall are supported."); |
650 | |
651 | return super.caseForkAction(object); |
652 | |
653 | } |
654 | |
655 | @Override |
656 | public String caseForkAction(ForkAction object){ |
657 | String id = Pcm2LqnHelper.getId(object, myContextWrapper); |
658 | ActivityDefType adt = lqnBuilder.addActivityDef(id); |
659 | |
660 | String currentId = id; |
661 | String predecessorId = id; |
662 | |
663 | EList<ForkedBehaviour> asyncBehList = object.getAsynchronousForkedBehaviours_ForkAction(); |
664 | for (ForkedBehaviour asyncBeh : asyncBehList){ |
665 | currentId = Pcm2LqnHelper.getIdForForkedBehaviour(asyncBeh, myContextWrapper); |
666 | |
667 | // create new task graph for the forked behaviour |
668 | ProcessorType pt = lqnBuilder.addProcessor(currentId); |
669 | TaskType tt = lqnBuilder.addTask(currentId,pt); |
670 | EntryType et = lqnBuilder.addEntry(currentId,tt); |
671 | lqnBuilder.addTaskActivityGraph(tt); |
672 | |
673 | // create the actions of the new task graph by traversing the forked behavior's steps |
674 | doSwitch(getStartAction(asyncBeh)); |
675 | |
676 | lqnBuilder.restoreFormerTaskActivityGraph(); |
677 | |
678 | // create an asynchronous external call to the task representing the forked behaviour |
679 | lqnBuilder.addActivityDef(currentId+"_Action"); |
680 | lqnBuilder.addActivityMakingCall(currentId+"_Action", currentId+"_Entry", CallType.ASYNCH); |
681 | |
682 | lqnBuilder.addSequencePrecedence(predecessorId, currentId+"_Action"); |
683 | predecessorId = currentId+"_Action"; |
684 | |
685 | } |
686 | |
687 | if (object.getSynchronisingBehaviours_ForkAction() != null |
688 | && object.getSynchronisingBehaviours_ForkAction().getSynchronousForkedBehaviours_SynchronisationPoint().size() > 0) { |
689 | EList<ForkedBehaviour> syncBehList = object.getSynchronisingBehaviours_ForkAction().getSynchronousForkedBehaviours_SynchronisationPoint(); |
690 | |
691 | PrecedenceType ptBegin = lqnBuilder.addBeginForkPrecedence(currentId+"_Action"); |
692 | PrecedenceType ptEnd = lqnBuilder.addEndForkPrecedence(); |
693 | |
694 | for (ForkedBehaviour syncBeh : syncBehList){ |
695 | |
696 | String startId = doSwitch(getStartAction(syncBeh)); |
697 | lqnBuilder.addActivityToPostAnd(startId, ptBegin); |
698 | |
699 | String stopId = Pcm2LqnHelper.getId(getStopAction(syncBeh), myContextWrapper); |
700 | lqnBuilder.addActivityToPreAnd(stopId, ptEnd); |
701 | |
702 | } |
703 | String successorId = (String) doSwitch(object.getSuccessor_AbstractAction()); |
704 | ptEnd.getPost().getActivity().setName(successorId); |
705 | } else { |
706 | String successorId = (String) doSwitch(object.getSuccessor_AbstractAction()); |
707 | lqnBuilder.addSequencePrecedence(currentId + "_Action", successorId); |
708 | } |
709 | |
710 | return id; |
711 | } |
712 | |
713 | |
714 | } |