Skip to content

Commit cb93a0a

Browse files
committed
GPU/TPC: Add vectorised CPU version of tail filter
1 parent e05c9db commit cb93a0a

5 files changed

Lines changed: 444 additions & 70 deletions

File tree

GPU/GPUTracking/Definitions/GPUSettingsList.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ AddOptionRTC(maxTimeBinAboveThresholdIn1000Bin, uint16_t, 500, "", 0, "Except pa
113113
AddOptionRTC(maxConsecTimeBinAboveThreshold, uint16_t, 200, "", 0, "Except pad from cluster finding if number of consecutive charges in a fragment is above this baseline (disable = 0)")
114114
AddOptionRTC(noisyPadSaturationThreshold, uint16_t, 700, "", 0, "Threshold where a timebin is considered saturated, disabling the noisy pad check for that pad")
115115
AddOptionRTC(hipTailFilter, uint8_t, 0, "", 0, "Enable Highly Ionising Particle tail filter in CheckPadBaseline (0 = disable, 1 = filter tails)")
116-
AddOptionRTC(hipTailFilterMinimum, uint16_t, 1024, "", 0, "Thread signal above this minimum as saturated")
116+
AddOptionRTC(hipTailFilterMinimum, uint16_t, 1023, "", 0, "Thread signal above this minimum as saturated")
117117
AddOptionRTC(hipTailFilterThreshold, uint16_t, 100, "", 0, "Threshold that must be exceeded for a timebin to be counted towards Highly Ionising Particle tail")
118118
AddOptionRTC(hipTailFilterAlpha, float, 0.5f, "", 0, "Smoothing factor for the exponential Highly Ionising Particle tail filter")
119119
AddOptionRTC(occupancyMapTimeBins, uint16_t, 16, "", 0, "Number of timebins per histogram bin of occupancy map (0 = disable occupancy map)")

GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,16 +1144,12 @@ int32_t GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput)
11441144
// TODO Add some warning when re enabling pad filter with this flag, so it's not just silently enabled when disabling was requested
11451145
checkForNoisyPads |= rec()->GetParam().rec.tpc.hipTailFilter;
11461146

1147-
if (rec()->GetParam().rec.tpc.hipTailFilter && !doGPU) {
1148-
GPUError("HIP tail filter enabled, but this is currently not supported on CPU");
1149-
}
1150-
11511147
if (checkForNoisyPads) {
11521148
if (rec()->GetParam().rec.tpc.hipTailFilter) {
11531149
runKernel<GPUMemClean16>({GetGridAutoStep(lane, RecoStep::TPCClusterFinding)}, clustererShadow.mPhipTailsByRow, GPUTPCGeometry::NROWS * sizeof(*clustererShadow.mPhipTailsByRow) * GPUTPCCFHIPClusterizer::MaxHIPTailsPerRow);
11541150
runKernel<GPUMemClean16>({GetGridAutoStep(lane, RecoStep::TPCClusterFinding)}, clustererShadow.mPnHIPTails, GPUTPCGeometry::NROWS * sizeof(*clustererShadow.mPnHIPTails));
11551151
}
1156-
const int32_t nBlocks = GPUTPCCFCheckPadBaseline::GetNBlocks(doGPU);
1152+
const int32_t nBlocks = GPUTPCGeometry::NROWS;
11571153

11581154
runKernel<GPUTPCCFCheckPadBaseline>({GetGridBlk(nBlocks, lane), {iSector}});
11591155
getKernelTimer<GPUTPCCFCheckPadBaseline>(RecoStep::TPCClusterFinding, iSector, TPC_REAL_PADS_IN_SECTOR * fragment.lengthWithoutOverlap() * sizeof(PackedCharge), false);

GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx

Lines changed: 262 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#ifndef GPUCA_GPUCODE
2323
#include "MCLabelAccumulator.h"
2424
#include "utils/VcShim.h"
25+
#include <vector>
2526
#endif
2627

2728
#if 0
@@ -344,7 +345,7 @@ GPUd() void GPUTPCCFCheckPadBaseline::CheckBaselineGPU(int32_t nBlocks, int32_t
344345

345346
GPUbarrier();
346347

347-
} // if (hipTriggerFound)
348+
} // if (hasHIPTrigger)
348349

