Skip to content

Commit ac46fff

Browse files
committed
GPU: Add some more optional sanity checks
1 parent 0aed7a6 commit ac46fff

File tree

11 files changed

+128
-67
lines changed

11 files changed

+128
-67
lines changed

GPU/GPUTracking/Base/GPUReconstruction.cxx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,14 +294,15 @@ int32_t GPUReconstruction::InitPhaseBeforeDevice()
294294
if (!(mRecoSteps.stepsGPUMask & GPUDataTypes::RecoStep::TPCMerging)) {
295295
mProcessingSettings->mergerSortTracks = false;
296296
}
297-
298297
if (GetProcessingSettings().debugLevel > 3 || !IsGPU() || GetProcessingSettings().deterministicGPUReconstruction) {
299298
mProcessingSettings->delayedOutput = false;
300299
}
301-
302300
if (!GetProcessingSettings().rtc.enable) {
303301
mProcessingSettings->rtc.optConstexpr = false;
304302
}
303+
if (GetProcessingSettings().allSanityChecks) {
304+
mProcessingSettings->clusterizerZSSanityCheck = mProcessingSettings->mergerSanityCheck = mProcessingSettings->outputSanityCheck = true;
305+
}
305306

306307
mMemoryScalers->scalingFactor = GetProcessingSettings().memoryScalingFactor;
307308
mMemoryScalers->conservative = GetProcessingSettings().conservativeMemoryEstimate;

