7#include "GaudiKernel/IIncidentSvc.h"
11#include "webdaq/webdaq-root.hpp"
12#include "webdaq/webdaq.hpp"
22#include <TBufferJSON.h>
24#include <boost/date_time/posix_time/posix_time.hpp>
25#include <boost/date_time/gregorian/gregorian_types.hpp>
34 static TROOT root(
"root",
"ROOT I/O");
40 gErrorIgnoreLevel = kBreak;
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());
52 static std::mutex
mutex;
57 m_appName = m_jobOptionsSvc->get(
"DataFlowConfig.DF_ApplicationName");
60 const char* tdaq_partition_cstr = std::getenv(
"TDAQ_PARTITION");
61 if (tdaq_partition_cstr !=
nullptr) {
62 m_partition = std::string(tdaq_partition_cstr);
66 return StatusCode::FAILURE;
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);
73 ATH_MSG_ERROR(
"TDAQ_WEBDAQ_BASE environment variable not set! Is needed for the OH publication through webdaq");
74 return StatusCode::FAILURE;
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);
80 m_tdaqOHServerName = m_OHServerName.value();
82 ATH_MSG_INFO(
"TDAQ_OH_SERVER value: " << m_tdaqOHServerName);
89 return StatusCode::SUCCESS;
97 ATH_MSG_INFO(
"Going to initialize the monitoring thread");
120 catch (
const std::exception& e) {
121 ATH_MSG_ERROR(
"Failed to join the monitoring thread: " << e.what());
122 return StatusCode::FAILURE;
130 catch (
const std::exception& e) {
131 ATH_MSG_ERROR(
"Failed to join the fast monitoring thread: " << e.what());
132 return StatusCode::FAILURE;
135 ATH_MSG_INFO(
"Performing final histogram publication before stop");
141 return StatusCode::SUCCESS;
152 return StatusCode::SUCCESS;
165 return StatusCode::FAILURE;
168 if (hist_unique->Class()->InheritsFrom(TH1::Class())) {
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;
176 if (!
m_hists.insert(accessor,
id)) {
177 ATH_MSG_ERROR(
"Failed to insert histogram with name " <<
id);
178 return StatusCode::FAILURE;
180 T* hist = hist_unique.release();
183 accessor->second =
THistID(
id, hist);
185 if (shared) accessor->second.mutex = std::make_unique<std::mutex>();
186 phid = &accessor->second;
188 << hist->GetName() <<
" registered under " <<
id <<
" " << name());
191 <<
" because it does not inherit from TH1");
192 return StatusCode::FAILURE;
194 return StatusCode::SUCCESS;
202 LockedHandle<T> lh(
nullptr,
nullptr);
204 tbb::concurrent_hash_map<std::string, THistID>::accessor accessor;
206 if (!
m_hists.find(accessor,
id)) {
208 T* phist = hist.get();
210 if (
regHist_i(std::move(hist),
id,
true, phid).isSuccess()) {
211 if (phid) lh.set(phist, phid->
mutex.get());
217 if (accessor->second.mutex ==
nullptr) {
218 ATH_MSG_ERROR(
"regShared: previously registered histogram \"" <<
id
219 <<
"\" was not marked shared");
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)));
228 lh.set(phist, accessor->second.mutex.get());
243 tbb::concurrent_hash_map<std::string, THistID>::const_accessor accessor;
244 if (!
m_hists.find(accessor,
id) or accessor.empty()) {
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)));
264 const std::string&
id = it->first;
266 if (
id.starts_with(dir)) {
270 return StatusCode::SUCCESS;
278 tbb::concurrent_hash_map<std::string, THistID>::const_accessor accessor;
279 if (
m_hists.find(accessor,
id)) {
281 auto * obj = accessor->second.obj;
284 if (accessor->second.mutex ==
nullptr) {
286 <<
"\", but it's not marked as shared");
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)));
297 return LockedHandle<T>(phist, accessor->second.mutex.get());
299 ATH_MSG_ERROR(
"getShared: cannot find histogram with id \"" <<
id <<
"\"");
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);
315 ATH_MSG_ERROR(
"Histogram with pointer " << optr <<
" not found in the histogram map");
316 return StatusCode::FAILURE;
323 tbb::concurrent_hash_map<std::string, THistID>::accessor accessor;
324 if (
m_hists.find(accessor,
id)) {
326 accessor->second.obj->Delete();
331 return StatusCode::SUCCESS;
333 ATH_MSG_ERROR(
"Deregistration failed: histogram with id \"" <<
id <<
"\" not found");
334 return StatusCode::FAILURE;
341 std::vector<std::string> l;
344 l.push_back(it->first);
353 std::vector<std::string> l;
356 if (boost::regex_match(it->first, nameSelect)) {
357 l.push_back(it->first);
361 return {l.begin(), l.end()};
367 const std::string path = appName +
'.' + histID;
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).");
376 ATH_MSG_DEBUG(
"Histogram found in map, going to lock mutex and then publish it");
378 std::unique_ptr<TObject> obj;
384 obj.reset(accessor->second.obj->Clone());
386 if (obj ==
nullptr) {
391 ATH_MSG_ERROR(
"Histogram publishing for " << histID <<
" failed");
401 std::set<std::string> HistoSet =
getSet(nameSelect);
403 <<
" histograms for provider " <<
m_appName);
405 for (
const std::string&
id : HistoSet) {
418 <<
" does NOT match IncludeType \"" <<
m_includeType <<
"\"");
423 ATH_MSG_WARNING(
"Object " << path <<
" of type " << o->ClassName() <<
" matches ExcludeType \""
452 std::unique_ptr<TH1> hist =
nullptr;
454 return regHist_i(std::move(hist),
id,
false, hid);
460 return regHist_i(std::move(hist),
id,
false, hid);
466 std::unique_ptr<TH1> hist(hist_ptr);
467 return regHist_i(std::move(hist),
id,
false, hid);
475 return (hist !=
nullptr ? StatusCode::SUCCESS : StatusCode::FAILURE);
481 return (hist !=
nullptr ? StatusCode::SUCCESS : StatusCode::FAILURE);
487 return (hist !=
nullptr ? StatusCode::SUCCESS : StatusCode::FAILURE);
494 if (recurse)
ATH_MSG_DEBUG(
"Recursive flag is not supported in this implementation");
495 return getTHists_i(std::string(td->GetPath()), tl);
500 if (recurse)
ATH_MSG_DEBUG(
"Recursive flag is not supported in this implementation");
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);
515 ATH_MSG_DEBUG(
"Recursive flag and automatic registration flag is not "
516 "supported in this implementation");
523 LockedHandle<TH1>& lh)
526 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
530 LockedHandle<TH2>& lh)
533 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
537 LockedHandle<TH3>& lh)
540 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
548 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
554 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
560 return (lh ? StatusCode::SUCCESS : StatusCode::FAILURE);
576void WebdaqHistSvc::monitoringTask(
const std::string& appName,
unsigned int numSlots,
unsigned int intervalSeconds, std::atomic<bool>& histoMapUpdated,
const boost::regex& nameSelect)
const
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();
585 if (numSlots == 0) numSlots = 1;
587 const boost::posix_time::time_duration slotSleepDuration = interval / (numSlots + 1);
590 std::set<std::string> HistoSet =
getSet(nameSelect);
591 histoMapUpdated =
false;
594 const boost::posix_time::ptime epoch(boost::gregorian::date(2024,1,1));
605 HistoSet =
getSet(nameSelect);
606 histoMapUpdated =
false;
610 const size_t totalHists = HistoSet.size();
611 const size_t batchSize = (totalHists + numSlots - 1) / numSlots;
612 ATH_MSG_DEBUG(
"Num of hists: " << totalHists <<
", Num of slots:" << numSlots <<
613 ", Interval_ms " << interval_ms <<
" milliseconds, Batch size: " << batchSize);
615 const boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::universal_time();
617 int BatchCounter = 0;
618 auto it = HistoSet.begin();
619 while(it != HistoSet.end())
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)
625 if(it == HistoSet.end())
633 ATH_MSG_DEBUG(
"Batch publication completed, " << counter <<
" histograms published");
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");
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));
652 ATH_MSG_DEBUG(
"Completed the publication of " << counter <<
" histograms. "
653 "Publication time: " << boost::posix_time::to_simple_string(end_time-start_time));
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");
672 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
673 const int now_ms = (now-epoch).total_milliseconds();
675 const boost::posix_time::time_duration sync(boost::posix_time::milliseconds(interval_ms - (now_ms % interval_ms)));
677 if (sync.total_milliseconds() > 50){
678 std::this_thread::sleep_for(std::chrono::milliseconds(sync.total_milliseconds()));
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(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.
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
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
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