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