GPU/GPUTracking/Definitions/GPUSettingsList.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,9 @@ AddOption(fastTransformObjectsMinMemorySize, uint32_t, 400u * 1024 * 1024, "", 0
352352
AddOption(lateO2MatLutProvisioningSize, uint32_t, 0u, "", 0, "Memory size to reserve for late provisioning of matlut table")
353353
AddOption(throttleAlarms, bool, false, "", 0, "Throttle rate at which alarms are sent to the InfoLogger in online runs")
354354
AddOption(outputSanityCheck, bool, false, "", 0, "Run some simple sanity checks finding errors in the output")
355+
AddOption(mergerSanityCheck, bool, false, "", 0, "Run some simple sanity checks after / during track merging")
356+
AddOption(clusterizerZSSanityCheck, bool, false, "", 0, "Run some simple sanity checks on ZS decoding during clusterization")
357+
AddOption(allSanityChecks, bool, false, "", 0, "Enable all sanity checks")
355358
AddOption(tpcSingleSector, int32_t, -1, "", 0, "Restrict TPC processing to a single sector")
356359
AddOption(tpcDownscaledEdx, uint8_t, 0, "", 0, "If != 0, downscale dEdx processing (if enabled) to x %")
357360
AddOption(tpcMaxAttachedClustersPerSectorRow, uint32_t, 51000, "", 0, "Maximum number of TPC attached clusters which can be decoded per SectorRow")

GPU/GPUTracking/Global/GPUChainTracking.cxx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,10 @@ bool GPUChainTracking::ValidateSettings()
269269
GPUError("noGPUMemoryRegistration only possible with gather mode 3 (set to %d / %d)", mRec->GetProcessingSettings().tpcCompressionGatherMode, gatherMode);
270270
return false;
271271
}
272+
if (mRec->IsGPU() && (GetProcessingSettings().clusterizerZSSanityCheck || GetProcessingSettings().mergerSanityCheck)) {
273+
GPUError("Clusterizer and merger Sanity checks only supported when not running on GPU");
274+
return false;
275+
}
272276
if (GetProcessingSettings().doublePipeline) {
273277
if (!GetRecoStepsOutputs().isOnlySet(GPUDataTypes::InOutType::TPCMergedTracks, GPUDataTypes::InOutType::TPCCompressedClusters, GPUDataTypes::InOutType::TPCClusters)) {
274278
GPUError("Invalid outputs for double pipeline mode 0x%x", (uint32_t)GetRecoStepsOutputs());
@@ -791,7 +795,7 @@ int32_t GPUChainTracking::RunChainFinalize()
791795
}
792796

793797
if (GetProcessingSettings().outputSanityCheck) {
794-
SanityCheck();
798+
OutputSanityCheck();
795799
}
796800

797801
const bool needQA = GPUQA::QAAvailable() && (GetProcessingSettings().runQA || (GetProcessingSettings().eventDisplay && mIOPtrs.nMCInfosTPC));

GPU/GPUTracking/Global/GPUChainTracking.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ class GPUChainTracking : public GPUChain
291291

292292
private:
293293
int32_t RunChainFinalize();
294-
void SanityCheck();
294+
void OutputSanityCheck();
295295
int32_t RunTPCTrackingSectors_internal();
296296
int32_t RunTPCClusterizer_prepare(bool restorePointers);
297297
#ifdef GPUCA_TPC_GEOMETRY_O2

GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ std::pair<uint32_t, uint32_t> GPUChainTracking::TPCClusterizerDecodeZSCountUpdat
107107
if (doGPU) {
108108
pages = o - processors()->tpcClusterer[iSector].mPzsOffsets;
109109
}
110-
if (!doGPU && GetProcessingSettings().debugLevel >= 4 && mCFContext->zsVersion >= ZSVersion::ZSVersionDenseLinkBased) {
110+
if (GetProcessingSettings().clusterizerZSSanityCheck && mCFContext->zsVersion >= ZSVersion::ZSVersionDenseLinkBased) {
111111
TPCClusterizerEnsureZSOffsets(iSector, fragment);
112112
}
113113
return {digits, pages};

GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ void GPUChainTracking::PrintOutputStat()
251251
GPUInfo("Output Tracks: %d (%d / %d / %d / %d clusters (fitted / attached / adjacent / total) - %s format)%s", nTracks, nAttachedClustersFitted, nAttachedClusters, nAdjacentClusters, nCls, GetProcessingSettings().createO2Output > 1 ? "O2" : "GPU", trdText);
252252
}
253253

254-
void GPUChainTracking::SanityCheck()
254+
void GPUChainTracking::OutputSanityCheck()
255255
{
256256
size_t nErrors = 0;
257257

GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ int32_t GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput)
163163
runKernel<GPUMemClean16>({{1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}}, MergerShadowAll.TmpCounter(), 2 * NSECTORS * sizeof(*MergerShadowAll.TmpCounter()));
164164

165165
runKernel<GPUTPCGMMergerLinkExtrapolatedTracks>(GetGridAuto(0, deviceType));
166+
if (GetProcessingSettings().mergerSanityCheck) {
167+
Merger.CheckMergeGraph();
168+
}
166169
runKernel<GPUTPCGMMergerCollect>(GetGridAuto(0, deviceType));
167170
if (GetProcessingSettings().deterministicGPUReconstruction) {
168171
runKernel<GPUTPCGlobalDebugSortKernels, GPUTPCGlobalDebugSortKernels::mergedTracks1>({{1, -WarpSize(), 0, deviceType}}, 1);
@@ -189,6 +192,9 @@ int32_t GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput)
189192
CondWaitEvent(waitForTransfer, &mEvents->single);
190193
runKernel<GPUTPCGMMergerSortTracks>(GetGridAuto(0, deviceType));
191194
}
195+
if (GetProcessingSettings().mergerSanityCheck) {
196+
Merger.CheckCollectedTracks();
197+
}
192198

