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
|