Skip to content

Commit 0ab8b76

Browse files
matthias-kleinerdavidrohr
authored andcommitted
Adding debug streamer for reconstruction
To enable the debug streamer export 'ENABLE_DEBUG_STREAMER=1' before compiling o2. Multithreading: each thread creates its own debug file. These files can be merged using hadd.
1 parent e129e12 commit 0ab8b76

7 files changed

Lines changed: 253 additions & 1 deletion

File tree

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ if (DPL_ENABLE_TRACING)
7575
add_definitions(-DDPL_ENABLE_TRACING)
7676
endif()
7777

78+
if(DEFINED ENV{ENABLE_DEBUG_STREAMER})
79+
add_definitions(-DDEBUG_STREAMER)
80+
MESSAGE(STATUS "Enable debug streamer")
81+
endif()
82+
7883
# include macros and functions that are used in the following subdirectories'
7984
# CMakeLists.txt
8085
include(O2AddExecutable)

Common/Utils/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ o2_add_library(CommonUtils
2323
src/BoostHistogramUtils.cxx
2424
src/NameConf.cxx
2525
src/IRFrameSelector.cxx
26+
src/DebugStreamer.cxx
2627
PUBLIC_LINK_LIBRARIES ROOT::Hist ROOT::Tree Boost::iostreams O2::CommonDataFormat O2::Headers
2728
FairLogger::FairLogger)
2829

@@ -45,7 +46,8 @@ o2_target_root_dictionary(CommonUtils
4546
include/CommonUtils/VerbosityConfig.h
4647
include/CommonUtils/FileFetcher.h
4748
include/CommonUtils/NameConf.h
48-
include/CommonUtils/IRFrameSelector.h)
49+
include/CommonUtils/IRFrameSelector.h
50+
include/CommonUtils/DebugStreamer.h)
4951

