Itoyori  v0.0.1
serial_loop.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "ityr/common/util.hpp"
4 #include "ityr/ito/ito.hpp"
5 #include "ityr/ori/ori.hpp"
9 
10 namespace ityr {
11 
12 namespace internal {
13 
14 template <typename T, typename = void>
15 struct needs_checkout : public std::false_type {};
16 
17 template <typename T>
18 struct needs_checkout<T, std::enable_if_t<is_global_iterator_v<T>>>
19  : public std::conditional_t<std::is_same_v<typename T::mode, checkout_mode::no_access_t>,
20  std::false_type,
21  std::true_type> {};
22 
23 template <typename T>
24 inline constexpr bool needs_checkout_v = needs_checkout<T>::value;
25 
26 inline auto checkout_global_iterators_aux(std::size_t) {
27  return std::make_tuple(std::make_tuple(), std::make_tuple());
28 }
29 
30 template <typename ForwardIterator, typename... ForwardIterators>
31 inline auto checkout_global_iterators_aux(std::size_t n, ForwardIterator it, ForwardIterators... rest) {
32  ITYR_CHECK(n > 0);
33  if constexpr (needs_checkout_v<ForwardIterator>) {
34  auto&& [cs, it_] = it.checkout_nb(n);
35  auto&& [css, its] = checkout_global_iterators_aux(n, rest...);
36  return std::make_tuple(std::tuple_cat(std::make_tuple(std::move(cs)), std::move(css)),
37  std::tuple_cat(std::make_tuple(it_), its));
38  } else {
39  auto&& [css, its] = checkout_global_iterators_aux(n, rest...);
40  return std::make_tuple(std::move(css),
41  std::tuple_cat(std::make_tuple(it), its));
42  }
43 }
44 
45 template <typename... ForwardIterators>
46 inline auto checkout_global_iterators(std::size_t n, ForwardIterators... its) {
47  auto ret = checkout_global_iterators_aux(n, its...);
49  return ret;
50 }
51 
52 template <typename Op, typename... ForwardIterators>
53 inline void apply_iterators(Op op,
54  std::size_t n,
55  ForwardIterators... its) {
56  for (std::size_t i = 0; i < n; (++i, ..., ++its)) {
57  op(*its...);
58  }
59 }
60 
61 template <typename Op, typename ForwardIterator, typename... ForwardIterators>
62 inline void for_each_aux(const execution::sequenced_policy& policy,
63  Op op,
64  ForwardIterator first,
65  ForwardIterator last,
66  ForwardIterators... firsts) {
67  if constexpr ((needs_checkout_v<ForwardIterator> || ... ||
68  needs_checkout_v<ForwardIterators>)) {
69  // perform automatic checkout for global iterators
70  std::size_t n = std::distance(first, last);
71  std::size_t c = policy.checkout_count;
72 
73  for (std::size_t d = 0; d < n; d += c) {
74  auto n_ = std::min(n - d, c);
75 
76  auto [css, its] = checkout_global_iterators(n_, first, firsts...);
77  std::apply([&](auto&&... args) {
78  apply_iterators(op, n_, std::forward<decltype(args)>(args)...);
79  }, its);
80 
81  ((first = std::next(first, n_)), ..., (firsts = std::next(firsts, n_)));
82  }
83 
84  } else {
85  for (; first != last; (++first, ..., ++firsts)) {
86  op(*first, *firsts...);
87  }
88  }
89 }
90 
91 template <typename Iterator, typename Mode>
92 inline auto convert_to_global_iterator(Iterator it, Mode mode) {
93  if constexpr (is_global_iterator_v<Iterator>) {
94  static_assert(std::is_same_v<typename Iterator::mode, Mode> ||
95  std::is_same_v<typename Iterator::mode, checkout_mode::no_access_t>);
96  return it;
97  } else if constexpr (ori::is_global_ptr_v<Iterator>) {
98  return make_global_iterator(it, mode);
99  } else {
100  return it;
101  }
102 }
103 
104 }
105 
106 template <typename BidirectionalIterator1, typename BidirectionalIteratorD>
107 inline BidirectionalIteratorD
109  BidirectionalIterator1 first1,
110  BidirectionalIterator1 last1,
111  BidirectionalIteratorD first_d) {
112  if constexpr (ori::is_global_ptr_v<BidirectionalIterator1> ||
113  ori::is_global_ptr_v<BidirectionalIteratorD>) {
114  using value_type1 = typename std::iterator_traits<BidirectionalIterator1>::value_type;
115  using value_type_d = typename std::iterator_traits<BidirectionalIteratorD>::value_type;
116  return move_backward(
117  policy,
118  internal::convert_to_global_iterator(first1 , internal::src_checkout_mode_t<value_type1>{}),
119  internal::convert_to_global_iterator(last1 , internal::src_checkout_mode_t<value_type1>{}),
120  internal::convert_to_global_iterator(first_d, internal::dest_checkout_mode_t<value_type_d>{}));
121 
122  } else {
125  internal::for_each_aux(
126  policy,
127  [&](auto&& r1, auto&& d) {
128  d = std::move(r1);
129  },
132  make_reverse_iterator(first_d));
133 
134  return std::prev(first_d, std::distance(first1, last1));
135  }
136 }
137 
138 ITYR_TEST_CASE("[ityr::pattern::serial_loop] move_backward") {
139  ito::init();
140  ori::init();
141 
142  long n = 100000;
143  ori::global_ptr<common::move_only_t> p = ori::malloc_coll<common::move_only_t>(n);
144 
145  root_exec([=] {
146  internal::for_each_aux(
147  execution::sequenced_policy(128),
148  [&](common::move_only_t& mo, long i) {
149  mo = common::move_only_t{i};
150  },
153  count_iterator<long>(0));
154 
155  long offset = 1000;
157  execution::sequenced_policy(128),
158  p, p + n - offset, p + n);
159 
160  internal::for_each_aux(
161  execution::sequenced_policy(128),
162  [&](const common::move_only_t& mo, long i) {
163  if (i < offset) {
164  ITYR_CHECK(mo.value() == -1);
165  } else {
166  ITYR_CHECK(mo.value() == i - offset);
167  }
168  },
171  count_iterator<long>(0));
172  });
173 
174  ori::free_coll(p);
175 
176  ori::fini();
177  ito::fini();
178 }
179 
180 }
#define ITYR_CHECK(cond)
Definition: util.hpp:48
constexpr read_write_t read_write
Read+Write checkout mode.
Definition: checkout_span.hpp:39
constexpr read_t read
Read-only checkout mode.
Definition: checkout_span.hpp:19
ITYR_CONCAT(mode_, ITYR_PROFILER_MODE) mode
Definition: profiler.hpp:257
va_list args
Definition: util.hpp:76
void fini()
Definition: ito.hpp:45
void init(MPI_Comm comm=MPI_COMM_WORLD)
Definition: ito.hpp:41
void fini()
Definition: ori.hpp:49
void init(MPI_Comm comm=MPI_COMM_WORLD)
Definition: ori.hpp:45
void free_coll(global_ptr< T > ptr)
Definition: ori.hpp:70
void checkout_complete()
Definition: ori.hpp:139
monoid< T, min_functor<>, highest< T > > min
Definition: reducer.hpp:101
Definition: allocator.hpp:16
global_reverse_iterator< global_iterator< T, Mode > > make_reverse_iterator(ori::global_ptr< T > gptr, Mode mode)
Make a reverse iterator for global memory.
Definition: global_iterator.hpp:333
BidirectionalIteratorD move_backward(const execution::sequenced_policy &policy, BidirectionalIterator1 first1, BidirectionalIterator1 last1, BidirectionalIteratorD first_d)
Definition: serial_loop.hpp:108
auto root_exec(Fn &&fn, Args &&... args)
Spawn the root thread (collective).
Definition: root_exec.hpp:47
global_iterator< T, Mode > make_global_iterator(ori::global_ptr< T > gptr, Mode)
Make a global iterator to enable/disable automatic checkout.
Definition: global_iterator.hpp:158
global_move_iterator< global_iterator< T, internal::src_checkout_mode_t< T > > > make_move_iterator(ori::global_ptr< T > gptr)
Make a global iterator for moving objects.
Definition: global_iterator.hpp:258
ForwardIteratorD move(const ExecutionPolicy &policy, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIteratorD first_d)
Move a range to another.
Definition: parallel_loop.hpp:934
Serial execution policy for iterator-based loop functions.
Definition: execution.hpp:16