alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
TaskKernelGenericSycl.hpp
Go to the documentation of this file.
1/* Copyright 2026 Jan Stephan, Andrea Bocci, Luca Ferragina, Aurora Perego
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5#pragma once
6
8#include "alpaka/acc/Tag.hpp"
11#include "alpaka/core/Sycl.hpp"
12#include "alpaka/dev/Traits.hpp"
13#include "alpaka/dim/Traits.hpp"
14#include "alpaka/idx/Traits.hpp"
22
23#include <cassert>
24#include <functional>
25#include <memory>
26#include <stdexcept>
27#include <string>
28#include <tuple>
29#include <type_traits>
30#include <utility>
31
32#ifdef ALPAKA_ACC_SYCL_ENABLED
33
34# if ALPAKA_COMP_CLANG
35# pragma clang diagnostic push
36# pragma clang diagnostic ignored "-Wunused-lambda-capture"
37# pragma clang diagnostic ignored "-Wunused-parameter"
38# endif
39
40# include <sycl/ext/oneapi/experimental/root_group.hpp>
41# include <sycl/ext/oneapi/properties/properties.hpp>
42# include <sycl/sycl.hpp>
43
44# define LAUNCH_SYCL_KERNEL_IF_SUBGROUP_SIZE_IS(sub_group_size) \
45 if constexpr(TCooperative) \
46 { \
47 auto const kernel = [item_elements, dyn_shared_accessor, st_shared_accessor, k_func, k_args]( \
48 sycl::nd_item<TDim::value> work_item) \
49 { \
50 auto acc = TAcc{item_elements, work_item, dyn_shared_accessor, st_shared_accessor}; \
51 std::apply([&](auto&&... args) { detail::checkKernelReturnType(k_func, acc, args...); }, k_args); \
52 std::apply( \
53 [k_func, &acc](typename std::decay_t<TArgs> const&... args) { k_func(acc, args...); }, \
54 k_args); \
55 }; \
56 cgh.parallel_for<detail::SyclKernel<TKernelFnObj, TDim, TIdx, TArgs...>>( \
57 sycl::nd_range<TDim::value>{global_size, local_size}, \
58 detail::SyclRootSyncKernel<sub_group_size, TDim::value, std::remove_const_t<decltype(kernel)>>{ \
59 kernel}); \
60 } \
61 else \
62 { \
63 cgh.parallel_for( \
64 sycl::nd_range<TDim::value>{global_size, local_size}, \
65 [item_elements, dyn_shared_accessor, st_shared_accessor, k_func, k_args]( \
66 sycl::nd_item<TDim::value> work_item) [[sycl::reqd_sub_group_size(sub_group_size)]] \
67 { \
68 auto acc = TAcc{item_elements, work_item, dyn_shared_accessor, st_shared_accessor}; \
69 std::apply([&](auto&&... args) { detail::checkKernelReturnType(k_func, acc, args...); }, k_args); \
70 std::apply( \
71 [k_func, &acc](typename std::decay_t<TArgs> const&... args) { k_func(acc, args...); }, \
72 k_args); \
73 }); \
74 }
75
76# define LAUNCH_SYCL_KERNEL_WITH_DEFAULT_SUBGROUP_SIZE \
77 if constexpr(TCooperative) \
78 { \
79 auto const kernel = [item_elements, dyn_shared_accessor, st_shared_accessor, k_func, k_args]( \
80 sycl::nd_item<TDim::value> work_item) \
81 { \
82 auto acc = TAcc{item_elements, work_item, dyn_shared_accessor, st_shared_accessor}; \
83 std::apply([&](auto&&... args) { detail::checkKernelReturnType(k_func, acc, args...); }, k_args); \
84 std::apply( \
85 [k_func, &acc](typename std::decay_t<TArgs> const&... args) { k_func(acc, args...); }, \
86 k_args); \
87 }; \
88 cgh.parallel_for<detail::SyclKernel<TKernelFnObj, TDim, TIdx, TArgs...>>( \
89 sycl::nd_range<TDim::value>{global_size, local_size}, \
90 detail::SyclRootSyncKernel<0, TDim::value, std::remove_const_t<decltype(kernel)>>{kernel}); \
91 } \
92 else \
93 { \
94 cgh.parallel_for( \
95 sycl::nd_range<TDim::value>{global_size, local_size}, \
96 [item_elements, dyn_shared_accessor, st_shared_accessor, k_func, k_args]( \
97 sycl::nd_item<TDim::value> work_item) \
98 { \
99 auto acc = TAcc{item_elements, work_item, dyn_shared_accessor, st_shared_accessor}; \
100 std::apply([&](auto&&... args) { detail::checkKernelReturnType(k_func, acc, args...); }, k_args); \
101 std::apply( \
102 [k_func, &acc](typename std::decay_t<TArgs> const&... args) { k_func(acc, args...); }, \
103 k_args); \
104 }); \
105 }
106
107# define THROW_AND_LAUNCH_EMPTY_SYCL_KERNEL \
108 throw std::runtime_error( \
109 "The SYCL targets do not support the sub-group size " + std::to_string(sub_group_size) \
110 + " required by the kernel on " + getAccName<TAcc>()); \
111 if constexpr(TCooperative) \
112 { \
113 cgh.parallel_for<detail::SyclKernel<TKernelFnObj, TDim, TIdx, TArgs...>>( \
114 sycl::nd_range<TDim::value>{global_size, local_size}, \
115 [item_elements, dyn_shared_accessor, st_shared_accessor, k_func, k_args]( \
116 sycl::nd_item<TDim::value> work_item) {}); \
117 } \
118 else \
119 { \
120 cgh.parallel_for( \
121 sycl::nd_range<TDim::value>{global_size, local_size}, \
122 [item_elements, dyn_shared_accessor, st_shared_accessor, k_func, k_args]( \
123 sycl::nd_item<TDim::value> work_item) {}); \
124 }
125
126namespace alpaka
127{
128 namespace detail
129 {
130 // A dummy class to pass as a template parameter when launching cooperative kernels
131 template<typename TKernel, typename TDim, typename TIdx, typename... TArgs>
132 class SyclKernel;
133
134 //! Wrap a SYCL kernel to launch it with the use_root_sync property, which is required to synchronise the
135 //! root group, i.e. all the work-items in the grid. If TSubGroupSize is not zero, require that sub-group size.
136 template<std::size_t TSubGroupSize, int TDims, typename TKernel>
137 struct SyclRootSyncKernel
138 {
139 TKernel kernel;
140
141 auto operator()(sycl::nd_item<TDims> work_item) const -> void
142 {
143 kernel(work_item);
144 }
145
146 auto get(sycl::ext::oneapi::experimental::properties_tag) const
147 {
148 namespace syclex = sycl::ext::oneapi::experimental;
149 if constexpr(TSubGroupSize == 0)
150 return syclex::properties{syclex::use_root_sync};
151 else
152 return syclex::properties{syclex::use_root_sync, syclex::sub_group_size<TSubGroupSize>};
153 }
154 };
155
156 // The size of the static shared memory, allocated as a local accessor -- value comes from the build system
157 inline constexpr auto syclStaticSharedMemBytes = std::size_t{ALPAKA_BLOCK_SHARED_DYN_MEMBER_ALLOC_KIB * 1024};
158
159 //! Convert the number of threads in a block to the size of a SYCL work-group.
160 template<typename TDim, typename TIdx>
161 auto syclWorkGroupSize(Vec<TDim, TIdx> const& group_items)
162 {
163 if constexpr(TDim::value == 1)
164 return sycl::range<1>{static_cast<std::size_t>(group_items[0])};
165 else if constexpr(TDim::value == 2)
166 return sycl::range<2>{
167 static_cast<std::size_t>(group_items[0]),
168 static_cast<std::size_t>(group_items[1])};
169 else
170 return sycl::range<3>{
171 static_cast<std::size_t>(group_items[0]),
172 static_cast<std::size_t>(group_items[1]),
173 static_cast<std::size_t>(group_items[2])};
174 }
175
176 //! The maximum number of work-groups of the kernel TKernelName that can be active at the same time on the
177 //! device of the given queue, i.e. the largest grid that can be used for a cooperative launch.
178 //!
179 //! \param localMemBytes The total size of the local memory accessors used by the kernel.
180 template<typename TKernelName, int TDims>
181 auto getMaxNumWorkGroupsSync(
182 sycl::queue const& queue,
183 [[maybe_unused]] sycl::range<TDims> const& workGroupSize,
184 [[maybe_unused]] std::size_t localMemBytes) -> std::size_t
185 {
186 auto const bundle = sycl::get_kernel_bundle<sycl::bundle_state::executable>(queue.get_context());
187 auto const kernel = bundle.template get_kernel<TKernelName>();
188# if ALPAKA_COMP_ICPX >= ALPAKA_VERSION_NUMBER(2025, 1, 0)
189 // oneAPI 2025.1 replaced the max_num_work_group_sync query with max_num_work_groups, which depends also
190 // on the work-group size and on the amount of local memory used by the kernel.
191 return kernel.template ext_oneapi_get_info<
192 sycl::ext::oneapi::experimental::info::kernel_queue_specific::max_num_work_groups>(
193 queue,
194 workGroupSize,
195 localMemBytes);
196# else
197 return kernel.template ext_oneapi_get_info<
198 sycl::ext::oneapi::experimental::info::kernel_queue_specific::max_num_work_group_sync>(queue);
199# endif
200 }
201 } // namespace detail
202
203 //! The SYCL accelerator execution task.
204 template<
205 concepts::Tag TTag,
206 typename TAcc,
207 typename TDim,
208 typename TIdx,
209 typename TKernelFnObj,
210 bool TCooperative,
211 typename... TArgs>
212 class TaskKernelGenericSycl final : public WorkDivMembers<TDim, TIdx>
213 {
214 public:
215 static_assert(TDim::value > 0 && TDim::value <= 3, "Invalid kernel dimensionality");
216
217 template<typename TWorkDiv>
218 TaskKernelGenericSycl(TWorkDiv&& workDiv, TKernelFnObj const& kernelFnObj, TArgs&&... args)
219 : WorkDivMembers<TDim, TIdx>(std::forward<TWorkDiv>(workDiv))
220 , m_kernelFnObj{kernelFnObj}
221 , m_args{std::forward<TArgs>(args)...}
222 {
223 }
224
225 auto operator()(sycl::handler& cgh, sycl::queue const& queue) const -> void
226 {
227 auto const work_groups = WorkDivMembers<TDim, TIdx>::m_gridBlockExtent;
228 auto const group_items = WorkDivMembers<TDim, TIdx>::m_blockThreadExtent;
229 auto const item_elements = WorkDivMembers<TDim, TIdx>::m_threadElemExtent;
230
231 auto const global_size = get_global_size(work_groups, group_items);
232 auto const local_size = get_local_size(group_items);
233
234 // allocate dynamic shared memory -- needs at least 1 byte to make the Xilinx Runtime happy
235 auto const dyn_shared_mem_bytes = std::max(
236 1ul,
237 std::apply(
238 [&](std::decay_t<TArgs> const&... args) {
239 return getBlockSharedMemDynSizeBytes<TAcc>(m_kernelFnObj, group_items, item_elements, args...);
240 },
241 m_args));
242
243 auto dyn_shared_accessor = sycl::local_accessor<std::byte>{sycl::range<1>{dyn_shared_mem_bytes}, cgh};
244
245 // allocate static shared memory -- value comes from the build system
246 constexpr auto st_shared_mem_bytes = detail::syclStaticSharedMemBytes;
247 auto st_shared_accessor = sycl::local_accessor<std::byte>{sycl::range<1>{st_shared_mem_bytes}, cgh};
248
249 // copy-by-value so we don't access 'this' on the device
250 auto k_func = m_kernelFnObj;
251 auto k_args = m_args;
252
253 constexpr std::size_t sub_group_size = trait::warpSize<TKernelFnObj, TAcc>;
254
255 // The SYCL CPU device forms sub-groups only along the innermost (fastest) dimension of the work-group,
256 // while GPUs (and CUDA and HIP) form warps from the linearised thread index. For multi-dimensional kernels
257 // that require a warp size, the innermost block extent must be a multiple of the warp size, otherwise the
258 // warps would be split and the warp operations would give wrong results.
259 if constexpr(std::is_same_v<TTag, TagCpuSycl> && TDim::value > 1 && sub_group_size > 0)
260 {
261 auto const innermost = static_cast<std::size_t>(group_items[TDim::value - 1]);
262 if(innermost % sub_group_size != 0)
263 {
264 throw std::runtime_error(
265 "On the SYCL CPU device, the innermost block extent (" + std::to_string(innermost)
266 + ") must be a multiple of the warp size (" + std::to_string(sub_group_size)
267 + ") because sub-groups are formed only along the innermost dimension");
268 }
269 }
270
271 bool supported = false;
272
273 if constexpr(TCooperative)
274 {
275 // Check that the device supports cooperative kernels before launching one: on devices that do not,
276 // launching a kernel with the use_root_sync property fails or gives undefined behaviour.
277 if(!detail::syclCooperativeLaunch<TTag>(queue.get_device()))
278 {
279 throw std::runtime_error(
280 "The device " + queue.get_device().get_info<sycl::info::device::name>() + " ("
281 + getAccName<TAcc>() + ") does not support cooperative kernels");
282 }
283 }
284
285# if ALPAKA_DEBUG >= ALPAKA_DEBUG_MINIMAL
286 if constexpr(TCooperative)
287 {
288 std::size_t const maxWGs
289 = detail::getMaxNumWorkGroupsSync<detail::SyclKernel<TKernelFnObj, TDim, TIdx, TArgs...>>(
290 queue,
291 local_size,
292 dyn_shared_mem_bytes + st_shared_mem_bytes);
293 if(static_cast<std::size_t>(work_groups.prod()) > maxWGs)
294 {
295 throw std::runtime_error(
296 "The number of requested blocks is larger than maximuma of the device for the kernel "
297 + std::string(core::demangled<TKernelFnObj>) + "! Device: " + getAccName<TAcc>()
298 + ", requested: " + std::to_string(work_groups.prod())
299 + ", maximum allowed: " + std::to_string(maxWGs) + ". Use getMaxActiveBlocks().");
300 }
301# if ALPAKA_DEBUG >= ALPAKA_DEBUG_FULL
302 std::cout << "maxBlocksPerGrid for the " << core::demangled<TKernelFnObj> << ": " << maxWGs
303 << std::endl;
304# endif
305 }
306# endif
307
308 if constexpr(sub_group_size == 0)
309 {
310 // no explicit subgroup size requirement
311 LAUNCH_SYCL_KERNEL_WITH_DEFAULT_SUBGROUP_SIZE
312 supported = true;
313 }
314 else
315 {
316# if(SYCL_SUBGROUP_SIZE == 0)
317 // no explicit SYCL target, assume JIT compilation
318 LAUNCH_SYCL_KERNEL_IF_SUBGROUP_SIZE_IS(sub_group_size)
319 supported = true;
320# else
321 // check if the kernel should be launched with a subgroup size of 4
322 if constexpr(sub_group_size == 4)
323 {
324# if(SYCL_SUBGROUP_SIZE & 4)
325 LAUNCH_SYCL_KERNEL_IF_SUBGROUP_SIZE_IS(4)
326 supported = true;
327# else
328 // empty kernel, required to keep SYCL happy
329 THROW_AND_LAUNCH_EMPTY_SYCL_KERNEL
330# endif
331 }
332
333 // check if the kernel should be launched with a subgroup size of 8
334 if constexpr(sub_group_size == 8)
335 {
336# if(SYCL_SUBGROUP_SIZE & 8)
337 LAUNCH_SYCL_KERNEL_IF_SUBGROUP_SIZE_IS(8)
338 supported = true;
339# else
340 // empty kernel, required to keep SYCL happy
341 THROW_AND_LAUNCH_EMPTY_SYCL_KERNEL
342# endif
343 }
344
345 // check if the kernel should be launched with a subgroup size of 16
346 if constexpr(sub_group_size == 16)
347 {
348# if(SYCL_SUBGROUP_SIZE & 16)
349 LAUNCH_SYCL_KERNEL_IF_SUBGROUP_SIZE_IS(16)
350 supported = true;
351# else
352 // empty kernel, required to keep SYCL happy
353 THROW_AND_LAUNCH_EMPTY_SYCL_KERNEL
354# endif
355 }
356
357 // check if the kernel should be launched with a subgroup size of 32
358 if constexpr(sub_group_size == 32)
359 {
360# if(SYCL_SUBGROUP_SIZE & 32)
361 LAUNCH_SYCL_KERNEL_IF_SUBGROUP_SIZE_IS(32)
362 supported = true;
363# else
364 // empty kernel, required to keep SYCL happy
365 THROW_AND_LAUNCH_EMPTY_SYCL_KERNEL
366# endif
367 }
368
369 // check if the kernel should be launched with a subgroup size of 64
370 if constexpr(sub_group_size == 64)
371 {
372# if(SYCL_SUBGROUP_SIZE & 64)
373 LAUNCH_SYCL_KERNEL_IF_SUBGROUP_SIZE_IS(64)
374 supported = true;
375# else
376 // empty kernel, required to keep SYCL happy
377 THROW_AND_LAUNCH_EMPTY_SYCL_KERNEL
378# endif
379 }
380# endif
381
382 // this subgroup size is not supported, raise an exception
383 if(not supported)
384 throw std::runtime_error(
385 "The SYCL targets do not support the sub-group size " + std::to_string(sub_group_size)
386 + " required by the kernel on " + getAccName<TAcc>());
387 }
388 }
389
390 static constexpr auto is_sycl_task = true;
391 // Distinguish from other tasks
392 static constexpr auto is_sycl_kernel = true;
393
394 private:
395 auto get_global_size(Vec<TDim, TIdx> const& work_groups, Vec<TDim, TIdx> const& group_items) const
396 {
397 if constexpr(TDim::value == 1)
398 return sycl::range<1>{static_cast<std::size_t>(work_groups[0] * group_items[0])};
399 else if constexpr(TDim::value == 2)
400 return sycl::range<2>{
401 static_cast<std::size_t>(work_groups[0] * group_items[0]),
402 static_cast<std::size_t>(work_groups[1] * group_items[1])};
403 else
404 return sycl::range<3>{
405 static_cast<std::size_t>(work_groups[0] * group_items[0]),
406 static_cast<std::size_t>(work_groups[1] * group_items[1]),
407 static_cast<std::size_t>(work_groups[2] * group_items[2])};
408 }
409
410 auto get_local_size(Vec<TDim, TIdx> const& group_items) const
411 {
412 return detail::syclWorkGroupSize(group_items);
413 }
414
415 public:
416 TKernelFnObj m_kernelFnObj;
417 std::tuple<std::decay_t<TArgs>...> m_args;
418 };
419
420} // namespace alpaka
421
422# if ALPAKA_COMP_CLANG
423# pragma clang diagnostic pop
424# endif
425
426namespace alpaka::trait
427{
428 //! The SYCL execution task accelerator type trait specialization.
429 template<typename TAcc, typename TDim, typename TIdx, typename TKernelFnObj, typename... TArgs>
430 struct AccType<TaskKernelGenericSycl<TAcc, TDim, TIdx, TKernelFnObj, TArgs...>>
431 {
432 using type = TAcc;
433 };
434
435 //! The SYCL execution task device type trait specialization.
436 template<typename TAcc, typename TDim, typename TIdx, typename TKernelFnObj, typename... TArgs>
437 struct DevType<TaskKernelGenericSycl<TAcc, TDim, TIdx, TKernelFnObj, TArgs...>>
438 {
439 using type = typename DevType<TAcc>::type;
440 };
441
442 //! The SYCL execution task platform type trait specialization.
443 template<typename TAcc, typename TDim, typename TIdx, typename TKernelFnObj, typename... TArgs>
444 struct PlatformType<TaskKernelGenericSycl<TAcc, TDim, TIdx, TKernelFnObj, TArgs...>>
445 {
446 using type = typename PlatformType<TAcc>::type;
447 };
448
449 //! The SYCL execution task dimension getter trait specialization.
450 template<typename TAcc, typename TDim, typename TIdx, typename TKernelFnObj, typename... TArgs>
451 struct DimType<TaskKernelGenericSycl<TAcc, TDim, TIdx, TKernelFnObj, TArgs...>>
452 {
453 using type = TDim;
454 };
455
456 //! The SYCL execution task idx type trait specialization.
457 template<typename TAcc, typename TDim, typename TIdx, typename TKernelFnObj, typename... TArgs>
458 struct IdxType<TaskKernelGenericSycl<TAcc, TDim, TIdx, TKernelFnObj, TArgs...>>
459 {
460 using type = TIdx;
461 };
462
463 //! \brief Specialisation of the class template FunctionAttributes
464 //! \tparam TTag The SYCL device selector.
465 //! \tparam TDev The device type.
466 //! \tparam TDim The dimensionality of the accelerator device properties.
467 //! \tparam TIdx The idx type of the accelerator device properties.
468 //! \tparam TKernelFn Kernel function object type.
469 //! \tparam TArgs Kernel function object argument types as a parameter pack.
470 template<concepts::Tag TTag, typename TDev, typename TDim, typename TIdx, typename TKernelFn, typename... TArgs>
471 struct FunctionAttributes<AccGenericSycl<TTag, TDim, TIdx>, TDev, TKernelFn, TArgs...>
472 {
473 //! \param dev The device instance
474 //! \param kernelFn The kernel function object which should be executed.
475 //! \param args The kernel invocation arguments.
476 //! \return KernelFunctionAttributes instance. The default version always returns an instance with zero
477 //! fields. For CPU, the field of max threads allowed by kernel function for the block is 1.
479 TDev const& dev,
480 [[maybe_unused]] TKernelFn const& kernelFn,
481 [[maybe_unused]] TArgs&&... args) -> alpaka::KernelFunctionAttributes
482 {
483 alpaka::KernelFunctionAttributes kernelFunctionAttributes;
484
485 // set function properties for maxThreadsPerBlock to device properties
487 kernelFunctionAttributes.maxThreadsPerBlock = static_cast<int>(props.m_blockThreadCountMax);
488 return kernelFunctionAttributes;
489 }
490 };
491
492 //! The CUDA/HIP get max active blocks for cooperative kernel specialization.
493 template<typename TAcc, typename TKernelFnObj, typename TTag, typename TDim, typename TIdx, typename... TArgs>
494 struct MaxActiveBlocks<TAcc, DevGenericSycl<TTag>, TKernelFnObj, TDim, TIdx, TArgs...>
495 {
497 TKernelFnObj const& kernelFnObj,
498 DevGenericSycl<TTag> const& device,
499 alpaka::Vec<TDim, TIdx> const& blockThreadExtent,
500 alpaka::Vec<TDim, TIdx> const& threadElemExtent,
501 TArgs const&... args) -> int
502 {
503 // the kernel uses the dynamic and the static shared memory, see TaskKernelGenericSycl::operator()
504 auto const dynSharedMemBytes = std::max(
505 std::size_t{1},
506 static_cast<std::size_t>(
507 getBlockSharedMemDynSizeBytes<TAcc>(kernelFnObj, blockThreadExtent, threadElemExtent, args...)));
508
509 sycl::queue queue{
510 std::move(device.getNativeHandle()
511 .second), // This is important. In SYCL a device can belong to multiple contexts.
512 std::move(device.getNativeHandle().first),
513 {sycl::property::queue::enable_profiling{}, sycl::property::queue::in_order{}}};
514
515 std::size_t const maxWGs
516 = detail::getMaxNumWorkGroupsSync<detail::SyclKernel<TKernelFnObj, TDim, TIdx, TArgs...>>(
517 queue,
518 detail::syclWorkGroupSize(blockThreadExtent),
519 dynSharedMemBytes + detail::syclStaticSharedMemBytes);
520 return static_cast<int>(maxWGs);
521 }
522 };
523} // namespace alpaka::trait
524
525# undef LAUNCH_SYCL_KERNEL_IF_SUBGROUP_SIZE_IS
526
527#endif
#define ALPAKA_BLOCK_SHARED_DYN_MEMBER_ALLOC_KIB
A n-dimensional vector.
Definition Vec.hpp:38
#define ALPAKA_FN_HOST
Definition Common.hpp:43
The accelerator traits.
The alpaka accelerator library.
ALPAKA_FN_HOST auto getAccDevProps(TDev const &dev) -> AccDevProps< Dim< TAcc >, Idx< TAcc > >
Definition Traits.hpp:95
WorkDivMembers(alpaka::Vec< TDim, TIdx > const &gridBlockExtent, alpaka::Vec< TDim, TIdx > const &blockThreadExtent, alpaka::Vec< TDim, TIdx > const &elemExtent) -> WorkDivMembers< TDim, TIdx >
Deduction guide for the constructor which can be called without explicit template type parameters.
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto getMaxActiveBlocks(TDev const &device, TKernelFnObj const &kernelFnObj, alpaka::Vec< TDim, TIdx > const &blockThreadExtent, alpaka::Vec< TDim, TIdx > const &threadElemExtent, TArgs const &... args) -> int
Definition Traits.hpp:248
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto getBlockSharedMemDynSizeBytes(TKernelFnObj const &kernelFnObj, Vec< TDim, Idx< TAcc > > const &blockThreadExtent, Vec< TDim, Idx< TAcc > > const &threadElemExtent, TArgs const &... args) -> std::size_t
Definition Traits.hpp:197
STL namespace.
Kernel function attributes struct. Attributes are filled by calling the API of the accelerator using ...
static ALPAKA_FN_HOST auto getFunctionAttributes(TDev const &dev, TKernelFnObj const &kernelFn, TArgs &&... args) -> alpaka::KernelFunctionAttributes
Definition Traits.hpp:100