Back to home page

EIC code displayed by LXR

 
 

    


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

0001 /** TRACCC library, part of the ACTS project (R&D line)
0002  *
0003  * (c) 2025 CERN for the benefit of the ACTS project
0004  *
0005  * Mozilla Public License Version 2.0
0006  */
0007 
0008 // Project include(s).
0009 #include "traccc/definitions/qualifiers.hpp"
0010 
0011 // Local include(s).
0012 #include "../../utils/global_index.hpp"
0013 #include "rearrange_tracks.cuh"
0014 
0015 // VecMem include(s).
0016 #include <vecmem/containers/device_vector.hpp>
0017 
0018 namespace traccc::cuda::kernels {
0019 
0020 TRACCC_DEVICE inline bool find_valid_index(
0021     unsigned int& idx, const int lower_bound, const int upper_bound,
0022     const vecmem::device_vector<const unsigned int>& sorted_ids,
0023     const vecmem::device_vector<const int>& is_updated) {
0024   const auto initial_idx = idx;
0025 
0026   for (int i = initial_idx; i <= upper_bound; i++) {
0027     if (!is_updated[sorted_ids[i]]) {
0028       idx = i;
0029       return true;
0030     }
0031   }
0032 
0033   for (int i = initial_idx - 1; i >= lower_bound; i--) {
0034     if (!is_updated[sorted_ids[i]]) {
0035       idx = i;
0036       return true;
0037     }
0038   }
0039 
0040   return false;
0041 }
0042 
0043 __launch_bounds__(1024) __global__
0044     void rearrange_tracks(device::rearrange_tracks_payload payload) {
0045   if (*(payload.terminate) == 1 || *(payload.n_updated_tracks) == 0) {
0046     return;
0047   }
0048 
0049   auto gid = threadIdx.x / nThreads_per_track +
0050              blockIdx.x * (blockDim.x / nThreads_per_track);
0051   const unsigned int n_accepted = *(payload.n_accepted);
0052 
0053   auto N = *(payload.n_updated_tracks);
0054 
0055   int neff_threads = (N + nThreads_per_track - 1) / nThreads_per_track;
0056 
0057   if (neff_threads > nThreads_per_track) {
0058     neff_threads = nThreads_per_track;
0059   }
0060 
0061   bool is_valid_thread = true;
0062   if (threadIdx.x % nThreads_per_track >= neff_threads || gid >= n_accepted) {
0063     is_valid_thread = false;
0064   }
0065 
0066   vecmem::device_vector<const unsigned int> sorted_ids(payload.sorted_ids_view);
0067   vecmem::device_vector<const unsigned int> inverted_ids(
0068       payload.inverted_ids_view);
0069   vecmem::device_vector<const traccc::scalar> rel_shared(
0070       payload.rel_shared_view);
0071   vecmem::device_vector<const traccc::scalar> pvals(payload.pvals_view);
0072   vecmem::device_vector<const unsigned int> updated_tracks(
0073       payload.updated_tracks_view);
0074   vecmem::device_vector<const int> is_updated(payload.is_updated_view);
0075   vecmem::device_vector<const int> prefix_sums(payload.prefix_sums_view);
0076   vecmem::device_vector<unsigned int> temp_sorted_ids(
0077       payload.temp_sorted_ids_view);
0078 
0079   __shared__ int shifted_indices[1024];
0080   auto& shifted_idx = shifted_indices[threadIdx.x / nThreads_per_track];
0081   unsigned int tid = std::numeric_limits<unsigned int>::max();
0082 
0083   if (is_valid_thread) {
0084     tid = sorted_ids[gid];
0085     auto rel_sh_ref = rel_shared[tid];
0086     auto pval_ref = pvals[tid];
0087 
0088     shifted_idx = static_cast<int>(gid);
0089 
0090     int stride = (N + neff_threads - 1) / neff_threads;
0091 
0092     int ini_idx = stride * (threadIdx.x % nThreads_per_track);
0093     int fin_idx = std::min(ini_idx + stride, static_cast<int>(N));
0094 
0095     // If it is an updated track, find new sorted index by using the binary
0096     // search. The index is also shifted by using the bitonic sort result
0097     // from sort_updated_tracks and prefix sums
0098     if (is_updated[tid]) {
0099       if (gid > 0) {
0100         unsigned int left = 0;
0101         unsigned int right = gid;
0102 
0103         bool first_iteration = true;
0104 
0105         if (threadIdx.x % nThreads_per_track == 0) {
0106           while (right > left) {
0107             const bool find_left =
0108                 find_valid_index(left, 0, gid, sorted_ids, is_updated);
0109 
0110             if (!find_left) {
0111               break;
0112             }
0113 
0114             const bool find_right =
0115                 find_valid_index(right, 0, gid, sorted_ids, is_updated);
0116 
0117             if (!find_right) {
0118               break;
0119             }
0120 
0121             if (first_iteration) {
0122               const auto right_idx = sorted_ids[right];
0123               auto rel_sh = rel_shared[right_idx];
0124               auto pval = pvals[right_idx];
0125 
0126               if (rel_sh < rel_sh_ref ||
0127                   (rel_sh == rel_sh_ref && pval >= pval_ref)) {
0128                 left = gid;
0129                 break;
0130               }
0131             }
0132 
0133             first_iteration = false;
0134 
0135             unsigned int mid = left + (right - left) / 2;
0136 
0137             const bool find_mid =
0138                 find_valid_index(mid, left, right - 1, sorted_ids, is_updated);
0139 
0140             if (find_mid) {
0141               const auto mid_idx = sorted_ids[mid];
0142               auto rel_sh = rel_shared[mid_idx];
0143               auto pval = pvals[mid_idx];
0144 
0145               if (rel_sh < rel_sh_ref ||
0146                   (rel_sh == rel_sh_ref && pval >= pval_ref)) {
0147                 left = mid + 1;
0148               } else {
0149                 right = mid;
0150               }
0151             }
0152           }
0153 
0154           int delta = delta =
0155               gid - left - (prefix_sums[gid] - prefix_sums[left]);
0156 
0157           if (!is_updated[sorted_ids[left]]) {
0158             delta++;
0159           }
0160 
0161           atomicAdd(&shifted_idx, -delta);
0162         }
0163       }
0164 
0165       for (int i = ini_idx; i < fin_idx; i++) {
0166         auto id = updated_tracks[i];
0167 
0168         if (inverted_ids[id] < gid) {
0169           atomicAdd(&shifted_idx, -1);
0170         }
0171       }
0172 
0173       int offset = 0;
0174       for (int i = ini_idx; i < fin_idx; i++) {
0175         if (updated_tracks[i] == tid) {
0176           offset = i;
0177           break;
0178         }
0179       }
0180       if (offset != 0) {
0181         atomicAdd(&shifted_idx, offset);
0182       }
0183     }
0184     // If it is not an updated track, it is enough to count the number of
0185     // updated tracks which need to come earlier.
0186     else {
0187       for (int i = ini_idx; i < fin_idx; i++) {
0188         auto id = updated_tracks[i];
0189         auto rel_sh = rel_shared[id];
0190         auto pval = pvals[id];
0191 
0192         if (inverted_ids[id] > gid) {
0193           if (rel_sh < rel_sh_ref) {
0194             atomicAdd(&shifted_idx, 1);
0195           } else if (rel_sh == rel_sh_ref && pval > pval_ref) {
0196             atomicAdd(&shifted_idx, 1);
0197           }
0198         }
0199       }
0200     }
0201   }
0202 
0203   __syncthreads();
0204 
0205   // Save the result of new indices into a temporary buffer
0206   if (is_valid_thread && (threadIdx.x % nThreads_per_track) == 0) {
0207     temp_sorted_ids.at(shifted_idx) = tid;
0208   }
0209 }
0210 
0211 }  // namespace traccc::cuda::kernels