Project
Loading...
Searching...
No Matches
GPUTPCCFCheckPadBaseline.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14
16#include "Array2D.h"
17#include "PackedCharge.h"
18#include "clusterFinderDefs.h"
19
20#ifndef GPUCA_GPUCODE
21#ifndef GPUCA_NO_VC
22#include <Vc/Vc>
23#else
24#include <array>
25#endif
26#endif
27
28using namespace o2::gpu;
29using namespace o2::gpu::tpccf;
30
31template <>
32GPUd() void GPUTPCCFCheckPadBaseline::Thread<0>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer)
33{
34 const CfFragment& fragment = clusterer.mPmemory->fragment;
35 Array2D<PackedCharge> chargeMap(reinterpret_cast<PackedCharge*>(clusterer.mPchargeMap));
36
37 int32_t basePad = iBlock * PadsPerCacheline;
38 ChargePos basePos = padToChargePos(basePad, clusterer);
39
40 if (not basePos.valid()) {
41 return;
42 }
43
44#ifdef GPUCA_GPUCODE
45 static_assert(TPC_MAX_FRAGMENT_LEN_GPU % NumOfCachedTimebins == 0);
46
47 int32_t totalCharges = 0;
48 int32_t consecCharges = 0;
49 int32_t maxConsecCharges = 0;
50 Charge maxCharge = 0;
51
52 int16_t localPadId = iThread / NumOfCachedTimebins;
53 int16_t localTimeBin = iThread % NumOfCachedTimebins;
54 bool handlePad = localTimeBin == 0;
55
56 for (tpccf::TPCFragmentTime t = fragment.firstNonOverlapTimeBin(); t < fragment.lastNonOverlapTimeBin(); t += NumOfCachedTimebins) {
57 const ChargePos pos = basePos.delta({localPadId, int16_t(t + localTimeBin)});
58 smem.charges[localPadId][localTimeBin] = (pos.valid()) ? chargeMap[pos].unpack() : 0;
59 GPUbarrier();
60 if (handlePad) {
61 for (int32_t i = 0; i < NumOfCachedTimebins; i++) {
62 const Charge q = smem.charges[localPadId][i];
63 totalCharges += (q > 0);
64 consecCharges = (q > 0) ? consecCharges + 1 : 0;
65 maxConsecCharges = CAMath::Max(consecCharges, maxConsecCharges);
66 maxCharge = CAMath::Max<Charge>(q, maxCharge);
67 }
68 }
69 GPUbarrier();
70 }
71
72 GPUbarrier();
73
74 if (handlePad) {
75 updatePadBaseline(basePad + localPadId, clusterer, totalCharges, maxConsecCharges, maxCharge);
76 }
77
78#else // CPU CODE
79
80 constexpr size_t ElemsInTileRow = (size_t)TilingLayout<GridSize<2>>::WidthInTiles * TimebinsPerCacheline * PadsPerCacheline;
81
82#ifndef GPUCA_NO_VC
83 using UShort8 = Vc::fixed_size_simd<uint16_t, PadsPerCacheline>;
84 using Charge8 = Vc::fixed_size_simd<float, PadsPerCacheline>;
85
86 UShort8 totalCharges{Vc::Zero};
87 UShort8 consecCharges{Vc::Zero};
88 UShort8 maxConsecCharges{Vc::Zero};
89 Charge8 maxCharge{Vc::Zero};
90#else
91 std::array<uint16_t, PadsPerCacheline> totalCharges{0};
92 std::array<uint16_t, PadsPerCacheline> consecCharges{0};
93 std::array<uint16_t, PadsPerCacheline> maxConsecCharges{0};
94 std::array<Charge, PadsPerCacheline> maxCharge{0};
95#endif
96
97 tpccf::TPCFragmentTime t = fragment.firstNonOverlapTimeBin();
98
99 // Access packed charges as raw integers. We throw away the PackedCharge type here to simplify vectorization.
100 const uint16_t* packedChargeStart = reinterpret_cast<uint16_t*>(&chargeMap[basePos.delta({0, t})]);
101
102 for (; t < fragment.lastNonOverlapTimeBin(); t += TimebinsPerCacheline) {
103 for (tpccf::TPCFragmentTime localtime = 0; localtime < TimebinsPerCacheline; localtime++) {
104#ifndef GPUCA_NO_VC
105 const UShort8 packedCharges{packedChargeStart + PadsPerCacheline * localtime, Vc::Aligned};
106 const UShort8::mask_type isCharge = packedCharges != 0;
107
108 if (isCharge.isNotEmpty()) {
109 totalCharges(isCharge)++;
110 consecCharges += 1;
111 consecCharges(not isCharge) = 0;
112 maxConsecCharges = Vc::max(consecCharges, maxConsecCharges);
113
114 // Manually unpack charges to float.
115 // Duplicated from PackedCharge::unpack to generate vectorized code:
116 // Charge unpack() const { return Charge(mVal & ChargeMask) / Charge(1 << DecimalBits); }
117 // Note that PackedCharge has to cut off the highest 2 bits via ChargeMask as they are used for flags by the cluster finder
118 // and are not part of the charge value. We can skip this step because the cluster finder hasn't run yet
119 // and thus these bits are guarenteed to be zero.
120 const Charge8 unpackedCharges = Charge8(packedCharges) / Charge(1 << PackedCharge::DecimalBits);
121 maxCharge = Vc::max(maxCharge, unpackedCharges);
122 } else {
123 consecCharges = 0;
124 }
125#else // Vc not available
126 for (tpccf::Pad localpad = 0; localpad < PadsPerCacheline; localpad++) {
127 const uint16_t packedCharge = packedChargeStart[PadsPerCacheline * localtime + localpad];
128 const bool isCharge = packedCharge != 0;
129 if (isCharge) {
130 totalCharges[localpad]++;
131 consecCharges[localpad]++;
132 maxConsecCharges[localpad] = CAMath::Max(maxConsecCharges[localpad], consecCharges[localpad]);
133
134 const Charge unpackedCharge = Charge(packedCharge) / Charge(1 << PackedCharge::DecimalBits);
135 maxCharge[localpad] = CAMath::Max<Charge>(maxCharge[localpad], unpackedCharge);
136 } else {
137 consecCharges[localpad] = 0;
138 }
139 }
140#endif
141 }
142
143 packedChargeStart += ElemsInTileRow;
144 }
145
146 for (tpccf::Pad localpad = 0; localpad < PadsPerCacheline; localpad++) {
147 updatePadBaseline(basePad + localpad, clusterer, totalCharges[localpad], maxConsecCharges[localpad], maxCharge[localpad]);
148 }
149#endif
150}
151
152GPUd() ChargePos GPUTPCCFCheckPadBaseline::padToChargePos(int32_t& pad, const GPUTPCClusterFinder& clusterer)
153{
154 const GPUTPCGeometry& geo = clusterer.Param().tpcGeometry;
155
156 int32_t padOffset = 0;
157 for (Row r = 0; r < GPUCA_ROW_COUNT; r++) {
158 int32_t npads = geo.NPads(r);
159 int32_t padInRow = pad - padOffset;
160 if (0 <= padInRow && padInRow < CAMath::nextMultipleOf<PadsPerCacheline, int32_t>(npads)) {
161 int32_t cachelineOffset = padInRow % PadsPerCacheline;
162 pad -= cachelineOffset;
163 return ChargePos{r, Pad(padInRow - cachelineOffset), 0};
164 }
165 padOffset += npads;
166 }
167
168 return ChargePos{0, 0, INVALID_TIME_BIN};
169}
170
171GPUd() void GPUTPCCFCheckPadBaseline::updatePadBaseline(int32_t pad, const GPUTPCClusterFinder& clusterer, int32_t totalCharges, int32_t consecCharges, Charge maxCharge)
172{
173 const CfFragment& fragment = clusterer.mPmemory->fragment;
174 const int32_t totalChargesBaseline = clusterer.Param().rec.tpc.maxTimeBinAboveThresholdIn1000Bin * fragment.lengthWithoutOverlap() / 1000;
175 const int32_t consecChargesBaseline = clusterer.Param().rec.tpc.maxConsecTimeBinAboveThreshold;
176 const uint16_t saturationThreshold = clusterer.Param().rec.tpc.noisyPadSaturationThreshold;
177 const bool isNoisy = (!saturationThreshold || maxCharge < saturationThreshold) && ((totalChargesBaseline > 0 && totalCharges >= totalChargesBaseline) || (consecChargesBaseline > 0 && consecCharges >= consecChargesBaseline));
178
179 if (isNoisy) {
180 clusterer.mPpadIsNoisy[pad] = true;
181 }
182}
#define INVALID_TIME_BIN
Definition ChargePos.h:23
int32_t i
#define GPUbarrier()
GPUd() void GPUTPCCFCheckPadBaseline
#define GPUCA_ROW_COUNT
uint16_t pos
Definition RawData.h:3
#define TPC_MAX_FRAGMENT_LEN_GPU
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean r
Definition glcorearb.h:1233