alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
util.hpp
Go to the documentation of this file.
1/* Copyright 2025 René Widera
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5
6#pragma once
7
8#include "alpaka/CVec.hpp"
12#include "alpaka/tag.hpp"
13#include "alpaka/utility.hpp"
14
15#include <cstdint>
16#include <utility>
17
19{
20 namespace detail
21 {
22 template<
23 std::integral auto T_limit,
24 std::integral auto T_index,
25 std::integral auto T_increment,
26 std::integral auto... T_idx>
27 consteval auto adjustToLimit(concepts::CVector auto const input, std::index_sequence<T_idx...>)
28 {
29 if constexpr(input.product() <= static_cast<typename ALPAKA_TYPEOF(input)::type>(T_limit))
30 return input;
31 else
32 {
33 constexpr uint32_t dim = static_cast<uint32_t>(sizeof...(T_idx));
34
35 constexpr auto newValue = CVec<
36 typename ALPAKA_TYPEOF(input)::type,
37 (T_idx == T_index ? divExZero(input[T_idx], static_cast<typename ALPAKA_TYPEOF(input)::type>(2))
38 : input[T_idx])...>{};
39
40 constexpr auto nextIncrement = dim == 1u ? 0u : T_increment;
41 constexpr auto nextIdx = T_index + T_increment;
42
43 if constexpr(nextIdx == dim)
44 {
45 constexpr auto nextIncrement = dim == 1u ? 0u : -1u;
46
47 return adjustToLimit<T_limit, (dim == 1 ? 0 : dim - 1u), nextIncrement>(
48 newValue,
49 std::index_sequence<T_idx...>{});
50 }
51 else if constexpr(nextIdx == 0u)
52 {
53 return adjustToLimit<T_limit, nextIdx, 1u>(newValue, std::index_sequence<T_idx...>{});
54 }
55
56 return adjustToLimit<T_limit, nextIdx, nextIncrement>(newValue, std::index_sequence<T_idx...>{});
57 }
58 }
59 } // namespace detail
60
61 /** adjust the input vector to a given limit by halving all components
62 * until the product of these is below or equal to the limit */
63 template<std::integral auto T_limit, std::integral auto T_index, std::integral auto T_increment>
64 consteval auto adjustToLimit(concepts::CVector auto const input)
65 {
66 return detail::adjustToLimit<T_limit, 0u, 1u>(input, std::make_index_sequence<input.dim()>{});
67 }
68
69 /** adjust the input vector to a given limit by halving the largest dimension until the product of all components
70 * is below or equal to the limit */
71 inline auto adjustToLimit(concepts::Vector auto input, std::integral auto const limit)
72 {
73 using IdxType = typename ALPAKA_TYPEOF(input)::type;
74 constexpr uint32_t dim = input.dim();
75 IdxType limitValue = static_cast<IdxType>(limit);
76
77 while(input.product() > limitValue)
78 {
79 uint32_t maxIdx = 0u;
80 auto maxValue = input[0];
81 for(auto i = 0u; i < dim; ++i)
82 if(maxValue < input[i])
83 {
84 maxIdx = i;
85 maxValue = input[i];
86 }
87 if(input.product() > limitValue)
88 input[maxIdx] = divExZero(input[maxIdx], IdxType{2u});
89 }
90 return input;
91 }
92
93 /** provides a memory description to create multidimensional linewise aligned memory within a one dimensional
94 * byte area
95 *
96 * @param alignment data alignment in bytes
97 * @return tuple with the linearized data blob size in bytes and multi-dimensional pitches,
98 * std::tuple(numBytes,pitchMD)
99 */
100 template<typename T_ValueType, alpaka::concepts::Vector T_Extents>
101 inline auto emulatedAlignedMemDescription(uint32_t alignmentInByte, T_Extents extents)
102 {
103 constexpr auto dim = T_Extents::dim();
104 if constexpr(dim == 1u)
105 {
106 size_t memSizeInByte = static_cast<size_t>(extents.x()) * sizeof(T_ValueType);
107 alpaka::concepts::Vector auto pitches = typename T_Extents::UniVec{sizeof(T_ValueType)};
108 return std::make_tuple(memSizeInByte, pitches);
109 }
110 else
111 {
112 using IdxType = typename T_Extents::type;
113 auto alignment = static_cast<IdxType>(alignmentInByte);
114
115 IdxType rowExtentInBytes = extents.x() * static_cast<IdxType>(sizeof(T_ValueType));
116 IdxType rowPitchInBytes = alpaka::divCeil(rowExtentInBytes, alignment) * alignment;
117 auto pitches = alpaka::calculatePitches<T_ValueType>(extents, rowPitchInBytes);
118
119 size_t memSizeInByte = static_cast<size_t>(pitches[0]) * static_cast<size_t>(extents[0]);
120 return std::make_tuple(memSizeInByte, pitches);
121 }
122 }
123
124 consteval uint32_t highestPowerOfTwo(uint32_t value)
125 {
126 uint32_t result = 1u;
127 while((result << 1u) <= value)
128 {
129 result <<= 1u;
130 }
131 return result;
132 }
133
134 /** Calculate the best alignment for SIMD optimized memory allocation
135 *
136 * @param api the API to use
137 * @param deviceKind the device kind to use
138 * @return the best alignment in bytes, will be a power of two value
139 */
140 template<typename T_ValueType>
142 {
143 constexpr uint32_t typeAlignmentBytes = alignof(T_ValueType);
144 constexpr uint32_t simdPackBytes
145 = alpaka::getArchSimdWidth<T_ValueType>(api, deviceKind) * sizeof(T_ValueType);
146 constexpr uint32_t bestSimdPackBytes = highestPowerOfTwo(simdPackBytes);
147 constexpr uint32_t optimalAlignment = std::max(bestSimdPackBytes, typeAlignmentBytes);
148 constexpr uint32_t adjustedAlignment = getAdjustedAlignment<T_ValueType>(api, deviceKind, optimalAlignment);
149 return adjustedAlignment;
150 }
151} // namespace alpaka::api::util
#define ALPAKA_TYPEOF(...)
Get the type of instance.
Definition common.hpp:154
Concept to check if a type is a CVector.
Definition Vec.hpp:75
Concept to check if something is a device kind.
Definition tag.hpp:145
Concept to check if a type is a vector.
Definition Vec.hpp:54
consteval auto adjustToLimit(concepts::CVector auto const input, std::index_sequence< T_idx... >)
Definition util.hpp:27
consteval auto adjustToLimit(concepts::CVector auto const input)
adjust the input vector to a given limit by halving all components until the product of these is belo...
Definition util.hpp:64
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
ALPAKA_FN_HOST_ACC constexpr auto divExZero(Integral a, Integral b) -> Integral
Returns the max(a / b, 1) as integer.
Definition utility.hpp:41
ALPAKA_FN_HOST_ACC constexpr auto divCeil(Integral a, Integral b) -> Integral
Returns the ceiling of a / b, as integer.
Definition utility.hpp:34
Vec< T, sizeof...(T_values), detail::CVec< T, T_values... > > CVec
A vector with compile-time known values.
Definition CVec.hpp:31
constexpr auto calculatePitches(T_Vec const &extent, typename T_Vec::type const &rowPitchBytes)
Calculate the pitches purely from the extents.
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
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