349350
} // for (uint16_t t = firstTB; t < lastTB; t += NumOfCachedTBs)
350351

@@ -374,60 +375,264 @@ GPUd() void GPUTPCCFCheckPadBaseline::CheckBaselineGPU(int32_t nBlocks, int32_t
374375
GPUd() void GPUTPCCFCheckPadBaseline::CheckBaselineCPU(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer)
375376
{
376377
#ifndef GPUCA_GPUCODE
377-
const CfFragment& fragment = clusterer.mPmemory->fragment;
378-
CfArray2D<PackedCharge> chargeMap(reinterpret_cast<PackedCharge*>(clusterer.mPchargeMap));
379-
380-
CfChargePos basePos(iBlock * PadsPerCacheline, 0);
381-
382-
constexpr GPUTPCGeometry geo;
383-
if (basePos.pad() >= geo.NPads(basePos.row())) {
378+
if (iBlock >= (int32_t)GPUTPCGeometry::NROWS) {
384379
return;
385380
}
386381

387-
constexpr size_t ElemsInTileRow = (size_t)TilingLayout<GridSize<2>>::WidthInTiles * TimebinsPerCacheline * PadsPerCacheline;
382+
constexpr GPUTPCGeometry geo;
383+
const int32_t row = iBlock;
384+
const int32_t nPads = geo.NPads(row);
385+
const int32_t nVecPads = (nPads + PadsPerCacheline - 1) / PadsPerCacheline;
386+
387+
const CfFragment& fragment = clusterer.mPmemory->fragment;
388+
const bool hipFilterOn = clusterer.Param().rec.tpc.hipTailFilter;
389+
const Charge hipTailThreshold = clusterer.Param().rec.tpc.hipTailFilterThreshold;
390+
const Charge hipTailFilterAlpha = clusterer.Param().rec.tpc.hipTailFilterAlpha;
391+
auto* nHIPTails = clusterer.mPnHIPTails;
392+
auto* hipTails = GetHIPTails(clusterer, row);
393+
394+
CfArray2D<PackedCharge> chargeMap(reinterpret_cast<PackedCharge*>(clusterer.mPchargeMap));
388395

389396
using UShort8 = Vc::fixed_size_simd<uint16_t, PadsPerCacheline>;
397+
using Short8 = Vc::fixed_size_simd<int16_t, PadsPerCacheline>;
390398
using Charge8 = Vc::fixed_size_simd<float, PadsPerCacheline>;
391399

392-
UShort8 totalCharges{Vc::Zero};
393-
UShort8 consecCharges{Vc::Zero};
394-
UShort8 maxConsecCharges{Vc::Zero};
395-
Charge8 maxCharge{Vc::Zero};
396-
397-
tpccf::TPCFragmentTime t = fragment.firstNonOverlapTimeBin();
398-
399-
// Access packed charges as raw integers. We throw away the PackedCharge type here to simplify vectorization.
400-
const uint16_t* packedChargeStart = reinterpret_cast<uint16_t*>(&chargeMap[basePos.delta({0, t})]);
401-
402-
for (; t < fragment.lastNonOverlapTimeBin(); t += TimebinsPerCacheline) {
403-
for (tpccf::TPCFragmentTime localtime = 0; localtime < TimebinsPerCacheline; localtime++) {
404-
const UShort8 packedCharges{packedChargeStart + PadsPerCacheline * localtime, Vc::Aligned};
405-
const UShort8::mask_type isCharge = packedCharges != 0;
406-
407-
if (isCharge.isNotEmpty()) {
408-
totalCharges(isCharge)++;
409-
consecCharges += 1;
410-
consecCharges(not isCharge) = 0;
411-
maxConsecCharges = Vc::max(consecCharges, maxConsecCharges);
412-
413-
// Manually unpack charges to float.
414-
// Duplicated from PackedCharge::unpack to generate vectorized code:
415-
// Charge unpack() const { return Charge(mVal & ChargeMask) / Charge(1 << DecimalBits); }
416-
// Note that PackedCharge has to cut off the highest 2 bits via ChargeMask as they are used for flags by the cluster finder
417-
// and are not part of the charge value. We can skip this step because the cluster finder hasn't run yet
418-
// and thus these bits are guarenteed to be zero.
419-
const Charge8 unpackedCharges = Charge8(packedCharges) / Charge(1 << PackedCharge::DecimalBits);
420-
maxCharge = Vc::max(maxCharge, unpackedCharges);
421-
} else {
422-
consecCharges = 0;
423-
}
400+
std::vector<UShort8> totalChargesV(nVecPads, UShort8{Vc::Zero});
401+
std::vector<UShort8> consecChargesV(nVecPads, UShort8{Vc::Zero});
402+
std::vector<UShort8> maxConsecChargesV(nVecPads, UShort8{Vc::Zero});
403+
std::vector<Charge8> maxChargeV(nVecPads, Charge8{Vc::Zero});
404+
405+
std::vector<Short8> localHipTbV(nVecPads, -1);
406+
std::vector<Short8> broadcastHipTbV(nVecPads, -1);
407+
std::vector<Short8> aboveThresholdStartV(nVecPads, -1);
408+
std::vector<Short8> activeHIPTailStartV(nVecPads, -1);
409+
std::vector<Short8> activeHIPTailEndV(nVecPads, -1);
410+
std::vector<Charge8> tailFilterChargeV(nVecPads, Charge8{Vc::Zero});
411+
412+
for (int16_t t = 0; t < fragment.length; t += NumOfCachedTBs) {
413+
414+
bool hasAnyTrigger = false;
415+
416+
// Run actual noisy pad filter and look for HIP trigger
417+
for (int16_t iVecPad = 0; iVecPad < nVecPads; iVecPad++) {
418+
419+
auto totalCharges = totalChargesV[iVecPad];
420+
auto consecCharges = consecChargesV[iVecPad];
421+
auto maxConsecCharges = maxConsecChargesV[iVecPad];
422+
auto maxCharge = maxChargeV[iVecPad];
423+
424+
auto hipTb = Short8(-1);
425+
auto aboveThresholdStart = aboveThresholdStartV[iVecPad];
426+
auto activeHIPTailStart = activeHIPTailStartV[iVecPad];
427+
auto activeHIPTailEnd = activeHIPTailEndV[iVecPad];
428+
auto tailFilterCharge = tailFilterChargeV[iVecPad];
429+
430+
431+
const CfChargePos basePos(row, iVecPad * PadsPerCacheline, t);
432+
433+
for (tpccf::TPCFragmentTime localtime = 0; localtime < NumOfCachedTBs; localtime++) {
434+
435+
const uint16_t* packedChargeStart = reinterpret_cast<uint16_t*>(&chargeMap[basePos.delta({0, localtime})]);
436+
const UShort8 packedCharges = t + localtime < fragment.length
437+
? UShort8{packedChargeStart, Vc::Aligned} : UShort8{Vc::Zero};
438+
const auto isCharge = packedCharges != 0;
439+
440+
const auto unpackedCharges = Charge8(packedCharges) / Charge(1 << PackedCharge::DecimalBits);
441+
442+
if (isCharge.isNotEmpty()) {
443+
totalCharges(isCharge)++;
444+
consecCharges += 1;
445+
consecCharges(not isCharge) = 0;
446+
maxConsecCharges = Vc::max(consecCharges, maxConsecCharges);
447+
448+
// Manually unpack charges to float.
449+
// Duplicated from PackedCharge::unpack to generate vectorized code:
450+
// Charge unpack() const { return Charge(mVal & ChargeMask) / Charge(1 << DecimalBits); }
451+
// Note that PackedCharge has to cut off the highest 2 bits via ChargeMask as they are used for flags by the cluster finder
452+
// and are not part of the charge value. We can skip this step because the cluster finder hasn't run yet
453+
// and thus these bits are guarenteed to be zero.
454+
maxCharge = Vc::max(maxCharge, unpackedCharges);
455+
456+
const auto aboveRisingEdge = unpackedCharges >= hipTailThreshold;
457+
const auto startRisingEdge = aboveRisingEdge && aboveThresholdStart < 0;
458+
aboveThresholdStart(startRisingEdge) = t + localtime;
459+
aboveThresholdStart(!aboveRisingEdge) = -1;
460+
461+
const auto hasNewTrigger = hipTb < 0 && unpackedCharges >= Charge(MaxADC);
462+
hipTb(hasNewTrigger) = aboveThresholdStart;
463+
hasAnyTrigger |= hasNewTrigger.isNotEmpty();
464+
} else {
465+
consecCharges = 0;
466+
aboveThresholdStart = -1;
467+
}
468+
469+
const auto tailOpen = activeHIPTailStart > -1 && activeHIPTailEnd < 0;
470+
tailFilterCharge(tailOpen) = tailFilterCharge + hipTailFilterAlpha * (unpackedCharges - tailFilterCharge);
471+
activeHIPTailEnd(tailOpen && tailFilterCharge < hipTailThreshold) = t + localtime;
472+
} // for (tpccf::TPCFragmentTime localtime = 0; localtime < TimebinsPerCacheline; localtime++)
473+
474+
totalChargesV[iVecPad] = totalCharges;
475+
consecChargesV[iVecPad] = consecCharges;
476+
maxConsecChargesV[iVecPad] = maxConsecCharges;
477+
maxChargeV[iVecPad] = maxCharge;
478+
479+
localHipTbV[iVecPad] = hipTb;
480+
aboveThresholdStartV[iVecPad] = aboveThresholdStart;
481+
activeHIPTailStartV[iVecPad] = activeHIPTailStart;
482+
activeHIPTailEndV[iVecPad] = activeHIPTailEnd;
483+
tailFilterChargeV[iVecPad] = tailFilterCharge;
484+
485+
} // for (int16_t iVecPad = 0; iVecPad < nVecPads; iVecPad++)
486+
487+
if (hasAnyTrigger) {
488+
broadcastHipTbV = localHipTbV;
424489
}
425490

426-
packedChargeStart += ElemsInTileRow;
427-
}
491+
// Broadcast trigger times to neighboring pads across the whole
492+
for (int16_t iVecPad = 0; iVecPad < nVecPads && hasAnyTrigger; iVecPad++) {
493+
494+
const auto hipTb = localHipTbV[iVecPad];
495+
496+
const auto hasHipTrigger = hipTb > -1;
497+
if (hasHipTrigger.isNotEmpty()) [[unlikely]] {
498+
499+
// TODO: This could be vectorised, but doesn't seem necessary
500+
for (uint16_t p = 0; p < PadsPerCacheline; p++) {
501+
if (hasHipTrigger[p]) {
502+
const int16_t pad = iVecPad * PadsPerCacheline + p;
503+
const int16_t neighborSt = CAMath::Max(0, pad - SSClusterPadWidth);
504+
const int16_t neighborEnd = CAMath::Min(nPads, pad + SSClusterPadWidth + 1);
505+
for (int16_t np = neighborSt; np < neighborEnd; np++) {
506+
if (np == pad) {
507+
continue;
508+
}
509+
const auto pv = np / PadsPerCacheline;
510+
const auto pi = np % PadsPerCacheline;
511+
// GPU keeps a pad's own trigger time; only pads without a local trigger inherit from neighbors.
512+
if (localHipTbV[pv][pi] < 0) {
513+
broadcastHipTbV[pv][pi] = CAMath::Max<int16_t>(hipTb[p], broadcastHipTbV[pv][pi]);
514+
}
515+
} // for (int16_t np = neighborSt; np < neighborEnd; np++)
516+
} // if (hasHipTrigger[p]) {
517+
} // for (uint16_t p = 0; p < PadsPerCacheline; p++)
518+
} // if (hasHipTrigger.isNotEmpty())
519+
} // for (int16_t iVecPad = 0; iVecPad < nVecPads; iVecPad++)
520+
521+
// Close old tails for all pads, open new tails in case of overlap
522+
for (int16_t iVecPad = 0; iVecPad < nVecPads && hasAnyTrigger; iVecPad++) {
523+
524+
auto hipTb = broadcastHipTbV[iVecPad];
525+
auto aboveThresholdStart = aboveThresholdStartV[iVecPad];
526+
auto activeHIPTailStart = activeHIPTailStartV[iVecPad];
527+
auto activeHIPTailEnd = activeHIPTailEndV[iVecPad];
528+
auto tailFilterCharge = tailFilterChargeV[iVecPad];
529+
530+
const auto shouldCloseTail = hipTb > -1 && activeHIPTailStart > -1;
531+
activeHIPTailEnd(shouldCloseTail && activeHIPTailEnd < 0) = hipTb;
532+
533+
// Closing tails will store them to global memory and zero the range
534+
// So it's enough to disable this part to fully disable the tail filter
535+
if (hipFilterOn && shouldCloseTail.isNotEmpty()) {
536+
for (int16_t p = 0; p < PadsPerCacheline; p++) {
537+
const int16_t pad = iVecPad * PadsPerCacheline + p;
538+
if (shouldCloseTail[p] && pad < nPads) {
539+
Charge tailQtot = 0;
540+
Charge tailQMax = 0;
541+
for (int16_t tt = activeHIPTailStart[p]; tt < activeHIPTailEnd[p]; tt++) {
542+
const CfChargePos basePos(row, iVecPad * PadsPerCacheline, 0);
543+
const auto pos = basePos.delta({p, tt});
544+
const auto q = chargeMap[pos].unpack();
545+
tailQtot += q;
546+
tailQMax = CAMath::Max(tailQMax, q);
547+
chargeMap[pos] = PackedCharge{0};
548+
}
549+
550+
if (activeHIPTailEnd[p] > activeHIPTailStart[p]) { // Prune empty tails
551+
const auto tailIdx = CAMath::AtomicAdd<uint32_t>(&nHIPTails[row], 1) + 1;
552+
if (tailIdx < GPUTPCCFHIPTailConnector::MaxHIPTailsPerRow) {
553+
hipTails[tailIdx] = {
554+
.iPrev = 0,
555+
.iNext = 0,
556+
.pad = uint16_t(pad),
557+
.tailStart = uint16_t(activeHIPTailStart[p]),
558+
.tailEnd = uint16_t(activeHIPTailEnd[p]),
559+
.qTot = tailQtot,
560+
.qMax = tailQMax,
561+
};
562+
}
563+
}
564+
565+
} // if (shouldCloseTail[p] && pad < nPads)
566+
} // for (uint16_t p = 0; p < PadsPerCacheline; p++)
567+
} // if (shouldCloseThipFilterOn && shouldCloseTail.isNotEmpty())
568+
569+
activeHIPTailStart(hipTb > -1) = hipTb;
570+
activeHIPTailEnd(hipTb > -1) = -1;
571+
tailFilterCharge(hipTb > -1) = MaxADC;
572+
573+
aboveThresholdStartV[iVecPad] = aboveThresholdStart;
574+
activeHIPTailStartV[iVecPad] = activeHIPTailStart;
575+
activeHIPTailEndV[iVecPad] = activeHIPTailEnd;
576+
tailFilterChargeV[iVecPad] = tailFilterCharge;
577+
578+
} // for (int32_t iVecPad = 0; iVecPad < nVecPads; iVecPad++)
579+
} // for (auto t = 0; t < fragment.length; t += TimebinsPerCacheline)
580+
581+
// Close old tails for all pads, open new tails in case of overlap
582+
for (int16_t iVecPad = 0; iVecPad < nVecPads; iVecPad++) {
583+
584+
auto activeHIPTailStart = activeHIPTailStartV[iVecPad];
585+
auto activeHIPTailEnd = activeHIPTailEndV[iVecPad];
586+
587+
const auto shouldCloseTail = activeHIPTailStart > -1;
588+
activeHIPTailEnd(shouldCloseTail && activeHIPTailEnd < 0) = fragment.length;
589+
590+
if (hipFilterOn && shouldCloseTail.isNotEmpty()) {
591+
for (int16_t p = 0; p < PadsPerCacheline; p++) {
592+
const int16_t pad = iVecPad * PadsPerCacheline + p;
593+
if (shouldCloseTail[p] && pad < nPads) {
594+
Charge tailQtot = 0;
595+
Charge tailQMax = 0;
596+
for (int16_t tt = activeHIPTailStart[p]; tt < activeHIPTailEnd[p]; tt++) {
597+
const CfChargePos basePos(row, iVecPad * PadsPerCacheline, 0);
598+
const auto pos = basePos.delta({p, tt});
599+
const auto q = chargeMap[pos].unpack();
600+
tailQtot += q;
601+
tailQMax = CAMath::Max(tailQMax, q);
602+
chargeMap[pos] = PackedCharge{0};
603+
}
604+
605+
if (activeHIPTailEnd[p] > activeHIPTailStart[p]) { // Prune empty tails
606+
const auto tailIdx = CAMath::AtomicAdd<uint32_t>(&nHIPTails[row], 1) + 1;
607+
if (tailIdx < GPUTPCCFHIPTailConnector::MaxHIPTailsPerRow) {
608+
hipTails[tailIdx] = {
609+
.iPrev = 0,
610+
.iNext = 0,
611+
.pad = uint16_t(pad),
612+
.tailStart = uint16_t(activeHIPTailStart[p]),
613+
.tailEnd = uint16_t(activeHIPTailEnd[p]),
614+
.qTot = tailQtot,
615+
.qMax = tailQMax,
616+
};
617+
}
618+
}
428619

429-
for (tpccf::Pad localpad = 0; localpad < PadsPerCacheline; localpad++) {
430-
updatePadBaseline(basePos.gpad + localpad, clusterer, totalCharges[localpad], maxConsecCharges[localpad], maxCharge[localpad]);
620+
} // if (shouldCloseTail[p] && pad < nPads)
621+
} // for (uint16_t p = 0; p < PadsPerCacheline; p++)
622+
} // if (hipFilterOn && shouldCloseTail.isNotEmpty())
623+
} // for (int16_t iVecPad = 0; iVecPad < nVecPads; iVecPad++)
624+
625+
for (int32_t iVecPad = 0; iVecPad < nVecPads; iVecPad++) {
626+
627+
const UShort8 totalCharges = totalChargesV[iVecPad];
628+
const UShort8 maxConsecCharges = maxConsecChargesV[iVecPad];
629+
const Charge8 maxCharge = maxChargeV[iVecPad];
630+
631+
const CfChargePos basePos(row, iVecPad * PadsPerCacheline, 0);
632+
633+
for (tpccf::Pad localpad = 0; localpad < PadsPerCacheline; localpad++) {
634+
updatePadBaseline(basePos.gpad + localpad, clusterer, totalCharges[localpad], maxConsecCharges[localpad], maxCharge[localpad]);
635+
}
431636
}
432637
#endif
433638
}
@@ -463,16 +668,23 @@ GPUd() void GPUTPCCFHIPTailConnector::Thread<0>(int32_t nBlocks, int32_t nThread
463668
#ifdef GPUCA_DETERMINISTIC_MODE
464669
// Races in tail comparisons and atomic swap can lead to slightly different clusters.
465670
// So need a sequential fallback for deterministic mode
466-
if (iThread > 0) {
467-
return;
468-
}
469-
nThreads = 1;
470671
GPUCommonAlgorithm::sortInBlock(tails + 1, tails + nTails + 1, [](auto&& t1, auto&& t2) {
471672
if (t1.pad != t2.pad) {
472673
return t1.pad < t2.pad;
674+
} else if (t1.tailStart != t2.tailStart) {
675+
return t1.tailStart < t2.tailStart;
676+
} else if (t1.tailEnd != t2.tailEnd) {
677+
return t1.tailEnd < t2.tailEnd;
678+
} else if (t1.qTot != t2.qTot) {
679+
return t1.qTot < t2.qTot;
680+
} else {
681+
return t1.qMax < t2.qMax;
473682
}
474-
return t1.tailStart < t2.tailStart;
475683
});
684+
if (iThread > 0) {
685+
return;
686+
}
687+
nThreads = 1;
476688
#endif
477689

478690
for (uint32_t iTail = iThread + 1; iTail <= nTails; iTail += nThreads) {

GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,6 @@ class GPUTPCCFCheckPadBaseline : public GPUKernelTemplate
126126
return gpudatatypes::RecoStep::TPCClusterFinding;
127127
}
128128

129-
static int32_t GetNBlocks(bool isGPU)
130-
{
131-
// Important to exclude rightmost padding from Pad Filter.
132-
// There's nothing to filter there and padding is counted as start of a row, so it causes an overflow in the row count.
133-
const int32_t nBlocksCPU = (TPC_CLUSTERER_STRIDED_PAD_COUNT - GPUCF_PADDING_PAD) / PadsPerCacheline;
134-
return isGPU ? GPUTPCGeometry::NROWS : nBlocksCPU;
135-
}
136-
137129
template <int32_t iKernel = defaultKernel>
138130
GPUd() static void Thread(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer);
139131

0 commit comments

Comments
 (0)