Skip to content

Commit 44f9245

Browse files
authored
ITSGPU: sort seed/cells in phi (#15728)
This avoids divergence due additional rotate calls Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch>
1 parent a63c2a2 commit 44f9245

1 file changed

Lines changed: 78 additions & 0 deletions

File tree

Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,63 @@ GPUg() void __launch_bounds__(GPUThreads, (std::is_same_v<CurrentSeed, CellSeed>
760760
}
761761
}
762762

763+
/// Sort key that orders seeds by azimuth without mixing hit-layer patterns.
764+
template <int NLayers>
765+
GPUg() void __launch_bounds__(GPUThreads, MinBlocks.compileLookupTable) computeTrackSeedSortKeysKernel(
766+
const TrackSeed<NLayers>* trackSeeds,
767+
const unsigned int nSeeds,
768+
unsigned int* keys)
769+
{
770+
static_assert(NLayers < 32, "the hit-layer pattern must leave room for the azimuth bits");
771+
constexpr int PhiShift{32 - NLayers};
772+
constexpr unsigned int PhiMask{(1u << PhiShift) - 1u};
773+
for (unsigned int iSeed = blockIdx.x * blockDim.x + threadIdx.x; iSeed < nSeeds; iSeed += blockDim.x * gridDim.x) {
774+
const auto& seed = trackSeeds[iSeed];
775+
const unsigned int hitPattern = seed.getHitLayerMask().value();
776+
const float phi = seed.getPhiPos(); // [0, 2pi)
777+
const unsigned int phiBin = static_cast<unsigned int>(phi * (static_cast<float>(PhiMask) / o2::constants::math::TwoPI)) & PhiMask;
778+
keys[iSeed] = (hitPattern << PhiShift) | phiBin;
779+
}
780+
}
781+
782+
/// Sort key that orders neighbour candidates by the cluster their fit will read.
783+
GPUg() void __launch_bounds__(GPUThreads, MinBlocks.compileLookupTable) computeNeighbourCandidateSortKeysKernel(
784+
const int defaultCellTopologyId,
785+
const int* currentCellTopologyIds,
786+
CellSeed** allCellSeeds,
787+
CellNeighbour** neighbours,
788+
const NeighbourCandidate* candidates,
789+
const int nCandidates,
790+
unsigned int* keys)
791+
{
792+
constexpr unsigned int ClusterMask{0x07FFFFFFu};
793+
for (int iCandidate = blockIdx.x * blockDim.x + threadIdx.x; iCandidate < nCandidates; iCandidate += blockDim.x * gridDim.x) {
794+
const NeighbourCandidate candidate = candidates[iCandidate];
795+
const int cellTopologyId = currentCellTopologyIds == nullptr ? defaultCellTopologyId : currentCellTopologyIds[candidate.currentCell];
796+
const auto& neighbourRef = neighbours[cellTopologyId][candidate.neighbourEntry];
797+
const auto& neighbourCell = allCellSeeds[neighbourRef.cellTopology][neighbourRef.cell];
798+
keys[iCandidate] = (static_cast<unsigned int>(neighbourCell.getInnerLayer()) << 27) |
799+
(static_cast<unsigned int>(neighbourCell.getFirstClusterIndex()) & ClusterMask);
800+
}
801+
}
802+
803+
/// Order a candidate list in place by the hit each fit will read.
804+
void sortNeighbourCandidates(const int defaultCellTopologyId,
805+
const int* currentCellTopologyIds,
806+
CellSeed** allCellSeeds,
807+
CellNeighbour** neighbours,
808+
NeighbourCandidate* candidates,
809+
const int nCandidates,
810+
o2::its::ExternalAllocator* alloc)
811+
{
812+
auto keys = TypedAllocator<unsigned int>(alloc).allocate(nCandidates);
813+
auto policy = THRUST_NAMESPACE::par_nosync(TypedAllocator<char>(alloc)).on(Stream::DefaultStream);
814+
computeNeighbourCandidateSortKeysKernel<<<gridBlocks(ResidentBlocks.compileLookupTable), GPUThreads, 0, Stream::DefaultStream>>>(
815+
defaultCellTopologyId, currentCellTopologyIds, allCellSeeds, neighbours, candidates, nCandidates,
816+
thrust::raw_pointer_cast(keys));
817+
thrust::stable_sort_by_key(policy, keys, keys + nCandidates, thrust::device_ptr<NeighbourCandidate>(candidates));
818+
}
819+
763820
} // namespace gpu
764821

