1 #include "OptimizerLoop.hxx"
2 #include "OutputPort.hxx"
6 using namespace YACS::ENGINE;
9 const char FakeNodeForOptimizerLoop::NAME[]="thisIsAFakeNode";
11 const int OptimizerLoop::NOT_RUNNING_BRANCH_ID=-1973012217;
13 const char OptimizerLoop::NAME_OF_FILENAME_INPUT[]="FileNameInitAlg";
15 const char OptimizerLoop::NAME_OF_OUT_POOL_INPUT[]="retPortForOutPool";
17 OptimizerAlgStandardized::OptimizerAlgStandardized(Pool *pool, OptimizerAlgBase *alg)
18 : OptimizerAlgSync(pool),_algBehind(alg),_threadInCaseOfNotEvent(0)
21 _algBehind->incrRef();
24 OptimizerAlgStandardized::~OptimizerAlgStandardized()
27 _algBehind->decrRef();
30 TypeCode *OptimizerAlgStandardized::getTCForIn() const
32 return _algBehind->getTCForIn();
35 TypeCode *OptimizerAlgStandardized::getTCForOut() const
37 return _algBehind->getTCForOut();
40 void OptimizerAlgStandardized::setAlgPointer(OptimizerAlgBaseFactory algFactory)
43 _algBehind->decrRef();
44 _algBehind=algFactory(_pool);
47 void OptimizerAlgStandardized::parseFileToInit(const std::string& fileName)
49 _algBehind->parseFileToInit(fileName);
52 void OptimizerAlgStandardized::initialize(const Any *input) throw (Exception)
54 _algBehind->initialize(input);
57 void OptimizerAlgStandardized::takeDecision()
59 switch(_algBehind->getType())
63 ((OptimizerAlgSync *) _algBehind)->takeDecision();
66 case NOT_EVENT_ORIENTED:
68 _condition.notifyOneSync();
72 throw Exception("Unrecognized type of algorithm. Only 2 types are available : EVENT_ORIENTED or NOT_EVENT_ORIENTED.");
76 void OptimizerAlgStandardized::finish()
81 void OptimizerAlgStandardized::start()
83 switch(_algBehind->getType())
87 ((OptimizerAlgSync *) _algBehind)->start();
90 case NOT_EVENT_ORIENTED:
92 void **stackForNewTh= new void* [2];
93 stackForNewTh[0]=(void *) ((OptimizerAlgASync *)(_algBehind));//In case of virtual inheritance
94 stackForNewTh[1]=(void *) &_condition;
95 _threadInCaseOfNotEvent=new ::YACS::BASES::Thread(threadFctForAsync,stackForNewTh);
96 _condition.waitForAWait();
100 throw Exception("Unrecognized type of algorithm. Only 2 types are available : EVENT_ORIENTED or NOT_EVENT_ORIENTED.");
104 void *OptimizerAlgStandardized::threadFctForAsync(void* ownStack)
106 void **ownStackCst=(void **)ownStack;
107 OptimizerAlgASync *alg=(OptimizerAlgASync *)ownStackCst[0];
108 ::YACS::BASES::DrivenCondition *cond=(::YACS::BASES::DrivenCondition *)ownStackCst[1];
109 delete [] ownStackCst;
110 alg->startToTakeDecision(cond);
113 FakeNodeForOptimizerLoop::FakeNodeForOptimizerLoop(OptimizerLoop *loop, bool normal, unsigned reason):ElementaryNode(NAME),_loop(loop),
117 _state=YACS::TOACTIVATE;
118 _father=_loop->getFather();
121 FakeNodeForOptimizerLoop::FakeNodeForOptimizerLoop(const FakeNodeForOptimizerLoop& other):ElementaryNode(other),_loop(0),
126 Node *FakeNodeForOptimizerLoop::simpleClone(ComposedNode *father, bool editionOnly) const
128 return new FakeNodeForOptimizerLoop(*this);
131 void FakeNodeForOptimizerLoop::exForwardFailed()
133 _loop->exForwardFailed();
134 FakeNodeForOptimizerLoop *normallyThis=_loop->_nodeForSpecialCases;
135 _loop->_nodeForSpecialCases=0;
139 void FakeNodeForOptimizerLoop::exForwardFinished()
141 _loop->exForwardFinished();
142 FakeNodeForOptimizerLoop *normallyThis=_loop->_nodeForSpecialCases;
143 _loop->_nodeForSpecialCases=0;
147 void FakeNodeForOptimizerLoop::execute()
152 if(_reason==ALG_WITHOUT_START_CASES)
153 what="Alg initialization of optimizerNode with name "; what+=_loop->getName(); what+=" returns no new case(s) to launch";
154 throw Exception(what);
158 void FakeNodeForOptimizerLoop::aborted()
160 _loop->_state=YACS::ERROR;
163 void FakeNodeForOptimizerLoop::finished()
168 OptimizerLoop::OptimizerLoop(const std::string& name, const std::string& algLibWthOutExt,
169 const std::string& symbolNameToOptimizerAlgBaseInstanceFactory,
170 bool algInitOnFile) throw(Exception)
171 try : DynParaLoop(name,Runtime::_tc_string),_loader(algLibWthOutExt),_algInitOnFile(algInitOnFile),
172 _portForInitFile(NAME_OF_FILENAME_INPUT,this,Runtime::_tc_string),
173 _alg(new OptimizerAlgStandardized(&_myPool,0)),_convergenceReachedWithOtherCalc(false),
174 _retPortForOutPool(NAME_OF_OUT_POOL_INPUT,this,Runtime::_tc_string),
175 _nodeForSpecialCases(0),_symbol(symbolNameToOptimizerAlgBaseInstanceFactory)
177 OptimizerAlgBaseFactory algFactory=(OptimizerAlgBaseFactory)_loader.getHandleOnSymbolWithName(_symbol);
179 throw Exception("Problem during library loading.");
180 _alg->setAlgPointer(algFactory);
181 _splittedPort.edSetType(_alg->getTCForIn());
182 _retPortForOutPool.edSetType(_alg->getTCForOut());
188 OptimizerLoop::OptimizerLoop(const OptimizerLoop& other, ComposedNode *father, bool editionOnly):
189 DynParaLoop(other,father,editionOnly),_algInitOnFile(other._algInitOnFile),_loader(other._loader.getLibNameWithoutExt()),_convergenceReachedWithOtherCalc(false),
190 _alg(new OptimizerAlgStandardized(&_myPool,0)),_portForInitFile(other._portForInitFile,this),_retPortForOutPool(other._retPortForOutPool,this),_nodeForSpecialCases(0),_symbol(other._symbol)
192 OptimizerAlgBaseFactory algFactory=(OptimizerAlgBaseFactory)_loader.getHandleOnSymbolWithName(_symbol);
193 _alg->setAlgPointer(algFactory);
194 _splittedPort.edSetType(_alg->getTCForIn());
195 _retPortForOutPool.edSetType(_alg->getTCForOut());
198 OptimizerLoop::~OptimizerLoop()
205 Node *OptimizerLoop::simpleClone(ComposedNode *father, bool editionOnly) const
207 return new OptimizerLoop(*this,father,editionOnly);
210 void OptimizerLoop::init(bool start)
212 DynParaLoop::init(start);
213 _portForInitFile.exInit(start);
214 _convergenceReachedWithOtherCalc=false;
219 void OptimizerLoop::exUpdateState()
221 if(_state == YACS::DISABLED)
223 if(_inGate.exIsReady())
225 _state=YACS::TOACTIVATE;
226 //internal graph update
228 int nbOfBr=_nbOfBranches.getIntValue();
231 delete _nodeForSpecialCases;
232 _nodeForSpecialCases=new FakeNodeForOptimizerLoop(this,getAllOutPortsLeavingCurrentScope().empty(),FakeNodeForOptimizerLoop::NO_BRANCHES);
236 if(_portForInitFile.isEmpty())
238 delete _nodeForSpecialCases;
239 _nodeForSpecialCases=new FakeNodeForOptimizerLoop(this,getAllOutPortsLeavingCurrentScope().empty(),FakeNodeForOptimizerLoop::NO_ALG_INITIALIZATION);
242 _execNodes.resize(nbOfBr);
243 _execIds.resize(nbOfBr);
246 _execInitNodes.resize(nbOfBr);
247 _initNodeUpdated.resize(nbOfBr);
248 for(i=0;i<nbOfBr;i++)
249 _initNodeUpdated[i]=false;
251 for(i=0;i<nbOfBr;i++)
253 _execIds[i]=NOT_RUNNING_BRANCH_ID;
254 _execNodes[i]=_node->clone(this,false);
256 _execInitNodes[i]=_initNode->clone(this,false);
257 prepareInputsFromOutOfScope(i);
259 initInterceptors(nbOfBr);
260 _alg->parseFileToInit(_portForInitFile.getValue()->getStringValue());
263 unsigned char priority;
264 Any *val=_myPool.getNextSampleWithHighestPriority(id,priority);
267 delete _nodeForSpecialCases;
268 _nodeForSpecialCases=new FakeNodeForOptimizerLoop(this,getAllOutPortsLeavingCurrentScope().empty(),FakeNodeForOptimizerLoop::ALG_WITHOUT_START_CASES);
271 launchMaxOfSamples(true);
275 int OptimizerLoop::getNumberOfInputPorts() const
277 return DynParaLoop::getNumberOfInputPorts()+2;
280 InputPort *OptimizerLoop::getInputPort(const std::string& name) const throw(Exception)
282 if(name==NAME_OF_FILENAME_INPUT)
283 return (InputPort *)&_portForInitFile;
284 else if(name==NAME_OF_OUT_POOL_INPUT)
285 return (InputPort *)&_retPortForOutPool;
287 return DynParaLoop::getInputPort(name);
290 std::list<InputPort *> OptimizerLoop::getSetOfInputPort() const
292 list<InputPort *> ret=DynParaLoop::getSetOfInputPort();
293 ret.push_back((InputPort *)&_portForInitFile);
294 ret.push_back((InputPort *)&_retPortForOutPool);
298 std::list<InputPort *> OptimizerLoop::getLocalInputPorts() const
300 list<InputPort *> ret=DynParaLoop::getLocalInputPorts();
301 ret.push_back((InputPort *)&_portForInitFile);
302 ret.push_back((InputPort *)&_retPortForOutPool);
306 void OptimizerLoop::selectRunnableTasks(std::vector<Task *>& tasks)
310 void OptimizerLoop::getReadyTasks(std::vector<Task *>& tasks)
314 if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
316 if(_nodeForSpecialCases)
318 _nodeForSpecialCases->getReadyTasks(tasks);
321 for(vector<Node *>::iterator iter=_execNodes.begin();iter!=_execNodes.end();iter++)
322 (*iter)->getReadyTasks(tasks);
323 for(vector<Node *>::iterator iter2=_execInitNodes.begin();iter2!=_execInitNodes.end();iter2++)
324 (*iter2)->getReadyTasks(tasks);
330 YACS::Event OptimizerLoop::updateStateOnFinishedEventFrom(Node *node)
333 switch(getIdentityOfNotifyerNode(node,id))
336 _execNodes[id]->exUpdateState();
340 if(_state==YACS::DONE)//This case happend when alg has reached its convergence whereas other calculations still compute.
343 _condForCompletenessB4Relaunch.wait();
344 return YACS::NOEVENT;
346 _myPool.putOutSampleAt(_execIds[id],_interceptorsForOutPool[id]->getValue());
347 _myPool.setCurrentId(_execIds[id]);
348 _alg->takeDecision();
349 _myPool.destroyCurrentCase();
352 pushValueOutOfScopeForCase(id);
353 _execIds[id]=NOT_RUNNING_BRANCH_ID;
354 if(!isFullyLazy())// This case happens when the hand is returned to continue, whereas some other are working in parallel for nothing.
355 _convergenceReachedWithOtherCalc=true;
359 _execIds[id]=NOT_RUNNING_BRANCH_ID;
361 unsigned char priority;
362 Any *val=_myPool.getNextSampleWithHighestPriority(newId, priority);
365 bool isFinished=true;
366 for(int i=0;i<_execIds.size() and isFinished;i++)
367 isFinished=(_execIds[i]==NOT_RUNNING_BRANCH_ID);
370 std::cerr <<"OptimizerLoop::updateStateOnFinishedEventFrom: Alg has not inserted more cases whereas last element has been calculated !" << std::endl;
372 _state=YACS::INTERNALERR;
375 return YACS::NOEVENT;
377 launchMaxOfSamples(false);
379 return YACS::NOEVENT;
382 void OptimizerLoop::checkNoCyclePassingThrough(Node *node) throw(Exception)
386 void OptimizerLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
388 DynParaLoop::buildDelegateOf(port,initialStart,pointsOfView);
389 if(port==&_retPortForOutPool)
390 throw Exception("OptimizerLoop::buildDelegateOf : uncorrect OptimizerLoop link : out pool port must be linked within the scope of OptimizerLoop node it belongs to.");
393 void OptimizerLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
395 DynParaLoop::buildDelegateOf(port,finalTarget,pointsOfView);
396 string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
397 if(typeOfPortInstance!=OutputPort::NAME)
398 throw Exception("OptimizerLoop::buildDelegateOf : not implemented for DS because not specified ");
401 void OptimizerLoop::checkControlDependancy(OutPort *start, InPort *end, bool cross,
402 std::map < ComposedNode *, std::list < OutPort * >, SortHierarc >& fw,
403 std::vector<OutPort *>& fwCross,
404 std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
405 LinkInfo& info) const
407 if(end==&_retPortForOutPool)
408 fw[(ComposedNode *)this].push_back(start);
410 DynParaLoop::checkControlDependancy(start,end,cross,fw,fwCross,bw,info);
413 void OptimizerLoop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
415 if(end==&_retPortForOutPool)
416 solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
418 DynParaLoop::checkCFLinks(starts,end,alreadyFed,direction,info);
421 void OptimizerLoop::cleanInterceptors()
423 //the destruction of interceptors whereas some running nodes can push value on them can lead to SIG SEGV.
424 if(!_execNodes.empty())
426 if(_convergenceReachedWithOtherCalc)
428 cout << "Waiting completion of last other useless cases." << endl;
429 _condForCompletenessB4Relaunch.waitForAWait();
432 // At this point all garanties taken let's clean all.
433 map<InputPort *,vector<InputPort *> >::iterator iter=_interceptors.begin();
434 for(;iter!=_interceptors.end();iter++)
435 for(vector<InputPort *>::iterator iter2=(*iter).second.begin();iter2!=(*iter).second.end();iter2++)
437 _interceptors.clear();
438 for(vector<AnyInputPort *>::iterator iter3=_interceptorsForOutPool.begin();iter3!=_interceptorsForOutPool.end();iter3++)
440 _interceptorsForOutPool.clear();
443 void OptimizerLoop::launchMaxOfSamples(bool first)
446 unsigned char priority;
449 for(val=_myPool.getNextSampleWithHighestPriority(id,priority);!isFullyBusy(i) && val;val=_myPool.getNextSampleWithHighestPriority(id,priority))
452 _myPool.markIdAsInUse(id);
455 if(!_initNodeUpdated[i])
457 putValueOnBranch(val,i,first);
458 _execInitNodes[i]->exUpdateState();
459 _initNodeUpdated[i]=true;
463 putValueOnBranch(val,i,first);
464 _execNodes[i]->exUpdateState();
471 _execNodes[i]->init(first);
472 putValueOnBranch(val,i,first);
473 _execNodes[i]->exUpdateState();
479 bool OptimizerLoop::isFullyLazy() const
482 for(unsigned i=0;i<_execIds.size() and isLazy;i++)
483 isLazy=(_execIds[i]==NOT_RUNNING_BRANCH_ID);
488 * Returns if a dynamic branch is available.
489 * \param branchId Out param. Only usable if returned value is equal to \b false.
491 bool OptimizerLoop::isFullyBusy(unsigned& branchId) const
493 bool isFinished=true;
495 for(i=0;i<_execIds.size() and isFinished;i++)
496 isFinished=(_execIds[i]!=NOT_RUNNING_BRANCH_ID);
503 * Perform initialization of interceptors. \b WARNING _execNodes have to be created before.
505 void OptimizerLoop::initInterceptors(unsigned nbOfBr)
507 //For all classical outputports leaving 'this'
508 set<OutPort *> portsToIntercept=getAllOutPortsLeavingCurrentScope();
509 for(set<OutPort *>::iterator iter=portsToIntercept.begin();iter!=portsToIntercept.end();iter++)
511 OutputPort *portC=(OutputPort *)(*iter);//Warrantied by OptimizerLoop::buildDelegateOf
512 const set<InputPort *>& links=portC->getSetOfPhyLinks();
513 for(set<InputPort *>::const_iterator iter2=links.begin();iter2!=links.end();iter2++)
516 InputPort *reprCur=dynamic_cast<InputPort *>((*iter2)->getPublicRepresentant());
518 InputPort *reprCur=(*iter2)->getPublicRepresentant();
520 if(!isInMyDescendance(reprCur->getNode()))
521 {//here we've got an out of scope link : Let's intercept it
522 if(_interceptors.find(reprCur)==_interceptors.end())
524 _interceptors[reprCur].resize(nbOfBr);
525 for(unsigned i=0;i<nbOfBr;i++)
527 OutputPort *portExecC=(OutputPort *)_execNodes[i]->getOutputPort(_node->getOutPortName(portC));
528 InputPort *clone=reprCur->clone(0);
529 _interceptors[reprCur][i]=clone;
530 portExecC->edAddInputPort(clone);
535 for(unsigned i=0;i<nbOfBr;i++)
537 OutputPort *portExecC=(OutputPort *)_execNodes[i]->getOutputPort(_node->getOutPortName(portC));
538 portExecC->edAddInputPort(_interceptors[reprCur][i]);
545 _interceptorsForOutPool.resize(nbOfBr);
546 set< OutPort * > links=_retPortForOutPool.edSetOutPort();
547 for(unsigned i=0;i<nbOfBr;i++)
548 _interceptorsForOutPool[i]=(AnyInputPort *)_retPortForOutPool.clone(this);
549 for(set<OutPort *>::iterator iter2=links.begin();iter2!=links.end();iter2++)
550 for(unsigned j=0;j<nbOfBr;j++)
553 Node *whatType=isInMyDescendance((*iter2)->getNode());
556 portExec=_execNodes[j]->getOutPort(_node->getOutPortName(*iter2));
557 portExec->addInPort(_interceptorsForOutPool[j]);
559 else if(whatType==_initNode && whatType!=0)//This case should never happend. Useless !
561 portExec=_execInitNodes[j]->getOutPort(_node->getOutPortName(*iter2));
562 portExec->addInPort(_interceptorsForOutPool[j]);
568 * Typically called when _alg has decided that convergence has been reached. In this case the links leaving the current scope are activated and filled
569 * with value of the branch specified by 'branchId' that is the branch in which the convergence has been reached.
571 void OptimizerLoop::pushValueOutOfScopeForCase(unsigned branchId)
573 map<InputPort *, std::vector<InputPort *> >::iterator iter;
574 for(iter=_interceptors.begin();iter!=_interceptors.end();iter++)
575 (*iter).first->put((*iter).second[branchId]->get());