for_each_impl.h 3.36 KB
Newer Older
1 2 3 4 5

#ifndef PLS_PARALLEL_FOR_IMPL_H
#define PLS_PARALLEL_FOR_IMPL_H

#include "pls/internal/scheduling/scheduler.h"
6
#include "pls/internal/scheduling/thread_state.h"
7
#include "pls/internal/helpers/range.h"
8

9 10
namespace pls {
namespace algorithm {
11
namespace internal {
12

13
template<typename RandomIt, typename Function>
14 15 16 17
void for_each(const RandomIt first,
              const RandomIt last,
              const Function function,
              const long min_elements) {
18 19
  using namespace ::pls::internal::scheduling;

20
  const long num_elements = std::distance(first, last);
21 22 23 24 25 26 27
  if (num_elements <= min_elements) {
    // calculate last elements in loop to avoid overhead
    for (auto current = first; current != last; current++) {
      function(*current);
    }
  } else {
    // Cut in half recursively
28
    const long middle_index = num_elements / 2;
29

30
    scheduler::spawn([first, middle_index, last, &function, min_elements] {
31 32 33 34
      return internal::for_each(first,
                                first + middle_index,
                                function,
                                min_elements);
35 36
    });
    scheduler::spawn([first, middle_index, last, &function, min_elements] {
37 38 39 40 41
      return internal::for_each(first + middle_index,
                                last,
                                function,
                                min_elements);
    });
42
    scheduler::sync();
43 44 45 46
  }
}

}
47

48 49 50 51 52
class dynamic_strategy {
 public:
  explicit dynamic_strategy(const unsigned int tasks_per_thread = 4) : tasks_per_thread_{tasks_per_thread} {};

  long calculate_min_elements(long num_elements) const {
53
    const long num_threads = pls::internal::scheduling::thread_state::get().get_scheduler().num_threads();
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
    return num_elements / (num_threads * tasks_per_thread_);
  }
 private:
  unsigned const int tasks_per_thread_;
};

class fixed_strategy {
 public:
  explicit fixed_strategy(const long min_elements_per_task) : min_elements_per_task_{min_elements_per_task} {};

  long calculate_min_elements(long /*num_elements*/) const {
    return min_elements_per_task_;
  }
 private:
  const long min_elements_per_task_;
};

template<typename RandomIt, typename Function, typename ExecutionStrategy>
72 73 74 75 76 77
void for_each(RandomIt
              first,
              RandomIt last,
              const Function &function,
              ExecutionStrategy
              execution_strategy) {
78
  long num_elements = std::distance(first, last);
79
  return
80
      internal::for_each(first, last, function, execution_strategy.calculate_min_elements(num_elements));
81 82 83
}

template<typename RandomIt, typename Function>
84
void for_each(RandomIt first, RandomIt last, const Function &function) {
85
  return for_each(first, last, function, dynamic_strategy{4});
86 87 88
}

template<typename Function, typename ExecutionStrategy>
89 90 91 92
void for_each_range(unsigned long first,
                    unsigned long last,
                    const Function &function,
                    ExecutionStrategy execution_strategy) {
93
  auto range = pls::internal::helpers::range(first, last);
94
  return for_each(range.begin(), range.end(), function, execution_strategy);
95 96 97
}

template<typename Function>
98 99 100
void for_each_range(unsigned long first,
                    unsigned long last,
                    const Function &function) {
101
  auto range = pls::internal::helpers::range(first, last);
102
  return for_each(range.begin(), range.end(), function);
103 104 105
}

}
106 107 108
}

#endif //PLS_INVOKE_PARALLEL_IMPL_H