Project
Loading...
Searching...
No Matches
GPUTPCClusterStatistics.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 "GPULogging.h"
17#include "GPUO2DataTypes.h"
18#include <algorithm>
19#include <cstring>
20#include <map>
21#include <queue>
22
23using namespace o2::gpu;
24
25// Small helper to compute Huffman probabilities
26namespace o2::gpu
27{
28namespace // anonymous
29{
30typedef std::vector<bool> HuffCode;
31typedef std::map<uint32_t, HuffCode> HuffCodeMap;
32
33class INode
34{
35 public:
36 const double f;
37
38 virtual ~INode() = default;
39
40 protected:
41 INode(double v) : f(v) {}
42};
43
44class InternalNode : public INode
45{
46 public:
47 INode* const left;
48 INode* const right;
49
50 InternalNode(INode* c0, INode* c1) : INode(c0->f + c1->f), left(c0), right(c1) {}
51 ~InternalNode() override
52 {
53 delete left;
54 delete right;
55 }
56};
57
58class LeafNode : public INode
59{
60 public:
61 const uint32_t c;
62
63 LeafNode(double v, uint32_t w) : INode(v), c(w) {}
64};
65
66struct NodeCmp {
67 bool operator()(const INode* lhs, const INode* rhs) const { return lhs->f > rhs->f; }
68};
69
70INode* BuildTree(const double* frequencies, uint32_t UniqueSymbols)
71{
72 std::priority_queue<INode*, std::vector<INode*>, NodeCmp> trees;
73
74 for (uint32_t i = 0; i < UniqueSymbols; i++) {
75 if (frequencies[i] != 0) {
76 trees.push(new LeafNode(frequencies[i], i));
77 }
78 }
79 while (trees.size() > 1) {
80 INode* childR = trees.top();
81 trees.pop();
82
83 INode* childL = trees.top();
84 trees.pop();
85
86 INode* parent = new InternalNode(childR, childL);
87 trees.push(parent);
88 }
89 return trees.top();
90}
91
92void GenerateCodes(const INode* node, const HuffCode& prefix, HuffCodeMap& outCodes)
93{
94 if (const LeafNode* lf = dynamic_cast<const LeafNode*>(node)) {
95 outCodes[lf->c] = prefix;
96 } else if (const InternalNode* in = dynamic_cast<const InternalNode*>(node)) {
97 HuffCode leftPrefix = prefix;
98 leftPrefix.push_back(false);
99 GenerateCodes(in->left, leftPrefix, outCodes);
100
101 HuffCode rightPrefix = prefix;
102 rightPrefix.push_back(true);
103 GenerateCodes(in->right, rightPrefix, outCodes);
104 }
105}
106} // anonymous namespace
107} // namespace o2::gpu
108
110{
111 uint32_t decodingErrors = 0;
112 o2::tpc::ClusterNativeAccess clustersNativeDecoded;
113 std::vector<o2::tpc::ClusterNative> clusterBuffer;
114 GPUInfo("Compression statistics, decoding: %d attached (%d tracks), %d unattached", clustersCompressed->nAttachedClusters, clustersCompressed->nTracks, clustersCompressed->nUnattachedClusters);
115 auto allocator = [&clusterBuffer](size_t size) {clusterBuffer.resize(size); return clusterBuffer.data(); };
116 mDecoder.decompress(clustersCompressed, clustersNativeDecoded, allocator, param, true);
117 std::vector<o2::tpc::ClusterNative> tmpClusters;
118 if (param.rec.tpc.rejectionStrategy == GPUSettings::RejectionNone) { // verification does not make sense if we reject clusters during compression
119 for (uint32_t i = 0; i < NSECTORS; i++) {
120 for (uint32_t j = 0; j < GPUCA_ROW_COUNT; j++) {
121 if (clustersNative->nClusters[i][j] != clustersNativeDecoded.nClusters[i][j]) {
122 GPUError("Number of clusters mismatch sector %u row %u: expected %d v.s. decoded %d", i, j, clustersNative->nClusters[i][j], clustersNativeDecoded.nClusters[i][j]);
123 decodingErrors++;
124 continue;
125 }
126 tmpClusters.resize(clustersNative->nClusters[i][j]);
127 for (uint32_t k = 0; k < clustersNative->nClusters[i][j]; k++) {
128 tmpClusters[k] = clustersNative->clusters[i][j][k];
129 if (param.rec.tpc.compressionTypeMask & GPUSettings::CompressionTruncate) {
130 GPUTPCCompression::truncateSignificantBitsChargeMax(tmpClusters[k].qMax, param);
131 GPUTPCCompression::truncateSignificantBitsCharge(tmpClusters[k].qTot, param);
132 GPUTPCCompression::truncateSignificantBitsWidth(tmpClusters[k].sigmaPadPacked, param);
133 GPUTPCCompression::truncateSignificantBitsWidth(tmpClusters[k].sigmaTimePacked, param);
134 }
135 }
136 std::sort(tmpClusters.begin(), tmpClusters.end());
137 for (uint32_t k = 0; k < clustersNative->nClusters[i][j]; k++) {
138 const o2::tpc::ClusterNative& c1 = tmpClusters[k];
139 const o2::tpc::ClusterNative& c2 = clustersNativeDecoded.clusters[i][j][k];
140 if (c1.timeFlagsPacked != c2.timeFlagsPacked || c1.padPacked != c2.padPacked || c1.sigmaTimePacked != c2.sigmaTimePacked || c1.sigmaPadPacked != c2.sigmaPadPacked || c1.qMax != c2.qMax || c1.qTot != c2.qTot) {
141 if (decodingErrors++ < 100) {
142 GPUWarning("Cluster mismatch: sector %2u row %3u hit %5u: %6d %3d %4d %3d %3d %4d %4d", i, j, k, (int32_t)c1.getTimePacked(), (int32_t)c1.getFlags(), (int32_t)c1.padPacked, (int32_t)c1.sigmaTimePacked, (int32_t)c1.sigmaPadPacked, (int32_t)c1.qMax, (int32_t)c1.qTot);
143 GPUWarning("%45s %6d %3d %4d %3d %3d %4d %4d", "", (int32_t)c2.getTimePacked(), (int32_t)c2.getFlags(), (int32_t)c2.padPacked, (int32_t)c2.sigmaTimePacked, (int32_t)c2.sigmaPadPacked, (int32_t)c2.qMax, (int32_t)c2.qTot);
144 }
145 }
146 }
147 }
148 }
149 if (decodingErrors) {
150 mDecodingError = true;
151 GPUWarning("Errors during cluster decoding %u\n", decodingErrors);
152 } else {
153 GPUInfo("Cluster decoding verification: PASSED");
154 }
155 }
156
157 FillStatistic(mPqTotA, clustersCompressed->qTotA, clustersCompressed->nAttachedClusters);
158 FillStatistic(mPqMaxA, clustersCompressed->qMaxA, clustersCompressed->nAttachedClusters);
159 FillStatistic(mPflagsA, clustersCompressed->flagsA, clustersCompressed->nAttachedClusters);
160 FillStatistic(mProwDiffA, clustersCompressed->rowDiffA, clustersCompressed->nAttachedClustersReduced);
161 FillStatistic(mPsectorLegDiffA, clustersCompressed->sliceLegDiffA, clustersCompressed->nAttachedClustersReduced);
162 FillStatistic(mPpadResA, clustersCompressed->padResA, clustersCompressed->nAttachedClustersReduced);
163 FillStatistic(mPtimeResA, clustersCompressed->timeResA, clustersCompressed->nAttachedClustersReduced);
164 FillStatistic(mPsigmaPadA, clustersCompressed->sigmaPadA, clustersCompressed->nAttachedClusters);
165 FillStatistic(mPsigmaTimeA, clustersCompressed->sigmaTimeA, clustersCompressed->nAttachedClusters);
166 FillStatistic(mPqPtA, clustersCompressed->qPtA, clustersCompressed->nTracks);
167 FillStatistic(mProwA, clustersCompressed->rowA, clustersCompressed->nTracks);
168 FillStatistic(mPsectorA, clustersCompressed->sliceA, clustersCompressed->nTracks);
169 FillStatistic(mPtimeA, clustersCompressed->timeA, clustersCompressed->nTracks);
170 FillStatistic(mPpadA, clustersCompressed->padA, clustersCompressed->nTracks);
171 FillStatistic(mPqTotU, clustersCompressed->qTotU, clustersCompressed->nUnattachedClusters);
172 FillStatistic(mPqMaxU, clustersCompressed->qMaxU, clustersCompressed->nUnattachedClusters);
173 FillStatistic(mPflagsU, clustersCompressed->flagsU, clustersCompressed->nUnattachedClusters);
174 FillStatistic(mPpadDiffU, clustersCompressed->padDiffU, clustersCompressed->nUnattachedClusters);
175 FillStatistic(mPtimeDiffU, clustersCompressed->timeDiffU, clustersCompressed->nUnattachedClusters);
176 FillStatistic(mPsigmaPadU, clustersCompressed->sigmaPadU, clustersCompressed->nUnattachedClusters);
177 FillStatistic(mPsigmaTimeU, clustersCompressed->sigmaTimeU, clustersCompressed->nUnattachedClusters);
178 FillStatistic<uint16_t, 1>(mPnTrackClusters, clustersCompressed->nTrackClusters, clustersCompressed->nTracks);
179 FillStatistic<uint32_t, 1>(mPnSectorRowClusters, clustersCompressed->nSliceRowClusters, clustersCompressed->nSliceRows);
180 FillStatisticCombined(mPsigmaA, clustersCompressed->sigmaPadA, clustersCompressed->sigmaTimeA, clustersCompressed->nAttachedClusters, P_MAX_SIGMA);
181 FillStatisticCombined(mPsigmaU, clustersCompressed->sigmaPadU, clustersCompressed->sigmaTimeU, clustersCompressed->nUnattachedClusters, P_MAX_SIGMA);
182 FillStatisticCombined(mPQA, clustersCompressed->qMaxA, clustersCompressed->qTotA, clustersCompressed->nAttachedClusters, P_MAX_QMAX);
183 FillStatisticCombined(mPQU, clustersCompressed->qMaxU, clustersCompressed->qTotU, clustersCompressed->nUnattachedClusters, P_MAX_QMAX);
184 FillStatisticCombined(mProwSectorA, clustersCompressed->rowDiffA, clustersCompressed->sliceLegDiffA, clustersCompressed->nAttachedClustersReduced, GPUCA_ROW_COUNT);
185 mNTotalClusters += clustersCompressed->nAttachedClusters + clustersCompressed->nUnattachedClusters;
186}
187
189{
190 if (mDecodingError) {
191 GPUError("-----------------------------------------\nERROR - INCORRECT CLUSTER DECODING!\n-----------------------------------------");
192 }
193 if (mNTotalClusters == 0) {
194 return;
195 }
196
197 GPUInfo("\nRunning cluster compression entropy statistics");
198 double eQ = Analyze(mPqTotA, "qTot Attached", false);
199 eQ += Analyze(mPqMaxA, "qMax Attached", false);
200 Analyze(mPflagsA, "flags Attached");
201 double eRowSector = Analyze(mProwDiffA, "rowDiff Attached", false);
202 eRowSector += Analyze(mPsectorLegDiffA, "sectorDiff Attached", false);
203 Analyze(mPpadResA, "padRes Attached");
204 Analyze(mPtimeResA, "timeRes Attached");
205 double eSigma = Analyze(mPsigmaPadA, "sigmaPad Attached", false);
206 eSigma += Analyze(mPsigmaTimeA, "sigmaTime Attached", false);
207 Analyze(mPqPtA, "qPt Attached");
208 Analyze(mProwA, "row Attached");
209 Analyze(mPsectorA, "sector Attached");
210 Analyze(mPtimeA, "time Attached");
211 Analyze(mPpadA, "pad Attached");
212 eQ += Analyze(mPqTotU, "qTot Unattached", false);
213 eQ += Analyze(mPqMaxU, "qMax Unattached", false);
214 Analyze(mPflagsU, "flags Unattached");
215 Analyze(mPpadDiffU, "padDiff Unattached");
216 Analyze(mPtimeDiffU, "timeDiff Unattached");
217 eSigma += Analyze(mPsigmaPadU, "sigmaPad Unattached", false);
218 eSigma += Analyze(mPsigmaTimeU, "sigmaTime Unattached", false);
219 Analyze(mPnTrackClusters, "nClusters in Track");
220 Analyze(mPnSectorRowClusters, "nClusters in Row");
221 double eSigmaCombined = Analyze(mPsigmaA, "combined sigma Attached");
222 eSigmaCombined += Analyze(mPsigmaU, "combined sigma Unattached");
223 double eQCombined = Analyze(mPQA, "combined Q Attached");
224 eQCombined += Analyze(mPQU, "combined Q Unattached");
225 double eRowSectorCombined = Analyze(mProwSectorA, "combined row/sector Attached");
226
227 GPUInfo("Combined Row/Sector: %6.4f --> %6.4f (%6.4f%%)", eRowSector, eRowSectorCombined, eRowSector > 1e-1 ? (100. * (eRowSector - eRowSectorCombined) / eRowSector) : 0.f);
228 GPUInfo("Combined Sigma: %6.4f --> %6.4f (%6.4f%%)", eSigma, eSigmaCombined, eSigma > 1e-3 ? (100. * (eSigma - eSigmaCombined) / eSigma) : 0.f);
229 GPUInfo("Combined Q: %6.4f --> %6.4f (%6.4f%%)", eQ, eQCombined, eQ > 1e-3 ? (100. * (eQ - eQCombined) / eQ) : 0.f);
230
231 printf("\nCombined Entropy: %7.4f (Size %'13.0f, %'zu clusters)\nCombined Huffman: %7.4f (Size %'13.0f, %f%%)\n\n", mEntropy / mNTotalClusters, mEntropy, mNTotalClusters, mHuffman / mNTotalClusters, mHuffman, 100. * (mHuffman - mEntropy) / mHuffman);
232}
233
234float GPUTPCClusterStatistics::Analyze(std::vector<int32_t>& p, const char* name, bool count)
235{
236 double entropy = 0.;
237 double huffmanSize = 0;
238
239 std::vector<double> prob(p.size());
240 double log2 = log(2.);
241 size_t total = 0;
242 for (uint32_t i = 0; i < p.size(); i++) {
243 total += p[i];
244 }
245 if (total) {
246 for (uint32_t i = 0; i < prob.size(); i++) {
247 if (p[i]) {
248 prob[i] = (double)p[i] / total;
249 double I = -log(prob[i]) / log2;
250 double H = I * prob[i];
251
252 entropy += H;
253 }
254 }
255
256 INode* root = BuildTree(prob.data(), prob.size());
257
258 HuffCodeMap codes;
259 GenerateCodes(root, HuffCode(), codes);
260 delete root;
261
262 for (HuffCodeMap::const_iterator it = codes.begin(); it != codes.end(); it++) {
263 huffmanSize += it->second.size() * prob[it->first];
264 }
265
266 if (count) {
267 mEntropy += entropy * total;
268 mHuffman += huffmanSize * total;
269 }
270 }
271 GPUInfo("Size: %30s: Entropy %7.4f Huffman %7.4f (Count) %9ld", name, entropy, huffmanSize, (int64_t)total);
272 return entropy;
273}
274
275template <class T, int32_t I>
276void GPUTPCClusterStatistics::FillStatistic(std::vector<int32_t>& p, const T* ptr, size_t n)
277{
278 for (size_t i = 0; i < n; i++) {
279 uint32_t val = ptr[i];
280 if (val >= p.size()) {
281 if (I) {
282 p.resize(val + 1);
283 } else {
284 GPUError("Invalid Value: %d >= %d", val, (int32_t)p.size());
285 continue;
286 }
287 }
288 p[val]++;
289 }
290}
291
292template <class T, class S, int32_t I>
293void GPUTPCClusterStatistics::FillStatisticCombined(std::vector<int32_t>& p, const T* ptr1, const S* ptr2, size_t n, int32_t max1)
294{
295 for (size_t i = 0; i < n; i++) {
296 uint32_t val = ptr1[i] + ptr2[i] * max1;
297 if (val >= p.size()) {
298 if (I) {
299 p.resize(val + 1);
300 } else {
301 GPUError("Invalid Value: %d >= %d", val, (int32_t)p.size());
302 continue;
303 }
304 }
305 p[val]++;
306 }
307}
int32_t i
bool const GPUTPCGMMerger::trackCluster * c1
bool const GPUTPCGMMerger::trackCluster const clcomparestruct * c2
#define GPUCA_ROW_COUNT
uint32_t j
Definition RawData.h:0
TBranch * ptr
float Analyze(std::vector< int32_t > &p, const char *name, bool count=true)
void FillStatisticCombined(std::vector< int32_t > &p, const T *ptr1, const S *ptr2, size_t n, int32_t max1)
void FillStatistic(std::vector< int32_t > &p, const T *ptr, size_t n)
void RunStatistics(const o2::tpc::ClusterNativeAccess *clustersNative, const o2::tpc::CompressedClusters *clustersCompressed, const GPUParam &param)
static int32_t decompress(const o2::tpc::CompressedClustersFlat *clustersCompressed, o2::tpc::ClusterNativeAccess &clustersNative, std::function< o2::tpc::ClusterNative *(size_t)> allocator, const GPUParam &param, bool deterministicRec)
GLdouble n
Definition glcorearb.h:1982
GLint GLsizei count
Definition glcorearb.h:399
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLuint const GLchar * name
Definition glcorearb.h:781
GLdouble GLdouble right
Definition glcorearb.h:4077
GLdouble f
Definition glcorearb.h:310
GLuint GLfloat * val
Definition glcorearb.h:1582
GLenum GLfloat param
Definition glcorearb.h:271
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
D const SVectorGPU< T, D > & rhs
Definition SMatrixGPU.h:191
void GenerateCodes(const INode *node, const HuffCode &prefix, HuffCodeMap &outCodes)
std::vector< bool > HuffCode
INode * BuildTree(const double *frequencies, uint32_t UniqueSymbols)
std::map< uint32_t, HuffCode > HuffCodeMap
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]