Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-16 08:20:29

0001 /**
0002  * traccc library, part of the ACTS project (R&D line)
0003  *
0004  * (c) 2024-2026 CERN for the benefit of the ACTS project
0005  *
0006  * Mozilla Public License Version 2.0
0007  */
0008 
0009 #pragma once
0010 
0011 // Project include(s).
0012 #include "../utils/global_index.hpp"
0013 #include "../utils/hip_error_handling.hpp"
0014 #include "../utils/utils.hpp"
0015 #include "traccc/hip/utils/stream_wrapper.hpp"
0016 
0017 // VecMem include(s).
0018 #include <vecmem/containers/data/vector_buffer.hpp>
0019 #include <vecmem/containers/device_vector.hpp>
0020 #include <vecmem/memory/memory_resource.hpp>
0021 #include <vecmem/memory/unique_ptr.hpp>
0022 #include <vecmem/utils/copy.hpp>
0023 
0024 // HIP include(s).
0025 #include <hip/hip_runtime.h>
0026 
0027 // System include
0028 #include <concepts>
0029 #include <utility>
0030 
0031 namespace traccc::hip {
0032 
0033 namespace kernels {
0034 
0035 /// Kernel used in implementing @c traccc::hip::is_contiguous_on
0036 template <typename CONTAINER, typename P, typename VIEW,
0037           std::equality_comparable S>
0038   requires std::regular_invocable<P,
0039                                   decltype(std::declval<CONTAINER>().at(0))> &&
0040            std::semiregular<P>
0041 __global__ void is_contiguous_on_compress_adjacent(
0042     P projection, VIEW _in, vecmem::data::vector_view<S> out_view) {
0043   const device::global_index_t tid = details::global_index1();
0044 
0045   const CONTAINER in(_in);
0046   vecmem::device_vector<S> out(out_view);
0047 
0048   if (tid > 0 && tid < in.size()) {
0049     S v1 = projection(in.at(tid - 1));
0050     S v2 = projection(in.at(tid));
0051 
0052     if (v1 != v2) {
0053       out.push_back(v2);
0054     }
0055   } else if (tid == 0) {
0056     out.push_back(projection(in.at(tid)));
0057   }
0058 }
0059 
0060 /// Kernel used in implementing @c traccc::hip::is_contiguous_on
0061 template <std::equality_comparable T>
0062 __global__ void is_contiguous_on_all_unique(
0063     vecmem::data::vector_view<T> in_view, bool* out) {
0064   const device::global_index_t tid_x = threadIdx.x + blockIdx.x * blockDim.x;
0065   const device::global_index_t tid_y = threadIdx.y + blockIdx.y * blockDim.y;
0066 
0067   const vecmem::device_vector<T> in(in_view);
0068 
0069   if (tid_x < in.size() && tid_y < in.size() && tid_x != tid_y &&
0070       in.at(tid_x) == in.at(tid_y)) {
0071     *out = false;
0072   }
0073 }
0074 
0075 }  // namespace kernels
0076 
0077 /**
0078  * @brief Sanity check that a given container is contiguous on a given
0079  *        projection.
0080  *
0081  * For a container $v$ to be contiguous on a projection $\pi$, it must be the
0082  * case that for all indices $i$ and $j$, if $v_i = v_j$, then all indices $k$
0083  * between $i$ and $j$, $v_i = v_j = v_k$.
0084  *
0085  * @note This function runs in O(n^2) time.
0086  *
0087  * @tparam CONTAINER The type of the (device) container.
0088  * @tparam P The type of projection $\pi$, a callable which returns some
0089  * comparable type.
0090  * @tparam VIEW The type of the view for the container.
0091  * @param projection A projection object of type `P`.
0092  * @param mr A memory resource used for allocating intermediate memory.
0093  * @param view The container which to check for contiguity.
0094  * @return true If the container is contiguous on `P`.
0095  * @return false Otherwise.
0096  */
0097 template <typename CONTAINER, typename P, typename VIEW>
0098   requires std::regular_invocable<P,
0099                                   decltype(std::declval<CONTAINER>().at(0))> &&
0100            std::semiregular<P>
0101 bool is_contiguous_on(P&& projection, vecmem::memory_resource& mr,
0102                       const vecmem::copy& copy, const stream_wrapper& stream,
0103                       const VIEW& view) {
0104   // This should never be a performance-critical step, so we can keep the
0105   // block size fixed.
0106   constexpr int block_size = 512;
0107   constexpr int block_size_2d = 32;
0108 
0109   hipStream_t hip_stream = details::get_stream(stream);
0110 
0111   // Grab the number of elements in our container.
0112   const typename VIEW::size_type n = copy.get_size(view);
0113 
0114   // Exit early for empty containers.
0115   if (n == 0) {
0116     return true;
0117   }
0118 
0119   // Get the output type of the projection.
0120   using projection_t =
0121       std::invoke_result_t<P, decltype(std::declval<CONTAINER>().at(0))>;
0122 
0123   // Allocate memory for intermediate values and outputs, then set them up.
0124   vecmem::data::vector_buffer<projection_t> iout(
0125       n, mr, vecmem::data::buffer_type::resizable);
0126   copy.setup(iout)->ignore();
0127   vecmem::unique_alloc_ptr<bool> out = vecmem::make_unique_alloc<bool>(mr);
0128 
0129   bool initial_out = true;
0130 
0131   TRACCC_HIP_ERROR_CHECK(hipMemcpyAsync(out.get(), &initial_out, sizeof(bool),
0132                                         hipMemcpyHostToDevice, hip_stream));
0133 
0134   // Launch the first kernel, which will squash consecutive equal elements
0135   // into one element.
0136   hipLaunchKernelGGL(kernels::is_contiguous_on_compress_adjacent<CONTAINER>,
0137                      (n + block_size - 1) / block_size, block_size, 0,
0138                      hip_stream, projection, view, iout);
0139   TRACCC_HIP_ERROR_CHECK(hipGetLastError());
0140 
0141   // Launch the second kernel, which will check if the values are unique.
0142   uint32_t grid_size_rd =
0143       (copy.get_size(iout) + block_size_2d - 1) / block_size_2d;
0144   dim3 all_unique_grid_size(grid_size_rd, grid_size_rd);
0145   dim3 all_unique_block_size(block_size_2d, block_size_2d);
0146 
0147   hipLaunchKernelGGL(kernels::is_contiguous_on_all_unique, all_unique_grid_size,
0148                      all_unique_block_size, 0, hip_stream, iout, out.get());
0149   TRACCC_HIP_ERROR_CHECK(hipGetLastError());
0150 
0151   // Get the result from the device and return it.
0152   bool host_out;
0153 
0154   TRACCC_HIP_ERROR_CHECK(hipMemcpyAsync(&host_out, out.get(), sizeof(bool),
0155                                         hipMemcpyDeviceToHost, hip_stream));
0156 
0157   stream.synchronize();
0158 
0159   return host_out;
0160 }
0161 
0162 }  // namespace traccc::hip