29#define DPRINT(...) printf(__VA_ARGS__)
33#define DPRINTB_IF(test, ...) \
34 if (iThread == 0 && (test)) \
37#define DPRINT(...) ((void)0)
38#define DPRINTB(...) ((void)0)
39#define DPRINTB_IF(test, ...) ((void)0)
55 return filteredCharge +
alpha * (
charge - filteredCharge);
60 const float length = tail.
tailEnd > tail.tailStart ? float(tail.tailEnd - tail.tailStart) : 1.f;
67static GPUdi() uint16_t CloseHIPTails(
68 Kernel::GPUSharedMemory& smem,
70 int32_t iThread, int32_t nThreads,
74 Kernel::PadChargeAccu& acc,
77 const uint32_t
row = basePos.row();
78 const uint16_t nClosedTails = work_group_count(shouldCloseTail);
80 auto* nHIPTails = clusterer.mPnHIPTails;
81 auto* hipTails = GetHIPTails(clusterer,
row);
83 if (nClosedTails > 0) {
84 int16_t iClosedTail = work_group_scan_inclusive_add((int16_t)shouldCloseTail) - 1;
85 const bool shouldStoreTail = shouldCloseTail && acc.activeHIPTail.Length() > 0;
86 uint16_t nStoredTails = work_group_count(shouldStoreTail);
87 int16_t iStoredTail = work_group_scan_inclusive_add((int16_t)shouldStoreTail) - 1;
91 if (nStoredTails > 0) {
93 smem.tailStoreBase = CAMath::AtomicAdd(&nHIPTails[
row], (uint32_t)nStoredTails);
97 if (shouldCloseTail) {
98 smem.tailsClosedPad[iClosedTail] = iPadHandle;
99 smem.tailsClosed[iClosedTail] = acc.activeHIPTail;
102 if (shouldStoreTail) {
103 const uint32_t
idx = smem.tailStoreBase + iStoredTail + 1;
104 smem.tailsClosedStoreIdx[iClosedTail] =
idx;
106 hipTails[
idx] = {0, 0, (uint16_t)iPadHandle,
107 (uint16_t)acc.activeHIPTail.start, (uint16_t)acc.activeHIPTail.end,
108 acc.activeSatStart, acc.activeSatEnd,
113 acc.tailFilterCharge = 0;
114 acc.activeHIPTail.Reset();
115 acc.activeSatStart = acc.activeSatEnd = -1;
122 for (uint16_t iTail = 0; iTail < nClosedTails; iTail++) {
123 const auto tailPad = smem.tailsClosedPad[iTail];
124 const auto tail = smem.tailsClosed[iTail];
125 const uint32_t tailStoreIdx = smem.tailsClosedStoreIdx[iTail];
129 for (uint16_t iTime = iThread; iTime < tail.Length(); iTime += nThreads) {
130 const int16_t
time = tail.start + iTime;
131 auto pos = basePos.delta({tailPad,
time});
132 const Charge q = chargeMap[
pos].unpack();
134 qMax = CAMath::Max(qMax, q);
138 smem.tailQTotScratch[iThread] = qTot;
139 smem.tailQMaxScratch[iThread] = qMax;
144 smem.tailQTotScratch[iThread] += smem.tailQTotScratch[iThread +
stride];
145 smem.tailQMaxScratch[iThread] = CAMath::Max(smem.tailQMaxScratch[iThread], smem.tailQMaxScratch[iThread +
stride]);
153 tailDescriptor.
qTot = smem.tailQTotScratch[0];
154 tailDescriptor.
qMax = smem.tailQMaxScratch[0];
161template <
bool CheckHIPTrigger,
bool CheckHIPTailEnd>
162static GPUdi()
void ScanCachedCharges(
Kernel::GPUSharedMemory& smem, uint16_t timeOffset, uint16_t pad,
Charge hipTailThreshold,
Charge hipTailFilterAlpha,
Kernel::PadChargeAccu& acc)
165 const Charge qs = smem.charges[
i][pad];
166 const int16_t curTB = timeOffset +
i;
168 acc.totalCharges += qs > 0;
169 acc.consecCharges = qs > 0 ? acc.consecCharges + 1 : 0;
170 acc.maxConsecCharges = CAMath::Max(acc.consecCharges, acc.maxConsecCharges);
171 acc.maxCharge = CAMath::Max<Charge>(qs, acc.maxCharge);
173 if (qs >= hipTailThreshold) {
174 if (acc.aboveThresholdStart < 0) {
175 acc.aboveThresholdStart = curTB;
178 acc.aboveThresholdStart = -1;
181 if constexpr (CheckHIPTrigger) {
185 if (isSaturated && !acc.plateauOpen) {
186 acc.plateauStart = curTB;
188 acc.plateauOpen = isSaturated;
190 if (isSaturated && acc.activeSatStart > -1 && acc.activeSatStart == acc.plateauStart) {
191 acc.activeSatEnd = curTB;
194 if (acc.HIPtb < 0 && isSaturated) {
195 acc.HIPtb = acc.aboveThresholdStart;
196 acc.satStart = acc.plateauStart;
197 smem.tails[pad] = {acc.HIPtb, 0};
199 if (isSaturated && acc.satStart > -1 && acc.satStart == acc.plateauStart) {
204 if constexpr (CheckHIPTailEnd) {
205 if (acc.activeHIPTail.IsOpen()) {
206 acc.tailFilterCharge = UpdateHIPTailFilter(acc.tailFilterCharge, qs, hipTailFilterAlpha);
207 if (acc.tailFilterCharge < hipTailThreshold) {
208 acc.activeHIPTail.end = curTB;
219 CheckBaselineGPU(nBlocks, nThreads, iBlock, iThread, smem, clusterer);
221 CheckBaselineCPU(nBlocks, nThreads, iBlock, iThread, smem, clusterer);
231GPUd()
void GPUTPCCFCheckPadBaseline::CheckBaselineGPU(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer)
233#if defined(GPUCA_GPUCODE) && !defined(GPUCA_DEVICE_SINGLE_THREAD)
235 if (iBlock >= (int32_t)GPUTPCGeometry::NROWS) {
239 const CfFragment& frag = clusterer.mPmemory->frag;
240 const bool hipFilterOn = clusterer.Param().rec.tpc.hipTailFilter;
241 const Charge hipTailThreshold = clusterer.Param().rec.tpc.hipTailFilterThreshold;
242 const Charge hipTailFilterAlpha = clusterer.Param().rec.tpc.hipTailFilterAlpha;
247 const auto iRow = iBlock;
248 const auto nPads = geo.NPads(iRow);
253 const int16_t iPadOffset = iThread % MaxNPadsPerRow;
254 const int16_t iTimeOffset = iThread / MaxNPadsPerRow;
255 const int16_t iPadHandle = iThread;
256 const bool handlePad = iPadHandle < nPads;
258 if (iPadHandle < MaxNPadsPerRow) {
259 smem.tails[iPadHandle] = {-1, -1};
270 for (uint16_t t = firstTB; t < lastTB; t += NumOfCachedTBs) {
272 bool thisThreadHasTrigger =
false;
273 for (uint16_t
tt = 0;
tt < NumOfCachedTBs;
tt += TimebinsPerCacheline) {
278 const Charge ql = iTimeLoad < lastTB && iPadOffset < nPads ? chargeMap[
pos].unpack() : 0;
279 smem.charges[
tt + iTimeOffset][iPadOffset] = ql;
281 thisThreadHasTrigger |= ql >=
Charge(MaxADC);
284 bool hasHIPTrigger =
false;
286 hasHIPTrigger = work_group_any(thisThreadHasTrigger);
293 acc.satStart = acc.satEnd = -1;
294 if (!hasHIPTrigger) {
295 acc.plateauOpen =
false;
302 if (!hasHIPTrigger) [[likely]] {
303 if (!acc.activeHIPTail.IsOpen()) {
304 ScanCachedCharges<false, false>(smem, t, iPadHandle, hipTailThreshold, hipTailFilterAlpha, acc);
306 ScanCachedCharges<false, true>(smem, t, iPadHandle, hipTailThreshold, hipTailFilterAlpha, acc);
309 if (!acc.activeHIPTail.IsOpen()) {
310 ScanCachedCharges<true, false>(smem, t, iPadHandle, hipTailThreshold, hipTailFilterAlpha, acc);
312 ScanCachedCharges<true, true>(smem, t, iPadHandle, hipTailThreshold, hipTailFilterAlpha, acc);
319 if (hasHIPTrigger) [[unlikely]] {
321 DPRINTB(
"%d: Trigger!\n", iBlock);
323 if (handlePad && acc.HIPtb < 0) {
326 for (int16_t
i = -SSClusterPadWidth;
i < 0;
i++) {
327 const auto p = iPadHandle +
i;
329 acc.HIPtb = CAMath::Max(smem.tails[p].start, acc.HIPtb);
333 for (int16_t
i = 1;
i <= SSClusterPadWidth;
i++) {
334 const auto p = iPadHandle +
i;
335 if (p < MaxNPadsPerRow) {
336 acc.HIPtb = CAMath::Max(smem.tails[p].start, acc.HIPtb);
341 bool shouldCloseTail = acc.HIPtb > -1 && acc.activeHIPTail.HasValue();
344 if (shouldCloseTail && (acc.activeHIPTail.IsOpen() || acc.activeHIPTail.end > acc.HIPtb)) {
345 DPRINT(
"%d: end = %d\n", iThread, acc.HIPtb);
346 acc.activeHIPTail.end = acc.HIPtb;
351 int16_t newSatStart = acc.satStart;
352 int16_t newSatEnd = acc.satEnd;
353 if (shouldCloseTail && acc.activeSatStart > -1) {
354 if (acc.satStart < 0 && acc.activeSatEnd >= acc.activeHIPTail.end) {
355 newSatStart = acc.activeSatStart;
356 newSatEnd = acc.activeSatEnd;
358 if (acc.activeSatStart >= acc.activeHIPTail.end) {
359 acc.activeSatStart = acc.activeSatEnd = -1;
363 CloseHIPTails(smem, clusterer, iThread, nThreads, iPadHandle, basePos, chargeMap, acc, shouldCloseTail);
367 if (acc.HIPtb > -1) {
368 DPRINT(
"%d: start = %d\n", iThread, acc.HIPtb);
369 acc.activeHIPTail.SetOpen(acc.HIPtb);
370 acc.tailFilterCharge =
Charge(MaxADC);
371 acc.activeSatStart = newSatStart;
372 acc.activeSatEnd = newSatEnd;
377 smem.tails[iPadHandle].Reset();
387 updatePadBaseline(basePos.gpad + iPadHandle, clusterer, acc.totalCharges, acc.maxConsecCharges, acc.maxCharge);
391 const bool shouldCloseTail = acc.activeHIPTail.HasValue();
396 if (work_group_any(shouldCloseTail)) {
397 if (shouldCloseTail && acc.activeHIPTail.IsOpen()) {
398 acc.activeHIPTail.end = lastTB;
401 [[maybe_unused]]
const uint16_t nClosedTails = CloseHIPTails(smem, clusterer, iThread, nThreads, iPadHandle, basePos, chargeMap, acc, shouldCloseTail);
403 DPRINTB_IF(nClosedTails > 0,
"%d: Close remaining tails (%d)\n", iBlock, nClosedTails);
409GPUd()
void GPUTPCCFCheckPadBaseline::CheckBaselineCPU(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer)
412 if (iBlock >= (int32_t)GPUTPCGeometry::NROWS) {
417 const int32_t
row = iBlock;
418 const int32_t nPads = geo.NPads(
row);
419 const int32_t nVecPads = (nPads + PadsPerCacheline - 1) / PadsPerCacheline;
421 const CfFragment& frag = clusterer.mPmemory->frag;
422 const bool hipFilterOn = clusterer.Param().rec.tpc.hipTailFilter;
423 const Charge hipTailThreshold = clusterer.Param().rec.tpc.hipTailFilterThreshold;
424 const Charge hipTailFilterAlpha = clusterer.Param().rec.tpc.hipTailFilterAlpha;
425 auto* nHIPTails = clusterer.mPnHIPTails;
426 auto* hipTails = GetHIPTails(clusterer,
row);
430 using UShort8 = Vc::fixed_size_simd<uint16_t, PadsPerCacheline>;
431 using Short8 = Vc::fixed_size_simd<int16_t, PadsPerCacheline>;
432 using Charge8 = Vc::fixed_size_simd<float, PadsPerCacheline>;
434 std::vector<UShort8> totalChargesV(nVecPads, UShort8{Vc::Zero});
435 std::vector<UShort8> consecChargesV(nVecPads, UShort8{Vc::Zero});
436 std::vector<UShort8> maxConsecChargesV(nVecPads, UShort8{Vc::Zero});
437 std::vector<Charge8> maxChargeV(nVecPads, Charge8{Vc::Zero});
439 std::vector<Short8> localHipTbV(nVecPads, -1);
440 std::vector<Short8> broadcastHipTbV(nVecPads, -1);
441 std::vector<Short8> localSatStartV(nVecPads, -1);
442 std::vector<Short8> localSatEndV(nVecPads, -1);
443 std::vector<Short8> plateauStartV(nVecPads, -1);
444 std::vector<Short8> plateauOpenV(nVecPads, 0);
445 std::vector<Short8> aboveThresholdStartV(nVecPads, -1);
446 std::vector<Short8> activeHIPTailStartV(nVecPads, -1);
447 std::vector<Short8> activeHIPTailEndV(nVecPads, -1);
448 std::vector<Short8> activeHIPTailSatStartV(nVecPads, -1);
449 std::vector<Short8> activeHIPTailSatEndV(nVecPads, -1);
450 std::vector<Charge8> tailFilterChargeV(nVecPads, Charge8{Vc::Zero});
452 for (int16_t t = 0; t < frag.
length; t += NumOfCachedTBs) {
454 bool hasAnyTrigger =
false;
457 for (int16_t iVecPad = 0; iVecPad < nVecPads; iVecPad++) {
459 auto totalCharges = totalChargesV[iVecPad];
460 auto consecCharges = consecChargesV[iVecPad];
461 auto maxConsecCharges = maxConsecChargesV[iVecPad];
462 auto maxCharge = maxChargeV[iVecPad];
464 auto hipTb = Short8(-1);
465 auto satStart = Short8(-1);
466 auto satEnd = Short8(-1);
467 auto plateauStart = plateauStartV[iVecPad];
468 auto plateauOpen = plateauOpenV[iVecPad];
469 const auto activeHIPTailSatStart = activeHIPTailSatStartV[iVecPad];
470 auto activeHIPTailSatEnd = activeHIPTailSatEndV[iVecPad];
471 auto aboveThresholdStart = aboveThresholdStartV[iVecPad];
472 auto activeHIPTailStart = activeHIPTailStartV[iVecPad];
473 auto activeHIPTailEnd = activeHIPTailEndV[iVecPad];
474 auto tailFilterCharge = tailFilterChargeV[iVecPad];
480 const uint16_t* packedChargeStart =
reinterpret_cast<uint16_t*
>(&chargeMap[basePos.delta({0, localtime})]);
481 const UShort8 packedCharges = t + localtime < frag.
length
482 ? UShort8{packedChargeStart, Vc::Aligned}
484 const auto isCharge = packedCharges != 0;
488 if (isCharge.isNotEmpty()) {
489 totalCharges(isCharge)++;
491 consecCharges(not isCharge) = 0;
492 maxConsecCharges = Vc::max(consecCharges, maxConsecCharges);
500 maxCharge = Vc::max(maxCharge, unpackedCharges);
502 const auto aboveRisingEdge = unpackedCharges >= hipTailThreshold;
503 const auto startRisingEdge = aboveRisingEdge && aboveThresholdStart < 0;
504 aboveThresholdStart(startRisingEdge) = t + localtime;
505 aboveThresholdStart(!aboveRisingEdge) = -1;
508 const auto isSaturated = unpackedCharges >=
Charge(MaxADC);
509 plateauStart(isSaturated && plateauOpen < 1) = t + localtime;
511 plateauOpen(isSaturated) = 1;
513 activeHIPTailSatEnd(isSaturated && activeHIPTailSatStart > -1 && (activeHIPTailSatStart - plateauStart) == 0) = t + localtime;
515 const auto hasNewTrigger = hipTb < 0 && isSaturated;
516 hipTb(hasNewTrigger) = aboveThresholdStart;
517 satStart(hasNewTrigger) = plateauStart;
518 satEnd(isSaturated && satStart > -1 && (satStart - plateauStart) == 0) = t + localtime;
519 hasAnyTrigger |= hasNewTrigger.isNotEmpty();
522 aboveThresholdStart = -1;
526 const auto tailOpen = activeHIPTailStart > -1 && activeHIPTailEnd < 0;
527 tailFilterCharge(tailOpen) = tailFilterCharge + hipTailFilterAlpha * (unpackedCharges - tailFilterCharge);
528 activeHIPTailEnd(tailOpen && tailFilterCharge < hipTailThreshold) = t + localtime;
531 totalChargesV[iVecPad] = totalCharges;
532 consecChargesV[iVecPad] = consecCharges;
533 maxConsecChargesV[iVecPad] = maxConsecCharges;
534 maxChargeV[iVecPad] = maxCharge;
536 localHipTbV[iVecPad] = hipTb;
537 localSatStartV[iVecPad] = satStart;
538 localSatEndV[iVecPad] = satEnd;
539 plateauStartV[iVecPad] = plateauStart;
540 plateauOpenV[iVecPad] = plateauOpen;
541 activeHIPTailSatEndV[iVecPad] = activeHIPTailSatEnd;
542 aboveThresholdStartV[iVecPad] = aboveThresholdStart;
543 activeHIPTailStartV[iVecPad] = activeHIPTailStart;
544 activeHIPTailEndV[iVecPad] = activeHIPTailEnd;
545 tailFilterChargeV[iVecPad] = tailFilterCharge;
550 broadcastHipTbV = localHipTbV;
554 for (int16_t iVecPad = 0; iVecPad < nVecPads && hasAnyTrigger; iVecPad++) {
556 const auto hipTb = localHipTbV[iVecPad];
558 const auto hasHipTrigger = hipTb > -1;
559 if (hasHipTrigger.isNotEmpty()) [[unlikely]] {
562 for (uint16_t p = 0;
p < PadsPerCacheline;
p++) {
563 if (hasHipTrigger[p]) {
564 const int16_t pad = iVecPad * PadsPerCacheline +
p;
565 const int16_t neighborSt = CAMath::Max(0, pad - SSClusterPadWidth);
566 const int16_t neighborEnd = CAMath::Min(nPads, pad + SSClusterPadWidth + 1);
567 for (int16_t np = neighborSt; np < neighborEnd; np++) {
571 const auto pv = np / PadsPerCacheline;
572 const auto pi = np % PadsPerCacheline;
574 if (localHipTbV[pv][pi] < 0) {
575 broadcastHipTbV[pv][pi] = CAMath::Max<int16_t>(hipTb[p], broadcastHipTbV[pv][pi]);
584 for (int16_t iVecPad = 0; iVecPad < nVecPads && hasAnyTrigger; iVecPad++) {
586 auto hipTb = broadcastHipTbV[iVecPad];
587 const auto satStart = localSatStartV[iVecPad];
588 const auto satEnd = localSatEndV[iVecPad];
589 auto aboveThresholdStart = aboveThresholdStartV[iVecPad];
590 auto activeHIPTailStart = activeHIPTailStartV[iVecPad];
591 auto activeHIPTailEnd = activeHIPTailEndV[iVecPad];
592 auto activeHIPTailSatStart = activeHIPTailSatStartV[iVecPad];
593 auto activeHIPTailSatEnd = activeHIPTailSatEndV[iVecPad];
594 auto tailFilterCharge = tailFilterChargeV[iVecPad];
596 const auto shouldCloseTail = hipTb > -1 && activeHIPTailStart > -1;
599 activeHIPTailEnd(shouldCloseTail && !(activeHIPTailEnd >= 0 && (activeHIPTailEnd - hipTb) < 1)) = hipTb;
603 auto newSatStart = satStart;
604 auto newSatEnd = satEnd;
605 const auto inheritSat = shouldCloseTail && satStart < 0 && activeHIPTailSatStart > -1 && (activeHIPTailSatEnd - activeHIPTailEnd) >= 0;
606 newSatStart(inheritSat) = activeHIPTailSatStart;
607 newSatEnd(inheritSat) = activeHIPTailSatEnd;
608 const auto oldLosesSat = shouldCloseTail && activeHIPTailSatStart > -1 && (activeHIPTailSatStart - activeHIPTailEnd) >= 0;
609 activeHIPTailSatStart(oldLosesSat) = -1;
610 activeHIPTailSatEnd(oldLosesSat) = -1;
614 if (hipFilterOn && shouldCloseTail.isNotEmpty()) {
615 for (int16_t p = 0;
p < PadsPerCacheline;
p++) {
616 const int16_t pad = iVecPad * PadsPerCacheline +
p;
617 if (shouldCloseTail[p] && pad < nPads) {
620 for (int16_t
tt = activeHIPTailStart[p];
tt < activeHIPTailEnd[
p];
tt++) {
622 const auto pos = basePos.delta({
p,
tt});
623 const auto q = chargeMap[
pos].unpack();
625 tailQMax = CAMath::Max(tailQMax, q);
629 if (activeHIPTailEnd[p] > activeHIPTailStart[p]) {
630 const auto tailIdx = CAMath::AtomicAdd<uint32_t>(&nHIPTails[
row], 1) + 1;
632 hipTails[tailIdx] = {
635 .pad = uint16_t(pad),
636 .tailStart = uint16_t(activeHIPTailStart[p]),
637 .tailEnd = uint16_t(activeHIPTailEnd[p]),
638 .satStart = int16_t(activeHIPTailSatStart[p]),
639 .satEnd = int16_t(activeHIPTailSatEnd[p]),
650 activeHIPTailStart(hipTb > -1) = hipTb;
651 activeHIPTailEnd(hipTb > -1) = -1;
652 activeHIPTailSatStart(hipTb > -1) = newSatStart;
653 activeHIPTailSatEnd(hipTb > -1) = newSatEnd;
654 tailFilterCharge(hipTb > -1) = MaxADC;
656 aboveThresholdStartV[iVecPad] = aboveThresholdStart;
657 activeHIPTailStartV[iVecPad] = activeHIPTailStart;
658 activeHIPTailEndV[iVecPad] = activeHIPTailEnd;
659 activeHIPTailSatStartV[iVecPad] = activeHIPTailSatStart;
660 activeHIPTailSatEndV[iVecPad] = activeHIPTailSatEnd;
661 tailFilterChargeV[iVecPad] = tailFilterCharge;
667 for (int16_t iVecPad = 0; iVecPad < nVecPads; iVecPad++) {
669 auto activeHIPTailStart = activeHIPTailStartV[iVecPad];
670 auto activeHIPTailEnd = activeHIPTailEndV[iVecPad];
671 const auto activeHIPTailSatStart = activeHIPTailSatStartV[iVecPad];
672 const auto activeHIPTailSatEnd = activeHIPTailSatEndV[iVecPad];
674 const auto shouldCloseTail = activeHIPTailStart > -1;
675 activeHIPTailEnd(shouldCloseTail && activeHIPTailEnd < 0) = frag.
length;
677 if (hipFilterOn && shouldCloseTail.isNotEmpty()) {
678 for (int16_t p = 0;
p < PadsPerCacheline;
p++) {
679 const int16_t pad = iVecPad * PadsPerCacheline +
p;
680 if (shouldCloseTail[p] && pad < nPads) {
683 for (int16_t
tt = activeHIPTailStart[p];
tt < activeHIPTailEnd[
p];
tt++) {
685 const auto pos = basePos.delta({
p,
tt});
686 const auto q = chargeMap[
pos].unpack();
688 tailQMax = CAMath::Max(tailQMax, q);
692 if (activeHIPTailEnd[p] > activeHIPTailStart[p]) {
693 const auto tailIdx = CAMath::AtomicAdd<uint32_t>(&nHIPTails[
row], 1) + 1;
695 hipTails[tailIdx] = {
698 .pad = uint16_t(pad),
699 .tailStart = uint16_t(activeHIPTailStart[p]),
700 .tailEnd = uint16_t(activeHIPTailEnd[p]),
701 .satStart = int16_t(activeHIPTailSatStart[p]),
702 .satEnd = int16_t(activeHIPTailSatEnd[p]),
714 for (int32_t iVecPad = 0; iVecPad < nVecPads; iVecPad++) {
716 const UShort8 totalCharges = totalChargesV[iVecPad];
717 const UShort8 maxConsecCharges = maxConsecChargesV[iVecPad];
718 const Charge8 maxCharge = maxChargeV[iVecPad];
722 for (
tpccf::Pad localpad = 0; localpad < PadsPerCacheline; localpad++) {
723 updatePadBaseline(basePos.gpad + localpad, clusterer, totalCharges[localpad], maxConsecCharges[localpad], maxCharge[localpad]);
731 const CfFragment& frag = clusterer.mPmemory->frag;
732 const int32_t totalChargesBaseline = clusterer.Param().rec.tpc.maxTimeBinAboveThresholdIn1000Bin * frag.lengthWithoutOverlap() / 1000;
733 const int32_t consecChargesBaseline = clusterer.Param().rec.tpc.maxConsecTimeBinAboveThreshold;
734 const uint16_t saturationThreshold = clusterer.Param().rec.tpc.noisyPadSaturationThreshold;
735 const bool isNoisy = (!saturationThreshold || maxCharge < saturationThreshold) && ((totalChargesBaseline > 0 && totalCharges >= totalChargesBaseline) || (consecChargesBaseline > 0 && consecCharges >= consecChargesBaseline));
738 clusterer.mPpadIsNoisy[pad] =
true;
747 if (iBlock >= (int32_t)GPUTPCGeometry::NROWS) {
750 const uint32_t
row = iBlock;
752 const uint32_t nTails = CAMath::Min(clusterer.mPnHIPTails[
row], (uint32_t)MaxHIPTailsPerRow - 1);
757#ifdef GPUCA_DETERMINISTIC_MODE
760 GPUCommonAlgorithm::sortInBlock(tails + 1, tails + nTails + 1, [](
auto&&
t1,
auto&& t2) {
761 if (
t1.pad != t2.pad) {
762 return t1.pad < t2.pad;
763 }
else if (
t1.tailStart != t2.tailStart) {
764 return t1.tailStart < t2.tailStart;
765 }
else if (
t1.tailEnd != t2.tailEnd) {
766 return t1.tailEnd < t2.tailEnd;
767 }
else if (
t1.satStart != t2.satStart) {
768 return t1.satStart < t2.satStart;
769 }
else if (
t1.satEnd != t2.satEnd) {
770 return t1.satEnd < t2.satEnd;
771 }
else if (
t1.qTot != t2.qTot) {
772 return t1.qTot < t2.qTot;
774 return t1.qMax < t2.qMax;
783 for (uint32_t iTail = iThread + 1; iTail <= nTails; iTail += nThreads) {
784 auto* tail = &tails[iTail];
788 uint16_t overlapWindowStart = tail->
tailStart >= 5 ? tail->tailStart - 5 : 0;
789 uint16_t overlapWindowEnd = tail->tailStart + 5;
791 for (uint32_t jTail = iTail + 1; jTail <= nTails; jTail++) {
792 auto* tailNext = &tails[jTail];
793 if (tailNext->iPrev > 0) {
798 const bool overlapTime = tailNext->tailStart >= overlapWindowStart && tailNext->tailStart < overlapWindowEnd;
800 if (overlapPad && overlapTime) {
801 if (CAMath::AtomicCAS(&tailNext->iPrev, 0u, iTail)) {
813GPUd()
void GPUTPCCFHIPClusterizer::Thread<0>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer, uint8_t onlyMC)
815 if (iBlock >= (int32_t)GPUTPCGeometry::NROWS) {
819 const uint32_t
row = iBlock;
820 uint32_t nTails = clusterer.mPnHIPTails[
row];
821 nTails = CAMath::Min(nTails, (uint32_t)MaxHIPTailsPerRow - 1);
823 const auto* tails = GetHIPTails(clusterer,
row);
824 const auto& frag = clusterer.mPmemory->frag;
826 auto* clusterPosInRow = clusterer.mPhipClusterPosInRow
827 ? clusterer.mPhipClusterPosInRow +
row * MaxHIPTailsPerRow
830 for (uint32_t iTail = iThread + 1; iTail <= nTails; iTail += nThreads) {
832 const auto* tail = &tails[iTail];
833 if (tail->iPrev != 0) {
843 float satTimeSum = 0;
844 uint32_t nSatTails = 0;
845 uint32_t tailStart = (uint32_t)-1;
846 uint32_t tailEnd = 0;
849 for (; tail != tails; tail = &tails[tail->iNext]) {
850 const float tailWeight = tail->qTot;
851 const float tailPad = tail->pad;
852 qMax = CAMath::Max(qMax, tail->qMax);
854 padSum += tailWeight * tailPad;
855 padSqSum += tailWeight * tailPad * tailPad;
856 if (tail->satStart >= 0 && tail->satEnd >= 0) {
857 satTimeSum += 0.5f * (tail->satStart + tail->satEnd);
860 tailStart = CAMath::Min<uint32_t>(tailStart, tail->tailStart);
861 tailEnd = CAMath::Max<uint32_t>(tailEnd, tail->tailEnd);
863 CPU_ONLY(labelAcc.collectTail(
row, tail->pad, tail->tailStart, tail->tailEnd));
866 const float weightSum = CAMath::Max(qTot, 1.f);
867 const float padMean = padSum / weightSum;
868 const float padSigma = CAMath::Sqrt(CAMath::Max(0.f, padSqSum / weightSum - padMean * padMean));
872 cn.setSaturatedQtot(qTot);
873 cn.setSaturatedTailLength(tailEnd - tailStart);
875 cn.setSigmaPad(padSigma);
877 if (cn.
qMax >= 1023) {
882 const float clusterTime = frag.
start + satTimeSum / nSatTails - clusterer.Param().rec.tpc.clustersShiftTimebinsClusterizer;
883 assert(!CAMath::IsNaN(clusterTime));
884 cn.setTimeFlags(clusterTime, 0);
892 index = CAMath::AtomicAdd(&clusterer.mPclusterInRow[
row], 1u);
893 if (
index < clusterer.mNMaxClusterPerRow) {
894 clusterer.mPclusterByRow[clusterer.mNMaxClusterPerRow *
row +
index] = cn;
896 if (clusterPosInRow) {
897 clusterPosInRow[iTail] =
index;
900 index = clusterPosInRow[iTail];
Class of a TPC cluster in TPC-native coordinates (row, time)
#define GPUCA_THREAD_INFO_PROVIDE
#define GPUCA_GET_THREAD_COUNT(...)
#define DPRINTB_IF(test,...)
GPUd() void GPUTPCCFCheckPadBaseline
Provides a basic fallback implementation for Vc.
GLfloat GLfloat GLfloat alpha
GLuint GLsizei GLsizei * length
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLint GLenum GLboolean GLsizei stride
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
tpccf::TPCFragmentTime length