ATLAS Offline Software
Loading...
Searching...
No Matches
TrigOpMonitor.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "TrigOpMonitor.h"
6
13#include "GaudiKernel/DirSearchPath.h"
14#include "GaudiKernel/IIncidentSvc.h"
15#include "Gaudi/Interfaces/IOptionsSvc.h"
16#include "eformat/DetectorMask.h"
17#include "eformat/SourceIdentifier.h"
18
19#include <algorithm>
20#include <fstream>
21#include <list>
22
23// Helpers
24namespace {
26 std::string folder2HistName(const std::string& folder)
27 {
28 std::string s(folder);
29 if (s.front() == '/') s.erase(0, 1);
30 std::replace(s.begin(), s.end(), '/', '_');
31 return s;
32 }
33
35 StatusCode readReleaseData(const std::string& file, std::map<std::string, std::string>& result)
36 {
37 std::ifstream f;
38 f.open(file.c_str(), std::ifstream::in);
39 if (!f.is_open()) return StatusCode::FAILURE;
40
41 std::string line;
42 while (getline(f, line)) {
43 // Format: name:value
44 std::string::size_type loc = line.find(':');
45 if (loc == std::string::npos || loc == 0) continue;
46 result[line.substr(0, loc)] = line.substr(loc + 1);
47 }
48 f.close();
49 return StatusCode::SUCCESS;
50 }
51
52} // namespace
53
54TrigOpMonitor::TrigOpMonitor(const std::string& name, ISvcLocator* pSvcLocator) :
55 base_class(name, pSvcLocator),
56 m_histPath("/EXPERT/HLTFramework/" + name + "/")
57{}
58
60{
61 ATH_CHECK(m_histSvc.retrieve());
64
65 ATH_CHECK( m_incidentSvc.retrieve() );
67
68 return StatusCode::SUCCESS;
69}
70
71void TrigOpMonitor::handle( const Incident& incident ) {
72 // One time fills after fork
73 if (incident.type() == AthenaInterprocess::UpdateAfterFork::type()) {
74 if (!m_IOVDbSvc) m_IOVDbSvc = service("IOVDbSvc", /*createIf=*/false);
77 const AthenaInterprocess::UpdateAfterFork& updinc = dynamic_cast<const AthenaInterprocess::UpdateAfterFork&>(incident);
79 }
80}
81
83{
84 m_previousLB = 0;
85 if (!m_IOVDbSvc) m_IOVDbSvc = service("IOVDbSvc", /*createIf=*/false);
87
89 return StatusCode::SUCCESS;
90}
91
93{
94 /* One-time fills */
95 [[maybe_unused]] const static bool once = [&]() {
97 return true;
98 }();
99
100 /* Per-LB fills */
101 const EventContext& ctx = getContext();
102 if (m_previousLB != ctx.eventID().lumi_block()) { // New LB
103 m_previousLB = ctx.eventID().lumi_block();
104
105 // Fill IOV diff histogram
107
108 // Fill lumi histogram
109 fillLumiHist(ctx);
110 }
111
112 return StatusCode::SUCCESS;
113}
114
116{
117 m_iovChangeHist = nullptr;
118 m_currentIOVs.clear();
119 m_folderHist.clear();
120
121 m_iovChangeHist = new TH2I("CoolFolderUpdate_LB", "COOL folder updates;Lumiblock;", 1, 0, 1, 1, 0, 1);
122
123 // create histogram for magnetic field information
124 m_magFieldHist = new TH2I("MagneticFieldSettings", "Magnetic field settings", 2, 0, 2, 2, 0, 2);
125 m_magFieldHist->GetYaxis()->SetBinLabel(1, "off");
126 m_magFieldHist->GetYaxis()->SetBinLabel(2, "on");
127 m_magFieldHist->GetXaxis()->SetBinLabel(1, "Solenoid");
128 m_magFieldHist->GetXaxis()->SetBinLabel(2, "Toroid");
129
130 m_releaseHist = new TH1I("GeneralOpInfo", "General operational info;;Applications", 1, 0, 1);
131
132 m_mtConfigHist = new TH2I("MTConfig", "Multi-threading configuration", 2, 0, 2, 10, 0, 10);
133 m_mtConfigHist->SetCanExtend(TH1::kYaxis);
134 m_mtConfigHist->GetXaxis()->SetBinLabel(1, "N threads");
135 m_mtConfigHist->GetXaxis()->SetBinLabel(2, "N slots");
136
137 m_workersHist = new TH1I("MPWorkers", "Worker IDs;Worker ID;Number of workers", 10, 0, 10);
138 m_workersHist->SetCanExtend(TH1::kXaxis);
139
140 m_subdetHist = new TH2I("Subdetectors", "State of subdetectors", 1, 0, 1, 3, 0, 3);
141 m_subdetHist->SetCanExtend(TH1::kXaxis);
142 m_subdetHist->GetYaxis()->SetBinLabel(1, "# ROB");
143 m_subdetHist->GetYaxis()->SetBinLabel(2, "off");
144 m_subdetHist->GetYaxis()->SetBinLabel(3, "on");
145
146 m_lumiHist = new TProfile("Luminosity", "Luminosity;Lumiblock;Luminosity [10^{33} cm^{-2}s^{-1}]",
147 m_maxLB, 0, m_maxLB);
148
149 m_muHist = new TProfile("Pileup", "Pileup;Lumiblock;Interactions per BX", m_maxLB, 0, m_maxLB);
150
151 // Register histograms
152 TH1* hist[] = {
155 };
156 for (TH1* h : hist) {
157 if (h) ATH_CHECK(m_histSvc->regHist(m_histPath + h->GetName(), h));
158 }
159
160 return StatusCode::SUCCESS;
161}
162
164{
165 if (!m_fieldMapKey.empty()) {
167 const MagField::AtlasFieldMap* fieldMap = fieldMapHandle->fieldMap();
168 // if there is no field map, the field is off
169 m_magFieldHist->Fill("Solenoid", fieldMap && fieldMap->solenoidOn() ? "on" : "off", 1.0);
170 m_magFieldHist->Fill("Toroid", fieldMap && fieldMap->toroidOn() ? "on" : "off", 1.0);
171 }
172}
173
175{
176 // create and fill histogram for IOVDb entries
177 std::vector<std::string> keyList;
178 if (m_IOVDbSvc) keyList = m_IOVDbSvc->getKeyList();
179
180 // set up histograms
181 TH2I* IOVDbRunHist = new TH2I("IOVDbRunRange", "IOVDb Run Range", 1, 0, 1, 1, 0, 1);
182 TH2I* IOVDbTimeHist = new TH2I("IOVDbTimeRange", "IOVDb Time Range", 1, 0, 1, 1, 0, 1);
183 TProfile* IOVDbBytesReadHist = new TProfile("IOVDbBytesRead", "Folder data read", 1, 0, 1);
184 IOVDbBytesReadHist->SetYTitle("Data read [bytes]");
185 TProfile* IOVDbReadTimeHist = new TProfile("IOVDbReadTime", "Folder update time", 1, 0, 1);
186 IOVDbReadTimeHist->SetYTitle("Update time [ms]");
187
188 // fill histograms
190 for (const std::string& key : keyList) {
191 // cppcheck-suppress nullPointerRedundantCheck
192 if (m_IOVDbSvc->getKeyInfo(key, info) && info.retrieved) {
193
194 m_currentIOVs[key] = info.range;
195
196 IOVTime start(info.range.start());
197 IOVTime stop(info.range.stop());
198
199 // fill start condition (run number)
200 if (start.isRunEvent()) {
201 IOVDbRunHist->Fill(std::to_string(start.run()).c_str(), info.folderName.c_str(), 1.0);
202 }
203
204 // fill start condition (timestamp)
205 if (start.isTimestamp()) {
206 IOVDbTimeHist->Fill(std::to_string(start.timestamp()).c_str(), info.folderName.c_str(), 1.0);
207 }
208
209 // fill stop condition (run number)
210 if (stop.isRunEvent()) {
211 if (stop.run() == IOVTime::MAXRUN) {
212 IOVDbRunHist->Fill("infinity", info.folderName.c_str(), 1.0);
213 }
214 else {
215 IOVDbRunHist->Fill(std::to_string(stop.run()).c_str(), info.folderName.c_str(), 1.0);
216 }
217 }
218
219 // fill stop condition (timestamp)
220 if (stop.isTimestamp()) {
221 if (stop.timestamp() == IOVTime::MAXTIMESTAMP) {
222 IOVDbTimeHist->Fill("infinity", info.folderName.c_str(), 1.0);
223 }
224 else {
225 IOVDbTimeHist->Fill(std::to_string(stop.timestamp()).c_str(), info.folderName.c_str(), 1.0);
226 }
227 }
228
229 // fill read bytes and time read
230 IOVDbBytesReadHist->Fill(info.folderName.c_str(), info.bytesRead, 1.0);
231 IOVDbReadTimeHist->Fill(info.folderName.c_str(), info.readTime * 1000, 1.0);
232 }
233 }
234
235 // final configuration of histograms
236 IOVDbRunHist->LabelsDeflate("X");
237 IOVDbRunHist->LabelsDeflate("Y");
238 IOVDbRunHist->GetYaxis()->LabelsOption("a");
239
240 IOVDbTimeHist->LabelsDeflate("X");
241 IOVDbTimeHist->LabelsDeflate("Y");
242 IOVDbTimeHist->GetYaxis()->LabelsOption("a");
243
244 IOVDbBytesReadHist->LabelsDeflate("X");
245 IOVDbReadTimeHist->LabelsDeflate("X");
246
247 // Register histograms
248 TH1* hist[] = {IOVDbRunHist, IOVDbTimeHist, IOVDbBytesReadHist, IOVDbReadTimeHist};
249 for (TH1* h : hist) {
250 m_histSvc->regHist(m_histPath + h->GetName(), h).ignore();
251 }
252}
253
254void TrigOpMonitor::fillIOVDbChangeHist(const EventContext& ctx)
255{
256 std::vector<std::string> keys;
257 if (m_IOVDbSvc) keys = m_IOVDbSvc->getKeyList();
258
259 // Loop over all keys known to IOVDbSvc
261 for (const std::string& k : keys) {
262 // cppcheck-suppress nullPointerRedundantCheck
263 if (not m_IOVDbSvc->getKeyInfo(k, info)) continue;
264 if (not info.retrieved) continue;
265
266 const auto curIOV = m_currentIOVs.find(k);
267 if (curIOV == m_currentIOVs.end()) {
268 m_currentIOVs[k] = info.range;
269 continue;
270 }
271
272 // Print IOV changes and fill histogram
273 if (info.range != curIOV->second) {
274 ATH_MSG_INFO("IOV of " << k << " changed from " << curIOV->second << " to " << info.range
275 << " on event: " << ctx.eventID());
276
277 if (m_iovChangeHist) {
278 // Perform a locked fill and remove any empty bins to allow correct gathering
280 m_iovChangeHist->Fill(std::to_string(ctx.eventID().lumi_block()).c_str(), info.folderName.c_str(),
281 1);
282 m_iovChangeHist->LabelsDeflate("X");
283 m_iovChangeHist->LabelsDeflate("Y");
284 }
285
286 // Create detailed histograms per changed folder
287 if (m_detailedHists) {
288 auto fh = m_folderHist.find(info.folderName);
289 if (fh == m_folderHist.end()) {
290 std::string name(folder2HistName(info.folderName));
291
292 fh = m_folderHist.insert({info.folderName, FolderHist()}).first;
293 fh->second.h_time = new TH1F((name + "_ReadTime").c_str(),
294 ("Update time for " + info.folderName + ";Time [ms];Entries").c_str(),
295 100, 0, 200);
296
297 fh->second.h_bytes = new TH1F(
298 (name + "_BytesRead").c_str(),
299 ("Bytes read for " + info.folderName + ";Data [bytes];Entries").c_str(), 100, 0, 1000);
300
301 for (TH1* h : {fh->second.h_time, fh->second.h_bytes}) {
302 m_histSvc->regHist(m_histPath + h->GetName(), h).ignore();
303 }
304 }
305
306 // Need to plot the difference because IOVDbSvc reports total time and bytes for entire job
307 fh->second.h_time->Fill(info.readTime * 1000 - m_folderHist[info.folderName].total_time);
308 fh->second.total_time += info.readTime * 1000;
309
310 fh->second.h_bytes->Fill(info.bytesRead - m_folderHist[info.folderName].total_bytes);
311 fh->second.total_bytes += info.bytesRead;
312 }
313
314 m_currentIOVs[k] = info.range;
315 }
316 }
317}
318
319void TrigOpMonitor::fillLumiHist(const EventContext& ctx)
320{
321 if (!m_lumiDataKey.empty()) {
323 m_lumiHist->Fill(ctx.eventID().lumi_block(), lumiData->lbAverageLuminosity());
324 m_muHist->Fill(ctx.eventID().lumi_block(), lumiData->lbAverageInteractionsPerCrossing());
325 }
326}
327
329{
330 const char* ld_lib_path = getenv("LD_LIBRARY_PATH");
331 if (ld_lib_path == nullptr) {
332 ATH_MSG_WARNING("LD_LIBRARY_PATH is not defined. Will not fill release histogram.");
333 return;
334 }
335
336 // Find all release metadata files
337 std::list<DirSearchPath::path> file_list = DirSearchPath(ld_lib_path, ":").find_all(m_releaseData.value());
338
339 if (file_list.empty()) {
340 ATH_MSG_WARNING("Could not find release metadata file " << m_releaseData
341 << " in LD_LIBRARY_PATH");
342 m_releaseHist->Fill("Release ?", 1);
343 return;
344 }
345
346 for (const auto& f : file_list) {
347 // Read metadata file
348 std::map<std::string, std::string> result;
349 if (readReleaseData(f.string(), result).isFailure()) {
350 ATH_MSG_WARNING("Could not read release metadata from " << f);
351 m_releaseHist->Fill("Release ?", 1);
352 return;
353 }
354
355 // Check format
356 if (result.find("project name") == result.end() || result.find("release") == result.end()) {
357 ATH_MSG_WARNING("Invalid release metadata format in " << f);
358 m_releaseHist->Fill("Release ?", 1);
359 return;
360 }
361
362 m_releaseHist->Fill((result["project name"] + " " + result["release"]).c_str(), 1);
363 }
364}
365
366void TrigOpMonitor::fillProcThreadHist(const int workerID)
367{
368 m_workersHist->Fill(workerID, 1);
369
370 auto getIntProp = [this](std::string_view name, const std::string& prop) -> std::optional<int> {
371 IProperty* svc = serviceLocator()->service(name).as<IProperty>();
372 if (svc == nullptr) return std::nullopt;
373 try {
374 return std::stoi(svc->getProperty(prop).toString());
375 }
376 catch (...) {
377 return std::nullopt;
378 }
379 };
380
381 const std::optional<int> numThreads = getIntProp("AvalancheSchedulerSvc","ThreadPoolSize");
382 if (numThreads.has_value()) {
383 m_mtConfigHist->Fill("N threads", numThreads.value(), 1.0);
384 }
385 else {
386 ATH_MSG_WARNING("Could not retrieve the number of threads to fill the monitoring histogram");
387 }
388
389 const std::optional<int> numSlots = getIntProp("EventDataSvc","NSlots");
390 if (numSlots.has_value()) {
391 m_mtConfigHist->Fill("N slots", numSlots.value(), 1.0);
392 }
393 else {
394 ATH_MSG_WARNING("Could not retrieve the number of slots to fill the monitoring histogram");
395 }
396}
397
399{
400 // Retrieve the enabled ROBs/SubDets list from DataFlowConfig which is a special object
401 // used online to hold DF properties passed from TDAQ to HLT as run parameters
402 auto jobOptionsSvc = service<Gaudi::Interfaces::IOptionsSvc>("JobOptionsSvc", /*createIf=*/ false);
403 if (!jobOptionsSvc.isValid()) {
404 ATH_MSG_WARNING("Could not retrieve JobOptionsSvc, will not fill SubDetectors histogram");
405 return;
406 }
407
408 Gaudi::Property<std::vector<uint32_t>> enabledROBsProp("EnabledROBs",{});
409 std::set<uint32_t> enabledROBs;
410 if (enabledROBsProp.fromString(jobOptionsSvc->get("DataFlowConfig.DF_Enabled_ROB_IDs","[]")).isSuccess()) {
411 enabledROBs.insert(enabledROBsProp.value().begin(), enabledROBsProp.value().end());
412 ATH_MSG_DEBUG("Retrieved a list of " << enabledROBs.size()
413 << " ROBs from DataFlowConfig.DF_Enabled_ROB_IDs");
414 }
415 else {
416 ATH_MSG_ERROR("Could not parse DataFlowConfig.DF_Enabled_ROB_IDs from JobOptionsSvc");
417 }
418
419 // Retrieve detector mask from detector store
420 SmartIF<StoreGateSvc> inputMetaDataStore = service<StoreGateSvc>("InputMetaDataStore", /*createIf=*/ false);
421 if (!inputMetaDataStore.isValid()) {
422 ATH_MSG_WARNING("Could not retrieve InputMetaDataStore, will not fill SubDetectors histogram");
423 return;
424 }
425 const ByteStreamMetadataContainer* metadatacont{nullptr};
426 if (inputMetaDataStore->retrieve(metadatacont, "ByteStreamMetadata").isFailure()) {
427 ATH_MSG_WARNING("Could not retrieve ByteStreamMetadata, will not fill SubDetectors histogram");
428 return;
429 }
430
431 const ByteStreamMetadata* metadata = *(metadatacont->begin());
432 uint64_t detMaskLeast = metadata->getDetectorMask();
433 uint64_t detMaskMost = metadata->getDetectorMask2();
434
435 // Decode subdetector masks
436 std::vector<eformat::SubDetector> subDetOn;
437 std::vector<eformat::SubDetector> subDetOff;
438 std::vector<eformat::SubDetector> subDetAll;
439 eformat::helper::DetectorMask(detMaskLeast, detMaskMost).sub_detectors(subDetOn);
440 eformat::helper::DetectorMask(~detMaskLeast, ~detMaskMost).sub_detectors(subDetOff);
441 eformat::helper::DetectorMask(~std::bitset<128>()).sub_detectors(subDetAll);
442
443 // Add bins with labels for every subdetector name
444 for (const eformat::SubDetector sd : subDetAll) {
445 m_subdetHist->GetXaxis()->FindBin(eformat::helper::SubDetectorDictionary.string(sd).data());
446 }
447 m_subdetHist->LabelsDeflate("X");
448
449 // Fill histogram with enabled subdetectors
450 for (const eformat::SubDetector sd : subDetOn) {
451 m_subdetHist->Fill(eformat::helper::SubDetectorDictionary.string(sd).data(), "on", 1.0);
452 }
453
454 // Fill histogram with disabled subdetectors
455 for (const eformat::SubDetector sd : subDetOff) {
456 m_subdetHist->Fill(eformat::helper::SubDetectorDictionary.string(sd).data(), "off", 1.0);
457 }
458
459 // Fill histogram with ROB counts
460 for (const uint32_t robid : enabledROBs) {
461 const std::string sdname = eformat::helper::SourceIdentifier(robid).human_detector();
462 m_subdetHist->Fill(sdname.data(), "# ROB", 1.0);
463 }
464}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
This file contains the class definition for the ByteStreamMetadataContainer class.
This file contains the class definition for the ByteStreamMetadata class.
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
Validity Range object.
OH histogram lock header file.
Online operations monitoring.
Header file for AthHistogramAlgorithm.
static const std::string & type()
Incident type.
Definition Incidents.h:49
int workerID() const
assigned worker ID from processing unit
Definition Incidents.h:40
This class is the StoreGate data object for bytestream metadata.
This class is the StoreGate data object for bytestream metadata.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
Basic time unit for IOVSvc.
Definition IOVTime.h:33
static constexpr uint64_t MAXTIMESTAMP
Definition IOVTime.h:58
static constexpr uint32_t MAXRUN
Definition IOVTime.h:48
Map for magnetic field.
bool solenoidOn() const
status of the magnets
void fillProcThreadHist(int workerID)
TH1I * m_releaseHist
std::string m_histPath
histogram booking path
std::unordered_map< std::string, IOVRange > m_currentIOVs
current IOVs managed by IOVDbSvc
ServiceHandle< ITHistSvc > m_histSvc
ServiceHandle< IIncidentSvc > m_incidentSvc
virtual StatusCode initialize() override
void fillReleaseDataHist()
virtual StatusCode execute() override
TrigOpMonitor(const std::string &name, ISvcLocator *pSvcLocator)
Gaudi::Property< bool > m_detailedHists
TH2I * m_magFieldHist
TProfile * m_lumiHist
virtual StatusCode start() override
TProfile * m_muHist
void fillIOVDbChangeHist(const EventContext &ctx)
Gaudi::Property< unsigned short int > m_maxLB
Gaudi::Property< std::string > m_releaseData
SG::ReadCondHandleKey< AtlasFieldMapCondObj > m_fieldMapKey
virtual void handle(const Incident &incident) override
std::unordered_map< std::string, FolderHist > m_folderHist
histograms for COOL folders
SG::ReadCondHandleKey< LuminosityCondData > m_lumiDataKey
void fillLumiHist(const EventContext &ctx)
EventIDBase::number_type m_previousLB
LB of previous event.
StatusCode bookHists()
SmartIF< IIOVDbSvc > m_IOVDbSvc
TH2I * m_subdetHist
TH2I * m_iovChangeHist
TH2I * m_mtConfigHist
TH1I * m_workersHist
Scoped lock to be used for threaded histogram operations.
::StatusCode StatusCode
StatusCode definition for legacy code.
Filled by IIOVDbSvc::getKeyInfo.
Definition IIOVDbSvc.h:44
Histograms for COOL folders.
TFile * file