alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
trait.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
10#include "alpaka/tag.hpp"
11
12#include <algorithm>
13#include <cstdint>
14
15namespace alpaka
16{
17 namespace trait
18 {
19 /** Map's all API's by default to stl math functions. */
21 {
22 template<alpaka::concepts::Api T_Api>
23 struct Op
24 {
25 constexpr decltype(auto) operator()(T_Api const) const
26 {
28 }
29 };
30 };
31
32 template<alpaka::concepts::Api T_Api>
33 constexpr decltype(auto) getMathImpl(T_Api const api)
34 {
36 }
37
38 /** Defines the implementation used for intrinsics */
40 {
41 template<alpaka::concepts::Api T_Api>
42 struct Op
43 {
44 constexpr decltype(auto) operator()(T_Api const) const
45 {
46 static_assert(
47 sizeof(T_Api) && false,
48 "Intrinsic implementation for the current used API is not defined.");
49 return 0;
50 }
51 };
52 };
53
54 template<alpaka::concepts::Api T_Api>
55 constexpr decltype(auto) getIntrinsicImpl(T_Api const api)
56 {
58 }
59
61 {
62 template<typename T_Type, alpaka::concepts::Api T_Api, alpaka::concepts::DeviceKind T_DeviceKind>
63 struct Op
64 {
65 consteval uint32_t operator()(T_Api const, T_DeviceKind const) const
66 {
67 static_assert(sizeof(T_Api) && false, "Missing definition of GetArchSimdWidth for API.");
68 return 1u;
69 }
70 };
71 };
72
73 /** Number of commands a CPU can issue at the same time. */
75 {
76 template<alpaka::concepts::Api T_Api, alpaka::concepts::DeviceKind T_DeviceKind>
77 struct Op
78 {
79 /** @return the return value must be >= 1 */
80 consteval uint32_t operator()(T_Api const, T_DeviceKind const) const
81 {
82 static_assert(sizeof(T_Api) && false, "Missing definition of GetNumPipelines for API.");
83 return 1u;
84 }
85 };
86 };
87
89 {
90 template<alpaka::concepts::Api T_Api, alpaka::concepts::DeviceKind T_DeviceKind>
91 struct Op
92 {
93 consteval uint32_t operator()(T_Api const, T_DeviceKind const) const
94 {
95 static_assert(sizeof(T_Api) && false, "GetCachelineSize for the current used API is not defined.");
96 return 42u;
97 }
98 };
99 };
100
101 // true for alpaka MdSpan implementations
102 template<typename T>
103 struct IsExecutor : std::false_type
104 {
105 };
106
107 /** Adjusting the requested in alignment in order to meet device specific constraints. */
109 {
110 template<typename T_Type, concepts::Api T_Api, concepts::DeviceKind T_DeviceKind>
111 struct Op
112 {
113 consteval uint32_t operator()(T_Api const, T_DeviceKind const, uint32_t const alignment) const
114 {
115 return alignment;
116 }
117 };
118 };
119 } // namespace trait
120
121 template<typename T>
123
124 namespace concepts
125 {
126 /** @brief Concept to check for an executor
127 *
128 * @details
129 * An executor in alpaka is a specific way of executing on an alpaka::onHost::Device. Examples of executors are
130 * alpaka::exec::GpuCuda or alpaka::onHost::cpu::OmpBlocks.
131 */
132 template<typename T>
134 } // namespace concepts
135
136 constexpr bool operator==(concepts::Executor auto lhs, concepts::Executor auto rhs)
137 {
138 return std::is_same_v<ALPAKA_TYPEOF(lhs), ALPAKA_TYPEOF(rhs)>;
139 }
140
141 constexpr bool operator!=(concepts::Executor auto lhs, concepts::Executor auto rhs)
142 {
143 return !(lhs == rhs);
144 }
145
146 /** Get the SIMD width in bytes for an API and device kind combination.
147 *
148 * @tparam T_Type data type
149 * @return number of elements that can be processed in parallel in a vector register
150 */
151 template<typename T_Type>
152 consteval uint32_t getArchSimdWidth(
153 concepts::Api auto const api,
154 alpaka::concepts::DeviceKind auto const deviceType)
155 {
156 return trait::GetArchSimdWidth::Op<T_Type, ALPAKA_TYPEOF(api), ALPAKA_TYPEOF(deviceType)>{}(api, deviceType);
157 }
158
159 /** Get the number of instructions that can be issued in parallel
160 */
161 consteval uint32_t getNumPipelines(
162 concepts::Api auto const api,
163 alpaka::concepts::DeviceKind auto const deviceType)
164 {
165 return trait::GetNumPipelines::Op<ALPAKA_TYPEOF(api), ALPAKA_TYPEOF(deviceType)>{}(api, deviceType);
166 }
167
168 /** Get the number of elements to compute per thread
169 *
170 * This function considers the SIMD width for the corresponding data type and the potential for instruction
171 * parallelism.
172 *
173 * @tparam T_Type The data type used to determine the SIMD width.
174 * @return The minimum number of elements a thread should compute to achieve optimal utilization.
175 */
176 template<typename T_Type>
177 consteval uint32_t getNumElemPerThread(
178 concepts::Api auto const api,
179 alpaka::concepts::DeviceKind auto const deviceType)
180 {
181 return getArchSimdWidth<T_Type>(api, deviceType) * getNumPipelines(api, deviceType);
182 }
183
184 /** get the cacheline size in bytes
185 *
186 * Cache line size is the distance between two memory address that guarantees to be false sharing free.
187 *
188 * @return cacheline size in bytes
189 */
190 consteval uint32_t getCachelineSize(
191 concepts::Api auto const api,
192 alpaka::concepts::DeviceKind auto const deviceType)
193 {
194 return trait::GetCachelineSize::Op<ALPAKA_TYPEOF(api), ALPAKA_TYPEOF(deviceType)>{}(api, deviceType);
195 }
196
197 /**
198 * @brief Adjusts the memory alignment based on a specific API and device kind.
199 * @tparam T_Type The data type being allocated.
200 * @param alignment the previously selected alignment
201 * @return adjusted alignment in bytes
202 */
203 template<typename T_Type>
204 consteval uint32_t getAdjustedAlignment(
205 concepts::Api auto const api,
206 concepts::DeviceKind auto const deviceType,
207 auto const alignment)
208 {
209 auto val = trait::GetAdjustedAlignment::Op<T_Type, ALPAKA_TYPEOF(api), ALPAKA_TYPEOF(deviceType)>{}(
210 api,
211 deviceType,
212 alignment);
213 return val;
214 }
215
216 namespace onAcc::trait
217 {
218 /** Defines the implementation used for atomic operations toghether with the used executor */
220 {
221 template<alpaka::concepts::Executor T_Executor, typename T_AtomicScope>
222 struct Op
223 {
224 constexpr decltype(auto) operator()(T_Executor const) const
225 {
226 static_assert(
227 sizeof(T_Executor) && false,
228 "Atomic implementation for the current used executor is not defined.");
229 return 0;
230 }
231 };
232 };
233
234 template<alpaka::concepts::Executor T_Executor, typename T_AtomicScope>
235 constexpr decltype(auto) getAtomicImpl(T_Executor const executor, T_AtomicScope const atomicScope)
236 {
237 return GetAtomicImpl::Op<T_Executor, T_AtomicScope>{}(executor, atomicScope);
238 }
239 } // namespace onAcc::trait
240} // namespace alpaka
#define ALPAKA_TYPEOF(...)
Get the type of instance.
Definition common.hpp:154
Concept to check for APIs.
Definition api.hpp:42
Concept to check if something is a device kind.
Definition tag.hpp:145
Concept to check for an executor.
Definition trait.hpp:133
constexpr auto stlMath
Definition stlMath.hpp:17
constexpr decltype(auto) getAtomicImpl(T_Executor const executor, T_AtomicScope const atomicScope)
Definition trait.hpp:235
constexpr decltype(auto) getMathImpl(T_Api const api)
Definition trait.hpp:33
constexpr decltype(auto) getIntrinsicImpl(T_Api const api)
Definition trait.hpp:55
main alpaka namespace.
Definition alpaka.hpp:76
consteval uint32_t getNumPipelines(concepts::Api auto const api, alpaka::concepts::DeviceKind auto const deviceType)
Get the number of instructions that can be issued in parallel.
Definition trait.hpp:161
consteval uint32_t getNumElemPerThread(concepts::Api auto const api, alpaka::concepts::DeviceKind auto const deviceType)
Get the number of elements to compute per thread.
Definition trait.hpp:177
consteval uint32_t getCachelineSize(concepts::Api auto const api, alpaka::concepts::DeviceKind auto const deviceType)
get the cacheline size in bytes
Definition trait.hpp:190
constexpr bool isExecutor
Definition trait.hpp:122
consteval uint32_t getArchSimdWidth(concepts::Api auto const api, alpaka::concepts::DeviceKind auto const deviceType)
Get the SIMD width in bytes for an API and device kind combination.
Definition trait.hpp:152
constexpr bool operator!=(concepts::Executor auto lhs, concepts::Executor auto rhs)
Definition trait.hpp:141
consteval uint32_t getAdjustedAlignment(concepts::Api auto const api, concepts::DeviceKind auto const deviceType, auto const alignment)
Adjusts the memory alignment based on a specific API and device kind.
Definition trait.hpp:204
constexpr bool operator==(concepts::Executor auto lhs, concepts::Executor auto rhs)
Definition trait.hpp:136
Defines the implementation used for atomic operations toghether with the used executor.
Definition trait.hpp:220
consteval uint32_t operator()(T_Api const, T_DeviceKind const, uint32_t const alignment) const
Definition trait.hpp:113
Adjusting the requested in alignment in order to meet device specific constraints.
Definition trait.hpp:109
consteval uint32_t operator()(T_Api const, T_DeviceKind const) const
Definition trait.hpp:65
consteval uint32_t operator()(T_Api const, T_DeviceKind const) const
Definition trait.hpp:93
Defines the implementation used for intrinsics.
Definition trait.hpp:40
Map's all API's by default to stl math functions.
Definition trait.hpp:21
consteval uint32_t operator()(T_Api const, T_DeviceKind const) const
Definition trait.hpp:80
Number of commands a CPU can issue at the same time.
Definition trait.hpp:75