5052
o2_add_test(TreeStream
5153
COMPONENT_NAME CommonUtils
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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+
12+
/// \file DebugStreamer.h
13+
/// \brief Definition of class for writing debug informations
14+
/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de>
15+
16+
#ifndef ALICEO2_TPC_DEBUGSTREAMER_H_
17+
#define ALICEO2_TPC_DEBUGSTREAMER_H_
18+
19+
#include "GPUCommonDef.h"
20+
#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE)
21+
#include "CommonUtils/ConfigurableParamHelper.h"
22+
#if defined(DEBUG_STREAMER)
23+
#include "CommonUtils/TreeStreamRedirector.h"
24+
#endif
25+
#endif
26+
27+
namespace o2::utils
28+
{
29+
30+
/// struct defining the flags which can be used to check if a certain debug streamer is used
31+
enum StreamFlags {
32+
streamdEdx = 1 << 0, ///< stream corrections and cluster properties used for the dE/dx
33+
};
34+
35+
#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE)
36+
37+
inline StreamFlags operator|(StreamFlags a, StreamFlags b)
38+
{
39+
return static_cast<StreamFlags>(static_cast<int>(a) | static_cast<int>(b));
40+
}
41+
inline StreamFlags operator&(StreamFlags a, StreamFlags b) { return static_cast<StreamFlags>(static_cast<int>(a) & static_cast<int>(b)); }
42+
inline StreamFlags operator~(StreamFlags a) { return static_cast<StreamFlags>(~static_cast<int>(a)); }
43+
44+
/// struct for setting and storing the streamer level
45+
struct ParameterDebugStreamer : public o2::conf::ConfigurableParamHelper<ParameterDebugStreamer> {
46+
StreamFlags StreamLevel{}; /// flag to store what will be streamed
47+
O2ParamDef(ParameterDebugStreamer, "DebugStreamerParam");
48+
};
49+
50+
#endif
51+
52+
/// class to enable streaming debug information to root files
53+
class DebugStreamer
54+
{
55+
56+
// CPU implementation of the class
57+
#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) && defined(DEBUG_STREAMER)
58+
public:
59+
/// set the streamer i.e. create the output file and set up the streamer
60+
/// \param outFile output file name without .root suffix
61+
/// \param option RECREATE or UPDATE
62+
void setStreamer(const char* outFile, const char* option);
63+
64+
/// \return returns if the streamer is set
65+
bool isStreamerSet() const { return mTreeStreamer ? true : false; }
66+
67+
/// \return returns streamer object
68+
o2::utils::TreeStreamRedirector& getStreamer() { return *mTreeStreamer; }
69+
70+
/// \return returns streamer level i.e. what will be written to file
71+
static StreamFlags getStreamFlags() { return ParameterDebugStreamer::Instance().StreamLevel; }
72+
73+
///< return returns unique ID for each CPU thread to give each thread an own output file
74+
static size_t getCPUID();
75+
76+
/// \return returns number of trees in the streamer
77+
int getNTrees() const;
78+
79+
/// \return returns an unique branch name which is not already written in the file
80+
/// \param tree name of the tree for which to get a unique tree name
81+
std::string getUniqueTreeName(const char* tree) const;
82+
83+
/// set directly the debug level
84+
static void setStreamFlags(const StreamFlags streamFlags) { o2::conf::ConfigurableParam::setValue("DebugStreamerParam", "StreamLevel", static_cast<int>(streamFlags)); }
85+
86+
/// enable specific streamer flag
87+
static void enableStream(const StreamFlags streamFlag);
88+
89+
/// disable a specific streamer flag
90+
static void disableStream(const StreamFlags streamFlag);
91+
92+
/// check if streamer for specific flag is enabled
93+
static bool checkStream(const StreamFlags streamFlag) { return ((getStreamFlags() & streamFlag) == streamFlag); }
94+
95+
/// merge trees with the same content structure, but different naming
96+
/// \param inpFile input file containing several trees with the same content
97+
/// \param outFile contains the merged tree from the input file in one branch
98+
/// \param option setting which is used for the merging
99+
static void mergeTrees(const char* inpFile, const char* outFile, const char* option = "fast");
100+
101+
private:
102+
std::unique_ptr<o2::utils::TreeStreamRedirector> mTreeStreamer; ///< streamer which is used for the debugging
103+
#else
104+
105+
// empty implementation of the class for GPU or when the debug streamer is not build for CPU
106+
public:
107+
/// empty for GPU
108+
template <typename... Args>
109+
GPUd() void setStreamer(Args... args){};
110+
111+
/// always false for GPU
112+
GPUd() static bool checkStream(const StreamFlags) { return false; }
113+
114+
class StreamerDummy
115+
{
116+
public:
117+
GPUd() int data() const { return 0; };
118+
119+
template <typename Type>
120+
GPUd() StreamerDummy& operator<<(Type)
121+
{
122+
return *this;
123+
}
124+
};
125+
126+
GPUd() StreamerDummy getStreamer() const { return StreamerDummy{}; };
127+
128+
template <typename Type>
129+
GPUd() StreamerDummy getUniqueTreeName(Type) const
130+
{
131+
return StreamerDummy{};
132+
}
133+
134+
#endif
135+
};
136+
137+
} // namespace o2::utils
138+
139+
#endif

Common/Utils/src/CommonUtilsLinkDef.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,7 @@
3939

4040
#pragma link C++ class o2::utils::IRFrameSelector + ;
4141

42+
#pragma link C++ struct o2::utils::ParameterDebugStreamer + ;
43+
#pragma link C++ class o2::utils::DebugStreamer + ;
44+
4245
#endif

Common/Utils/src/DebugStreamer.cxx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
12+
#include "CommonUtils/DebugStreamer.h"
13+
#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE)
14+
#include <thread>
15+
#include <fmt/format.h>
16+
#include "TROOT.h"
17+
#include "TKey.h"
18+
#endif
19+
20+
O2ParamImpl(o2::utils::ParameterDebugStreamer);
21+
22+
#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) && defined(DEBUG_STREAMER)
23+
24+
void o2::utils::DebugStreamer::setStreamer(const char* outFile, const char* option)
25+
{
26+
if (!isStreamerSet()) {
27+
ROOT::EnableThreadSafety();
28+
mTreeStreamer = std::make_unique<o2::utils::TreeStreamRedirector>(fmt::format("{}_{}.root", outFile, getCPUID()).data(), option);
29+
}
30+
}
31+
32+
std::string o2::utils::DebugStreamer::getUniqueTreeName(const char* tree) const { return fmt::format("{}_{}", tree, getNTrees()); }
33+
34+
size_t o2::utils::DebugStreamer::getCPUID() { return std::hash<std::thread::id>{}(std::this_thread::get_id()); }
35+
36+
int o2::utils::DebugStreamer::getNTrees() const { return mTreeStreamer->GetFile()->GetListOfKeys()->GetEntries(); }
37+
38+
void o2::utils::DebugStreamer::mergeTrees(const char* inpFile, const char* outFile, const char* option)
39+
{
40+
TFile fInp(inpFile, "READ");
41+
TList list;
42+
for (TObject* keyAsObj : *fInp.GetListOfKeys()) {
43+
const auto key = dynamic_cast<TKey*>(keyAsObj);
44+
list.Add((TTree*)fInp.Get(key->GetName()));
45+
}
46+
47+
TFile fOut(outFile, "RECREATE");
48+
auto tree = TTree::MergeTrees(&list, option);
49+
fOut.WriteObject(tree, "tree");
50+
}
51+
52+
void o2::utils::DebugStreamer::enableStream(const StreamFlags streamFlag)
53+
{
54+
StreamFlags streamlevel = getStreamFlags();
55+
streamlevel = streamFlag | streamlevel;
56+
setStreamFlags(streamlevel);
57+
}
58+
59+
void o2::utils::DebugStreamer::disableStream(const StreamFlags streamFlag)
60+
{
61+
StreamFlags streamlevel = getStreamFlags();
62+
streamlevel = (~streamFlag) & streamlevel;
63+
setStreamFlags(streamlevel);
64+
}
65+
66+
#endif

GPU/GPUTracking/Standalone/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ include_directories(${GPUTRACKING_DIR}/TPCClusterFinder
164164
${O2_DIR}/Common/Field/include
165165
${O2_DIR}/Common/Constants/include
166166
${O2_DIR}/Common/MathUtils/include
167+
${O2_DIR}/Common/Utils/include
167168
${O2_DIR}/DataFormats/common/include
168169
${O2_DIR}/DataFormats/Detectors/Common/include
169170
${O2_DIR}/DataFormats/Detectors/ITSMFT/common/include

GPU/GPUTracking/dEdx/GPUdEdx.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "GPUCommonMath.h"
2121
#include "GPUParam.h"
2222
#include "GPUdEdxInfo.h"
23+
#include "CommonUtils/DebugStreamer.h"
2324
#if defined(GPUCA_HAVE_O2HEADERS) && !defined(GPUCA_OPENCL1)
2425
#include "DataFormatsTPC/Defs.h"
2526
#include "CalibdEdxContainer.h"
@@ -86,6 +87,7 @@ class GPUdEdx
8687
unsigned char mCount = 0;
8788
unsigned char mLastROC = 255;
8889
char mNSubThresh = 0;
90+
o2::utils::DebugStreamer mStreamer;
8991
};
9092

9193
GPUdi() void GPUdEdx::checkSubThresh(int roc)
@@ -182,6 +184,40 @@ GPUdnii() void GPUdEdx::fillCluster(float qtot, float qmax, int padRow, unsigned
182184
if (qmax < mSubThreshMinMax) {
183185
mSubThreshMinMax = qmax;
184186
}
187+
188+
using Streamer = o2::utils::DebugStreamer;
189+
if (Streamer::checkStream(o2::utils::StreamFlags::streamdEdx)) {
190+
mStreamer.setStreamer("debug_dedx", "UPDATE");
191+
int regionTmp = region;
192+
float absRelPadTmp = absRelPad;
193+
float thresholdTmp = threshold;
194+
float qMaxTopologyCorrTmp = qMaxTopologyCorr;
195+
float qTotTopologyCorrTmp = qTotTopologyCorr;
196+
float qMaxResidualCorrTmp = qMaxResidualCorr;
197+
float qTotResidualCorrTmp = qTotResidualCorr;
198+
float residualGainMapGainTmp = residualGainMapGain;
199+
float fullGainMapGainTmp = fullGainMapGain;
200+
mStreamer.getStreamer() << mStreamer.getUniqueTreeName("tree").data()
201+
<< "qTot=" << mChargeTot[mCount - 1]
202+
<< "qMax=" << mChargeMax[mCount - 1]
203+
<< "region=" << regionTmp
204+
<< "padRow=" << padRow
205+
<< "tanTheta=" << tanTheta
206+
<< "trackTgl=" << trackTgl
207+
<< "sinPhi=" << trackSnp
208+
<< "z=" << z
209+
<< "absRelPad=" << absRelPadTmp
210+
<< "relTime=" << relTime
211+
<< "threshold=" << thresholdTmp
212+
<< "qTotIn=" << qTotIn
213+
<< "qMaxTopologyCorr=" << qMaxTopologyCorrTmp
214+
<< "qTotTopologyCorr=" << qTotTopologyCorrTmp
215+
<< "qMaxResidualCorr=" << qMaxResidualCorrTmp
216+
<< "qTotResidualCorr=" << qTotResidualCorrTmp
217+
<< "residualGainMapGain=" << residualGainMapGainTmp
218+
<< "fullGainMapGain=" << fullGainMapGainTmp
219+
<< "\n";
220+
}
185221
}
186222

187223
GPUdi() void GPUdEdx::fillSubThreshold(int padRow, const GPUParam& GPUrestrict() param)

0 commit comments

Comments
 (0)