ATLAS Offline Software
GenericMonitoringTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include <algorithm>
6 
7 #include <TH1.h>
8 #include <TH2.h>
9 #include <TProfile.h>
10 #include <TProfile2D.h>
11 
15 
18 
19 using namespace Monitored;
20 
22 
24  ATH_CHECK(m_histSvc.retrieve());
25  return StatusCode::SUCCESS;
26 }
27 
29  if ( not m_explicitBooking ) {
30  ATH_MSG_DEBUG("Proceeding to histogram booking");
31  return book();
32  }
33  return StatusCode::SUCCESS;
34 }
35 
37  m_alwaysCreateFillers.clear();
38  m_fillers.clear();
39  if (m_registerHandler) {
40  ATH_MSG_DEBUG("Deregistering incident handler");
41  SmartIF<IIncidentSvc> incSvc{service("IncidentSvc")};
42  ATH_CHECK(incSvc.isValid());
43  incSvc->removeListener(this, IncidentType::BeginEvent);
44  }
45  return StatusCode::SUCCESS;
46 }
47 
48 void GenericMonitoringTool::handle( const Incident& ) {
49  for (const auto& filler : m_alwaysCreateFillers) {
50  filler->touch();
51  }
52 }
53 
55 
56  // If no histogram path given use parent or our own name
57  if (m_histoPath.empty()) {
58  auto named = dynamic_cast<const INamedInterface*>(parent());
59  m_histoPath = named ? named->name() : name();
60  }
61 
62  // Replace dot (e.g. MyAlg.MyTool) with slash to create sub-directory
63  std::replace( m_histoPath.begin(), m_histoPath.end(), '.', '/' );
64 
65  ATH_MSG_DEBUG("Booking histograms in path: " << m_histoPath.value());
66 
67  HistogramFillerFactory factory(this, m_histoPath);
68 
69  for (const std::string& item : m_histograms) {
70  if (item.empty()) {
71  ATH_MSG_DEBUG( "Skipping empty histogram definition" );
72  continue;
73  }
74  ATH_MSG_DEBUG( "Configuring monitoring for: " << item );
76 
77  if (def.ok) {
78  std::shared_ptr<HistogramFiller> filler(factory.create(def));
79 
80  if (filler) {
81  if (def.kAlwaysCreate) {
82  if (m_registerHandler) {
83  m_alwaysCreateFillers.push_back(filler); // prepare list of fillers for handler
84  } else {
85  filler->touch(); // create now and be done with it
86  }
87  }
88  m_fillers.push_back(std::move(filler));
89  } else {
90  ATH_MSG_WARNING( "The histogram filler cannot be instantiated for: " << def.name );
91  }
92  } else {
93  ATH_MSG_ERROR( "Unparsable histogram definition: " << item );
94  return StatusCode::FAILURE;
95  }
96  ATH_MSG_DEBUG( "Monitoring for variable " << def.name << " prepared" );
97  }
98 
99  if ( m_fillers.empty() && m_failOnEmpty ) {
100  std::string hists;
101  for (const auto &h : m_histograms) hists += (h+",");
102  ATH_MSG_ERROR("No monitored variables created based on histogram definition: [" << hists <<
103  "] Remove this monitoring tool or check its configuration.");
104  return StatusCode::FAILURE;
105  }
106 
107  // are there some histograms that should always be made?
108  // then register to be notified on every event
109  if (! m_alwaysCreateFillers.empty() && m_registerHandler) {
110  ATH_MSG_DEBUG("Registering incident handler");
111  SmartIF<IIncidentSvc> incSvc{service("IncidentSvc")};
112  ATH_CHECK(incSvc.isValid());
113  incSvc->addListener(this, IncidentType::BeginEvent);
114  }
115 
116  return StatusCode::SUCCESS;
117 }
118 
119 namespace Monitored {
120  std::ostream& operator<< ( std::ostream& os, const std::reference_wrapper<Monitored::IMonitoredVariable>& rmv ) {
121  std::string s = rmv.get().name();
122  return os << s;
123  }
124 }
125 
126 namespace {
127  void invokeFillersDebug(MsgStream& log,
129  const std::shared_ptr<Monitored::HistogramFiller>& filler,
130  const std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>>& monitoredVariables) {
131  bool reasonFound = false;
132  if (ATH_UNLIKELY(!filler->histogramWeightName().empty() && !vars.weight)) {
133  reasonFound = true;
134  log << MSG::DEBUG << "Filler weight not found in monitoredVariables:"
135  << "\n Filler weight : " << filler->histogramWeightName()
136  << "\n Asked to fill from mon. tl_vars: " << monitoredVariables << endmsg;
137  }
138  if (ATH_UNLIKELY(!filler->histogramCutMaskName().empty() && !vars.cut)) {
139  reasonFound = true;
140  log << MSG::DEBUG << "Filler cut mask not found in monitoredVariables:"
141  << "\n Filler cut mask : " << filler->histogramCutMaskName()
142  << "\n Asked to fill from mon. tl_vars: " << monitoredVariables << endmsg;
143  }
144  if ( not reasonFound ) {
145  log << MSG::DEBUG << "Filler has different variables than monitoredVariables:"
146  << "\n Filler variables : " << filler->histogramVariablesNames()
147  << "\n Asked to fill from mon. tl_vars: " << monitoredVariables
148  << "\n Selected monitored variables: " << vars.names() << endmsg;
149  }
150  }
151 
157  std::string fillerKey(const std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>>& v) {
158  std::string r;
159  for (const auto& m : v) r.append(m.get().name());
160  return r;
161  }
162 }
163 
164 void GenericMonitoringTool::invokeFillers(const std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>>& monitoredVariables) const {
165  // This is the list of fillers to consider in the invocation.
166  // If we are using the cache then this may be a proper subset of m_fillers; otherwise will just be m_fillers
167  const std::vector<std::shared_ptr<Monitored::HistogramFiller>>* fillerList{&m_fillers};
168  // pointer to list of matched fillers, if we need to update the cache (default doesn't create the vector)
169  std::vector<std::shared_ptr<Monitored::HistogramFiller>>* matchedFillerList{nullptr};
170  if (m_useCache) {
171  const auto match = m_fillerCacheMap.find(fillerKey(monitoredVariables));
172  if (match != m_fillerCacheMap.end()) {
173  fillerList = &match->second;
174  } else {
175  // make new cache entry
176  matchedFillerList = new std::vector<std::shared_ptr<Monitored::HistogramFiller>>;
177  }
178  }
179 
180  for ( auto filler: *fillerList ) {
181  const int fillerCardinality = filler->histogramVariablesNames().size() + (filler->histogramWeightName().empty() ? 0: 1) + (filler->histogramCutMaskName().empty() ? 0 : 1);
182 
183  if ( fillerCardinality == 1 ) { // simplest case, optimising this to be super fast
184  for ( auto& var: monitoredVariables ) {
185  if ( var.get().name().compare( filler->histogramVariablesNames()[0] ) == 0 ) {
186  {
187  auto guard{filler->getLock()};
188  filler->fill({&var.get()});
189  }
190  if (matchedFillerList) {
191  matchedFillerList->push_back(std::move(filler));
192  }
193  break;
194  }
195  }
196  } else { // a more complicated case, and cuts or weights
197  int matchesCount = 0;
199  for ( const auto& var: monitoredVariables ) {
200  bool matched = false;
201  for ( unsigned fillerVarIndex = 0; fillerVarIndex < filler->histogramVariablesNames().size(); ++fillerVarIndex ) {
202  if ( var.get().name().compare( filler->histogramVariablesNames()[fillerVarIndex] ) == 0 ) {
203  vars.set(fillerVarIndex, &var.get());
204  matched = true;
205  matchesCount++;
206  break;
207  }
208  }
209  if ( matchesCount == fillerCardinality ) break;
210  if ( not matched ) { // may be a weight or cut variable still
211  if ( var.get().name().compare( filler->histogramWeightName() ) == 0 ) {
212  vars.weight = &var.get();
213  matchesCount ++;
214  } else if ( var.get().name().compare( filler->histogramCutMaskName() ) == 0 ) {
215  vars.cut = &var.get();
216  matchesCount++;
217  }
218  }
219  if ( matchesCount == fillerCardinality ) break;
220  }
221  if ( matchesCount == fillerCardinality ) {
222  {
223  auto guard{filler->getLock()};
224  filler->fill( vars );
225  }
226  if (matchedFillerList) {
227  matchedFillerList->push_back(std::move(filler));
228  }
229  } else if ( ATH_UNLIKELY( msgLvl(MSG::DEBUG) && matchesCount != 0 ) ) { // something has matched, but not all, worth informing user
230  invokeFillersDebug(msg(), vars, filler, monitoredVariables);
231  }
232  }
233  }
234 
235  if (matchedFillerList) {
236  // We may hit this multiple times. If another thread has updated the cache in the meanwhile,
237  // nothing will be done here.
238  m_fillerCacheMap.emplace(fillerKey(monitoredVariables), std::move(*matchedFillerList));
239  }
240 }
241 
243  return Gaudi::Hive::currentContext().eventID().run_number();
244 }
245 
247  return Gaudi::Hive::currentContext().eventID().lumi_block();
248 }
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:307
beamspotman.r
def r
Definition: beamspotman.py:672
beamspotnt.var
var
Definition: bin/beamspotnt.py:1393
Monitored::HistogramFiller::histogramVariablesNames
const std::vector< std::string > & histogramVariablesNames() const
Definition: HistogramFiller.h:135
GenericMonitoringTool::stop
virtual StatusCode stop() override
Definition: GenericMonitoringTool.cxx:36
IMonitoredVariable.h
Monitored::HistogramFiller::histogramWeightName
const std::string & histogramWeightName() const
Definition: HistogramFiller.h:139
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
HistogramDef.h
Monitored::HistogramFiller::VariablesPack::cut
const Monitored::IMonitoredVariable * cut
pointer to cut mask variable, typically absent
Definition: HistogramFiller.h:113
GenericMonitoringTool::lumiBlock
virtual uint32_t lumiBlock()
Definition: GenericMonitoringTool.cxx:246
Monitored::HistogramFiller::getLock
const std::unique_lock< std::mutex > getLock() const
Definition: HistogramFiller.h:147
Monitored::operator<<
std::ostream & operator<<(std::ostream &os, const std::reference_wrapper< Monitored::IMonitoredVariable > &rmv)
Definition: GenericMonitoringTool.cxx:120
ATH_UNLIKELY
#define ATH_UNLIKELY(x)
Definition: AthUnlikelyMacros.h:17
GenericMonitoringTool::book
StatusCode book()
Book histograms.
Definition: GenericMonitoringTool.cxx:54
Monitored::HistogramDef
the internal class used to keep parsed Filler properties
Definition: HistogramDef.h:15
Monitored::HistogramFiller::VariablesPack::set
void set(unsigned index, const IMonitoredVariable *ptr)
sets monitored variable at the index (may need to resize vector of variables)
Definition: HistogramFiller.h:94
GenericMonitoringTool::~GenericMonitoringTool
virtual ~GenericMonitoringTool() override
Definition: GenericMonitoringTool.cxx:21
Monitored::HistogramDef::ok
bool ok
good declaration: parsing or copying successful
Definition: HistogramDef.h:77
GenericMonitoringTool::initialize
virtual StatusCode initialize() override
Definition: GenericMonitoringTool.cxx:23
PyPoolBrowser.item
item
Definition: PyPoolBrowser.py:129
Monitored::HistogramFiller::VariablesPack::weight
const Monitored::IMonitoredVariable * weight
pointer to weight variable, typically absent
Definition: HistogramFiller.h:112
Monitored::HistogramFiller::VariablesPack
helper class to pass variables to fillers
Definition: HistogramFiller.h:72
GenericMonitoringTool.h
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
Monitored
Generic monitoring tool for athena components.
Definition: GenericMonitoringTool.h:28
h
Monitored::HistogramFiller::histogramCutMaskName
const std::string & histogramCutMaskName() const
Definition: HistogramFiller.h:143
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Monitored::HistogramDef::name
std::vector< std::string > name
names of monitored variables
Definition: HistogramDef.h:16
Monitored::HistogramDef::parse
static const HistogramDef parse(const std::string &histogramDefinition)
Parses histogram defintion from json data.
Definition: HistogramDef.cxx:11
GenericMonitoringTool::handle
void handle(const Incident &) override
Definition: GenericMonitoringTool.cxx:48
test_pyathena.parent
parent
Definition: test_pyathena.py:15
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
MakeTH3DFromTH2Ds.hists
hists
Definition: MakeTH3DFromTH2Ds.py:72
Monitored::HistogramFiller::fill
virtual unsigned fill(const VariablesPack &) const =0
Method that actually fills the ROOT object.
Monitored::HistogramFiller::VariablesPack::names
std::vector< std::string > names() const
names of all variables stored
Definition: HistogramFiller.h:104
Monitored::HistogramFillerFactory
Factory of the histogram fillers.
Definition: HistogramFillerFactory.h:22
ReadFromCoolCompare.os
os
Definition: ReadFromCoolCompare.py:231
GenericMonitoringTool::runNumber
virtual uint32_t runNumber()
Definition: GenericMonitoringTool.cxx:242
GenericMonitoringTool::invokeFillers
void invokeFillers(const std::vector< std::reference_wrapper< Monitored::IMonitoredVariable >> &monitoredVariables) const
feed the fillers
Definition: GenericMonitoringTool.cxx:164
GenericMonitoringTool::start
virtual StatusCode start() override
Definition: GenericMonitoringTool.cxx:28
HistogramFiller.h
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
python.ElectronD3PDObject.matched
matched
Definition: ElectronD3PDObject.py:138
python.PyAthena.v
v
Definition: PyAthena.py:154
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Monitored::HistogramFiller::touch
void touch() const
Ensure histogram exists.
Definition: HistogramFiller.h:130
DEBUG
#define DEBUG
Definition: page_access.h:11
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
python.SystemOfUnits.s
float s
Definition: SystemOfUnits.py:147
Monitored::HistogramFillerFactory::create
HistogramFiller * create(const HistogramDef &def)
Creates HistogramFiller instance for given definition.
Definition: HistogramFillerFactory.cxx:25
Monitored::HistogramDef::kAlwaysCreate
bool kAlwaysCreate
always create this histogram, even if never filled
Definition: HistogramDef.h:52
HistogramFillerFactory.h
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
match
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition: hcg.cxx:356
python.SystemOfUnits.m
float m
Definition: SystemOfUnits.py:106