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
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.
Filled by IIOVDbSvc::getKeyInfo.
Definition IIOVDbSvc.h:44
Histograms for COOL folders.
TFile * file