Salome HOME
Before virtualization of SalomeContainerTools
[modules/yacs.git] / src / engine / PlayGround.cxx
1 // Copyright (C) 2006-2019  CEA/DEN, EDF R&D
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 "PlayGround.hxx"
21 #include "Runtime.hxx"
22
23 #include <set>
24 #include <map>
25 #include <sstream>
26 #include <iomanip>
27 #include <numeric>
28 #include <algorithm>
29
30 using namespace YACS::ENGINE;
31
32 std::size_t Resource::getNumberOfFreePlace(int nbCoresPerCont) const
33 {
34   std::size_t ret(0),pos(0);
35   while( pos < _occupied.size() )
36     {
37       bool isChunckFree(true);
38       int posInChunck(0);
39       for( ; ( posInChunck < nbCoresPerCont ) && ( pos < _occupied.size() ) ; ++posInChunck, ++pos)
40         if(_occupied[pos])
41           isChunckFree = false;
42       if( isChunckFree && (posInChunck == nbCoresPerCont) )
43         ret++;
44     }
45   return ret;
46 }
47
48 std::vector<std::size_t> Resource::allocateFor(std::size_t& nbOfPlacesToTake, int nbCoresPerCont) const
49 {
50   std::vector<std::size_t> ret;
51   std::size_t pos(0),curWorkerId(0);
52   while( ( pos < _occupied.size() ) && ( nbOfPlacesToTake > 0 ) )
53     {
54       bool isChunckFree(true);
55       int posInChunck(0);
56       for( ; ( posInChunck < nbCoresPerCont ) && ( pos < _occupied.size() ) ; ++posInChunck, ++pos)
57         if(_occupied[pos])
58           isChunckFree = false;
59       if( isChunckFree && (posInChunck == nbCoresPerCont) )
60         {
61           for(int i = 0 ; i < nbCoresPerCont ; ++i)
62             _occupied[pos-nbCoresPerCont+i] = true;
63           ret.push_back(curWorkerId);
64           --nbOfPlacesToTake;
65         }
66       ++curWorkerId;
67     }
68   return ret;
69 }
70
71 void Resource::release(std::size_t workerId, int nbCoresPerCont) const
72 {
73   if(workerId >= this->getNumberOfWorkers(nbCoresPerCont))
74     throw Exception("Resource::release : invalid worker id !");
75   std::size_t pos(workerId*static_cast<std::size_t>(nbCoresPerCont));
76   for(int i = 0 ; i < nbCoresPerCont ; ++i)
77     {
78       if(!_occupied[pos + static_cast<std::size_t>(i)])
79         throw Exception("Resource::release : internal error ! A core is expected to be occupied !");
80       _occupied[pos + static_cast<std::size_t>(i)] = false;
81     }
82 }
83
84 std::size_t Resource::getNumberOfWorkers(int nbCoresPerCont) const
85 {
86   return static_cast<std::size_t>(this->nbCores())/static_cast<std::size_t>(nbCoresPerCont);
87 }
88
89 std::string PlayGround::printSelf() const
90 {
91   std::ostringstream oss;
92   std::size_t sz(0);
93   for(auto it : _data)
94     sz=std::max(sz,it.name().length());
95   for(auto it : _data)
96     {
97       oss << " - " << std::setw(10) << it.name() << " : " << it.nbCores() << std::endl;
98     }
99   return oss.str();
100 }
101
102 void PlayGround::loadFromKernelCatalog()
103 {
104   Runtime *r(getRuntime());
105   if(!r)
106     throw Exception("PlayGround::loadFromKernelCatalog : no runtime  !");
107   std::vector< std::pair<std::string,int> > data(r->getCatalogOfComputeNodes());
108   setData(data);
109 }
110
111 void PlayGround::setData(const std::vector< std::pair<std::string,int> >& defOfRes)
112 {
113   _data=std::vector<Resource>(defOfRes.begin(),defOfRes.end());
114   checkCoherentInfo();
115 }
116
117 int PlayGround::getNumberOfCoresAvailable() const
118 {
119   int ret(0);
120   for(auto it : _data)
121     ret+=it.nbCores();
122   return ret;
123 }
124
125 int PlayGround::getMaxNumberOfContainersCanBeHostedWithoutOverlap(int nbCoresPerCont) const
126 {
127   if(nbCoresPerCont<1)
128     throw Exception("PlayGround::getMaxNumberOfContainersCanBeHostedWithoutOverlap : invalid nbCoresPerCont. Must be >=1 !");
129   int ret(0);
130   for(auto it : _data)
131     ret+=it.nbCores()/nbCoresPerCont;
132   return ret;
133 }
134
135 std::vector<int> PlayGround::computeOffsets() const
136 {
137   std::size_t sz(_data.size()),i(0);
138   std::vector<int> ret(sz+1); ret[0]=0;
139   for(auto it=_data.begin();it!=_data.end();it++,i++)
140     ret[i+1]=ret[i]+it->nbCores();
141   return ret;
142 }
143
144 void PlayGround::checkCoherentInfo() const
145 {
146   std::set<std::string> s;
147   for(auto it : _data)
148     {
149       s.insert(it.name());
150       if(it.nbCores()<0)
151         throw Exception("Presence of negative int value !");
152     }
153   if(s.size()!=_data.size())
154     throw Exception("host names entries must be different each other !");
155 }
156
157 std::vector<int> PlayGround::GetIdsMatching(const std::vector<bool>& bigArr, const std::vector<bool>& pat)
158 {
159   std::vector<int> ret;
160   std::size_t szp(pat.size());
161   std::size_t sz(bigArr.size()/szp);
162   for(std::size_t i=0;i<sz;i++)
163     {
164       std::vector<bool> t(bigArr.begin()+i*szp,bigArr.begin()+(i+1)*szp);
165       if(t==pat)
166         ret.push_back(i);
167     }
168   return ret;
169 }
170
171 std::size_t PlayGround::getNumberOfFreePlace(int nbCoresPerCont) const
172 {
173   std::size_t ret(0);
174   for(auto res : _data)
175     {
176       ret += res.getNumberOfFreePlace(nbCoresPerCont);
177     }
178   return ret;
179 }
180
181 std::vector<std::size_t> PlayGround::allocateFor(std::size_t nbOfPlacesToTake, int nbCoresPerCont) const
182 {
183   std::vector<std::size_t> ret;
184   std::size_t nbOfPlacesToTakeCpy(nbOfPlacesToTake),offset(0);
185   for(auto res : _data)
186     {
187       std::vector<std::size_t> contIdsInRes(res.allocateFor(nbOfPlacesToTakeCpy,nbCoresPerCont));
188       std::for_each(contIdsInRes.begin(),contIdsInRes.end(),[offset](std::size_t& val) { val += offset; });
189       ret.insert(ret.end(),contIdsInRes.begin(),contIdsInRes.end());
190       offset += static_cast<std::size_t>(res.nbCores()/nbCoresPerCont);
191     }
192   if( ( nbOfPlacesToTakeCpy!=0 ) || ( ret.size()!=nbOfPlacesToTake ) )
193     throw Exception("PlayGround::allocateFor : internal error ! Promised place is not existing !");
194   return ret;
195 }
196
197 void PlayGround::release(std::size_t workerId, int nbCoresPerCont) const
198 {
199   std::size_t offset(0);
200   for(auto res : _data)
201     {
202       std::size_t nbOfWorker(static_cast<std::size_t>(res.nbCores()/nbCoresPerCont));
203       std::size_t minId(offset),maxId(offset+nbOfWorker);
204       if(workerId>=minId && workerId<maxId)
205         {
206           res.release(workerId-minId,nbCoresPerCont);
207           break;
208         }
209     }
210 }
211
212 std::vector<int> PlayGround::BuildVectOfIdsFromVecBool(const std::vector<bool>& v)
213 {
214   std::size_t sz(std::count(v.begin(),v.end(),true)),i(0);
215   std::vector<int> ret(sz);
216   std::vector<bool>::const_iterator it(v.begin());
217   while(i<sz)
218     {
219       it=std::find(it,v.end(),true);
220       ret[i++]=std::distance(v.begin(),it);
221       it++;
222     }
223   return ret;
224 }
225
226 void PlayGround::highlightOnIds(const std::vector<int>& coreIds, std::vector<bool>& v) const
227 {
228   if(v.size()!=getNumberOfCoresAvailable())
229     throw Exception("PlayGround::highlightOnIds : oops ! invalid size !");
230   for(std::vector<int>::const_iterator it=coreIds.begin();it!=coreIds.end();it++)
231     v[*it]=true;
232 }
233
234 /*! 
235  * you must garantee coherence between PlayGround::deduceMachineFrom, PlayGround::getNumberOfWorkers, and PartDefinition::computeWorkerIdsCovered
236  */
237 // std::vector<bool> PlayGround::getFetchedCores(int nbCoresPerWorker) const
238 // {
239 //   int nbCores(getNumberOfCoresAvailable());
240 //   std::vector<bool> ret(nbCores,false);
241 //   if(nbCoresPerWorker==1)
242 //     std::fill(ret.begin(),ret.end(),true);
243 //   else
244 //     {
245 //       std::size_t posBg(0);
246 //       for(std::vector< std::pair<std::string,int> >::const_iterator it=_data.begin();it!=_data.end();it++)
247 //         {
248 //           int nbElemsToPutOn(((*it).second/nbCoresPerWorker)*nbCoresPerWorker);
249 //           std::fill(ret.begin()+posBg,ret.begin()+posBg+nbElemsToPutOn,true);
250 //           posBg+=(*it).second;
251 //         }
252 //     }
253 //   return ret;
254 //}
255 /*!
256  * follow getMaxNumberOfContainersCanBeHostedWithoutOverlap method
257  */
258 std::vector<std::size_t> PlayGround::getWorkerIdsFullyFetchedBy(int nbCoresPerComp, const std::vector<bool>& coreFlags) const
259 {
260   std::size_t posBg(0),posWorker(0);
261   std::vector<std::size_t> ret;
262   for(auto it : _data)
263     {
264       int nbWorker(it.nbCores()/nbCoresPerComp);
265       for(int j=0;j<nbWorker;j++,posWorker++)
266         {
267           std::vector<bool>::const_iterator it2(std::find(coreFlags.begin()+posBg+j*nbCoresPerComp,coreFlags.begin()+posBg+(j+1)*nbCoresPerComp,false));
268           if(it2==coreFlags.begin()+posBg+(j+1)*nbCoresPerComp)
269             ret.push_back(posWorker);
270         }
271       posBg+=it.nbCores();
272     }
273   return ret;
274 }
275
276 std::vector< YACS::BASES::AutoRefCnt<PartDefinition> > PlayGround::partition(const std::vector< std::pair<const PartDefinition *, const ComplexWeight *> >& parts, const std::vector< int>& nbCoresPerShot) const
277 {
278   std::size_t sz(parts.size()),szs(getNumberOfCoresAvailable());
279   if (sz!=nbCoresPerShot.size())
280     throw Exception("PlayGround::partition : incoherent vector size !");
281   if(sz==0)
282     return std::vector< YACS::BASES::AutoRefCnt<PartDefinition> >();
283   if(sz==1)
284     {
285       const PartDefinition *pd(parts[0].first);
286       if(!pd)
287         throw Exception("Presence of null pointer as part def  0 !");
288       YACS::BASES::AutoRefCnt<PartDefinition> ret(pd->copy());
289       std::vector< YACS::BASES::AutoRefCnt<PartDefinition> > ret2(1,ret);
290       return ret2;
291     }
292   if(sz>31)
293     throw Exception("PlayGround::partition : not implemented yet for more than 31 ! You need to pay for it :)");
294   std::vector<bool> zeArr(szs*sz,false);
295   std::size_t i(0);
296   for(std::vector< std::pair<const PartDefinition *, const ComplexWeight *> >::const_iterator it=parts.begin();it!=parts.end();it++,i++)
297     {
298       const PartDefinition *pd((*it).first);
299       if(!pd)
300         throw Exception("Presence of null pointer as part def !");
301       if(pd->getPlayGround()!=this)
302         throw Exception("Presence of non homogeneous playground !");
303       std::vector<bool> bs(pd->getCoresOn()); // tab of length nbCores, with True or False for each Core
304       for(std::size_t j=0;j<szs;j++)
305         zeArr[j*sz+i]=bs[j]; // remplis une table avec les valeurs de bs. La table est [nb part] * [nb cores]
306     }
307   std::vector< std::vector<int> > retIds(sz);
308   for(std::size_t i=0;i<szs;i++)
309     {
310       std::vector<bool> code(zeArr.begin()+i*sz,zeArr.begin()+(i+1)*sz);// vecteur contenant le true/false d'un coeur pour ttes les partitions
311       std::vector<int> locIds(GetIdsMatching(zeArr,code)); // liste des coeurs qui peuvent correspondre au pattern code
312       std::vector<int> partsIds(BuildVectOfIdsFromVecBool(code));// pour chaque partition retourne l'id de la premiere partition Ã  true
313       if(partsIds.empty())
314         continue;
315       std::vector<std::pair <const ComplexWeight *, int> > wg;
316       for(std::vector<int>::const_iterator it=partsIds.begin();it!=partsIds.end();it++)
317         {
318           wg.push_back(std::pair <const ComplexWeight *, int> (parts[*it].second, nbCoresPerShot[*it]));
319         }
320       std::vector< std::vector<int> > ress(splitIntoParts(locIds,wg));
321       std::size_t k(0);
322       for(std::vector<int>::const_iterator it=partsIds.begin();it!=partsIds.end();it++,k++)
323         {
324           retIds[*it].insert(retIds[*it].end(),ress[k].begin(),ress[k].end());
325         }
326     }
327   //
328   std::vector< YACS::BASES::AutoRefCnt<PartDefinition> > ret(sz);
329   for(std::size_t i=0;i<sz;i++)
330     {
331       std::set<int> s(retIds[i].begin(),retIds[i].end());
332       std::vector<int> v(s.begin(),s.end());
333       ret[i]=PartDefinition::BuildFrom(this,v);
334     }
335   return ret;
336 }
337
338 std::vector< std::vector<int> > PlayGround::splitIntoParts(const std::vector<int>& coreIds, const std::vector< std::pair <const ComplexWeight *, int> >& weights) const
339 {
340   std::size_t sz(weights.size());
341   if(sz==0)
342     return std::vector< std::vector<int> >();
343   std::vector< std::vector<int> > ret;
344   std::vector< std::vector<int> > disorderRet(sz);
345   std::vector<bool> zeArr(getNumberOfCoresAvailable(),false);
346   highlightOnIds(coreIds,zeArr);
347   int nbOfCoresToSplit(coreIds.size());
348   int totalSpace(coreIds.size());
349   int remainingSpace(totalSpace);
350   std::vector<int> nbOfCoresAllocated(sz);
351   std::vector<int> nbCoresPerShot(sz,-1);  
352   // first every other branchs take its minimal part of the cake
353   // and remove branch without valid weight
354   int i(0);
355   std::map<int,int> saveOrder;
356   const std::vector< std::pair <const ComplexWeight *, int> > sortedWeights(bigToTiny(weights, saveOrder));
357   for(std::vector<std::pair <const ComplexWeight *, int> >::const_iterator it=sortedWeights.begin();it!=sortedWeights.end();it++,i++)
358     {
359       nbCoresPerShot[i]=(*it).second;
360       if ((*it).first->isUnsetLoopWeight())
361         {
362           nbOfCoresAllocated[i]=nbCoresPerShot[i]; // branch with only elementary nodes
363         }
364       else if (!(*it).first->hasValidLoopWeight())
365         {
366           nbOfCoresAllocated[i]=std::max((int)((double)totalSpace/(double)(sz)), nbCoresPerShot[i]); // branch with undefined weight, takes his part proportionnally to the number of branchs
367         }
368       else
369         {
370           nbOfCoresAllocated[i]=nbCoresPerShot[i];
371         }
372     }
373   remainingSpace-=std::accumulate(nbOfCoresAllocated.begin(), nbOfCoresAllocated.end(), 0);
374   //get critical path (between path with loopWeight)
375   int criticalPathRank=getCriticalPath(sortedWeights, nbOfCoresAllocated);
376   if (criticalPathRank!=-1)
377     {
378       // add cores to critical path while enough cores are availables
379           while (remainingSpace >= nbCoresPerShot[criticalPathRank])
380             {
381               nbOfCoresAllocated[criticalPathRank]+=nbCoresPerShot[criticalPathRank];
382               remainingSpace-=nbCoresPerShot[criticalPathRank];
383               criticalPathRank=getCriticalPath(sortedWeights, nbOfCoresAllocated);
384             }
385           //fill other paths with remaining cores (if possible) (reuse fromBigToTiny here?)
386           // and takePlace
387           int coresToAdd;
388           int j(0);
389           for(std::vector<int>::iterator it=nbOfCoresAllocated.begin();it!=nbOfCoresAllocated.end();it++,j++)
390             {
391               coresToAdd=((int)(remainingSpace/nbCoresPerShot[j]))*nbCoresPerShot[j];
392               *it+=coresToAdd;
393               remainingSpace-=coresToAdd;
394             }
395     }
396   int k(0);
397   for(std::vector<int>::iterator it=nbOfCoresAllocated.begin();it!=nbOfCoresAllocated.end();it++,k++)
398     {
399       disorderRet[k]=takePlace(*it,nbCoresPerShot[k],zeArr,k==(sz-1));
400     }   
401   ret=backToOriginalOrder(disorderRet, saveOrder);
402   return ret;
403 }
404
405 std::vector< std::pair <const ComplexWeight *, int> > PlayGround::bigToTiny(const std::vector< std::pair <const ComplexWeight *, int> > &weights, std::map<int,int> &saveOrder) const
406 {
407   int maxCoresPerShot(0), rankMax(0);
408   int i(0);
409   std::vector< std::pair <const ComplexWeight *, int> > ret;
410   std::size_t sz(weights.size());
411   while (ret.size()<sz)
412     {
413       for(std::vector<std::pair <const ComplexWeight *, int> >::const_iterator it=weights.begin();it!=weights.end();it++,i++)
414         {
415           if ((maxCoresPerShot<(*it).second) && (saveOrder.find(i)==saveOrder.end()))
416             {
417               maxCoresPerShot=(*it).second;
418               rankMax=i;
419             }
420         }
421       ret.push_back(std::pair <const ComplexWeight *, int>(weights[rankMax].first,weights[rankMax].second));
422       saveOrder[rankMax]=ret.size()-1;
423       maxCoresPerShot=0;
424       i=0;
425     }
426   return ret;   
427 }
428
429 std::vector< std::vector<int> > PlayGround::backToOriginalOrder(const std::vector< std::vector<int> > &disorderVec, const std::map<int,int> &saveOrder) const
430 {
431   std::vector< std::vector<int> > ret;
432   std::size_t sz(disorderVec.size());
433   if (disorderVec.size()!=saveOrder.size())
434     throw Exception("PlayGround::backToOriginalOrder : incoherent vector size !");
435   for (int i=0; i<sz; i++)
436       ret.push_back(disorderVec[saveOrder.at(i)]);
437   return ret;
438 }
439
440 int PlayGround::getCriticalPath(const std::vector<std::pair <const ComplexWeight *, int > >& weights, const std::vector<int>& nbOfCoresAllocated) const
441 {
442   double maxWeight(0.);
443   double pathWeight(0.);
444   int rankMaxPath(-1);
445   if ((weights.size()!=nbOfCoresAllocated.size()) || (weights.size()==0))
446     throw Exception("PlayGround::getCriticalPath : internal error !");
447   int i=0;
448   for(std::vector<std::pair <const ComplexWeight *, int> >::const_iterator it=weights.begin();it!=weights.end();it++,i++)
449     {
450       if (nbOfCoresAllocated[i]==0)
451         throw Exception("PlayGround::getCriticalPath : nbOfCoresAllocated is null! error !");
452       if (!(*it).first->isDefaultValue())
453         {
454               pathWeight=(*it).first->calculateTotalLength(nbOfCoresAllocated[i]);
455               if (pathWeight > maxWeight)
456                 {
457                   maxWeight=pathWeight;
458                   rankMaxPath=i;
459                 }
460         }         
461     }
462   return rankMaxPath;
463
464
465 std::vector<int> PlayGround::takePlace(int maxNbOfCoresToAlloc, int nbCoresPerShot, std::vector<bool>& distributionOfCores, bool lastOne) const
466 {
467   if(maxNbOfCoresToAlloc<1)
468     throw Exception("PlayGround::takePlace : internal error ! no space to alloc !");
469   int tmpMaxNbOfCoresToAlloc(maxNbOfCoresToAlloc);
470   if(lastOne)
471     tmpMaxNbOfCoresToAlloc=std::max(tmpMaxNbOfCoresToAlloc,(int)std::count(distributionOfCores.begin(),distributionOfCores.end(),true));
472   std::vector<int> ret;
473   std::vector<int> offsets(computeOffsets());
474   int nbFullItem(0);
475   std::size_t sz(offsets.size()-1);
476   for(std::size_t i=0;i<sz && tmpMaxNbOfCoresToAlloc>=nbCoresPerShot;i++)
477     {
478       int d(offsets[i+1]-offsets[i]);
479       if(nbCoresPerShot>d)
480         continue;
481       std::vector<bool> target(nbCoresPerShot,true);
482       for(int j=0;j<=d-nbCoresPerShot && tmpMaxNbOfCoresToAlloc>=nbCoresPerShot;)
483         {
484           std::vector<bool> t(distributionOfCores.begin()+offsets[i]+j,distributionOfCores.begin()+offsets[i]+j+nbCoresPerShot);
485           if(t==target)
486             {
487               nbFullItem++;
488               tmpMaxNbOfCoresToAlloc-=nbCoresPerShot;
489               std::fill(distributionOfCores.begin()+offsets[i]+j,distributionOfCores.begin()+offsets[i]+j+nbCoresPerShot,false);
490               for(int k=offsets[i]+j;k<offsets[i]+j+nbCoresPerShot;k++)
491                 ret.push_back(k);
492               j+=nbCoresPerShot;
493             }
494           else
495             j++;
496         }
497     }
498   if(nbFullItem>0)
499     return ret;
500   if(nbCoresPerShot<=1)
501     throw Exception("PlayGround::takePlace : internal error !");
502   // not enough contiguous place. Find the first wider contiguous place
503   for(int kk=std::min(nbCoresPerShot-1,tmpMaxNbOfCoresToAlloc);kk>=1;kk--)
504     {
505       for(std::size_t i=0;i<sz && tmpMaxNbOfCoresToAlloc>=kk;i++)
506         {
507           int d(offsets[i+1]-offsets[i]);
508           if(kk>d)
509             continue;
510           std::vector<bool> target(kk,true);
511           for(int j=0;j<=d-kk && tmpMaxNbOfCoresToAlloc>=kk;)
512             {
513               std::vector<bool> t(distributionOfCores.begin()+offsets[i]+j,distributionOfCores.begin()+offsets[i]+j+kk);
514               if(t==target)
515                 {
516                   nbFullItem++;
517                   tmpMaxNbOfCoresToAlloc-=kk;
518                   std::fill(distributionOfCores.begin()+offsets[i]+j,distributionOfCores.begin()+offsets[i]+j+kk,false);
519                   for(int k=offsets[i]+j;k<offsets[i]+j+kk;k++)
520                     ret.push_back(k);
521                   return ret;
522                 }
523               else
524                 j++;
525             }
526         }
527     }
528   throw Exception("PlayGround::takePlace : internal error ! All cores are occupied !");
529 }
530
531 int PlayGround::fromWorkerIdToResId(int workerId, int nbProcPerNode) const
532 {
533   std::size_t sz2(_data.size());
534   std::vector<int> deltas(sz2+1); deltas[0]=0;
535   for(std::size_t i=0;i<sz2;i++)
536     deltas[i+1]=deltas[i]+(_data[i].nbCores())/nbProcPerNode;
537   int zePos(0);
538   while(zePos<sz2 && (workerId<deltas[zePos] || workerId>=deltas[zePos+1]))
539     zePos++;
540   if(zePos==sz2)
541     zePos=workerId%sz2;
542   return zePos;
543 }
544
545 /*! 
546  * you must garantee coherence between PlayGround::deduceMachineFrom, PlayGround::getNumberOfWorkers, and PartDefinition::computeWorkerIdsCovered
547  */
548 std::string PlayGround::deduceMachineFrom(int workerId, int nbProcPerNode) const
549 {
550   int zePos(fromWorkerIdToResId(workerId,nbProcPerNode));
551   return _data[zePos].name();
552 }
553
554 /*! 
555  * you must garantee coherence between PlayGround::deduceMachineFrom, PlayGround::getNumberOfWorkers, PlayGround::getFetchedCores and PartDefinition::computeWorkerIdsCovered
556  */
557 int PlayGround::getNumberOfWorkers(int nbCoresPerWorker) const
558 {
559   return getMaxNumberOfContainersCanBeHostedWithoutOverlap(nbCoresPerWorker);
560 }
561
562 PlayGround::~PlayGround()
563 {
564 }
565
566 //////////////////////
567
568 PartDefinition::PartDefinition(const PlayGround *pg)
569 {
570   _pg.takeRef(pg);
571 }
572
573 PartDefinition::PartDefinition(const PartDefinition& other):_pg(other._pg)
574 {
575 }
576
577 PartDefinition::~PartDefinition()
578 {
579 }
580
581 // std::vector< YACS::BASES::AutoRefCnt<PartDefinition> > PartDefinition::partition(const std::vector< const ComplexWeight *>& wgs) const
582 // {
583 //   std::size_t sz(wgs.size());
584 //   std::vector< std::pair<const PartDefinition *, const ComplexWeight *> > elts(sz);
585 //   for(std::size_t i=0;i<sz;i++)
586 //     elts[i]=std::pair<const PartDefinition *, const ComplexWeight *>(this,wgs[i]);
587 //   return getPlayGround()->partition(elts);
588 // }
589
590 YACS::BASES::AutoRefCnt<PartDefinition> PartDefinition::BuildFrom(const PlayGround *pg, const std::vector<int>& coreIds)
591 {
592   int spaceSz(pg->getNumberOfCoresAvailable()),sz(coreIds.size());
593   if(sz>spaceSz)
594     throw Exception("PartDefinition::BuildFrom : error 1 !");
595   if(sz==0)
596     throw Exception("PartDefinition::BuildFrom : error 2 !");
597   int zeStart(coreIds.front()),zeEnd(coreIds.back());
598   if(zeStart<0 || zeEnd<zeStart)
599     throw Exception("PartDefinition::BuildFrom : error ! The content of core Ids is not OK !");
600   for(std::size_t i=0;i<sz-1;i++)
601     if(coreIds[i+1]<coreIds[i])
602       throw Exception("PartDefinition::BuildFrom : error ! The content of core Ids is not OK 2 !");
603   if(zeEnd-zeStart+1!=sz)
604     {
605       YACS::BASES::AutoRefCnt<PartDefinition> pd(new NonContigPartDefinition(pg,coreIds));
606       return pd;
607     }
608   if(sz==spaceSz)
609     {
610       YACS::BASES::AutoRefCnt<PartDefinition> pd(new AllPartDefinition(pg));
611       return pd;
612     }
613   YACS::BASES::AutoRefCnt<PartDefinition> pd(new ContigPartDefinition(pg,zeStart,zeEnd+1));
614   return pd;
615 }
616
617 void PartDefinition::stashPart(int nbCoresStashed, double weightOfRemain, YACS::BASES::AutoRefCnt<PartDefinition>& pdStashed, YACS::BASES::AutoRefCnt<PartDefinition>& pdRemain) const
618 {
619   if(nbCoresStashed<=0)
620     throw Exception("stashPart : Invalid nbCoresStashed value !");
621   if(weightOfRemain<=0.)
622     throw Exception("stashPart : Invalid weight !");
623   std::vector<bool> coresOn(getCoresOn());
624   int nbCoresAvailable(std::count(coresOn.begin(),coresOn.end(),true));
625   std::vector<int> ids(PlayGround::BuildVectOfIdsFromVecBool(coresOn));
626   if(nbCoresAvailable==0)
627     throw Exception("PartDefinition::stashPart : no available cores !");
628   if(nbCoresAvailable<=nbCoresStashed)
629     {
630       int n0((int)(1./(1.+weightOfRemain)*nbCoresAvailable)); n0=std::max(n0,1);
631       int n1(nbCoresAvailable-n0);
632       if(n1<=0)
633         {
634           pdStashed=PartDefinition::BuildFrom(getPlayGround(),ids);
635           pdRemain=PartDefinition::BuildFrom(getPlayGround(),ids);
636         }
637       else
638         {
639           std::vector<int> ids0(ids.begin(),ids.begin()+n0),ids1(ids.begin()+n0,ids.end());
640           pdStashed=PartDefinition::BuildFrom(getPlayGround(),ids0);
641           pdRemain=PartDefinition::BuildFrom(getPlayGround(),ids1);
642         }
643     }
644   else
645     {
646       std::vector<int> ids0(ids.begin(),ids.begin()+nbCoresStashed),ids1(ids.begin()+nbCoresStashed,ids.end());
647       pdStashed=PartDefinition::BuildFrom(getPlayGround(),ids0);
648       pdRemain=PartDefinition::BuildFrom(getPlayGround(),ids1);
649     }
650 }
651
652 /*! 
653  * you must garantee coherence between PlayGround::deduceMachineFrom, PlayGround::getNumberOfWorkers, and PartDefinition::computeWorkerIdsCovered
654  */
655 std::vector<std::size_t> PartDefinition::computeWorkerIdsCovered(int nbCoresPerComp) const
656 {
657   std::vector<bool> coresOn(getCoresOn());
658   return _pg->getWorkerIdsFullyFetchedBy(nbCoresPerComp,coresOn);
659 }
660
661 //////////////////////
662
663 ContigPartDefinition::ContigPartDefinition(const PlayGround *pg, int zeStart, int zeStop):PartDefinition(pg),_start(zeStart),_stop(zeStop)
664 {
665   if(_start<0 || _stop<_start || _stop>getSpaceSize())
666     throw Exception("ContigPartDefinition constructor : Invalid input values");
667 }
668
669 ContigPartDefinition::ContigPartDefinition(const ContigPartDefinition& other):PartDefinition(other),_start(other._start),_stop(other._stop)
670 {
671 }
672
673 std::string ContigPartDefinition::printSelf() const
674 {
675   std::ostringstream oss;
676   oss << "Contiguous : start=" << _start << " stop=" << _stop;
677   return oss.str();
678 }
679
680 std::vector<bool> ContigPartDefinition::getCoresOn() const
681 {
682   std::vector<bool> ret(getSpaceSize(),false);
683   for(int i=_start;i<_stop;i++)
684     ret[i]=true;
685   return ret;
686 }
687
688 ContigPartDefinition *ContigPartDefinition::copy() const
689 {
690   return new ContigPartDefinition(*this);
691 }
692
693 int ContigPartDefinition::getNumberOfCoresConsumed() const
694 {
695   return _stop-_start;
696 }
697
698 //////////////////////
699
700 NonContigPartDefinition::NonContigPartDefinition(const PlayGround *pg, const std::vector<int>& ids):PartDefinition(pg),_ids(ids)
701 {
702   checkOKIds();
703 }
704
705 NonContigPartDefinition::NonContigPartDefinition(const ContigPartDefinition& other):PartDefinition(other)
706 {
707 }
708
709 std::string NonContigPartDefinition::printSelf() const
710 {
711   std::ostringstream oss;
712   oss << "Non contiguous : ";
713   for(std::vector<int>::const_iterator it=_ids.begin();it!=_ids.end();it++)
714     oss << *it << ", ";
715   return oss.str();
716 }
717
718 std::vector<bool> NonContigPartDefinition::getCoresOn() const
719 {
720   std::vector<bool> ret(getSpaceSize(),false);
721   for(std::vector<int>::const_iterator it=_ids.begin();it!=_ids.end();it++)
722     ret[*it]=true;
723   return ret;
724 }
725
726 NonContigPartDefinition *NonContigPartDefinition::copy() const
727 {
728   return new NonContigPartDefinition(*this);
729 }
730
731 int NonContigPartDefinition::getNumberOfCoresConsumed() const
732 {
733   return _ids.size();
734 }
735
736 void NonContigPartDefinition::checkOKIds() const
737 {
738   int maxVal(getSpaceSize());
739   if(_ids.empty())
740     return;
741   int val(_ids.front());
742   if(val<0 || val>=maxVal)
743     throw Exception("checkOKIds : error 2 !");
744   std::size_t sz(_ids.size());
745   for(std::size_t i=0;i<sz-1;i++)
746     {
747       if(_ids[i+1]<=_ids[i])
748         throw Exception("checkOKIds : error 1 !");
749       if(_ids[i+1]>=maxVal)
750         throw Exception("checkOKIds : error 3 !");
751     }
752 }
753
754 //////////////////////
755
756 AllPartDefinition::AllPartDefinition(const AllPartDefinition& other):PartDefinition(other)
757 {
758 }
759
760 std::string AllPartDefinition::printSelf() const
761 {
762   std::ostringstream oss;
763   oss << "All";
764   return oss.str();
765 }
766
767 std::vector<bool> AllPartDefinition::getCoresOn() const
768 {
769   std::vector<bool> ret(getSpaceSize(),true);
770   return ret;
771 }
772
773 AllPartDefinition *AllPartDefinition::copy() const
774 {
775   return new AllPartDefinition(*this);
776 }
777
778 int AllPartDefinition::getNumberOfCoresConsumed() const
779 {
780   return getSpaceSize();
781 }
782
783 //////////////////////
784  
785  std::vector<int> ForTestOmlyHPContCls::getIDS() const
786  {
787    std::size_t sz(_ids.size());
788    std::vector<int> ret(sz);
789    for(std::size_t i=0;i<sz;i++)
790      ret[i]=_ids[i];
791    return ret;
792  }