41 static constexpr std::string_view variant_type_name =
"reference";
45 static constexpr std::string_view variant_type_name =
"naive_gpu";
49 static constexpr std::string_view variant_type_name =
"gpu_team_fetching";
53 static constexpr std::string_view variant_type_name =
"gpu_oversubscribe";
57 compute_histogram_impl{[](
const sham::DeviceScheduler_ptr &dev_sched,
auto &self) {
58 if (dev_sched->ctx->device->prop.type == sham::DeviceType::GPU) {
67 return compute_histogram_impl.get_default_config_list();
72 return compute_histogram_impl.get_current_config();
80 shamlog_info_ln(
"algs",
"setting compute_histogram implementation to impl :",
impl);
81 compute_histogram_impl.set(
impl);
86 compute_histogram_impl.autoselect(dev_sched);
89 "defaulting compute_histogram implementation to impl :",
93 template<
class T,
class Tbins,
class... Targs,
class Tfunctor>
94 inline void compute_histogram_reference(
105 auto cpu_basic_impl = [&](
const std::vector<Tbins> &bin_edge_inf,
106 const std::vector<Tbins> &bin_edge_sup,
107 const std::vector<Targs> &...in_data,
108 std::vector<T> &result) {
109 for (
size_t ibin = 0; ibin < nbins; ibin++) {
110 Tbins edge_inf = bin_edge_inf[ibin];
111 Tbins edge_sup = bin_edge_sup[ibin];
115 for (
size_t i = 0; i < element_count; i++) {
116 bool has_value =
false;
117 auto tmp = functor(edge_inf, edge_sup, in_data[i]..., has_value);
123 result[ibin] = accumulator;
128 bin_edge_inf.copy_to_stdvec(),
129 bin_edge_sup.copy_to_stdvec(),
136 template<
class T,
class Tbins,
class... Targs,
class Tfunctor>
137 inline void compute_histogram_naive_gpu(
138 const sham::DeviceScheduler_ptr &dev_sched,
139 const sham::DeviceBuffer<Tbins> &bin_edge_inf,
140 const sham::DeviceBuffer<Tbins> &bin_edge_sup,
142 size_t element_count,
144 sham::DeviceBuffer<T> &result,
145 const sham::DeviceBuffer<Targs> &...input_data) {
148 dev_sched->get_queue(),
149 sham::MultiRef{bin_edge_inf, bin_edge_sup, input_data...},
150 sham::MultiRef{result},
152 [element_count, functor](
154 const Tbins *__restrict bin_edge_inf,
155 const Tbins *__restrict bin_edge_sup,
156 const Targs *__restrict... in_data,
157 T *__restrict result) {
158 Tbins edge_inf = bin_edge_inf[ibin];
159 Tbins edge_sup = bin_edge_sup[ibin];
163 for (size_t i = 0; i < element_count; i++) {
164 bool has_value = false;
165 T tmp = functor(edge_inf, edge_sup, in_data[i]..., has_value);
171 result[ibin] = accumulator;
175 template<
class T,
class Tbins,
class... Targs,
class Tfunctor>
176 inline void compute_histogram_gpu_team_fetching(
177 const sham::DeviceScheduler_ptr &dev_sched,
178 const sham::DeviceBuffer<Tbins> &bin_edge_inf,
179 const sham::DeviceBuffer<Tbins> &bin_edge_sup,
181 size_t element_count,
183 sham::DeviceBuffer<T> &result,
184 const sham::DeviceBuffer<Targs> &...input_data) {
186 sham::kernel_call_hndl(
187 dev_sched->get_queue(),
188 sham::MultiRef{bin_edge_inf, bin_edge_sup, input_data...},
189 sham::MultiRef{result},
191 [element_count, functor](
193 const Tbins *__restrict bin_edge_inf,
194 const Tbins *__restrict bin_edge_sup,
195 const Targs *__restrict... in_data,
196 T *__restrict result) {
197 return [=, in_data = std::tuple{in_data...}](sycl::handler &cgh) {
198 u32 group_size = 128;
199 u32 group_cnt = shambase::group_count(nbins, group_size);
202 group_cnt = (group_cnt + 3) / 4 * 4;
203 u32 corrected_len = group_cnt * group_size;
206 = sycl::local_accessor<std::tuple<Targs...>, 1>(group_size, cgh);
209 sycl::nd_range<1>{corrected_len, group_size},
210 [=](sycl::nd_item<1> item) {
211 u32 local_id = item.get_local_id(0);
212 u32 group_tile_id = item.get_group_linear_id();
213 u32 ibin = group_tile_id * group_size + local_id;
215 bool is_valid_point = (ibin < nbins);
216 Tbins edge_inf = is_valid_point ? bin_edge_inf[ibin] : Tbins{};
217 Tbins edge_sup = is_valid_point ? bin_edge_sup[ibin] : Tbins{};
221 for (
size_t i = 0; i < element_count; i += group_size) {
223 item.barrier(sycl::access::fence_space::local_space);
225 if (i + local_id < element_count) {
227 [&](
auto &...in_data) {
229 = std::tuple{in_data[i + local_id]...};
234 item.barrier(sycl::access::fence_space::local_space);
236 if (is_valid_point) {
237 for (
size_t lane = 0; lane < group_size; lane++) {
238 if (i + lane >= element_count) {
241 bool has_value =
false;
243 [&](
auto &...local_accs) {
257 item.barrier(sycl::access::fence_space::local_space);
260 if (is_valid_point) {
261 result[ibin] = local_sum;
268 template<
class T,
class Tbins,
class... Targs,
class Tfunctor>
269 inline void compute_histogram_gpu_oversubscribe(
270 const sham::DeviceScheduler_ptr &dev_sched,
275 size_t element_count,
280 sham::kernel_call_hndl(
281 dev_sched->get_queue(),
285 [element_count, functor, group_size, nbins](
286 u32 nbins_oversubscribed,
287 const Tbins *__restrict bin_edge_inf,
288 const Tbins *__restrict bin_edge_sup,
289 const Targs *__restrict... in_data,
290 T *__restrict result) {
291 return [=, in_data = std::tuple{in_data...}](sycl::handler &cgh) {
292 u32 group_cnt = shambase::group_count(nbins_oversubscribed, group_size);
295 group_cnt = (group_cnt + 3) / 4 * 4;
297 u32 corrected_len = group_cnt * group_size;
300 sycl::nd_range<1>{corrected_len, group_size},
301 [=](sycl::nd_item<1> item) {
302 u32 local_id = item.get_local_id(0);
303 u32 ibin = item.get_group_linear_id();
305 bool is_valid_point = (ibin < nbins);
306 Tbins edge_inf = is_valid_point ? bin_edge_inf[ibin] : Tbins{};
307 Tbins edge_sup = is_valid_point ? bin_edge_sup[ibin] : Tbins{};
313 for (
size_t i = 0; i < element_count; i += group_size) {
315 if (i + local_id < element_count) {
317 bool has_value =
false;
322 [&](
auto &...in_data) {
326 in_data[i + local_id]...,
340 auto group_sum = sycl::reduce_over_group(
341 item.get_group(), local_sum, sycl::plus<T>{});
343 if (is_valid_point && local_id == 0) {
344 result[ibin] = group_sum;