Salome HOME
Merge branch 'V9_7_BR'
[modules/yacs.git] / src / workloadmanager / DefaultAlgorithm.cxx
index d25d18f46d443c2df2d294ef0a866ddd804d1eeb..0c58ac17c600340d9de67ad2fb36004c859bdbe3 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2020  CEA/DEN, EDF R&D
+// Copyright (C) 2020-2021  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 #include "Task.hxx"
 #include <stdexcept>
 #include <limits>
+#include <algorithm>
 
 namespace WorkloadManager
 {
 void DefaultAlgorithm::addTask(Task* t)
 {
   // put the tasks which need more cores in front.
-  float newNeedCores = t->type()->neededCores;
+  float newNeedCores = t->type().neededCores;
   if(_waitingTasks.empty())
     _waitingTasks.push_back(t);
-  else if(_waitingTasks.back()->type()->neededCores >= newNeedCores)
+  else if(_waitingTasks.back()->type().neededCores >= newNeedCores)
     _waitingTasks.push_back(t);
   else
   {
     std::list<Task*>::iterator it = _waitingTasks.begin();
-    while(it != _waitingTasks.end() && (*it)->type()->neededCores >= newNeedCores)
+    while(it != _waitingTasks.end() && (*it)->type().neededCores >= newNeedCores)
       it++;
     _waitingTasks.insert(it, t);
   }
@@ -45,13 +46,9 @@ bool DefaultAlgorithm::empty()const
   return _waitingTasks.empty();
 }
 
-void DefaultAlgorithm::addResource(Resource* r)
+void DefaultAlgorithm::addResource(const Resource& r)
 {
-  // add the resource. The operation is ignored if the resource already exists.
-  _resources.emplace(std::piecewise_construct,
-                     std::forward_as_tuple(r),
-                     std::forward_as_tuple(r)
-                    );
+  _resources.emplace_back(r);
 }
 
 WorkloadAlgorithm::LaunchInfo DefaultAlgorithm::chooseTask()
@@ -62,33 +59,51 @@ WorkloadAlgorithm::LaunchInfo DefaultAlgorithm::chooseTask()
       !result.taskFound && itTask != _waitingTasks.end();
       itTask ++)
   {
-    const ContainerType* ctype = (*itTask)->type();
-    std::map<const Resource *, ResourceLoadInfo>::iterator best_resource;
-    best_resource = _resources.end();
-    float best_cost = std::numeric_limits<float>::max();
-    for(auto itResource = _resources.begin();
-        itResource != _resources.end();
-        itResource++)
-      if(itResource->second.isSupported(ctype))
-      {
-        if(itResource->second.isAllocPossible(ctype))
+    const ContainerType& ctype = (*itTask)->type();
+    if(ctype.ignoreResources)
+      result.taskFound = true;
+    else
+    {
+      std::list<ResourceLoadInfo>::iterator best_resource;
+      best_resource = _resources.end();
+      float best_cost = std::numeric_limits<float>::max();
+      bool isSupported = false;
+      for(auto itResource = _resources.begin();
+          itResource != _resources.end();
+          itResource++)
+        if(itResource->isSupported(ctype)
+            && (*itTask)->isAccepted(itResource->resource()))
         {
-          float thisCost = itResource->second.cost(ctype);
-          if( best_cost > thisCost)
+          isSupported = true;
+          if(itResource->isAllocPossible(ctype))
           {
-            best_cost = thisCost;
-            best_resource = itResource;
+            float thisCost = itResource->cost(ctype);
+            if( best_cost > thisCost)
+            {
+              best_cost = thisCost;
+              best_resource = itResource;
+            }
           }
         }
+      if(best_resource != _resources.end())
+      {
+        result.taskFound = true;
+        result.worker.resource = best_resource->resource();
+        result.worker.index = best_resource->alloc(ctype);
       }
-    if(best_resource != _resources.end())
+      else if(!isSupported && _resourcesFrozen)
+      {
+        // This task can never be run by any available resource.
+        result.taskFound = true;
+        result.worker.isOk = false;
+        result.worker.error_message = "No resource can run this task.";
+      }
+    }
+    if(result.taskFound)
     {
       chosenTaskIt = itTask;
       result.task = (*itTask);
-      result.taskFound = true;
-      result.worker.resource = best_resource->first;
       result.worker.type = ctype;
-      result.worker.index = best_resource->second.alloc(ctype);
     }
   }
   if(result.taskFound)
@@ -98,17 +113,22 @@ WorkloadAlgorithm::LaunchInfo DefaultAlgorithm::chooseTask()
 
 void DefaultAlgorithm::liberate(const LaunchInfo& info)
 {
-  const Resource* r = info.worker.resource;
-  unsigned int index = info.worker.index;
-  const ContainerType* ctype = info.worker.type;
-  std::map<const Resource* ,ResourceLoadInfo>::iterator it = _resources.find(r);
-  it->second.free(ctype, index);
+  const ContainerType& ctype = info.worker.type;
+  if(!ctype.ignoreResources && info.worker.isOk)
+  {
+    const Resource& r = info.worker.resource;
+    unsigned int index = info.worker.index;
+    std::list<ResourceLoadInfo>::iterator it = std::find(_resources.begin(),
+                                                        _resources.end(),
+                                                        r);
+    it->free(ctype, index); // we are sure to find it
+  }
 }
 
 // ResourceInfoForContainer
 
 DefaultAlgorithm::ResourceInfoForContainer::ResourceInfoForContainer
-                                (const Resource * r, const ContainerType* ctype)
+                                (const Resource& r, const ContainerType& ctype)
 : _ctype(ctype)
 , _resource(r)
 , _runningContainers()
@@ -118,7 +138,7 @@ DefaultAlgorithm::ResourceInfoForContainer::ResourceInfoForContainer
 
 unsigned int DefaultAlgorithm::ResourceInfoForContainer::maxContainers()const
 {
-  return float(_resource->nbCores) / _ctype->neededCores;
+  return float(_resource.nbCores) / _ctype.neededCores;
 }
 
 unsigned int  DefaultAlgorithm::ResourceInfoForContainer::alloc()
@@ -151,55 +171,65 @@ bool DefaultAlgorithm::ResourceInfoForContainer::isContainerRunning
 
 // ResourceLoadInfo
 
-DefaultAlgorithm::ResourceLoadInfo::ResourceLoadInfo(const Resource * r)
+DefaultAlgorithm::ResourceLoadInfo::ResourceLoadInfo(const Resource& r)
 : _resource(r)
 , _load(0.0)
+, _loadCost(0.0)
 , _ctypes()
 {
 }
 
 bool DefaultAlgorithm::ResourceLoadInfo::isSupported
-                                (const ContainerType* ctype)const
+                                (const ContainerType& ctype)const
 {
-  return ctype->neededCores <= _resource->nbCores ;
+  return ctype.neededCores <= _resource.nbCores ;
 }
-                                          
+
 bool DefaultAlgorithm::ResourceLoadInfo::isAllocPossible
-                                (const ContainerType* ctype)const
+                                (const ContainerType& ctype)const
 {
-  return ctype->neededCores + _load <= _resource->nbCores;
+  return ctype.neededCores + _load <= _resource.nbCores;
 }
 
 float DefaultAlgorithm::ResourceLoadInfo::cost
-                                (const ContainerType* ctype)const
+                                (const ContainerType& ctype)const
 {
-  return _load * 100.0 / float(_resource->nbCores);
+  return _loadCost * 100.0 / float(_resource.nbCores);
 }
 
 unsigned int DefaultAlgorithm::ResourceLoadInfo::alloc
-                                (const ContainerType* ctype)
+                                (const ContainerType& ctype)
 {
-  std::map<const ContainerType*, ResourceInfoForContainer>::iterator it;
-  it = _ctypes.find(ctype);
+  std::list<ResourceInfoForContainer>::iterator it = std::find(_ctypes.begin(),
+                                                               _ctypes.end(),
+                                                               ctype);
+  // add the type if not found
   if(it == _ctypes.end())
   {
-    // add the type if not found
-    it = _ctypes.emplace(std::piecewise_construct,
-                         std::forward_as_tuple(ctype),
-                         std::forward_as_tuple(_resource, ctype)
-                        ).first;
+    _ctypes.emplace_back(_resource, ctype);
+    it = _ctypes.end();
+    it--;
   }
-  _load += ctype->neededCores;
-  return it->second.alloc();
+  _load += ctype.neededCores;
+  if(ctype.neededCores == 0)
+    _loadCost += COST_FOR_0_CORE_TASKS;
+  else
+    _loadCost += ctype.neededCores;
+  return it->alloc();
 }
 
 void DefaultAlgorithm::ResourceLoadInfo::free
-                                (const ContainerType* ctype, int index)
+                                (const ContainerType& ctype, int index)
 {
-  _load -= ctype->neededCores;
-  std::map<const ContainerType*, ResourceInfoForContainer>::iterator it;
-  it = _ctypes.find(ctype);
-  it->second.free(index);
+  _load -= ctype.neededCores;
+  if(ctype.neededCores == 0)
+    _loadCost -= COST_FOR_0_CORE_TASKS;
+  else
+    _loadCost -= ctype.neededCores;
+  std::list<ResourceInfoForContainer>::iterator it = std::find(_ctypes.begin(),
+                                                               _ctypes.end(),
+                                                               ctype);
+  it->free(index);
 }
 
 }