LCOV - code coverage report
Current view: top level - Src/Task - SpAbstractTask.hpp (source / functions) Hit Total Coverage
Test: Coverage example Lines: 153 157 97.5 %
Date: 2021-12-02 17:21:05 Functions: 65 68 95.6 %

          Line data    Source code
       1             : ///////////////////////////////////////////////////////////////////////////
       2             : // Spetabaru - Berenger Bramas MPCDF - 2017
       3             : // Under LGPL Licence, please you must read the LICENCE file.
       4             : ///////////////////////////////////////////////////////////////////////////
       5             : #ifndef SPABSTRACTTASK_HPP
       6             : #define SPABSTRACTTASK_HPP
       7             : 
       8             : #include <cassert>
       9             : #include <vector>
      10             : #include <atomic>
      11             : #include <mutex>
      12             : #include <condition_variable>
      13             : #include <unordered_set>
      14             : 
      15             : #include "Utils/SpTimePoint.hpp"
      16             : #include "Utils/SpUtils.hpp"
      17             : #include "Data/SpDataAccessMode.hpp"
      18             : #include "Task/SpPriority.hpp"
      19             : #include "Task/SpProbability.hpp"
      20             : #include "Utils/small_vector.hpp"
      21             : 
      22             : class SpAbstractTaskGraph;
      23             : 
      24             : /** The possible state of a task */
      25             : enum class SpTaskState {
      26             :     NOT_INITIALIZED, //! Is currently being build in the runtime
      27             :     INITIALIZED, //! Has been built, dependences will be checked
      28             :     WAITING_TO_BE_READY, //! Depdences are not ready
      29             :     READY, //! Dependences are ready, the task is in the "ready" list
      30             :     RUNNING, //! The task is currently being computed
      31             :     POST_RUN, //! The task is over, post dependences are checked
      32             :     FINISHED, //! The task is in the "finished" list
      33             : };
      34             : 
      35             : enum class SpTaskActivation{
      36             :     DISABLE,
      37             :     ENABLE
      38             : };
      39             : 
      40             : class SpDataHandle;
      41             : 
      42             : class SpSpecTaskGroup;
      43             : 
      44             : /**
      45             :  * This class is the interface to the real task,
      46             :  * it is used to store the id and terminaison mechanism.
      47             :  */
      48             : class SpAbstractTask{
      49             :     static std::atomic<long int> TaskIdsCounter;
      50             : 
      51             :     //! Current task id
      52             :     const long int taskId;
      53             :     //! Tells if a task has been executed
      54             :     std::atomic_bool hasBeenExecuted;
      55             : 
      56             :     //! Mutex to protected the waiting condition conditionExecuted
      57             :     mutable std::mutex mutexExecuted;
      58             :     //! Should be use to wait for task completion
      59             :     mutable std::condition_variable conditionExecuted;
      60             : 
      61             :     //! To protect critical part of a task
      62             :     std::mutex mutexTakeControl;
      63             :     //! Current state of the task
      64             :     std::atomic<SpTaskState> currentState;
      65             : 
      66             :     //! Task name
      67             :     std::string taskName;
      68             : 
      69             :     //! When the task has been created (construction time)
      70             :     SpTimePoint creationTime;
      71             :     //! When a task has been ready
      72             :     SpTimePoint readyTime;
      73             :     //! When the task has been computed (begin)
      74             :     SpTimePoint startingTime;
      75             :     //! When the task has been computed (end)
      76             :     SpTimePoint endingTime;
      77             : 
      78             :     //! The Id of the thread that computed the task
      79             :     long int threadIdComputer;
      80             : 
      81             :     //! Priority
      82             :     SpPriority priority;
      83             : 
      84             :     //! To know if the callback has to be executed
      85             :     std::atomic<SpTaskActivation> isEnabled;
      86             : 
      87             :     void* specTaskGroup;
      88             :     SpAbstractTask* originalTask;
      89             :     
      90             :     SpAbstractTaskGraph* const atg;
      91             : 
      92             : public:
      93        1073 :     explicit SpAbstractTask(SpAbstractTaskGraph* const inAtg, const SpTaskActivation initialAtivationState, const SpPriority& inPriority):
      94        1073 :         taskId(TaskIdsCounter++), hasBeenExecuted(false),
      95             :                                currentState(SpTaskState::NOT_INITIALIZED),
      96             :                                threadIdComputer(-1), priority(inPriority),
      97             :                                isEnabled(initialAtivationState),
      98             :                                specTaskGroup(nullptr),
      99             :                                originalTask(nullptr),
     100        1073 :                                atg(inAtg) {
     101        1073 :     }
     102             : 
     103        1073 :     virtual ~SpAbstractTask(){}
     104             : 
     105             :     //! A task cannot be copied or move
     106             :     SpAbstractTask(const SpAbstractTask&) = delete;
     107             :     SpAbstractTask(SpAbstractTask&&) = delete;
     108             :     SpAbstractTask& operator=(const SpAbstractTask&) = delete;
     109             :     SpAbstractTask& operator=(SpAbstractTask&&) = delete;
     110             : 
     111             :     ///////////////////////////////////////////////////////////////////////////
     112             :     /// Methods to be specialized by sub classes
     113             :     ///////////////////////////////////////////////////////////////////////////
     114             : 
     115             :     virtual long int getNbParams() = 0;
     116             :     virtual bool dependencesAreReady() const = 0;
     117             :     virtual void executeCore(SpCallableType ct) = 0;
     118             :     virtual void releaseDependences(small_vector_base<SpAbstractTask*>* potentialReady) = 0;
     119             :     virtual void getDependences(small_vector_base<SpAbstractTask*>* allDeps) const = 0;
     120             :     virtual void getPredecessors(small_vector_base<SpAbstractTask*>* allPredecessors) const = 0;
     121             :     virtual void useDependences(std::unordered_set<SpDataHandle*>* exceptionList) = 0;
     122             :     virtual bool hasMode(const SpDataAccessMode inMode) const = 0;
     123             :     virtual small_vector<std::pair<SpDataHandle*,SpDataAccessMode>> getDataHandles() const = 0;
     124             :     virtual void executeCallback() = 0;
     125             :     virtual bool hasCallableOfType(const SpCallableType sct) const = 0;
     126             :     virtual std::string getTaskBodyString() = 0;
     127             : 
     128        1073 :     void useDependences() {
     129        1073 :         useDependences(nullptr);
     130        1072 :     }
     131             : 
     132        1073 :     void execute(SpCallableType ct) {
     133        1073 :         startingTime.setToNow();
     134        1073 :         if(isEnabled == SpTaskActivation::ENABLE){
     135         875 :             executeCore(ct);
     136             :         }
     137        1073 :         endingTime.setToNow();
     138             : 
     139             :         {
     140        2146 :             std::unique_lock<std::mutex> locker(mutexExecuted);
     141        1073 :             threadIdComputer = SpUtils::GetThreadId();
     142        1073 :             hasBeenExecuted = true;
     143        1073 :             conditionExecuted.notify_all();
     144             :         }
     145             :         
     146        1073 :         executeCallback();
     147        1073 :     }
     148             : 
     149             :     ///////////////////////////////////////////////////////////////////////////
     150             :     /// Getter methods
     151             :     ///////////////////////////////////////////////////////////////////////////
     152             : 
     153        2254 :     int getPriority() const{
     154        2254 :         return priority.getPriority();
     155             :     }
     156             : 
     157             :     const SpPriority& getPriorityObject() const{
     158             :         return priority;
     159             :     }
     160             : 
     161       29015 :     long int getId() const{
     162       29015 :         return taskId;
     163             :     }
     164             : 
     165        3042 :     long int getThreadIdComputer() const{
     166        3042 :         return threadIdComputer;
     167             :     }
     168             : 
     169             :     //! Will return only when the task will be over
     170          10 :     void wait() const {
     171          10 :         if(hasBeenExecuted == false){
     172          16 :             std::unique_lock<std::mutex> locker(mutexExecuted);
     173          24 :             conditionExecuted.wait(locker, [&]{ return bool(hasBeenExecuted);});
     174             :         }
     175          10 :     }
     176             : 
     177        7235 :     SpTaskState getState() const {
     178        7235 :         return currentState;
     179             :     }
     180             : 
     181        6437 :     void setState(SpTaskState inState) {
     182        6437 :         currentState = inState;
     183        6437 :         if(SpTaskState::READY == currentState){
     184        1073 :             readyTime.setToNow();
     185             :         }
     186        6436 :     }
     187             : 
     188        7230 :     bool isState(SpTaskState inState) const{
     189        7230 :         return getState() == inState;
     190             :     }
     191             : 
     192         507 :     bool isOver() const{
     193         507 :         return hasBeenExecuted;
     194             :     }
     195             : 
     196          46 :     bool canTakeControl(){
     197          46 :         return mutexTakeControl.try_lock();
     198             :     }
     199             : 
     200        4516 :     void takeControl(){
     201        4516 :         return mutexTakeControl.lock();
     202             :     }
     203             : 
     204        4558 :     void releaseControl(){
     205        4558 :         mutexTakeControl.unlock();
     206        4558 :     }
     207             : 
     208             :     //! Will return true even if the task is over
     209           5 :     bool isReady() const{
     210           5 :         return SpTaskState::READY <= getState();
     211             :     }
     212             : 
     213             :     // Not const ref because of the original name build on the fly
     214        3766 :     std::string getTaskName() const{
     215        3766 :         if(originalTask){
     216         503 :             return originalTask->taskName + "'";
     217             :         }
     218             :         else{
     219        3263 :             return taskName;
     220             :         }
     221             :     }
     222             : 
     223        1712 :     void setTaskName(const std::string& inTaskName){
     224        1712 :         taskName = inTaskName;
     225        1712 :     }
     226             : 
     227         599 :     const SpTimePoint& getCreationTime() const{
     228         599 :         return creationTime;
     229             :     }
     230         599 :     const SpTimePoint& getReadyTime() const{
     231         599 :         return readyTime;
     232             :     }
     233        3042 :     const SpTimePoint& getStartingTime() const{
     234        3042 :         return startingTime;
     235             :     }
     236        2396 :     const SpTimePoint& getEndingTime() const{
     237        2396 :         return endingTime;
     238             :     }
     239             : 
     240        1370 :     bool isTaskEnabled() const{
     241        1370 :         return isEnabled == SpTaskActivation::ENABLE;
     242             :     }
     243             :     
     244           0 :     virtual void setEnabledDelegate(const SpTaskActivation inIsEnable) {
     245           0 :         setEnabled(inIsEnable);
     246           0 :     }
     247             : 
     248         121 :     void setEnabled(const SpTaskActivation inIsEnable) {
     249         121 :         isEnabled = inIsEnable;
     250         121 :     }
     251             : 
     252          46 :     void setDisabledIfNotOver(){
     253          46 :         if(canTakeControl()){
     254          42 :             if(isOver() == false){
     255          35 :                 isEnabled = SpTaskActivation::DISABLE;
     256             :             }
     257          42 :             releaseControl();
     258             :         }
     259          46 :     }
     260             : 
     261             :     template <class SpSpecGroupType>
     262         912 :     void setSpecGroup(SpSpecGroupType* inSpecTaskGroup){
     263         912 :         specTaskGroup = inSpecTaskGroup;
     264         912 :     }
     265             : 
     266             :     template <class SpSpecGroupType>
     267        1313 :     SpSpecGroupType* getSpecGroup(){
     268        1313 :         return reinterpret_cast<SpSpecGroupType*>(specTaskGroup);
     269             :     }
     270             : 
     271         109 :     void setOriginalTask(SpAbstractTask* inOriginal){
     272         109 :         originalTask = inOriginal;
     273         109 :     }
     274             : 
     275         430 :     bool isEnable() const{
     276         430 :         return isEnabled == SpTaskActivation::ENABLE;
     277             :     }
     278             :     
     279        1073 :     SpAbstractTaskGraph* getAbstractTaskGraph() {
     280        1073 :         return atg;
     281             :     }
     282             : };
     283             : 
     284             : 
     285             : ///////////////////////////////////////////////////////////////////////////
     286             : /// Specialization for tasks that return a value
     287             : ///////////////////////////////////////////////////////////////////////////
     288             : 
     289             : 
     290             : #include <future>
     291             : #include <functional>
     292             : 
     293             : //! If the return type is not void
     294             : template <class RetType>
     295             : class SpAbstractTaskWithReturn : public SpAbstractTask {
     296             : public:
     297             : 
     298             :     class SpTaskViewer{
     299             :         SpAbstractTaskWithReturn<RetType>* target;
     300             :         
     301         407 :         SpTaskViewer(SpAbstractTaskWithReturn<RetType>* inTarget) : target(inTarget){}
     302             :     public:
     303             :         SpTaskViewer() : target(nullptr) {}
     304             :         SpTaskViewer(const SpTaskViewer&) = default;
     305             :         SpTaskViewer(SpTaskViewer&&) = default;
     306             :         SpTaskViewer& operator=(const SpTaskViewer&) = default;
     307             :         SpTaskViewer& operator=(SpTaskViewer&&) = default;
     308             : 
     309           2 :         void wait() const {
     310           2 :             target->wait();
     311           2 :         }
     312             : 
     313             :         bool isOver() const{
     314             :             return target->isOver();
     315             :         }
     316             : 
     317             :         bool isReady() const{
     318             :             return target->isReady();
     319             :         }
     320             : 
     321           4 :         RetType getValue() const{
     322           4 :             return target->getValue();
     323             :         }
     324             : 
     325             :         // Not const ref because of the original name build on the fly
     326             :         std::string getTaskName() const{
     327             :             return target->getTaskName();
     328             :         }
     329             : 
     330          36 :         void setTaskName(const std::string& inTaskName){
     331          36 :             target->setTaskName(inTaskName);
     332          36 :         }
     333             : 
     334         921 :         SpAbstractTask* getTaskPtr(){
     335         921 :             return target;
     336             :         }
     337             : 
     338         183 :         void addCallback(std::function<void(const bool, const RetType&, SpTaskViewer&, const bool)> func){
     339         183 :             target->addCallback(std::move(func));
     340         183 :         }
     341             : 
     342          85 :         void setOriginalTask(SpAbstractTask* inOriginal){// For speculation
     343          85 :             target->setOriginalTask(inOriginal);
     344          85 :         }
     345             : 
     346             :         bool hasCallableOfType(const SpCallableType sct) const {
     347             :             return target->hasCallableOfType(sct);
     348             :         }
     349             : 
     350             :         friend SpAbstractTaskWithReturn;
     351             :     };
     352             : private:
     353             :     RetType resultValue;
     354             : 
     355             :     std::mutex mutexCallbacks;
     356             :     small_vector<std::function<void(const bool, const RetType&, SpTaskViewer&, const bool)>> callbacks;
     357             : 
     358             : public:
     359         199 :     explicit SpAbstractTaskWithReturn(SpAbstractTaskGraph* const inAtg, const SpTaskActivation initialAtivationState, const SpPriority& inPriority):
     360         199 :         SpAbstractTask(inAtg, initialAtivationState, inPriority), resultValue(){
     361         199 :     }
     362             : 
     363           4 :     const RetType& getValue() const {
     364           4 :         wait();
     365           4 :         return resultValue;
     366             :     }
     367             : 
     368         126 :     void setValue(RetType&& inValue){
     369         126 :         resultValue = std::move(inValue);
     370         126 :     }
     371             : 
     372         199 :     void executeCallback() final{
     373         398 :         std::unique_lock<std::mutex> locker(mutexCallbacks);
     374         199 :         SpTaskViewer viewer(this);
     375         373 :         for(auto& func : callbacks){
     376         174 :             func(false, resultValue, viewer, isEnable());
     377             :         }
     378         199 :     }
     379             : 
     380         183 :     void addCallback(std::function<void(const bool, const RetType&, SpTaskViewer&, const bool)> func){
     381         366 :         std::unique_lock<std::mutex> locker(mutexCallbacks);
     382         183 :         if(isOver() == false){
     383         174 :             callbacks.emplace_back(std::move(func));
     384             :         }
     385             :         else{
     386           9 :             SpTaskViewer viewer(this);
     387           9 :             func(true, resultValue,viewer, isEnable());
     388             :         }
     389         183 :     }
     390             : 
     391             : 
     392         199 :     SpTaskViewer getViewer() {
     393         199 :         return SpTaskViewer(this);
     394             :     }
     395             : };
     396             : 
     397             : //! If the return type is void
     398             : template <>
     399             : class SpAbstractTaskWithReturn<void> : public SpAbstractTask {
     400             : public:
     401             : 
     402             :     class SpTaskViewer{
     403             :         SpAbstractTaskWithReturn<void>* target;
     404             : 
     405        1748 :         SpTaskViewer(SpAbstractTaskWithReturn<void>* inTarget) : target(inTarget){}
     406             :     public:
     407             :         SpTaskViewer() : target(nullptr) {}
     408             :         SpTaskViewer(const SpTaskViewer&) = default;
     409             :         SpTaskViewer(SpTaskViewer&&) = default;
     410             :         SpTaskViewer& operator=(const SpTaskViewer&) = default;
     411             :         SpTaskViewer& operator=(SpTaskViewer&&) = default;
     412             : 
     413           4 :         void wait() const {
     414           4 :             target->wait();
     415           4 :         }
     416             : 
     417             :         bool isOver() const{
     418             :             return target->isOver();
     419             :         }
     420             : 
     421           5 :         bool isReady() const{
     422           5 :             return target->isReady();
     423             :         }
     424             : 
     425           2 :         void getValue() {
     426           2 :             wait();
     427           2 :         }
     428             : 
     429             :         // Not const ref because of the original name build on the fly
     430             :         std::string getTaskName() const{
     431             :             return target->getTaskName();
     432             :         }
     433             : 
     434         603 :         void setTaskName(const std::string& inTaskName){
     435         603 :             target->setTaskName(inTaskName);
     436         603 :         }
     437             : 
     438        1069 :         SpAbstractTask* getTaskPtr(){
     439        1069 :             return target;
     440             :         }
     441             : 
     442             :         void addCallback(std::function<void(const bool, SpTaskViewer&, const bool)> func){
     443             :             target->addCallback(std::move(func));
     444             :         }
     445             : 
     446             : 
     447          24 :         void setOriginalTask(SpAbstractTask* inOriginal){// For speculation
     448          24 :             target->setOriginalTask(inOriginal);
     449          24 :         }
     450             :         
     451             :         bool hasCallableOfType(const SpCallableType sct) const {
     452             :             return target->hasCallableOfType(sct);
     453             :         }
     454             : 
     455             :         friend SpAbstractTaskWithReturn;
     456             :     };
     457             : private:
     458             :     std::mutex mutexCallbacks;
     459             :     small_vector<std::function<void(const bool, SpTaskViewer&, const bool)>> callbacks;
     460             : 
     461             : public:
     462             :     using SpAbstractTask::SpAbstractTask;
     463             : 
     464             :     void setValue(void) = delete;
     465             : 
     466         874 :     void executeCallback() final{
     467        1748 :         std::unique_lock<std::mutex> locker(mutexCallbacks);
     468         874 :         SpTaskViewer viewer(this);
     469         874 :         for(auto& func : callbacks){
     470           0 :             func(false, viewer, isEnable());
     471             :         }
     472         874 :     }
     473             : 
     474             :     void addCallback(std::function<void(const bool, SpTaskViewer&, const bool)> func){
     475             :         std::unique_lock<std::mutex> locker(mutexCallbacks);
     476             :         if(isOver() == false){
     477             :             callbacks.emplace_back(std::move(func));
     478             :         }
     479             :         else{
     480             :             SpTaskViewer viewer(this);
     481             :             func(true,viewer, isEnable());
     482             :         }
     483             :     }
     484             : 
     485         874 :     SpTaskViewer getViewer() {
     486         874 :         return SpTaskViewer(this);
     487             :     }
     488             : };
     489             : 
     490             : 
     491             : #endif

Generated by: LCOV version 1.14