765822
template <int NLayers>
@@ -1197,6 +1254,7 @@ void TrackingKernels<NLayers>::processNeighboursHandler(const int startLevel,
11971254
});
11981255

11991256
if (nCandidates > 0) {
1257+
gpu::sortNeighbourCandidates(topologyId, levelCellTopologyIds, allCellSeeds, neighbours, candidatePtr, nCandidates, alloc);
12001258
gpu::fitNeighbourCandidatesKernel<NLayers, LevelSeed><<<neighbourGrid, gpu::GPUThreads>>>(
12011259
topologyId, allCellSeeds, levelSeeds, levelCellTopologyIds,
12021260
candidatePtr, candidateCounterPtr, candidateCapacity, neighbours,
@@ -1300,6 +1358,26 @@ int TrackingKernels<NLayers>::computeTrackSeedHandler(TrackSeed<NLayers>* trackS
13001358
{
13011359
GPUChkErrS(cudaMemsetAsync(outputCounter, 0, sizeof(int), gpu::Stream::DefaultStream));
13021360

1361+
if (nSeeds > 1) { // Group the seeds by hit-layer pattern before fitting them
1362+
constexpr uint64_t SortTag = qStr2Tag("ITS_TSSK");
1363+
alloc->pushTagOnStack(SortTag);
1364+
auto allocKey = gpu::TypedAllocator<unsigned int>(alloc);
1365+
auto allocIndex = gpu::TypedAllocator<int>(alloc);
1366+
auto allocSeed = gpu::TypedAllocator<TrackSeed<NLayers>>(alloc);
1367+
auto keys = allocKey.allocate(nSeeds);
1368+
auto order = allocIndex.allocate(nSeeds);
1369+
auto sortedSeeds = allocSeed.allocate(nSeeds);
1370+
auto sort_policy = THRUST_NAMESPACE::par_nosync(gpu::TypedAllocator<char>(alloc)).on(gpu::Stream::DefaultStream);
1371+
gpu::computeTrackSeedSortKeysKernel<NLayers><<<gpu::gridBlocks(gpu::ResidentBlocks.compileLookupTable), gpu::GPUThreads, 0, gpu::Stream::DefaultStream>>>(
1372+
trackSeeds, nSeeds, thrust::raw_pointer_cast(keys));
1373+
thrust::sequence(sort_policy, order, order + nSeeds);
1374+
thrust::stable_sort_by_key(sort_policy, keys, keys + nSeeds, order);
1375+
thrust::gather(sort_policy, order, order + nSeeds, thrust::device_ptr<TrackSeed<NLayers>>(trackSeeds), sortedSeeds);
1376+
GPUChkErrS(cudaMemcpyAsync(trackSeeds, thrust::raw_pointer_cast(sortedSeeds), nSeeds * sizeof(TrackSeed<NLayers>), cudaMemcpyDeviceToDevice, gpu::Stream::DefaultStream));
1377+
GPUChkErrS(cudaStreamSynchronize(gpu::Stream::DefaultStream));
1378+
alloc->popTagOffStack(SortTag);
1379+
}
1380+
13031381
// track follower is compiled out of the kernel when no iteration asks for it
13041382
const auto launchFit = [&](auto extendTracks) {
13051383
gpu::fitTrackSeedsKernel<NLayers, decltype(extendTracks)::value><<<gpu::gridBlocks(decltype(extendTracks)::value ? gpu::ResidentBlocks.fitTrackSeedsExtended

0 commit comments

Comments
 (0)