Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_Concepts.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>
19 static_assert(false,
20  "Including non-public Kokkos header files is not allowed.");
21 #endif
22 #ifndef KOKKOS_CORE_CONCEPTS_HPP
23 #define KOKKOS_CORE_CONCEPTS_HPP
24 
25 #include <type_traits>
26 
27 // Needed for 'is_space<S>::host_mirror_space
28 #include <Kokkos_Core_fwd.hpp>
29 
30 #include <Kokkos_DetectionIdiom.hpp>
31 
32 //----------------------------------------------------------------------------
33 //----------------------------------------------------------------------------
34 
35 namespace Kokkos {
36 
37 // Schedules for Execution Policies
38 struct Static {};
39 struct Dynamic {};
40 
41 // Schedule Wrapper Type
42 template <class T>
43 struct Schedule {
44  static_assert(std::is_same<T, Static>::value ||
45  std::is_same<T, Dynamic>::value,
46  "Kokkos: Invalid Schedule<> type.");
47  using schedule_type = Schedule;
48  using type = T;
49 };
50 
51 // Specify Iteration Index Type
52 template <typename T>
53 struct IndexType {
54  static_assert(std::is_integral<T>::value, "Kokkos: Invalid IndexType<>.");
55  using index_type = IndexType;
56  using type = T;
57 };
58 
59 namespace Experimental {
60 struct WorkItemProperty {
61  template <unsigned long Property>
62  struct ImplWorkItemProperty {
63  static const unsigned value = Property;
64  using work_item_property = ImplWorkItemProperty<Property>;
65  };
66 
67  constexpr static const ImplWorkItemProperty<0> None =
68  ImplWorkItemProperty<0>();
69  constexpr static const ImplWorkItemProperty<1> HintLightWeight =
70  ImplWorkItemProperty<1>();
71  constexpr static const ImplWorkItemProperty<2> HintHeavyWeight =
72  ImplWorkItemProperty<2>();
73  constexpr static const ImplWorkItemProperty<4> HintRegular =
74  ImplWorkItemProperty<4>();
75  constexpr static const ImplWorkItemProperty<8> HintIrregular =
76  ImplWorkItemProperty<8>();
77  constexpr static const ImplWorkItemProperty<16> ImplForceGlobalLaunch =
78  ImplWorkItemProperty<16>();
79  using None_t = ImplWorkItemProperty<0>;
80  using HintLightWeight_t = ImplWorkItemProperty<1>;
81  using HintHeavyWeight_t = ImplWorkItemProperty<2>;
82  using HintRegular_t = ImplWorkItemProperty<4>;
83  using HintIrregular_t = ImplWorkItemProperty<8>;
84  using ImplForceGlobalLaunch_t = ImplWorkItemProperty<16>;
85 };
86 
87 template <unsigned long pv1, unsigned long pv2>
88 inline constexpr WorkItemProperty::ImplWorkItemProperty<pv1 | pv2> operator|(
89  WorkItemProperty::ImplWorkItemProperty<pv1>,
90  WorkItemProperty::ImplWorkItemProperty<pv2>) {
91  return WorkItemProperty::ImplWorkItemProperty<pv1 | pv2>();
92 }
93 
94 template <unsigned long pv1, unsigned long pv2>
95 inline constexpr WorkItemProperty::ImplWorkItemProperty<pv1 & pv2> operator&(
96  WorkItemProperty::ImplWorkItemProperty<pv1>,
97  WorkItemProperty::ImplWorkItemProperty<pv2>) {
98  return WorkItemProperty::ImplWorkItemProperty<pv1 & pv2>();
99 }
100 
101 template <unsigned long pv1, unsigned long pv2>
102 inline constexpr bool operator==(WorkItemProperty::ImplWorkItemProperty<pv1>,
103  WorkItemProperty::ImplWorkItemProperty<pv2>) {
104  return pv1 == pv2;
105 }
106 
107 } // namespace Experimental
108 
113 template <unsigned int maxT = 0 /* Max threads per block */
114  ,
115  unsigned int minB = 0 /* Min blocks per SM */
116  >
117 struct LaunchBounds {
118  using launch_bounds = LaunchBounds;
119  using type = LaunchBounds<maxT, minB>;
120  static constexpr unsigned int maxTperB{maxT};
121  static constexpr unsigned int minBperSM{minB};
122 };
123 
124 } // namespace Kokkos
125 
126 //----------------------------------------------------------------------------
127 //----------------------------------------------------------------------------
128 
129 namespace Kokkos {
130 
131 #define KOKKOS_IMPL_IS_CONCEPT(CONCEPT) \
132  template <typename T> \
133  struct is_##CONCEPT { \
134  private: \
135  template <typename U> \
136  using have_t = typename U::CONCEPT; \
137  template <typename U> \
138  using have_type_t = typename U::CONCEPT##_type; \
139  \
140  public: \
141  static constexpr bool value = \
142  std::is_base_of<detected_t<have_t, T>, T>::value || \
143  std::is_base_of<detected_t<have_type_t, T>, T>::value; \
144  constexpr operator bool() const noexcept { return value; } \
145  }; \
146  template <typename T> \
147  inline constexpr bool is_##CONCEPT##_v = is_##CONCEPT<T>::value;
148 
149 // Public concept:
150 
151 KOKKOS_IMPL_IS_CONCEPT(memory_space)
152 KOKKOS_IMPL_IS_CONCEPT(memory_traits)
153 KOKKOS_IMPL_IS_CONCEPT(execution_space)
154 KOKKOS_IMPL_IS_CONCEPT(execution_policy)
155 KOKKOS_IMPL_IS_CONCEPT(array_layout)
156 KOKKOS_IMPL_IS_CONCEPT(reducer)
157 KOKKOS_IMPL_IS_CONCEPT(team_handle)
158 namespace Experimental {
159 KOKKOS_IMPL_IS_CONCEPT(work_item_property)
160 KOKKOS_IMPL_IS_CONCEPT(hooks_policy)
161 } // namespace Experimental
162 
163 namespace Impl {
164 
165 // Implementation concept:
166 
167 KOKKOS_IMPL_IS_CONCEPT(thread_team_member)
168 KOKKOS_IMPL_IS_CONCEPT(host_thread_team_member)
169 KOKKOS_IMPL_IS_CONCEPT(graph_kernel)
170 
171 } // namespace Impl
172 
173 #undef KOKKOS_IMPL_IS_CONCEPT
174 
175 } // namespace Kokkos
176 
177 namespace Kokkos {
178 namespace Impl {
179 
180 template <class Object>
181 class has_member_team_shmem_size {
182  template <typename T>
183  static int32_t test_for_member(decltype(&T::team_shmem_size)) {
184  return int32_t(0);
185  }
186  template <typename T>
187  static int64_t test_for_member(...) {
188  return int64_t(0);
189  }
190 
191  public:
192  constexpr static bool value =
193  sizeof(test_for_member<Object>(nullptr)) == sizeof(int32_t);
194 };
195 
196 template <class Object>
197 class has_member_shmem_size {
198  template <typename T>
199  static int32_t test_for_member(decltype(&T::shmem_size_me)) {
200  return int32_t(0);
201  }
202  template <typename T>
203  static int64_t test_for_member(...) {
204  return int64_t(0);
205  }
206 
207  public:
208  constexpr static bool value =
209  sizeof(test_for_member<Object>(0)) == sizeof(int32_t);
210 };
211 
212 } // namespace Impl
213 } // namespace Kokkos
214 //----------------------------------------------------------------------------
215 
216 namespace Kokkos {
217 
218 template <class ExecutionSpace, class MemorySpace>
219 struct Device {
220  static_assert(Kokkos::is_execution_space<ExecutionSpace>::value,
221  "Execution space is not valid");
222  static_assert(Kokkos::is_memory_space<MemorySpace>::value,
223  "Memory space is not valid");
224  using execution_space = ExecutionSpace;
225  using memory_space = MemorySpace;
226  using device_type = Device<execution_space, memory_space>;
227 };
228 
229 namespace Impl {
230 
231 template <typename T>
232 struct is_device_helper : std::false_type {};
233 
234 template <typename ExecutionSpace, typename MemorySpace>
235 struct is_device_helper<Device<ExecutionSpace, MemorySpace>> : std::true_type {
236 };
237 
238 } // namespace Impl
239 
240 template <typename T>
241 using is_device = typename Impl::is_device_helper<std::remove_cv_t<T>>::type;
242 
243 template <typename T>
244 inline constexpr bool is_device_v = is_device<T>::value;
245 
246 //----------------------------------------------------------------------------
247 
248 template <typename T>
249 struct is_space {
250  private:
251  template <typename, typename = void>
252  struct exe : std::false_type {
253  using space = void;
254  };
255 
256  template <typename, typename = void>
257  struct mem : std::false_type {
258  using space = void;
259  };
260 
261  template <typename, typename = void>
262  struct dev : std::false_type {
263  using space = void;
264  };
265 
266  template <typename U>
267  struct exe<U, std::conditional_t<true, void, typename U::execution_space>>
268  : std::is_same<U, typename U::execution_space>::type {
269  using space = typename U::execution_space;
270  };
271 
272  template <typename U>
273  struct mem<U, std::conditional_t<true, void, typename U::memory_space>>
274  : std::is_same<U, typename U::memory_space>::type {
275  using space = typename U::memory_space;
276  };
277 
278  template <typename U>
279  struct dev<U, std::conditional_t<true, void, typename U::device_type>>
280  : std::is_same<U, typename U::device_type>::type {
281  using space = typename U::device_type;
282  };
283 
284  using is_exe = typename is_space<T>::template exe<std::remove_cv_t<T>>;
285  using is_mem = typename is_space<T>::template mem<std::remove_cv_t<T>>;
286  using is_dev = typename is_space<T>::template dev<std::remove_cv_t<T>>;
287 
288  public:
289  static constexpr bool value = is_exe::value || is_mem::value || is_dev::value;
290 
291  constexpr operator bool() const noexcept { return value; }
292 
293  using execution_space = typename is_exe::space;
294  using memory_space = typename is_mem::space;
295 
296  // For backward compatibility, deprecated in favor of
297  // Kokkos::Impl::HostMirror<S>::host_mirror_space
298 
299  private:
300  // The actual definitions for host_memory_space and host_execution_spaces are
301  // in do_not_use_host_memory_space and do_not_use_host_execution_space to be
302  // able to use them within this class without deprecation warnings.
303  using do_not_use_host_memory_space = std::conditional_t<
304  std::is_same<memory_space, Kokkos::HostSpace>::value
305 #if defined(KOKKOS_ENABLE_CUDA)
306  || std::is_same<memory_space, Kokkos::CudaUVMSpace>::value ||
307  std::is_same<memory_space, Kokkos::CudaHostPinnedSpace>::value
308 #elif defined(KOKKOS_ENABLE_HIP)
309  || std::is_same<memory_space, Kokkos::HIPHostPinnedSpace>::value ||
310  std::is_same<memory_space, Kokkos::HIPManagedSpace>::value
311 #elif defined(KOKKOS_ENABLE_SYCL)
312  || std::is_same<memory_space,
313  Kokkos::Experimental::SYCLSharedUSMSpace>::value ||
314  std::is_same<memory_space,
315  Kokkos::Experimental::SYCLHostUSMSpace>::value
316 #endif
317  ,
318  memory_space, Kokkos::HostSpace>;
319 
320  using do_not_use_host_execution_space = std::conditional_t<
321 #if defined(KOKKOS_ENABLE_CUDA)
322  std::is_same<execution_space, Kokkos::Cuda>::value ||
323 #elif defined(KOKKOS_ENABLE_HIP)
324  std::is_same<execution_space, Kokkos::HIP>::value ||
325 #elif defined(KOKKOS_ENABLE_SYCL)
326  std::is_same<execution_space, Kokkos::Experimental::SYCL>::value ||
327 #elif defined(KOKKOS_ENABLE_OPENMPTARGET)
328  std::is_same<execution_space,
329  Kokkos::Experimental::OpenMPTarget>::value ||
330 #endif
331  false,
332  Kokkos::DefaultHostExecutionSpace, execution_space>;
333 };
334 
335 } // namespace Kokkos
336 
337 //----------------------------------------------------------------------------
338 
339 namespace Kokkos {
340 namespace Impl {
341 
347 template <typename DstMemorySpace, typename SrcMemorySpace>
348 struct MemorySpaceAccess {
349  static_assert(Kokkos::is_memory_space<DstMemorySpace>::value &&
350  Kokkos::is_memory_space<SrcMemorySpace>::value,
351  "template arguments must be memory spaces");
352 
360  enum { assignable = std::is_same<DstMemorySpace, SrcMemorySpace>::value };
361 
365  enum { accessible = assignable };
366 
370  enum { deepcopy = assignable };
371 };
372 
373 } // namespace Impl
374 } // namespace Kokkos
375 
376 namespace Kokkos {
377 
397 template <typename AccessSpace, typename MemorySpace>
398 struct SpaceAccessibility {
399  private:
400  static_assert(Kokkos::is_space<AccessSpace>::value,
401  "template argument #1 must be a Kokkos space");
402 
403  static_assert(Kokkos::is_memory_space<MemorySpace>::value,
404  "template argument #2 must be a Kokkos memory space");
405 
406  // The input AccessSpace may be a Device<ExecSpace,MemSpace>
407  // verify that it is a valid combination of spaces.
408  static_assert(Kokkos::Impl::MemorySpaceAccess<
409  typename AccessSpace::execution_space::memory_space,
410  typename AccessSpace::memory_space>::accessible,
411  "template argument #1 is an invalid space");
412 
413  using exe_access = Kokkos::Impl::MemorySpaceAccess<
414  typename AccessSpace::execution_space::memory_space, MemorySpace>;
415 
416  using mem_access =
417  Kokkos::Impl::MemorySpaceAccess<typename AccessSpace::memory_space,
418  MemorySpace>;
419 
420  public:
426  enum { accessible = exe_access::accessible };
427 
433  enum {
434  assignable = is_memory_space<AccessSpace>::value && mem_access::assignable
435  };
436 
438  enum { deepcopy = mem_access::deepcopy };
439 
440  // What intercessory space for AccessSpace::execution_space
441  // to be able to access MemorySpace?
442  // If same memory space or not accessible use the AccessSpace
443  // else construct a device with execution space and memory space.
444  using space = std::conditional_t<
445  std::is_same<typename AccessSpace::memory_space, MemorySpace>::value ||
446  !exe_access::accessible,
447  AccessSpace,
448  Kokkos::Device<typename AccessSpace::execution_space, MemorySpace>>;
449 };
450 
451 } // namespace Kokkos
452 
453 //----------------------------------------------------------------------------
454 
455 #endif // KOKKOS_CORE_CONCEPTS_HPP
Memory management for host memory.
Access relationship between DstMemorySpace and SrcMemorySpace.