ptr.h
Go to the documentation of this file.
1 #ifndef TTG_PARSEC_PTR_H
2 #define TTG_PARSEC_PTR_H
3 
4 #include <unordered_map>
5 #include <mutex>
6 
9 #include "ttg/parsec/task.h"
10 
11 namespace ttg_parsec {
12 
13  // fwd decl
14  template<typename T>
15  struct ptr;
16 
17  namespace detail {
18  /* fwd decl */
19  template <typename Value>
20  inline ttg_data_copy_t *create_new_datacopy(Value &&value);
21 
22  struct ptr_impl {
24 
25  private:
26  static inline std::unordered_map<ptr_impl*, bool> m_ptr_map;
27  static inline std::mutex m_ptr_map_mtx;
28 
29  copy_type *m_copy = nullptr;
30 
31  void drop_copy() {
32  std::cout << "ptr drop_copy " << m_copy << " ref " << m_copy->num_ref() << std::endl;
33  if (nullptr != m_copy && 1 == m_copy->drop_ref()) {
34  delete m_copy;
35  }
36  m_copy = nullptr;
37  }
38 
39  void register_self() {
40  /* insert ourselves from the list of ptr */
41  std::lock_guard _{m_ptr_map_mtx};
42  m_ptr_map.insert(std::pair{this, true});
43  }
44 
45  void deregister_self() {
46  /* remove ourselves from the list of ptr */
47  std::lock_guard _{m_ptr_map_mtx};
48  if (m_ptr_map.contains(this)) {
49  m_ptr_map.erase(this);
50  }
51  }
52 
53  public:
55  : m_copy(copy)
56  {
57  register_self();
58  m_copy->add_ref();
59  std::cout << "ptr copy_obj ref " << m_copy->num_ref() << std::endl;
60  }
61 
62  copy_type* get_copy() const {
63  return m_copy;
64  }
65 
66  ptr_impl(const ptr_impl& p)
67  : m_copy(p.m_copy)
68  {
69  register_self();
70  m_copy->add_ref();
71  std::cout << "ptr cpy " << m_copy << " ref " << m_copy->num_ref() << std::endl;
72  }
73 
75  : m_copy(p.m_copy)
76  {
77  register_self();
78  p.m_copy = nullptr;
79  std::cout << "ptr mov " << m_copy << " ref " << m_copy->num_ref() << std::endl;
80  }
81 
83  deregister_self();
84  drop_copy();
85  }
86 
88  {
89  drop_copy();
90  m_copy = p.m_copy;
91  m_copy->add_ref();
92  std::cout << "ptr cpy " << m_copy << " ref " << m_copy->num_ref() << std::endl;
93  return *this;
94  }
95 
97  drop_copy();
98  m_copy = p.m_copy;
99  p.m_copy = nullptr;
100  std::cout << "ptr mov " << m_copy << " ref " << m_copy->num_ref() << std::endl;
101  return *this;
102  }
103 
104  bool is_valid() const {
105  return (nullptr != m_copy);
106  }
107 
108  void reset() {
109  drop_copy();
110  }
111 
112  /* drop all currently registered ptr
113  * \note this function is not thread-safe
114  * and should only be called at the
115  * end of the execution, e.g., during finalize.
116  */
117  static void drop_all_ptr() {
118  for(auto it : m_ptr_map) {
119  it.first->drop_copy();
120  }
121  }
122  };
123 
124 
125  template<typename T>
127  } // namespace detail
128 
129  // fwd decl
130  template<typename T, typename... Args>
131  Ptr<T> make_ptr(Args&&... args);
132 
133  // fwd decl
134  template<typename T>
135  inline Ptr<std::decay_t<T>> get_ptr(T&& obj);
136 
137  template<typename T>
138  struct Ptr {
139 
140  using value_type = std::decay_t<T>;
141 
142  private:
144 
145  std::unique_ptr<detail::ptr_impl> m_ptr;
146 
147  /* only PaRSEC backend functions are allowed to touch our private parts */
148  template<typename... Args>
149  friend Ptr<T> make_ptr(Args&&... args);
150  template<typename S>
151  friend Ptr<std::decay_t<S>> get_ptr(S&& obj);
152  template<typename S>
155 
156  /* only accessible by get_ptr and make_ptr */
158  : m_ptr(new detail::ptr_impl(copy))
159  { }
160 
161  copy_type* get_copy() const {
162  return static_cast<copy_type*>(m_ptr->get_copy());
163  }
164 
165  public:
166 
167  Ptr() = default;
168 
169  Ptr(const Ptr& p)
170  : Ptr(p.get_copy())
171  { }
172 
173  Ptr(Ptr&& p) = default;
174 
175  ~Ptr() = default;
176 
177  Ptr& operator=(const Ptr& p) {
178  m_ptr.reset(new detail::ptr_impl(p.get_copy()));
179  return *this;
180  }
181 
182  Ptr& operator=(Ptr&& p) = default;
183 
185  return **static_cast<copy_type*>(m_ptr->get_copy());
186  }
187 
189  return **static_cast<copy_type*>(m_ptr->get_copy());
190  }
191 
192  bool is_valid() const {
193  return m_ptr && m_ptr->is_valid();
194  }
195 
196  void reset() {
197  m_ptr.reset();
198  }
199  };
200 
201 #if 0
202  namespace detail {
203  template<typename Arg>
204  inline auto get_ptr(Arg&& obj) {
205 
206  for (int i = 0; i < detail::parsec_ttg_caller->data_count; ++i) {
207  detail::ttg_data_copy_t *copy = detail::parsec_ttg_caller->copies[i];
208  if (nullptr != copy) {
209  if (copy->get_ptr() == &obj) {
210  bool is_ready = true;
211  /* TODO: how can we force-sync host and device? Current data could be on either. */
212 #if 0
213  /* check all tracked device data for validity */
214  for (auto it : copy) {
215  parsec_data_t *data = *it;
216  for (int i = 0; i < parsec_nb_devices; ++i) {
217  if (nullptr != data->device_copies[i]) {
218 
219  } else {
220  is_ready = false;
221  }
222  }
223  }
224 #endif // 0
225  return std::make_pair(is_ready, std::tuple{ttg_parsec::ptr<std::decay_t<Arg>>(copy)});
226  }
227  }
228  }
229 
230  throw std::runtime_error("ttg::get_ptr called on an unknown object!");
231  }
232  }
233 
234  template<typename... Args>
235  inline std::pair<bool, std::tuple<ptr<std::decay_t<Args>>...>> get_ptr(Args&&... args) {
236  if (nullptr == detail::parsec_ttg_caller) {
237  throw std::runtime_error("ttg::get_ptr called outside of a task!");
238  }
239 
240  bool ready = true;
241  auto fn = [&](auto&& arg){
242  auto pair = get_ptr(std::forward<decltype(arg)>(arg));
243  ready &= pair.first;
244  return std::move(pair.second);
245  };
246  std::tuple<ptr<std::decay_t<Args>>...> tpl = {(fn(std::forward<Args>(args)))...};
247  return {ready, std::move(tpl)};
248  }
249 #endif // 0
250 
251  template<typename T>
252  inline Ptr<std::decay_t<T>> get_ptr(T&& obj) {
253  using ptr_type = Ptr<std::decay_t<T>>;
254  if (nullptr != detail::parsec_ttg_caller) {
255  for (int i = 0; i < detail::parsec_ttg_caller->data_count; ++i) {
257  if (nullptr != copy) {
258  if (copy->get_ptr() == &obj) {
259  return ptr_type(copy);
260  }
261  }
262  }
263  }
264  /* object not tracked, make a new ptr that is now tracked */
266  return ptr_type(copy);
267  }
268 
269  template<typename T, typename... Args>
270  inline Ptr<T> make_ptr(Args&&... args) {
271  detail::ttg_data_copy_t *copy = detail::create_new_datacopy(T(std::forward<Args>(args)...));
272  return Ptr<T>(copy);
273  }
274 
275  namespace detail {
276  template<typename T>
278  return p.get_copy();
279  }
280  } // namespace detail
281 
282 } // namespace ttg_parsec
283 
284 #endif // TTG_PARSEC_PTR_H
constexpr auto data(C &c) -> decltype(c.data())
Definition: span.h:189
ttg_parsec::detail::ttg_data_copy_t * get_copy(ttg_parsec::Ptr< T > &p)
Definition: ptr.h:277
ttg_data_copy_t * create_new_datacopy(Value &&value)
Definition: ttg.h:705
thread_local parsec_ttg_task_base_t * parsec_ttg_caller
Definition: thread_local.h:12
this contains PaRSEC-based TTG functionality
Definition: fwd.h:18
Ptr< std::decay_t< T > > get_ptr(T &&obj)
Definition: ptr.h:252
Ptr< T > make_ptr(Args &&... args)
Definition: ptr.h:270
value_type & operator*() const
Definition: ptr.h:184
bool is_valid() const
Definition: ptr.h:192
Ptr(Ptr &&p)=default
friend Ptr< std::decay_t< S > > get_ptr(S &&obj)
~Ptr()=default
value_type & operator->() const
Definition: ptr.h:188
Ptr & operator=(const Ptr &p)
Definition: ptr.h:177
void reset()
Definition: ptr.h:196
Ptr & operator=(Ptr &&p)=default
Ptr(const Ptr &p)
Definition: ptr.h:169
friend Ptr< T > make_ptr(Args &&... args)
Definition: ptr.h:270
std::decay_t< T > value_type
Definition: ptr.h:140
static void drop_all_ptr()
Definition: ptr.h:117
bool is_valid() const
Definition: ptr.h:104
ptr_impl(ptr_impl &&p)
Definition: ptr.h:74
ptr_impl(copy_type *copy)
Definition: ptr.h:54
ptr_impl(const ptr_impl &p)
Definition: ptr.h:66
ptr_impl & operator=(const ptr_impl &p)
Definition: ptr.h:87
copy_type * get_copy() const
Definition: ptr.h:62
ptr_impl & operator=(ptr_impl &&p)
Definition: ptr.h:96