Kokkos Core Kernels Package Version of the Day
Loading...
Searching...
No Matches
Kokkos_Future.hpp
1//@HEADER
2// ************************************************************************
3//
4// Kokkos v. 4.0
5// Copyright (2022) National Technology & Engineering
6// Solutions of Sandia, LLC (NTESS).
7//
8// Under the terms of Contract DE-NA0003525 with NTESS,
9// the U.S. Government retains certain rights in this software.
10//
11// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12// See https://kokkos.org/LICENSE for license information.
13// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14//
15//@HEADER
16
17#include <Kokkos_Macros.hpp>
18
19#ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
20static_assert(false,
21 "Including non-public Kokkos header files is not allowed.");
22#endif
23
24#ifndef KOKKOS_ENABLE_DEPRECATED_CODE_4
25#error "The tasking framework is deprecated"
26#endif
27
28#ifndef KOKKOS_FUTURE_HPP
29#define KOKKOS_FUTURE_HPP
30
31//----------------------------------------------------------------------------
32
33#include <Kokkos_Macros.hpp>
34#if defined(KOKKOS_ENABLE_TASKDAG)
35
36#include <Kokkos_Core_fwd.hpp>
37#include <Kokkos_TaskScheduler_fwd.hpp>
38//----------------------------------------------------------------------------
39
40#include <impl/Kokkos_TaskQueue.hpp>
41#include <impl/Kokkos_TaskResult.hpp>
42#include <impl/Kokkos_TaskBase.hpp>
43#include <Kokkos_Atomic.hpp>
44
45#include <Kokkos_Concepts.hpp> // is_space
46
47//----------------------------------------------------------------------------
48//----------------------------------------------------------------------------
49
50#ifdef KOKKOS_ENABLE_DEPRECATION_WARNINGS
51// We allow using deprecated classes in this file
52KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH()
53#endif
54
55namespace Kokkos {
56
57// For now, hack this in as a partial specialization
58// TODO @tasking @cleanup Make this the "normal" class template and make the old
59// code the specialization
60template <typename ValueType, typename ExecutionSpace, typename QueueType>
61class KOKKOS_DEPRECATED
62 BasicFuture<ValueType, SimpleTaskScheduler<ExecutionSpace, QueueType>> {
63 public:
64 using value_type = ValueType;
65 using execution_space = ExecutionSpace;
66 using scheduler_type = SimpleTaskScheduler<ExecutionSpace, QueueType>;
67 using queue_type = typename scheduler_type::task_queue_type;
68
69 private:
70 template <class, class>
71 friend class SimpleTaskScheduler;
72 template <class, class>
73 friend class BasicFuture;
74
75 using task_base_type = typename scheduler_type::task_base_type;
76 using task_queue_type = typename scheduler_type::task_queue_type;
77
78 using task_queue_traits = typename scheduler_type::task_queue_traits;
79 using task_scheduling_info_type =
80 typename scheduler_type::task_scheduling_info_type;
81
82 using result_storage_type = Impl::TaskResultStorage<
83 ValueType,
84 Impl::SchedulingInfoStorage<Impl::RunnableTaskBase<task_queue_traits>,
85 task_scheduling_info_type>>;
86
87 OwningRawPtr<task_base_type> m_task = nullptr;
88
89 KOKKOS_INLINE_FUNCTION
90 explicit BasicFuture(task_base_type* task) : m_task(task) {
91 // Note: reference count starts at 2 to account for initial increment
92 // TODO @tasking @minor DSH verify reference count here and/or encapsulate
93 // starting reference count closer to here
94 }
95
96 public:
97 KOKKOS_INLINE_FUNCTION
98 BasicFuture() noexcept : m_task(nullptr) {}
99
100 KOKKOS_INLINE_FUNCTION
101 BasicFuture(BasicFuture&& rhs) noexcept : m_task(std::move(rhs.m_task)) {
102 rhs.m_task = nullptr;
103 }
104
105 KOKKOS_INLINE_FUNCTION
106 BasicFuture(BasicFuture const& rhs)
107 // : m_task(rhs.m_task)
108 : m_task(nullptr) {
109 *static_cast<task_base_type* volatile*>(&m_task) = rhs.m_task;
110 if (m_task) m_task->increment_reference_count();
111 }
112
113 KOKKOS_INLINE_FUNCTION
114 BasicFuture& operator=(BasicFuture&& rhs) noexcept {
115 if (m_task != rhs.m_task) {
116 clear();
117 // m_task = std::move(rhs.m_task);
118 *static_cast<task_base_type* volatile*>(&m_task) = rhs.m_task;
119 // rhs.m_task reference count is unchanged, since this is a move
120 } else {
121 // They're the same, but this is a move, so 1 fewer references now
122 rhs.clear();
123 }
124 rhs.m_task = nullptr;
125 return *this;
126 }
127
128 KOKKOS_INLINE_FUNCTION
129 BasicFuture& operator=(BasicFuture const& rhs) {
130 if (m_task != rhs.m_task) {
131 clear();
132 // m_task = rhs.m_task;
133 *static_cast<task_base_type* volatile*>(&m_task) = rhs.m_task;
134 }
135 if (m_task != nullptr) {
136 m_task->increment_reference_count();
137 }
138 return *this;
139 }
140
141 //----------------------------------------
142
143 template <class T, class S>
144 KOKKOS_INLINE_FUNCTION BasicFuture(
145 BasicFuture<T, S>&& rhs) noexcept // NOLINT(google-explicit-constructor)
146 : m_task(std::move(rhs.m_task)) {
147 static_assert(
148 std::is_void_v<scheduler_type> || std::is_same_v<scheduler_type, S>,
149 "Moved Futures must have the same scheduler");
150
151 static_assert(std::is_void_v<value_type> || std::is_same_v<value_type, T>,
152 "Moved Futures must have the same value_type");
153
154 // reference counts are unchanged, since this is a move
155 rhs.m_task = nullptr;
156 }
157
158 template <class T, class S>
159 KOKKOS_INLINE_FUNCTION BasicFuture(
160 BasicFuture<T, S> const& rhs) // NOLINT(google-explicit-constructor)
161 //: m_task(rhs.m_task)
162 : m_task(nullptr) {
163 static_assert(
164 std::is_void_v<scheduler_type> || std::is_same_v<scheduler_type, S>,
165 "Copied Futures must have the same scheduler");
166
167 static_assert(std::is_void_v<value_type> || std::is_same_v<value_type, T>,
168 "Copied Futures must have the same value_type");
169
170 *static_cast<task_base_type* volatile*>(&m_task) = rhs.m_task;
171 if (m_task) m_task->increment_reference_count();
172 }
173
174 template <class T, class S>
175 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S> const& rhs) {
176 static_assert(
177 std::is_void_v<scheduler_type> || std::is_same_v<scheduler_type, S>,
178 "Assigned Futures must have the same scheduler");
179
180 static_assert(std::is_void_v<value_type> || std::is_same_v<value_type, T>,
181 "Assigned Futures must have the same value_type");
182
183 if (m_task != rhs.m_task) {
184 clear();
185 // m_task = rhs.m_task;
186 *static_cast<task_base_type* volatile*>(&m_task) = rhs.m_task;
187 if (m_task != nullptr) {
188 m_task->increment_reference_count();
189 }
190 }
191 return *this;
192 }
193
194 template <class T, class S>
195 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S>&& rhs) {
196 static_assert(
197 std::is_void_v<scheduler_type> || std::is_same_v<scheduler_type, S>,
198 "Assigned Futures must have the same scheduler");
199
200 static_assert(std::is_void_v<value_type> || std::is_same_v<value_type, T>,
201 "Assigned Futures must have the same value_type");
202
203 if (m_task != rhs.m_task) {
204 clear();
205 // m_task = std::move(rhs.m_task);
206 *static_cast<task_base_type* volatile*>(&m_task) = rhs.m_task;
207 // rhs.m_task reference count is unchanged, since this is a move
208 } else {
209 // They're the same, but this is a move, so 1 fewer references now
210 rhs.clear();
211 }
212 rhs.m_task = nullptr;
213 return *this;
214 }
215
216 KOKKOS_INLINE_FUNCTION
217 ~BasicFuture() noexcept { clear(); }
218
219 //----------------------------------------
220
221 KOKKOS_INLINE_FUNCTION
222 void clear() noexcept {
223 if (m_task) {
224 bool should_delete = m_task->decrement_and_check_reference_count();
225 if (should_delete) {
226 static_cast<task_queue_type*>(m_task->ready_queue_base_ptr())
227 ->deallocate(std::move(*m_task));
228 }
229 }
230 // m_task = nullptr;
231 *static_cast<task_base_type* volatile*>(&m_task) = nullptr;
232 }
233
234 KOKKOS_INLINE_FUNCTION
235 bool is_null() const noexcept { return m_task == nullptr; }
236
237 KOKKOS_INLINE_FUNCTION
238 bool is_ready() const noexcept {
239 return (m_task == nullptr) || m_task->wait_queue_is_consumed();
240 }
241
242 KOKKOS_INLINE_FUNCTION
243 const typename Impl::TaskResult<ValueType>::reference_type get() const {
244 KOKKOS_EXPECTS(is_ready());
245 return static_cast<result_storage_type*>(m_task)->value_reference();
246 // return Impl::TaskResult<ValueType>::get(m_task);
247 }
248};
249
251// OLD CODE
253
254template <typename ValueType, typename Scheduler>
255class KOKKOS_DEPRECATED BasicFuture {
256 private:
257 template <typename, typename>
258 friend class BasicTaskScheduler;
259 template <typename, typename>
260 friend class BasicFuture;
261 friend class Impl::TaskBase;
262 template <typename, typename, typename>
263 friend class Impl::Task;
264
265 //----------------------------------------
266
267 public:
268 //----------------------------------------
269
270 using scheduler_type = Scheduler;
271 using queue_type = typename scheduler_type::queue_type;
272 using execution_space = typename scheduler_type::execution_space;
273 using value_type = ValueType;
274
275 //----------------------------------------
276
277 private:
278 //----------------------------------------
279
280 using task_base = Impl::TaskBase;
281
282 task_base* m_task;
283
284 KOKKOS_INLINE_FUNCTION explicit BasicFuture(task_base* task)
285 : m_task(nullptr) {
286 if (task) queue_type::assign(&m_task, task);
287 }
288
289 //----------------------------------------
290
291 public:
292 //----------------------------------------
293
294 KOKKOS_INLINE_FUNCTION
295 bool is_null() const { return nullptr == m_task; }
296
297 KOKKOS_INLINE_FUNCTION
298 int reference_count() const {
299 return nullptr != m_task ? m_task->reference_count() : 0;
300 }
301
302 //----------------------------------------
303
304 KOKKOS_INLINE_FUNCTION
305 void clear() {
306 if (m_task) queue_type::assign(&m_task, nullptr);
307 }
308
309 //----------------------------------------
310
311 KOKKOS_INLINE_FUNCTION
312 ~BasicFuture() { clear(); }
313
314 //----------------------------------------
315
316 KOKKOS_INLINE_FUNCTION
317 BasicFuture() noexcept : m_task(nullptr) {}
318
319 KOKKOS_INLINE_FUNCTION
320 BasicFuture(BasicFuture&& rhs) noexcept : m_task(rhs.m_task) {
321 rhs.m_task = nullptr;
322 }
323
324 KOKKOS_INLINE_FUNCTION
325 BasicFuture(const BasicFuture& rhs) : m_task(nullptr) {
326 if (rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
327 }
328
329 KOKKOS_INLINE_FUNCTION
330 BasicFuture& operator=(BasicFuture&& rhs) noexcept {
331 clear();
332 m_task = rhs.m_task;
333 rhs.m_task = nullptr;
334 return *this;
335 }
336
337 KOKKOS_INLINE_FUNCTION
338 BasicFuture& operator=(BasicFuture const& rhs) {
339 if (&rhs == this) return *this;
340 if (m_task || rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
341 return *this;
342 }
343
344 //----------------------------------------
345
346 template <class T, class S>
347 KOKKOS_INLINE_FUNCTION BasicFuture(
348 BasicFuture<T, S>&& rhs) noexcept // NOLINT(google-explicit-constructor)
349 : m_task(rhs.m_task) {
350 static_assert(
351 std::is_void_v<scheduler_type> || std::is_same_v<scheduler_type, S>,
352 "Assigned Futures must have the same scheduler");
353
354 static_assert(std::is_void_v<value_type> || std::is_same_v<value_type, T>,
355 "Assigned Futures must have the same value_type");
356
357 rhs.m_task = 0;
358 }
359
360 template <class T, class S>
361 KOKKOS_INLINE_FUNCTION BasicFuture(
362 BasicFuture<T, S> const& rhs) // NOLINT(google-explicit-constructor)
363 : m_task(nullptr) {
364 static_assert(
365 std::is_void_v<scheduler_type> || std::is_same_v<scheduler_type, S>,
366 "Assigned Futures must have the same scheduler");
367
368 static_assert(std::is_void_v<value_type> || std::is_same_v<value_type, T>,
369 "Assigned Futures must have the same value_type");
370
371 if (rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
372 }
373
374 template <class T, class S>
375 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S> const& rhs) {
376 static_assert(
377 std::is_void_v<scheduler_type> || std::is_same_v<scheduler_type, S>,
378 "Assigned Futures must have the same scheduler");
379
380 static_assert(std::is_void_v<value_type> || std::is_same_v<value_type, T>,
381 "Assigned Futures must have the same value_type");
382
383 if (m_task || rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
384 return *this;
385 }
386
387 template <class T, class S>
388 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S>&& rhs) {
389 static_assert(
390 std::is_void_v<scheduler_type> || std::is_same_v<scheduler_type, S>,
391 "Assigned Futures must have the same scheduler");
392
393 static_assert(std::is_void_v<value_type> || std::is_same_v<value_type, T>,
394 "Assigned Futures must have the same value_type");
395
396 clear();
397 m_task = rhs.m_task;
398 rhs.m_task = 0;
399 return *this;
400 }
401
402 //----------------------------------------
403
404 KOKKOS_INLINE_FUNCTION
405 int is_ready() const noexcept {
406 return (nullptr == m_task) ||
407 (reinterpret_cast<task_base*>(task_base::LockTag) == m_task->m_wait);
408 }
409
410 KOKKOS_INLINE_FUNCTION
411 const typename Impl::TaskResult<ValueType>::reference_type get() const {
412 if (nullptr == m_task) {
413 Kokkos::abort("Kokkos:::Future::get ERROR: is_null()");
414 }
415 return Impl::TaskResult<ValueType>::get(m_task);
416 }
417};
418
419// Is a Future with the given execution space
420template <typename, typename ExecSpace = void>
421struct KOKKOS_DEPRECATED is_future : public std::false_type {};
422
423template <typename ValueType, typename Scheduler, typename ExecSpace>
424struct KOKKOS_DEPRECATED is_future<BasicFuture<ValueType, Scheduler>, ExecSpace>
425 : std::bool_constant<
426 std::is_same_v<ExecSpace, typename Scheduler::execution_space> ||
427 std::is_void_v<ExecSpace>> {};
428
430// END OLD CODE
432
433namespace Impl {
434
435template <class Arg1, class Arg2>
436class ResolveFutureArgOrder {
437 private:
438 enum { Arg1_is_space = Kokkos::is_space<Arg1>::value };
439 enum { Arg2_is_space = Kokkos::is_space<Arg2>::value };
440 enum { Arg1_is_value = !Arg1_is_space && !std::is_void_v<Arg1> };
441 enum { Arg2_is_value = !Arg2_is_space && !std::is_void_v<Arg2> };
442
443 static_assert(!(Arg1_is_space && Arg2_is_space),
444 "Future cannot be given two spaces");
445
446 static_assert(!(Arg1_is_value && Arg2_is_value),
447 "Future cannot be given two value types");
448
449 using value_type =
450 std::conditional_t<Arg1_is_value, Arg1,
451 std::conditional_t<Arg2_is_value, Arg2, void>>;
452
453 using execution_space = typename std::conditional_t<
454 Arg1_is_space, Arg1,
455 std::conditional_t<Arg2_is_space, Arg2, void>>::execution_space;
456
457 public:
458 using type = BasicFuture<value_type, TaskScheduler<execution_space>>;
459};
460
461} // end namespace Impl
462
470template <class Arg1 = void, class Arg2 = void>
471using Future KOKKOS_DEPRECATED =
472 typename Impl::ResolveFutureArgOrder<Arg1, Arg2>::type;
473
474} // namespace Kokkos
475
476#ifdef KOKKOS_ENABLE_DEPRECATION_WARNINGS
477KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP()
478#endif
479
480//----------------------------------------------------------------------------
481//----------------------------------------------------------------------------
482
483#endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */
484#endif /* #ifndef KOKKOS_FUTURE */
Atomic functions.