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