193199
uint32_t maxId = Merger.NMaxClusters();
194200
if (maxId > Merger.NMaxClusters()) {

GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx

Lines changed: 104 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,98 @@ GPUTPCGMMerger::GPUTPCGMMerger()
164164
#if !defined(GPUCA_GPUCODE) && (defined(GPUCA_MERGER_BY_MC_LABEL) || defined(GPUCA_CADEBUG_ENABLED) || GPUCA_MERGE_LOOPER_MC)
165165
#include "GPUQAHelper.h"
166166

167-
void GPUTPCGMMerger::CheckMergedTracks()
167+
template <class T>
168+
inline const auto* resolveMCLabels(const o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>* a, const AliHLTTPCClusterMCLabel* b)
169+
{
170+
return a;
171+
}
172+
template <>
173+
inline const auto* resolveMCLabels<AliHLTTPCClusterMCLabel>(const o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>* a, const AliHLTTPCClusterMCLabel* b)
174+
{
175+
return b;
176+
}
177+
178+
template <class T, class S>
179+
int64_t GPUTPCGMMerger::GetTrackLabelA(const S& trk) const
180+
{
181+
GPUTPCGMSectorTrack* sectorTrack = nullptr;
182+
int32_t nClusters = 0;
183+
if constexpr (std::is_same_v<S, GPUTPCGMBorderTrack&>) {
184+
sectorTrack = &mSectorTrackInfos[trk.TrackID()];
185+
nClusters = sectorTrack->OrigTrack()->NHits();
186+
} else {
187+
nClusters = trk.NClusters();
188+
}
189+
auto acc = GPUTPCTrkLbl<false, GPUTPCTrkLbl_ret>(resolveMCLabels<T>(GetConstantMem()->ioPtrs.clustersNative ? GetConstantMem()->ioPtrs.clustersNative->clustersMCTruth : nullptr, GetConstantMem()->ioPtrs.mcLabelsTPC), 0.5f);
190+
for (int32_t i = 0; i < nClusters; i++) {
191+
int32_t id;
192+
if constexpr (std::is_same_v<S, GPUTPCGMBorderTrack&>) {
193+
const GPUTPCTracker& tracker = GetConstantMem()->tpcTrackers[sectorTrack->Sector()];
194+
const GPUTPCHitId& ic = tracker.TrackHits()[sectorTrack->OrigTrack()->FirstHitID() + i];
195+
id = tracker.Data().ClusterDataIndex(tracker.Data().Row(ic.RowIndex()), ic.HitIndex()) + GetConstantMem()->ioPtrs.clustersNative->clusterOffset[sectorTrack->Sector()][0];
196+
} else {
197+
id = mClusters[trk.FirstClusterRef() + i].num;
198+
}
199+
acc.addLabel(id);
200+
}
201+
return acc.computeLabel().id;
202+
}
203+
204+
template <class S>
205+
int64_t GPUTPCGMMerger::GetTrackLabel(const S& trk) const
206+
{
207+
#ifdef GPUCA_TPC_GEOMETRY_O2
208+
if (GetConstantMem()->ioPtrs.clustersNative->clustersMCTruth) {
209+
return GetTrackLabelA<o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>, S>(trk);
210+
} else
211+
#endif
212+
{
213+
return GetTrackLabelA<AliHLTTPCClusterMCLabel, S>(trk);
214+
}
215+
}
216+
217+
#endif
218+
// END DEBUG CODE
219+
220+
void GPUTPCGMMerger::CheckCollectedTracks()
221+
{
222+
uint32_t nErr = 0;
223+
for (uint32_t i = 0; i < mMemory->nMergedTracks; i++) {
224+
const GPUTPCGMMergedTrack& trk = mMergedTracks[i];
225+
if (trk.OK()) {
226+
if (trk.NClusters() == 0) {
227+
GPUError("FAILURE: Track marked ok but has 0 clusters");
228+
nErr++;
229+
}
230+
if (!trk.CCE() && !trk.MergedLooper()) {
231+
const GPUTPCGMMergedTrack* updTrk = &trk;
232+
while (updTrk->PrevSegment() >= 0) {
233+
auto next = &mMergedTracks[updTrk->PrevSegment()];
234+
if (!next->MergedLooper()) {
235+
GPUError("FAILURE: prev segment not marked as merged looper\n");
236+
nErr++;
237+
}
238+
if (next == &trk) {
239+
GPUError("FAILURE: segment cycle found\n");
240+
break;
241+
}
242+
updTrk = next;
243+
}
244+
if (updTrk->NClusters() == 0) {
245+
printf("FAILURE: segment leg has 0 clusters");
246+
}
247+
}
248+
}
249+
}
250+
251+
if (nErr == 0) {
252+
GPUInfo("Merged Tracks OK");
253+
} else {
254+
throw std::runtime_error("Error during track merging");
255+
}
256+
}
257+
258+
void GPUTPCGMMerger::CheckMergeGraph()
168259
{
169260
uint32_t nErr = 0;
170261
std::vector<bool> trkUsed(SectorTrackInfoLocalTotal());
@@ -175,19 +266,19 @@ void GPUTPCGMMerger::CheckMergedTracks()
175266
for (int32_t itr = 0; itr < SectorTrackInfoLocalTotal(); itr++) {
176267
GPUTPCGMSectorTrack& track = mSectorTrackInfos[itr];
177268
if (track.PrevSegmentNeighbour() >= 0 && mSectorTrackInfos[track.PrevSegmentNeighbour()].NextSegmentNeighbour() != itr) {
178-
GPUError("Invalid reciprocal segment link: %d PrevSegmentNeighbour %d NextSegmentNeighbour %d", itr, track.PrevSegmentNeighbour(), mSectorTrackInfos[track.PrevSegmentNeighbour()].NextSegmentNeighbour());
269+
GPUError("FAILURE: Invalid reciprocal segment link: %d PrevSegmentNeighbour %d NextSegmentNeighbour %d", itr, track.PrevSegmentNeighbour(), mSectorTrackInfos[track.PrevSegmentNeighbour()].NextSegmentNeighbour());
179270
nErr++;
180271
}
181272
if (track.NextSegmentNeighbour() >= 0 && mSectorTrackInfos[track.NextSegmentNeighbour()].PrevSegmentNeighbour() != itr) {
182-
GPUError("Invalid reciprocal segment link: %d NextSegmentNeighbour %d PrevSegmentNeighbour %d", itr, track.NextSegmentNeighbour(), mSectorTrackInfos[track.NextSegmentNeighbour()].PrevSegmentNeighbour());
273+
GPUError("FAILURE: Invalid reciprocal segment link: %d NextSegmentNeighbour %d PrevSegmentNeighbour %d", itr, track.NextSegmentNeighbour(), mSectorTrackInfos[track.NextSegmentNeighbour()].PrevSegmentNeighbour());
183274
nErr++;
184275
}
185276
if (track.PrevNeighbour() >= 0 && mSectorTrackInfos[track.PrevNeighbour()].NextNeighbour() != itr) {
186-
GPUError("Invalid reciprocal link: %d PrevNeighbour %d NextNeighbour %d", itr, track.PrevNeighbour(), mSectorTrackInfos[track.PrevNeighbour()].NextNeighbour());
277+
GPUError("FAILURE: Invalid reciprocal link: %d PrevNeighbour %d NextNeighbour %d", itr, track.PrevNeighbour(), mSectorTrackInfos[track.PrevNeighbour()].NextNeighbour());
187278
nErr++;
188279
}
189280
if (track.NextNeighbour() >= 0 && mSectorTrackInfos[track.NextNeighbour()].PrevNeighbour() != itr) {
190-
GPUError("Invalid reciprocal link: %d NextNeighbour %d PrevNeighbour %d", itr, track.NextNeighbour(), mSectorTrackInfos[track.NextNeighbour()].PrevNeighbour());
281+
GPUError("FAILURE: Invalid reciprocal link: %d NextNeighbour %d PrevNeighbour %d", itr, track.NextNeighbour(), mSectorTrackInfos[track.NextNeighbour()].PrevNeighbour());
191282
nErr++;
192283
}
193284
if (track.PrevSegmentNeighbour() >= 0) {
@@ -202,19 +293,26 @@ void GPUTPCGMMerger::CheckMergedTracks()
202293
if (trkUsed[iTrk]) {
203294
GPUError("FAILURE: double use");
204295
nErr++;
296+
break;
205297
}
206298
trkUsed[iTrk] = true;
207299

208300
int32_t jtr = tr->NextSegmentNeighbour();
209301
if (jtr >= 0) {
210302
tr = &(mSectorTrackInfos[jtr]);
303+
if (tr->PrevNeighbour() >= 0) {
304+
GPUError("FAILURE: Non-base segment has previous leg");
305+
nErr++;
306+
}
211307
continue;
212308
}
213309
jtr = trbase->NextNeighbour();
214310
if (jtr >= 0) {
215311
trbase = &(mSectorTrackInfos[jtr]);
216312
tr = trbase;
217313
if (tr->PrevSegmentNeighbour() >= 0) {
314+
GPUError("FAILURE: Neibhbour leg has previous segment neightbout");
315+
nErr++;
218316
break;
219317
}
220318
continue;
@@ -230,62 +328,11 @@ void GPUTPCGMMerger::CheckMergedTracks()
230328
}
231329
if (nErr == 0) {
232330
GPUInfo("Merged Track Graph OK");
233-
}
234-
}
235-
236-
template <class T>
237-
inline const auto* resolveMCLabels(const o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>* a, const AliHLTTPCClusterMCLabel* b)
238-
{
239-
return a;
240-
}
241-
template <>
242-
inline const auto* resolveMCLabels<AliHLTTPCClusterMCLabel>(const o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>* a, const AliHLTTPCClusterMCLabel* b)
243-
{
244-
return b;
245-
}
246-
247-
template <class T, class S>
248-
int64_t GPUTPCGMMerger::GetTrackLabelA(const S& trk) const
249-
{
250-
GPUTPCGMSectorTrack* sectorTrack = nullptr;
251-
int32_t nClusters = 0;
252-
if constexpr (std::is_same_v<S, GPUTPCGMBorderTrack&>) {
253-
sectorTrack = &mSectorTrackInfos[trk.TrackID()];
254-
nClusters = sectorTrack->OrigTrack()->NHits();
255331
} else {
256-
nClusters = trk.NClusters();
257-
}
258-
auto acc = GPUTPCTrkLbl<false, GPUTPCTrkLbl_ret>(resolveMCLabels<T>(GetConstantMem()->ioPtrs.clustersNative ? GetConstantMem()->ioPtrs.clustersNative->clustersMCTruth : nullptr, GetConstantMem()->ioPtrs.mcLabelsTPC), 0.5f);
259-
for (int32_t i = 0; i < nClusters; i++) {
260-
int32_t id;
261-
if constexpr (std::is_same_v<S, GPUTPCGMBorderTrack&>) {
262-
const GPUTPCTracker& tracker = GetConstantMem()->tpcTrackers[sectorTrack->Sector()];
263-
const GPUTPCHitId& ic = tracker.TrackHits()[sectorTrack->OrigTrack()->FirstHitID() + i];
264-
id = tracker.Data().ClusterDataIndex(tracker.Data().Row(ic.RowIndex()), ic.HitIndex()) + GetConstantMem()->ioPtrs.clustersNative->clusterOffset[sectorTrack->Sector()][0];
265-
} else {
266-
id = mClusters[trk.FirstClusterRef() + i].num;
267-
}
268-
acc.addLabel(id);
269-
}
270-
return acc.computeLabel().id;
271-
}
272-
273-
template <class S>
274-
int64_t GPUTPCGMMerger::GetTrackLabel(const S& trk) const
275-
{
276-
#ifdef GPUCA_TPC_GEOMETRY_O2
277-
if (GetConstantMem()->ioPtrs.clustersNative->clustersMCTruth) {
278-
return GetTrackLabelA<o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>, S>(trk);
279-
} else
280-
#endif
281-
{
282-
return GetTrackLabelA<AliHLTTPCClusterMCLabel, S>(trk);
332+
throw std::runtime_error("Invalid merge graph");
283333
}
284334
}
285335

286-
#endif
287-
// END DEBUG CODE
288-
289336
void GPUTPCGMMerger::PrintMergeGraph(const GPUTPCGMSectorTrack* trk, std::ostream& out) const
290337
{
291338
const GPUTPCGMSectorTrack* orgTrack = trk;
@@ -1441,7 +1488,6 @@ struct GPUTPCGMMerger_CompareClusterIds {
14411488

14421489
GPUd() void GPUTPCGMMerger::CollectMergedTracks(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread)
14431490
{
1444-
// if (iThread == 0 && iBlock == 0) { CheckMergedTracks(); } return; // (if GPUCA_CADEBUG_ENABLED)
14451491
static constexpr int32_t kMaxParts = 16;
14461492
static constexpr int32_t kMaxClusters = GPUCA_MERGER_MAX_TRACK_CLUSTERS;
14471493

GPU/GPUTracking/Merger/GPUTPCGMMerger.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,16 @@ class GPUTPCGMMerger : public GPUProcessor
218218
GPUdi() int32_t SectorTrackInfoLocalTotal() const { return mSectorTrackInfoIndex[NSECTORS]; }
219219
GPUdi() int32_t SectorTrackInfoTotal() const { return mSectorTrackInfoIndex[2 * NSECTORS]; }
220220

221+
void CheckMergeGraph();
222+
void CheckCollectedTracks();
223+
221224
private:
222225
GPUd() void MergeSectorsPrepareStep2(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iBorder, GPUTPCGMBorderTrack** B, GPUAtomic(uint32_t) * nB, bool useOrigTrackParam = false);
223226
template <int32_t I>
224227
GPUd() void MergeBorderTracks(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iSector1, GPUTPCGMBorderTrack* B1, int32_t N1, int32_t iSector2, GPUTPCGMBorderTrack* B2, int32_t N2, int32_t mergeMode = 0);
225228

226229
GPUd() void MergeCEFill(const GPUTPCGMSectorTrack* track, const GPUTPCGMMergedTrackHit& cls, int32_t itr);
227230

228-
void CheckMergedTracks();
229231
#ifndef GPUCA_GPUCODE
230232
void PrintMergeGraph(const GPUTPCGMSectorTrack* trk, std::ostream& out) const;
231233
template <class T, class S>

GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ class GPUTPCGMTrackParam
149149
GPUd() bool AttachClustersPropagate(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t sector, int32_t lastRow, int32_t toRow, int32_t iTrack, bool goodLeg, GPUTPCGMPropagator& prop, bool inFlyDirection, float maxSinPhi = GPUCA_MAX_SIN_PHI, bool checkdEdx = false);
150150
GPUd() float AttachClusters(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t sector, int32_t iRow, int32_t iTrack, bool goodLeg, GPUTPCGMPropagator& prop); // Returns uncorrectedY for later use
151151
GPUd() float AttachClusters(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t sector, int32_t iRow, int32_t iTrack, bool goodLeg, float Y, float Z);
152-
// We force to compile these twice, for PropagateLooper and for Fit, for better optimization
153152
GPUd() void AttachClustersLooper(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t sector, int32_t iRow, int32_t iTrack, bool outwards, GPUTPCGMPropagator& prop);
154153
GPUd() void AttachClustersLooperFollow(const GPUTPCGMMerger* GPUrestrict() Merger, GPUTPCGMPropagator& prop, int32_t sector, int32_t iRow, int32_t iTrack, bool outwards);
155154
GPUd() void StoreLoopPropagation(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t sector, int32_t iRow, int32_t iTrack, bool outwards, float alpha);

0 commit comments

Comments
 (0)