Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-26 08:22:11

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/cuda_error_handling.hpp"
0013 #include "../utils/global_index.hpp"
0014 #include "../utils/utils.hpp"
0015 #include "traccc/cuda/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 // CUDA include
0025 #include <cuda_runtime.h>
0026 
0027 // System include
0028 #include <concepts>
0029 #include <utility>
0030 
0031 namespace traccc::cuda {
0032 
0033 namespace kernels {
0034 
0035 /// Kernel used in implementing @c traccc::cuda::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::cuda::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 }  // namespace kernels
0075 
0076 /**
0077  * @brief Sanity check that a given container is contiguous on a given
0078  *        projection.
0079  *
0080  * For a container $v$ to be contiguous on a projection $\pi$, it must be the
0081  * case that for all indices $i$ and $j$, if $v_i = v_j$, then all indices $k$
0082  * between $i$ and $j$, $v_i = v_j = v_k$.
0083  *
0084  * @note This function runs in O(n^2) time.
0085  *
0086  * @tparam CONTAINER The type of the (device) container.
0087  * @tparam P The type of projection $\pi$, a callable which returns some
0088  * comparable type.
0089  * @tparam VIEW The type of the view for the container.
0090  * @param projection A projection object of type `P`.
0091  * @param mr A memory resource used for allocating intermediate memory.
0092  * @param view The container which to check for contiguity.
0093  * @return true If the container is contiguous on `P`.
0094  * @return false Otherwise.
0095  */
0096 template <typename CONTAINER, typename P, typename VIEW>
0097   requires std::regular_invocable<P,
0098                                   decltype(std::declval<CONTAINER>().at(0))> &&
0099            std::semiregular<P>
0100 bool is_contiguous_on(P&& projection, vecmem::memory_resource& mr,
0101                       const vecmem::copy& copy, const stream_wrapper& stream,
0102                       const VIEW& view) {
0103   // This should never be a performance-critical step, so we can keep the
0104   // block size fixed.
0105   constexpr int block_size = 512;
0106   constexpr int block_size_2d = 32;
0107 
0108   cudaStream_t cuda_stream = details::get_stream(stream);
0109 
0110   // Grab the number of elements in our container.
0111   const typename VIEW::size_type n = copy.get_size(view);
0112 
0113   // Exit early for empty containers.
0114   if (n == 0) {
0115     return true;
0116   }
0117 
0118   // Get the output type of the projection.
0119   using projection_t =
0120       std::invoke_result_t<P, decltype(std::declval<CONTAINER>().at(0))>;
0121 
0122   // Allocate memory for intermediate values and outputs, then set them up.
0123   vecmem::data::vector_buffer<projection_t> iout(
0124       n, mr, vecmem::data::buffer_type::resizable);
0125   copy.setup(iout)->ignore();
0126   vecmem::unique_alloc_ptr<bool> out = vecmem::make_unique_alloc<bool>(mr);
0127 
0128   bool initial_out = true;
0129 
0130   TRACCC_CUDA_ERROR_CHECK(cudaMemcpyAsync(out.get(), &initial_out, sizeof(bool),
0131                                           cudaMemcpyHostToDevice, cuda_stream));
0132 
0133   // Launch the first kernel, which will squash consecutive equal elements
0134   // into one element.
0135   kernels::is_contiguous_on_compress_adjacent<CONTAINER>
0136       <<<(n + block_size - 1) / block_size, block_size, 0, cuda_stream>>>(
0137           projection, view, iout);
0138 
0139   TRACCC_CUDA_ERROR_CHECK(cudaGetLastError());
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   kernels::is_contiguous_on_all_unique<<<
0148       all_unique_grid_size, all_unique_block_size, 0, cuda_stream>>>(iout,
0149                                                                      out.get());
0150 
0151   TRACCC_CUDA_ERROR_CHECK(cudaGetLastError());
0152 
0153   // Get the result from the device and return it.
0154   bool host_out;
0155 
0156   TRACCC_CUDA_ERROR_CHECK(cudaMemcpyAsync(&host_out, out.get(), sizeof(bool),
0157                                           cudaMemcpyDeviceToHost, cuda_stream));
0158 
0159   stream.synchronize();
0160 
0161   return host_out;
0162 }
0163 }  // namespace traccc::cuda