ttg 1.0.0
Template Task Graph (TTG): flowgraph-based programming model for high-performance distributed-memory algorithms
Loading...
Searching...
No Matches
task.h
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2#ifndef TTG_PARSEC_TASK_H
3#define TTG_PARSEC_TASK_H
4
6
7#include <memory>
8#include <vector>
9
10#include <parsec/parsec_internal.h>
11#include <parsec/mca/device/device_gpu.h>
12
13namespace ttg_parsec {
14
15 namespace detail {
16
17 struct device_ptr_t {
18 parsec_gpu_task_t* gpu_task = nullptr;
19 parsec_flow_t* flows = nullptr;
20 parsec_gpu_exec_stream_t* stream = nullptr;
21 parsec_device_gpu_module_t* device = nullptr;
22 parsec_task_class_t task_class; // copy of the taskclass
23 };
24
25 template<bool SupportDevice>
27 {
28 static constexpr bool support_device = false;
29 static constexpr size_t num_flows = 0;
32 static constexpr device_ptr_t* dev_ptr() {
33 return nullptr;
34 }
35 };
36
37 template<>
38 struct device_state_t<true> {
39 static constexpr bool support_device = false;
40 static constexpr size_t num_flows = MAX_PARAM_COUNT;
41 parsec_flow_t m_flows[num_flows];
42 device_ptr_t m_dev_ptr = {nullptr, &m_flows[0], nullptr, nullptr}; // gpu_task will be allocated in each task
44 return &m_dev_ptr;
45 }
46 };
47
48 enum class ttg_parsec_data_flags : uint8_t {
49 NONE = 0,
50 SINGLE_READER = 1 << 0,
51 MULTIPLE_READER = 1 << 1,
52 SINGLE_WRITER = 1 << 2,
53 MULTIPLE_WRITER = 1 << 3,
54 IS_MODIFIED = 1 << 4,
55 MARKED_PUSHOUT = 1 << 5
56 };
57
58 inline
60 using flags_type = std::underlying_type<ttg_parsec_data_flags>::type;
61 return ttg_parsec_data_flags(static_cast<flags_type>(lhs) | static_cast<flags_type>(rhs));
62 }
63
64 inline
66 using flags_type = std::underlying_type<ttg_parsec_data_flags>::type;
67 lhs = ttg_parsec_data_flags(static_cast<flags_type>(lhs) | static_cast<flags_type>(rhs));
68 return lhs;
69 }
70
71 inline
73 using flags_type = std::underlying_type<ttg_parsec_data_flags>::type;
74 return static_cast<flags_type>(lhs) & static_cast<flags_type>(rhs);
75 }
76
77 inline
79 using flags_type = std::underlying_type<ttg_parsec_data_flags>::type;
80 lhs = ttg_parsec_data_flags(static_cast<flags_type>(lhs) & static_cast<flags_type>(rhs));
81 return lhs;
82 }
83
84 inline
86 using flags_type = std::underlying_type<ttg_parsec_data_flags>::type;
87 return lhs == ttg_parsec_data_flags::NONE;
88 }
89
90
91 typedef parsec_hook_return_t (*parsec_static_op_t)(void *); // static_op will be cast to this type
92
95 explicit atomic_lock_guard(parsec_atomic_lock_t &lock) : m_lock(lock) { parsec_atomic_lock(&m_lock); }
96 ~atomic_lock_guard() { parsec_atomic_unlock(&m_lock); }
99
100 private:
101 parsec_atomic_lock_t &m_lock;
102 };
103
105 parsec_task_t parsec_task;
106 int32_t in_data_count = 0; //< number of satisfied inputs
107 int32_t data_count = 0; //< number of data elements in the copies array
108 ttg_data_copy_t **copies; //< pointer to the fixed copies array of the derived task
109 parsec_hash_table_item_t tt_ht_item = {};
110
112 stream_info_t() { parsec_atomic_lock_init(&reduce_copies_lock); }
113 std::size_t goal;
114 std::size_t size;
115 /* a spinlock rather than std::mutex: every task carries one per input */
116 parsec_atomic_lock_t reduce_copies_lock;
117 std::vector<ttg_data_copy_t*> reduce_copies;
118 std::atomic<std::size_t> reduce_count;
119 };
120
121 protected:
122 template<std::size_t i = 0, typename TT>
123 void init_stream_info_impl(TT *tt, std::array<stream_info_t, TT::numins>& streams) {
124 if constexpr (TT::numins > i) {
125 if (std::get<i>(tt->input_reducers)) {
126 streams[i].goal = tt->static_stream_goal[i];
127 streams[i].size = 0;
128 parsec_atomic_lock_init(&streams[i].reduce_copies_lock);
129 streams[i].reduce_copies.clear();
130 streams[i].reduce_count.store(0, std::memory_order_relaxed);
131 }
132 /* recursion */
133 if constexpr((i + 1) < TT::numins) {
134 init_stream_info_impl<i+1>(tt, streams);
135 }
136 }
137 }
138
139 template<typename TT>
140 void init_stream_info(TT *tt, std::array<stream_info_t, TT::numins>& streams) {
141 init_stream_info_impl<0>(tt, streams);
142 }
143
144 public:
146 /* Poor-mans virtual function
147 * We cannot use virtual inheritance or private visibility because we
148 * need offsetof for the mempool and scheduling.
149 */
152 bool remove_from_hash = true;
153 bool dummy = false;
154 bool defer_writer = TTG_PARSEC_DEFER_WRITER; // whether to defer writer instead of creating a new copy
155 ttg_parsec_data_flags data_flags; // HACKY: flags set by prepare_send and reset by the copy_handler
156
157 /*
158 virtual void release_task() = 0;
159 */
160 //public:
162 release_task_cb(this);
163 }
164
165 protected:
171 parsec_ttg_task_base_t(parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class,
175 , copies(copies)
177 PARSEC_OBJ_CONSTRUCT(&parsec_task, parsec_task_t);
178 PARSEC_LIST_ITEM_SINGLETON(&parsec_task.super);
179 parsec_task.mempool_owner = mempool;
180 parsec_task.task_class = task_class;
181 parsec_task.priority = 0;
182
183 // TODO: can we avoid this?
184 for (int i = 0; i < MAX_PARAM_COUNT; ++i) {
185 this->parsec_task.data[i].data_in = nullptr;
186 this->parsec_task.data[i].data_out = nullptr;
187 }
188 }
189
190 parsec_ttg_task_base_t(parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class,
191 parsec_taskpool_t *taskpool, int32_t priority,
193 release_task_fn *release_fn,
196 , copies(copies)
197 , release_task_cb(release_fn)
199 PARSEC_OBJ_CONSTRUCT(&parsec_task, parsec_task_t);
200 PARSEC_LIST_ITEM_SINGLETON(&parsec_task.super);
201 parsec_task.mempool_owner = mempool;
202 parsec_task.task_class = task_class;
203 parsec_task.status = PARSEC_TASK_STATUS_HOOK;
204 parsec_task.taskpool = taskpool;
205 parsec_task.priority = priority;
206 parsec_task.chore_mask = 1<<0;
207
208 // TODO: can we avoid this?
209 for (int i = 0; i < MAX_PARAM_COUNT; ++i) {
210 this->parsec_task.data[i].data_in = nullptr;
211 this->parsec_task.data[i].data_out = nullptr;
212 }
213 }
214
215 public:
216 void set_dummy(bool d) { dummy = d; }
217 bool is_dummy() { return dummy; }
218 };
219
220 template <typename TT, bool KeyIsVoid = ttg::meta::is_void_v<typename TT::key_type>>
222 using key_type = typename TT::key_type;
223 static constexpr size_t num_streams = TT::numins;
224 /* device tasks may have to store more copies than # of its inputs as their sends are aggregated */
225 static constexpr size_t num_copies = TT::derived_has_device_op() ? static_cast<size_t>(MAX_PARAM_COUNT)
226 : (num_streams+1);
227 TT* tt = nullptr;
229 std::array<stream_info_t, num_streams> streams;
230#ifdef TTG_HAVE_COROUTINE
231 void* suspended_task_address = nullptr; // if not null the function is suspended
233#endif
235 ttg_data_copy_t *copies[num_copies] = { nullptr }; // the data copies tracked by this task
236
237 parsec_ttg_task_t(parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class, TT *tt_ptr)
238 : parsec_ttg_task_base_t(mempool, task_class, num_streams, copies)
239 , tt(tt_ptr) {
240 tt_ht_item.key = pkey();
241 this->dev_ptr = this->dev_state.dev_ptr();
242 // We store the hash of the key and the address where it can be found in locals considered as a scratchpad
243 *(uintptr_t*)&(parsec_task.locals[0]) = 0; //there is no key
244 *(uintptr_t*)&(parsec_task.locals[2]) = 0; //there is no key
245 }
246
247 parsec_ttg_task_t(const key_type& key, parsec_thread_mempool_t *mempool,
248 parsec_task_class_t *task_class, parsec_taskpool_t *taskpool,
249 TT *tt_ptr, int32_t priority)
250 : parsec_ttg_task_base_t(mempool, task_class, taskpool, priority,
252 &release_task, tt_ptr->m_defer_writer)
253 , tt(tt_ptr), key(key) {
254 tt_ht_item.key = pkey();
255 this->dev_ptr = this->dev_state.dev_ptr();
256
257 // We store the hash of the key and the address where it can be found in locals considered as a scratchpad
258 uint64_t hv = ttg::hash<std::decay_t<decltype(key)>>{}(key);
259 *(uintptr_t*)&(parsec_task.locals[0]) = hv;
260 *(uintptr_t*)&(parsec_task.locals[2]) = reinterpret_cast<uintptr_t>(&this->key);
261
263 }
264
275 void destroy() {
276 this->~parsec_ttg_task_t();
277 }
278
279 static void release_task(parsec_ttg_task_base_t* task_base) {
280 parsec_ttg_task_t *task = static_cast<parsec_ttg_task_t*>(task_base);
281 TT *tt = task->tt;
282 tt->release_task(task);
283 }
284
285 template<ttg::ExecutionSpace Space>
286 parsec_hook_return_t invoke_op() {
287 if constexpr (Space == ttg::ExecutionSpace::Host) {
288 return TT::static_op(&this->parsec_task);
289 } else {
290 return TT::device_static_op(&this->parsec_task);
291 }
292 }
293
294 template<ttg::ExecutionSpace Space>
295 parsec_hook_return_t invoke_evaluate() {
296 if constexpr (Space == ttg::ExecutionSpace::Host) {
297 return PARSEC_HOOK_RETURN_DONE;
298 } else {
300 }
301 }
302
303 parsec_key_t pkey() { return reinterpret_cast<parsec_key_t>(&key); }
304 };
305
306 template <typename TT>
308 static constexpr size_t num_streams = TT::numins;
309 TT* tt = nullptr;
310 std::array<stream_info_t, num_streams> streams;
311#ifdef TTG_HAVE_COROUTINE
312 void* suspended_task_address = nullptr; // if not null the function is suspended
314#endif
316 ttg_data_copy_t *copies[num_streams+1] = { nullptr }; // the data copies tracked by this task
317 // +1 for the copy needed during send/bcast
318
319 parsec_ttg_task_t(parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class, TT *tt_ptr)
320 : parsec_ttg_task_base_t(mempool, task_class, num_streams, copies)
321 , tt(tt_ptr) {
322 tt_ht_item.key = pkey();
323 this->dev_ptr = this->dev_state.dev_ptr();
324 }
325
326 parsec_ttg_task_t(parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class,
327 parsec_taskpool_t *taskpool, TT *tt_ptr, int32_t priority)
328 : parsec_ttg_task_base_t(mempool, task_class, taskpool, priority,
330 &release_task, tt_ptr->m_defer_writer)
331 , tt(tt_ptr) {
332 tt_ht_item.key = pkey();
333 this->dev_ptr = this->dev_state.dev_ptr();
335 }
336
347 void destroy() {
348 this->~parsec_ttg_task_t();
349 }
350
351 static void release_task(parsec_ttg_task_base_t* task_base) {
352 parsec_ttg_task_t *task = static_cast<parsec_ttg_task_t*>(task_base);
353 TT *tt = task->tt;
354 tt->release_task(task);
355 }
356
357 template<ttg::ExecutionSpace Space>
358 parsec_hook_return_t invoke_op() {
359 if constexpr (Space == ttg::ExecutionSpace::Host) {
360 return TT::static_op(&this->parsec_task);
361 } else {
362 return TT::device_static_op(&this->parsec_task);
363 }
364 }
365
366 template<ttg::ExecutionSpace Space>
367 parsec_hook_return_t invoke_evaluate() {
368 if constexpr (Space == ttg::ExecutionSpace::Host) {
369 return PARSEC_HOOK_RETURN_DONE;
370 } else {
372 }
373 }
374
375 parsec_key_t pkey() { return 0; }
376 };
377
378
389
390 reducer_task_t(parsec_ttg_task_base_t* task, parsec_thread_mempool_t *mempool,
391 parsec_task_class_t *task_class, parsec_taskpool_t *taskpool,
392 int32_t priority, bool is_first)
393 : parsec_ttg_task_base_t(mempool, task_class, taskpool, priority,
394 0, nullptr,
396 true /* deferred until other readers have completed */)
397 , parent_task(task)
399 {
400 /* store the first 4 integers from the parent task (needed for profiling) */
401 for (int i = 0; i < 4; ++i) {
402 parsec_task.locals[i] = task->parsec_task.locals[i];
403 }
404 }
405
406 static void release_task(parsec_ttg_task_base_t* task_base) {
407 /* reducer tasks have one mutable input so the task can be submitted on the first release */
408 parsec_task_t *vp_task_rings[1] = { &task_base->parsec_task };
409 parsec_execution_stream_t *es = parsec_my_execution_stream();
410 __parsec_schedule_vp(es, vp_task_rings, 0);
411 }
412 };
413
414 } // namespace detail
415
416} // namespace ttg_parsec
417
418#endif // TTG_PARSEC_TASK_H
void release_task(task_t *task, parsec_task_t **task_ring=nullptr)
Definition ttg.h:2731
static constexpr bool derived_has_device_op()
Definition ttg.h:1262
static resultT get(InTuple &&intuple)
Definition ttg.h:1293
keyT key_type
Definition ttg.h:1273
uint8_t operator&(ttg_parsec_data_flags lhs, ttg_parsec_data_flags rhs)
Definition task.h:72
parsec_hook_return_t(* parsec_static_op_t)(void *)
Definition task.h:91
ttg_parsec_data_flags operator|=(ttg_parsec_data_flags &lhs, ttg_parsec_data_flags rhs)
Definition task.h:65
ttg_parsec_data_flags operator&=(ttg_parsec_data_flags &lhs, ttg_parsec_data_flags rhs)
Definition task.h:78
bool operator!(ttg_parsec_data_flags lhs)
Definition task.h:85
ttg_parsec_data_flags operator|(ttg_parsec_data_flags lhs, ttg_parsec_data_flags rhs)
Definition task.h:59
this contains PaRSEC-based TTG functionality
Definition fwd.h:19
TaskCoroutineID
Definition coroutine.h:223
@ Invalid
not a coroutine, i.e. a standard task function, -> void
Computes hash values for objects of type T.
Definition hash.h:82
RAII guard for a PaRSEC spinlock.
Definition task.h:94
atomic_lock_guard(parsec_atomic_lock_t &lock)
Definition task.h:95
atomic_lock_guard(const atomic_lock_guard &)=delete
atomic_lock_guard & operator=(const atomic_lock_guard &)=delete
parsec_gpu_task_t * gpu_task
Definition task.h:18
parsec_task_class_t task_class
Definition task.h:22
parsec_gpu_exec_stream_t * stream
Definition task.h:20
parsec_flow_t * flows
Definition task.h:19
parsec_device_gpu_module_t * device
Definition task.h:21
static constexpr device_ptr_t * dev_ptr()
Definition task.h:32
static constexpr size_t num_flows
Definition task.h:29
static constexpr bool support_device
Definition task.h:28
std::vector< ttg_data_copy_t * > reduce_copies
Definition task.h:117
parsec_ttg_task_base_t(parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class, int data_count, ttg_data_copy_t **copies, bool defer_writer=TTG_PARSEC_DEFER_WRITER)
Definition task.h:171
void() release_task_fn(parsec_ttg_task_base_t *)
Definition task.h:145
void init_stream_info(TT *tt, std::array< stream_info_t, TT::numins > &streams)
Definition task.h:140
void init_stream_info_impl(TT *tt, std::array< stream_info_t, TT::numins > &streams)
Definition task.h:123
ttg_parsec_data_flags data_flags
Definition task.h:155
parsec_hash_table_item_t tt_ht_item
Definition task.h:109
parsec_ttg_task_base_t(parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class, parsec_taskpool_t *taskpool, int32_t priority, int data_count, ttg_data_copy_t **copies, release_task_fn *release_fn, bool defer_writer=TTG_PARSEC_DEFER_WRITER)
Definition task.h:190
parsec_ttg_task_t(parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class, parsec_taskpool_t *taskpool, TT *tt_ptr, int32_t priority)
Definition task.h:326
parsec_ttg_task_t(parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class, TT *tt_ptr)
Definition task.h:319
device_state_t< TT::derived_has_device_op()> dev_state
Definition task.h:315
std::array< stream_info_t, num_streams > streams
Definition task.h:310
static void release_task(parsec_ttg_task_base_t *task_base)
Definition task.h:351
static constexpr size_t num_copies
Definition task.h:225
parsec_hook_return_t invoke_op()
Definition task.h:286
parsec_ttg_task_t(parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class, TT *tt_ptr)
Definition task.h:237
std::array< stream_info_t, num_streams > streams
Definition task.h:229
typename TT::key_type key_type
Definition task.h:222
parsec_ttg_task_t(const key_type &key, parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class, parsec_taskpool_t *taskpool, TT *tt_ptr, int32_t priority)
Definition task.h:247
static constexpr size_t num_streams
Definition task.h:223
parsec_hook_return_t invoke_evaluate()
Definition task.h:295
device_state_t< TT::derived_has_device_op()> dev_state
Definition task.h:234
static void release_task(parsec_ttg_task_base_t *task_base)
Definition task.h:279
ttg_data_copy_t * copies[num_copies]
Definition task.h:235
parsec_ttg_task_base_t * parent_task
Definition task.h:387
reducer_task_t(parsec_ttg_task_base_t *task, parsec_thread_mempool_t *mempool, parsec_task_class_t *task_class, parsec_taskpool_t *taskpool, int32_t priority, bool is_first)
Definition task.h:390
static void release_task(parsec_ttg_task_base_t *task_base)
Definition task.h:406
#define TTG_PARSEC_DEFER_WRITER
Definition ttg.h:14