abstract_task.cpp 3.35 KB
Newer Older
1
#include "pls/internal/helpers/profiler.h"
2

3
#include "pls/internal/scheduling/thread_state.h"
4
#include "pls/internal/scheduling/abstract_task.h"
5
#include "pls/internal/scheduling/scheduler.h"
6 7 8 9

namespace pls {
    namespace internal {
        namespace scheduling {
10
            bool abstract_task::steal_work() {
11
                PROFILE_STEALING("abstract_task::steal_work")
12 13
                const auto my_state = base::this_thread::state<thread_state>();
                const auto my_scheduler = my_state->scheduler_;
14

15 16 17 18 19 20 21 22
                const size_t my_id = my_state->id_;
                const size_t offset = my_state->random_() % my_scheduler->num_threads();
                const size_t max_tries = 1; // my_scheduler->num_threads(); TODO: Tune this value
                for (size_t i = 0; i < max_tries; i++) {
                    size_t target = (offset + i) % my_scheduler->num_threads();
                    if (target == my_id) {
                        continue;
                    }
23
                    auto target_state = my_scheduler->thread_state_for(target);
24 25 26

                    // TODO: Cleaner Locking Using std::guarded_lock
                    target_state->lock_.lock();
27 28

                    // Dig down to our level
29
                    PROFILE_STEALING("Go to our level")
30 31 32 33
                    abstract_task* current_task = target_state->root_task_;
                    while (current_task != nullptr && current_task->depth() < depth()) {
                        current_task = current_task->child_task_;
                    }
34
                    PROFILE_END_BLOCK
35

FritzFlorian committed
36
                    // Try to steal 'internal', e.g. for_join_sub_tasks in a fork_join_task constellation
37
                    PROFILE_STEALING("Internal Steal")
38 39 40 41 42 43
                    if (current_task != nullptr) {
                        // See if it equals our type and depth of task
                        if (current_task->unique_id_ == unique_id_ &&
                            current_task->depth_ == depth_) {
                            if (internal_stealing(current_task)) {
                                // internal steal was a success, hand it back to the internal scheduler
44
                                target_state->lock_.unlock();
45 46 47 48 49 50 51
                                return true;
                            }

                            // No success, we need to steal work from a deeper level using 'top level task stealing'
                            current_task = current_task->child_task_;
                        }
                    }
52
                    PROFILE_END_BLOCK;
53 54 55


                    // Execute 'top level task steal' if possible
FritzFlorian committed
56
                    // (only try deeper tasks to keep depth restricted stealing).
57
                    PROFILE_STEALING("Top Level Steal")
58
                    while (current_task != nullptr) {
59 60
                        auto lock = &target_state->lock_;
                        if (current_task->split_task(lock)) {
61 62 63 64 65 66
                            // internal steal was no success (we did a top level task steal)
                            return false;
                        }

                        current_task = current_task->child_task_;
                    }
67
                    PROFILE_END_BLOCK;
68
                    target_state->lock_.unlock();
69 70 71 72 73
                }

                // internal steal was no success
                return false;
            };
74 75 76
        }
    }
}