Added lookahead scheduler.
Most scheduler now use estimated finish time instead of predicted execution time.
This commit is contained in:
@@ -113,6 +113,7 @@ protected:
|
|||||||
wepMap_t wepMap;
|
wepMap_t wepMap;
|
||||||
bool simulationMode;
|
bool simulationMode;
|
||||||
double cummulativePredictionTime = 0;
|
double cummulativePredictionTime = 0;
|
||||||
|
std::map<resource::ComputingResource*, std::vector<std::shared_ptr<SchedulingDecision>>> scheduledTasks;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Hook functions for AbstractScheduler functions below to allow customisation of common functionality
|
// Hook functions for AbstractScheduler functions below to allow customisation of common functionality
|
||||||
@@ -121,6 +122,8 @@ protected:
|
|||||||
virtual void _notifyWEPUpdate(WepMapEntry& wepe, std::set<wep::AtomicWepNode*> readyToExecute, std::unique_lock<std::mutex>& schedulerLock) {}
|
virtual void _notifyWEPUpdate(WepMapEntry& wepe, std::set<wep::AtomicWepNode*> readyToExecute, std::unique_lock<std::mutex>& schedulerLock) {}
|
||||||
virtual void _notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {}
|
virtual void _notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {}
|
||||||
|
|
||||||
|
virtual double _getResourceEstimatedAvailableTime(resource::ComputingResource* resource);
|
||||||
|
|
||||||
// Convenience functions for passing a scheduling decision to the execution layer.
|
// Convenience functions for passing a scheduling decision to the execution layer.
|
||||||
bool executeSchedulingDecision(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) noexcept;
|
bool executeSchedulingDecision(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) noexcept;
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,6 @@ protected:
|
|||||||
fastestExecutionTimes(new prediction::ExecutionTimeResult[resourceCount]) {}
|
fastestExecutionTimes(new prediction::ExecutionTimeResult[resourceCount]) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//std::map<wep::ActivityWepNode*, std::shared_ptr<OptimisticCostTableEntry>> optimisticCostTable;
|
|
||||||
|
|
||||||
std::set<wep::AtomicWepNode*> readySet;
|
std::set<wep::AtomicWepNode*> readySet;
|
||||||
|
|
||||||
void calcTaskRanks(wep::ActivityWepNode& node, std::vector<resource::ComputingResource*>& resources);
|
void calcTaskRanks(wep::ActivityWepNode& node, std::vector<resource::ComputingResource*>& resources);
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <wfr/scheduling/AbstractScheduler.h>
|
||||||
|
#include <wfr/prediction/PredictionManager.h>
|
||||||
|
#include <wfr/common/resource/Resource.h>
|
||||||
|
#include <wfr/common/resource/ResourceManager.h>
|
||||||
|
#include <wfr/common/types/WfrTypes.h>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include <queue>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <iostream>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
namespace wfr {
|
||||||
|
|
||||||
|
namespace wfs {
|
||||||
|
class AtomicActivityInstance;
|
||||||
|
}
|
||||||
|
namespace wep {
|
||||||
|
class AtomicWepNode;
|
||||||
|
class ActivityWepNode;
|
||||||
|
class AbstractWepNode;
|
||||||
|
}
|
||||||
|
namespace resource {
|
||||||
|
class ResourceManager;
|
||||||
|
}
|
||||||
|
namespace prediction {
|
||||||
|
class PredictionManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace wfr {
|
||||||
|
namespace scheduling {
|
||||||
|
|
||||||
|
|
||||||
|
class LookaheadScheduler: public scheduling::SchedulerBase {
|
||||||
|
protected:
|
||||||
|
resource::ResourceManager& resourceManager;
|
||||||
|
prediction::PredictionManager& predictionManager;
|
||||||
|
|
||||||
|
struct TaskRankEntry {
|
||||||
|
double rank = 0;
|
||||||
|
bool finalized = false;
|
||||||
|
|
||||||
|
wfs::AtomicActivityImplementation** fastestImplementations;
|
||||||
|
prediction::ExecutionTimeResult* fastestExecutionTimes;
|
||||||
|
double averageExecutionTime = 0.0;
|
||||||
|
|
||||||
|
TaskRankEntry(wfr_size_t resourceCount) : fastestImplementations(new wfs::AtomicActivityImplementation*[resourceCount]),
|
||||||
|
fastestExecutionTimes(new prediction::ExecutionTimeResult[resourceCount]) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::set<wep::AtomicWepNode*> readySet;
|
||||||
|
|
||||||
|
void calcTaskRanks(wep::ActivityWepNode& node, std::vector<resource::ComputingResource*>& resources);
|
||||||
|
|
||||||
|
void scheduleReadySet(WepMapEntry& wepe, std::vector<resource::ComputingResource*>& resources, std::unique_lock<std::mutex>& schedulerLock);
|
||||||
|
|
||||||
|
public:
|
||||||
|
LookaheadScheduler(resource::ResourceManager& resourceManager, prediction::PredictionManager& predictionManager)
|
||||||
|
: resourceManager(resourceManager), predictionManager(predictionManager) {}
|
||||||
|
|
||||||
|
~LookaheadScheduler() {}
|
||||||
|
|
||||||
|
virtual void _notifyWEPUpdate(SchedulerBase::WepMapEntry& wepe, std::set<wep::AtomicWepNode*> readyToExecute, std::unique_lock<std::mutex>& schedulerLock) override;
|
||||||
|
virtual void _notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) override;
|
||||||
|
virtual void _unregisterWEP(WepMapEntry& wepe, std::unique_lock<std::mutex>& schedulerLock) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace scheduling */
|
||||||
|
} /* namespace wfr */
|
||||||
|
|
||||||
|
|
||||||
@@ -25,13 +25,9 @@ protected:
|
|||||||
resource::ResourceManager& resourceManager;
|
resource::ResourceManager& resourceManager;
|
||||||
prediction::PredictionManager& predictionManager;
|
prediction::PredictionManager& predictionManager;
|
||||||
|
|
||||||
std::map<resource::ComputingResource*, std::vector<std::shared_ptr<SchedulingDecision>>> scheduledTasks;
|
|
||||||
|
|
||||||
typedef std::map<resource::ComputingResourceType*, std::pair<wfs::AtomicActivityImplementation*, prediction::ExecutionTimeResult>> ImplementationCacheInnerMap;
|
typedef std::map<resource::ComputingResourceType*, std::pair<wfs::AtomicActivityImplementation*, prediction::ExecutionTimeResult>> ImplementationCacheInnerMap;
|
||||||
std::map<wfs::AtomicActivityType*, ImplementationCacheInnerMap> implementationCache;
|
std::map<wfs::AtomicActivityType*, ImplementationCacheInnerMap> implementationCache;
|
||||||
|
|
||||||
double _getResourceEstimatedAvailableTime(resource::ComputingResource* resource);
|
|
||||||
|
|
||||||
typedef std::tuple<resource::ComputingResource*, wfs::AtomicActivityImplementation*, double, prediction::ExecutionTimeResult> ECTEntry;
|
typedef std::tuple<resource::ComputingResource*, wfs::AtomicActivityImplementation*, double, prediction::ExecutionTimeResult> ECTEntry;
|
||||||
virtual std::pair<wep::AtomicWepNode*, ECTEntry> _getNextTaskToSchedule(std::map<wep::AtomicWepNode*, ECTEntry>& estimatedTaskCompletionTimes);
|
virtual std::pair<wep::AtomicWepNode*, ECTEntry> _getNextTaskToSchedule(std::map<wep::AtomicWepNode*, ECTEntry>& estimatedTaskCompletionTimes);
|
||||||
|
|
||||||
|
|||||||
@@ -25,13 +25,9 @@ protected:
|
|||||||
resource::ResourceManager& resourceManager;
|
resource::ResourceManager& resourceManager;
|
||||||
prediction::PredictionManager& predictionManager;
|
prediction::PredictionManager& predictionManager;
|
||||||
|
|
||||||
std::map<resource::ComputingResource*, std::vector<std::shared_ptr<SchedulingDecision>>> scheduledTasks;
|
|
||||||
|
|
||||||
typedef std::map<resource::ComputingResourceType*, std::pair<wfs::AtomicActivityImplementation*, prediction::ExecutionTimeResult>> ImplementationCacheInnerMap;
|
typedef std::map<resource::ComputingResourceType*, std::pair<wfs::AtomicActivityImplementation*, prediction::ExecutionTimeResult>> ImplementationCacheInnerMap;
|
||||||
std::map<wfs::AtomicActivityType*, ImplementationCacheInnerMap> implementationCache;
|
std::map<wfs::AtomicActivityType*, ImplementationCacheInnerMap> implementationCache;
|
||||||
|
|
||||||
double _getResourceEstimatedAvailableTime(resource::ComputingResource* resource);
|
|
||||||
|
|
||||||
typedef std::tuple<resource::ComputingResource*, wfs::AtomicActivityImplementation*, double, prediction::ExecutionTimeResult> ECTEntry;
|
typedef std::tuple<resource::ComputingResource*, wfs::AtomicActivityImplementation*, double, prediction::ExecutionTimeResult> ECTEntry;
|
||||||
std::pair<wep::AtomicWepNode*, ECTEntry> _getNextTaskToSchedule(std::map<wep::AtomicWepNode*, ECTEntry>& estimatedTaskCompletionTimes);
|
std::pair<wep::AtomicWepNode*, ECTEntry> _getNextTaskToSchedule(std::map<wep::AtomicWepNode*, ECTEntry>& estimatedTaskCompletionTimes);
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ void SchedulerBase::notifyWEPUpdate(wep::WorkflowExecutionPlan& wep, std::set<we
|
|||||||
|
|
||||||
bool SchedulerBase::executeSchedulingDecision(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) noexcept {
|
bool SchedulerBase::executeSchedulingDecision(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) noexcept {
|
||||||
wepe.decisions.insert(sd);
|
wepe.decisions.insert(sd);
|
||||||
|
scheduledTasks[sd->resource].push_back(sd);
|
||||||
schedulerLock.unlock();
|
schedulerLock.unlock();
|
||||||
sd->activityInstance->setSchedulingDecision(sd);
|
sd->activityInstance->setSchedulingDecision(sd);
|
||||||
if (sd->activityInstance->activityType() == wfs::ActivityType::Atomic) {
|
if (sd->activityInstance->activityType() == wfs::ActivityType::Atomic) {
|
||||||
@@ -92,6 +93,13 @@ void SchedulerBase::notifySchedulingDecisionStatusUpdate(std::shared_ptr<Schedul
|
|||||||
std::unique_lock<std::mutex> objLock(schedulerMutex);
|
std::unique_lock<std::mutex> objLock(schedulerMutex);
|
||||||
auto wepe = wepMap.find(sd->wep);
|
auto wepe = wepMap.find(sd->wep);
|
||||||
if (wepe != wepMap.end()) {
|
if (wepe != wepMap.end()) {
|
||||||
|
auto& innerMap = scheduledTasks[sd->resource];
|
||||||
|
for (auto i = innerMap.begin(); i != innerMap.end(); i++) {
|
||||||
|
if (*i == sd) {
|
||||||
|
innerMap.erase(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
_notifySchedulingDecisionStatusUpdate(wepe->second, sd, objLock);
|
_notifySchedulingDecisionStatusUpdate(wepe->second, sd, objLock);
|
||||||
// Notify enactment engine
|
// Notify enactment engine
|
||||||
auto ee = wepe->second.engine;
|
auto ee = wepe->second.engine;
|
||||||
@@ -102,6 +110,36 @@ void SchedulerBase::notifySchedulingDecisionStatusUpdate(std::shared_ptr<Schedul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double SchedulerBase::_getResourceEstimatedAvailableTime(resource::ComputingResource* resource) {
|
||||||
|
if (resource->getFreeSlotCount() > 0) {
|
||||||
|
return 0.0;
|
||||||
|
} else {
|
||||||
|
// Calculating the estimated available time for resources with more than 1 slot is not trivial
|
||||||
|
// Here we are employing a heuristic that partitions the scheduled tasks into chunks the size of the maximal slot count,
|
||||||
|
// takes the minimum time of each chunk and adds them together.
|
||||||
|
unsigned i = 0;
|
||||||
|
double eat = 0;
|
||||||
|
double minTime = -1;
|
||||||
|
auto& tasks = scheduledTasks[resource];
|
||||||
|
for (auto t : tasks) {
|
||||||
|
i++;
|
||||||
|
if (minTime < 0) {
|
||||||
|
minTime = t->getPrediction().getExecutionTime().getValue();
|
||||||
|
} else {
|
||||||
|
if (i > resource->getMaxSlotCount()) {
|
||||||
|
eat += minTime;
|
||||||
|
i = 0;
|
||||||
|
minTime = t->getPrediction().getExecutionTime().getValue();
|
||||||
|
} else {
|
||||||
|
if (t->getPrediction().getExecutionTime().getValue() < minTime) {
|
||||||
|
minTime = t->getPrediction().getExecutionTime().getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return eat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace scheduling */
|
} /* namespace scheduling */
|
||||||
} /* namespace wfr */
|
} /* namespace wfr */
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <wfr/scheduling/scheduler/maxmin/MaxMinScheduler.h>
|
#include <wfr/scheduling/scheduler/maxmin/MaxMinScheduler.h>
|
||||||
#include <wfr/scheduling/scheduler/sufferage/SufferageScheduler.h>
|
#include <wfr/scheduling/scheduler/sufferage/SufferageScheduler.h>
|
||||||
#include <wfr/scheduling/scheduler/peft/PEFTScheduler.h>
|
#include <wfr/scheduling/scheduler/peft/PEFTScheduler.h>
|
||||||
|
#include <wfr/scheduling/scheduler/lookahead/LookaheadScheduler.h>
|
||||||
|
|
||||||
namespace wfr {
|
namespace wfr {
|
||||||
namespace scheduling {
|
namespace scheduling {
|
||||||
@@ -78,6 +79,9 @@ SchedulerManager::SchedulerManager(std::string defaultScheduler) : defaultSchedu
|
|||||||
schedulerFactories.insert(factoryMap_t::value_type("heft", []()->AbstractScheduler* {
|
schedulerFactories.insert(factoryMap_t::value_type("heft", []()->AbstractScheduler* {
|
||||||
return new HEFTScheduler(resource::ResourceManager::getInstance(), prediction::PredictionManager::getInstance());
|
return new HEFTScheduler(resource::ResourceManager::getInstance(), prediction::PredictionManager::getInstance());
|
||||||
}));
|
}));
|
||||||
|
schedulerFactories.insert(factoryMap_t::value_type("lookahead", []()->AbstractScheduler* {
|
||||||
|
return new LookaheadScheduler(resource::ResourceManager::getInstance(), prediction::PredictionManager::getInstance());
|
||||||
|
}));
|
||||||
schedulerFactories.insert(factoryMap_t::value_type("random", []()->AbstractScheduler* {
|
schedulerFactories.insert(factoryMap_t::value_type("random", []()->AbstractScheduler* {
|
||||||
return new RandomScheduler(resource::ResourceManager::getInstance(), prediction::PredictionManager::getInstance());
|
return new RandomScheduler(resource::ResourceManager::getInstance(), prediction::PredictionManager::getInstance());
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -10,4 +10,5 @@ set(wfr_cpp_files "${wfr_cpp_files}"
|
|||||||
src/scheduling/scheduler/maxmin/MaxMinScheduler.cpp
|
src/scheduling/scheduler/maxmin/MaxMinScheduler.cpp
|
||||||
src/scheduling/scheduler/sufferage/SufferageScheduler.cpp
|
src/scheduling/scheduler/sufferage/SufferageScheduler.cpp
|
||||||
src/scheduling/scheduler/peft/PEFTScheduler.cpp
|
src/scheduling/scheduler/peft/PEFTScheduler.cpp
|
||||||
|
src/scheduling/scheduler/lookahead/LookaheadScheduler.cpp
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace wfr {
|
|||||||
namespace scheduling {
|
namespace scheduling {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void HEFTScheduler::calcTaskRanks(wep::ActivityWepNode& node, std::vector<resource::ComputingResource*>& resources) {
|
void HEFTScheduler::calcTaskRanks(wep::ActivityWepNode& node, std::vector<resource::ComputingResource*>& resources) {
|
||||||
/*std::cout << "calcTaskRanks: " << node.activity.baseActivity.baseTemplate.activityName << " (" << node.activity.instanceID << ")"
|
/*std::cout << "calcTaskRanks: " << node.activity.baseActivity.baseTemplate.activityName << " (" << node.activity.instanceID << ")"
|
||||||
<< " [" << print::toString(node.activity.baseActivity.activityType()) << "]"
|
<< " [" << print::toString(node.activity.baseActivity.activityType()) << "]"
|
||||||
@@ -156,11 +157,6 @@ void HEFTScheduler::_notifyWEPUpdate(SchedulerBase::WepMapEntry& wepe, std::set<
|
|||||||
scheduleReadySet(wepe, resources, schedulerLock);
|
scheduleReadySet(wepe, resources, schedulerLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HEFTScheduler::_notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {
|
|
||||||
//auto resources = resourceManager.getComputingResources();
|
|
||||||
//scheduleReadySet(wepe, resources, schedulerLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HEFTScheduler::scheduleReadySet(WepMapEntry& wepe, std::vector<resource::ComputingResource*>& resources, std::unique_lock<std::mutex>& schedulerLock) {
|
void HEFTScheduler::scheduleReadySet(WepMapEntry& wepe, std::vector<resource::ComputingResource*>& resources, std::unique_lock<std::mutex>& schedulerLock) {
|
||||||
struct _schedulingPriorityQueueComparison {
|
struct _schedulingPriorityQueueComparison {
|
||||||
@@ -193,9 +189,12 @@ void HEFTScheduler::scheduleReadySet(WepMapEntry& wepe, std::vector<resource::Co
|
|||||||
prediction::ExecutionTimeResult fastestPred;
|
prediction::ExecutionTimeResult fastestPred;
|
||||||
wfs::AtomicActivityImplementation* fastestImpl = nullptr;
|
wfs::AtomicActivityImplementation* fastestImpl = nullptr;
|
||||||
resource::ComputingResource* fastestResource = nullptr;
|
resource::ComputingResource* fastestResource = nullptr;
|
||||||
|
double earliestEstimatedFinishTime = -1;
|
||||||
for (auto res : resources) {
|
for (auto res : resources) {
|
||||||
if (entry->fastestImplementations[ri] && res->getFreeSlotCount() > 0) {
|
if (entry->fastestImplementations[ri]) {
|
||||||
if (!fastestPred.isValid() || entry->fastestExecutionTimes[ri].executionTime.getValue() < fastestPred.executionTime.getValue()) {
|
auto estimatedFinishTime = _getResourceEstimatedAvailableTime(res) + entry->fastestExecutionTimes[ri].executionTime.getValue();
|
||||||
|
if (earliestEstimatedFinishTime < 0.0 || estimatedFinishTime < earliestEstimatedFinishTime) {
|
||||||
|
earliestEstimatedFinishTime = estimatedFinishTime;
|
||||||
fastestImpl = entry->fastestImplementations[ri];
|
fastestImpl = entry->fastestImplementations[ri];
|
||||||
fastestPred = entry->fastestExecutionTimes[ri];
|
fastestPred = entry->fastestExecutionTimes[ri];
|
||||||
fastestResource = res;
|
fastestResource = res;
|
||||||
@@ -222,6 +221,11 @@ void HEFTScheduler::scheduleReadySet(WepMapEntry& wepe, std::vector<resource::Co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HEFTScheduler::_notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {
|
||||||
|
//auto resources = resourceManager.getComputingResources();
|
||||||
|
//scheduleReadySet(wepe, resources, schedulerLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void HEFTScheduler::_unregisterWEP(WepMapEntry& wepe, std::unique_lock<std::mutex>& schedulerLock) {
|
void HEFTScheduler::_unregisterWEP(WepMapEntry& wepe, std::unique_lock<std::mutex>& schedulerLock) {
|
||||||
/*std::cout << "Task Ranks: " << std::endl;
|
/*std::cout << "Task Ranks: " << std::endl;
|
||||||
|
|||||||
+319
@@ -0,0 +1,319 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <wfr/prediction/PredictionManager.h>
|
||||||
|
#include <wfr/common/resource/ResourceManager.h>
|
||||||
|
#include <wfr/common/wep/WorkflowExecutionPlan.h>
|
||||||
|
#include <wfr/common/wep/AbstractWepNode.h>
|
||||||
|
#include <wfr/common/wep/activities/AtomicWepNode.h>
|
||||||
|
#include <wfr/common/wep/ActivityWepNode.h>
|
||||||
|
#include <wfr/common/wfs/Activity.h>
|
||||||
|
#include <wfr/common/wfs/ActivityInstance.h>
|
||||||
|
#include <wfr/common/wfs/instances/AtomicActivityInstance.h>
|
||||||
|
#include <wfr/common/wfs/AtomicActivityImplementation.h>
|
||||||
|
#include <wfr/common/wfs/templates/AtomicActivityTemplate.h>
|
||||||
|
#include <wfr/enactment/EnactmentEngine.h>
|
||||||
|
#include <wfr/common/scheduling/SchedulingDecision.h>
|
||||||
|
#include <wfr/execution/ExecutionManager.h>
|
||||||
|
#include <wfr/wep/utils/WepSearch.h>
|
||||||
|
#include <wfr/common/utils/print.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <set>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
#include <wfr/scheduling/scheduler/lookahead/LookaheadScheduler.h>
|
||||||
|
#include <queue>
|
||||||
|
#include <memory>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
namespace wfr {
|
||||||
|
namespace scheduling {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void LookaheadScheduler::calcTaskRanks(wep::ActivityWepNode& node, std::vector<resource::ComputingResource*>& resources) {
|
||||||
|
/*std::cout << "calcTaskRanks: " << node.activity.baseActivity.baseTemplate.activityName << " (" << node.activity.instanceID << ")"
|
||||||
|
<< " [" << print::toString(node.activity.baseActivity.activityType()) << "]"
|
||||||
|
<< " [" << (int)node.nodeType << "]" << std::endl;*/
|
||||||
|
|
||||||
|
auto entry = (TaskRankEntry*)node.getUserData().get();
|
||||||
|
if (!entry) {
|
||||||
|
entry = new TaskRankEntry(resources.size());
|
||||||
|
if (node.nodeType == wep::WepNodeType::Atomic) {
|
||||||
|
// get fastest implementation for each resource
|
||||||
|
unsigned ri = 0;
|
||||||
|
double sumExecutionTimes = 0.0;
|
||||||
|
unsigned sumExecutionTimeCount = 0;
|
||||||
|
for (auto res : resources) {
|
||||||
|
prediction::ExecutionTimeResult fastestPred;
|
||||||
|
wfs::AtomicActivityImplementation* fastestImpl = nullptr;
|
||||||
|
for (auto impl : node.activity.baseActivity.baseTemplate.as<wfs::AtomicActivityTemplate>().atomicActivityType->getImplementations()) {
|
||||||
|
auto pred = predictionManager.predictExecutionTime(node.activity, *impl, res->resourceType, 1);
|
||||||
|
if (pred.isValid()) {
|
||||||
|
if (!fastestPred.isValid() || pred < fastestPred) {
|
||||||
|
fastestPred = pred;
|
||||||
|
fastestImpl = impl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry->fastestImplementations[ri] = fastestImpl;
|
||||||
|
entry->fastestExecutionTimes[ri] = fastestPred;
|
||||||
|
if (fastestPred.isValid()) {
|
||||||
|
sumExecutionTimeCount++;
|
||||||
|
sumExecutionTimes += fastestPred.executionTime.getValue();
|
||||||
|
}
|
||||||
|
ri++;
|
||||||
|
}
|
||||||
|
entry->averageExecutionTime = sumExecutionTimes / (double)sumExecutionTimeCount;
|
||||||
|
}
|
||||||
|
node.setUserData(std::shared_ptr<void>(entry));
|
||||||
|
if (node.nodeType == wep::WepNodeType::Atomic) {
|
||||||
|
node.activity.setUserData(std::shared_ptr<void>(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!entry->finalized) {
|
||||||
|
auto successors = node.getSuccessors();
|
||||||
|
if (successors.size() == 0) {
|
||||||
|
// exit task
|
||||||
|
//std::cout << "\tNo successors => exit task: " << entry->averageExecutionTime << std::endl;
|
||||||
|
entry->rank = entry->averageExecutionTime;
|
||||||
|
entry->finalized = true;
|
||||||
|
} else {
|
||||||
|
bool succsFinalized = true;
|
||||||
|
double maxSuccRank = 0.0;
|
||||||
|
for (auto s : successors) {
|
||||||
|
auto& succ = s->as<wep::ActivityWepNode>();
|
||||||
|
/*std::cout << "\tSuccessor: " << succ.activity.baseActivity.baseTemplate.activityName << " (" << succ.activity.instanceID << ")"
|
||||||
|
<< " [" << print::toString(succ.activity.baseActivity.activityType()) << "]"
|
||||||
|
<< "[" << (int)succ.nodeType << "]" << std::endl;*/
|
||||||
|
auto succEntry = (TaskRankEntry*)succ.getUserData().get();
|
||||||
|
if (!succEntry || !succEntry->finalized) {
|
||||||
|
// recursively calculate ranks
|
||||||
|
//std::cout << "recursive call start" << std::endl;
|
||||||
|
calcTaskRanks(succ, resources);
|
||||||
|
//std::cout << "recursive call end" << std::endl;
|
||||||
|
if (!succEntry) {
|
||||||
|
succEntry = (TaskRankEntry*)succ.getUserData().get();
|
||||||
|
}
|
||||||
|
succsFinalized = succsFinalized && succEntry->finalized;
|
||||||
|
}
|
||||||
|
// Get average communication time
|
||||||
|
double averaveCommTime = 0.0;
|
||||||
|
if (node.nodeType == wep::WepNodeType::Atomic && succ.nodeType == wep::WepNodeType::Atomic) {
|
||||||
|
double sumCommTime = 0.0;
|
||||||
|
unsigned sumCommTimeCount = 0;
|
||||||
|
for (auto res1 : resources) {
|
||||||
|
for (auto res2 : resources) {
|
||||||
|
if (res1 != res2) {
|
||||||
|
auto pred = predictionManager.predictCommunicationTime(node.activity, *res1, succ.activity, *res2);
|
||||||
|
if (pred.isValid) {
|
||||||
|
sumCommTime += pred.communicationTime.getValue();
|
||||||
|
sumCommTimeCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
averaveCommTime = sumCommTime / (double)sumCommTimeCount;
|
||||||
|
}
|
||||||
|
auto succRank = averaveCommTime + succEntry->rank;
|
||||||
|
if (succRank > maxSuccRank) {
|
||||||
|
maxSuccRank = succRank;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node.nodeType == wep::WepNodeType::Atomic) {
|
||||||
|
/*std::cout << "AverageExecTime: " << node.activity.baseActivity.baseTemplate.activityName << " (" << node.activity.instanceID << ")"
|
||||||
|
<< " [" << print::toString(node.activity.baseActivity.activityType()) << "]"
|
||||||
|
<< " [" << (int)node.nodeType << "]: " << entry->averageExecutionTime << std::endl;*/
|
||||||
|
entry->rank = entry->averageExecutionTime + maxSuccRank;
|
||||||
|
} else {
|
||||||
|
entry->rank = maxSuccRank;
|
||||||
|
}
|
||||||
|
/*std::cout << "Rank: " << node.activity.baseActivity.baseTemplate.activityName << " (" << node.activity.instanceID << ")"
|
||||||
|
<< " [" << print::toString(node.activity.baseActivity.activityType()) << "]"
|
||||||
|
<< " [" << (int)node.nodeType << "]: " << entry->rank << std::endl;*/
|
||||||
|
if (succsFinalized) {
|
||||||
|
if (node.nodeType == wep::WepNodeType::CompositeStart || node.nodeType == wep::WepNodeType::IterationStart) {
|
||||||
|
if (node.getLastKnownInstanceStatus() >= wfs::ActivityInstanceStatus::ReadyForExecution) {
|
||||||
|
entry->finalized = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entry->finalized = true;
|
||||||
|
}
|
||||||
|
/*if (entry->finalized) {
|
||||||
|
std::cout << "Finalizing: " << node.activity.baseActivity.baseTemplate.activityName << " (" << node.activity.instanceID << ")"
|
||||||
|
<< " [" << print::toString(node.activity.baseActivity.activityType()) << "]"
|
||||||
|
<< " [" << (int)node.nodeType << "]" << std::endl;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LookaheadScheduler::_notifyWEPUpdate(SchedulerBase::WepMapEntry& wepe, std::set<wep::AtomicWepNode*> readyToExecute, std::unique_lock<std::mutex>& schedulerLock) {
|
||||||
|
auto resourceTypes = resourceManager.getComputingResourceTypes();
|
||||||
|
auto resources = resourceManager.getComputingResources();
|
||||||
|
|
||||||
|
calcTaskRanks(wepe.wep->getStartNode()->as<wep::ActivityWepNode>(), resources);
|
||||||
|
|
||||||
|
readySet.insert(readyToExecute.begin(), readyToExecute.end());
|
||||||
|
|
||||||
|
scheduleReadySet(wepe, resources, schedulerLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LookaheadScheduler::scheduleReadySet(WepMapEntry& wepe, std::vector<resource::ComputingResource*>& resources, std::unique_lock<std::mutex>& schedulerLock) {
|
||||||
|
struct _schedulingPriorityQueueComparison {
|
||||||
|
bool operator()(wep::AtomicWepNode* e1, wep::AtomicWepNode* e2) {
|
||||||
|
auto entry1 = (TaskRankEntry*)e1->getUserData().get();
|
||||||
|
auto entry2 = (TaskRankEntry*)e2->getUserData().get();
|
||||||
|
if (entry1 && !entry2) {
|
||||||
|
return false;
|
||||||
|
} else if (!entry1 && entry2) {
|
||||||
|
return true;
|
||||||
|
} else if (entry1 && entry2) {
|
||||||
|
return entry1->rank < entry2->rank;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::priority_queue<wep::AtomicWepNode*, std::vector<wep::AtomicWepNode*>, _schedulingPriorityQueueComparison> schedulingPriorityQueue;
|
||||||
|
// Put elements from ready set into priority queue thereby sorting them by rank
|
||||||
|
for (auto n : readySet) {
|
||||||
|
schedulingPriorityQueue.push(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!schedulingPriorityQueue.empty()) {
|
||||||
|
auto task = schedulingPriorityQueue.top();
|
||||||
|
schedulingPriorityQueue.pop();
|
||||||
|
auto entry = (TaskRankEntry*)task->getUserData().get();
|
||||||
|
int ri = 0;
|
||||||
|
|
||||||
|
prediction::ExecutionTimeResult fastestPred;
|
||||||
|
wfs::AtomicActivityImplementation* fastestImpl = nullptr;
|
||||||
|
resource::ComputingResource* fastestResource = nullptr;
|
||||||
|
double earliestEstimatedFinishTime = -1;
|
||||||
|
double minSuccEFT = -1;
|
||||||
|
auto succs = task->activity.getSuccessors();
|
||||||
|
for (auto res : resources) {
|
||||||
|
if (entry->fastestImplementations[ri]) {
|
||||||
|
auto estimatedFinishTime = _getResourceEstimatedAvailableTime(res) + entry->fastestExecutionTimes[ri].executionTime.getValue();
|
||||||
|
|
||||||
|
auto maxSuccEFT = -1;
|
||||||
|
if (succs.size() > 0) {
|
||||||
|
// do lookahead
|
||||||
|
struct _succSchedulingQueueComparison {
|
||||||
|
bool operator()(wfs::ActivityInstance* e1, wfs::ActivityInstance* e2) {
|
||||||
|
auto entry1 = (TaskRankEntry*)e1->getUserData().get();
|
||||||
|
auto entry2 = (TaskRankEntry*)e2->getUserData().get();
|
||||||
|
if (entry1 && !entry2) {
|
||||||
|
return false;
|
||||||
|
} else if (!entry1 && entry2) {
|
||||||
|
return true;
|
||||||
|
} else if (entry1 && entry2) {
|
||||||
|
return entry1->rank < entry2->rank;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::priority_queue<wfs::ActivityInstance*, std::vector<wfs::ActivityInstance*>, _succSchedulingQueueComparison> succSchedulingQueue;
|
||||||
|
std::map<resource::ComputingResource*, double> resourceEATMap;
|
||||||
|
resourceEATMap[res] = estimatedFinishTime;
|
||||||
|
for (auto succ : succs) {
|
||||||
|
if (succ->activityType() == wfs::ActivityType::Atomic) {
|
||||||
|
succSchedulingQueue.push(succ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!succSchedulingQueue.empty()) {
|
||||||
|
auto succ = succSchedulingQueue.top();
|
||||||
|
succSchedulingQueue.pop();
|
||||||
|
auto succEntry = (TaskRankEntry*)succ->getUserData().get();
|
||||||
|
unsigned ri2 = 0;
|
||||||
|
unsigned minEFT = -1;
|
||||||
|
resource::ComputingResource* minEFTResource = nullptr;
|
||||||
|
for (auto res2 : resources) {
|
||||||
|
double succEFT = -1;
|
||||||
|
if (entry->fastestImplementations[ri2]) {
|
||||||
|
succEFT = resourceEATMap[res2] + succEntry->fastestExecutionTimes[ri2].executionTime.getValue();
|
||||||
|
}
|
||||||
|
if (succEFT > 0 && (minEFT < 0 || succEFT < minEFT)) {
|
||||||
|
minEFT = succEFT;
|
||||||
|
minEFTResource = res2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minEFT > 0) {
|
||||||
|
resourceEATMap[minEFTResource] = minEFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto e : resourceEATMap) {
|
||||||
|
if (maxSuccEFT < 0 || e.second > maxSuccEFT) {
|
||||||
|
maxSuccEFT = e.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minSuccEFT < 0 || maxSuccEFT < minSuccEFT) {
|
||||||
|
minSuccEFT = maxSuccEFT;
|
||||||
|
earliestEstimatedFinishTime = estimatedFinishTime;
|
||||||
|
fastestImpl = entry->fastestImplementations[ri];
|
||||||
|
fastestPred = entry->fastestExecutionTimes[ri];
|
||||||
|
fastestResource = res;
|
||||||
|
}
|
||||||
|
// no successors
|
||||||
|
} else if (earliestEstimatedFinishTime < 0.0 || estimatedFinishTime < earliestEstimatedFinishTime) {
|
||||||
|
earliestEstimatedFinishTime = estimatedFinishTime;
|
||||||
|
fastestImpl = entry->fastestImplementations[ri];
|
||||||
|
fastestPred = entry->fastestExecutionTimes[ri];
|
||||||
|
fastestResource = res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ri++;
|
||||||
|
}
|
||||||
|
if (fastestResource) {
|
||||||
|
|
||||||
|
/*auto entry = (TaskRankEntry*)task->getUserData().get();
|
||||||
|
std::cout << task->activity.baseActivity.baseTemplate.activityName << "[" << task->activity.instanceID << "]: "
|
||||||
|
<< entry->rank << std::endl;
|
||||||
|
std::cout << "\tFastest Resource: " << fastestResource->resourceIdentifier << ": prediction = " << fastestPred.getExecutionTime().getValue() << std::endl;*/
|
||||||
|
|
||||||
|
auto reservation = resourceManager.reserveComputingResource(fastestResource, 1, true);
|
||||||
|
if (reservation) {
|
||||||
|
std::shared_ptr<SchedulingDecision> sd = std::make_shared<SchedulingDecision>(&task->activity, fastestImpl, wepe.wep, reservation);
|
||||||
|
sd->setPrediction(fastestPred);
|
||||||
|
task->activity.setInstanceStatus(wfs::ActivityInstanceStatus::Scheduled);
|
||||||
|
executeSchedulingDecision(wepe, sd, schedulerLock);
|
||||||
|
readySet.erase(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LookaheadScheduler::_notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {
|
||||||
|
//auto resources = resourceManager.getComputingResources();
|
||||||
|
//scheduleReadySet(wepe, resources, schedulerLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LookaheadScheduler::_unregisterWEP(WepMapEntry& wepe, std::unique_lock<std::mutex>& schedulerLock) {
|
||||||
|
/*std::cout << "Task Ranks: " << std::endl;
|
||||||
|
std::set<wep::AbstractWepNode*> visitedNodes;
|
||||||
|
auto visitFunc = [&](wep::AbstractWepNode* node) -> bool {
|
||||||
|
if (visitedNodes.find(node) == visitedNodes.end()) {
|
||||||
|
auto entry = (TaskRankEntry*)node->getUserData().get();
|
||||||
|
if (entry) {
|
||||||
|
std::cout << "\t" << node->as<wep::ActivityWepNode>().activity.baseActivity.baseTemplate.activityName
|
||||||
|
<< "[" << node->as<wep::ActivityWepNode>().activity.instanceID << "]: " << entry->rank << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "\t" << node->as<wep::ActivityWepNode>().activity.baseActivity.baseTemplate.activityName
|
||||||
|
<< "[" << node->as<wep::ActivityWepNode>().activity.instanceID << "]: No Entry" << std::endl;
|
||||||
|
}
|
||||||
|
visitedNodes.insert(node);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
wfr::utils::wep::wepBreadthFirstSearch(wepe.wep->getStartNode(), visitFunc);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace scheduler */
|
||||||
|
} /* namespace wfr */
|
||||||
|
|
||||||
|
|
||||||
@@ -24,39 +24,6 @@ namespace scheduling {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
double MinMinScheduler::_getResourceEstimatedAvailableTime(resource::ComputingResource* resource) {
|
|
||||||
if (resource->getFreeSlotCount() > 0) {
|
|
||||||
return 0.0;
|
|
||||||
} else {
|
|
||||||
// Calculating the estimated available time for resources with more than 1 slot is not trivial
|
|
||||||
// Here we are employing a heuristic that partitions the scheduled tasks into chunks the size of the maximal slot count,
|
|
||||||
// takes the minimum time of each chunk and adds them together.
|
|
||||||
unsigned i = 0;
|
|
||||||
double eat = 0;
|
|
||||||
double minTime = -1;
|
|
||||||
auto& tasks = scheduledTasks[resource];
|
|
||||||
for (auto t : tasks) {
|
|
||||||
i++;
|
|
||||||
if (minTime < 0) {
|
|
||||||
minTime = t->getPrediction().getExecutionTime().getValue();
|
|
||||||
} else {
|
|
||||||
if (i > resource->getMaxSlotCount()) {
|
|
||||||
eat += minTime;
|
|
||||||
i = 0;
|
|
||||||
minTime = t->getPrediction().getExecutionTime().getValue();
|
|
||||||
} else {
|
|
||||||
if (t->getPrediction().getExecutionTime().getValue() < minTime) {
|
|
||||||
minTime = t->getPrediction().getExecutionTime().getValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return eat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::pair<wep::AtomicWepNode*, MinMinScheduler::ECTEntry> MinMinScheduler::_getNextTaskToSchedule(std::map<wep::AtomicWepNode*, ECTEntry>& estimatedTaskCompletionTimes) {
|
std::pair<wep::AtomicWepNode*, MinMinScheduler::ECTEntry> MinMinScheduler::_getNextTaskToSchedule(std::map<wep::AtomicWepNode*, ECTEntry>& estimatedTaskCompletionTimes) {
|
||||||
wep::AtomicWepNode* selectedNode = nullptr;
|
wep::AtomicWepNode* selectedNode = nullptr;
|
||||||
ECTEntry selectedEntry;
|
ECTEntry selectedEntry;
|
||||||
@@ -143,22 +110,13 @@ void MinMinScheduler::_notifyWEPUpdate(SchedulerBase::WepMapEntry& wepe, std::se
|
|||||||
auto sd = std::make_shared<SchedulingDecision>(&selectedTask.first->activity, std::get<1>(selectedTask.second), wepe.wep, reservation);
|
auto sd = std::make_shared<SchedulingDecision>(&selectedTask.first->activity, std::get<1>(selectedTask.second), wepe.wep, reservation);
|
||||||
sd->setPrediction(std::get<3>(selectedTask.second));
|
sd->setPrediction(std::get<3>(selectedTask.second));
|
||||||
selectedTask.first->activity.setInstanceStatus(wfs::ActivityInstanceStatus::Scheduled);
|
selectedTask.first->activity.setInstanceStatus(wfs::ActivityInstanceStatus::Scheduled);
|
||||||
scheduledTasks[sd->resource].push_back(sd);
|
|
||||||
executeSchedulingDecision(wepe, sd, schedulerLock);
|
executeSchedulingDecision(wepe, sd, schedulerLock);
|
||||||
readyToExecute.erase(selectedTask.first);
|
readyToExecute.erase(selectedTask.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MinMinScheduler::_notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {
|
void MinMinScheduler::_notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {}
|
||||||
auto& innerMap = scheduledTasks[sd->resource];
|
|
||||||
for (auto i = innerMap.begin(); i != innerMap.end(); i++) {
|
|
||||||
if (*i == sd) {
|
|
||||||
innerMap.erase(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace scheduling */
|
} /* namespace scheduling */
|
||||||
} /* namespace wfr */
|
} /* namespace wfr */
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace wfr {
|
|||||||
namespace scheduling {
|
namespace scheduling {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PEFTScheduler::calcOptimisticCosts(wep::ActivityWepNode& node, std::vector<resource::ComputingResource*>& resources) {
|
void PEFTScheduler::calcOptimisticCosts(wep::ActivityWepNode& node, std::vector<resource::ComputingResource*>& resources) {
|
||||||
/*std::cout << "calcOptimisticCosts: " << node.activity.baseActivity.baseTemplate.activityName << " (" << node.activity.instanceID << ")"
|
/*std::cout << "calcOptimisticCosts: " << node.activity.baseActivity.baseTemplate.activityName << " (" << node.activity.instanceID << ")"
|
||||||
<< " [" << print::toString(node.activity.baseActivity.activityType()) << "]"
|
<< " [" << print::toString(node.activity.baseActivity.activityType()) << "]"
|
||||||
@@ -157,11 +158,6 @@ void PEFTScheduler::_notifyWEPUpdate(SchedulerBase::WepMapEntry& wepe, std::set<
|
|||||||
scheduleReadySet(wepe, resources, schedulerLock);
|
scheduleReadySet(wepe, resources, schedulerLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PEFTScheduler::_notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {
|
|
||||||
//auto resources = resourceManager.getComputingResources();
|
|
||||||
//scheduleReadySet(wepe, resources, schedulerLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PEFTScheduler::scheduleReadySet(WepMapEntry& wepe, std::vector<resource::ComputingResource*>& resources, std::unique_lock<std::mutex>& schedulerLock) {
|
void PEFTScheduler::scheduleReadySet(WepMapEntry& wepe, std::vector<resource::ComputingResource*>& resources, std::unique_lock<std::mutex>& schedulerLock) {
|
||||||
struct _schedulingPriorityQueueComparison {
|
struct _schedulingPriorityQueueComparison {
|
||||||
@@ -194,9 +190,12 @@ void PEFTScheduler::scheduleReadySet(WepMapEntry& wepe, std::vector<resource::Co
|
|||||||
prediction::ExecutionTimeResult fastestPred;
|
prediction::ExecutionTimeResult fastestPred;
|
||||||
wfs::AtomicActivityImplementation* fastestImpl = nullptr;
|
wfs::AtomicActivityImplementation* fastestImpl = nullptr;
|
||||||
resource::ComputingResource* fastestResource = nullptr;
|
resource::ComputingResource* fastestResource = nullptr;
|
||||||
|
double earliestEstimatedFinishTime = -1;
|
||||||
for (auto res : resources) {
|
for (auto res : resources) {
|
||||||
if (entry->fastestImplementations[ri] && res->getFreeSlotCount() > 0) {
|
if (entry->fastestImplementations[ri]) {
|
||||||
if (!fastestPred.isValid() || entry->fastestExecutionTimes[ri].executionTime.getValue() < fastestPred.executionTime.getValue()) {
|
auto estimatedFinishTime = _getResourceEstimatedAvailableTime(res) + entry->fastestExecutionTimes[ri].executionTime.getValue();
|
||||||
|
if (earliestEstimatedFinishTime < 0.0 || estimatedFinishTime < earliestEstimatedFinishTime) {
|
||||||
|
earliestEstimatedFinishTime = estimatedFinishTime;
|
||||||
fastestImpl = entry->fastestImplementations[ri];
|
fastestImpl = entry->fastestImplementations[ri];
|
||||||
fastestPred = entry->fastestExecutionTimes[ri];
|
fastestPred = entry->fastestExecutionTimes[ri];
|
||||||
fastestResource = res;
|
fastestResource = res;
|
||||||
@@ -217,6 +216,11 @@ void PEFTScheduler::scheduleReadySet(WepMapEntry& wepe, std::vector<resource::Co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PEFTScheduler::_notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {
|
||||||
|
//auto resources = resourceManager.getComputingResources();
|
||||||
|
//scheduleReadySet(wepe, resources, schedulerLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} /* namespace scheduler */
|
} /* namespace scheduler */
|
||||||
|
|||||||
@@ -24,39 +24,6 @@ namespace scheduling {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
double SufferageScheduler::_getResourceEstimatedAvailableTime(resource::ComputingResource* resource) {
|
|
||||||
if (resource->getFreeSlotCount() > 0) {
|
|
||||||
return 0.0;
|
|
||||||
} else {
|
|
||||||
// Calculating the estimated available time for resources with more than 1 slot is not trivial
|
|
||||||
// Here we are employing a heuristic that partitions the scheduled tasks into chunks the size of the maximal slot count,
|
|
||||||
// takes the minimum time of each chunk and adds them together.
|
|
||||||
unsigned i = 0;
|
|
||||||
double eat = 0;
|
|
||||||
double minTime = -1;
|
|
||||||
auto& tasks = scheduledTasks[resource];
|
|
||||||
for (auto t : tasks) {
|
|
||||||
i++;
|
|
||||||
if (minTime < 0) {
|
|
||||||
minTime = t->getPrediction().getExecutionTime().getValue();
|
|
||||||
} else {
|
|
||||||
if (i > resource->getMaxSlotCount()) {
|
|
||||||
eat += minTime;
|
|
||||||
i = 0;
|
|
||||||
minTime = t->getPrediction().getExecutionTime().getValue();
|
|
||||||
} else {
|
|
||||||
if (t->getPrediction().getExecutionTime().getValue() < minTime) {
|
|
||||||
minTime = t->getPrediction().getExecutionTime().getValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return eat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::pair<wep::AtomicWepNode*, SufferageScheduler::ECTEntry> SufferageScheduler::_getNextTaskToSchedule(std::map<wep::AtomicWepNode*, ECTEntry>& estimatedTaskCompletionTimes) {
|
std::pair<wep::AtomicWepNode*, SufferageScheduler::ECTEntry> SufferageScheduler::_getNextTaskToSchedule(std::map<wep::AtomicWepNode*, ECTEntry>& estimatedTaskCompletionTimes) {
|
||||||
wep::AtomicWepNode* selectedNode = nullptr;
|
wep::AtomicWepNode* selectedNode = nullptr;
|
||||||
ECTEntry selectedEntry;
|
ECTEntry selectedEntry;
|
||||||
@@ -155,22 +122,13 @@ void SufferageScheduler::_notifyWEPUpdate(SchedulerBase::WepMapEntry& wepe, std:
|
|||||||
auto sd = std::make_shared<SchedulingDecision>(&selectedTask.first->activity, std::get<1>(selectedTask.second), wepe.wep, reservation);
|
auto sd = std::make_shared<SchedulingDecision>(&selectedTask.first->activity, std::get<1>(selectedTask.second), wepe.wep, reservation);
|
||||||
sd->setPrediction(std::get<3>(selectedTask.second));
|
sd->setPrediction(std::get<3>(selectedTask.second));
|
||||||
selectedTask.first->activity.setInstanceStatus(wfs::ActivityInstanceStatus::Scheduled);
|
selectedTask.first->activity.setInstanceStatus(wfs::ActivityInstanceStatus::Scheduled);
|
||||||
scheduledTasks[sd->resource].push_back(sd);
|
|
||||||
executeSchedulingDecision(wepe, sd, schedulerLock);
|
executeSchedulingDecision(wepe, sd, schedulerLock);
|
||||||
readyToExecute.erase(selectedTask.first);
|
readyToExecute.erase(selectedTask.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SufferageScheduler::_notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {
|
void SufferageScheduler::_notifySchedulingDecisionStatusUpdate(WepMapEntry& wepe, std::shared_ptr<SchedulingDecision> sd, std::unique_lock<std::mutex>& schedulerLock) {}
|
||||||
auto& innerMap = scheduledTasks[sd->resource];
|
|
||||||
for (auto i = innerMap.begin(); i != innerMap.end(); i++) {
|
|
||||||
if (*i == sd) {
|
|
||||||
innerMap.erase(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace scheduling */
|
} /* namespace scheduling */
|
||||||
} /* namespace wfr */
|
} /* namespace wfr */
|
||||||
|
|||||||
Reference in New Issue
Block a user