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