Salome HOME
Allow to control max number of threads to be launched simultaneouly in case of big...
[modules/yacs.git] / src / engine / DynParaLoop.cxx
1 // Copyright (C) 2006-2023  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "DynParaLoop.hxx"
21 #include "LinkInfo.hxx"
22 #include "OutPort.hxx"
23 #include "Container.hxx"
24 #include "ComponentInstance.hxx"
25 #include "ServiceNode.hxx"
26 #include "InlineNode.hxx"
27 #include "ElementaryNode.hxx"
28 #include "Visitor.hxx"
29
30 #include <list>
31 #include <vector>
32
33 //#define _DEVDEBUG_
34 #include "YacsTrace.hxx"
35
36 using namespace std;
37 using namespace YACS::ENGINE;
38
39 const char DynParaLoop::NAME_OF_SPLITTED_SEQ_OUT[] = "evalSamples";
40 const char DynParaLoop::OLD_NAME_OF_SPLITTED_SEQ_OUT[] = "SmplPrt"; // For backward compatibility with 5.1.4
41
42 DynParaLoop::DynParaLoop(const std::string& name, TypeCode *typeOfDataSplitted, std::unique_ptr<NbBranchesAbstract>&& branchManager)
43   : ComposedNode(name),_node(0),_initNode(0),_finalizeNode(0),_nbOfEltConsumed(0),
44     _nbOfBranches(std::move(branchManager)),
45     _splittedPort(NAME_OF_SPLITTED_SEQ_OUT,this,typeOfDataSplitted),_initializingCounter(0),_unfinishedCounter(0),_failedCounter(0),_weight(), _loopWeight(0)
46 {
47   _weight.setDefaultLoop();
48 }
49
50 DynParaLoop::~DynParaLoop()
51 {
52   delete _node;
53   delete _initNode;
54   delete _finalizeNode;
55 }
56
57 DynParaLoop::DynParaLoop(const DynParaLoop& other, ComposedNode *father, bool editionOnly)
58   : ComposedNode(other,father),_nbOfBranches(other._nbOfBranches->copy(this)),
59     _splittedPort(other._splittedPort,this), _node(0), _initNode(0), _finalizeNode(0),
60     _nbOfEltConsumed(0),_initializingCounter(0),_unfinishedCounter(0),_failedCounter(0),_weight(other._weight), _loopWeight(other._loopWeight)
61 {
62   if(other._node)
63     _node=other._node->clone(this,editionOnly);
64   if(other._initNode)
65     _initNode=other._initNode->clone(this,editionOnly);
66   if(other._finalizeNode)
67     _finalizeNode = other._finalizeNode->clone(this,editionOnly);
68   const AnyOutputPort& startOfLinksToReproduce=other._splittedPort;
69   set<InPort *> endsOfLinksToReproduce=startOfLinksToReproduce.edSetInPort();
70   for(set<InPort *>::iterator iter=endsOfLinksToReproduce.begin();iter!=endsOfLinksToReproduce.end();iter++)
71     edAddLink(&_splittedPort,getInPort(other.getPortName(*iter)));
72 }
73
74 Node *DynParaLoop::edSetNode(Node *node)
75 {
76   return checkConsistencyAndSetNode(_node, node);
77 }
78
79 //! This method is used to factorize methods edSetNode, edSetInitNode and edSetFinalizeNode
80 Node * DynParaLoop::checkConsistencyAndSetNode(Node* &nodeToReplace, Node* node)
81 {
82   if (node == NULL || nodeToReplace == node)
83     return 0;
84   if (node->_father)
85     throw Exception(string("Can't set node: node ") + node->getName() + " is not orphan.");
86   if (_node && _node != nodeToReplace && _node->getName() == node->getName())
87     throw Exception(string("Can't set node: node ") + node->getName() +
88                     " has the same name than exec node already in " + _name + ".");
89   if (_initNode && _initNode != nodeToReplace && _initNode->getName() == node->getName())
90     throw Exception(string("Can't set node: node ") + node->getName() +
91                     " has the same name than init node already in " + _name + ".");
92   if (_finalizeNode && _finalizeNode != nodeToReplace && _finalizeNode->getName() == node->getName())
93     throw Exception(string("Can't set node: node ") + node->getName() +
94                     " has the same name than finalize node already in " + _name + ".");
95   checkNoCrossHierachyWith(node);
96   ComposedNode::edRemoveChild(nodeToReplace);
97   Node * ret = nodeToReplace;
98   nodeToReplace = node;
99   nodeToReplace->_father = this;
100   // set _modified flag so that edUpdateState can refresh state
101   modified();
102   return ret;
103 }
104
105 void DynParaLoop::init(bool start)
106 {
107   ComposedNode::init(start);
108   if(!_node)
109     {
110       string what("DynParaLoop::init : no node specified for ForEachLoop with name "); what +=_name;
111       throw Exception(what);
112     }
113   _node->init(start);
114   if (_initNode) _initNode->init(start);
115   if (_finalizeNode) _finalizeNode->init(start);
116   _nbOfBranches->exInit(start);
117   _splittedPort.exInit();
118   _nbOfEltConsumed=0;
119   _failedCounter=0;
120 }
121
122 Node *DynParaLoop::edSetInitNode(Node *node)
123 {
124   return checkConsistencyAndSetNode(_initNode, node);
125 }
126
127 Node * DynParaLoop::edSetFinalizeNode(Node * node)
128 {
129   return checkConsistencyAndSetNode(_finalizeNode, node);
130 }
131
132 //! Connect an OutPort to an InPort and add control link if necessary
133 /*!
134  * Connect the ports with a data link (edAddLink)
135  * In a Loop don't add control flow link : use this only to add data back links
136  *
137  * \param start : the OutPort to connect
138  * \param end : the InPort to connect
139  * \return  true if a new link has been created, false otherwise.
140  */
141 bool DynParaLoop::edAddDFLink(OutPort *start, InPort *end)
142 {
143   return edAddLink(start,end);
144 }
145
146 int DynParaLoop::getNumberOfInputPorts() const
147 {
148   return ComposedNode::getNumberOfInputPorts()+1;
149 }
150
151 int DynParaLoop::getNumberOfOutputPorts() const
152 {
153   return ComposedNode::getNumberOfOutputPorts()+1;
154 }
155
156 /*!
157  * DynParaLoop creates at runtime (exupdateState) clone of nodes. One clone per branch.
158  * This method returns the id of the branch given the node \a node.
159  * If \a node is not a dynamically created node in \a this -1 is returned.
160  */
161 int DynParaLoop::getBranchIDOfNode(Node *node) const
162 {
163   if(_node)
164     {
165       for(std::vector<Node *>::const_iterator it=_execNodes.begin();it!=_execNodes.end();it++)
166         if(node==*it)
167           return std::distance(_execNodes.begin(),it);
168     }
169   if(_finalizeNode)
170     {
171       for(std::vector<Node *>::const_iterator it=_execFinalizeNodes.begin();it!=_execFinalizeNodes.end();it++)
172         if(node==*it)
173           return std::distance(_execFinalizeNodes.begin(),it);
174     }
175   if(_initNode)
176     {
177       for(std::vector<Node *>::const_iterator it=_execInitNodes.begin();it!=_execInitNodes.end();it++)
178         if(node==*it)
179           return std::distance(_execInitNodes.begin(),it);
180     }
181   return -1;
182 }
183
184 std::list<OutputPort *> DynParaLoop::getSetOfOutputPort() const
185 {
186   list<OutputPort *> ret=ComposedNode::getSetOfOutputPort();
187   ret.push_back((OutputPort *)&_splittedPort);
188   return ret;
189 }
190
191 std::list<OutputPort *> DynParaLoop::getLocalOutputPorts() const
192 {
193   list<OutputPort *> ret=ComposedNode::getLocalOutputPorts();
194   ret.push_back((OutputPort *)&_splittedPort);
195   return ret;
196 }
197
198 OutPort *DynParaLoop::getOutPort(const std::string& name) const
199 {
200   if (name == NAME_OF_SPLITTED_SEQ_OUT || name == OLD_NAME_OF_SPLITTED_SEQ_OUT)
201     return (OutPort *)&_splittedPort;
202   return ComposedNode::getOutPort(name);
203 }
204
205
206 OutputPort *DynParaLoop::getOutputPort(const std::string& name) const
207 {
208   if (name == NAME_OF_SPLITTED_SEQ_OUT || name == OLD_NAME_OF_SPLITTED_SEQ_OUT)
209     return (OutputPort *)&_splittedPort;
210   return ComposedNode::getOutputPort(name);
211 }
212
213 bool DynParaLoop::isPlacementPredictableB4Run() const
214 {
215   return false;
216 }
217
218 Node *DynParaLoop::edRemoveNode()
219 {
220   return removeNode(_node);
221 }
222
223 //! This method is used to factorize methods edRemoveNode, edRemoveInitNode and edRemoveFinalizeNode
224 Node * DynParaLoop::removeNode(Node* &nodeToRemove)
225 {
226   if (!nodeToRemove)
227     return NULL;
228   ComposedNode::edRemoveChild(nodeToRemove);
229   Node * ret = nodeToRemove;
230   nodeToRemove = NULL;
231   modified();
232   return ret;
233 }
234
235 Node *DynParaLoop::edRemoveInitNode()
236 {
237   return removeNode(_initNode);
238 }
239
240 Node * DynParaLoop::edRemoveFinalizeNode()
241 {
242   return removeNode(_finalizeNode);
243 }
244
245 void DynParaLoop::edRemoveChild(Node *node)
246 {
247   ComposedNode::edRemoveChild(node);
248   if(node==_node)
249     _node=0;
250   if(node==_initNode)
251     _initNode=0;
252   if(node==_finalizeNode)
253     _finalizeNode=0;
254   modified();
255 }
256
257 bool DynParaLoop::edAddChild(Node *DISOWNnode)
258 {
259   return edSetNode(DISOWNnode);
260 }
261
262 std::list<Node *> DynParaLoop::edGetDirectDescendants() const
263 {
264   list<Node *> ret;
265   if(_node)
266     ret.push_back(_node);
267   if(_initNode)
268     ret.push_back(_initNode);
269   if(_finalizeNode)
270     ret.push_back(_finalizeNode);
271   return ret;
272 }
273
274 std::list<InputPort *> DynParaLoop::getSetOfInputPort() const
275 {
276   list<InputPort *> ret=ComposedNode::getSetOfInputPort();
277   InputPort *port(_nbOfBranches->getPort());
278   if(port)
279     ret.push_back(port);
280   return ret;
281 }
282
283 InputPort *DynParaLoop::getInputPort(const std::string& name) const
284 {
285   if(_nbOfBranches->isMyName(name))
286     return _nbOfBranches->getPort();
287   return ComposedNode::getInputPort(name);
288 }
289
290 std::list<InputPort *> DynParaLoop::getLocalInputPorts() const
291 {
292   list<InputPort *> ret=ComposedNode::getLocalInputPorts();
293   InputPort *port(_nbOfBranches->getPort());
294   if(port)
295     ret.push_back(port);
296   return ret;
297 }
298
299 unsigned DynParaLoop::getNumberOfBranchesCreatedDyn() const
300 {
301   if(_execNodes.empty())
302     throw Exception("ForEachLoop::getNumberOfBranches : No branches created dynamically ! - ForEachLoop needs to run or to be runned to call getNumberOfBranches");
303   else
304     return _execNodes.size();
305 }
306
307 Node *DynParaLoop::getChildByShortName(const std::string& name) const
308 {
309   if (_node && name == _node->getName())
310     return _node;
311   if (_initNode && name == _initNode->getName())
312     return  _initNode;
313   if (_finalizeNode && name == _finalizeNode->getName())
314     return  _finalizeNode;
315   std::string what("node "); what+= name ; what+=" is not a child of DynParaLoop node "; what += getName();
316   throw Exception(what);
317 }
318
319 Node *DynParaLoop::getChildByNameExec(const std::string& name, unsigned id) const
320 {
321   if(id>=getNumberOfBranchesCreatedDyn())
322     throw Exception("ForEachLoop::getChildByNameExec : invalid id - too large compared with dynamically created branches.");
323   if (_node && name == _node->getName())
324     return _execNodes[id];
325   if (_initNode && name == _initNode->getName())
326     return _execInitNodes[id];
327   if (_finalizeNode && name == _finalizeNode->getName())
328     return _execFinalizeNodes[id];
329   std::string what("node "); what+= name ; what+=" is not a child of DynParaLoop node "; what += getName();
330   throw Exception(what);
331 }
332
333 void DynParaLoop::cleanDynGraph()
334 {
335   vector<Node *>::iterator iter;
336   for(iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
337     delete *iter;
338   _execNodes.clear();
339   for(iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
340     delete *iter;
341   _execInitNodes.clear();
342   for(iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
343     delete *iter;
344   _execFinalizeNodes.clear();
345 }
346
347 /*!
348  * This method applies on newly cloned on exec nodes (_execNodes/_execInitNodes)
349  * the setting of input ports coming from outside of 'this'
350  */
351 void DynParaLoop::prepareInputsFromOutOfScope(int branchNb)
352 {
353   set< InPort * > portsToSetVals=getAllInPortsComingFromOutsideOfCurrentScope();
354
355   // This tweak is to fix problems with nested dynamic loops where links are not cloned properly
356   list<InPort *> temp = getSetOfInPort();
357   for(list<InPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
358     {
359       if ((*iter2)->edSetOutPort().size() == 1 && *(*iter2)->edSetOutPort().begin() == NULL)
360         {
361           portsToSetVals.insert(*iter2);
362         }
363     }
364
365   // local input ports are not candidates for dynamically duplicated inport.
366   list<InputPort *> localPorts = getLocalInputPorts();
367   for(list<InputPort *>::iterator iter = localPorts.begin() ; iter != localPorts.end() ; iter++)
368     portsToSetVals.erase(*iter);
369   for(set< InPort * >::iterator iter=portsToSetVals.begin();iter!=portsToSetVals.end();iter++)
370     {
371       InputPort *curPortCasted=(InputPort *) *iter;//Cast granted by ForEachLoop::buildDelegateOf(InPort)
372       void *val=curPortCasted->get();
373       InputPort *portToSet=getDynInputPortByAbsName(branchNb,getInPortName(*iter),true);
374       if(portToSet)//portToSet==0 in case of portToSet==_splitterNode._dataPortToDispatch of ForEach
375         {
376           portToSet->put((const void *)val);
377           portToSet->edNotifyReferencedBy(nullptr,false);//This is to indicate that somewhere somebody deals with this inputport
378           //even if no direct physical link exists. This exclusively for _execNodes[branchNb]::init on the next turn of loop.
379           //false is put as 2nd parameter to tell to portToSet, do not touch to the data in case of squeezeMemory.
380         }
381     }
382 }
383
384 void DynParaLoop::putValueOnBranch(Any *val, unsigned branchId, bool first)
385 {
386   bool isDispatched = false;
387   set<InPort *> inPrtLkdWthSplttdPrt=_splittedPort.edSetInPort();
388   for(set<InPort *>::iterator iter=inPrtLkdWthSplttdPrt.begin();iter!=inPrtLkdWthSplttdPrt.end();iter++)
389     {
390       std::string portNameOnCurPrt=getPortName(*iter);
391       InputPort *portOnGivenBranch=getDynInputPortByAbsName(branchId,portNameOnCurPrt,first);//Cast granted because impossible to have cross protocol with _splittedPort
392       //see OptimizerLoop::buildDelegateOf
393       if(portOnGivenBranch)
394         {
395           if(first)
396             portOnGivenBranch->edNotifyReferencedBy(0);
397           InputPort *traducer=getRuntime()->adapt(portOnGivenBranch,
398                                                   Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME,_splittedPort.edGetType());
399           traducer->put((const void *)val);
400           isDispatched = true;
401           if(traducer!=portOnGivenBranch)
402             delete traducer;
403         }
404     }
405   if ( isDispatched )
406     {
407       Any *tmp=val->clone();
408       _splittedPort.setValue(tmp);
409       tmp->decrRef();
410     }
411 }
412
413 DynParaLoop::TypeOfNode DynParaLoop::getIdentityOfNotifyerNode(const Node *node, unsigned& id)
414 {
415   vector<Node *>::iterator iter;
416   id=0;
417   for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++,id++)
418     if (*iter==node)
419       return WORK_NODE;
420   id=0;
421   for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++,id++)
422     if (*iter==node)
423       return INIT_NODE;
424   id=0;
425   for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++,id++)
426     if (*iter==node)
427       return FINALIZE_NODE;
428   throw Exception("DynParaLoop::getIdentityOfNotifyerNode: unrecognized node !");
429 }
430
431 void DynParaLoop::setWeight(double loopWeight)
432 {
433   if(loopWeight<=0.)
434     throw Exception("DynParaLoop::setWeight : invalid input value !");
435   _loopWeight=loopWeight;
436 }
437
438 ComplexWeight* DynParaLoop::getWeight()
439 {
440   if (_loopWeight>0.)
441     _weight.setLoopWeight(_loopWeight, _node->getMaxLevelOfParallelism()); // not done in setWeight because _node can be null at that time
442   return &_weight;      
443 }
444
445 bool DynParaLoop::isMultiplicitySpecified(unsigned& value) const
446 {
447   return _nbOfBranches->isMultiplicitySpecified(value);
448 }
449
450 void DynParaLoop::forceMultiplicity(unsigned value)
451 {
452   _nbOfBranches->forceMultiplicity(value);
453 }
454
455 void DynParaLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
456 {
457   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
458   if(typeOfPortInstance!=InputPort::NAME)
459     throw Exception("DynParaLoop::buildDelegateOf : A link with datastream end inside DynParaLoop is not possible");
460 }
461
462 void DynParaLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
463 {
464   std::string linkName("(");
465   linkName += port.first->getName()+" to "+finalTarget->getName()+")";
466   if(_initNode)
467     if(isInMyDescendance(port.first->getNode())==_initNode)
468       throw Exception(std::string("Illegal link within a parallel loop: \
469 a link starting from the init node can't leave the scope of the loop.")
470                     + linkName);
471
472   if(_finalizeNode)
473     if(isInMyDescendance(port.first->getNode())==_finalizeNode)
474       throw Exception(std::string("Illegal link within a parallel loop: \
475 an output port of the finalize node can't be linked.")
476                     + linkName);
477
478   if(port.first==&_splittedPort)
479     throw Exception(std::string("Illegal link within a parallel loop: \
480 the 'evalSamples' port must be linked within the scope of the loop.")
481                     + linkName);
482 }
483
484 void DynParaLoop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
485 {
486   const char what[]="DynParaLoop::checkCFLinks : internal error.";
487   //First dealing checkCFLinks forwarding...
488   if(isInMyDescendance(end->getNode())==0)//no chance that _splittedPort is in starts due to buildDelegate.
489     solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
490   else
491     {//no forwarding here.
492       if(starts.size()!=1)
493         throw Exception(what);
494       //ASSERT(direction) : see DynParaLoop::checkControlDependancy only 'fw' filled.
495       if(alreadyFed==FREE_ST)
496         alreadyFed=FED_ST;
497       else if(alreadyFed==FED_ST)
498         {//Shame ! splittedPort fills a port already fed...
499           info.pushInfoLink(*(starts.begin()),end,I_USELESS);
500         }
501     }
502 }
503
504 /*!
505  * \param start : start port
506  * \param end : end port
507  * \param cross indicates if start -> end link is a DS link behind.
508  * \param fw out parameter.
509  * \param fwCross out parameter storing links where a cross has been detected.
510  * \param bw out parameter where backward links are stored.
511  * \param info : collected information
512  */
513 void DynParaLoop::checkControlDependancy(OutPort *start, InPort *end, bool cross,
514                                          std::map < ComposedNode *,  std::list < OutPort * >, SortHierarc >& fw,
515                                          std::vector<OutPort *>& fwCross,
516                                          std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
517                                          LinkInfo& info) const
518 {
519     fw[(ComposedNode *)this].push_back(start);
520 }
521
522 void DynParaLoop::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
523                                 InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd)
524 {
525   ComposedNode::checkLinkPossibility(start, pointsOfViewStart, end, pointsOfViewEnd);
526   Node * startNode = isInMyDescendance(start->getNode());
527   Node * endNode = isInMyDescendance(end->getNode());
528   std::string linkName("(");
529   linkName += start->getName()+" to "+end->getName()+")";
530   
531   if(start == &_splittedPort && endNode != _node)
532     throw Exception(std::string("Illegal link within a parallel loop: \
533 the 'evalSamples' port can only be connected to the working node of the loop.")
534                     + linkName);
535   
536   if(_finalizeNode && _finalizeNode == startNode)
537     throw Exception(std::string("Illegal link within a parallel loop: \
538 the finalize node can't be the origin of a link.")
539                     + linkName);
540   
541   if(_initNode && _node == startNode && _initNode == endNode)
542     throw Exception(std::string("Illegal link within a parallel loop: \
543 can't make a link from the working node to the init node.")
544                     + linkName);
545   
546   if(_finalizeNode && _node == startNode && _finalizeNode == endNode)
547     throw Exception(std::string("Illegal link within a parallel loop: \
548 can't make a link from the working node to the finalize node.")
549                     + linkName);
550 }
551
552 /*!
553  * \note : For a given name 'name' of port in absolute form from this, returns the corresponding InputPort 
554  *         instance of the port for the branch # 'branchNb'. 
555  *         The port can be part of _node or _initNode if it exists (if 'initNodeAdmitted' is true).
556  *         \b WARNING : no check performed on  'branchNb' value to see if it is compatible with size of '_execNodes'.
557  *         This method is called to dispatch value on each InputPort linked to this->._splitterNode._splittedPort
558  */
559 InputPort *DynParaLoop::getDynInputPortByAbsName(int branchNb, const std::string& name, bool initNodeAdmitted)
560 {
561   string portName, nodeName;
562   splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true);
563   Node *staticChild = getChildByName(nodeName);
564   Node *desc=isInMyDescendance(staticChild);
565   if(desc==_node)
566     {
567       splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
568       return _execNodes[branchNb]->getInputPort(portName);
569     }
570   else if(desc==_initNode)
571     if(initNodeAdmitted)
572       {
573         splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
574         return _execInitNodes[branchNb]->getInputPort(portName);
575       }
576   return 0;
577 }
578
579 void DynParaLoop::checkBasicConsistency() const
580 {
581   DEBTRACE("DynParaLoop::checkBasicConsistency");
582   ComposedNode::checkBasicConsistency();
583   if(!_node)
584     throw Exception("For a dynamic loop, internal node is mandatory");
585 }
586
587 std::string DynParaLoop::getErrorReport()
588 {
589   DEBTRACE("DynParaLoop::getErrorReport: " << getName() << " " << _state);
590   YACS::StatesForNode effectiveState=getEffectiveState();
591
592   if(effectiveState != YACS::INVALID &&  effectiveState != YACS::ERROR && effectiveState != YACS::FAILED)
593     return "";
594
595   std::string report="<error node= " + getName();
596   switch(effectiveState)
597     {
598     case YACS::INVALID:
599       report=report+" state= INVALID";
600       break;
601     case YACS::ERROR:
602       report=report+" state= ERROR";
603       break;
604     case YACS::FAILED:
605       report=report+" state= FAILED";
606       break;
607     default:
608       break;
609     }
610   report=report + ">\n" ;
611   if(_errorDetails != "")
612     report=report+_errorDetails+"\n";
613
614   if(_execNodes.empty())
615     {
616       // edition node
617       list<Node *> constituents=edGetDirectDescendants();
618       for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
619         {
620           std::string rep=(*iter)->getErrorReport();
621           if(rep != "")
622             {
623               report=report+rep+"\n";
624             }
625         }
626     }
627   else
628     {
629       // execution nodes
630       for(vector<Node *>::iterator iter=_execInitNodes.begin();iter!=_execInitNodes.end();iter++)
631         {
632           std::string rep=(*iter)->getErrorReport();
633           if(rep != "")
634             {
635               report=report+rep+"\n";
636             }
637         }
638       for(vector<Node *>::iterator iter=_execNodes.begin();iter!=_execNodes.end();iter++)
639         {
640           if(*iter)
641             {
642               std::string rep=(*iter)->getErrorReport();
643               if(rep != "")
644                 {
645                   report=report+rep+"\n";
646                 }
647             }
648         }
649       for(vector<Node *>::iterator iter=_execFinalizeNodes.begin();iter!=_execFinalizeNodes.end();iter++)
650         {
651           std::string rep=(*iter)->getErrorReport();
652           if(rep != "")
653             {
654               report=report+rep+"\n";
655             }
656         }
657     }
658
659   report=report+"</error>";
660   return report;
661 }
662
663 void DynParaLoop::forwardExecStateToOriginalBody(Node *execNode)
664 {
665   unsigned int id;
666   Node * origNode = NULL;
667   switch (getIdentityOfNotifyerNode(execNode,id))
668     {
669     case INIT_NODE:
670     {
671       origNode = _initNode;
672       break;
673     }
674     case WORK_NODE:
675     {
676       origNode = _node;
677       break;
678     }
679     case FINALIZE_NODE:
680     {
681       origNode = _finalizeNode;
682       break;
683     }
684     default:
685       YASSERT(false)
686     }
687
688   YASSERT(origNode != NULL)
689   origNode->setState(execNode->getState());
690   origNode->setErrorDetails(execNode->getErrorDetails());
691
692   ComposedNode* compNode = dynamic_cast<ComposedNode*>(origNode);
693   ComposedNode* compNodeExe = dynamic_cast<ComposedNode*>(execNode);
694   if (compNode && compNodeExe)
695     {
696       list<Node *> aChldn = compNodeExe->getAllRecursiveConstituents();
697       list<Node *>::iterator iter=aChldn.begin();
698       for(;iter!=aChldn.end();iter++)
699         {
700           Node* node=compNode->getChildByName(compNodeExe->getChildName(*iter));
701           node->setState((*iter)->getState());
702           node->setErrorDetails((*iter)->getErrorDetails());
703         }
704     }
705 }
706
707 //! Method used to notify the node that a child node has failed
708 /*!
709  * Update the current state and return the change state
710  *
711  *  \param node : the child node that has failed
712  *  \return the state change
713  */
714 YACS::Event DynParaLoop::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
715 {
716   DEBTRACE("DynParaLoop::updateStateOnFailedEventFrom " << node->getName());
717   setState(YACS::FAILED);
718   forwardExecStateToOriginalBody(node);
719   unsigned int id;
720   switch (getIdentityOfNotifyerNode(node,id))
721     {
722     case INIT_NODE:
723     {
724       _node->setState(YACS::FAILED);
725       if (_finalizeNode != NULL) _finalizeNode->setState(YACS::FAILED);
726       break;
727     }
728     case WORK_NODE:
729     {
730       if (_finalizeNode != NULL) _finalizeNode->setState(YACS::FAILED);
731       break;
732     }
733     }
734   return YACS::ABORT;
735 }
736
737 //! Clone nodes and make their placement consistent with the placement of the original ones.
738 /*!
739  *  For instance, if two original nodes are placed on a component comp1 in a container cont1
740  *  and a third one is placed on a component comp2 in the container cont1, the clones of the two
741  *  first nodes will be placed on a component comp3 in a container cont2 and the third clone
742  *  will be placed on a component comp4 in the container cont2.
743  */
744 vector<Node *> DynParaLoop::cloneAndPlaceNodesCoherently(const vector<Node *> & origNodes)
745 {
746   DEBTRACE("Begin cloneAndPlaceNodesCoherently")
747   vector<Node *> clones;
748   DeploymentTree treeToDup;
749   vector<list<ElementaryNode *> > origElemNodeList;
750   for (int i=0 ; i<origNodes.size() ; i++)
751     {
752       DEBTRACE("Cloning node " << i)
753       if (origNodes[i] == NULL)
754         {
755           DEBTRACE("Cloning node " << i << ", NULL" )
756           clones.push_back(NULL);
757           origElemNodeList.push_back(list<ElementaryNode *>());
758         }
759       else
760         {
761           DEBTRACE("Cloning node " << i << "," << origNodes[i]->getName())
762           clones.push_back(origNodes[i]->simpleClone(this, false));
763           list<ElementaryNode *> tasks = origNodes[i]->getRecursiveConstituents();
764           origElemNodeList.push_back(tasks);
765           for (list< ElementaryNode *>::iterator iter=tasks.begin() ; iter!=tasks.end() ; iter++)
766             treeToDup.appendTask(*iter, (*iter)->getDynClonerIfExists(this));
767         }
768     }
769   
770   // Build the links between clones.
771   // Only the links starting from initNode are possible.
772   if(_initNode)
773   {
774     std::vector< std::pair<OutPort *, InPort *> > outLinks = _initNode->getSetOfLinksLeavingCurrentScope();
775     std::vector< std::pair<OutPort *, InPort *> >::const_iterator it;
776     for(it=outLinks.begin(); it!=outLinks.end(); it++)
777     {
778       OutPort *startPort = it->first;
779       InPort *endPort = it->second;
780       Node* destNode = isInMyDescendance(endPort->getNode());
781       if(destNode == _node)
782         edAddLink(clones[0]->getOutPort(startPort->getName()),
783                   clones[1]->getInPort(endPort->getName()));
784       if(destNode == _finalizeNode)
785         edAddLink(clones[0]->getOutPort(startPort->getName()),
786                   clones[2]->getInPort(endPort->getName()));
787     }
788   }
789
790   DEBTRACE("Placing nodes...")
791   vector<Container *> conts=treeToDup.getAllContainers();
792
793   //iterate on all containers
794   for(vector<Container *>::iterator iterCt=conts.begin();iterCt!=conts.end();iterCt++)
795     {
796       DEBTRACE("Container " << ((*iterCt)?(*iterCt)->getName():"NULL"))
797       vector<ComponentInstance *> comps=treeToDup.getComponentsLinkedToContainer(*iterCt);
798       Container *contCloned=0;
799       if((*iterCt))
800         contCloned=(*iterCt)->clone();
801
802       //iterate on all component instances linked to the container
803       for(vector<ComponentInstance *>::iterator iterCp=comps.begin();iterCp!=comps.end();iterCp++)
804         {
805           DEBTRACE("Component " << (*iterCp)->getCompoName())
806           vector<Task *> tasks=treeToDup.getTasksLinkedToComponent(*iterCp);
807           ComponentInstance *curCloned=(*iterCp)->clone();
808           DEBTRACE("Assign container " << (*iterCp)->getCompoName())
809           curCloned->setContainer(contCloned);
810           for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
811             {
812               DEBTRACE("Task " << ((ElementaryNode *)(*iterT))->getName())
813               int i = 0;
814               ElementaryNode * origElemNode = NULL;
815               for (i=0 ; i<origNodes.size() ; i++)
816                 if (origNodes[i] != NULL)
817                   {
818                     DEBTRACE("Looking in original node " << i)
819                     list<ElementaryNode *>::iterator res=find(origElemNodeList[i].begin(),
820                                                               origElemNodeList[i].end(),
821                                                               (ElementaryNode *)(*iterT));
822                     if (res != origElemNodeList[i].end()) {
823                       origElemNode = *res;
824                       break;
825                     }
826                   }
827
828               YASSERT(origElemNode != NULL)
829               DEBTRACE("Found task in node " << i)
830               ServiceNode * nodeC = NULL;
831               if (origNodes[i] == origElemNode)
832                 nodeC = (ServiceNode *)clones[i];
833               else
834                 {
835                   string childName = ((ComposedNode *)origNodes[i])->getChildName(origElemNode);
836                   nodeC = (ServiceNode *)clones[i]->getChildByName(childName);
837                 }
838               DEBTRACE("Assign component: " << (*iterCp)->getCompoName() << "," << nodeC->getName())
839               nodeC->setComponent(curCloned);
840             }
841           curCloned->decrRef();
842         }
843
844       // iterate on all tasks linked to the container
845       vector<Task *> tasks=treeToDup.getTasksLinkedToContainer(*iterCt);
846       for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
847         {
848           DEBTRACE("Task " << ((ElementaryNode *)(*iterT))->getName())
849           int i = 0;
850           ElementaryNode * origElemNode = NULL;
851           for (i=0 ; i<origNodes.size() ; i++)
852             if (origNodes[i] != NULL)
853               {
854                 DEBTRACE("Looking in original node " << i)
855                 list<ElementaryNode *>::iterator res=find(origElemNodeList[i].begin(),
856                                                           origElemNodeList[i].end(),
857                                                           (ElementaryNode *)(*iterT));
858                 if (res != origElemNodeList[i].end()) 
859                   {
860                     origElemNode = *res;
861                     break;
862                   }
863               }
864           YASSERT(origElemNode != NULL)
865           DEBTRACE("Found task in node " << i)
866           InlineFuncNode * nodeC = NULL;
867           if (origNodes[i] == origElemNode)
868             {
869               nodeC = (InlineFuncNode *)clones[i];
870             }
871           else
872             {
873               string childName = ((ComposedNode *)origNodes[i])->getChildName(origElemNode);
874               nodeC = (InlineFuncNode *)clones[i]->getChildByName(childName);
875             }
876           DEBTRACE("Assign container " << nodeC->getName() << "," << contCloned->getName())
877           nodeC->setContainer(contCloned);
878         }
879
880       // ended with current container
881       if(contCloned)
882         contCloned->decrRef();
883     }
884
885   DEBTRACE("End cloneAndPlaceNodesCoherently")
886   return clones;
887 }
888
889 void DynParaLoop::accept(Visitor *visitor)
890 {
891   visitor->visitDynParaLoop(this);
892 }
893
894 Node * DynParaLoop::getInitNode()
895 {
896   return _initNode;
897 }
898
899 Node * DynParaLoop::getExecNode()
900 {
901   return _node;
902 }
903
904 Node * DynParaLoop::getFinalizeNode()
905 {
906   return _finalizeNode;
907 }
908
909 int DynParaLoop::getMaxLevelOfParallelism() const
910 {
911   return _nbOfBranches->getIntValue() * _node->getMaxLevelOfParallelism();
912 }
913
914 void DynParaLoop::partitionRegardingDPL(const PartDefinition *pd, std::map<ComposedNode *, YACS::BASES::AutoRefCnt<PartDefinition> >& zeMap)
915 {
916   YACS::BASES::AutoRefCnt<PartDefinition> pd2(pd->copy());
917   zeMap[this]=pd2;
918   if(_node)
919     _node->partitionRegardingDPL(pd,zeMap);
920 }
921
922 void DynParaLoop::shutdown(int level)
923 {
924   if(level==0)return;
925   if(!_node) return;
926
927   std::vector<Node *>::iterator iter;
928   for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
929     (*iter)->shutdown(level);
930   for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
931     (*iter)->shutdown(level);
932   for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
933     (*iter)->shutdown(level);
934 }