Files
Matthias 19d695d4d8 Added lookahead scheduler.
Most scheduler now use estimated finish time instead of predicted execution time.
2017-07-26 18:56:44 +02:00

145 lines
5.2 KiB
C++
Executable File

#pragma once
#include <wfr/common/resource/Resource.h>
#include <wfr/common/types/WfrTypes.h>
#include <mutex>
#include <thread>
#include <memory>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <condition_variable>
namespace wfr {
// Forward declarations
namespace wep {
class WorkflowExecutionPlan;
class AtomicWepNode;
}
namespace enactment {
class EnactmentEngine;
}
namespace execution {
class ExecutionManager;
}
namespace prediction {
class PredictionManager;
}
namespace resource {
class ResourceManager;
}
// Main namespace
namespace scheduling {
// Forward declaration
class SchedulingDecision;
/*
* Represents the interface every scheduler needs to implement.
*
* Workflow execution sequence:
* 1) registerWEP() is called by enactment engine to register new workflow instance
* 2) notifyWEPUpdate() is called by enactment engine to notify scheduler of workflow progress
* 3) The scheduler creates scheduling decisions objects and passes them to the execution layer
* - uses convenience function SchedulerBase::executeSchedulingDecision, or
* - directly calls ExecutionManager::executeSchedulingDecision
* 4) The execution layer calls notifySchedulingDecisionStatusUpdate to notify scheduler about executed (or failed) activities.
* - the scheduler needs then to call EnactmentEngine::notifyActivityInstanceStateUpdate() to notify the enactment engine.
* - SchedulerBase already automatically notifies the enactment engine.
* 5) Goto 2) till unregisterWEP() is called.
*/
class AbstractScheduler {
public:
virtual ~AbstractScheduler() noexcept {}
/*
* Is called by the enactment engine to let the scheduler know of a new workflow instance.
*
* @param wep workflow execution plan object representing the workflow instance
* @param ee reference to enactment engine
*/
virtual void registerWEP(wep::WorkflowExecutionPlan& wep, enactment::EnactmentEngine& ee) noexcept = 0;
/*
* Is called by the enactment engine to let the scheduler know that a workflow instance has finished
*
* @param wep workflow execution plan object representing the workflow instance
*/
virtual void unregisterWEP(wep::WorkflowExecutionPlan& wep) noexcept = 0;
/*
* Is called by the enactment engine to let the scheduler know about changes to the workflow execution plan.
*
* @param wep workflow execution plan object representing the workflow instance
* @param readytoExecute set of new ready-to-execute activities (for convenience)
*/
virtual void notifyWEPUpdate(wep::WorkflowExecutionPlan& wep, std::set<wep::AtomicWepNode*> readyToExecute) noexcept = 0;
/*
* Called by the execution layer to notify the scheduler that an activity finished (or failed) execution.
*
* @param sd reference to scheduling decision object.
*/
virtual void notifySchedulingDecisionStatusUpdate(std::shared_ptr<SchedulingDecision> sd) noexcept = 0;
virtual double getCummulativePredictionTime() noexcept = 0;
};
/*
* Scheduler base class implementing common scheduler functionality.
*/
class SchedulerBase : public AbstractScheduler {
public:
struct WepMapEntry {
WepMapEntry(enactment::EnactmentEngine* engine, wep::WorkflowExecutionPlan* wep)
: engine(engine), wep(wep) {}
enactment::EnactmentEngine* engine;
wep::WorkflowExecutionPlan* wep;
std::set<std::shared_ptr<SchedulingDecision>> decisions;
void* userData = nullptr;
};
protected:
typedef std::map<wep::WorkflowExecutionPlan*, WepMapEntry> wepMap_t;
std::mutex schedulerMutex;
wepMap_t wepMap;
bool simulationMode;
double cummulativePredictionTime = 0;
std::map<resource::ComputingResource*, std::vector<std::shared_ptr<SchedulingDecision>>> scheduledTasks;
protected:
// Hook functions for AbstractScheduler functions below to allow customisation of common functionality
virtual void _registerWEP(WepMapEntry& wepe, std::unique_lock<std::mutex>& schedulerLock) {};
virtual void _unregisterWEP(WepMapEntry& wepe, 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 double _getResourceEstimatedAvailableTime(resource::ComputingResource* resource);
// 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;
public:
SchedulerBase();
virtual ~SchedulerBase() noexcept;
// From AbstractScheduler class
virtual void registerWEP(wep::WorkflowExecutionPlan& wep, enactment::EnactmentEngine& ee) noexcept override;
virtual void unregisterWEP(wep::WorkflowExecutionPlan& wep) noexcept override;
virtual void notifyWEPUpdate(wep::WorkflowExecutionPlan& wep, std::set<wep::AtomicWepNode*> readyToExecute) noexcept override;
virtual void notifySchedulingDecisionStatusUpdate(std::shared_ptr<SchedulingDecision> wep) noexcept override;
virtual double getCummulativePredictionTime() noexcept override { return cummulativePredictionTime; }
};
} /* namespace scheduling */
} /* namespace wfr */