Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
scan_exclusive_sum_in_place.cpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
16
26#include <numeric>
27
28#if defined(__has_include)
29 #if __has_include(<AdaptiveCpp/algorithms/numeric.hpp>)
30 #include <AdaptiveCpp/algorithms/numeric.hpp>
31 #define ACPP_ALG_AVAILABLE
32 #endif
33#endif
34
35namespace {
36
37#ifdef __ACPP__
38 template<class T>
39 void scan_exclusive_sum_in_place_std_scan_single_task_acpp(
40 sham::DeviceBuffer<T> &buf1, u32 len) {
41
42 auto &q = buf1.get_dev_scheduler_ptr()->get_queue();
43
44 sycl::queue &q_s = q.q;
45
46 if (q_s.is_host()) {
47 sham::EventList deps{};
48 T *in_out_ptr = buf1.get_write_access(deps);
49
50 auto e = q.submit(deps, [&](sycl::handler &cgh) {
51 cgh.single_task([=]() {
52 std::exclusive_scan(in_out_ptr, in_out_ptr + len, in_out_ptr, T{});
53 });
54 });
55
57 } else {
58 auto acc_src = buf1.copy_to_stdvec_idx_range(0, len);
59 std::exclusive_scan(acc_src.begin(), acc_src.end(), acc_src.begin(), T{});
60 buf1.copy_from_stdvec(acc_src, len);
61 }
62 }
63#endif
64
65 template<class T>
66 void scan_exclusive_sum_in_place_fallback(sham::DeviceBuffer<T> &buf1, u32 len) {
67 auto acc_src = buf1.copy_to_stdvec_idx_range(0, len);
68 std::exclusive_scan(acc_src.begin(), acc_src.end(), acc_src.begin(), 0);
69 buf1.copy_from_stdvec(acc_src, len);
70 }
71
72#ifdef SYCL2020_FEATURE_GROUP_REDUCTION
73 template<class T>
74 void scan_exclusive_sum_in_place_decoupled_lookback_512(sham::DeviceBuffer<T> &buf1, u32 len) {
75 shamalgs::numeric::details::exclusive_sum_atomic_decoupled_v5_usm_in_place<T, 512>(
76 buf1, len);
77 }
78#endif
79
80#ifdef ACPP_ALG_AVAILABLE
81 template<class T>
82 void scan_exclusive_sum_in_place_adaptivecpp(sham::DeviceBuffer<T> &buf1, u32 len) {
83 auto &q = buf1.get_dev_scheduler_ptr()->get_queue().q;
84
85 acpp::algorithms::util::allocation_cache cache{
86 acpp::algorithms::util::allocation_type::device};
87 acpp::algorithms::util::allocation_group scratch{&cache, q.get_device()};
88
90
91 sham::EventList deps{};
92 const T *in_out_ptr = buf1.get_read_access(deps);
93 T *temp_ptr = temp.get_write_access(deps);
94
95 sycl::event e = adaptivecpp::algorithms::exclusive_scan(
96 q, scratch, in_out_ptr, in_out_ptr + len, temp_ptr, T{}, deps.get_events());
97 deps.set_consumed(true);
98
100 temp.complete_event_state(e);
101
102 buf1.copy_from(temp, len);
103 }
104#endif
105} // namespace
106
107namespace shamalgs::primitives {
108
110 namespace impl {
111
113 struct StdScan {
114 static constexpr std::string_view variant_type_name = "std_scan";
115 };
116
117#ifdef __ACPP__
120 struct StdScanSingleTaskAcpp {
121 static constexpr std::string_view variant_type_name = "std_scan_single_task_acpp";
122 };
123#endif
124
125#ifdef SYCL2020_FEATURE_GROUP_REDUCTION
127 struct DecoupledLookback512 {
128 static constexpr std::string_view variant_type_name = "decoupled_lookback_512";
129 };
130#endif
131
132#ifdef ACPP_ALG_AVAILABLE
134 struct AdaptiveCppAlg {
135 static constexpr std::string_view variant_type_name = "acpp_alg";
136 };
137#endif
138
140 StdScan
141#ifdef __ACPP__
142 ,
143 StdScanSingleTaskAcpp
144#endif
145#ifdef SYCL2020_FEATURE_GROUP_REDUCTION
146 ,
147 DecoupledLookback512
148#endif
149#ifdef ACPP_ALG_AVAILABLE
150 ,
151 AdaptiveCppAlg
152#endif
153 >
154 scan_exclusive_sum_in_place_impl{[](const sham::DeviceScheduler_ptr &, auto &self) {
155#ifdef __MACH__ // decoupled lookback perf on mac os is awful
156 #ifdef __ACPP__ // for acpp we gain using enqueue custom operation instead of copying
157 self.set(StdScanSingleTaskAcpp{});
158 #else
159 self.set(StdScan{});
160 #endif
161#else
162 #ifdef SYCL2020_FEATURE_GROUP_REDUCTION
163 self.set(DecoupledLookback512{});
164 #else
165 self.set(StdScan{});
166 #endif
167#endif
168 }};
169
172 return scan_exclusive_sum_in_place_impl.get_default_config_list();
173 }
174
177 return scan_exclusive_sum_in_place_impl.get_current_config();
178 }
179
182 return scan_exclusive_sum_in_place_impl.is_set();
183 }
184
187 shamlog_info_ln(
188 "algs", "setting scan_exclusive_sum_in_place implementation to impl :", impl);
189 scan_exclusive_sum_in_place_impl.set(impl);
190 }
191
194 const sham::DeviceScheduler_ptr &dev_sched) {
195 scan_exclusive_sum_in_place_impl.autoselect(dev_sched);
196 shamlog_info_ln(
197 "algs",
198 "defaulting scan_exclusive_sum_in_place implementation to impl :",
200 }
201
202 } // namespace impl
203
204 template<class T>
206
207 if (len == 0) {
208 return;
209 }
210
211 if (len > buf1.get_size()) {
213 "The buffer is smaller than the length of the scan\n"
214 "len > buf1.get_size(), len = {}, buf1.get_size() = {}",
215 len,
216 buf1.get_size()));
217 }
218
219 if (!impl::scan_exclusive_sum_in_place_impl.is_set()) {
221 }
222
223 std::visit(
225 [&](impl::StdScan) {
226 scan_exclusive_sum_in_place_fallback(buf1, len);
227 },
228#ifdef __ACPP__
229 [&](impl::StdScanSingleTaskAcpp) {
230 scan_exclusive_sum_in_place_std_scan_single_task_acpp(buf1, len);
231 },
232#endif
233#ifdef SYCL2020_FEATURE_GROUP_REDUCTION
234 [&](impl::DecoupledLookback512) {
235 scan_exclusive_sum_in_place_decoupled_lookback_512(buf1, len);
236 },
237#endif
238#ifdef ACPP_ALG_AVAILABLE
239 [&](impl::AdaptiveCppAlg) {
240 scan_exclusive_sum_in_place_adaptivecpp(buf1, len);
241 },
242#endif
243 },
244 impl::scan_exclusive_sum_in_place_impl.get());
245 }
246
247 template void scan_exclusive_sum_in_place<u32>(sham::DeviceBuffer<u32> &buf1, u32 len);
248
249} // namespace shamalgs::primitives
Generic std::variant-based implementation selector.
std::uint32_t u32
32 bit unsigned integer
A buffer allocated in USM (Unified Shared Memory).
void complete_event_state(sycl::event e) const
Complete the event state of the buffer.
void copy_from_stdvec(const std::vector< T > &vec)
Copy the content of a std::vector into the buffer.
T * get_write_access(sham::EventList &depends_list, SourceLocation src_loc=SourceLocation{})
Get a read-write pointer to the buffer's data.
std::shared_ptr< DeviceScheduler > & get_dev_scheduler_ptr()
Gets the Device scheduler pointer corresponding to the held allocation.
void copy_from(const DeviceBuffer< T, new_target > &other, size_t copy_size)
Copies the content of another buffer to this one.
size_t get_size() const
Gets the number of elements in the buffer.
std::vector< T > copy_to_stdvec_idx_range(size_t begin, size_t end) const
Copies a specified range of elements from the buffer to a std::vector.
const T * get_read_access(sham::EventList &depends_list, SourceLocation src_loc=SourceLocation{}) const
Get a read-only pointer to the buffer's data.
Class to manage a list of SYCL events.
Definition EventList.hpp:32
void set_consumed(bool consumed)
Set the consumed state of the EventList (to be used with interop).
std::vector< sycl::event > & get_events()
Get the list of events.
Drop-in replacement for the hand-rolled "global variable + enum + name mapping.
This header file contains utility functions related to exception handling in the code.
namespace to control implementation behavior
std::vector< std::string > get_default_impl_list_scan_exclusive_sum_in_place()
Get list of available scan_exclusive_sum_in_place implementations.
bool is_impl_set_scan_exclusive_sum_in_place()
Check if an implementation has been selected for scan_exclusive_sum_in_place.
void set_impl_scan_exclusive_sum_in_place(const std::string &impl)
Set the implementation for scan_exclusive_sum_in_place, from a config json string.
void autoselect_impl_scan_exclusive_sum_in_place(const sham::DeviceScheduler_ptr &dev_sched)
Select the default implementation for scan_exclusive_sum_in_place.
std::string get_current_impl_scan_exclusive_sum_in_place()
Get the current implementation for scan_exclusive_sum_in_place.
namespace for primitive algorithm (e.g. sort, scan, reductions, ...)
void scan_exclusive_sum_in_place(sham::DeviceBuffer< T > &buf1, u32 len)
Compute exclusive prefix sum in-place on a device buffer.
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
In-place exclusive scan (prefix sum) algorithm for device buffers.
std::exclusive_scan on a host copy of the buffer (portable fallback)
Build an overload set out of several callables, for use with std::visit.