abstract_task.cpp 2.63 KB
Newer Older
1
#include <pls/internal/base/backoff.h>
2
#include "pls/internal/helpers/profiler.h"
3

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

namespace pls {
9 10
namespace internal {
namespace scheduling {
11

12
bool abstract_task::steal_work() {
13 14
  thread_local static base::backoff backoff{};

15 16 17
  PROFILE_STEALING("abstract_task::steal_work")
  const auto my_state = base::this_thread::state<thread_state>();
  const auto my_scheduler = my_state->scheduler_;
18

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

29 30 31
    if (!target_state->lock_.reader_try_lock()) {
      continue;
    }
32

33 34 35 36
    // Dig down to our level
    PROFILE_STEALING("Go to our level")
    abstract_task *current_task = target_state->root_task_;
    while (current_task != nullptr && current_task->depth() < depth()) {
37
      current_task = current_task->child();
38 39
    }
    PROFILE_END_BLOCK
40

41 42 43 44 45 46 47 48
    // Try to steal 'internal', e.g. for_join_sub_tasks in a fork_join_task constellation
    PROFILE_STEALING("Internal Steal")
    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
49
          target_state->lock_.reader_unlock();
50
          backoff.reset();
51 52
          return true;
        }
53

54
        // No success, we need to steal work from a deeper level using 'top level task stealing'
55
        current_task = current_task->child();
56 57 58
      }
    }
    PROFILE_END_BLOCK;
59 60


61 62 63 64 65 66
    // Execute 'top level task steal' if possible
    // (only try deeper tasks to keep depth restricted stealing).
    PROFILE_STEALING("Top Level Steal")
    while (current_task != nullptr) {
      auto lock = &target_state->lock_;
      if (current_task->split_task(lock)) {
67
        // top level steal was a success (we did a top level task steal)
68
        backoff.reset();
69 70
        return false;
      }
71

72
      current_task = current_task->child_task_;
73
    }
74
    PROFILE_END_BLOCK;
75
    target_state->lock_.reader_unlock();
76 77 78
  }

  // internal steal was no success
79
  backoff.do_backoff();
80 81 82 83 84
  return false;
}

}
}
85
}