File indexing completed on 2026-07-26 08:22:10
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include <cub/cub.cuh>
0011
0012 #include "traccc/device/sort.hpp"
0013
0014 namespace traccc::cuda {
0015 namespace kernels {
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 template <std::size_t SORT_THREADS_PER_BLOCK, std::size_t PER_THREAD_MAX>
0042 __global__ __launch_bounds__(SORT_THREADS_PER_BLOCK) void sort_cells(
0043 const unsigned int cells_per_thread, const unsigned int num_cells,
0044 const edm::silicon_cell_collection::const_view cells,
0045 edm::silicon_cell_collection::view new_cells,
0046 vecmem::data::vector_view<unsigned int> permutation_map_view,
0047 const bool write_permutation) {
0048
0049
0050
0051
0052
0053
0054
0055
0056 using key_t = std::uint64_t;
0057 using value_t = std::uint32_t;
0058 static_assert(sizeof(key_t) == 8);
0059 static_assert(sizeof(value_t) == 4);
0060
0061
0062
0063
0064
0065
0066 using sort_t = cub::BlockRadixSort<key_t, SORT_THREADS_PER_BLOCK,
0067 PER_THREAD_MAX, value_t>;
0068
0069
0070
0071
0072
0073
0074 unsigned int partition_target_size = cells_per_thread * blockDim.x;
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087 union smem_union {
0088 typename sort_t::TempStorage cub_sorting_tmp;
0089 struct {
0090 unsigned short channel0[SORT_THREADS_PER_BLOCK * PER_THREAD_MAX];
0091 unsigned short channel1[SORT_THREADS_PER_BLOCK * PER_THREAD_MAX];
0092 unsigned int module_index[SORT_THREADS_PER_BLOCK * PER_THREAD_MAX];
0093 } cell_attribute_cache;
0094 };
0095
0096
0097
0098
0099
0100 __shared__ smem_union smem;
0101 __shared__ unsigned int partition_start, partition_end;
0102 __shared__ unsigned int min_module_index, max_module_index, max_channel0,
0103 max_channel1;
0104
0105 vecmem::device_vector<unsigned int> permutation_map(permutation_map_view);
0106 const edm::silicon_cell_collection::const_device cells_device(cells);
0107 edm::silicon_cell_collection::device new_cells_device(new_cells);
0108
0109
0110
0111
0112
0113
0114
0115 const unsigned int search_start = blockIdx.x * partition_target_size;
0116 const unsigned int search_end =
0117 std::min(num_cells, search_start + partition_target_size);
0118
0119 if (threadIdx.x == 0) {
0120
0121
0122
0123
0124
0125 partition_start = std::numeric_limits<unsigned int>::max();
0126 partition_end = num_cells;
0127
0128
0129
0130
0131
0132 min_module_index = std::numeric_limits<unsigned int>::max();
0133 max_module_index = 0;
0134 max_channel0 = 0;
0135 max_channel1 = 0;
0136 }
0137
0138 __syncthreads();
0139
0140
0141
0142
0143
0144
0145
0146 {
0147 unsigned int i = search_end + threadIdx.x;
0148 bool valid_split = false;
0149
0150 do {
0151 valid_split = (i > 0 && i < num_cells)
0152 ? cells_device.module_index().at(i - 1) !=
0153 cells_device.module_index().at(i)
0154 : true;
0155
0156 if (valid_split) {
0157 atomicMin(&partition_end, i);
0158 }
0159
0160 i += blockDim.x;
0161 } while (!__syncthreads_or(valid_split));
0162 }
0163
0164
0165
0166
0167
0168
0169
0170
0171 {
0172 unsigned int i = search_start + threadIdx.x;
0173 bool valid_split = false;
0174
0175 do {
0176 valid_split = (i > 0 && i < partition_end)
0177 ? (cells_device.module_index().at(i - 1) !=
0178 cells_device.module_index().at(i))
0179 : true;
0180
0181 if (valid_split) {
0182 atomicMin(&partition_start, i);
0183 }
0184
0185 i += blockDim.x;
0186 } while (!__syncthreads_or(valid_split));
0187 }
0188
0189 __syncthreads();
0190
0191
0192
0193
0194
0195 assert(partition_start <= partition_end);
0196
0197 const unsigned int partition_size = partition_end - partition_start;
0198
0199 if (partition_size == 0) {
0200 return;
0201 }
0202
0203
0204
0205
0206
0207
0208 if (partition_size > SORT_THREADS_PER_BLOCK * PER_THREAD_MAX) [[unlikely]] {
0209
0210
0211
0212
0213
0214 for (unsigned int i = partition_start + threadIdx.x; i < partition_end;
0215 i += blockDim.x) {
0216 permutation_map.at(i) = i;
0217 }
0218
0219 __syncthreads();
0220
0221
0222
0223
0224
0225 auto compare_cells = [&cells_device](const unsigned int idx_a,
0226 const unsigned int idx_b) {
0227 const auto& a = cells_device.at(idx_a);
0228 const auto& b = cells_device.at(idx_b);
0229 if (a.module_index() < b.module_index()) {
0230 return true;
0231 } else if (a.module_index() == b.module_index()) {
0232 if (a.channel1() < b.channel1()) {
0233 return true;
0234 } else if (a.channel1() == b.channel1()) {
0235 return a.channel0() < b.channel0();
0236 } else {
0237 return false;
0238 }
0239
0240 } else {
0241 return false;
0242 }
0243 };
0244
0245
0246
0247
0248 traccc::cuda::details::thread_id1 thread_id;
0249 traccc::cuda::barrier barrier;
0250 device::blockOddEvenSort(thread_id, barrier,
0251 &permutation_map.at(partition_start),
0252 partition_size, compare_cells);
0253
0254
0255
0256
0257
0258 for (unsigned int i = partition_start + threadIdx.x; i < partition_end;
0259 i += blockDim.x) {
0260 new_cells_device.at(i) = cells_device.at(permutation_map.at(i));
0261 }
0262 } else {
0263
0264
0265
0266
0267
0268
0269
0270 unsigned int local_max_channel_0 = 0;
0271 unsigned int local_max_channel_1 = 0;
0272 unsigned int local_min_module_index =
0273 std::numeric_limits<unsigned int>::max();
0274 unsigned int local_max_module_index = 0;
0275
0276
0277
0278
0279
0280
0281 for (unsigned int i = threadIdx.x; i < partition_size; i += blockDim.x) {
0282 const auto& cell = cells_device.at(partition_start + i);
0283 const auto channel0 = cell.channel0();
0284 const auto channel1 = cell.channel1();
0285 const auto module_index = cell.module_index();
0286
0287 local_max_channel_0 = std::max(local_max_channel_0, channel0);
0288 local_max_channel_1 = std::max(local_max_channel_1, channel1);
0289 local_min_module_index = std::min(local_min_module_index, module_index);
0290 local_max_module_index = std::max(local_max_module_index, module_index);
0291
0292 assert(channel0 <= 0xFFFF);
0293 smem.cell_attribute_cache.channel0[i] = channel0;
0294 assert(channel1 <= 0xFFFF);
0295 smem.cell_attribute_cache.channel1[i] = channel1;
0296 smem.cell_attribute_cache.module_index[i] = module_index;
0297 }
0298
0299
0300
0301
0302
0303 atomicMax(&max_channel0, local_max_channel_0);
0304 atomicMax(&max_channel1, local_max_channel_1);
0305 atomicMin(&min_module_index, local_min_module_index);
0306 atomicMax(&max_module_index, local_max_module_index);
0307
0308 __syncthreads();
0309
0310
0311
0312
0313
0314
0315 const auto module_index_clz = __clz(max_module_index - min_module_index);
0316 const unsigned int module_index_bits =
0317 CHAR_BIT * sizeof(std::decay_t<decltype(module_index_clz)>) -
0318 module_index_clz;
0319
0320 const auto channel0_clz = __clz(max_channel0);
0321 const unsigned int channel0_bits =
0322 CHAR_BIT * sizeof(std::decay_t<decltype(channel0_clz)>) - channel0_clz;
0323
0324 const auto channel1_clz = __clz(max_channel1);
0325 const unsigned int channel1_bits =
0326 CHAR_BIT * sizeof(std::decay_t<decltype(channel1_clz)>) - channel1_clz;
0327
0328 const unsigned int total_bits =
0329 module_index_bits + channel0_bits + channel1_bits;
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339 assert((total_bits + 1) <= (CHAR_BIT * sizeof(key_t)));
0340
0341
0342
0343
0344
0345 key_t keys[PER_THREAD_MAX];
0346 value_t values[PER_THREAD_MAX];
0347
0348 for (unsigned int i = 0; i < PER_THREAD_MAX; ++i) {
0349 unsigned int eff = i * blockDim.x + threadIdx.x;
0350 if (eff < partition_size) {
0351 const auto module_index =
0352 smem.cell_attribute_cache.module_index[eff] - min_module_index;
0353 const auto channel0 = smem.cell_attribute_cache.channel0[eff];
0354 const auto channel1 = smem.cell_attribute_cache.channel1[eff];
0355
0356 keys[i] = static_cast<key_t>(module_index)
0357 << (channel0_bits + channel1_bits) |
0358 static_cast<key_t>(channel1) << (channel0_bits) |
0359 static_cast<key_t>(channel0);
0360 values[i] = eff;
0361 } else {
0362 keys[i] = std::numeric_limits<key_t>::max();
0363 values[i] = std::numeric_limits<value_t>::max();
0364 }
0365 }
0366
0367 __syncthreads();
0368
0369
0370
0371
0372
0373 sort_t(smem.cub_sorting_tmp)
0374 .SortBlockedToStriped(keys, values, 0, total_bits + 1);
0375
0376
0377
0378
0379
0380 for (unsigned int i = 0; i < PER_THREAD_MAX; ++i) {
0381 unsigned int eff = i * blockDim.x + threadIdx.x;
0382 if (eff < partition_size) {
0383 new_cells_device.at(partition_start + eff) =
0384 cells_device.at(partition_start + values[i]);
0385 if (write_permutation) {
0386 permutation_map.at(partition_start + eff) =
0387 partition_start + values[i];
0388 }
0389 }
0390 }
0391 }
0392 }
0393 }
0394 }