alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
Queue.hpp
Go to the documentation of this file.
1/* Copyright 2024 René Widera
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5#pragma once
6
13#include "alpaka/api/util.hpp"
16#include "alpaka/interface.hpp"
25
26#include <cstdint>
27#include <cstring>
28#include <future>
29#include <sstream>
30
31namespace alpaka::onHost
32{
33 namespace cpu
34 {
35 template<typename T_Device>
36 struct Queue : std::enable_shared_from_this<Queue<T_Device>>
37 {
38 public:
39 Queue(internal::concepts::DeviceHandle auto device, uint32_t const idx, uint32_t numIdx, bool isBlocking)
40 : m_device(std::move(device))
41 , m_idx(idx)
42 , m_numaIdx(numIdx)
43 , m_workerThread(numIdx)
44 , m_isBlocking(isBlocking)
45 {
47 }
48
50 {
52 internal::wait(*this);
53 }
54
55 Queue(Queue const&) = delete;
56 Queue& operator=(Queue const&) = delete;
57
58 Queue(Queue&&) = delete;
59 Queue& operator=(Queue&&) = delete;
60
61 bool operator==(Queue const& other) const
62 {
63 return m_idx == other.m_idx && m_device == other.m_device;
64 }
65
66 bool operator!=(Queue const& other) const
67 {
68 return !(*this == other);
69 }
70
71 private:
72 void _()
73 {
74 static_assert(internal::concepts::Queue<Queue>);
75 }
76
77 Handle<T_Device> m_device;
78 uint32_t m_idx = 0u;
79 uint32_t m_numaIdx = 0u;
80 core::CallbackThread m_workerThread;
81 bool m_isBlocking{false};
82 /** Flag to show if a blocking tasks is executed
83 *
84 * This variable is only used if m_isBlocking == true.
85 *
86 * state: If true a thread is executing a blocking tasks, else false.
87 */
88 std::atomic<bool> m_isBlockingTaskExecuted{false};
89
90 /** Mutex to ensure sequential execution of tasks and operation if the queue is blocking.
91 *
92 * For non-blocking queue @c m_workerThread is taking care of the execution order
93 */
94 std::mutex m_mutex;
95
96 /** Submit a task to the queue.
97 *
98 * Centralizes blocking / non-blocking behavior within the method to keep other code as easy as possible.
99 * For a blocking queue this method is NOT giving the control back to the caller until the operation is
100 * processed.
101 * All internal calls should use this method and not enqueue tasks directly in @c m_workerThread
102 */
103 template<typename T_Fn>
104 auto submit(T_Fn&& fn)
105 {
107 if(m_isBlocking)
108 {
109 std::lock_guard<std::mutex> lk(m_mutex);
110 m_isBlockingTaskExecuted = true;
111 fn();
112 // silent tsan warnings: The promise is fulfilled directly and only a future which is true is
113 // returned, there can not be a data race in between.
114#if defined(__GNUC__) && !defined(__clang__)
115# pragma GCC diagnostic push
116# pragma GCC diagnostic ignored "-Wtsan"
117#endif
118 // return a ready future-like placeholder; reuse CallbackThread interface minimally
119 std::promise<void> p;
120 auto f = p.get_future();
121 p.set_value();
122#if defined(__GNUC__) && !defined(__clang__)
123# pragma GCC diagnostic pop
124#endif
125 m_isBlockingTaskExecuted = false;
126 // to keep the uniform interface with the non-blocking case,
127 // return by moving the f since it is move-only
128 return f;
129 }
130 // enqueue the task into the worker thread, callers can wait/chain later.
131 return m_workerThread.submit(std::forward<T_Fn>(fn));
132 }
133
134 friend struct alpaka::internal::GetName;
135
136 std::string getName() const
137 {
138 return std::string("host::Queue id=") + std::to_string(m_idx);
139 }
140
141 friend struct internal::GetNativeHandle;
142
143 [[nodiscard]] auto getNativeHandle() const noexcept
144 {
145 return m_idx;
146 }
147
148 friend struct internal::Enqueue;
149
150 template<alpaka::onHost::concepts::ThreadSpec T_ThreadSpec>
151 void enqueue(T_ThreadSpec const& threadSpec, auto const& kernelBundle)
152 {
153 static_assert(
154 ALPAKA_TYPEOF(threadSpec)::getExecutor() != exec::anyExecutor,
155 "'exec::anyExecutor' can not be used to enqueue an kernel.");
157 auto deviceKind = alpaka::getDeviceKind(m_device);
158
159 /* Only set the thread affinity if we use a blocking queue, else the affinity is already set in the
160 * callback thread. The callback thread affinity will be given to all threads created bya task executed
161 * by the callback thread. */
162 bool setThreadAffinity = m_isBlocking;
163 submit(
164 [kernelBundle, threadSpec, deviceKind, numIdx = m_numaIdx, setThreadAffinity]()
165 {
166 auto moreLayer = Dict{
167 DictEntry(object::launchedWidthFrameSpec, std::false_type{}),
168 DictEntry(object::api, api::host),
169 DictEntry(object::deviceKind, deviceKind),
170 DictEntry(object::exec, threadSpec.getExecutor())};
171 onAcc::Acc acc = makeAcc(threadSpec, numIdx, setThreadAffinity);
172 acc(kernelBundle, moreLayer);
173 });
174 }
175
176 template<alpaka::onHost::concepts::FrameSpec T_FrameSpec>
177 void enqueue(T_FrameSpec const& frameSpec, auto const& kernelBundle)
178 {
179 static_assert(
180 ALPAKA_TYPEOF(frameSpec)::getExecutor() != exec::anyExecutor,
181 "'exec::anyExecutor' can not be used to enqueue an kernel.");
183 auto adjustedThreadSpec = internal::adjustThreadSpec(*m_device.get(), frameSpec, kernelBundle);
184 auto deviceKind = alpaka::getDeviceKind(m_device);
185
186 /* Only set the thread affinity if we use a blocking queue, else the affinity is already set in the
187 * callback thread. The callback thread affinity will be given to all threads created bya task executed
188 * by the callback thread. */
189 bool setThreadAffinity = m_isBlocking;
190 submit(
191 [kernelBundle, adjustedThreadSpec, deviceKind, numIdx = m_numaIdx, setThreadAffinity]()
192 {
193 auto moreLayer = Dict{
194 DictEntry(object::launchedWidthFrameSpec, std::true_type{}),
195 DictEntry(object::api, api::host),
196 DictEntry(object::deviceKind, deviceKind),
197 DictEntry(object::exec, adjustedThreadSpec.getExecutor())};
198 onAcc::Acc acc = makeAcc(adjustedThreadSpec, numIdx, setThreadAffinity);
199 acc(kernelBundle, moreLayer);
200 });
201 }
202
203 /** execute a task in the queue
204 *
205 * @attention Do NOT enqueue a task which captures the queue internally to keep the queue alive as
206 * dependency. In this case the destructure of the queue is not called.
207 */
208 void enqueueHostFn(auto const& task)
209 {
211 submit([task]() { task(); });
212 }
213
214 void enqueueHostFnDeferred(auto const& task)
215 {
217 m_workerThread.submit(task);
218 }
219
220 void enqueueNativeFn(auto const& fn)
221 {
223 submit([queueId = getNativeHandle(), fn]() { fn(queueId); });
224 }
225
226 friend struct alpaka::internal::GetDeviceType;
227
228 auto getDeviceKind() const
229 {
230 return alpaka::internal::getDeviceKind(*m_device.get());
231 }
232
233 auto getDevice() const
234 {
235 return m_device;
236 }
237
238 std::shared_ptr<Queue> getSharedPtr()
239 {
240 return this->shared_from_this();
241 }
242
243 friend struct internal::IsQueueEmpty;
244
245 /** Checks if the queue is empty
246 *
247 * If m_isBlocking is true, only tasks will be taken into account, events will be ignored they could not
248 * influence the usage of isQueueEmpty. if m_isBlocking is false, events will be taken into account because
249 * they are handled as normal tasks.
250 *
251 * @return true if no tasks is executed else false
252 */
253 bool isQueueEmpty() const
254 {
256 if(m_isBlocking)
257 {
258 // check if the queue is currently executing a blocking task
259 return !m_isBlockingTaskExecuted;
260 }
261 else
262 {
263 return m_workerThread.isEmpty();
264 }
265 }
266
267 friend struct onHost::internal::GetDevice;
268
269 friend struct internal::Wait;
270 friend struct internal::WaitFor;
271 friend struct internal::Memcpy;
272 friend struct internal::MemcpyDeviceGlobal;
273 friend struct internal::Memset;
274 friend struct alpaka::internal::GetApi;
275 friend struct internal::AllocDeferred;
276 };
277 } // namespace cpu
278
279 namespace internal
280 {
281 template<typename T_Device>
282 struct Wait::Op<cpu::Queue<T_Device>>
283 {
284 void operator()(cpu::Queue<T_Device>& queue) const
285 {
287 /* If empty -> Enqueue an empty task as marker and wait for the future
288 * else there is no need to wait
289 */
290 if(queue.isQueueEmpty() == false)
291 {
292 queue.submit([]() {}).wait();
293 }
294 }
295 };
296
297 template<typename T_Device, typename T_Event>
298 struct Enqueue::Event<cpu::Queue<T_Device>, T_Event>
299 {
300 void operator()(cpu::Queue<T_Device>& queue, T_Event& event) const
301 {
303 // open a scope to avoid logging during we hold the lock for this class
304 {
305 // Setting the event state (e.g. the future) and enqueuing it has to be atomic.
306 std::lock_guard<std::mutex> lk(event.m_mutex);
307
308 ++event.m_enqueueCount;
309
310 auto const enqueueCount = event.m_enqueueCount;
311
312 /* In case the queue is blocking we can not use queue.submit() because we hold the lock already.
313 * The blocking queue executes the lambda directly which will create a deadlock.
314 */
315 if(queue.m_isBlocking)
316 {
317 // Nothing to do if it has been re-enqueued to a later position in the queue.
318 if(enqueueCount == event.m_enqueueCount)
319 {
320 event.m_LastReadyEnqueueCount = std::max(enqueueCount, event.m_LastReadyEnqueueCount);
321 }
322 // apply a fulfilled future
323 std::promise<void> p;
324 p.set_value();
325 event.m_future = p.get_future();
326 }
327 else
328 {
329 auto sharedEvent = event.getSharedPtr();
330 // Enqueue a task that only resets the events flag if it is completed.
331 event.m_future = queue.submit(
332 [sharedEvent, enqueueCount]() mutable
333 {
334 std::unique_lock<std::mutex> lk2(sharedEvent->m_mutex);
335
336 // Nothing to do if it has been re-enqueued to a later position in the queue.
337 if(enqueueCount == sharedEvent->m_enqueueCount)
338 {
339 sharedEvent->m_LastReadyEnqueueCount
340 = std::max(enqueueCount, sharedEvent->m_LastReadyEnqueueCount);
341 }
342 });
343 }
344 }
345 }
346 };
347
348 template<typename T_Device, typename T_Event>
349 struct WaitFor::Op<cpu::Queue<T_Device>, T_Event>
350 {
351 void operator()(cpu::Queue<T_Device>& queue, cpu::Event<T_Device>& event) const
352 {
354 // open a scope to avoid logging during we hold the lock for this class
355 {
356 // Setting the event state and enqueuing it has to be atomic.
357 std::unique_lock<std::mutex> lk(event.m_mutex);
358
359 if(!event.isReady())
360 {
361 /* In case the queue is blocking we can not use queue.submit() because we hold the lock
362 * already. The blocking queue executes the lambda directly which will create a deadlock.
363 */
364 if(queue.m_isBlocking)
365 {
366 std::shared_future sFuture = event.m_future;
367 lk.unlock();
368 sFuture.get();
369 }
370 else
371 {
372 auto sharedEvent = event.getSharedPtr();
373 auto oldFuture = event.m_future;
374
375 // unlock here to avoid keeping the look during the maybe expensive enqueue of the task
376 lk.unlock();
377 // Enqueue a task that waits for the given future of the event.
378 queue.submit([sharedEvent, oldFuture]() { oldFuture.get(); });
379 }
380 }
381 }
382 }
383 };
384
385 template<typename T_Device, typename T_Dest, typename T_Source, typename T_Extents>
386 struct Memcpy::Op<cpu::Queue<T_Device>, T_Dest, T_Source, T_Extents>
387 {
388 /** Perform data copy.
389 *
390 * To understand the usage of pitches to shift pointers within the implementation see
391 * https://alpaka3.readthedocs.io/en/latest/advanced/datastorage.html#pitches
392 */
393 void operator()(cpu::Queue<T_Device>& queue, auto&& dest, T_Source const& source, T_Extents const& extents)
394 const requires std::same_as<ALPAKA_TYPEOF(dest), T_Dest>
395 {
397 constexpr auto dim = alpaka::trait::getDim_v<T_Extents>;
398
399 // use always 64bit precision to avoid overflows in the pitch calculations
400 auto extentMd = pCast<size_t>(extents);
401 if(extentMd.product() == size_t{0u})
402 return;
403
404 /* Get all required properties outside the lambda function to not extend the life-time of the data.
405 * The life-time is not extended to have some life-time behaviours with all backends.
406 */
407 void* destPtr = toVoidPtr(alpaka::onHost::data(ALPAKA_FORWARD(dest)));
408 void const* srcPtr = toVoidPtr(alpaka::onHost::data(source));
409
410 if constexpr(dim == 1u)
411 {
412 queue.submit(
413 [numElementsInX = extentMd.x(), destPtr, srcPtr]()
414 {
415 std::memcpy(
416 destPtr,
417 srcPtr,
418 numElementsInX * sizeof(alpaka::trait::GetValueType_t<T_Dest>));
419 });
420 }
421 else
422 {
423 // memcpy is implemented as row wise copy therefore the last dimension is not required
424 auto destPitchBytesWithoutColumn = pCast<size_t>(onHost::getPitches(dest).eraseBack());
425 auto sourcePitchBytesWithoutColumn = pCast<size_t>(onHost::getPitches(source).eraseBack());
426
427 queue.submit(
428 [extentMd, destPtr, srcPtr, destPitchBytesWithoutColumn, sourcePitchBytesWithoutColumn]()
429 {
430 alpaka::concepts::Vector<size_t> auto const dstExtentWithoutColumn
431 = pCast<size_t>(extentMd.eraseBack());
432
434 dstExtentWithoutColumn,
435 [&](auto const& idx)
436 {
437 std::memcpy(
438 reinterpret_cast<std::uint8_t*>(destPtr)
439 + (idx * destPitchBytesWithoutColumn).sum(),
440 reinterpret_cast<std::uint8_t const*>(srcPtr)
441 + (idx * sourcePitchBytesWithoutColumn).sum(),
442 static_cast<size_t>(extentMd.back())
444 });
445 });
446 }
447 }
448 };
449
450 // copy to device global memory
451 template<typename T_Device, typename T_Source, typename T_Storage, typename T>
452 struct internal::MemcpyDeviceGlobal::
453 Op<cpu::Queue<T_Device>, onAcc::internal::GlobalDeviceMemoryWrapper<T_Storage, T>, T_Source>
454 {
455 void operator()(
456 cpu::Queue<T_Device>& queue,
457 onAcc::internal::GlobalDeviceMemoryWrapper<T_Storage, T> dest,
458 auto&& source) const
459 {
461 auto* destPtr = dest.getHandle(api::host).data();
462 void const* srcPtr{nullptr};
463 if constexpr(std::is_pointer_v<ALPAKA_TYPEOF(source)>)
464 srcPtr = source;
465 else
467 queue.submit([destPtr, srcPtr]() { std::memcpy(destPtr, srcPtr, sizeof(T)); });
468 }
469 };
470
471 // copy from device global memory
472 template<typename T_Device, typename T_Dest, typename T_Storage, typename T>
473 struct internal::MemcpyDeviceGlobal::
474 Op<cpu::Queue<T_Device>, T_Dest, onAcc::internal::GlobalDeviceMemoryWrapper<T_Storage, T>>
475 {
476 void operator()(
477 cpu::Queue<T_Device>& queue,
478 auto&& dest,
479 onAcc::internal::GlobalDeviceMemoryWrapper<T_Storage, T> source) const
480 {
482 void* destPtr{nullptr};
483 if constexpr(std::is_pointer_v<ALPAKA_TYPEOF(dest)>)
484 destPtr = dest;
485 else
487 auto const* srcPtr = source.getHandle(api::host).data();
488 queue.submit([destPtr, srcPtr]() { std::memcpy(destPtr, srcPtr, sizeof(T)); });
489 }
490 };
491
492 template<typename T_Device, typename T_Dest, typename T_Extents>
493 struct Memset::Op<cpu::Queue<T_Device>, T_Dest, T_Extents>
494 {
495 /** @attention Do not use `requires std::same_as<ALPAKA_TYPEOF(dest), T_Dest>` here else gcc 11.X
496 * (tested 11.4 and 11.3) will run into an internal compiler segfault during the evaluation of the
497 * constraints */
498 void operator()(cpu::Queue<T_Device>& queue, auto&& dest, uint8_t byteValue, T_Extents const& extents)
499 const requires(std::is_same_v<ALPAKA_TYPEOF(dest), T_Dest>)
500 {
502 constexpr auto dim = alpaka::trait::getDim_v<T_Extents>;
503
504 // use always 64bit precision to avoid overflows in the pitch calculations
505 auto extentMd = pCast<size_t>(extents);
506 if(extentMd.product() == size_t{0u})
507 return;
508
509 void* destPtr = static_cast<void*>(alpaka::onHost::data(dest));
510
511 if constexpr(dim == 1u)
512 {
513 queue.submit(
514 [numElementsInX = extentMd.x(), destPtr, byteValue]()
515 {
516 std::memset(
517 destPtr,
518 byteValue,
519 numElementsInX * sizeof(alpaka::trait::GetValueType_t<T_Dest>));
520 });
521 }
522 else
523 {
524 // memset is implemented as row wise memset therefore the last dimension is not required
525 auto destPitchBytesWithoutColumn = pCast<size_t>(onHost::getPitches(dest).eraseBack());
526 queue.submit(
527 [extentMd, destPtr, destPitchBytesWithoutColumn, byteValue]()
528 {
529 auto const dstExtentWithoutColumn = extentMd.eraseBack();
531 dstExtentWithoutColumn,
532 [&](auto const& idx)
533 {
534 std::memset(
535 reinterpret_cast<std::uint8_t*>(destPtr)
536 + (idx * destPitchBytesWithoutColumn).sum(),
537 byteValue,
538 extentMd.back() * sizeof(alpaka::trait::GetValueType_t<T_Dest>));
539 });
540 });
541 }
542 }
543 };
544
545 template<typename T_Device, typename T_Dest, typename T_Value, typename T_Extents>
546 struct Fill::Op<cpu::Queue<T_Device>, T_Dest, T_Value, T_Extents>
547 {
548 void operator()(cpu::Queue<T_Device>& queue, auto&& dest, T_Value elementValue, T_Extents const& extents)
549 const requires std::same_as<ALPAKA_TYPEOF(dest), T_Dest>
550 && std::same_as<alpaka::trait::GetValueType_t<ALPAKA_TYPEOF(dest)>, T_Value>
551 {
553 // avoid that we pass a SharedBuffer and convert non alpaka data views
554 alpaka::concepts::IView<T_Value> auto dataView = makeView(dest);
555
556 alpaka::internal::generic::fill(
557 queue,
558 defaultExecutor(getDevice(queue)),
559 dataView.getSubView(extents),
560 elementValue);
561 }
562 };
563
564 /** The code is a copy of the Alloc::Op with the difference that the memory is allocated and freed
565 * within a queue
566 */
567 template<typename T_Type, typename T_Device, alpaka::concepts::Vector T_Extents>
568 struct AllocDeferred::Op<T_Type, cpu::Queue<T_Device>, T_Extents>
569 {
570 static consteval uint32_t highestPowerOfTwo(uint32_t value)
571 {
572 uint32_t result = 1u;
573 while((result << 1u) <= value)
574 {
575 result <<= 1u;
576 }
577 return result;
578 }
579
580 auto operator()(cpu::Queue<T_Device>& queue, T_Extents const& extents) const
581 {
583 auto device = queue.getDevice();
584 constexpr uint32_t alignment = api::util::simdOptimizedAlignment<T_Type>(
585 ALPAKA_TYPEOF(getApi(device)){},
586 ALPAKA_TYPEOF(getDeviceKind(device)){});
587 auto [memSizeInByte, pitches] = api::util::emulatedAlignedMemDescription<T_Type>(alignment, extents);
588
589 auto deviceDependency = onHost::Device{queue.getDevice()->getSharedPtr()};
590 auto queueDependency = queue.getSharedPtr();
591
592 T_Type* ptr = reinterpret_cast<T_Type*>(alpaka::core::alignedAlloc(alignment, memSizeInByte));
593 device->pinPointer(ptr, memSizeInByte);
594
595 // queueDependency is captured to keep the device alive until the memory is deleted
596 auto deleter = [ptr, queueDep = std::move(queueDependency)]()
597 { queueDep.get()->submit([ptr]() { alpaka::core::alignedFree(alignment, ptr); }); };
598
599 auto sharedBuffer = onHost::SharedBuffer{
600 deviceDependency,
601 ptr,
602 extents,
603 pitches,
604 std::move(deleter),
605 Alignment<alignment>{}};
606
609 [&]()
610 {
611 std::stringstream ss;
612 ss << sharedBuffer;
613 return ss.str();
614 });
615 return sharedBuffer;
616 }
617 };
618 } // namespace internal
619} // namespace alpaka::onHost
620
621namespace alpaka::internal
622{
623 template<typename T_Device>
624 struct GetApi::Op<onHost::cpu::Queue<T_Device>>
625 {
626 inline constexpr auto operator()(auto&& queue) const
627 {
628 return alpaka::getApi(queue.m_device);
629 }
630 };
631} // namespace alpaka::internal
#define ALPAKA_TYPEOF(...)
Get the type of instance.
Definition common.hpp:154
#define ALPAKA_FORWARD(instance)
Perfectly forward an instance as argument.
Definition common.hpp:148
#define ALPAKA_LOG_INFO(logLvl, callable)
Write a meta data message to the output.
Definition logger.hpp:106
#define ALPAKA_LOG_FUNCTION(logLvl)
Log the entry and exit of a scope.
Definition logger.hpp:95
consteval uint32_t highestPowerOfTwo(uint32_t value)
Definition util.hpp:124
auto emulatedAlignedMemDescription(uint32_t alignmentInByte, T_Extents extents)
provides a memory description to create multidimensional linewise aligned memory within a one dimensi...
Definition util.hpp:101
constexpr auto simdOptimizedAlignment(auto api, alpaka::concepts::DeviceKind auto deviceKind)
Calculate the best alignment for SIMD optimized memory allocation.
Definition util.hpp:141
constexpr auto host
Definition Api.hpp:39
ALPAKA_FN_INLINE ALPAKA_FN_HOST void alignedFree(size_t alignment, auto ptr)
ALPAKA_FN_INLINE ALPAKA_FN_HOST auto alignedAlloc(size_t alignment, size_t size) -> void *
constexpr auto cpu
Definition tag.hpp:168
constexpr AnyExecutor anyExecutor
Automatic executor selection.
Definition executor.hpp:33
auto ndLoopIncIdx(TExtentVec &idx, TExtentVec const &extent, TFnObj const &f) -> void
Loops over an n-dimensional iteration index variable calling f(idx, args...) for each iteration....
Definition NdLoop.hpp:73
constexpr DeviceKind deviceKind
Definition tag.hpp:30
constexpr Api api
Definition tag.hpp:24
constexpr Device device
Definition scope.hpp:70
constexpr auto queue
Definition lvl.hpp:127
constexpr auto kernel
Definition lvl.hpp:142
constexpr auto memory
Definition lvl.hpp:112
constexpr auto event
Definition lvl.hpp:97
Functionality which is usable on the host CPU controller thread.
Definition api.hpp:40
constexpr auto defaultExecutor(internal::concepts::DeviceHandle auto deviceHandle)
Select a default executor for the given device.
Definition trait.hpp:169
SharedBuffer(T_Any const &, T_Type *, T_UserExtents const &, T_UserPitches const &, std::invocable<> auto, T_MemAlignment const) -> SharedBuffer< ALPAKA_TYPEOF(getApi(std::declval< T_Any >())), T_Type, typename T_UserPitches::UniVec, T_MemAlignment >
std::shared_ptr< T > Handle
Definition Handle.hpp:30
decltype(auto) data(auto &&any)
pointer to data of an object
auto makeAcc(alpaka::onHost::concepts::ThreadSpec auto const &threadSpec, uint32_t numaIdx, bool setThreadAffinity)
Definition Serial.hpp:92
Device(Handle< T_Device > &&) -> Device< ALPAKA_TYPEOF(alpaka::internal::getApi(std::declval< T_Device >())), ALPAKA_TYPEOF(alpaka::internal::getDeviceKind(std::declval< T_Device >()))>
void wait(alpaka::concepts::HasGet auto &handle)
wait for all work to be finished
Queue(Handle< T_Queue > &&, T_QueueKind) -> Queue< Device< ALPAKA_TYPEOF(alpaka::internal::getApi(std::declval< T_Queue >())), ALPAKA_TYPEOF(alpaka::internal::getDeviceKind(std::declval< T_Queue >()))>, T_QueueKind >
decltype(auto) getPitches(auto &&any)
Object pitches.
Definition interface.hpp:55
typename GetValueType< T >::type GetValueType_t
Definition trait.hpp:65
constexpr uint32_t getDim_v
Definition trait.hpp:41
constexpr decltype(auto) getExecutor(auto &&any)
Get the executor associated with an object.
Definition interface.hpp:23
auto * toVoidPtr(T inPtr)
Cast a pointer that may or may not point to volatile memory to a (void*) or (void const*).
Definition util.hpp:34
constexpr decltype(auto) getDeviceKind(auto &&any)
Get the device type of an object.
Definition interface.hpp:78
constexpr decltype(auto) getApi(auto &&any)
Get the API an object depends on.
Definition interface.hpp:42
constexpr auto makeView(auto &&anyWithApi, T_ValueType *pointer, concepts::Vector auto const &extents, T_MemAlignment const memAlignment=T_MemAlignment{})
Definition View.hpp:37
ALPAKA_FN_HOST_ACC Dict(Tuple< DictEntry< T_Keys, T_Values >... > const &) -> Dict< DictEntry< T_Keys, T_Values >... >
constexpr decltype(auto) pCast(auto &&input)
Performs a static_cast on the storage type of combined data type.
Definition cast.hpp:48
STL namespace.
bool operator!=(Queue const &other) const
Definition Queue.hpp:66
Queue & operator=(Queue const &)=delete
bool operator==(Queue const &other) const
Definition Queue.hpp:61
Queue & operator=(Queue &&)=delete
Queue(internal::concepts::DeviceHandle auto device, uint32_t const idx, uint32_t numIdx, bool isBlocking)
Definition Queue.hpp:39
Queue(Queue &&)=delete
Queue(Queue const &)=delete