Realm
A distributed, event-based tasking library
Loading...
Searching...
No Matches
hip_redop.h
Go to the documentation of this file.
1/*
2 * Copyright 2025 Stanford University, NVIDIA Corporation
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17#ifndef REALM_HIP_REDOP_H
18#define REALM_HIP_REDOP_H
19
20#include "realm/realm_config.h"
21#include "hip_reduc.h"
22
23#if defined(__CUDACC__) || defined(__HIPCC__)
24#ifdef REALM_USE_HIP
25#include <hip/hip_runtime.h>
26#endif
27#endif
28
29#if defined(__CUDACC__) || defined(__HIPCC__)
30namespace Realm {
31 namespace Hip {
32 // The general formula for a linearized index is the following:
33 // I = \sum_{i=0}^{N} v_i (\prod_{j=0}^{i-1} D_j)
34 // This implies that the general form for a coordinate is:
35 // v_i = mod(div, D_j) where div is the floored dividend of all the dimensions D
36 // of the earlier dimensions, e.g. for 3D:
37 // I = z * D_y * D_x + y * D_x + x
38 // x = mod(I, D_x) = I % D_x
39 // y = mod(div(I, D_x), D_y) = (I / D_x) % D_y
40 // z = mod(div(div((I,D_x),D_y), D_z) = ((I / D_x) / D_y) % D_z
41 template <typename Offset_t = size_t>
42 static __device__ inline void index_to_coords(Offset_t *coords, Offset_t index,
43 const Offset_t *extents,
44 const size_t elem_size)
45 {
46 size_t div = index;
47 const unsigned n = 3;
48#pragma unroll
49 for(int i = 0; i < n - 1; i++) {
50 size_t div_tmp = div / extents[i];
51 coords[i] = div - div_tmp * extents[i];
52 div = div_tmp;
53 }
54 coords[n - 1] = div;
55 coords[0] = coords[0] * elem_size;
56 }
57
58 template <typename Offset_t = size_t>
59 static __device__ inline size_t coords_to_index(const Offset_t *coords,
60 const Offset_t *strides,
61 const size_t elem_size)
62 {
63 size_t i = 0;
64 size_t vol = 1;
65 int d = 0;
66 const unsigned n = 3;
67#pragma unroll
68 for(; d < n - 1; d++) {
69 i += vol * coords[d];
70 vol *= strides[d];
71 }
72
73 i += vol * coords[d];
74 i = i / elem_size;
75 return i;
76 }
77
78 template <typename Offset_t = size_t>
79 static __device__ inline size_t coords_to_index_transpose(const Offset_t *coords,
80 const Offset_t *strides)
81 {
82 size_t i = 0;
83 i = coords[1] * strides[0] + coords[2] * strides[1] + coords[0];
84 return i;
85 }
86
87 namespace ReductionKernelsAdvanced {
88 template <typename REDOP, bool EXCL>
89 __global__ void fold_hip_kernel(Realm::Hip::AffineReducInfo<3> info, REDOP redop)
90 {
91 size_t off = blockIdx.x * blockDim.x + threadIdx.x;
92 Realm::Hip::AffineReducPair<3> &current_info = info.subrects[0];
93 size_t vol = current_info.volume;
94 size_t num_elems_rhs = current_info.src.elem_size / sizeof(typename REDOP::RHS);
95 size_t redop_rhs_size = sizeof(typename REDOP::RHS);
96 typename REDOP::RHS *dst =
97 reinterpret_cast<typename REDOP::RHS *>(current_info.dst.addr);
98 typename REDOP::RHS *src =
99 reinterpret_cast<typename REDOP::RHS *>(current_info.src.addr);
100 for(size_t idx = off; idx < vol; idx += blockDim.x * gridDim.x) {
101 size_t coords[3];
102 index_to_coords<size_t>(coords, idx, current_info.extents, redop_rhs_size);
103 const size_t src_idx =
104 coords_to_index<size_t>(coords, current_info.src.strides, redop_rhs_size);
105 const size_t dst_idx =
106 coords_to_index<size_t>(coords, current_info.dst.strides, redop_rhs_size);
107 redop.template fold_hip<EXCL>(
108 *reinterpret_cast<typename REDOP::RHS *>(&dst[dst_idx * num_elems_rhs]),
109 *reinterpret_cast<const typename REDOP::RHS *>(
110 &src[src_idx * num_elems_rhs]));
111 }
112 }
113
114 template <typename REDOP, bool EXCL>
115 __global__ void apply_hip_kernel(Realm::Hip::AffineReducInfo<3> info, REDOP redop)
116 {
117 size_t off = blockIdx.x * blockDim.x + threadIdx.x;
118 Realm::Hip::AffineReducPair<3> &current_info = info.subrects[0];
119 size_t vol = current_info.volume;
120 size_t num_elems_lhs = current_info.dst.elem_size / sizeof(typename REDOP::LHS);
121 size_t num_elems_rhs = current_info.src.elem_size / sizeof(typename REDOP::RHS);
122 size_t redop_lhs_size = sizeof(typename REDOP::LHS);
123 size_t redop_rhs_size = sizeof(typename REDOP::RHS);
124 typename REDOP::LHS *dst =
125 reinterpret_cast<typename REDOP::LHS *>(current_info.dst.addr);
126 typename REDOP::RHS *src =
127 reinterpret_cast<typename REDOP::RHS *>(current_info.src.addr);
128 for(size_t idx = off; idx < vol; idx += blockDim.x * gridDim.x) {
129 size_t coords[3];
130 index_to_coords<size_t>(coords, idx, current_info.extents, redop_rhs_size);
131 const size_t src_idx =
132 coords_to_index<size_t>(coords, current_info.src.strides, redop_rhs_size);
133 const size_t dst_idx =
134 coords_to_index<size_t>(coords, current_info.dst.strides, redop_lhs_size);
135 redop.template apply_hip<EXCL>(
136 *reinterpret_cast<typename REDOP::LHS *>(&(dst[dst_idx * num_elems_lhs])),
137 *reinterpret_cast<const typename REDOP::RHS *>(
138 &src[src_idx * num_elems_rhs]));
139 }
140 }
141 }; // namespace ReductionKernelsAdvanced
142
143 namespace ReductionKernelsTranspose {
144 template <typename REDOP, bool EXCL>
145 __global__ void fold_hip_kernel(Realm::Hip::MemReducInfo<size_t> current_info,
146 REDOP redop)
147 {
148 size_t offset = blockIdx.x * blockDim.x + threadIdx.x;
149 size_t vol = current_info.volume;
150 size_t num_elems = current_info.elem_size / sizeof(typename REDOP::RHS);
151 typename REDOP::RHS *dst =
152 reinterpret_cast<typename REDOP::RHS *>(current_info.dst);
153 typename REDOP::RHS *src =
154 reinterpret_cast<typename REDOP::RHS *>(current_info.src);
155 for(size_t idx = offset; idx < vol; idx += blockDim.x * gridDim.x) {
156 size_t coords[3];
157 index_to_coords<size_t>(coords, idx, current_info.extents, 1);
158 const size_t src_idx =
159 coords_to_index_transpose<size_t>(coords, current_info.src_strides);
160 const size_t dst_idx =
161 coords_to_index_transpose<size_t>(coords, current_info.dst_strides);
162 redop.template fold_hip<EXCL>(
163 *reinterpret_cast<typename REDOP::RHS *>(&dst[dst_idx * num_elems]),
164 *reinterpret_cast<const typename REDOP::RHS *>(&src[src_idx * num_elems]));
165 }
166 }
167
168 template <typename REDOP, bool EXCL>
169 __global__ void apply_hip_kernel(Realm::Hip::MemReducInfo<size_t> current_info,
170 REDOP redop)
171 {
172 const size_t offset = blockIdx.x * blockDim.x + threadIdx.x;
173 size_t vol = current_info.volume;
174 size_t num_elems = current_info.elem_size / sizeof(typename REDOP::RHS);
175 typename REDOP::LHS *dst =
176 reinterpret_cast<typename REDOP::LHS *>(current_info.dst);
177 typename REDOP::RHS *src =
178 reinterpret_cast<typename REDOP::RHS *>(current_info.src);
179
180 for(size_t idx = offset; idx < vol; idx += blockDim.x * gridDim.x) {
181 size_t coords[3];
182 index_to_coords<size_t>(coords, idx, current_info.extents, 1);
183 const size_t src_idx =
184 coords_to_index_transpose<size_t>(coords, current_info.src_strides);
185 const size_t dst_idx =
186 coords_to_index_transpose<size_t>(coords, current_info.dst_strides);
187 redop.template apply_hip<EXCL>(
188 *reinterpret_cast<typename REDOP::LHS *>(&dst[dst_idx * num_elems]),
189 *reinterpret_cast<const typename REDOP::RHS *>(&src[src_idx * num_elems]));
190 }
191 }
192 }; // namespace ReductionKernelsTranspose
193
194 // the ability to add HIP kernels to a reduction op is only available
195 // when using a compiler that understands HIP
196 namespace ReductionKernels {
197
198 template <typename LHS, typename RHS, typename F>
199 __device__ void iter_hip_kernel(uintptr_t lhs_base, uintptr_t lhs_stride,
200 uintptr_t rhs_base, uintptr_t rhs_stride,
201 size_t count, F func, void *context = nullptr)
202 {
203 const size_t tid = blockIdx.x * blockDim.x + threadIdx.x;
204 for(size_t idx = tid; idx < count; idx += blockDim.x * gridDim.x) {
205 (*func)(*reinterpret_cast<LHS *>(lhs_base + idx * lhs_stride),
206 *reinterpret_cast<const RHS *>(rhs_base + idx * rhs_stride), context);
207 }
208 }
209
210 template <typename REDOP, bool EXCL>
211 __device__ void redop_apply_wrapper(typename REDOP::LHS &lhs,
212 const typename REDOP::RHS &rhs, void *context)
213 {
214 REDOP &redop = *reinterpret_cast<REDOP *>(context);
215 redop.template apply_hip<EXCL>(lhs, rhs);
216 }
217 template <typename REDOP, bool EXCL>
218 __device__ void redop_fold_wrapper(typename REDOP::RHS &rhs1,
219 const typename REDOP::RHS &rhs2, void *context)
220 {
221 REDOP &redop = *reinterpret_cast<REDOP *>(context);
222 redop.template fold_hip<EXCL>(rhs1, rhs2);
223 }
224
225 template <typename REDOP, bool EXCL>
226 __global__ void apply_hip_kernel(uintptr_t lhs_base, uintptr_t lhs_stride,
227 uintptr_t rhs_base, uintptr_t rhs_stride,
228 size_t count, REDOP redop)
229 {
230 iter_hip_kernel<typename REDOP::LHS, typename REDOP::RHS>(
231 lhs_base, lhs_stride, rhs_base, rhs_stride, count,
232 redop_apply_wrapper<REDOP, EXCL>, (void *)&redop);
233 }
234
235 template <typename REDOP, bool EXCL>
236 __global__ void fold_hip_kernel(uintptr_t rhs1_base, uintptr_t rhs1_stride,
237 uintptr_t rhs2_base, uintptr_t rhs2_stride,
238 size_t count, REDOP redop)
239 {
240 iter_hip_kernel<typename REDOP::RHS, typename REDOP::RHS>(
241 rhs1_base, rhs1_stride, rhs2_base, rhs2_stride, count,
242 redop_fold_wrapper<REDOP, EXCL>, (void *)&redop);
243 }
244 }; // namespace ReductionKernels
245
246 template <typename REDOP, typename T /*= ReductionOpUntyped*/>
247 void add_hip_redop_kernels_advanced(T *redop)
248 {
249 redop->hip_apply_excl_fn_advanced = reinterpret_cast<void *>(
250 &ReductionKernelsAdvanced::apply_hip_kernel<REDOP, true>);
251 redop->hip_apply_nonexcl_fn_advanced = reinterpret_cast<void *>(
252 &ReductionKernelsAdvanced::apply_hip_kernel<REDOP, false>);
253 redop->hip_fold_excl_fn_advanced = reinterpret_cast<void *>(
254 &ReductionKernelsAdvanced::fold_hip_kernel<REDOP, true>);
255 redop->hip_fold_nonexcl_fn_advanced = reinterpret_cast<void *>(
256 &ReductionKernelsAdvanced::fold_hip_kernel<REDOP, false>);
257
258 redop->hip_apply_excl_fn_transpose = reinterpret_cast<void *>(
259 &ReductionKernelsTranspose::apply_hip_kernel<REDOP, true>);
260 redop->hip_apply_nonexcl_fn_transpose = reinterpret_cast<void *>(
261 &ReductionKernelsTranspose::apply_hip_kernel<REDOP, false>);
262 redop->hip_fold_excl_fn_transpose = reinterpret_cast<void *>(
263 &ReductionKernelsTranspose::fold_hip_kernel<REDOP, true>);
264 redop->hip_fold_nonexcl_fn_transpose = reinterpret_cast<void *>(
265 &ReductionKernelsTranspose::fold_hip_kernel<REDOP, false>);
266 }
267
268 // this helper adds the appropriate kernels for REDOP to a ReductionOpUntyped,
269 // although the latter is templated to work around circular include deps
270 template <typename REDOP, typename T /*= ReductionOpUntyped*/>
271 void add_hip_redop_kernels(T *redop)
272 {
273 // store the host proxy function pointer, as it's the same for all
274 // devices - translation to actual hip functions happens later
275 redop->hip_apply_excl_fn =
276 reinterpret_cast<void *>(&ReductionKernels::apply_hip_kernel<REDOP, true>);
277 redop->hip_apply_nonexcl_fn =
278 reinterpret_cast<void *>(&ReductionKernels::apply_hip_kernel<REDOP, false>);
279 redop->hip_fold_excl_fn =
280 reinterpret_cast<void *>(&ReductionKernels::fold_hip_kernel<REDOP, true>);
281 redop->hip_fold_nonexcl_fn =
282 reinterpret_cast<void *>(&ReductionKernels::fold_hip_kernel<REDOP, false>);
283 add_hip_redop_kernels_advanced<REDOP, T>(redop);
284 }
285 }; // namespace Hip
286}; // namespace Realm
287#endif
288#endif
Definition activemsg.h:42
Definition hip_reduc.h:58
AffineReducPair< N > subrects[MAX_RECTS]
Definition hip_reduc.h:64
Definition hip_reduc.h:47
size_t extents[N]
Definition hip_reduc.h:51
AffineReducSubRect< N > dst
Definition hip_reduc.h:49
AffineReducSubRect< N > src
Definition hip_reduc.h:48
size_t volume
Definition hip_reduc.h:54
Definition hip_reduc.h:27
size_t elem_size
Definition hip_reduc.h:34
Offset_t src_strides[2]
Definition hip_reduc.h:29
size_t volume
Definition hip_reduc.h:33
uintptr_t dst
Definition hip_reduc.h:31
uintptr_t src
Definition hip_reduc.h:32
Offset_t dst_strides[2]
Definition hip_reduc.h:30
Offset_t extents[3]
Definition hip_reduc.h:28
NodeID src
Definition ucp_internal.h:1