ATLAS Offline Software
Loading...
Searching...
No Matches
WebdaqHistSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "WebdaqHistSvc.h"
6
7#include "GaudiKernel/IIncidentSvc.h"
10
11#include "webdaq/webdaq-root.hpp"
12#include "webdaq/webdaq.hpp"
13
14#include "TError.h"
15#include "TGraph.h"
16#include "TH1.h"
17#include "TH2.h"
18#include "TH3.h"
19#include "TObject.h"
20#include "TROOT.h"
21#include "TTree.h"
22#include <TBufferJSON.h>
23
24#include <boost/date_time/posix_time/posix_time.hpp>
25#include <boost/date_time/gregorian/gregorian_types.hpp>
26
27
28/**************************************************************************************/
29
30StatusCode WebdaqHistSvc::initialize ATLAS_NOT_THREAD_SAFE()
31{
32 // Protect against multiple instances of TROOT
33 if (0 == gROOT) {
34 static TROOT root("root", "ROOT I/O");
35 }
36 else {
37 ATH_MSG_VERBOSE("ROOT already initialized, debug = " << gDebug);
38 }
39
40 gErrorIgnoreLevel = kBreak; // ignore warnings see TError.h in ROOT base src
41
42 // compile regexes
43 m_excludeTypeRegex = boost::regex(m_excludeType.value());
44 m_includeTypeRegex = boost::regex(m_includeType.value());
45 m_excludeNameRegex = boost::regex(m_excludeName.value());
46 m_includeNameRegex = boost::regex(m_includeName.value());
47 m_PublicationIncludeNameRegex = boost::regex(m_PublicationIncludeName.value());
48 m_fastPublicationIncludeNameRegex = boost::regex(m_fastPublicationIncludeName.value());
49
50 // Create and set OH mutex
51 ATH_MSG_INFO("Enabling use of OH histogram mutex");
52 static std::mutex mutex;
54
55 // Application name
56 ATH_CHECK( m_jobOptionsSvc.retrieve() );
57 m_appName = m_jobOptionsSvc->get("DataFlowConfig.DF_ApplicationName");
58
59 //Retireve enviroment variables
60 const char* tdaq_partition_cstr = std::getenv("TDAQ_PARTITION");
61 if (tdaq_partition_cstr != nullptr) {
62 m_partition = std::string(tdaq_partition_cstr);
63 ATH_MSG_INFO("Partition: " << m_partition);
64 } else {
65 ATH_MSG_ERROR("TDAQ_PARTITION environment variable not set");
66 return StatusCode::FAILURE;
67 }
68 const char* tdaqWebdaqBase_cstr = std::getenv("TDAQ_WEBDAQ_BASE");
69 if (tdaqWebdaqBase_cstr != nullptr) {
70 m_tdaqWebdaqBase = std::string(tdaqWebdaqBase_cstr);
71 ATH_MSG_INFO("TDAQ_WEBDAQ_BASE value: " << m_tdaqWebdaqBase);
72 } else {
73 ATH_MSG_ERROR("TDAQ_WEBDAQ_BASE environment variable not set! Is needed for the OH publication through webdaq");
74 return StatusCode::FAILURE;
75 }
76 const char* tdaq_oh_server = std::getenv("TDAQ_OH_SERVER");
77 if (tdaq_oh_server != nullptr) {
78 m_tdaqOHServerName = std::string(tdaq_oh_server);
79 } else {
80 m_tdaqOHServerName = m_OHServerName.value();
81 }
82 ATH_MSG_INFO("TDAQ_OH_SERVER value: " << m_tdaqOHServerName);
83
84 // Incident handler
85 ServiceHandle<IIncidentSvc> incSvc("IncidentSvc", name());
86 ATH_CHECK( incSvc.retrieve() );
87 incSvc->addListener(this, AthenaInterprocess::UpdateAfterFork::type());
88
89 return StatusCode::SUCCESS;
90}
91
92/**************************************************************************************/
93
94void WebdaqHistSvc::handle(const Incident& incident)
95{
96 if (incident.type() == AthenaInterprocess::UpdateAfterFork::type()) {
97 ATH_MSG_INFO("Going to initialize the monitoring thread");
98
100
101 // OH doesn't allow multiple providers for a given server.
102 // Need to modify the path for one of the threads to avoid the issue.
104 }
105}
106
107/**************************************************************************************/
108
110{
112 ATH_MSG_DEBUG("Stopping monitoring task");
113 m_stopFlag = true;
114 // Wait for the task to finish
115 if (m_thread.joinable()) {
116 ATH_MSG_DEBUG("Going to join the monitoring thread");
117 try {
118 m_thread.join();
119 }
120 catch (const std::exception& e) {
121 ATH_MSG_ERROR("Failed to join the monitoring thread: " << e.what());
122 return StatusCode::FAILURE;
123 }
124 }
125 if (m_threadFast.joinable()) {
126 ATH_MSG_DEBUG("Going to join the fast monitoring thread");
127 try {
128 m_threadFast.join();
129 }
130 catch (const std::exception& e) {
131 ATH_MSG_ERROR("Failed to join the fast monitoring thread: " << e.what());
132 return StatusCode::FAILURE;
133 }
134 }
135 ATH_MSG_INFO("Performing final histogram publication before stop");
137 ATH_MSG_DEBUG("Clearing list of histograms");
138 m_hists.clear();
139 m_histoMapUpdated = true;
141 return StatusCode::SUCCESS;
142}
143
144/**************************************************************************************/
145
147{
148 ATH_MSG_INFO("finalize");
149 // Reset OH mutex
151
152 return StatusCode::SUCCESS;
153}
154
155/**************************************************************************************/
156
157template <typename T>
158StatusCode WebdaqHistSvc::regHist_i(std::unique_ptr<T> hist_unique, const std::string& id,
159 bool shared, THistID*& phid)
160{
161 ATH_MSG_DEBUG("Registering histogram " << id);
162
163 phid = nullptr;
164 if (not isObjectAllowed(id, hist_unique.get())) {
165 return StatusCode::FAILURE;
166 }
167
168 if (hist_unique->Class()->InheritsFrom(TH1::Class())) {
169
170 tbb::concurrent_hash_map<std::string, THistID>::accessor accessor;
171 if (m_hists.find(accessor, id)) {
172 ATH_MSG_ERROR("Histogram with name " << id << " already registered");
173 return StatusCode::FAILURE;
174 }
175 // Element not found, attempt to insert
176 if (!m_hists.insert(accessor, id)) {
177 ATH_MSG_ERROR("Failed to insert histogram with name " << id);
178 return StatusCode::FAILURE;
179 }
180 T* hist = hist_unique.release();
181 m_histoMapUpdated = true;
183 accessor->second = THistID(id, hist);
184 //finished
185 if (shared) accessor->second.mutex = std::make_unique<std::mutex>();
186 phid = &accessor->second;
187 ATH_MSG_DEBUG((shared ? "Shared histogram " : "Histogram ")
188 << hist->GetName() << " registered under " << id << " " << name());
189 } else {
190 ATH_MSG_ERROR("Cannot register " << hist_unique->ClassName()
191 << " because it does not inherit from TH1");
192 return StatusCode::FAILURE;
193 }
194 return StatusCode::SUCCESS;
195}
196
197/**************************************************************************************/
198
199template <typename T>
200LockedHandle<T> WebdaqHistSvc::regShared_i(const std::string& id, std::unique_ptr<T> hist)
201{
202 LockedHandle<T> lh(nullptr, nullptr);
203
204 tbb::concurrent_hash_map<std::string, THistID>::accessor accessor;
205 // Check if the histogram is already registered
206 if (!m_hists.find(accessor, id)) {
207 // No histogram under that id yet
208 T* phist = hist.get();
209 THistID* phid = nullptr;
210 if (regHist_i(std::move(hist), id, true, phid).isSuccess()) {
211 if (phid) lh.set(phist, phid->mutex.get());
212 }
213 }
214 else
215 {
216 // Histogram already registered under that id
217 if (accessor->second.mutex == nullptr) {
218 ATH_MSG_ERROR("regShared: previously registered histogram \"" << id
219 << "\" was not marked shared");
220 }
221 T* phist = dynamic_cast<T*>(accessor->second.obj);
222 if (phist == nullptr) {
223 ATH_MSG_ERROR("regShared: unable to dcast retrieved shared hist \""
224 << id << "\" of type " << accessor->second.obj->IsA()->GetName()
225 << " to requested type " << System::typeinfoName(typeid(T)));
226 }
227 else {
228 lh.set(phist, accessor->second.mutex.get());
229 //hist is automatically deleted at end of method
230 }
231 }
232 return lh;
233}
234
235
236/**************************************************************************************/
237
238template <typename T>
239T* WebdaqHistSvc::getHist_i(const std::string& id, const size_t& /*ind*/, bool quiet) const
240{
241 ATH_MSG_DEBUG("Getting histogram " << id);
242
243 tbb::concurrent_hash_map<std::string, THistID>::const_accessor accessor;
244 if (!m_hists.find(accessor, id) or accessor.empty()) {
245 if (!quiet) ATH_MSG_ERROR("could not locate Hist with id \"" << id << "\"");
246 return nullptr;
247 }
248
249 T* phist = dynamic_cast<T*>(accessor->second.obj);
250 if (phist == nullptr) {
251 ATH_MSG_ERROR("getHist: unable to dcast retrieved shared hist \""
252 << id << "\" of type " << accessor->second.obj->IsA()->GetName() << " to requested type "
253 << System::typeinfoName(typeid(T)));
254 return nullptr;
255 }
256 return phist;
257}
258
259/**************************************************************************************/
260
261StatusCode WebdaqHistSvc::getTHists_i(const std::string& dir, TList& tl) const
262{
263 for (auto it = m_hists.begin(); it != m_hists.end(); ++it) {
264 const std::string& id = it->first;
265 const THistID& h = it->second;
266 if (id.starts_with(dir)) { // histogram booking path starts from the dir
267 tl.Add(h.obj);
268 }
269 }
270 return StatusCode::SUCCESS;
271}
272
273/**************************************************************************************/
274
275template <typename T>
276LockedHandle<T> WebdaqHistSvc::getShared_i(const std::string& id) const
277{
278 tbb::concurrent_hash_map<std::string, THistID>::const_accessor accessor;
279 if (m_hists.find(accessor, id)) {
280 //coverity[FORWARD_NULL]
281 auto * obj = accessor->second.obj;
282 //accessor is implicitly valid
283 //coverity[FORWARD_NULL]
284 if (accessor->second.mutex == nullptr) {
285 ATH_MSG_ERROR("getShared: found Hist with id \"" << id
286 << "\", but it's not marked as shared");
287 return {};
288 }
289 T* phist = dynamic_cast<T*>(obj);
290 if (phist == nullptr) {
291 const char* gotType = obj ? obj->IsA()->GetName() : "<null>";
292 ATH_MSG_ERROR("getShared: unable to dcast retrieved shared hist \""
293 << id << "\" of type " << gotType
294 << " to requested type " << System::typeinfoName(typeid(T)));
295 return {};
296 }
297 return LockedHandle<T>(phist, accessor->second.mutex.get());
298 }
299 ATH_MSG_ERROR("getShared: cannot find histogram with id \"" << id << "\"");
300 return {};
301}
302
303/**************************************************************************************/
304
305StatusCode WebdaqHistSvc::deReg(TObject* optr)
306{
307 // Find the relevant histogram and deregister it
308 for (auto it = m_hists.begin(); it != m_hists.end(); ++it) {
309 if (it->second.obj == optr) {
310 ATH_MSG_DEBUG("Found histogram " << optr << " booked under " << it->first
311 << " and will deregister it");
312 return deReg(it->first);
313 }
314 }
315 ATH_MSG_ERROR("Histogram with pointer " << optr << " not found in the histogram map");
316 return StatusCode::FAILURE;
317}
318
319/**************************************************************************************/
320
321StatusCode WebdaqHistSvc::deReg(const std::string& id)
322{
323 tbb::concurrent_hash_map<std::string, THistID>::accessor accessor;
324 if (m_hists.find(accessor, id)) {
325 //Delete the histogram
326 accessor->second.obj->Delete();
327 m_hists.erase(accessor);
328 m_histoMapUpdated = true;
330 ATH_MSG_DEBUG("Deregistration of " << id << " done");
331 return StatusCode::SUCCESS;
332 }
333 ATH_MSG_ERROR("Deregistration failed: histogram with id \"" << id << "\" not found");
334 return StatusCode::FAILURE;
335}
336
337/**************************************************************************************/
338
339std::vector<std::string> WebdaqHistSvc::getHists() const
340{
341 std::vector<std::string> l;
342 l.reserve(m_hists.size());
343 for (auto it = m_hists.begin(); it != m_hists.end(); ++it) {
344 l.push_back(it->first);
345 }
346 return l;
347}
348
349/**************************************************************************************/
350
351std::set<std::string> WebdaqHistSvc::getSet(const boost::regex& nameSelect) const
352{
353 std::vector<std::string> l;
354 l.reserve(m_hists.size());
355 for (auto it = m_hists.begin(); it != m_hists.end(); ++it) {
356 if (boost::regex_match(it->first, nameSelect)) {
357 l.push_back(it->first);
358 }
359 }
360 ATH_MSG_DEBUG("Number of histograms matched: " << l.size());
361 return {l.begin(), l.end()};
362}
363
364/**************************************************************************************/
365void WebdaqHistSvc::publish(const std::string& appName, const std::string& histID) const {
366
367 const std::string path = appName + '.' + histID;
368
369 ATH_MSG_DEBUG("Publishing to " << m_partition << " Histogram " << path << " to the OH server " << m_tdaqOHServerName);
370 tbb::concurrent_hash_map<std::string, THistID>::const_accessor accessor;
371 if (!m_hists.find(accessor, histID)) {
372 ATH_MSG_WARNING("Histogram with name " << histID << " not found in histogram map (probably deregistered).");
373 return;
374 }
375
376 ATH_MSG_DEBUG("Histogram found in map, going to lock mutex and then publish it");
377 //Here we clone the histogram to avoid locking the OH mutex during the whole publication
378 std::unique_ptr<TObject> obj;
379 {
380 //Locking the OH mutex before touching the Histogram
382 //accessor is implicitly valid
383 //coverity[FORWARD_NULL]
384 obj.reset(accessor->second.obj->Clone());
385 }
386 if (obj == nullptr) {
387 ATH_MSG_ERROR("Failed to clone histogram " << histID);
388 return;
389 }
390 if (!webdaq::oh::put(m_partition, m_tdaqOHServerName, path, obj.get())) {
391 ATH_MSG_ERROR("Histogram publishing for " << histID << " failed");
392 }
393}
394
395
396/**************************************************************************************/
397
398
399void WebdaqHistSvc::publishAll(const boost::regex& nameSelect) const
400{
401 std::set<std::string> HistoSet = getSet(nameSelect);
402 ATH_MSG_DEBUG("Final publication of " << HistoSet.size()
403 << " histograms for provider " << m_appName);
404
405 for (const std::string& id : HistoSet) {
406 publish(m_appName, id);
407 }
408}
409
410/**************************************************************************************/
411
412bool WebdaqHistSvc::isObjectAllowed(const std::string& path, const TObject* o) const
413{
414 boost::cmatch what;
415
416 if (not boost::regex_match(o->ClassName(), what, m_includeTypeRegex)) {
417 ATH_MSG_WARNING("Object " << path << " of type " << o->ClassName()
418 << " does NOT match IncludeType \"" << m_includeType << "\"");
419 return false;
420 }
421
422 if (boost::regex_match(o->ClassName(), what, m_excludeTypeRegex)) {
423 ATH_MSG_WARNING("Object " << path << " of type " << o->ClassName() << " matches ExcludeType \""
424 << m_excludeType << "\"");
425 return false;
426 }
427
428 if (not boost::regex_match(path.c_str(), what, m_includeNameRegex)) {
429 ATH_MSG_WARNING("Object " << path << " does NOT match IncludeName \"" << m_includeName << "\"");
430 return false;
431 }
432
433 if (boost::regex_match(path.c_str(), what, m_excludeNameRegex)) {
434 ATH_MSG_WARNING("Object " << path << " matches ExcludeName \"" << m_excludeName << "\"");
435 return false;
436 }
437
438 return true;
439}
440
441bool WebdaqHistSvc::existsHist(const std::string& name) const
442{
443 return (getHist_i<TH1>(name, 0, true) != nullptr);
444}
445
446/**************************************************************************************
447 * Typed interface methods
448 * All these are just forwarding to the templated xyz_i methods
449 **************************************************************************************/
450StatusCode WebdaqHistSvc::regHist(const std::string& id)
451{
452 std::unique_ptr<TH1> hist = nullptr;
453 THistID* hid = nullptr;
454 return regHist_i(std::move(hist), id, false, hid);
455}
456
457StatusCode WebdaqHistSvc::regHist(const std::string& id, std::unique_ptr<TH1> hist)
458{
459 THistID* hid = nullptr;
460 return regHist_i(std::move(hist), id, false, hid);
461}
462
463StatusCode WebdaqHistSvc::regHist(const std::string& id, TH1* hist_ptr)
464{
465 THistID* hid = nullptr;
466 std::unique_ptr<TH1> hist(hist_ptr);
467 return regHist_i(std::move(hist), id, false, hid);
468}
469
470/**************************************************************************************/
471
472StatusCode WebdaqHistSvc::getHist(const std::string& id, TH1*& hist, size_t ind) const
473{
474 hist = getHist_i<TH1>(id, ind);
475 return (hist != nullptr ? StatusCode::SUCCESS : StatusCode::FAILURE);
476}
477
478StatusCode WebdaqHistSvc::getHist(const std::string& id, TH2*& hist, size_t ind) const
479{
480 hist = getHist_i<TH2>(id, ind);
481 return (hist != nullptr ? StatusCode::SUCCESS : StatusCode::FAILURE);
482}
483
484StatusCode WebdaqHistSvc::getHist(const std::string& id, TH3*& hist, size_t ind) const
485{
486 hist = getHist_i<TH3>(id, ind);
487 return (hist != nullptr ? StatusCode::SUCCESS : StatusCode::FAILURE);
488}
489
490/**************************************************************************************/
491
492StatusCode WebdaqHistSvc::getTHists(TDirectory* td, TList& tl, bool recurse) const
493{
494 if (recurse) ATH_MSG_DEBUG("Recursive flag is not supported in this implementation");
495 return getTHists_i(std::string(td->GetPath()), tl);
496}
497
498StatusCode WebdaqHistSvc::getTHists(const std::string& dir, TList& tl, bool recurse) const
499{
500 if (recurse) ATH_MSG_DEBUG("Recursive flag is not supported in this implementation");
501 return getTHists_i(dir, tl);
502}
503
504StatusCode WebdaqHistSvc::getTHists(TDirectory* td, TList& tl, bool recurse, bool reg)
505{
506 if (recurse || reg)
507 ATH_MSG_DEBUG("Recursive flag and automatic registration flag is not "
508 "supported in this implementation");
509 return getTHists_i(std::string(td->GetPath()), tl);
510}
511
512StatusCode WebdaqHistSvc::getTHists(const std::string& dir, TList& tl, bool recurse, bool reg)
513{
514 if (recurse || reg)
515 ATH_MSG_DEBUG("Recursive flag and automatic registration flag is not "
516 "supported in this implementation");
517 return getTHists_i(dir, tl);
518}
519
520/**************************************************************************************/
521
522StatusCode WebdaqHistSvc::regShared(const std::string& id, std::unique_ptr<TH1> hist,
523 LockedHandle<TH1>& lh)
524{
525 lh = regShared_i<TH1>(id, std::move(hist));
526 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
527}
528
529StatusCode WebdaqHistSvc::regShared(const std::string& id, std::unique_ptr<TH2> hist,
530 LockedHandle<TH2>& lh)
531{
532 lh = regShared_i<TH2>(id, std::move(hist));
533 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
534}
535
536StatusCode WebdaqHistSvc::regShared(const std::string& id, std::unique_ptr<TH3> hist,
537 LockedHandle<TH3>& lh)
538{
539 lh = regShared_i<TH3>(id, std::move(hist));
540 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
541}
542
543/**************************************************************************************/
544
545StatusCode WebdaqHistSvc::getShared(const std::string& id, LockedHandle<TH1>& lh) const
546{
547 lh = getShared_i<TH1>(id);
548 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
549}
550
551StatusCode WebdaqHistSvc::getShared(const std::string& id, LockedHandle<TH2>& lh) const
552{
553 lh = getShared_i<TH2>(id);
554 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
555}
556
557StatusCode WebdaqHistSvc::getShared(const std::string& id, LockedHandle<TH3>& lh) const
558{
559 lh = getShared_i<TH3>(id);
560 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
561}
562
563/**************************************************************************************/
564
576void WebdaqHistSvc::monitoringTask(const std::string& appName, unsigned int numSlots, unsigned int intervalSeconds, std::atomic<bool>& histoMapUpdated, const boost::regex& nameSelect) const
577{
578 ATH_MSG_INFO("Started monitoring task for partition: " << m_partition << "and regex: " << nameSelect.str());
579
580 // Set the publication period
581 const boost::posix_time::time_duration interval{boost::posix_time::seconds(intervalSeconds)};
582 ATH_MSG_DEBUG("Interval set to " << interval.total_seconds() << " seconds");
583 const int interval_ms = interval.total_milliseconds();
584
585 if (numSlots == 0) numSlots = 1;
586 // Sleep duration between slots (plus an extra slot for allowing a last sleep cycle)
587 const boost::posix_time::time_duration slotSleepDuration = interval / (numSlots + 1);
588
589 // Create the Set of the histograms keys to order the histograms publication and reset the histoMapUpdated flag
590 std::set<std::string> HistoSet = getSet(nameSelect);
591 histoMapUpdated = false;
592
593 // Sync the publication to the period
594 const boost::posix_time::ptime epoch(boost::gregorian::date(2024,1,1));
595 syncPublish(interval_ms, epoch);
596 ATH_MSG_DEBUG("Monitoring task synced");
597
598 // Publication loop
599 while (!m_stopFlag)
600 {
601 // Check if the histograms map has been updated, and if so update the Set
602 if (histoMapUpdated)
603 {
604 ATH_MSG_DEBUG("Histo map updated, updating the Set");
605 HistoSet = getSet(nameSelect);
606 histoMapUpdated = false;
607 }
608
609 // Divide the histograms in batches
610 const size_t totalHists = HistoSet.size();
611 const size_t batchSize = (totalHists + numSlots - 1) / numSlots; // Ceiling division
612 ATH_MSG_DEBUG("Num of hists: " << totalHists << ", Num of slots:" << numSlots <<
613 ", Interval_ms " << interval_ms << " milliseconds, Batch size: " << batchSize);
614
615 const boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::universal_time();
616 int counter = 0;
617 int BatchCounter = 0;
618 auto it = HistoSet.begin();
619 while(it != HistoSet.end())
620 {
621 const boost::posix_time::ptime slot_start_time = boost::posix_time::microsec_clock::universal_time();
622 ATH_MSG_DEBUG("Batch publication number " << BatchCounter << " starting.");
623 for(size_t j = 0; j < batchSize; ++j)
624 {
625 if(it == HistoSet.end())
626 {
627 break;
628 }
629 publish(appName, *it);
630 ++it;
631 ++counter;
632 }
633 ATH_MSG_DEBUG("Batch publication completed, " << counter << " histograms published");
634 // Sleep for slotSleepDuration - slot publication time, unless it's the last slot
635 if (it != HistoSet.end()) {
636 boost::posix_time::ptime slot_end_time = boost::posix_time::microsec_clock::universal_time();
637 int slot_sleep_time = slotSleepDuration.total_milliseconds() - (slot_end_time-slot_start_time).total_milliseconds();
638 if (slot_sleep_time > 0) {
639 ATH_MSG_DEBUG("Sleeping for " << slot_sleep_time << " seconds before publishing the next batch");
640 TrigServices::conditionedSleep(std::chrono::milliseconds(slot_sleep_time), m_stopFlag);
641 }
642 }
643 ++BatchCounter;
644 }
645
646 //check if we exceeded the publication period
647 const boost::posix_time::ptime end_time = boost::posix_time::microsec_clock::universal_time();
648 if (boost::posix_time::time_duration(end_time-start_time) > interval) {
649 ATH_MSG_WARNING("Publication deadline missed, cycle exceeded the interval.. Total publication time "
650 << boost::posix_time::to_simple_string(end_time-start_time));
651 }
652 ATH_MSG_DEBUG("Completed the publication of " << counter << " histograms. "
653 "Publication time: " << boost::posix_time::to_simple_string(end_time-start_time));
654
655 //sleep till the next cycle
656 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
657 const int nowMs = (now-epoch).total_milliseconds();
658 const boost::posix_time::time_duration next_cycle(boost::posix_time::milliseconds(interval_ms - (nowMs % interval_ms)));
659 ATH_MSG_DEBUG("epoch " << epoch <<", interval_ms" << interval_ms << ", now_ms " << nowMs
660 << "sleeping for " << next_cycle.total_milliseconds() << " milliseconds till the next cycle");
661 TrigServices::conditionedSleep(std::chrono::milliseconds(next_cycle.total_milliseconds()), m_stopFlag);
662 }
663 ATH_MSG_INFO("Monitoring task stopped");
664}
665
666/**************************************************************************************/
667
668void WebdaqHistSvc::syncPublish(long int interval_ms, const boost::posix_time::ptime& epoch) const
669{
670 //Sync the publication to a multple of the interval
671 //Code taken from TDAQ monsvc https://gitlab.cern.ch/atlas-tdaq-software/monsvc/-/blob/master/src/PeriodicScheduler.cxx?ref_type=heads#L163
672 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
673 const int now_ms = (now-epoch).total_milliseconds();
674 //If now_ms % interval_ms == 0 we skip a cycle. Too bad.
675 const boost::posix_time::time_duration sync(boost::posix_time::milliseconds(interval_ms - (now_ms % interval_ms)));
676 //Do not sync if we are below 50 ms
677 if (sync.total_milliseconds() > 50){
678 std::this_thread::sleep_for(std::chrono::milliseconds(sync.total_milliseconds()));
679 }
680}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
OH histogram lock header file.
StatusCode WebdaqHistSvc::initialize ATLAS_NOT_THREAD_SAFE()
Install fatal handler with default options.
Header file for AthHistogramAlgorithm.
static const std::string & type()
Incident type.
Definition Incidents.h:49
Gaudi::Property< std::string > m_includeType
boost::regex m_fastPublicationIncludeNameRegex
virtual StatusCode stop() override
virtual StatusCode getHist(const std::string &id, TH1 *&hist, size_t ind) const override
Gaudi::Property< unsigned int > m_intervalSeconds
Gaudi::Property< std::string > m_excludeType
Gaudi::Property< std::string > m_excludeName
std::thread m_threadFast
void monitoringTask(const std::string &, unsigned int, unsigned int, std::atomic< bool > &, const boost::regex &) const
The actual publication Task.
boost::regex m_PublicationIncludeNameRegex
std::thread m_thread
Publication thread.
boost::regex m_includeTypeRegex
std::atomic< bool > m_stopFlag
Flag to stop the monitoring task.
virtual std::vector< std::string > getHists() const override
virtual void handle(const Incident &incident) override
std::string m_appName
Application name.
boost::regex m_excludeNameRegex
LockedHandle< T > getShared_i(const std::string &id) const
std::set< std::string > getSet(const boost::regex &) const
virtual StatusCode getShared(const std::string &, LockedHandle< TH1 > &) const override
virtual bool existsHist(const std::string &name) const override
std::atomic< bool > m_histoMapUpdatedFast
Flag to indicate when the histogram map is updated for the fast publication.
StatusCode regHist_i(std::unique_ptr< T > hist, const std::string &name, bool shared, THistID *&phid)
Gaudi::Property< unsigned int > m_intervalSecondsFast
Gaudi::Property< unsigned int > m_numSlots
std::string m_tdaqOHServerName
The OH server name (TDAQ_OH_SERVER if defined, m_OHServerName otherwise).
virtual StatusCode finalize() override
boost::regex m_includeNameRegex
boost::regex m_excludeTypeRegex
LockedHandle< T > regShared_i(const std::string &id, std::unique_ptr< T > hist)
virtual StatusCode regHist(const std::string &name) override
tbb::concurrent_hash_map< std::string, THistID > m_hists
Map of the registered histograms.
virtual StatusCode regShared(const std::string &, std::unique_ptr< TH1 >, LockedHandle< TH1 > &) override
void publish(const std::string &appName, const std::string &histID) const
Publish one histogram.
std::string m_partition
The partition to publish to.
Gaudi::Property< unsigned int > m_numSlotsFast
T * getHist_i(const std::string &id, const size_t &ind, bool quiet=false) const
std::atomic< bool > m_histoMapUpdated
Flag to indicate when the histogram map is updated.
bool isObjectAllowed(const std::string &path, const TObject *o) const
Does the histogram follow the naming rules ?
virtual StatusCode deReg(TObject *obj) override
virtual StatusCode getTHists(TDirectory *td, TList &, bool recurse=false) const override
void publishAll(const boost::regex &nameSelect) const
Final publication after stop.
StatusCode getTHists_i(const std::string &name, TList &) const
Get TList of registered histograms.
void syncPublish(long int, const boost::posix_time::ptime &) const
Sync the publication to a multiple of the interval.
Gaudi::Property< std::string > m_includeName
STL class.
static void reset_histogram_mutex()
Reset (disable) histogram mutex.
static void set_histogram_mutex(std::mutex &mutex)
Set mutex to be used in oh_lock_histogram.
Scoped lock to be used for threaded histogram operations.
void conditionedSleep(std::chrono::milliseconds duration, const std::atomic< bool > &stopFlag)
Sleep for duration or until stopFlag is set, whichever comes first.
Helper struct that bundles the histogram, name and mutex.
std::unique_ptr< std::mutex > mutex