-// 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);
}
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()
!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)
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()
unsigned int DefaultAlgorithm::ResourceInfoForContainer::maxContainers()const
{
- return float(_resource->nbCores) / _ctype->neededCores;
+ return float(_resource.nbCores) / _ctype.neededCores;
}
unsigned int DefaultAlgorithm::ResourceInfoForContainer::alloc()
// 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);
}
}