MUSIC unknown
Analysis for the MUSIC active-target ionization chamber
Loading...
Searching...
No Matches
gpu_sort.cu
Go to the documentation of this file.
1#include "gpu_interface.h"
2
3#include <cuda_runtime.h>
4#include <thrust/device_vector.h>
5#include <thrust/host_vector.h>
6#include <thrust/sort.h>
7
8#include <cstdint>
9#include <cstring>
10#include <iostream>
11#include <vector>
12
13// Mirrors layout of RawHit in include/BinaryUtils.hpp.
14// The host struct uses ROOT types (UShort_t, ULong64_t, UInt_t) but the
15// memory layout under the standard ABI is:
16// offset 0: board (2 bytes)
17// offset 2: channel (2 bytes)
18// offset 4: energy (2 bytes)
19// offset 6: padding (2 bytes for ULong64_t alignment)
20// offset 8: timestamp (8 bytes)
21// offset 16: flags (4 bytes)
22// offset 20: padding (4 bytes for struct alignment)
23// Total: 24 bytes.
24struct RawHitGPU {
25 uint16_t board;
26 uint16_t channel;
27 uint16_t energy;
28 uint16_t _pad0;
29 uint64_t timestamp;
30 uint32_t flags;
31 uint32_t _pad1;
32};
33
34static_assert(sizeof(RawHitGPU) == 24,
35 "RawHitGPU must be 24 bytes to match host RawHit layout");
36static_assert(offsetof(RawHitGPU, timestamp) == 8,
37 "timestamp must sit at byte offset 8");
38
39// Sort hits by timestamp. Rather than shipping the full 24-byte structs to the
40// device and sorting them with a comparator (which forces thrust into a
41// comparator merge sort needing ~2x the data in scratch), we ship only the
42// 8-byte uint64 timestamp keys plus a 4-byte uint32 index and run a key/value
43// sort -- a primitive-key radix sort. The device footprint per call drops from
44// ~48 B/hit to ~24 B/hit (so more sorts fit concurrently) and H2D/D2H traffic
45// drops from 24 down to 8 (down) + 4 (back) B/hit. The resulting permutation is
46// applied to the host array by a gather; the full structs never touch the GPU.
47extern "C" int gpu_sort_hits_by_timestamp(void *hits, long long n_hits) {
48 if (n_hits <= 0)
49 return 0;
50
51 // Indices are uint32 to keep the device payload small; a single subfile's hit
52 // count is far below 2^32, but guard anyway and let the caller fall back to
53 // the CPU sort if that ever stops holding.
54 if (static_cast<unsigned long long>(n_hits) > 0xFFFFFFFFULL) {
55 std::cerr << "[GPU sort] n_hits " << n_hits
56 << " exceeds uint32 index range" << std::endl;
57 return 6;
58 }
59
60 RawHitGPU *host_hits = static_cast<RawHitGPU *>(hits);
61
62 try {
63 thrust::host_vector<uint64_t> h_keys(n_hits);
64 thrust::host_vector<uint32_t> h_idx(n_hits);
65 for (long long i = 0; i < n_hits; i++) {
66 h_keys[i] = host_hits[i].timestamp;
67 h_idx[i] = static_cast<uint32_t>(i);
68 }
69
70 thrust::device_vector<uint64_t> d_keys = h_keys;
71 thrust::device_vector<uint32_t> d_idx = h_idx;
72
73 cudaError_t err = cudaGetLastError();
74 if (err != cudaSuccess) {
75 std::cerr << "[GPU sort] H2D copy failed: " << cudaGetErrorString(err)
76 << std::endl;
77 return 1;
78 }
79
80 thrust::sort_by_key(d_keys.begin(), d_keys.end(), d_idx.begin());
81
82 err = cudaGetLastError();
83 if (err != cudaSuccess) {
84 std::cerr << "[GPU sort] sort kernel failed: " << cudaGetErrorString(err)
85 << std::endl;
86 return 2;
87 }
88
89 thrust::copy(d_idx.begin(), d_idx.end(), h_idx.begin());
90
91 err = cudaGetLastError();
92 if (err != cudaSuccess) {
93 std::cerr << "[GPU sort] D2H copy failed: " << cudaGetErrorString(err)
94 << std::endl;
95 return 3;
96 }
97
98 // Gather the hits into sorted order on the host.
99 std::vector<RawHitGPU> sorted(n_hits);
100 for (long long i = 0; i < n_hits; i++)
101 sorted[i] = host_hits[h_idx[i]];
102 std::memcpy(host_hits, sorted.data(),
103 static_cast<size_t>(n_hits) * sizeof(RawHitGPU));
104 } catch (const std::exception &e) {
105 std::cerr << "[GPU sort] exception: " << e.what() << std::endl;
106 return 4;
107 } catch (...) {
108 std::cerr << "[GPU sort] unknown exception" << std::endl;
109 return 5;
110 }
111
112 return 0;
113}
int gpu_sort_hits_by_timestamp(void *hits, long long n_hits)
Definition gpu_sort.cu:47
uint16_t energy
Definition gpu_sort.cu:27
uint64_t timestamp
Definition gpu_sort.cu:29
uint32_t flags
Definition gpu_sort.cu:30
uint16_t _pad0
Definition gpu_sort.cu:28
uint16_t channel
Definition gpu_sort.cu:26
uint16_t board
Definition gpu_sort.cu:25
uint32_t _pad1
Definition gpu_sort.cu:31