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