]> SALOME platform Git repositories - modules/yacs.git/blob - src/workloadmanager/DefaultAlgorithm.cxx
Salome HOME
Work in progress : workload manager uses nb_parallel_procs.
[modules/yacs.git] / src / workloadmanager / DefaultAlgorithm.cxx
1 // Copyright (C) 2020  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 #include "DefaultAlgorithm.hxx"
20 #include "Task.hxx"
21 #include <stdexcept>
22 #include <limits>
23 #include <algorithm>
24
25 namespace WorkloadManager
26 {
27 void DefaultAlgorithm::addTask(Task* t)
28 {
29   // put the tasks which need more cores in front.
30   float newNeedCores = t->type().neededCores;
31   if(_waitingTasks.empty())
32     _waitingTasks.push_back(t);
33   else if(_waitingTasks.back()->type().neededCores >= newNeedCores)
34     _waitingTasks.push_back(t);
35   else
36   {
37     std::list<Task*>::iterator it = _waitingTasks.begin();
38     while(it != _waitingTasks.end() && (*it)->type().neededCores >= newNeedCores)
39       it++;
40     _waitingTasks.insert(it, t);
41   }
42 }
43
44 bool DefaultAlgorithm::empty()const
45 {
46   return _waitingTasks.empty();
47 }
48
49 void DefaultAlgorithm::addResource(const Resource& r)
50 {
51   _resources.emplace_back(r);
52 }
53
54 WorkloadAlgorithm::LaunchInfo DefaultAlgorithm::chooseTask()
55 {
56   LaunchInfo result;
57   std::list<Task*>::iterator chosenTaskIt;
58   for( std::list<Task*>::iterator itTask = _waitingTasks.begin();
59       !result.taskFound && itTask != _waitingTasks.end();
60       itTask ++)
61   {
62     const ContainerType& ctype = (*itTask)->type();
63     if(ctype.ignoreResources)
64       result.taskFound = true;
65     else
66     {
67       std::list<ResourceLoadInfo>::iterator best_resource;
68       best_resource = _resources.end();
69       float best_cost = std::numeric_limits<float>::max();
70       bool isSupported = false;
71       for(auto itResource = _resources.begin();
72           itResource != _resources.end();
73           itResource++)
74         if(itResource->isSupported(ctype)
75             && (*itTask)->isAccepted(itResource->resource()))
76         {
77           if(itResource->isAllocPossible(ctype))
78           {
79             float thisCost = itResource->cost(ctype);
80             if( best_cost > thisCost)
81             {
82               best_cost = thisCost;
83               best_resource = itResource;
84             }
85           }
86         }
87       if(best_resource != _resources.end())
88       {
89         result.taskFound = true;
90         result.worker.resource = best_resource->resource();
91         result.worker.index = best_resource->alloc(ctype);
92       }
93       else if(!isSupported)
94       {
95         // TODO: This task can never be run by any available resource.
96       }
97     }
98     if(result.taskFound)
99     {
100       chosenTaskIt = itTask;
101       result.task = (*itTask);
102       result.worker.type = ctype;
103     }
104   }
105   if(result.taskFound)
106     _waitingTasks.erase(chosenTaskIt);
107   return result;
108 }
109
110 void DefaultAlgorithm::liberate(const LaunchInfo& info)
111 {
112   const ContainerType& ctype = info.worker.type;
113   if(!ctype.ignoreResources)
114   {
115     const Resource& r = info.worker.resource;
116     unsigned int index = info.worker.index;
117     std::list<ResourceLoadInfo>::iterator it = std::find(_resources.begin(),
118                                                         _resources.end(),
119                                                         r);
120     it->free(ctype, index); // we are sure to find it
121   }
122 }
123
124 // ResourceInfoForContainer
125
126 DefaultAlgorithm::ResourceInfoForContainer::ResourceInfoForContainer
127                                 (const Resource& r, const ContainerType& ctype)
128 : _ctype(ctype)
129 , _resource(r)
130 , _runningContainers()
131 , _firstFreeContainer(0)
132 {
133 }
134
135 unsigned int DefaultAlgorithm::ResourceInfoForContainer::maxContainers()const
136 {
137   return float(_resource.nbCores) / _ctype.neededCores;
138 }
139
140 unsigned int  DefaultAlgorithm::ResourceInfoForContainer::alloc()
141 {
142   unsigned int result = _firstFreeContainer;
143   _runningContainers.insert(result);
144   _firstFreeContainer++;
145   while(isContainerRunning(_firstFreeContainer))
146     _firstFreeContainer++;
147   return result;
148 }
149
150 void DefaultAlgorithm::ResourceInfoForContainer::free(unsigned int index)
151 {
152   _runningContainers.erase(index);
153   if(index < _firstFreeContainer)
154     _firstFreeContainer = index;
155 }
156
157 unsigned int DefaultAlgorithm::ResourceInfoForContainer::nbRunningContainers()const
158 {
159   return _runningContainers.size();
160 }
161
162 bool DefaultAlgorithm::ResourceInfoForContainer::isContainerRunning
163                                 (unsigned int index)const
164 {
165   return _runningContainers.find(index)!=_runningContainers.end();
166 }
167
168 // ResourceLoadInfo
169
170 DefaultAlgorithm::ResourceLoadInfo::ResourceLoadInfo(const Resource& r)
171 : _resource(r)
172 , _load(0.0)
173 , _loadCost(0.0)
174 , _ctypes()
175 {
176 }
177
178 bool DefaultAlgorithm::ResourceLoadInfo::isSupported
179                                 (const ContainerType& ctype)const
180 {
181   return ctype.neededCores <= _resource.nbCores ;
182 }
183                                           
184 bool DefaultAlgorithm::ResourceLoadInfo::isAllocPossible
185                                 (const ContainerType& ctype)const
186 {
187   return ctype.neededCores + _load <= _resource.nbCores;
188 }
189
190 float DefaultAlgorithm::ResourceLoadInfo::cost
191                                 (const ContainerType& ctype)const
192 {
193   return _loadCost * 100.0 / float(_resource.nbCores);
194 }
195
196 unsigned int DefaultAlgorithm::ResourceLoadInfo::alloc
197                                 (const ContainerType& ctype)
198 {
199   std::list<ResourceInfoForContainer>::iterator it = std::find(_ctypes.begin(),
200                                                                _ctypes.end(),
201                                                                ctype);
202   // add the type if not found
203   if(it == _ctypes.end())
204   {
205     _ctypes.emplace_back(_resource, ctype);
206     it = _ctypes.end();
207     it--;
208   }
209   _load += ctype.neededCores;
210   if(ctype.neededCores == 0)
211     _loadCost += COST_FOR_0_CORE_TASKS;
212   else
213     _loadCost += ctype.neededCores;
214   return it->alloc();
215 }
216
217 void DefaultAlgorithm::ResourceLoadInfo::free
218                                 (const ContainerType& ctype, int index)
219 {
220   _load -= ctype.neededCores;
221   if(ctype.neededCores == 0)
222     _loadCost -= COST_FOR_0_CORE_TASKS;
223   else
224     _loadCost -= ctype.neededCores;
225   std::list<ResourceInfoForContainer>::iterator it = std::find(_ctypes.begin(),
226                                                                _ctypes.end(),
227                                                                ctype);
228   it->free(index);
229 }
230
231 }