Kokkos Core Kernels Package Version of the Day
Loading...
Searching...
No Matches
Kokkos_TaskScheduler.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#ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
18#include <Kokkos_Macros.hpp>
19static_assert(false,
20 "Including non-public Kokkos header files is not allowed.");
21#endif
22#ifndef KOKKOS_TASKSCHEDULER_HPP
23#define KOKKOS_TASKSCHEDULER_HPP
24
25//----------------------------------------------------------------------------
26
27#include <Kokkos_Macros.hpp>
28#if defined(KOKKOS_ENABLE_TASKDAG)
29
30#include <Kokkos_Core_fwd.hpp>
31#include <Kokkos_TaskScheduler_fwd.hpp>
32//----------------------------------------------------------------------------
33
34#include <Kokkos_MemoryPool.hpp>
35
36#include <Kokkos_Future.hpp>
37#include <impl/Kokkos_TaskQueue.hpp>
38#include <impl/Kokkos_SingleTaskQueue.hpp>
39#include <impl/Kokkos_TaskQueueMultiple.hpp>
40#include <impl/Kokkos_TaskPolicyData.hpp>
41#include <impl/Kokkos_TaskTeamMember.hpp>
42#include <impl/Kokkos_SimpleTaskScheduler.hpp>
43
44//----------------------------------------------------------------------------
45//----------------------------------------------------------------------------
46
47namespace Kokkos {
48
49namespace Impl {
50
51template <class, class>
52class TaskExec;
53
54} // end namespace Impl
55
56template <class ExecSpace, class QueueType>
57class BasicTaskScheduler : public Impl::TaskSchedulerBase {
58 public:
59 using scheduler_type = BasicTaskScheduler;
60 using execution_space = ExecSpace;
61 using queue_type = QueueType;
62 using memory_space = typename queue_type::memory_space;
63 using memory_pool = typename queue_type::memory_pool;
64 using specialization = Impl::TaskQueueSpecialization<BasicTaskScheduler>;
65 using member_type = typename specialization::member_type;
66 using team_scheduler_type = BasicTaskScheduler;
67 template <class Functor>
68 using runnable_task_type =
69 Impl::Task<scheduler_type, typename Functor::value_type, Functor>;
70 template <class ValueType>
71 using future_type = Kokkos::BasicFuture<ValueType, BasicTaskScheduler>;
72 template <class FunctorType>
73 using future_type_for_functor = future_type<typename FunctorType::value_type>;
74
75 private:
76 using track_type = Kokkos::Impl::SharedAllocationTracker;
77 using task_base = Impl::TaskBase;
78
79 track_type m_track;
80 queue_type* m_queue;
81
82 //----------------------------------------
83
84 template <typename, typename>
85 friend class Impl::TaskQueue;
86 template <typename>
87 friend struct Impl::TaskQueueSpecialization;
88 template <typename, typename>
89 friend class Impl::TaskQueueSpecializationConstrained;
90 template <typename, typename>
91 friend class Impl::TaskTeamMemberAdapter;
92 template <typename, typename>
93 friend class Impl::TaskExec;
94
95 //----------------------------------------
96
97 KOKKOS_INLINE_FUNCTION
98 BasicTaskScheduler(track_type arg_track, queue_type* arg_queue)
99 : m_track(std::move(arg_track)), m_queue(std::move(arg_queue)) {}
100
101 KOKKOS_INLINE_FUNCTION
102 team_scheduler_type get_team_scheduler(int team_rank) const {
103 return {m_track, &m_queue->get_team_queue(team_rank)};
104 }
105
106 //----------------------------------------
107
108 KOKKOS_INLINE_FUNCTION
109 static constexpr task_base* _get_task_ptr(std::nullptr_t) { return nullptr; }
110
111 template <class ValueType>
112 KOKKOS_INLINE_FUNCTION static constexpr task_base* _get_task_ptr(
113 future_type<ValueType>&& f) {
114 return f.m_task;
115 }
116
117 template <int TaskEnum, typename DepTaskType, typename FunctorType>
118 KOKKOS_FUNCTION
119 Kokkos::BasicFuture<typename FunctorType::value_type, scheduler_type>
120 _spawn_impl(DepTaskType* arg_predecessor_task, TaskPriority arg_priority,
121 typename task_base::function_type arg_function,
122 typename task_base::destroy_type /*arg_destroy*/,
123 FunctorType&& arg_functor) {
124 using functor_future_type =
125 future_type_for_functor<std::decay_t<FunctorType>>;
126 using task_type =
127 Impl::Task<BasicTaskScheduler, typename functor_future_type::value_type,
128 FunctorType>;
129
130 //----------------------------------------
131 // Give single-thread back-ends an opportunity to clear
132 // queue of ready tasks before allocating a new task
133
134 // TODO @tasking @optimization DSH re-enable this, maybe?
135 // specialization::iff_single_thread_recursive_execute(scheduler);
136
137 //----------------------------------------
138
139 functor_future_type f;
140
141 // Allocate task from memory pool
142
143 const size_t alloc_size =
144 m_queue->template spawn_allocation_size<FunctorType>();
145
146 void* task_storage = m_queue->allocate(alloc_size);
147
148 if (task_storage) {
149 // Placement new construction
150 // Reference count starts at two:
151 // +1 for the matching decrement when task is complete
152 // +1 for the future
153 f.m_task =
154 new (task_storage) task_type(std::forward<FunctorType>(arg_functor));
155
156 f.m_task->m_apply = arg_function;
157 // f.m_task->m_destroy = arg_destroy;
158 f.m_task->m_queue = m_queue;
159 f.m_task->m_next = arg_predecessor_task;
160 f.m_task->m_ref_count = 2;
161 f.m_task->m_alloc_size = alloc_size;
162 f.m_task->m_task_type = TaskEnum;
163 f.m_task->m_priority = (int16_t)arg_priority;
164
165 Kokkos::memory_fence();
166
167 // The dependence (if any) is processed immediately
168 // within the schedule function, as such the dependence's
169 // reference count does not need to be incremented for
170 // the assignment.
171
172 m_queue->schedule_runnable(f.m_task);
173 // This task may be updated or executed at any moment,
174 // even during the call to 'schedule'.
175 }
176
177 return f;
178 }
179
180 public:
181 KOKKOS_INLINE_FUNCTION
182 BasicTaskScheduler() : m_track(), m_queue(nullptr) {}
183
184 KOKKOS_INLINE_FUNCTION
185 BasicTaskScheduler(BasicTaskScheduler&& rhs) noexcept
186 : m_track(rhs.m_track), // probably should be a move, but this is
187 // deprecated code anyway
188 m_queue(std::move(rhs.m_queue)) {}
189
190 KOKKOS_INLINE_FUNCTION
191 BasicTaskScheduler(BasicTaskScheduler const& rhs)
192 : m_track(rhs.m_track), m_queue(rhs.m_queue) {}
193
194 KOKKOS_INLINE_FUNCTION
195 BasicTaskScheduler& operator=(BasicTaskScheduler&& rhs) noexcept {
196 m_track = rhs.m_track; // probably should be a move, but this is deprecated
197 // code anyway
198 m_queue = std::move(rhs.m_queue);
199 return *this;
200 }
201
202 KOKKOS_INLINE_FUNCTION
203 BasicTaskScheduler& operator=(BasicTaskScheduler const& rhs) {
204 m_track = rhs.m_track;
205 m_queue = rhs.m_queue;
206 return *this;
207 }
208
209 explicit BasicTaskScheduler(memory_pool const& arg_memory_pool) noexcept
210 : m_track(), m_queue(nullptr) {
211 using record_type =
212 Kokkos::Impl::SharedAllocationRecord<memory_space,
213 typename queue_type::Destroy>;
214
215 record_type* record = record_type::allocate(
216 memory_space(), "Kokkos::TaskQueue", sizeof(queue_type));
217
218 m_queue = new (record->data()) queue_type(arg_memory_pool);
219
220 record->m_destroy.m_queue = m_queue;
221
222 m_track.assign_allocated_record_to_uninitialized(record);
223 }
224
225 BasicTaskScheduler(memory_space const& arg_memory_space,
226 size_t const mempool_capacity,
227 unsigned const mempool_min_block_size // = 1u << 6
228 ,
229 unsigned const mempool_max_block_size // = 1u << 10
230 ,
231 unsigned const mempool_superblock_size // = 1u << 12
232 )
233 : BasicTaskScheduler(memory_pool(
234 arg_memory_space, mempool_capacity, mempool_min_block_size,
235 mempool_max_block_size, mempool_superblock_size)) {}
236
237 //----------------------------------------
238
239 KOKKOS_INLINE_FUNCTION
240 queue_type& queue() const noexcept {
241 KOKKOS_EXPECTS(m_queue != nullptr);
242 return *m_queue;
243 }
244
245 KOKKOS_INLINE_FUNCTION
246 memory_pool* memory() const noexcept {
247 return m_queue ? &(m_queue->m_memory) : (memory_pool*)0;
248 }
249
250 //----------------------------------------
252 template <typename FunctorType>
253 KOKKOS_FUNCTION size_t spawn_allocation_size() const {
254 return m_queue->template spawn_allocation_size<FunctorType>();
255 }
256
258 KOKKOS_FUNCTION
259 size_t when_all_allocation_size(int narg) const {
260 return m_queue->when_all_allocation_size(narg);
261 }
262
263 //----------------------------------------
264
265 template <int TaskEnum, typename DepFutureType, typename FunctorType>
266 KOKKOS_FUNCTION static Kokkos::BasicFuture<typename FunctorType::value_type,
267 scheduler_type>
268 spawn(Impl::TaskPolicyWithScheduler<TaskEnum, scheduler_type, DepFutureType>&&
269 arg_policy,
270 typename task_base::function_type arg_function,
271 typename task_base::destroy_type arg_destroy,
272 FunctorType&& arg_functor) {
273 return std::move(arg_policy.scheduler())
274 .template _spawn_impl<TaskEnum>(
275 _get_task_ptr(std::move(arg_policy.predecessor())),
276 arg_policy.priority(), arg_function, arg_destroy,
277 std::forward<FunctorType>(arg_functor));
278 }
279
280 template <int TaskEnum, typename DepFutureType, typename FunctorType>
281 KOKKOS_FUNCTION future_type_for_functor<std::decay_t<FunctorType>> spawn(
282 Impl::TaskPolicyWithPredecessor<TaskEnum, DepFutureType>&& arg_policy,
283 FunctorType&& arg_functor) {
284 using task_type = runnable_task_type<FunctorType>;
285 typename task_type::function_type const ptr = task_type::apply;
286 typename task_type::destroy_type const dtor = task_type::destroy;
287
288 return _spawn_impl<TaskEnum>(
289 _get_task_ptr(std::move(arg_policy).predecessor()),
290 arg_policy.priority(), ptr, dtor,
291 std::forward<FunctorType>(arg_functor));
292 }
293
294 template <typename FunctorType, typename ValueType, typename Scheduler>
295 KOKKOS_FUNCTION static void respawn(
296 FunctorType* arg_self,
297 BasicFuture<ValueType, Scheduler> const& arg_dependence,
298 TaskPriority const& arg_priority) {
299 // Precondition: task is in Executing state
300
301 using value_type = typename FunctorType::value_type;
302 using task_type = Impl::Task<BasicTaskScheduler, value_type, FunctorType>;
303
304 task_type* const task = static_cast<task_type*>(arg_self);
305
306 task->m_priority = static_cast<int>(arg_priority);
307
308 task->add_dependence(arg_dependence.m_task);
309
310 // Postcondition: task is in Executing-Respawn state
311 }
312
313 template <typename FunctorType>
314 KOKKOS_FUNCTION static void respawn(FunctorType* arg_self,
315 BasicTaskScheduler const&,
316 TaskPriority const& arg_priority) {
317 // Precondition: task is in Executing state
318
319 using value_type = typename FunctorType::value_type;
320 using task_type = Impl::Task<BasicTaskScheduler, value_type, FunctorType>;
321
322 task_type* const task = static_cast<task_type*>(arg_self);
323
324 task->m_priority = static_cast<int>(arg_priority);
325
326 task->add_dependence(nullptr);
327
328 // Postcondition: task is in Executing-Respawn state
329 }
330
331 //----------------------------------------
335 template <typename ValueType>
336 KOKKOS_FUNCTION BasicFuture<void, scheduler_type> when_all(
337 BasicFuture<ValueType, BasicTaskScheduler> const arg[], int narg) {
338 future_type<void> f;
339
340 if (narg) {
341 queue_type* q = m_queue;
342
343 // BasicTaskScheduler const* scheduler_ptr = nullptr;
344
345 for (int i = 0; i < narg; ++i) {
346 task_base* const t = arg[i].m_task;
347 if (nullptr != t) {
348 // Increment reference count to track subsequent assignment.
349 // This likely has to be SeqCst
350 Kokkos::Impl::desul_atomic_inc(&(t->m_ref_count),
351 Kokkos::Impl::MemoryOrderSeqCst(),
352 Kokkos::Impl::MemoryScopeDevice());
353 if (q != static_cast<queue_type const*>(t->m_queue)) {
354 Kokkos::abort(
355 "Kokkos when_all Futures must be in the same scheduler");
356 }
357 }
358 }
359
360 if (q != nullptr) { // this should probably handle the queue == 0 case,
361 // but this is deprecated code anyway
362
363 size_t const alloc_size = q->when_all_allocation_size(narg);
364
365 f.m_task = reinterpret_cast<task_base*>(q->allocate(alloc_size));
366 // f.m_scheduler = *scheduler_ptr;
367
368 if (f.m_task) {
369 // Reference count starts at two:
370 // +1 to match decrement when task completes
371 // +1 for the future
372
373 new (f.m_task) task_base();
374
375 f.m_task->m_queue = q;
376 f.m_task->m_ref_count = 2;
377 f.m_task->m_alloc_size = static_cast<int32_t>(alloc_size);
378 f.m_task->m_dep_count = narg;
379 f.m_task->m_task_type = task_base::Aggregate;
380
381 // Assign dependences, reference counts were already incremented
382
383 task_base* volatile* const dep = f.m_task->aggregate_dependences();
384
385 for (int i = 0; i < narg; ++i) {
386 dep[i] = arg[i].m_task;
387 }
388
389 Kokkos::memory_fence();
390
391 q->schedule_aggregate(f.m_task);
392 // this when_all may be processed at any moment
393 }
394 }
395 }
396
397 return f;
398 }
399
400 template <class F>
401 KOKKOS_FUNCTION BasicFuture<void, scheduler_type> when_all(int narg,
402 F const func) {
403 using input_type = decltype(func(0));
404
405 static_assert(is_future<input_type>::value,
406 "Functor must return a Kokkos::Future");
407
408 future_type<void> f;
409
410 if (0 == narg) return f;
411
412 size_t const alloc_size = m_queue->when_all_allocation_size(narg);
413
414 f.m_task = reinterpret_cast<task_base*>(m_queue->allocate(alloc_size));
415
416 if (f.m_task) {
417 // Reference count starts at two:
418 // +1 to match decrement when task completes
419 // +1 for the future
420
421 new (f.m_task) task_base();
422 // f.m_scheduler = *this;
423
424 // f.m_task->m_scheduler = &f.m_scheduler;
425 f.m_task->m_queue = m_queue;
426 f.m_task->m_ref_count = 2;
427 f.m_task->m_alloc_size = static_cast<int32_t>(alloc_size);
428 f.m_task->m_dep_count = narg;
429 f.m_task->m_task_type = task_base::Aggregate;
430 // f.m_task->m_apply = nullptr;
431 // f.m_task->m_destroy = nullptr;
432
433 // Assign dependences, reference counts were already incremented
434
435 task_base* volatile* const dep = f.m_task->aggregate_dependences();
436
437 for (int i = 0; i < narg; ++i) {
438 const input_type arg_f = func(i);
439 if (nullptr != arg_f.m_task) {
440 // Not scheduled, so task scheduler is not yet set
441 // if ( m_queue != static_cast< BasicTaskScheduler const * >(
442 // arg_f.m_task->m_scheduler )->m_queue ) {
443 // Kokkos::abort("Kokkos when_all Futures must be in the same
444 // scheduler" );
445 //}
446 // Increment reference count to track subsequent assignment.
447 // This increment likely has to be SeqCst
448 Kokkos::Impl::desul_atomic_inc(&(arg_f.m_task->m_ref_count),
449 Kokkos::Impl::MemoryOrderSeqCst(),
450 Kokkos::Impl::MemoryScopeDevice());
451 dep[i] = arg_f.m_task;
452 }
453 }
454
455 Kokkos::memory_fence();
456
457 m_queue->schedule_aggregate(f.m_task);
458 // this when_all may be processed at any moment
459 }
460 return f;
461 }
462
463 //----------------------------------------
464
465 KOKKOS_INLINE_FUNCTION
466 int allocation_capacity() const noexcept {
467 return m_queue->m_memory.capacity();
468 }
469
470 KOKKOS_INLINE_FUNCTION
471 int allocated_task_count() const noexcept { return m_queue->m_count_alloc; }
472
473 KOKKOS_INLINE_FUNCTION
474 int allocated_task_count_max() const noexcept { return m_queue->m_max_alloc; }
475
476 KOKKOS_INLINE_FUNCTION
477 long allocated_task_count_accum() const noexcept {
478 return m_queue->m_accum_alloc;
479 }
480
481 //----------------------------------------
482
483 template <class S, class Q>
484 friend void wait(Kokkos::BasicTaskScheduler<S, Q> const&);
485};
486
487} // namespace Kokkos
488
489//----------------------------------------------------------------------------
490//----------------------------------------------------------------------------
491
492namespace Kokkos {
493
494//----------------------------------------------------------------------------
495// Construct a TaskTeam execution policy
496
497template <class T, class Scheduler>
498Impl::TaskPolicyWithPredecessor<Impl::TaskType::TaskTeam,
499 Kokkos::BasicFuture<T, Scheduler>>
500 KOKKOS_INLINE_FUNCTION
501 TaskTeam(Kokkos::BasicFuture<T, Scheduler> arg_future,
502 TaskPriority arg_priority = TaskPriority::Regular) {
503 return {std::move(arg_future), arg_priority};
504}
505
506template <class Scheduler>
507Impl::TaskPolicyWithScheduler<Impl::TaskType::TaskTeam, Scheduler>
508 KOKKOS_INLINE_FUNCTION TaskTeam(
509 Scheduler arg_scheduler,
510 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value, TaskPriority>
511 arg_priority = TaskPriority::Regular) {
512 return {std::move(arg_scheduler), arg_priority};
513}
514
515template <class Scheduler, class PredecessorFuture>
516Impl::TaskPolicyWithScheduler<Kokkos::Impl::TaskType::TaskTeam, Scheduler,
517 PredecessorFuture>
518 KOKKOS_INLINE_FUNCTION
519 TaskTeam(Scheduler arg_scheduler, PredecessorFuture arg_future,
520 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value &&
521 Kokkos::is_future<PredecessorFuture>::value,
522 TaskPriority>
523 arg_priority = TaskPriority::Regular) {
524 static_assert(std::is_same<typename PredecessorFuture::scheduler_type,
525 Scheduler>::value,
526 "Can't create a task policy from a scheduler and a future from "
527 "a different scheduler");
528
529 return {std::move(arg_scheduler), std::move(arg_future), arg_priority};
530}
531
532// Construct a TaskSingle execution policy
533
534template <class T, class Scheduler>
535Impl::TaskPolicyWithPredecessor<Impl::TaskType::TaskSingle,
536 Kokkos::BasicFuture<T, Scheduler>>
537 KOKKOS_INLINE_FUNCTION
538 TaskSingle(Kokkos::BasicFuture<T, Scheduler> arg_future,
539 TaskPriority arg_priority = TaskPriority::Regular) {
540 return {std::move(arg_future), arg_priority};
541}
542
543template <class Scheduler>
544Impl::TaskPolicyWithScheduler<Impl::TaskType::TaskSingle, Scheduler>
545 KOKKOS_INLINE_FUNCTION TaskSingle(
546 Scheduler arg_scheduler,
547 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value, TaskPriority>
548 arg_priority = TaskPriority::Regular) {
549 return {std::move(arg_scheduler), arg_priority};
550}
551
552template <class Scheduler, class PredecessorFuture>
553Impl::TaskPolicyWithScheduler<Kokkos::Impl::TaskType::TaskSingle, Scheduler,
554 PredecessorFuture>
555 KOKKOS_INLINE_FUNCTION
556 TaskSingle(Scheduler arg_scheduler, PredecessorFuture arg_future,
557 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value &&
558 Kokkos::is_future<PredecessorFuture>::value,
559 TaskPriority>
560 arg_priority = TaskPriority::Regular) {
561 static_assert(std::is_same<typename PredecessorFuture::scheduler_type,
562 Scheduler>::value,
563 "Can't create a task policy from a scheduler and a future from "
564 "a different scheduler");
565
566 return {std::move(arg_scheduler), std::move(arg_future), arg_priority};
567}
568
569//----------------------------------------------------------------------------
570
577template <int TaskEnum, typename Scheduler, typename DepFutureType,
578 typename FunctorType>
579typename Scheduler::template future_type_for_functor<std::decay_t<FunctorType>>
580host_spawn(Impl::TaskPolicyWithScheduler<TaskEnum, Scheduler, DepFutureType>
581 arg_policy,
582 FunctorType&& arg_functor) {
583 using scheduler_type = Scheduler;
584 using task_type =
585 typename scheduler_type::template runnable_task_type<FunctorType>;
586
587 static_assert(TaskEnum == Impl::TaskType::TaskTeam ||
588 TaskEnum == Impl::TaskType::TaskSingle,
589 "Kokkos host_spawn requires TaskTeam or TaskSingle");
590
591 // May be spawning a Cuda task, must use the specialization
592 // to query on-device function pointer.
593 typename task_type::function_type ptr;
594 typename task_type::destroy_type dtor;
595 Kokkos::Impl::TaskQueueSpecialization<
596 scheduler_type>::template get_function_pointer<task_type>(ptr, dtor);
597
598 return scheduler_type::spawn(std::move(arg_policy), ptr, dtor,
599 std::forward<FunctorType>(arg_functor));
600}
601
608template <int TaskEnum, typename Scheduler, typename DepFutureType,
609 typename FunctorType>
610typename Scheduler::template future_type_for_functor<std::decay_t<FunctorType>>
611 KOKKOS_INLINE_FUNCTION
612 task_spawn(Impl::TaskPolicyWithScheduler<TaskEnum, Scheduler, DepFutureType>
613 arg_policy,
614 FunctorType&& arg_functor) {
615 using scheduler_type = Scheduler;
616
617 using task_type =
618 typename scheduler_type::template runnable_task_type<FunctorType>;
619
620 static_assert(TaskEnum == Impl::TaskType::TaskTeam ||
621 TaskEnum == Impl::TaskType::TaskSingle,
622 "Kokkos task_spawn requires TaskTeam or TaskSingle");
623
624 typename task_type::function_type const ptr = task_type::apply;
625 typename task_type::destroy_type const dtor = task_type::destroy;
626
627 return scheduler_type::spawn(std::move(arg_policy), ptr, dtor,
628 std::forward<FunctorType>(arg_functor));
629}
630
636template <typename FunctorType, typename T>
637void KOKKOS_INLINE_FUNCTION
638respawn(FunctorType* arg_self, T const& arg,
639 TaskPriority const& arg_priority = TaskPriority::Regular) {
640 static_assert(Kokkos::is_future<T>::value || Kokkos::is_scheduler<T>::value,
641 "Kokkos respawn argument must be Future or TaskScheduler");
642
643 T::scheduler_type::respawn(arg_self, arg, arg_priority);
644}
645
646//----------------------------------------------------------------------------
647
648// template<typename ValueType, typename Scheduler>
649// KOKKOS_INLINE_FUNCTION
650// BasicFuture<void, Scheduler>
651// when_all(BasicFuture<ValueType, Scheduler> const arg[], int narg)
652//{
653// return BasicFuture<void, Scheduler>::scheduler_type::when_all(arg, narg);
654//}
655
656//----------------------------------------------------------------------------
657// Wait for all runnable tasks to complete
658
659template <class ExecSpace, class QueueType>
660inline void wait(BasicTaskScheduler<ExecSpace, QueueType> const& scheduler) {
661 using scheduler_type = BasicTaskScheduler<ExecSpace, QueueType>;
662 scheduler_type::specialization::execute(scheduler);
663 // scheduler.m_queue->execute();
664}
665
666} // namespace Kokkos
667
668//----------------------------------------------------------------------------
669//----------------------------------------------------------------------------
670
672// END OLD CODE
674
675#endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */
676#endif /* #ifndef KOKKOS_TASKSCHEDULER_HPP */