From 7b46138b25e49299b87f72aa3ada76d8b5e9d4de Mon Sep 17 00:00:00 2001 From: Werner Wiedenmann <wiedenat@cern.ch> Date: Tue, 4 Oct 2016 16:41:42 +0200 Subject: [PATCH] fix for ATR-14403 (TrigServices-20-10-11) --- .../TrigControl/TrigServices/CMakeLists.txt | 55 + .../TrigServices/HltEventLoopMgr.h | 476 +++ .../TrigServices/HltROBDataProviderSvc.h | 224 ++ .../TrigServices/TrigServices/TrigHLTIssues.h | 37 + .../TrigServices/TrigServices/TrigIS.h | 79 + .../TrigServices/TrigServices/TrigISHelper.h | 211 ++ .../TrigServices/TrigMessageSvc.h | 226 ++ .../TrigControl/TrigServices/cmt/requirements | 49 + .../TrigServices/python/HltTHistSvcConfig.py | 28 + .../TrigServices/python/TrigServicesConfig.py | 27 + .../python/TriggerUnixStandardSetup.py | 243 ++ .../TrigServices/python/__init__.py | 6 + .../TrigServices/share/MessageSvc.py | 79 + .../TrigServices/share/OfflineTHistSvc.py | 17 + .../share/TrigServicesBootstrap.py | 29 + .../share/TrigServicesCommonBegin.py | 20 + .../share/TrigServicesCommonEnd.py | 19 + .../share/TrigServicesEventLoopMgr.py | 76 + .../share/TrigServicesTHistSvc.py | 59 + .../TrigControl/TrigServices/share/hadd.C | 212 ++ .../TrigControl/TrigServices/share/hadd.sh | 66 + .../TrigServices/src/HltEventLoopMgr.cxx | 3234 +++++++++++++++++ .../src/HltROBDataProviderSvc.cxx | 1279 +++++++ .../TrigServices/src/THistSvcHLT.cxx | 2089 +++++++++++ .../TrigServices/src/THistSvcHLT.h | 230 ++ .../TrigServices/src/THistSvcHLT.icc | 311 ++ .../TrigServices/src/TrigCOOLUpdateHelper.cxx | 404 ++ .../TrigServices/src/TrigCOOLUpdateHelper.h | 191 + .../TrigControl/TrigServices/src/TrigIS.cxx | 85 + .../TrigServices/src/TrigISHelper.cxx | 139 + .../TrigServices/src/TrigMessageSvc.cxx | 1203 ++++++ .../TrigServices/src/TrigMonTHistSvc.cxx | 403 ++ .../TrigServices/src/TrigMonTHistSvc.h | 134 + .../TrigServices/src/TrigPreFlightCheck.cxx | 87 + .../TrigServices/src/TrigPreFlightCheck.h | 70 + .../src/TrigSORFromPtreeHelper.cxx | 253 ++ .../TrigServices/src/TrigSORFromPtreeHelper.h | 65 + .../src/components/TrigServices_entries.cxx | 30 + .../src/components/TrigServices_load.cxx | 3 + 39 files changed, 12448 insertions(+) create mode 100644 HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/HltEventLoopMgr.h create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigHLTIssues.h create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigIS.h create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigISHelper.h create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigMessageSvc.h create mode 100755 HLT/Trigger/TrigControl/TrigServices/cmt/requirements create mode 100644 HLT/Trigger/TrigControl/TrigServices/python/HltTHistSvcConfig.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/python/TriggerUnixStandardSetup.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/python/__init__.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/MessageSvc.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/OfflineTHistSvc.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/TrigServicesBootstrap.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonBegin.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonEnd.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/TrigServicesEventLoopMgr.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/TrigServicesTHistSvc.py create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/hadd.C create mode 100755 HLT/Trigger/TrigControl/TrigServices/share/hadd.sh create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.h create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigIS.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigISHelper.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.h create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.h create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_entries.cxx create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_load.cxx diff --git a/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt b/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt new file mode 100644 index 00000000000..007f3f211fc --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt @@ -0,0 +1,55 @@ +################################################################################ +# Package: TrigServices +################################################################################ + +# Declare the package name: +atlas_subdir( TrigServices ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + Control/AthenaBaseComps + Control/AthenaKernel + Control/StoreGate + Event/ByteStreamCnvSvcBase + Event/ByteStreamData + Event/EventInfo + Event/xAOD/xAODEventInfo + GaudiKernel + HLT/Trigger/TrigControl/TrigKernel + Trigger/TrigDataAccess/TrigDataAccessMonitoring + Trigger/TrigDataAccess/TrigROBDataProviderSvc + Trigger/TrigEvent/TrigSteeringEvent + PRIVATE + Control/CLIDSvc + Control/SGTools + Database/AthenaPOOL/AthenaPoolUtilities + Trigger/TrigConfiguration/TrigConfInterfaces + Trigger/TrigEvent/TrigNavigation + Trigger/TrigMonitoring/TrigMonitorBase + Trigger/TrigSteer/TrigInterfaces ) + +# External dependencies: +find_package( Boost COMPONENTS filesystem thread system ) +find_package( CORAL COMPONENTS CoralBase CoralKernel RelationalAccess ) +find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) +find_package( tdaq COMPONENTS omniORB4 omnithread ipc is owl ) +find_package( tdaq-common COMPONENTS CTPfragment eformat eformat_write hltinterface ) + +# Component(s) in the package: +atlas_add_library( TrigServicesLib + src/*.cxx + PUBLIC_HEADERS TrigServices + INCLUDE_DIRS ${TDAQ-COMMON_INCLUDE_DIRS} ${TDAQ_INCLUDE_DIRS} + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS} + LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES} ${TDAQ_LIBRARIES} AthenaBaseComps AthenaKernel ByteStreamData EventInfo xAODEventInfo GaudiKernel TrigKernel TrigSteeringEvent StoreGateLib SGtests ByteStreamCnvSvcBaseLib ByteStreamData_test TrigDataAccessMonitoringLib TrigROBDataProviderSvcLib TrigNavigationLib TrigMonitorBaseLib TrigInterfacesLib + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${CORAL_LIBRARIES} SGTools AthenaPoolUtilities ) + +atlas_add_component( TrigServices + src/components/*.cxx + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS} ${TDAQ-COMMON_INCLUDE_DIRS} ${TDAQ_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${CORAL_LIBRARIES} ${TDAQ-COMMON_LIBRARIES} ${TDAQ_LIBRARIES} AthenaBaseComps AthenaKernel StoreGateLib SGtests ByteStreamCnvSvcBaseLib ByteStreamData ByteStreamData_test EventInfo xAODEventInfo GaudiKernel TrigKernel TrigDataAccessMonitoringLib TrigROBDataProviderSvcLib TrigSteeringEvent SGTools AthenaPoolUtilities TrigNavigationLib TrigMonitorBaseLib TrigInterfacesLib TrigServicesLib ) + +# Install files from the package: +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/*.py ) + diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltEventLoopMgr.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltEventLoopMgr.h new file mode 100644 index 00000000000..e13807e457e --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltEventLoopMgr.h @@ -0,0 +1,476 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGSERVICES_HLTEVENTLOOPMGR_H +#define TRIGSERVICES_HLTEVENTLOOPMGR_H + +#include "TrigKernel/ITrigEventLoopMgr.h" +#include "EventInfo/EventID.h" /* number_type */ +#include "EventInfo/TriggerInfo.h" +#include "xAODEventInfo/EventInfo.h" +#include "eformat/eformat.h" + +// Framework include files +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/SmartIF.h" +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/MinimalEventLoopMgr.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/HistoProperty.h" +#include "AthenaKernel/Timeout.h" +#include "TrigKernel/HltOstreams.h" +#include "TrigKernel/HltAcceptFlag.h" +#include "TrigKernel/HltResultStatusCode.h" +#include "TrigKernel/HltPscErrorCode.h" +#include "TrigKernel/IHltTHistSvc.h" +#include "TrigROBDataProviderSvc/ITrigROBDataProviderSvc.h" + +#include <tuple> +#include <utility> +#include <functional> +#include <memory> +#include <vector> +#include <set> +#include <stdint.h> + +// Forward declarations +class IIncidentSvc; +class IAlgContextSvc; +class StoreGateSvc; +class IROBDataProviderSvc; +class ITHistSvc; +class TrigISHelper; +class TH1F; +class TH2I; +class TProfile; +class EventInfo; +class TrigCOOLUpdateHelper; +class CondAttrListCollection; +namespace coral { + class AttributeList; +} +namespace TrigConf { + class IHLTConfigSvc; +} +namespace HLT { + class HLTResult; +} +namespace eformat { + namespace write { + class ROBFragment; + } +} + +class HltEventLoopMgr : public MinimalEventLoopMgr, + virtual public ITrigEventLoopMgr, + virtual public Athena::TimeoutMaster +{ + +public: + /// Creator friend class + friend class SvcFactory<HltEventLoopMgr>; + + /// Standard Constructor + HltEventLoopMgr(const std::string& nam, ISvcLocator* svcLoc); + /// Standard Destructor + virtual ~HltEventLoopMgr(); + + /// implementation of IInterface: queryInterface + virtual StatusCode queryInterface(const InterfaceID& riid, void** ppvInterface); + + /// \name State transitions + //@{ + virtual StatusCode sysInitialize(); + virtual StatusCode initialize(); + + virtual StatusCode prepareForRun(const boost::property_tree::ptree & pt); + + virtual StatusCode hltUpdateAfterFork(const boost::property_tree::ptree & pt); + + virtual StatusCode stop(); + + virtual StatusCode sysFinalize(); + virtual StatusCode finalize(); + + virtual StatusCode sysReinitialize(); + virtual StatusCode reinitialize(); + //@} + + /// Event processing + virtual StatusCode executeEvent(void* par); + + virtual StatusCode + processRoIs(const std::vector<eformat::ROBFragment<const uint32_t*> >& l1_result, + hltinterface::HLTResult& hlt_result, + const hltinterface::EventId& evId); + + /// Event timoeut reached + virtual StatusCode timeOutReached(const boost::property_tree::ptree& pt); + + /// return the application Name + std::string applicationName() const { return m_applicationName.value(); } + + /// \name Obsolete methods for online running + //@{ + virtual StatusCode nextEvent(int maxevt); ///< Obsolete + virtual StatusCode executeRun(int runNumber); ///< Obsolete + virtual StatusCode stopRun(); ///< Obsolete + virtual StatusCode start(); ///< Obsolete + //@} + +private: + + /** + * @brief Accessor method for the MsgStream. + * @return handle to the MsgStream. + */ + inline MsgStream& logStream() const { return *m_msg; } + + /** + * @brief Accessor method for the message level variable. + * @return value of the message level for this algorithm. + */ + inline MSG::Level logLevel() const { return (m_msg != 0) ? m_msg->level() : MSG::NIL; } + + /** + * @brief Call execute method of algorithms + * @return FAILURE in case one algorithm failed + */ + StatusCode executeAlgorithms(); + + /** + * @brief Check if an HLT prescale update is required + * @param hltCounter list of "HLT counters" from CTP fragment (only one used) + */ + StatusCode checkHltPrescaleUpdate(std::vector<uint32_t>& hltCounter); + + /** + * @brief Do HLT prescale update + * @param lumiBlock LB for which the update should be done + */ + StatusCode hltPrescaleUpdate(uint32_t lumiBlock); + + /** + * @brief Helper to fill histograms from HLT result + * @param hlt_result reference to dataflow HLTResult object + */ + void fillHltResultHistograms(const hltinterface::HLTResult& hlt_result); + + /// Check if running in partition + bool validPartition() const { + return (m_partitionName.value()!="None" && m_partitionName.value()!="NONE"); + } + + /** + * @brief Helper to set PSC error word + * @param hlt_result reference to dataflow HLTResult object; filled on return + * @param pscErrorCode PSC Error code which should be set + */ + void HltSetPscError(hltinterface::HLTResult& hlt_result, + hltonl::PSCErrorCode pscErrorCode) const; + + /** + * @brief Helper to build an empty dataflow HLT Result object + * @param hlt_result reference to dataflow HLTResult object; filled on return + * @param run_no for ROB fragment + * @param lvl1_id for ROB fragment + * @param bunch_crossing_id for ROB fragment + * @param l1_Trigger_Type for ROB fragment + * @param l1_detev_type for ROB fragment + * @param pscErrorCode PSC Error code which should be set + */ + void HltEmptyResultROB(hltinterface::HLTResult& hlt_result, + uint32_t run_no, uint32_t lvl1_id, uint32_t bunch_crossing_id, + uint32_t l1_Trigger_Type, uint32_t l1_detev_type, + hltonl::PSCErrorCode pscErrorCode); + + /** + * @brief Helper to build the dataflow HLT Result object. + * @return value error code hltonl::PSCErrorCode + * @param hlt_result reference to dataflow HLTResult object; filled on return + * @param run_no for ROB fragment + * @param lvl1_id for ROB fragment + * @param bunch_crossing_id for ROB fragment + * @param l1_Trigger_Type for ROB fragment + * @param l1_detev_type for ROB fragment + * @param trigger_info trigger info words for the HLT + * @param stream_tags stream tags generated during HLT processing + */ + hltonl::PSCErrorCode HltResultROBs(hltinterface::HLTResult& hlt_result, + uint32_t run_no, uint32_t lvl1_id, uint32_t bunch_crossing_id, + uint32_t l1_Trigger_Type, uint32_t l1_detev_type, + const std::vector<TriggerInfo::number_type>& trigger_info, + const std::vector<TriggerInfo::StreamTag>& stream_tags, + const std::vector<xAOD::EventInfo::StreamTag>& xsts); + + /// Helper to build an empty HLTResult object + void HltEmptyResultROB(hltinterface::HLTResult& hlt_result, + hltonl::PSCErrorCode pscErrorCode); + /// Helper to build HLTResult object from Steering result + void HltResult(hltinterface::HLTResult& hlt_result, + const EventInfo* pEvent, + const xAOD::EventInfo* xev); + /// Helpers to book histograms + void bookHistograms(); + void HltBookHistograms(); + void bookAllHistograms(); + void updateDFProps(); + // Call a simple IAlgorithm (usually member) function on all algorithms + StatusCode callOnAlgs(const std::function<StatusCode(IAlgorithm&)> & func, + const std::string & fname, bool failureIsError = false); + StatusCode prepareAlgs(const EventInfo& evinfo); + /// Helper to reset necessary data at prepareForRun + StatusCode internalPrepareResets(); + /// Helper to do whatever is necessary with RunParams (prepare) ptree + const CondAttrListCollection * + processRunParams(const boost::property_tree::ptree & pt); + // Helper to update internally kept data from new sor + void updInternal(const coral::AttributeList & sor_attrlist); + // Helper to get update the metadata store with a new metadata record + void updMetadaStore(const coral::AttributeList & sor_attrlist); + /// Helper to clear per-event stores + StatusCode clearTemporaryStores(); + /// Helper to update the detector mask + void updDetMask(const std::pair<uint64_t, uint64_t>& dm); + /// Helper to update the SOR time stamp + void updSorTime(unsigned long long st); + /// Helper to extract the single attr list off the SOR CondAttrListCollection + const coral::AttributeList & + getSorAttrList(const CondAttrListCollection * sor) const; + /// Update the HLTConfigSvc (only required to succeed with DB based config) + StatusCode updHLTConfigSvc(); + /// Set the EventInfo in the event store and return it + const EventInfo * prepEventInfo() const; + /// Set the xAOD::EventInfo in the event store + StatusCode prepXAODEventInfo() const; + /// Update the magnet field from IS when necessary and possible + StatusCode updMagField(const boost::property_tree::ptree& pt) const; + /// Reset selected proxies / IOV folders + StatusCode resetCoolValidity(); + /// Helper to log a message with some details when ready to run + void readyMsg() const; + /// Helper to fill in HLTResult with stream tags + void setStreamTags(hltinterface::HLTResult& hltr, + const std::vector<TriggerInfo::StreamTag>& stream_tags) const; + void mergeStreamTags(hltinterface::HLTResult& hltr, + const std::vector<xAOD::EventInfo::StreamTag>& xsts) const; + /// get the right hlt decision, setting debug stream tag if necessary + hltonl::AcceptFlag processHltDecision(hltinterface::HLTResult& hltr) const; + /// Serializes Steering's result into hltinterface's result robs + hltonl::PSCErrorCode serializeRobs(hltinterface::HLTResult& hltr, bool& serOk, + HLT::HLTResult* dobj, uint32_t rn, + uint32_t l1id, uint32_t bcid, + uint32_t l1tt, uint32_t dett); + // Check whether a rob fits the space left. If not, issue an error + bool checkRobSize(uint32_t robsize, uint32_t spaceleft, uint32_t maxsize); + // Check consistency of the info received in the EventId and the CTP fragment + bool checkEventIdConsistency(const hltinterface::EventId& evId) const; + // serialize rob from steering's HLTResult + bool serializeRob(uint32_t*& tmpstor, + eformat::write::ROBFragment& rob, + HLT::HLTResult& dobj, + unsigned int robid, + int payload_max); + // add rob to hltinterface::HLTResult + void addRobToHLTResult(hltinterface::HLTResult& hltr, + eformat::write::ROBFragment& rob, + uint32_t*& next_fragment, + uint32_t& spaceleft); /* don't pass original + fragment_pointer or max_result_size (notice parameters + passed by reference) */ + // Get monitoring information for navigation sizes of HLT EDM + void recordEDMSizeInfo(size_t nav_size, bool serializationOk) const; + // check if a ROB is enabled for readout in OKS + bool isRobEnabled(uint32_t robid) const; + // check if a Sub Detector is enabled for readout in OKS + bool isSubDetectorEnabled(uint32_t subdetid) const; + // filter a set of robs according to whether or not they are enabled + std::set<uint32_t> filterRobs(const std::set<uint32_t> robs) const; + // filter a set of dets according to whether or not they are enabled + std::set<eformat::SubDetector> + filterDets(const std::set<uint32_t> dets) const; + + // act on failure to process event + void failedEvent(hltinterface::HLTResult& hlt_result, + hltonl::PSCErrorCode ecode, + const std::string& emsg, + bool empty_result = true); + + // get a vector with the ids of the expected L1R robs that are missing + std::vector<uint32_t> + missingL1Robs(const std::vector<eformat::ROBFragment<const uint32_t*>>& l1r) + const; + + // check whether a subdetector is in the run, according to the current detmask + bool isSubDetectorIn(eformat::SubDetector sd) const; + + /** Handles to required services/tools **/ + typedef ServiceHandle<IIncidentSvc> IIncidentSvc_t; + IIncidentSvc_t m_incidentSvc; + + typedef ServiceHandle<StoreGateSvc> StoreGateSvc_t; + StoreGateSvc_t m_evtStore; + StoreGateSvc_t m_detectorStore; + StoreGateSvc_t m_inputMetaDataStore; + + typedef ServiceHandle<IROBDataProviderSvc> IIROBDataProviderSvc_t; + IIROBDataProviderSvc_t m_robDataProviderSvc; + + typedef ServiceHandle<ITHistSvc> ITHistSvc_t; + ITHistSvc_t m_THistSvc; + + ToolHandle<TrigISHelper> m_isHelper; + ToolHandle<TrigCOOLUpdateHelper> m_coolHelper; + + /** Pointers to optional services/tools **/ + TrigConf::IHLTConfigSvc* m_hltConfigSvc; + IAlgContextSvc* m_algContextSvc; + + IntegerProperty m_lvl1CTPROBid ; // Source ID for CTP ROB fragment + BooleanProperty m_doMonitoring; // Monitoring + + /// Helper classes for error codes + hltonl::MapPscErrorCode m_mapPscError; + hltonl::MapResultStatusCode m_mapResultStatus; + hltonl::MapAcceptFlag m_mapAccept; + + MsgStream* m_msg ; //!< Pointer to MsgStream + EventID::number_type m_currentRun; //!< current run number + EventID::number_type m_currentLB; //!< current lumiblock + const EventInfo* m_currentEvent; //!< current EventInfo object in StoreGate + + /// Start of Run Time: posix time in seconds since 1970/01/01 + /// Start of Run Time: time stamp ns - ns time offset for time_stamp, 32 bit unsigned + std::vector<EventID::number_type> m_sorTime_stamp; + + /// detector mask0,1,2,3 - bit field indicating which TTC zones have been + /// built into the event, one bit per zone, 128 bit total + /// significance increases from first to last + typedef EventID::number_type numt; + std::tuple<numt, numt, numt, numt> m_detector_mask; + + uint32_t m_l1_hltPrescaleUpdateLB; //!< LB of prescale update from CTP fragment + + // --------------------------- Monitoring Histograms -------------------------- + TH1F* m_hist_eventAcceptFlags; //!< Accept flags for processed events + TH1F* m_hist_frameworkErrorCodes; //!< PSC error codes + TH1F* m_hist_Hlt_result_size; //!< size of HLT result + TH1F* m_hist_Hlt_result_status; //!< Status flags in HLT result + TH1F* m_hist_numStreamTags; //!< Number of StreamTags from HLT + TH1F* m_hist_streamTagTypes; //!< StreamTag types from HLT + TH1F* m_hist_streamTagNames; //!< StreamTag names from HLT + TH1F* m_hist_num_partial_eb_robs; //!< Number of ROBs for partial event building from HLT + TH1F* m_hist_num_partial_eb_SubDetectors; //!< Number of SubDetectors for partial event building from HLT + TH1F* m_hist_partial_eb_SubDetectors_ROBs;//!< SubDetectors for partial event building derived from ROB list + TH1F* m_hist_partial_eb_SubDetectors_SDs; //!< SubDetectors for partial event building derived from SubDetector list + TH1F* m_hist_Hlt_result_size_physics; //!< size of HLT result in physics Main + TH1F* m_hist_Hlt_result_size_express; //!< size of HLT result in express stream + TH1F* m_hist_Hlt_result_size_DataScouting; //!< size of HLT result in express stream + TProfile* m_hist_HltResultSizes_Stream_physics; //!< HLT Result sizes for physiscs streams + TProfile* m_hist_HltResultSizes_Stream_DataScouting;//!< HLT Result sizes for DataScouting streams + TProfile* m_hist_HltEdmSizes_No_Truncation; //!< HLT EDM sizes for all events without a truncated HLT result + TProfile* m_hist_HltEdmSizes_With_Truncation; //!< HLT EDM sizes for all events with a truncated HLT result + TProfile* m_hist_HltEdmSizes_TruncatedResult_Retained_Collections; //!< HLT EDM sizes for all collections which were retained in a truncated HLT result + TProfile* m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections;//!< HLT EDM sizes for all collections which were truncated in a truncated HLT result + // --------------------------- Properties ------------------------------------- + BooleanProperty m_setMagFieldFromPtree; //!< Read magnet currents from ptree + StringProperty m_applicationName; //!< Application Name (="None" or "athenaHLT" for simulated data, "HLTMPPU-xx"? in online environment) */ + StringProperty m_partitionName; //!< Partition Name (="None" for offline, real partion name in online environment) + BooleanProperty m_forceHltReject; // force reject of all events + BooleanProperty m_forceHltAccept; // force accept of all events + StringProperty m_HltResultName; // name of HLT result in StoreGate + StringProperty m_HltDebugStreamName; // stream name for Debug events + StringProperty m_HltForcedStreamName; // stream name for forced accept events + IntegerProperty m_predefinedLumiBlock; + IntegerProperty m_prepareForRunSleep; //!< max random sleep during prepareForRun in sec + + typedef SimpleProperty< std::vector<uint32_t> > Uint32ArrayProperty; + Uint32ArrayProperty m_enabledROBs; //!< list of all enabled ROBs which can be retrieved + Uint32ArrayProperty m_enabledSubDetectors; //!< list of all enabled Sub Detectors which can be retrieved + Uint32ArrayProperty m_mandatoryL1ROBs; //!< list of mandatory ROB IDs coming from the RoIB (must come in L1R seed) + + StringArrayProperty m_hltEdmCollectionNames; //!< names of all HLT EDM collections for histogram label + + StringProperty m_jobOptionsType; //!< JobOptions type (="NONE" or "DB", same as in PSC) + + Histo1DProperty m_histProp_Hlt_result_size; + Histo1DProperty m_histProp_numStreamTags; + Histo1DProperty m_histProp_streamTagNames; + Histo1DProperty m_histProp_num_partial_eb_robs; + Histo1DProperty m_histProp_Hlt_Edm_Sizes; //!< HLT EDM sizes profile plots + + int m_total_evt; + int m_failed_evt; + int m_invalid_lvl1_result; + int m_invalid_hlt_result; + int m_truncated_hlt_result; + int m_truncated_hlt_result_to_debug; + int m_truncated_hlt_result_not_to_debug; + + // for CTP Lvl1 Rob + std::vector<uint32_t> m_ctpRobIdVec ; + // event number - 32 bit unsigned + uint32_t m_lvl1id ; + // run number - 32 bit unsigned + EventID::number_type m_run_no ; + // bunch crossing ID, 32 bit unsigned + EventID::number_type m_bunch_crossing_id ; + // time stamp - posix time in seconds from 1970, 32 bit unsigned + EventID::number_type m_time_stamp ; + // time stamp ns - ns time offset for time_stamp, 32 bit unsigned + EventID::number_type m_time_stamp_ns_offset ; + // luminosity block identifier, 32 bit unsigned + EventID::number_type m_lumi_block ; + // status element + TriggerInfo::number_type m_l1_Status_Element ; + // LVL1 trigger type + TriggerInfo::number_type m_l1_Trigger_Type ; + // LVL1 trigger info + std::vector<TriggerInfo::number_type> m_l1_Trigger_Info ; + // LVL1 detev type + uint32_t m_l1_detev_type ; + + /// Reference to a THistSvc which implements also the Hlt additions + SmartIF<IHltTHistSvc> m_hltTHistSvc; + + /// Reference to a ROBDataProviderSvc which implements also the Hlt additions + SmartIF<ITrigROBDataProviderSvc> m_hltROBDataProviderSvc; + + /// Check integrity of CTP ROB and put event to debug stream when it fails + BooleanProperty m_lvl1CTPROBcheck ; + + /// Monitoring + TH1F* m_hist_l1_robs; + + /// Flag to write events with truncated HLT result to a special debug stream + BooleanProperty m_writeHltTruncationToDebug ; + /// Debug stream name for events with a truncated HLT result + StringProperty m_HltTruncationDebugStreamName; + /// Stream names for which events should be not send to the debug stream even when the HLT result is truncated + StringArrayProperty m_excludeFromHltTruncationDebugStream; + /// Monitoring histogram for truncated HLT results + TH1F* m_hist_Hlt_truncated_result; + + /// we need this maintain the data + uint32_t m_status_words[3]; + +}; + +//========================================================================= +inline StatusCode HltEventLoopMgr::start() +{ + // This method might be called by ServiceManager::start and does nothing. + // The real start method is prepareForRun and invoked by the PSC. + return StatusCode::SUCCESS; +} + +//========================================================================= +inline void +HltEventLoopMgr::HltSetPscError(hltinterface::HLTResult& hlt_result, + hltonl::PSCErrorCode pscErrorCode) const +{ + hlt_result.psc_errors.push_back(pscErrorCode); +} + +#endif // TRIGSERVICES_HLTEVENTLOOPMGR_H diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h new file mode 100644 index 00000000000..1a336a23814 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h @@ -0,0 +1,224 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGSERVICES_HLTROBDATAPROVIDERSVC_H +#define TRIGSERVICES_HLTROBDATAPROVIDERSVC_H + +/** =============================================================== + * HltROBDataProviderSvc.h + * =============================================================== + * Description: ROBDataProvider class for accessing ROBData + * To be used for Offline/Online + * + * Requirements: define a ROBData class in the scope + * provide a method + * void getROBData(const vector<uint>& ids, vector<ROBData*>& v) + * Implementation: Use an interal map to store all ROBs + * We can not assume any ROB/ROS relationship, no easy + * way to search. + * + * Created: Sept 19, 2002 + * By: Hong Ma + * Modified: Aug. 18 2003 (common class for Online/Offline) + * By: Werner Wiedenmann + * Modified: Apr 21 2005 (implementation for online) + * By: Werner Wiedenmann + * Modified: Jun. 02 2006 (added monitoring horograms) + * By: Tomasz Bold + * Modified: May 21 2007 (updates for release 13) + * By: Werner Wiedenmann + * Modified: Nov. 10 2008 (updates for L2/EF result node ID handling) + * By: Werner Wiedenmann + * Modified: Mar. 05, 2013 (adapted from L2 for merged HLT) + * By: Ricardo Abreu + * Modified: Nov. 04, 2013 (implement complete hltinterface definitions) + * By: Werner Wiedenmann + */ +#include "GaudiKernel/Service.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/IIncidentListener.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/HistoProperty.h" +#include "GaudiKernel/Property.h" +#include "TrigROBDataProviderSvc/ITrigROBDataProviderSvc.h" +#include "ByteStreamCnvSvcBase/ROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "TrigDataAccessMonitoring/ROBDataMonitor.h" +#include "eformat/Status.h" +#include "hltinterface/DCM_ROBInfo.h" +#include <vector> +#include <map> + +// Forward declarations +class StoreGateSvc; +class IAlgContextSvc; +class TH1F; /// for monitoring purposes +class TH2F; /// for monitoring purposes + +class HltROBDataProviderSvc : public ROBDataProviderSvc, + virtual public ITrigROBDataProviderSvc, + virtual public IIncidentListener +{ +public: + + typedef OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment ROBF ; + + HltROBDataProviderSvc(const std::string& name, ISvcLocator* svcloc); + + virtual ~HltROBDataProviderSvc(void); + + virtual StatusCode initialize(); + + virtual StatusCode finalize(); + + virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ); + + /// --- Implementation of IROBDataProviderSvc interface --- + + /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector + virtual void addROBData(const std::vector<uint32_t>& robIds, + const std::string callerName="UNKNOWN"); + + /// Add a given LVL1/HLT ROBFragment to cache + virtual void setNextEvent(const std::vector<ROBF>& result); + + /// Add all ROBFragments of a RawEvent to cache + virtual void setNextEvent(const RawEvent* re); + + /// Retrieve ROBFragments for given ROB ids from cache + virtual void getROBData(const std::vector<uint32_t>& robIds, + std::vector<const ROBF*>& robFragments, + const std::string callerName="UNKNOWN"); + + /// Retrieve the whole event. + virtual const RawEvent* getEvent() ; + + /// --- Implementation of ITrigROBDataProviderSvc interface --- + + /// Return vector with all ROBFragments stored in the cache + virtual void getAllROBData(std::vector<const ROBF*>& robFragments) ; + + // Dump ROB cache + virtual std::string dumpROBcache() const ; + + /// Return size of ROBFragments cache + virtual int sizeROBCache() { return m_online_robmap.size(); } + + /// iterators over cache entries + virtual std::map<uint32_t, ROBF>::iterator beginROBCache() { return m_online_robmap.begin(); } + virtual std::map<uint32_t, ROBF>::iterator endROBCache() { return m_online_robmap.end(); } + + /// Flag to check if complete event data are already in cache + virtual bool isEventComplete() { return m_isEventComplete; } + + /// Collect all data for an event from the ROS and put them into the cache + /// Return value: number of ROBs which were retrieved to complete the event + /// Optinonally the name of the caller of this method can be specified for cost monitoring + virtual int collectCompleteEventData(const std::string callerName="UNKNOWN"); + + /// set the name of the program which uses the ROBDataProviderSvc + virtual void setCallerName(const std::string); + + /// get the name of the program which is presently registered in the ROBDataProviderSvc + virtual std::string getCallerName() { return m_callerName; }; + + /// --- Implementation of IIncidentListener interface --- + + // handler for BeginRun actions + void handle(const Incident& incident); + +protected: + /** + * @brief Accessor method for the MsgStream. + * @return handle to the MsgStream. + */ + inline MsgStream& logStream() const { return *m_msg; } + + /** + * @brief Accessor method for the message level variable. + * @return value of the message level for this algorithm. + */ + inline MSG::Level logLevel() const { return (m_msg != 0) ? m_msg->level() : MSG::NIL; } + +private: + typedef ServiceHandle<StoreGateSvc> StoreGateSvc_t; + /// Reference to StoreGateSvc; + StoreGateSvc_t m_storeGateSvc; + + /// Pointer to AlgContextSvc + IAlgContextSvc* m_algContextSvc; + + typedef SimpleProperty< std::vector<uint32_t> > Uint32ArrayProperty; + typedef SimpleProperty< std::map<int,int> > IntegerMapProperty; + + // flag indicates if running in online/offline + bool m_onlineRunning ; + + // read enabled ROBs from OKS when possible + BooleanProperty m_readROBfromOKS; + + // list of all enabled ROBs which can be retrieved + Uint32ArrayProperty m_enabledROBs; + + // list of ROBs which should be ignored for retrieval + Uint32ArrayProperty m_ignoreROB; + + // list of all LAr MET ROBs which can be retrieved + Uint32ArrayProperty m_enabledLArMetROBs ; + UnsignedIntegerProperty m_genericLArMetModuleID ; + + // list of all Tile MET ROBs which can be retrieved + Uint32ArrayProperty m_enabledTileMetROBs; + UnsignedIntegerProperty m_genericTileMetModuleID ; + + // Separate data collector calls to ROS for normal ROBs and MET ROBs + BooleanProperty m_separateMETandDetROBRetrieval ; + + // Filter out empty ROB fragments which are send by the ROS + bool m_removeEmptyROB; + + // map for all the ROB fragments (cache for ROB data so that they are + // not deleted when local containers go out of scope) + typedef std::map<uint32_t, ROBF> ONLINE_ROBMAP; + ONLINE_ROBMAP m_online_robmap; + + // helper function to retrieve ROB fragments over the network and to add them to the cache + void addROBDataToCache(std::vector<uint32_t>& robIdsForRetrieval, // vector of ROBs to retrieve + robmonitor::ROBDataMonitorStruct* p_robMonStruct); // pointer to ROB monitoring structure for retrieval + + // helper function to put retrieved ROB fragments into the local cache and update the monitoring records + void updateROBDataCache(std::vector<hltinterface::DCM_ROBInfo>& vRobInfo, // vector of ROB Info records with retrieved fragments + robmonitor::ROBDataMonitorStruct* p_robMonStruct); // pointer to ROB monitoring structure + + // Flag to indicate if all event data are already in the cache + bool m_isEventComplete; + + // name of the program which presently uses the ROBDataProviderSvc + std::string m_callerName; + + /** @brief Pointer to MsgStream.*/ + MsgStream* m_msg; + + // monitoring + std::map<eformat::GenericStatus, std::string> m_map_GenericStatus; + std::vector<std::string> m_vec_SpecificStatus; + + BooleanProperty m_doMonitoring; + BooleanProperty m_doDetailedROBMonitoring; + StringProperty m_ROBDataMonitorCollection_SG_Name; + + Histo1DProperty m_histProp_requestedROBsPerCall; + Histo1DProperty m_histProp_receivedROBsPerCall; + Histo1DProperty m_histProp_timeROBretrieval; + + TH1F* m_hist_requestedROBsPerCall; + TH1F* m_hist_receivedROBsPerCall; + TH1F* m_hist_timeROBretrieval; + TH2F* m_hist_genericStatusForROB; + TH2F* m_hist_specificStatusForROB; +}; + +#endif diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigHLTIssues.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigHLTIssues.h new file mode 100644 index 00000000000..3e282bed7f2 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigHLTIssues.h @@ -0,0 +1,37 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file TrigHLTIssues.h + * @author <a href="mailto:Werner.Wiedenmann@cern.ch">Werner Wiedenmann</a> + * + * @brief ERS issue classes for HLT + */ + +#ifndef TRIG_HLT_ISSUES_H +#define TRIG_HLT_ISSUES_H + +#include "ers/ers.h" + +ERS_DECLARE_ISSUE( ers, HLTMessage, , ) +ERS_DECLARE_ISSUE( ers, HLTAbort, "Fatal error during event processing", ) + +#define ERS_HLT_WARNING( message ) \ +{ \ + ERS_REPORT_IMPL( ers::warning, ers::HLTMessage, message, ); \ +} + +#define ERS_HLT_ERROR( message ) \ +{ \ + ERS_REPORT_IMPL( ers::error, ers::HLTMessage, message, ); \ +} + +#define ERS_HLT_FATAL( message ) \ +{ \ + ERS_REPORT_IMPL( ers::fatal, ers::HLTMessage, message, ); \ +} + +#endif /* TRIG_HLT_ISSUES_H */ diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigIS.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigIS.h new file mode 100644 index 00000000000..31ecb9f5e7a --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigIS.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGSERVICES_TRIGIS_H +#define TRIGSERVICES_TRIGIS_H + +/**@class TrigIS + * @brief IS publication service + * + * This service is a simple wrapper around ISInfoDictionary. Mainly to handle + * exceptions and to setup the IPC infrastrucure. In addition, it may provide + * asynchronous publishing (currently not implemented). By default the ownership + * of the ISInfo object remains with the client. Hoever, for asynchronous publishing + * this service takes the ownership and deletes the objects after publication. + * + * @author Frank Winklmeier + * @version $Id: TrigIS.h 5 2013-05-14 10:33:04Z ricab $ + */ + +#include "TrigKernel/ITrigIS.h" +#include "AthenaBaseComps/AthService.h" + +#undef PACKAGE_VERSION +#include "ipc/partition.h" +#include "is/infodictionary.h" + +// Forward declarations +class IPCPartition; +class ISInfoDictionary; +class ISInfo; + +template <class TYPE> class SvcFactory; + +class TrigIS : virtual public ITrigIS, + public AthService { + +public: + TrigIS(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~TrigIS(); + + /* + * Publish ISInfo object + * + * Forwards to IsInfoDictionary::checkin and catches exceptions. + * Ownership of info remains with caller. + */ + virtual StatusCode publish(const std::string& name, const ISInfo& info, bool keep_history=false); + + /* + * Same as publish but might publish ISInfo object asynchronously. + * Ownership of info is transfered to this service. + */ + virtual void publish_async(const std::string& name, ISInfo* info, bool keep_history=false); + + /* + * Return reference to ISInfoDictionary + */ + virtual ISInfoDictionary& infoDict() { return m_isDict; } + + virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ); + virtual StatusCode initialize(); + +protected: + friend class SvcFactory<TrigIS>; + + /// default constructor (do not use) + TrigIS(); + +private: + IPCPartition m_partition; + ISInfoDictionary m_isDict; + bool m_validPartition; + + /* Properties */ + std::string m_partitionName; ///< partition name +}; + +#endif diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigISHelper.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigISHelper.h new file mode 100644 index 00000000000..53b82877f07 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigISHelper.h @@ -0,0 +1,211 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGSERVICES_TRIGISHELPER_H +#define TRIGSERVICES_TRIGISHELPER_H + +/** + * @file TrigISHelper.h + * @brief Helper tool for IS access + * @author Frank Winklmeier, Werner Wiedenmann + * + * $Id: TrigISHelper.h 5 2013-05-14 10:33:04Z ricab $ + */ + +// STL includes +#include <string> +#include <vector> +#include <map> +#include <utility> + +// Framework includes +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/StatusCode.h" + +// To avoid compiler warnings about redefinition through omni includes +#undef PACKAGE_VERSION +// TDAQ includes +#include "is/info.h" +#include "is/infodictionary.h" +#include "is/infodynany.h" +#include "ipc/partition.h" + + +/** + * @brief Helper tool for IS access + * + * This tool wraps some of the IS methods. Mainly to allow for configurable + * partition and IS names. Use the properties (e.g. RunParams) to specify + * them: + * + * Example: TrigISHelper.MyISInfo = initial/MyISServer.ISInfoName + * + * This will read the IS value from partition initial. If no partition is + * explicitly specified use the value of the PartitionName property. + */ +class TrigISHelper : public AthAlgTool { + +public: + /// Aliases for IS objects this tool can read + enum ISObject { + RunParams, + LumiBlock, + SolenoidCurrent, + ToroidCurrent + }; + +public: + + TrigISHelper(const std::string &type, const std::string &name, const IInterface *parent); + virtual ~TrigISHelper(); + + static const InterfaceID& interfaceID(); + virtual StatusCode initialize(); + + /** + * @brief Wrapper for ISInfoDictionary::findValue + * + * Main difference to the IS method is that it returns immediatelly + * if running without a partition. + * + * @param name Name of IS value + * @param value Filled with IS value + * + * @return SUCCESS Value retrieved or running without partition + * FAILURE Could not retrieve value from IS + */ + StatusCode findValue(ISObject obj, ISInfo& value); + + /** + * @brief Get attributes of a given type for IS objects + * + * This method retrieves all attributes of type T from the + * given IS object. This can be used in case there is no IS type + * definition available. + * + * @param name Name of IS value + * @param values Vector to be filled with attributes of type T + * + * @return SUCCESS Value retrieved or running without partition + * FAILURE Could not retrieve value from IS + */ + template <class T> + StatusCode getAttributes(ISObject obj, std::vector<T>& values); + + /** + * @brief Read attribute of an ISNamedInfo object + * + * T is the type of the ISNamedInfo object, R the value type and + * G is a function object that reads the attribute of T. + * + * @param name Name of IS value + * @param value Filled with value of attribute + * @param getter Functor of type 'void (const T& t, R& r)' that fills r + * with the value of an attribute of t. + * + * @return SUCCESS Value retrieved or running without partition + * FAILURE Could not retrieve value from IS + */ + template <class T, class R, class G> + StatusCode findValue(ISObject obj, R& value, G getter); + + /* + * Check if partition for ISObject obj is valid (!= 'none') + */ + bool validPartition(ISObject obj); + + const std::string& partition(ISObject obj) const; + const std::string& isName(ISObject obj) const; + +private: + // Properties + StringProperty m_partitionName; ///< Default partition name + bool m_ignoreIfMissing; + std::map<ISObject, std::string> m_isprop; ///< Names of IS objects + + /// Property handler + void initPartitionName(Property& prop); + + /// Map ISObject -> (partition, IS name) + typedef std::map<ISObject, std::pair<std::string, std::string> > ISObjectMap_t; + ISObjectMap_t m_isid; ///< partition and IS name for each ISObject + + /// Return (partition, IS) name pair from isid property + std::pair<std::string,std::string> split(const std::string& isid); +}; + + +//-------------------------------------------------------------------------------- +// Inline +//-------------------------------------------------------------------------------- +inline bool TrigISHelper::validPartition(ISObject obj) +{ + const std::string& name = m_isid[obj].first; + return (name!="None" && name!="NONE"); +} + + +inline const InterfaceID& TrigISHelper::interfaceID() +{ + static const InterfaceID _IID("TrigISHelper", 1, 0); + return _IID; +} + +//-------------------------------------------------------------------------------- +// Templates +//-------------------------------------------------------------------------------- +template <class T, class R, class G> +StatusCode TrigISHelper::findValue(ISObject obj, R& value, G getter) +{ + const std::string& partName = m_isid[obj].first; + const std::string& isName = m_isid[obj].second; + + try { + IPCPartition part(partName); + T namedInfo(part, isName); + namedInfo.checkout(); + getter(namedInfo, value); // set 'value' + } + catch (daq::is::Exception& e) { + msg() << MSG::WARNING << "IS Exception reading " << isName << " from partition " + << partName << ". Exception was: " << e.what() << endreq; + + return m_ignoreIfMissing ? StatusCode::SUCCESS : StatusCode::FAILURE; + } + + if ( msgLvl(MSG::DEBUG) ) { + msg() << MSG::DEBUG << "Successfully read " << isName << " from IS: " << value << endreq; + } + return StatusCode::SUCCESS; +} + + +template <class T> +StatusCode TrigISHelper::getAttributes(ISObject obj, std::vector<T>& values) +{ + const std::string& partName = m_isid[obj].first; + const std::string& isName = m_isid[obj].second; + + ISInfoDynAny ida; + try { + IPCPartition part(partName); + ISInfoDictionary isInfoDict(part); + isInfoDict.findValue(isName, ida); + } + catch (daq::is::Exception e) { + msg() << MSG::WARNING << "IS Exception reading " << isName << " from partition " + << partName << ". Exception was: " << e.what() << endreq; + + return m_ignoreIfMissing ? StatusCode::SUCCESS : StatusCode::FAILURE; + } + + for (size_t i=0; i<ida.getAttributesNumber(); ++i) { + if ( is::type2id<T>::id == ida.getAttributeType(i) ) { + values.push_back(ida.getAttributeValue<T>(i)); + } + } + return StatusCode::SUCCESS; +} + +#endif diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigMessageSvc.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigMessageSvc.h new file mode 100644 index 00000000000..8666170d971 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigMessageSvc.h @@ -0,0 +1,226 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file TrigMessageSvc.h + * + * $Id: TrigMessageSvc.h 5 2013-05-14 10:33:04Z ricab $ + */ +#ifndef TRIGSERVICES_TRIGMESSAGESVC_H +#define TRIGSERVICES_TRIGMESSAGESVC_H + +// Include files +#include <string> +#include <vector> +#include <map> + +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/Service.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/IMessageSvc.h" +#include "GaudiKernel/IIncidentListener.h" +#include "GaudiKernel/Message.h" +#include "GaudiKernel/Property.h" + +#include "StoreGate/StoreGateSvc.h" + +#include "TrigKernel/ITrigMessageSvc.h" + +// Forward declarations +class ISvcLocator; +class TH1I; +class TH2I; + +/**@class TrigMessageSvc + * @brief MessageSvc used by the HLT applications + * + * This MessageSvc implementation it used by the HLT applications. It has some additional + * features compared to the default Gaudi MessageSvc. Most notably the forwarding of messages + * to the TDAQ ERS message system. + * + * The message suppression is configured with the following parameters: + * @param <level>Limit = 0: no message suppression for <level> + * @param <level>Limit = N > 0: suppress messages after N messages (per source) + * @param <level>Limit = -N < 0: use logarithmic suppression after N messages (per message) + * + * Note, that the logarithmic suppression works on a per-message basis (ignoring any digits + * in the message). + * + * @author Iain Last, Werner Wiedenmann, Frank Winklmeier + */ + +class TrigMessageSvc : public Service, + virtual public IMessageSvc, + virtual public ITrigMessageSvc, + virtual public IIncidentListener { +public: + typedef std::pair< std::string, std::ostream* > NamedStream; + typedef std::multimap< int, NamedStream > StreamMap; + typedef std::multimap< StatusCode, Message > MessageMap; + typedef std::map< std::string, int > ThresholdMap; + + // Default constructor. + TrigMessageSvc( const std::string& name, ISvcLocator* svcloc ); + // Destructor. + virtual ~TrigMessageSvc(); + + // Implementation of IService::reinitialize() + virtual StatusCode reinitialize(); + // Implementation of IService::initialize() + virtual StatusCode initialize(); + // Implementation of IService::finalize() + virtual StatusCode finalize(); + + // Implementation of IMessageSvc::reportMessage() + virtual void reportMessage( const Message& message ); + + // Implementation of IMessageSvc::reportMessage() + virtual void reportMessage( const Message& message, int outputLevel ); + + // Implementation of IMessageSvc::reportMessage() + virtual void reportMessage( const StatusCode& code, const std::string& source = ""); + + // Implementation of IMessageSvc::reportMessage() + virtual void reportMessage( const char* source, int type, const char* message); + + // Implementation of IMessageSvc::reportMessage() + virtual void reportMessage( const std::string& source, int type, const std::string& message); + + // Implementation of IMessageSvc::insertMessage() + virtual void insertMessage( const StatusCode& code, const Message& message ); + + // Implementation of IMessageSvc::eraseMessage() + virtual void eraseMessage(); + + // Implementation of IMessageSvc::eraseMessage() + virtual void eraseMessage( const StatusCode& code ) ; + + // Implementation of IMessageSvc::eraseMessage() + virtual void eraseMessage( const StatusCode& code, const Message& message ); + + // Implementation of IMessageSvc::insertStream() + virtual void insertStream( int message_type, const std::string& name, std::ostream* stream ); + + // Implementation of IMessageSvc::eraseStream() + virtual void eraseStream(); + + // Implementation of IMessageSvc::eraseStream() + virtual void eraseStream( int message_type ); + + // Implementation of IMessageSvc::eraseStream() + virtual void eraseStream( int message_type, std::ostream* stream ); + + // Implementation of IMessageSvc::eraseStream() + virtual void eraseStream( std::ostream* stream ); + + // Implementation of IMessageSvc::desaultStream() + virtual std::ostream* defaultStream() const { + return m_defaultStream; + } + + // Implementation of IMessageSvc::setDefaultStream() + virtual void setDefaultStream( std::ostream* stream ) { + m_defaultStream = stream; + } + + // Implementation of IMessageSvc::ouputLevel() + virtual int outputLevel() const; + + // Implementation of IMessageSvc::ouputLevel() + virtual int outputLevel(const std::string& source) const; + + // Implementation of IMessageSvc::setOuputLevel() + virtual void setOutputLevel(int new_level); + + // Implementation of IMessageSvc::setOuputLevel() + virtual void setOutputLevel(const std::string& source, int new_level); + + // Implementation of IInterface::queryInterface() + virtual StatusCode queryInterface(const InterfaceID& riid, void** ppvUnknown); + + // Implementation of IMessageSvc::useColor() + virtual bool useColor() const { return m_color; } + + // Implementation of IMessageSvc::getLogColor() + virtual std::string getLogColor(int logLevel) const; + + // Implementation of IMessageSvc::messageCount() + virtual int messageCount( MSG::Level logLevel ) const; + + /// \name ITrigMessageSvc implementation + //@{ + /// Reset all individual output levels + virtual void resetOutputLevels(); + //@} + + // Implemenation of IIncidentListener::handle() + virtual void handle(const Incident& inc); + +private: + typedef std::map<std::string, MSG::Color> ColorMap; + typedef std::map< unsigned int, unsigned int > MsgCountMap; + + std::ostream* m_defaultStream; ///< Pointer to the output stream. + Message m_defaultMessage; ///< Default Message + StreamMap m_streamMap; ///< Stream map + MessageMap m_messageMap; ///< Message map + ThresholdMap m_thresholdMap; ///< Output level threshold map + std::string m_defaultFormat; ///< Default format for the messages + std::string m_defaultTimeFormat; ///< Default time format for the messages + int m_defaultLimit; ///< Original default message limit + bool m_doSuppress; ///< Message suppression currently active? + bool m_running; ///< In RUNNING state + bool m_canEnter; ///< used to avoid infinite recursions + + ServiceHandle<StoreGateSvc> m_evtStore; ///< Event store + + /* Properties */ + StringArrayProperty m_thresholdProp[MSG::NUM_LEVELS]; + StringArrayProperty m_logColors[MSG::NUM_LEVELS]; + UnsignedIntegerProperty m_statLevel; + UnsignedIntegerProperty m_statLevelRun; + UnsignedIntegerProperty m_publishLevel; + UnsignedIntegerProperty m_eventIDLevel; + IntegerProperty m_msgLimit[MSG::NUM_LEVELS]; + BooleanProperty m_color; + BooleanProperty m_stats; + BooleanProperty m_publishStats; + BooleanProperty m_resetStats; + StringArrayProperty m_useERS[MSG::NUM_LEVELS]; + BooleanProperty m_alwaysUseMsgStream; + BooleanProperty m_useErsRunningOnly; + BooleanProperty m_suppress; + BooleanProperty m_suppressRunningOnly; + BooleanProperty m_forceOutputLevel; + + /* Message colors */ + std::string m_logColorCodes[MSG::NUM_LEVELS]; + std::string colTrans(std::string, int); + ColorMap m_colMap; + + /* Message counting */ + struct msgAry { int msg[MSG::NUM_LEVELS]; }; + std::map<std::string, msgAry> m_sourceMap; ///< Current message counting per source + std::map<std::string, msgAry> m_sourceMapTotal; ///< Total message counting per source + int m_msgCount[MSG::NUM_LEVELS]; ///< Message counting per level + MsgCountMap m_msgCountMap; ///< Message counting per message + TH1I* m_msgCountHist; ///< Message counting per level histogram + TH2I* m_msgCountSrcHist; ///< Message counting per message source + + /* Update handlers */ + void initColors(Property& prop); + void setupColors(Property& prop); + void setupLimits(Property& prop); + void setupThreshold(Property& prop); + void setupSuppression(Property& prop); + + unsigned int msgHash(const Message& msg); ///< Hash of message (for log. suppression) + void resetMsgStats(); ///< Reset message statistics + void reportMsgStats(uint statLevel, bool total=false); ///< Report message statistics + void setOutputLevelViaJobOptSvc(); ///< Change OutputLevel properties in JobOptionsSvc + void bookHistograms(); ///< Book histograms for message statistics + bool passErsFilter(const std::string& source, const std::vector<std::string>& filter); ///< Source passes ERS filter? +}; + +#endif diff --git a/HLT/Trigger/TrigControl/TrigServices/cmt/requirements b/HLT/Trigger/TrigControl/TrigServices/cmt/requirements new file mode 100755 index 00000000000..48161de2595 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/cmt/requirements @@ -0,0 +1,49 @@ +package TrigServices + +author W. Wiedenmann <Werner.Wiedenmann@cern.ch> +author Frank Winklmeier <Frank.Winklmeier@cern.ch> +author Ricardo Abreu <Ricardo.Abreu@cern.ch> + +use AtlasPolicy AtlasPolicy-* +use GaudiInterface GaudiInterface-* External +use AthenaKernel AthenaKernel-* Control +use StoreGate StoreGate-* Control +use TrigKernel TrigKernel-* HLT/Trigger/TrigControl +use EventInfo EventInfo-* Event +use xAODEventInfo xAODEventInfo-* Event/xAOD +use AthenaBaseComps AthenaBaseComps-* Control +use TrigSteeringEvent TrigSteeringEvent-* Trigger/TrigEvent +use TrigDataAccessMonitoring TrigDataAccessMonitoring-* Trigger/TrigDataAccess +use TrigROBDataProviderSvc TrigROBDataProviderSvc-* Trigger/TrigDataAccess +use ByteStreamCnvSvcBase ByteStreamCnvSvcBase-* Event +use ByteStreamData ByteStreamData-* Event +use DataCollection DataCollection-* External +use HLTtdaq HLTtdaq-* HLT/HLTExternal +use HLTtdaqcommon HLTtdaqcommon-* HLT/HLTExternal + +private +use AtlasBoost AtlasBoost-* External +use AtlasROOT AtlasROOT-* External +use AtlasCORAL AtlasCORAL-* External +use AthenaPoolUtilities AthenaPoolUtilities-* Database/AthenaPOOL +use TrigInterfaces TrigInterfaces-* Trigger/TrigSteer +use TrigConfInterfaces TrigConfInterfaces-* Trigger/TrigConfiguration +use TrigMonitorBase TrigMonitorBase-* Trigger/TrigMonitoring +use TrigNavigation TrigNavigation-* Trigger/TrigEvent +use CLIDSvc CLIDSvc-* Control +use CTPfragment * +end_private + +apply_pattern dual_use_library files="*.cxx" + +apply_pattern declare_joboptions files="*.py" + +apply_pattern declare_python_modules files="*.py" + +#--- leave this as public +macro_append TrigServices_linkopts \ + " $(HLTtdaq_linkopts) -lers -leformat -leformat_write " + +private +macro_append TrigServices_linkopts " $(Boost_linkopts) $(Boost_linkopts_regex) " +macro_append TrigServices_linkopts " $(HLTtdaq_linkopts) -lhltinterface -lCTPfragment -lomniORB4 -lomnithread -lipc -lis -lowl " diff --git a/HLT/Trigger/TrigControl/TrigServices/python/HltTHistSvcConfig.py b/HLT/Trigger/TrigControl/TrigServices/python/HltTHistSvcConfig.py new file mode 100644 index 00000000000..f2568e66d00 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/python/HltTHistSvcConfig.py @@ -0,0 +1,28 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +from TrigServicesConf import HltTHistSvc + +# just a helper function +# def defineTHistSvcOutputFile(dir, name, service, opt='NEW'): +# if globals().has_key('numberOfThreads'): +# threads = globals()['numberOfThreads'] +# else: +# threads=0 + +# if threads.value() == 0: +# THistSvc = Service(service) +# THistSvc.Output += [dir+" DATAFILE=\'"+name+"' OPT=\'"+opt+"\'" ] +# return +# for n in range(0,threads.value()): +# threadID = '__%(#)d' % { '#': n} +# THistSvc = Service ( service+threadID ) +# THistSvc.Output += [dir+" DATAFILE=\'"+name+threadID+"' OPT=\'"+opt+"\'" ] + + +class HltTHistSvcConfig(HltTHistSvc): + def __init__(self, name='THistSvc'): + super(HltTHistSvcConfig, self).__init__(name) + self.Output += ["SHIFT DATAFILE='shift-monitoring.root' OPT='RECREATE'"] + self.Output += ["EXPERT DATAFILE='expert-monitoring.root' OPT='RECREATE'"] + self.Output += ["DEBUG DATAFILE='debug-monitoring.root' OPT='RECREATE'"] + self.Output += ["RUNSTAT DATAFILE='runstat-monitoring.root' OPT='RECREATE'"] diff --git a/HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py b/HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py new file mode 100644 index 00000000000..0e3b4824c04 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py @@ -0,0 +1,27 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# @file: TrigServicesConfig.py +# @purpose: customized configurables + +from TrigServicesConf import TrigCOOLUpdateHelper as _TrigCOOLUpdateHelper + +class TrigCOOLUpdateHelper(_TrigCOOLUpdateHelper): + __slots__ = () + + def __init__(self, name='TrigCOOLUpdateHelper'): + super(TrigCOOLUpdateHelper, self).__init__(name) + return + + def enable(self, folder='/TRIGGER/HLT/COOLUPDATE', tag=None): + """Enable the COOL folder updates (only use this for data)""" + + from AthenaCommon.AppMgr import ServiceMgr as svcMgr + if not hasattr(svcMgr,'IOVDbSvc'): return + + self.coolFolder = folder + from IOVDbSvc.CondDB import conddb + if tag==None: + conddb.addFolder('TRIGGER',self.coolFolder) + else: + conddb.addFolderWithTag('TRIGGER',self.coolFolder,tag) + diff --git a/HLT/Trigger/TrigControl/TrigServices/python/TriggerUnixStandardSetup.py b/HLT/Trigger/TrigControl/TrigServices/python/TriggerUnixStandardSetup.py new file mode 100644 index 00000000000..0b3d8e892d0 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/python/TriggerUnixStandardSetup.py @@ -0,0 +1,243 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +## @file TriggerUnixStandardSetup.py +## @brief py-module to configure the Athena AppMgr for trigger +## @author Werner Wiedenmann <Werner.Wiedenmann@cern.ch> +############################################################### + +class _Conf: + """Some configuration flags for this module with defaults""" + useOnlineTHistSvc = True # set via TrigServices/OfflineTHistSvc.py + athenaXT = False # set below in _setupCommonServices + + +def _setupRoot6IfNeeded(): + import cppyy + try: + # try to touch ROOT5-only attribute (success means we have ROOT5) + cppyy.Cintex.Debug + except AttributeError: + # ROOT 6 + from PyUtils.Helpers import ROOT6Setup + ROOT6Setup() + +def _eventLoopMgr(svcMgr): + if hasattr(svcMgr, 'HltEventLoopMgr'): return svcMgr.HltEventLoopMgr + return None + +def _setupCommonServices(): + from AthenaCommon.Constants import VERBOSE, DEBUG, INFO, ERROR + + # Add timestamp to python logger + from AthenaCommon.Logging import log + log.setFormat("%(asctime)s Py:%(name)-31s %(levelname)7s %(message)s") + + from AthenaCommon.Logging import logging + log = logging.getLogger( 'TriggerUnixStandardSetup::setupCommonServices:' ) + + # Do the default Atlas job configuration first + import AthenaCommon.AtlasUnixStandardJob + + # Now do HLT specific configuration + from AthenaCommon import CfgMgr + from AthenaCommon.AppMgr import theApp + from AthenaCommon.AppMgr import ServiceMgr as svcMgr + from AthenaCommon.AppMgr import ToolSvc + + # Check whether we are running in athenaXT + # Only a minimal set of properties should depend on this + import sys + if sys.modules.has_key('HLTTestApps'): + _Conf.athenaXT = True + log.debug("Configuration for athenaXT running") + else: + _Conf.athenaXT = False + log.debug("Configuration for online running") + + # setup ROOT6 if needed + _setupRoot6IfNeeded() + + # StoreGateSvc + svcMgr.StoreGateSvc.ActivateHistory = False + + # ProxyProviderSvc services configuration + svcMgr += CfgMgr.ProxyProviderSvc() + + # --- ByteStreamAddressProviderSvc configuration + svcMgr += CfgMgr.ByteStreamAddressProviderSvc() + svcMgr.ProxyProviderSvc.ProviderNames += [ "ByteStreamAddressProviderSvc" ] + theApp.CreateSvc += [ svcMgr.ByteStreamAddressProviderSvc.getFullName() ] + + # Initialization of DetDescrCnvSvc + svcMgr += CfgMgr.DetDescrCnvSvc( + # specify primary Identifier dictionary to be used + IdDictName = "IdDictParser/ATLAS_IDS.xml" + ) + theApp.CreateSvc += [ svcMgr.DetDescrCnvSvc.getFullName() ] + svcMgr.EventPersistencySvc.CnvServices += [ "DetDescrCnvSvc" ] + + # --- ByteStreamCnvSvc configuration + svcMgr += CfgMgr.ByteStreamCnvSvc("ByteStreamCnvSvc") + svcMgr.EventPersistencySvc.CnvServices += [ "ByteStreamCnvSvc" ] + + # Disable history + svcMgr += CfgMgr.HistorySvc() + svcMgr.HistorySvc.Activate = False + + # Configuration of Interval of Validity Service + svcMgr += CfgMgr.IOVSvc() + + # Configure TrigISHelper + from TrigServices.TrigServicesConf import TrigISHelper + ToolSvc += TrigISHelper("TrigISHelper") + + # Configure TrigPreFlightCheck + from TrigServices.TrigServicesConf import TrigPreFlightCheck + ToolSvc += TrigPreFlightCheck("TrigPreFlightCheck", + ReleaseDirs = ["AtlasP1HLT","AtlasHLT"] + ) + + # Configure CoreDumpSvc + if not hasattr(svcMgr,"CoreDumpSvc"): + from AthenaServices.Configurables import CoreDumpSvc + svcMgr += CoreDumpSvc() + + # Configure COOL update helper tool + from TrigServices.TrigServicesConfig import TrigCOOLUpdateHelper + _eventLoopMgr(svcMgr).CoolUpdateTool = TrigCOOLUpdateHelper() + + # Setup online THistSvc unless specifically configured otherwise + if _Conf.useOnlineTHistSvc: + if hasattr(svcMgr, 'THistSvc'): + log.fatal("The offline histogramming THistSvc is already in place.") + raise RuntimeError("Cannot setup online histogramming TrigMonTHistSvc") + log.debug("Using online histogramming service (TrigMonTHistSvc)") + from TrigServices.TrigServicesConf import TrigMonTHistSvc + svcMgr += TrigMonTHistSvc("THistSvc") + else: + log.debug("Using offline histogramming service (THistSvc)") + from GaudiSvc.GaudiSvcConf import THistSvc + svcMgr += THistSvc() + + # Explicitly set a few OutputLevels (needed because some services are created in + # different order when running with the PSC) + svcMgr.StatusCodeSvc.OutputLevel = theApp.OutputLevel + svcMgr.IncidentSvc.OutputLevel = theApp.OutputLevel + svcMgr.ProxyProviderSvc.OutputLevel = theApp.OutputLevel + svcMgr.StoreGateSvc.OutputLevel = theApp.OutputLevel + + return + + +def _setupCommonServicesEnd(): + from AthenaCommon.AppMgr import theApp + from AthenaCommon.AppMgr import ServiceMgr as svcMgr + from AthenaCommon.Logging import logging + from TriggerJobOpts.TriggerFlags import TriggerFlags + + log = logging.getLogger( 'TriggerUnixStandardSetup::setupCommonServicesEnd:' ) + + # --- create the ByteStreamCnvSvc after the Detector Description otherwise + # --- the initialization of converters fails + theApp.CreateSvc += [ svcMgr.ByteStreamCnvSvc.getFullName() ] + + # Make sure no THistSvc output/input stream is defined for online running + if _Conf.useOnlineTHistSvc: + svcMgr.THistSvc.Output = [] + if len(svcMgr.THistSvc.Input)>0: + log.error('THistSvc.Input = %s. Input not allowed for online running. Disabling input.' % svcMgr.THistSvc.Input) + svcMgr.THistSvc.Input = [] + + # For offline running make sure at least the EXPERT stream is defined + else: + if 1 not in [ o.count('EXPERT') for o in svcMgr.THistSvc.Output ]: + svcMgr.THistSvc.Output += ["EXPERT DATAFILE='expert-monitoring.root' OPT='RECREATE'"] + + + # Set default properties for some important services after all user job options + log.info('Configure core services for online runnig') + + svcMgr.CoreDumpSvc.CoreDumpStream = "stdout" + svcMgr.CoreDumpSvc.CallOldHandler = True + svcMgr.CoreDumpSvc.FatalHandler = 0 # no extra fatal handler + svcMgr.CoreDumpSvc.TimeOut = 0 # no timeout for stack trace generation + + # Disable StatusCodeSvc (causes problems with shutting down children at stop in HLTPU) + svcMgr.StatusCodeSvc.SuppressCheck = True + svcMgr.StatusCodeSvc.AbortOnError = False + + svcMgr.IOVSvc.updateInterval = "RUN" + svcMgr.IOVSvc.preLoadData = True + svcMgr.IOVSvc.forceResetAtBeginRun = False + + if hasattr(svcMgr,'IOVDbSvc'): + svcMgr.IOVDbSvc.CacheAlign = 0 # VERY IMPORTANT to get unique queries for folder udpates (see Savannah #81092) + svcMgr.IOVDbSvc.CacheRun = 0 + svcMgr.IOVDbSvc.CacheTime = 0 + + # Flag to extract trigger configuration + if TriggerFlags.Online.doDBConfig(): + from TrigConfigSvc import DoDBConfig + + # --- print out configuration details + _printConfiguration(log.name) + + return + +def _printConfiguration(loggerName): + from AthenaCommon.Constants import VERBOSE, DEBUG, INFO, ERROR + + from AthenaCommon.Logging import logging + if loggerName == '': + loggerName = 'TriggerUnixStandardSetup::_printConfiguration' + + log = logging.getLogger( loggerName ) + + # --- print out configuration details + # --- + from AthenaCommon.AppMgr import theApp + log.debug("---> Application Manager") + log.debug(theApp) + + from AthenaCommon.AppMgr import ServiceMgr as svcMgr + log.debug("---> Service Manager") + log.debug(svcMgr) + + from AthenaCommon.AlgSequence import AlgSequence + topSequence = AlgSequence() + log.debug("---> Algorithm Sequence") + log.debug(topSequence) + + return + +def setupHLTServicesBegin(): + from AthenaCommon import CfgMgr + from AthenaCommon.Constants import VERBOSE, DEBUG, INFO, ERROR + from AthenaCommon.AppMgr import theApp + from AthenaCommon.AppMgr import ServiceMgr as svcMgr + from AthenaCommon.Logging import logging + log = logging.getLogger( 'TriggerUnixStandardSetup::setupHLTServicesBegin:' ) + log.debug( "---> Start" ) + + # --- setup the standard services + _setupCommonServices() + + # --- Hlt ROBDataProvider configuration + svcMgr += CfgMgr.HltROBDataProviderSvc("ROBDataProviderSvc") + theApp.CreateSvc += [ svcMgr.ROBDataProviderSvc.getFullName() ] + + log.debug( "---> End" ) + return + +def setupHLTServicesEnd(): + from AthenaCommon.Constants import VERBOSE, DEBUG, INFO, ERROR + + from AthenaCommon.Logging import logging + log = logging.getLogger( 'TriggerUnixStandardSetup::setupHLTServicesEnd:' ) + log.debug( "---> Start" ) + + # --- final modifications to standard services + _setupCommonServicesEnd() + + log.debug( "---> End" ) + return diff --git a/HLT/Trigger/TrigControl/TrigServices/python/__init__.py b/HLT/Trigger/TrigControl/TrigServices/python/__init__.py new file mode 100644 index 00000000000..96403d7b4bb --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/python/__init__.py @@ -0,0 +1,6 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# File: TrigServices/__init__.py + +__version__ = '1.0.0' +__author__ = 'Werner.Wiedenmann@cern.ch' diff --git a/HLT/Trigger/TrigControl/TrigServices/share/MessageSvc.py b/HLT/Trigger/TrigControl/TrigServices/share/MessageSvc.py new file mode 100644 index 00000000000..cde14a414ff --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/share/MessageSvc.py @@ -0,0 +1,79 @@ +#************************************************************** +# +# MessageSvc configuration file +# +#============================================================== +from AthenaCommon.AppMgr import theApp +from AthenaCommon.AppMgr import ServiceMgr as svcMgr +from AthenaCommon.Constants import * + +# make the message service available +svcMgr.MessageSvc = theApp.service( "MessageSvc" ) # already instantiated +MessageSvc = svcMgr.MessageSvc + +MessageSvc.OutputLevel = OutputLevel + +# Use color for different message levels +# -------------------------------------- +MessageSvc.useColors = False + +# Format string for all messages +# ------------------------------ +MessageSvc.Format = "%t % F%35W%S%7W%R%T %0W%M" + +# Message suppression +# ------------------- +MessageSvc.enableSuppression = False +MessageSvc.suppressRunningOnly = True +MessageSvc.resetStatsAtBeginRun = True + +# 0 = no suppression, negative = log-suppression, positive = normal suppression +# Do not rely on the defaultLimit property, always set each limit separately +MessageSvc.defaultLimit = -100 +MessageSvc.verboseLimit = MessageSvc.defaultLimit +MessageSvc.debugLimit = MessageSvc.defaultLimit +MessageSvc.infoLimit = MessageSvc.defaultLimit +MessageSvc.warningLimit = MessageSvc.defaultLimit +MessageSvc.errorLimit = 0 +MessageSvc.fatalLimit = 0 + +# set message limit to unlimited when general DEBUG is requested +if (("OutputLevel" in dir()) and (OutputLevel<=DEBUG)) : + MessageSvc.defaultLimit = 0 + MessageSvc.enableSuppression = False +if (("HLTOutputLevel" in dir()) and (HLTOutputLevel<=DEBUG)) : + MessageSvc.defaultLimit = 0 + MessageSvc.enableSuppression = False + +# show summary statistics of messages in finalize +# ----------------------------------------------- +MessageSvc.showStats = True +MessageSvc.statLevel = WARNING +MessageSvc.statLevelRun = VERBOSE + +# publish message counts during RUNNING in histogram +# -------------------------------------------------- +MessageSvc.publishStats = True +MessageSvc.publishLevel = INFO + + +# report messages via ERS +# ----------------------- +# report given message severities via ERS +# MessageSvc.useErsVerbose = ['*'] +# MessageSvc.useErsDebug = ['*'] +# MessageSvc.useErsInfo = ['*'] +# MessageSvc.useErsWarning = ['*'] +# MessageSvc.useErsError = ['*'] +# MessageSvc.useErsFatal = ['*'] + +# Set to True, if ERS messages should be duplicated to the MsgStream +# MessageSvc.alwaysUseMsgStream = True +# Only forward message during RUNNING +# MessageSvc.useErsRunningOnly = True + +#============================================================== +# +# End of MessageSvc configuration file +# +#************************************************************** diff --git a/HLT/Trigger/TrigControl/TrigServices/share/OfflineTHistSvc.py b/HLT/Trigger/TrigControl/TrigServices/share/OfflineTHistSvc.py new file mode 100644 index 00000000000..51d2d0913bc --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/share/OfflineTHistSvc.py @@ -0,0 +1,17 @@ +## @file OfflineTHistSvc.py +## @brief Configure the offline THistSvc +## @author Frank Winklmeier <fwinkl@cern> +## +## This fragment will be included by atheanMT/PT if we are +## running withtout the OH monitoring. Otherwise, the default +## is to use the online histogramming service (TrigMonTHistSvc) +################################################################### + +from TrigServices.TriggerUnixStandardSetup import _Conf +_Conf.useOnlineTHistSvc = False +del _Conf + +## Couple validation flag (i.e. time stamps in messages) to "-M" option +from TriggerJobOpts.TriggerFlags import TriggerFlags +TriggerFlags.Online.doValidation = True +del TriggerFlags diff --git a/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesBootstrap.py b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesBootstrap.py new file mode 100644 index 00000000000..3bf4063c5b7 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesBootstrap.py @@ -0,0 +1,29 @@ +#************************************************************** +# +# HLT bootstrap options file +# +#============================================================== + +#-------------------------------------------------------------- +# HLT specific event loop and output stream +#-------------------------------------------------------------- +theApp.EventLoop = "HltEventLoopMgr" +#theApp.OutStreamType = "AthenaOutputStream" + +#-------------------------------------------------------------- +# in Hlt the EventLoop is controlled by the HLT Processing Unit +# so the default is no Event Selector +#-------------------------------------------------------------- +theApp.EvtSel = "NONE" + +#-------------------------------------------------------------- +# take care of job options legacy +#-------------------------------------------------------------- +theApp.JobOptionsPath = "" +theApp.JobOptionsType = "NONE" + +#============================================================== +# +# End of HLT bootstrap options file +# +#************************************************************** diff --git a/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonBegin.py b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonBegin.py new file mode 100644 index 00000000000..ab547b95b65 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonBegin.py @@ -0,0 +1,20 @@ +#************************************************************** +# +# HLT common configuration file: TrigServicesCommonBegin.py +# +#============================================================== + +include( "TrigServices/MessageSvc.py" ) +include( "TrigServices/TrigServicesEventLoopMgr.py" ) + +## HLT standard service configuration +from TrigServices.TriggerUnixStandardSetup import setupHLTServicesBegin +setupHLTServicesBegin() +## clean-up: avoid running multiple times this method +del setupHLTServicesBegin + +#============================================================== +# +# End of HLT common configuration file: TrigServicesCommonBegin.py +# +#************************************************************** diff --git a/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonEnd.py b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonEnd.py new file mode 100644 index 00000000000..dc98afa1a7a --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonEnd.py @@ -0,0 +1,19 @@ +#************************************************************** +# +# HLT common configuration file: TrigServicesCommonEnd.py +# +#============================================================== + +## get a handle on the ServiceMgr +from AthenaCommon.AppMgr import ServiceMgr as svcMgr + +## HLT standard service configuration +from TrigServices.TriggerUnixStandardSetup import setupHLTServicesEnd +setupHLTServicesEnd() +## clean-up: avoid running multiple times this method +del setupHLTServicesEnd +#============================================================== +# +# End of HLT common configuration file: TrigServicesCommonEnd.py +# +#************************************************************** diff --git a/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesEventLoopMgr.py b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesEventLoopMgr.py new file mode 100644 index 00000000000..9eaddbeae6b --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesEventLoopMgr.py @@ -0,0 +1,76 @@ +#************************************************************** +# +# TrigServicesEventLoopMgr configuration file +# +#============================================================== +from AthenaCommon.AppMgr import theApp +from AthenaCommon.AppMgr import ServiceMgr as svcMgr +from AthenaCommon.Constants import * + +# make the HltEventLoopMgr service available +svcMgr.HltEventLoopMgr = theApp.service( "HltEventLoopMgr" ) # already instantiated +HltEventLoopMgr = svcMgr.HltEventLoopMgr + +# configure here Level-1 CTP ROB identifier which is used in HLT +HltEventLoopMgr.Lvl1CTPROBid = 0x770001 + +# request that events with invalid or missing CTP ROBs are skipped by the HltEventLoopMgr +# (default: don't skip these events) +HltEventLoopMgr.Lvl1CTPROBcheck = TRUE + +# +# name of the HLT Result object in StoreGate +# +HltEventLoopMgr.HltResultName = "HLTResult_HLT" + +# +# handling of truncated HLT Results +# +# switch on saving of events with truncated HLT results to DEBUG stream (default FALSE) +#HltEventLoopMgr.WriteTruncatedHLTtoDebug = FALSE +# name of DEBUG Stream (default "TruncatedHLTResult") +#HltEventLoopMgr.HltTruncationDebugStreamName = "TruncatedHLTResult" +# list of stream names which should not be send to the truncation DEBUG stream (default ["CostMonitoring"]) +#HltEventLoopMgr.ExcludeFromHltTruncationDebugStream = ["CostMonitoring"] + +# +# properties for the HLT result size histogram +# --> set upper edge of histogram to maximum allowed number of words in HLT +# +HltEventLoopMgr.histHltResultSize=("HltResultSize",0,125000,100) + +# +# Configuration of EDM size monitoring plots +# +try: + from TrigEDMConfig.TriggerEDM import EDMDetails,getTypeAndKey,keyToLabel + from TrigEDMConfig.TriggerEDM import TriggerHLTList + + # TODO update to use import TriggerHLTList directly + #from TrigEDMConfig.TriggerEDM import TriggerL2List,TriggerEFList + #TriggerHLTList = list(set(TriggerL2List).union(TriggerEFList)) + + l = [] + for item in TriggerHLTList: + if ('BS' in item[1].split()) or ('DS' in item[1].split()): + t,k = getTypeAndKey(item[0]) + ctype = t + if EDMDetails[t].has_key('collection'): + ctype = EDMDetails[t]['collection'] + l += [ctype+'__'+keyToLabel(k)] + # add a bin for not accounted collections + l += ['not__configured'] + + HltEventLoopMgr.HltEDMCollectionNames = l + number_of_collections=len( HltEventLoopMgr.HltEDMCollectionNames ) + HltEventLoopMgr.histHltEdmSizes=("HltEDMSizes",0., 15000., number_of_collections) +except ImportError,e: + print " +----------------------------------------------------------------------+ " + print " | No initial configuration for EDM monitoring plots will be available! | " + print " +----------------------------------------------------------------------+ " + print e +#============================================================== +# +# End of TrigServicesEventLoopMgr configuration file +# +#************************************************************** diff --git a/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesTHistSvc.py b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesTHistSvc.py new file mode 100644 index 00000000000..5cb0622e166 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesTHistSvc.py @@ -0,0 +1,59 @@ +#************************************************************** +# +# TrigServicesTHistSvc configuration file +# +#============================================================== + +# loading of this library (not a problem if done twice) +theApp.Dlls += [ "TrigServices" ] + +# service creation +theApp.ExtSvc += [ "HltTHistSvc/THistSvc" ] +theApp.MultiThreadExtSvc += [ "HltTHistSvc/THistSvc" ] + + +# just a helper function +def defineTHistSvcOutputFile(dir, name, opt='NEW', service='THistSvc'): + if numberOfThreads.value() == 0: + THistSvc = Service(service) + THistSvc.Output += [dir+" DATAFILE=\'"+name+"' OPT=\'"+opt+"\'" ] + return + for n in range(0,numberOfThreads.value()): + threadID = '__%(#)d' % { '#': n} + THistSvc = Service ( service+threadID ) + THistSvc.Output += [dir+" DATAFILE=\'"+name+threadID+"' OPT=\'"+opt+"\'" ] + +# default settings +defineTHistSvcOutputFile("SHIFT", "monitoring-shift.root") +defineTHistSvcOutputFile("EXPERT", "monitoring-expert.root") +defineTHistSvcOutputFile("DEBUG", "monitoring-debug.root") +defineTHistSvcOutputFile("RUNSTAT", "monitoring-runstat.root") + + + +# user can also specify REGEX used to check Histograms Naming Convention +# THistSvc = Service("THistSvc") +# +# all sort of regex can be given +# THistSvc.ExcludeName = ".+LAr.+" # no LAr histograms any more +# THistSvc.IncludeName = "/SHIFT/.+" # only monitoring allowed +# +# the default is (implementation of the naming convention): +# see: https://edms.cern.ch/document/710911/1 +# see: https://twiki.cern.ch/twiki/bin/view/Atlas/AthenaMTHistogramming +# +# THistSvc.ExcludeName = ".*\..*" +# THistSvc.IncludeName = "^/((SHIFT)|(EXPERT)|(DEBUG)|(RUNSTAT))/.+/.+" +# +# Similar can be specified for histogram types (name of the ROOT class) +# example below can be used to exclude 2dim histograms from being registered +# THistSvc.ExcludeType = ".+2.+" +# example below accepts only 1 dimensional integer histogram +# THistSvc.ExcludeType = ".+" +# THistSvc.IncludeType = "TH1I" + +#============================================================== +# +# End of TrigServicesTHistSvc configuration file +# +#************************************************************** diff --git a/HLT/Trigger/TrigControl/TrigServices/share/hadd.C b/HLT/Trigger/TrigControl/TrigServices/share/hadd.C new file mode 100644 index 00000000000..f566a4f55c1 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/share/hadd.C @@ -0,0 +1,212 @@ +/* + + NOTE: This macro is kept for back compatibility only. + Use instead the executable $ROOTSYS/bin/hadd + + This macro will add histograms from a list of root files and write them + to a target root file. The target file is newly created and must not be + identical to one of the source files. + + Author: Sven A. Schmidt, sven.schmidt@cern.ch + Date: 13.2.2001 + + This code is based on the hadd.C example by Rene Brun and Dirk Geppert, + which had a problem with directories more than one level deep. + (see macro hadd_old.C for this previous implementation). + + The macro from Sven has been enhanced by + Anne-Sylvie Nicollerat <Anne-Sylvie.Nicollerat@cern.ch> + to automatically add Trees (via a chain of trees). + + To use this macro, modify the file names in function hadd. + + NB: This macro is provided as a tutorial. + Use $ROOTSYS/bin/hadd to merge many histogram files + + ATLAS HLT COMMENT by T. Bold: + This is modified macro used to deal with the sort of strange + ROOT files generated while athenaMT is run. There possibly + number of the output files. With this one can work whit standard hadd. + But in fact there is number of the TTrees in the file + having the same name, just subsequent sequence(version) number. + This can only be handled by this script. + */ + + +#include <string.h> +#include "TChain.h" +#include "TFile.h" +#include "TH1.h" +#include "TTree.h" +#include "TKey.h" +#include "Riostream.h" + +TList *FileList; +TFile *Target; + +void MergeRootfile( TDirectory *target, TList *sourcelist ); + + +void hadd() { + // in an interactive ROOT session, edit the file names + // Target and FileList, then + // root > .L hadd.C + // root > hadd() + + Target = TFile::Open( "result.root", "RECREATE" ); + + FileList = new TList(); + FileList->Add( TFile::Open("hsimple1.root") ); + FileList->Add( TFile::Open("hsimple2.root") ); + + MergeRootfile( Target, FileList ); + +} + +TTree * mergeCircularTrees(const char* treename, TDirectory *dir, TTree *nTree = 0) { + + TString basename(treename); + TIter nextIter(gDirectory->GetListOfKeys()); + gDirectory->GetListOfKeys()->Print(); + TKey *obj; + TTree *tptr; + TList myTreesList; + + while ( (obj = (TKey *)nextIter()) != 0 ) { + + if ( TString(obj->GetClassName()) == TString("TTree") ) { + // it is the tree let's read it in + tptr = (TTree *)obj->ReadObj(); + if ( TString(tptr->GetName()) == basename ) { + if ( nTree == 0 ) { + nTree = (TTree*)tptr->Clone(); + nTree->SetCircular(kMaxLong64); // maximum circularity + } + else + myTreesList.AddLast(tptr); + } + } + } + + dir->cd(); + nTree->SetDirectory(dir); + nTree->Merge(&myTreesList); + return nTree; +} + +void MergeRootfile( TDirectory *target, TList *sourcelist ) { + + // cout << "Target path: " << target->GetPath() << endl; + TString path( (char*)strstr( target->GetPath(), ":" ) ); + path.Remove( 0, 2 ); + + TFile *first_source = (TFile*)sourcelist->First(); + first_source->cd( path ); + TDirectory *current_sourcedir = gDirectory; + //gain time, do not add the objects in the list in memory + Bool_t status = TH1::AddDirectoryStatus(); + TH1::AddDirectory(kFALSE); + + // loop over all keys in this directory + TTree *nTree = 0; + TIter nextkey( current_sourcedir->GetListOfKeys() ); + TKey *key, *oldkey=0; + while ( (key = (TKey*)nextkey())) { + // cout << "found key " << key->GetName() << endl; + //keep only the highest cycle number for each key + if (oldkey) + if ( strcmp(oldkey->GetName(),key->GetName()) == 0 ) { + // cout << "skipping key " << key->GetName() << endl; + continue; + } + // always set oldkey ptr + oldkey = key; + + // read object from first source file + first_source->cd( path ); + TObject *obj = key->ReadObj(); + + if ( obj->IsA()->InheritsFrom( "TH1" ) ) { + // descendant of TH1 -> merge it + + // cout << "Merging histogram " << obj->GetName() << endl; + TH1 *h1 = (TH1*)obj; + + // loop over all source files and add the content of the + // correspondant histogram to the one pointed to by "h1" + TFile *nextsource = (TFile*)sourcelist->After( first_source ); + while ( nextsource ) { + + // make sure we are at the correct directory level by cd'ing to path + nextsource->cd( path ); + TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(h1->GetName()); + if (key2) { + TH1 *h2 = (TH1*)key2->ReadObj(); + h1->Add( h2 ); + delete h2; + } + + nextsource = (TFile*)sourcelist->After( nextsource ); + } + } + else if ( obj->IsA()->InheritsFrom( "TTree" ) ) { + + // loop over all source files create a chain of Trees "globChain" + const char* obj_name= obj->GetName(); + cout << "merging all trees in first file" << endl; + nTree = mergeCircularTrees(obj_name, target); + cout << "merged trees in first file" << endl; + + TFile *nextsource = (TFile*)sourcelist->After( first_source ); + + while ( nextsource ) { + nextsource->cd( path ); + cout << "merging all trees in file "<< nextsource->GetName() << endl; + mergeCircularTrees(obj_name, target, nTree); + cout << "merged all trees "<< nextsource->GetName() << endl; + nextsource = (TFile*)sourcelist->After( nextsource ); + } + + } else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) { + // it's a subdirectory + + cout << "Found subdirectory " << obj->GetName() << endl; + + // create a new subdir of same name and title in the target file + target->cd(); + TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() ); + + // newdir is now the starting point of another round of merging + // newdir still knows its depth within the target file via + // GetPath(), so we can still figure out where we are in the recursion + MergeRootfile( newdir, sourcelist ); + + } else { + + // object is of no type that we know or can handle + cout << "Unknown object type, name: " + << obj->GetName() << " title: " << obj->GetTitle() << endl; + } + + // now write the merged histogram (which is "in" obj) to the target file + // note that this will just store obj in the current directory level, + // which is not persistent until the complete directory itself is stored + // by "target->Write()" below + if ( obj ) { + target->cd(); + + //!!if the object is a tree, it is stored in globChain... + if(obj->IsA()->InheritsFrom( "TTree" )) { + nTree->Write(); + nTree->Print(); + } + else + obj->Write( key->GetName() ); + } + + } // while ( ( TKey *key = (TKey*)nextkey() ) ) + + // save modifications to target file + target->SaveSelf(kTRUE); + TH1::AddDirectory(status); +} diff --git a/HLT/Trigger/TrigControl/TrigServices/share/hadd.sh b/HLT/Trigger/TrigControl/TrigServices/share/hadd.sh new file mode 100755 index 00000000000..f68f3bd59d3 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/share/hadd.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# generate the script for ROOT hadd.C + +#script which will be generated in order to do the merging job +sums=thishadd.C + +# find out where hadd.C is located +haddmacro=$( dirname $(which hadd.sh))"/hadd.C" +#echo $haddmacro + +if [ ! -f $haddmacro ] + then + echo "$haddmacro macro could not be found" + echo "It is expected to be in the same directory as hadd.sh" + echo "Check your installation!" + exit 0 +fi + + +# make local copy of the macro +cp $haddmacro . + + +if [ $# -lt 2 ] + then + echo "Usage: hadd.sh destination source1|source2|..." + exit 127 +fi + +output=$1 +shift 1 + +#build the actual script +echo "{ +gROOT->LoadMacro(\"hadd.C+\"); +TFile *foutput = TFile::Open(\"$output\",\"NEW\"); +if ( foutput == 0 ) { + cout << \"output file already exist, exitting ...\" << endl; + gROOT->ProcessLine(\".q\"); +} +TList *inputs = new TList(); + +" > $sums + + + +echo "INPUT FILES: " `ls $@` +echo "OUTPUT FILE: " $output + +# trick to expand wildcards +for f in `ls $@` +do + echo "inputs->AddLast( TFile::Open (\"$f\") );" >> $sums +done + +echo " +MergeRootfile(foutput , inputs); +foutput->Close(); +gROOT->ProcessLine(\".q\"); +} +" >> $sums +echo "EXECUTING ROOT to merge files: " +root -l -b $sums +# do cleanup +rm -f $sums hadd.C +echo "done" \ No newline at end of file diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx new file mode 100644 index 00000000000..4197a6e621c --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx @@ -0,0 +1,3234 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Gaudi includes +#include "GaudiKernel/IAlgorithm.h" +#include "GaudiKernel/Incident.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/IEvtSelector.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "GaudiKernel/IssueSeverity.h" +#include "GaudiKernel/ITHistSvc.h" +#include "GaudiKernel/ThreadGaudi.h" +#include "GaudiKernel/Timing.h" +#include "GaudiKernel/IAlgContextSvc.h" +#include "GaudiKernel/IAlgManager.h" +#include "GaudiKernel/ServiceLocatorHelper.h" +#include "GaudiKernel/SmartIF.h" + +// Athena includes +#include "StoreGate/StoreGateSvc.h" +#include "EventInfo/EventIncident.h" +#include "EventInfo/EventInfo.h" +#include "EventInfo/EventType.h" +#include "xAODEventInfo/EventAuxInfo.h" +#include "ByteStreamData/ByteStreamMetadata.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "AthenaPoolUtilities/CondAttrListCollection.h" +#include "CLIDSvc/CLASS_DEF.h" + +// omni redefines this macro, so we save it +namespace { +static std::string CMT_PACKAGE_VERSION = PACKAGE_VERSION; +} + +// Trigger includes +#include "TrigServices/HltEventLoopMgr.h" +#include "TrigServices/TrigISHelper.h" +#include "TrigServices/TrigHLTIssues.h" +#include "TrigPreFlightCheck.h" +#include "TrigCOOLUpdateHelper.h" +#include "TrigSORFromPtreeHelper.h" +#include "TrigConfInterfaces/IHLTConfigSvc.h" +#include "TrigInterfaces/Incidents.h" +#include "TrigMonitorBase/TrigLockedHist.h" +#include "TrigKernel/HltAcceptFlag.h" +#include "TrigKernel/HltResultStatusCode.h" +#include "TrigKernel/HltExtraStatusCode.h" +#include "TrigKernel/IHltTHistSvc.h" +#include "TrigSteeringEvent/HLTResult.h" +#include "TrigSteeringEvent/HLTExtraData.h" +#include "TrigNavigation/TrigEDMSizes.h" + +// TDAQ includes +#include "ers/ers.h" +#include "eformat/eformat.h" +#include "eformat/write/ROBFragment.h" +#include "TTCInfo/LumiBlock.h" +#include "ddc/DdcFloatInfoNamed.h" +#include "hltinterface/HLTInterface.h" +#include "hltinterface/EventId.h" +#include "hltinterface/HLTResult.h" +#include "CTPfragment/CTPfragment.h" +#include "CTPfragment/CTPExtraWordsFormat.h" +#include "CTPfragment/Issue.h" + +// ROOT includes +#include "TH1F.h" +#include "TH2I.h" +#include "TProfile.h" +#include "TClass.h" + +// Other includes +#include <set> +#include <string> +#include <algorithm> +#include <ctime> +#include <mutex> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <boost/property_tree/ptree.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/lexical_cast.hpp> + +#undef PACKAGE_VERSION // use the CMT_PACKAGE_VERSION std::string instead + +#define ST_WHERE "HltEventLoopMgr::" << __func__ << "(): " + +#if ROOT_VERSION_CODE >= ROOT_VERSION(6,0,0) +# define CAN_REBIN(hist) hist->SetCanExtend(TH1::kAllAxes) +#else +# define CAN_REBIN(hist) hist->SetBit(TH1::kCanRebin) +#endif + +using namespace boost::property_tree; +using std::string; +using std::function; +using std::begin; +using std::end; +using SOR = TrigSORFromPtreeHelper::SOR; + +namespace +{ + //========================================================================= + const eformat::helper::Status SW_UNCLASSIFIED(eformat::UNCLASSIFIED, 0), + SW_FAIL(eformat::DATA_CORRUPTION, 0), + SW_TRUNCATION(eformat::INTERNAL_OVERFLOW, 0); + constexpr unsigned + INITIAL_ROB_SIZE_MARGIN = 4; /* margin for the rob size, to account for + possible additional status words that may + still be unknonw */ + + //========================================================================= + constexpr std::array<uint32_t, 7> L1R_MANDATORY_ROBS = + {{ + 0x7300a8, 0x7300a9, 0x7300aa, 0x7300ab, // TDAQ_CALO_CLUSTER_PROC_ROI ROBs + 0x7500ac, 0x7500ad, // TDAQ_CALO_JET_PROC_ROI ROBs + 0x760001 // TDAQ_MUON_CTP_INTERFACE ROB + }}; // default list of IDs of ROBs that must come in the L1R from the RoIB + + //========================================================================= + constexpr std::array<uint32_t, 12> L1R_SKIP_ROB_CHECK = + {{ + 0x7300a8, 0x7300a9, 0x7300aa, 0x7300ab, // TDAQ_CALO_CLUSTER_PROC_ROI ROBs + 0x7500ac, 0x7500ad, // TDAQ_CALO_JET_PROC_ROI ROBs + 0x760001, // TDAQ_MUON_CTP_INTERFACE ROB + 0x770001, // TDAQ_CTP ROB + 0x910081, 0x910091, 0x910082, 0x910092 // TDAQ_CALO_TOPO_PROC ROBs + }}; //concrete IDs still unknown for TDAQ_FTK and TDAQ_CALO_FEAT_EXTRACT_ROI + + //========================================================================= + constexpr std::array<eformat::SubDetector, 7> L1R_SKIP_SD_CHECK = + {{ + eformat::TDAQ_CALO_CLUSTER_PROC_ROI, + eformat::TDAQ_CALO_JET_PROC_ROI, + eformat::TDAQ_HLT, + eformat::TDAQ_FTK, + eformat::TDAQ_CALO_TOPO_PROC, + eformat::TDAQ_CALO_DIGITAL_PROC, + eformat::TDAQ_CALO_FEAT_EXTRACT_ROI + }}; + + //========================================================================= + constexpr std::array<eformat::SubDetector, 8> L1R_BINS = + {{ + eformat::TDAQ_CALO_CLUSTER_PROC_ROI, + eformat::TDAQ_CALO_JET_PROC_ROI, + eformat::TDAQ_MUON_CTP_INTERFACE, + eformat::TDAQ_CTP, + eformat::TDAQ_FTK, + eformat::TDAQ_CALO_TOPO_PROC, + eformat::TDAQ_CALO_DIGITAL_PROC, + eformat::TDAQ_CALO_FEAT_EXTRACT_ROI + }}; + + //========================================================================= + constexpr const char * UNEXPECTED_L1R_ROB_LABEL = "Unexpected_ROB"; + constexpr const char * MISSING_L1R_CTP_LABEL = "Missing_CTP_Fragment"; + + //========================================================================= + std::mutex timeout_mutex; // To synchronize main and time out threads + + //========================================================================= + bool skipEnabledCheck(eformat::SubDetector sd) + { + // Skip check for HLT Result ROBs (for DataScouting) + if (sd == eformat::TDAQ_HLT) return true; + + // Skip check for certain L1 input ROBs + return std::find(begin(L1R_SKIP_SD_CHECK), + end(L1R_SKIP_SD_CHECK), + sd) != end(L1R_SKIP_SD_CHECK); + } + + //========================================================================= + bool skipEnabledCheck(uint32_t robid) + { + // Skip check for HLT Result ROBs (for DataScouting) + if (eformat::helper::SourceIdentifier(robid).subdetector_id() == eformat::TDAQ_HLT) return true; + + // Skip check for certain L1 input ROBs + return std::find(begin(L1R_SKIP_ROB_CHECK), + end(L1R_SKIP_ROB_CHECK), + robid) != end(L1R_SKIP_ROB_CHECK); + } + + //========================================================================= + std::string + missingL1RobsMsg(const std::vector<uint32_t>& rob_ids) + { + std::ostringstream ost; + if(!rob_ids.empty()) + { + ost << "L1 result ROBs missing: "; + + ost << "0x" << std::hex << std::setfill('0') << std::setw(6); + std::copy(std::begin(rob_ids), + std::end(rob_ids) - 1, // leave one to avoid delimiter + std::ostream_iterator<uint32_t>{ost, ", 0x"}); + ost << rob_ids.back() << "."; // append without delimiter + } + + return ost.str(); + } + + //========================================================================= + void fillEdmHist(TProfile * hist, const std::string& colname, + const HLT::TrigEDMSizes::EDMObjectInfo& info) + { + if(hist) + hist->Fill(colname.c_str(), static_cast<double>(info.words)); + } + + //========================================================================= + void addDebugStreamTag(hltinterface::HLTResult& hlt_result, + const std::string& tagname) + { + hlt_result.stream_tag.emplace_back(tagname, eformat::DEBUG_TAG, false); + } + + //========================================================================= + std::unique_ptr<eformat::write::ROBFragment> + initRob(uint16_t modid, uint32_t rn, uint32_t l1id, uint32_t bcid, + uint32_t l1tt, uint32_t dett, uint32_t * status_words) + { + using namespace eformat; + using write::ROBFragment; + + auto src = helper::SourceIdentifier{TDAQ_HLT, modid}.code(); + auto robp = std::unique_ptr<ROBFragment>{ + new ROBFragment{src, rn, l1id, bcid, l1tt, dett, 0, 0, STATUS_FRONT}}; + + status_words[0] = SW_UNCLASSIFIED.code(); + status_words[1] = hltonl::NORMAL_HLT_RESULT; + status_words[2] = hltonl::PSC_ERROR_UNCLASSIFIED; + + robp->status(1, status_words); + robp->rod_status(1, status_words); + + return robp; + } + + //========================================================================= + // Class that resets a pointer upon destruction, locking given mutex + template <typename T, typename MUTEX> + class PtrResetter + { + public: + explicit PtrResetter(T*& ptr, MUTEX& mut) + : m_ptr{ptr} + , m_mut(mut) // cannot use uniform init due to gcc4.8 bug + {} + ~PtrResetter() // this is where the work happens + { + std::lock_guard<MUTEX>{m_mut}; + m_ptr = nullptr; + } + PtrResetter(const PtrResetter&) = delete; + PtrResetter operator=(const PtrResetter&) = delete; + // no need to delete move ops explicitly in this case - not generated + + private: + T*& m_ptr; + MUTEX& m_mut; + }; +} + + +//========================================================================= +// Standard Constructor +//========================================================================= +HltEventLoopMgr::HltEventLoopMgr(const std::string& nam, + ISvcLocator* svcLoc) +: MinimalEventLoopMgr(nam, svcLoc), + m_incidentSvc ( "IncidentSvc", nam ), + m_evtStore( "StoreGateSvc", nam ), + m_detectorStore( "DetectorStore", nam ), + m_inputMetaDataStore( "StoreGateSvc/InputMetaDataStore", nam ), + m_robDataProviderSvc( "ROBDataProviderSvc",nam ), + m_THistSvc( "THistSvc", nam ), + m_isHelper( "TrigISHelper", this), + m_coolHelper( "TrigCOOLUpdateHelper", this), + m_hltConfigSvc(0), + m_algContextSvc(0), + m_msg(0), + m_currentRun(0), + m_currentLB(0), + m_currentEvent(0), + m_sorTime_stamp(2,0), + m_detector_mask(0xffffffff, 0xffffffff, 0, 0), + m_l1_hltPrescaleUpdateLB(0xffffffff), + m_hist_eventAcceptFlags(0), + m_hist_frameworkErrorCodes(0), + m_hist_Hlt_result_size(0), + m_hist_Hlt_result_status(0), + m_hist_numStreamTags(0), + m_hist_streamTagTypes(0), + m_hist_streamTagNames(0), + m_hist_num_partial_eb_robs(0), + m_hist_num_partial_eb_SubDetectors(0), + m_hist_partial_eb_SubDetectors_ROBs(0), + m_hist_partial_eb_SubDetectors_SDs(0), + m_hist_Hlt_result_size_physics(0), + m_hist_Hlt_result_size_express(0), + m_hist_Hlt_result_size_DataScouting(0), + m_hist_HltResultSizes_Stream_physics(0), + m_hist_HltResultSizes_Stream_DataScouting(0), + m_hist_HltEdmSizes_No_Truncation(0), + m_hist_HltEdmSizes_With_Truncation(0), + m_hist_HltEdmSizes_TruncatedResult_Retained_Collections(0), + m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections(0), + m_mandatoryL1ROBs{{begin(L1R_MANDATORY_ROBS), end(L1R_MANDATORY_ROBS)}}, + m_histProp_Hlt_result_size(Gaudi::Histo1DDef("HltResultSize",0,200000,100)), + m_histProp_numStreamTags(Gaudi::Histo1DDef("NumberOfStreamTags",-.5,9.5,10)), + m_histProp_streamTagNames(Gaudi::Histo1DDef("StreamTagNames",-.5,.5,1)), + m_histProp_num_partial_eb_robs(Gaudi::Histo1DDef("NumberROBsPartialEB",-.5,99.5,100)), + m_histProp_Hlt_Edm_Sizes(Gaudi::Histo1DDef("HltEDMSizes",0.,10000.,100)), + m_total_evt(0), + m_failed_evt(0), + m_invalid_lvl1_result(0), + m_invalid_hlt_result(0), + m_truncated_hlt_result(0), + m_truncated_hlt_result_to_debug(0), + m_truncated_hlt_result_not_to_debug(0), + m_lvl1id(0), + m_run_no(0), + m_bunch_crossing_id(0), + m_time_stamp(0), + m_time_stamp_ns_offset(0), + m_lumi_block(0), + m_l1_Status_Element(0), + m_l1_Trigger_Type(0), + m_l1_detev_type(0), + m_hist_l1_robs(0), + m_hist_Hlt_truncated_result(0) +{ + // General properties for event loop managers + declareProperty("predefinedLumiBlock", m_predefinedLumiBlock=0); + declareProperty("Lvl1CTPROBid", m_lvl1CTPROBid=0x770001); + declareProperty("ApplicationName", m_applicationName="None"); + declareProperty("PartitionName", m_partitionName="None"); + declareProperty("setMagFieldFromPtree", m_setMagFieldFromPtree=false); + declareProperty("enabledROBs", m_enabledROBs); + declareProperty("enabledSubDetectors", m_enabledSubDetectors); + declareProperty("MandatoryL1ROBs", m_mandatoryL1ROBs, "List of mandatory ROB IDs coming from the RoIB (must come in L1R seed)"); + declareProperty("HltEDMCollectionNames", m_hltEdmCollectionNames, "Names of all HLT EDM Collections"); + declareProperty("JobOptionsType", m_jobOptionsType="NONE"); + declareProperty("doMonitoring", m_doMonitoring=true, "Produce framework monitoring histograms"); + declareProperty("histHltResultSize", m_histProp_Hlt_result_size, "Histogram for HLT result size in words"); + declareProperty("histNumberOfStreamTags", m_histProp_numStreamTags, "Histogram with number of stream tags"); + declareProperty("histStreamTagNames", m_histProp_streamTagNames,"Histogram with stream tag names"); + declareProperty("histNumberROBsPartialEB", m_histProp_num_partial_eb_robs, "Histogram with number of ROBs for PEB" ); + declareProperty("histHltEdmSizes", m_histProp_Hlt_Edm_Sizes, "Histogram with sizes of HLT EDM collections" ); + declareProperty("ForceHltReject", m_forceHltReject=false); + declareProperty("ForceHltAccept", m_forceHltAccept=false); + declareProperty("HltResultName", m_HltResultName="HLTResult_HLT"); + declareProperty("HltDebugStreamName", m_HltDebugStreamName ="HLTMissingData"); + declareProperty("HltForcedStreamName", m_HltForcedStreamName ="HLTEventAcceptForced"); + declareProperty("CoolUpdateTool", m_coolHelper); + declareProperty("maxPrepareForRunSleepSec", m_prepareForRunSleep = 0, "Max number of seconds to sleep at the beginning of prepareForRun"); + declareProperty("Lvl1CTPROBcheck", m_lvl1CTPROBcheck=true); + declareProperty("WriteTruncatedHLTtoDebug", m_writeHltTruncationToDebug=true); + declareProperty("HltTruncationDebugStreamName", m_HltTruncationDebugStreamName ="TruncatedHLTResult"); + declareProperty("ExcludeFromHltTruncationDebugStream", m_excludeFromHltTruncationDebugStream ={"CostMonitoring"}); +} + +//========================================================================= +// Standard Destructor +//========================================================================= +HltEventLoopMgr::~HltEventLoopMgr() +{ +} + +//========================================================================= +// implementation of IInterface: queryInterface +//========================================================================= +StatusCode HltEventLoopMgr::queryInterface(const InterfaceID& riid, void** ppvInterface) +{ + if(!ppvInterface) + return StatusCode::FAILURE; + + if(ITrigEventLoopMgr::interfaceID().versionMatch(riid)) + *ppvInterface = static_cast<ITrigEventLoopMgr*>(this); + else + return MinimalEventLoopMgr::queryInterface(riid, ppvInterface); + + addRef(); + return StatusCode::SUCCESS; +} + +//========================================================================= +// implementation of IService::sysInitalize +//========================================================================= +StatusCode HltEventLoopMgr::sysInitialize() +{ + // set message stream + m_msg = new MsgStream( msgSvc(), name() ); + + // initialize the base class + StatusCode sc = MinimalEventLoopMgr::sysInitialize(); + sc.setChecked(); + return sc; +} + +void HltEventLoopMgr::updateDFProps() +{ + ServiceHandle<IJobOptionsSvc> p_jobOptionsSvc("JobOptionsSvc", name()); + if ((p_jobOptionsSvc.retrieve()).isFailure()) { + logStream() << MSG::WARNING << "Could not find JobOptionsSvc to set " + << "DataFlow properties" << endreq; + } else { + auto dfprops = p_jobOptionsSvc->getProperties("DataFlowConfig"); + + // Application name + auto pname = "DF_ApplicationName"; + const auto * prop = Gaudi::Utils::getProperty(dfprops, pname); + if(prop && m_applicationName.assign(*prop)) { + logStream() << MSG::DEBUG << " ---> Read from DataFlow configuration: " + << m_applicationName << endreq; + } else { + logStream() << MSG::WARNING << "Could not set Property '" << pname + << "' from DataFlow." << endreq; + } + + // Partition name + pname = "DF_PartitionName"; + prop = Gaudi::Utils::getProperty(dfprops, pname); + if (prop && m_partitionName.assign(*prop)) { + logStream() << MSG::DEBUG << " ---> Read from DataFlow configuration: " + << m_partitionName << endreq; + } else { + logStream() << MSG::WARNING << "Could not set Property '" << pname + << "' from DataFlow." << endreq; + } + + // get the list of enabled ROBs + pname = "DF_Enabled_ROB_IDs"; + prop = Gaudi::Utils::getProperty(dfprops, pname); + if (prop && m_enabledROBs.assign(*prop)) { + logStream() << MSG::DEBUG << " ---> Read from DataFlow configuration: " + << m_enabledROBs.value().size() << " enabled ROB IDs." + << endreq; + } else { + // this is only info, because it is normal in athenaHLT + logStream() << MSG::INFO << "Could not set Property '" << pname + << "' from DataFlow." << endreq; + } + + // get the list of enabled Sub Detectors + pname = "DF_Enabled_SubDet_IDs"; + prop = Gaudi::Utils::getProperty(dfprops, pname); + if (prop && m_enabledSubDetectors.assign(*prop)) { + logStream() << MSG::DEBUG << " ---> Read from DataFlow configuration: " + << m_enabledSubDetectors.value().size() + << " enabled Sub Detector IDs." << endreq; + } else { + // this is only info, because it is normal in athenaHLT + logStream() << MSG::INFO << "Could not set Property '" + << pname << "' from DataFlow." << endreq; + } + } + + p_jobOptionsSvc.release().ignore(); +} + +//========================================================================= +// implementation of IService::initalize +//========================================================================= +StatusCode HltEventLoopMgr::initialize() +{ + // initialize the base class + StatusCode sc = MinimalEventLoopMgr::initialize(); + + // leave this after initialization of base class, otherwise msgSvc is not correctly set up + // ----- + logStream() << MSG::INFO << " ---> HltEventLoopMgr = " << name() << " initialize " + << " - package version " << CMT_PACKAGE_VERSION << endreq ; + if (sc.isFailure()) { + logStream() << MSG::ERROR << "Failed to initialize base class MinimalEventLoopMgr" << endreq; + return sc; + } + + updateDFProps(); + + // JobOptions type + SmartIF<IProperty> propMgr ( Gaudi::createApplicationMgr() ); + if( propMgr.isValid() ) { + try { + if (m_jobOptionsType.assign( propMgr->getProperty("JobOptionsType") )) + logStream() << MSG::DEBUG << " ---> Read from DataFlow configuration: " << m_jobOptionsType << endreq; + } + catch (...) { + logStream() << MSG::WARNING << "Could not set Property '" << m_jobOptionsType.name() << "' from DataFlow." << endreq; + } + } + else { + logStream() << MSG::WARNING << "Error retrieving IProperty interface of ApplicationMgr" << endreq; + } + + // print properties + logStream() << MSG::INFO << " ---> predefinedLumiBlock = " << m_predefinedLumiBlock << endreq ; + logStream() << MSG::INFO << " ---> Lvl1 CTP ROB Id = " << m_lvl1CTPROBid + << " SourceID in hex = 0x" << MSG::hex << m_lvl1CTPROBid.value() << MSG::dec << endreq ; + logStream() << MSG::INFO << " ---> ApplicationName = " << m_applicationName << endreq ; + logStream() << MSG::INFO << " ---> PartitionName = " << m_partitionName << endreq ; + logStream() << MSG::INFO << " ---> JobOptionsType = " << m_jobOptionsType << endreq ; + + logStream() << MSG::INFO << " ---> Enabled ROBs: size = " + << m_enabledROBs.value().size(); + if (m_enabledROBs.value().size() == 0) + { + logStream() << MSG::INFO << ". No check will be performed "; + } + logStream() << endreq; + + logStream() << MSG::INFO << " ---> Enabled Sub Detectors: size = " + << m_enabledSubDetectors.value().size(); + if (m_enabledSubDetectors.value().size() == 0) + { + logStream() << ". No check will be performed " << endreq; + } + logStream() << endreq; + + logStream() << MSG::INFO << " ---> Fill monitoring histograms = " << m_doMonitoring << endreq ; + logStream() << MSG::INFO << " ---> Hist: histHltResultSize = " << m_histProp_Hlt_result_size << endreq ; + logStream() << MSG::INFO << " ---> Hist: histNumberOfStreamTags = " << m_histProp_numStreamTags << endreq ; + logStream() << MSG::INFO << " ---> Hist: histStreamTagNames = " << m_histProp_streamTagNames << endreq ; + logStream() << MSG::INFO << " ---> Hist: histNumberROBsPartialEB= " << m_histProp_num_partial_eb_robs << endreq ; + logStream() << MSG::INFO << " ---> Hist: histHltEdmSizes = " << m_histProp_Hlt_Edm_Sizes << endreq; + logStream() << MSG::INFO << " ---> HLT EDM Collection Names = " << m_hltEdmCollectionNames << endreq; + logStream() << MSG::INFO << " ---> HltResult SG key = " << m_HltResultName << endreq ; + logStream() << MSG::INFO << " ---> HLT debug stream name = " << m_HltDebugStreamName << endreq ; + logStream() << MSG::INFO << " ---> HLT stream for forced events = " << m_HltForcedStreamName << endreq ; + logStream() << MSG::INFO << " ---> ForceHltReject = " << m_forceHltReject << endreq ; + logStream() << MSG::INFO << " ---> ForceHltAccept = " << m_forceHltAccept << endreq; + + if (m_forceHltReject.value()) { + logStream() << MSG::INFO << " +------------------------------------------+ " << endreq ; + logStream() << MSG::INFO << " | >>> ForceHltReject is enabled ! <<< | " << endreq ; + logStream() << MSG::INFO << " | It takes precedence over ForceHltAccept | " << endreq ; + logStream() << MSG::INFO << " +------------------------------------------+ " << endreq ; + } + + logStream() << MSG::INFO << " ---> Write events with truncated HLT result to debug stream = " << m_writeHltTruncationToDebug << endreq; + logStream() << MSG::INFO << " ---> Debug stream name for events with truncated HLT result = " << m_HltTruncationDebugStreamName << endreq; + logStream() << MSG::INFO << " ---> Stream names of events with a truncated HLT result which will not be send to the debug stream = " << m_excludeFromHltTruncationDebugStream << endreq; + + //------------------------------------------------------------------------- + // Setup the StoreGateSvc + //------------------------------------------------------------------------- + sc = m_evtStore.retrieve(); + if(sc.isFailure()) + { + logStream() << MSG::FATAL << "Error retrieving StoreGateSvc "+m_evtStore << endreq; + return sc; + } + + //------------------------------------------------------------------------- + // Setup the DetectorStore + //------------------------------------------------------------------------- + sc = m_detectorStore.retrieve(); + if(sc.isFailure()) + { + logStream() << MSG::FATAL << "Error retrieving DetectorStore "+m_detectorStore << endreq; + return sc; + } + + //------------------------------------------------------------------------- + // Setup the InputMetaDataStore + //------------------------------------------------------------------------- + sc = m_inputMetaDataStore.retrieve(); + if(sc.isFailure()) + { + logStream() << MSG::FATAL << "Error retrieving InputMetaDataStore"+m_inputMetaDataStore << endreq; + return sc; + } + + //-------------------------------------------------------------------------- + // Setup the IncidentSvc + //-------------------------------------------------------------------------- + sc = m_incidentSvc.retrieve(); + if(sc.isFailure()) + { + logStream() << MSG::FATAL << "Error retrieving IncidentSvc "+m_incidentSvc << endreq; + return sc; + } + + //-------------------------------------------------------------------------- + // Setup the ROBDataProviderSvc + //-------------------------------------------------------------------------- + sc = m_robDataProviderSvc.retrieve(); + if(sc.isFailure()) + { + logStream() << MSG::FATAL << "Error retrieving ROBDataProviderSvc "+m_robDataProviderSvc << endreq; + return sc; + } + + //-------------------------------------------------------------------------- + // Setup the Histogram Service + //-------------------------------------------------------------------------- + sc = m_THistSvc.retrieve(); + if(sc.isFailure()) + { + logStream() << MSG::FATAL << "Error retrieving THistSvc "+m_THistSvc << endreq; + return sc; + } + + //-------------------------------------------------------------------------- + // Setup the TrigISHelper + //-------------------------------------------------------------------------- + sc = m_isHelper.retrieve(); + if(sc.isFailure()) + { + logStream() << MSG::FATAL << "Error retrieving TrigISHelper "+m_isHelper << endreq; + return sc; + } + sc = m_isHelper->setProperty(m_partitionName); + if(sc.isFailure()) + { + logStream() << MSG::FATAL << "Error setting " << m_partitionName.name() + << " of " << m_isHelper << endreq; + return sc; + } + + //-------------------------------------------------------------------------- + // COOL helper + //-------------------------------------------------------------------------- + if (m_coolHelper.retrieve().isFailure()) { + logStream() << MSG::FATAL << "Error retrieving" << m_coolHelper << endreq; + return StatusCode::FAILURE; + } + + //-------------------------------------------------------------------------- + // Setup optional services/tools + //-------------------------------------------------------------------------- + if (service("AlgContextSvc", m_algContextSvc, /*createIf=*/ false).isFailure()) { + m_algContextSvc = 0; + logStream() << MSG::DEBUG << "No AlgContextSvc available" << endreq; + } + + //-------------------------------------------------------------------------- + // Pre flight check + //-------------------------------------------------------------------------- + ToolHandle<TrigPreFlightCheck> preFlightCheck; + if (preFlightCheck.retrieve().isFailure()) { + logStream() << MSG::FATAL << "Error retrieving TrigPreFlightCheck "+preFlightCheck << endreq; + return StatusCode::FAILURE; + } + + // A failed pre-flight check is fatal in a partition + if ( validPartition() ) { + if ( preFlightCheck->check(MSG::ERROR).isFailure() ) { + logStream() << MSG::FATAL << "Pre-flight check for HLT failed." << endreq; + return StatusCode::FAILURE; + } + } + else { + if ( preFlightCheck->check(MSG::WARNING).isFailure() ) + logStream() << MSG::WARNING << "Pre-flight check for HLT failed." << endreq; + } + preFlightCheck->release(); + + // The remainder of this method used to be in the L2/EF specialization + + // fill CTP ROB id vector + m_ctpRobIdVec.clear(); + if (m_lvl1CTPROBid.value() != 0) { + m_ctpRobIdVec.push_back( m_lvl1CTPROBid.value() ); + } + + // print properties + logStream() << MSG::INFO << " ---> HltEventLoopMgr = " << name() << " special properties <--- " << endreq ; + logStream() << MSG::INFO << " ---> Lvl1 CTP ROB Id vec. = 0x" << MSG::hex << m_ctpRobIdVec[0] << MSG::dec + << " size of vector = " << m_ctpRobIdVec.size() << endreq ; + logStream() << MSG::INFO << " ---> Check for invalid CTP ROBs = " << m_lvl1CTPROBcheck << endreq ; + +//------------------------------------------------------------------------- +// Reset counters +//------------------------------------------------------------------------- + m_total_evt = 0; + m_failed_evt = 0; + m_invalid_lvl1_result = 0; + m_invalid_hlt_result = 0; + m_truncated_hlt_result = 0; + m_truncated_hlt_result_to_debug = 0; + m_truncated_hlt_result_not_to_debug = 0; + +//-------------------------------------------------------------------------- +// Setup the HLT Histogram Service when configured +//-------------------------------------------------------------------------- + if ( &*m_THistSvc ) { + m_hltTHistSvc = SmartIF<IHltTHistSvc>( &*m_THistSvc ); + if (m_hltTHistSvc.isValid()) { + logStream() << MSG::INFO << "A THistSvc implementing the HLT interface IHltTHistSvc was found." + << endreq; + } else { + logStream() << MSG::INFO << "No THistSvc implementing the HLT interface IHltTHistSvc was found." + << endreq; + } + } + +//-------------------------------------------------------------------------- +// Setup the HLT ROB Data Provider Service when configured +//-------------------------------------------------------------------------- + if ( &*m_robDataProviderSvc ) { + m_hltROBDataProviderSvc = SmartIF<ITrigROBDataProviderSvc>( &*m_robDataProviderSvc ); + if (m_hltROBDataProviderSvc.isValid()) { + logStream() << MSG::INFO << "A ROBDataProviderSvc implementing the HLT interface ITrigROBDataProviderSvc was found." + << endreq; + } else { + logStream() << MSG::INFO << "No ROBDataProviderSvc implementing the HLT interface ITrigROBDataProviderSvc was found." + << endreq; + } + } + + return StatusCode::SUCCESS; +} + +//========================================================================= +// implementation of IService::sysFinalize +//========================================================================= +StatusCode HltEventLoopMgr::sysFinalize() +{ + // initialize the base class + StatusCode sc = MinimalEventLoopMgr::sysFinalize(); + sc.setChecked(); + // delete message stream + if ( m_msg ) delete m_msg; + return sc; +} + +//========================================================================= +// implementation of IService::finalize +//========================================================================= +StatusCode HltEventLoopMgr::finalize() +{ + MsgStream log(msgSvc(), name()); + log << MSG::INFO << " ---> HltEventLoopMgr = " << name() << " finalize " << endreq; + log << MSG::INFO << " Total number of events processed : " << m_total_evt << endreq; + log << MSG::INFO << " Events with error in event processing " << m_failed_evt << endreq; + log << MSG::INFO << " Events with invalid Lvl1 Result " << m_invalid_lvl1_result << endreq; + log << MSG::INFO << " Events with invalid Hlt Result " << m_invalid_hlt_result << endreq; + log << MSG::INFO << " Events with truncated Hlt Result payload " << m_truncated_hlt_result << endreq; + log << MSG::INFO << " Events with truncated Hlt Result payload (send to debug stream) " << m_truncated_hlt_result_to_debug << endreq; + log << MSG::INFO << " Events with truncated Hlt Result payload (not send to debug stream) " << m_truncated_hlt_result_not_to_debug << endreq; + + // Need to release now. Automatic release in destructor is too late since services are already gone. + m_hltTHistSvc.reset(); + m_hltROBDataProviderSvc.reset(); + + StatusCode sc = MinimalEventLoopMgr::finalize(); + if (sc.isFailure()) { + logStream() << MSG::ERROR << "Error in MinimalEventLoopMgr Finalize" << endreq; + } + + // Release all interfaces + m_incidentSvc.release().ignore(); + m_robDataProviderSvc.release().ignore(); + m_evtStore.release().ignore(); + m_detectorStore.release().ignore(); + m_inputMetaDataStore.release().ignore(); + m_THistSvc.release().ignore(); + m_isHelper.release().ignore(); + + return sc; +} + +//========================================================================= +// implementation of IService::sysReinitialize +//========================================================================= +StatusCode HltEventLoopMgr::sysReinitialize() +{ + // initialize the base class + StatusCode sc = MinimalEventLoopMgr::sysReinitialize(); + sc.setChecked(); + // set message stream if not already done + if ( !m_msg ) { + m_msg = new MsgStream( msgSvc(), name() ); + } + return sc; +} + +//========================================================================= +// implementation of IService::reinitialize +//========================================================================= +StatusCode HltEventLoopMgr::reinitialize() +{ + MsgStream log(msgSvc(), name()); + log << MSG::INFO << " ---> HltEventLoopMgr = " << name() << " reinitialize " << endreq; + +//------------------------------------------------------------------------- +// Reset counters +//------------------------------------------------------------------------- + m_total_evt = 0; + m_failed_evt = 0; + m_invalid_lvl1_result = 0; + m_invalid_hlt_result = 0; + m_truncated_hlt_result = 0; + m_truncated_hlt_result_to_debug = 0; + m_truncated_hlt_result_not_to_debug = 0; + + StatusCode sc = MinimalEventLoopMgr::reinitialize(); + if (sc.isFailure()) { + logStream() << MSG::ERROR << "Error in MinimalEventLoopMgr Reinitialize" << endreq; + } + + return sc; +} + +StatusCode HltEventLoopMgr::executeAlgorithms() +{ + // Call the resetExecuted() method of ALL "known" algorithms + // (before we were reseting only the topalgs) + SmartIF<IAlgManager> algMan(serviceLocator()); + if ( algMan.isValid() ) { + const auto& allAlgs = algMan->getAlgorithms() ; + for( auto ialg = allAlgs.begin() ; allAlgs.end() != ialg ; ++ialg ) { + if ( 0 != *ialg ) (*ialg)->resetExecuted(); + } + } + + // Call the execute() method of all top algorithms + return callOnAlgs(&IAlgorithm::sysExecute, "sysExecute", true); +} + + +//========================================================================= +// implementation of IEventProcessor::executeEvent(void* par) ---> for "online" running +//========================================================================= +StatusCode HltEventLoopMgr::executeEvent(void* par) +{ + StatusCode sc; + if (logLevel() <= MSG::DEBUG) { + logStream() << MSG::DEBUG << " ---> HltEventLoopMgr = " << name() + << " executeEvent(par): par = 0x" << MSG::hex << par << MSG::dec << endreq; + } + + { + std::lock_guard<std::mutex>{timeout_mutex}; + + resetTimeout(Athena::Timeout::instance()); + sc = m_evtStore->retrieve(m_currentEvent); + } + + if( sc.isFailure() ) { + logStream() << MSG::ERROR << "Expected an EventInfo object." << endreq; + return StatusCode::FAILURE; + } else { + const auto eventrn = m_currentEvent->event_ID()->run_number(); + if ( (m_currentRun != eventrn)) + logStream() << (m_currentRun ? MSG::WARNING : MSG::DEBUG) + << "Run number changed from " << m_currentRun << " to " + << eventrn << " Complete EventID = " + << *(m_currentEvent->event_ID()) << endreq; + } + + //----------------------------------------------------------------------- + // obtain the HLT conditions update counters from the CTP fragment + //----------------------------------------------------------------------- + std::vector<uint32_t> l1_hltCounters(1,0); // HLT counters from CTP fragment + std::vector<uint32_t> l1_extraPayload; // extra paylaod from CTP fragment + + // find the CTP ROB and get the HLT conditions update counters + bool b_invalidCTPRob = false; + std::vector<uint32_t> ctpRobIdVec(1,m_lvl1CTPROBid.value()); + std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*> ctpRobFragmentVec; + m_robDataProviderSvc->getROBData(ctpRobIdVec,ctpRobFragmentVec); + if( ctpRobFragmentVec.size() == 1 ) { + try { + // get the HLT Counter + l1_hltCounters[0] = CTPfragment::hltCounter( ctpRobFragmentVec[0] ); + l1_extraPayload = CTPfragment::extraPayloadWords( ctpRobFragmentVec[0] ); + } + catch (CTPfragment::NullFragmentPointer& ex) { + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR,ex.what()); + } + catch (CTPfragment::Inconsistency& ex) { + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR,ex.what()); + } + catch (CTPfragment::TimeOutOfRange& ex) { + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR,ex.what()); + } + catch (CTPfragment::TriggerWordsOutOfRange& ex) { + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR,ex.what()); + } + catch (CTPfragment::GenericIssue& ex) { + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR,ex.what()); + } + catch (eformat::Issue& ex) { + std::string issue_msg = std::string("Uncaught eformat issue: ")+std::string(ex.what()); + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR, issue_msg); + } + catch (ers::Issue& ex) { + std::string issue_msg = std::string("Uncaught ERS issue: ")+std::string(ex.what()); + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR, issue_msg); + } + catch (std::exception& ex) { + std::string issue_msg = std::string("Uncaught std exception: ")+std::string(ex.what()); + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR, issue_msg); + } + catch (...) { + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR,"Uncaught unknown exception."); + } + } else { + // no valid CTP fragment found + std::string issue_msg = std::string("No valid CTP fragment found. ") ; + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR, issue_msg); + } + + //----------------------------------------------------------------------- + // create an empty HLT Result Object and register it in StoreGate + // (if this fails, steering will try to create a HLT result object) + //----------------------------------------------------------------------- + auto pHltResult = new HLT::HLTResult; + pHltResult->setLvl1Id(m_currentEvent->event_ID()->event_number()); + HLT::HLTExtraData& extraData = pHltResult->getExtraData(); + extraData.appName = applicationName(); + extraData.statusCode |= hltonl::HLT_PRESCALE_UPDATE; // OK + + // Record it in StoreGate (object can be modified) + sc = m_evtStore->record(pHltResult, m_HltResultName, true); + if(sc.isFailure()) { + logStream() << MSG::ERROR << "Error declaring HLT Result object in SG" << endreq; + } + + //----------------------------------------------------------------------- + // Decode CTP extra payload words + //----------------------------------------------------------------------- + CTPfragment::ExtraPayload ctp_payload; + try { + ctp_payload = CTPfragment::ExtraPayload(l1_extraPayload); + } + catch (CTPfragment::ExtraPayloadTooLong& ex) { + b_invalidCTPRob=true; + ISSUE(IssueSeverity::ERROR, std::string("Invalid CTP fragment. Exception = ")+ex.what()); + } + + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << "CTP extra payload (" << l1_extraPayload.size() << " words): "; + for (std::size_t i=0; i<l1_extraPayload.size(); ++i) logStream() << " " << l1_extraPayload[i]; + + logStream() << ctp_payload << endreq; + } + + // Schedule COOL updates + m_coolHelper->setFolderUpdates(ctp_payload.getFolderUpdates()); + + //----------------------------------------------------------------------- + // Check if an HLT conditions update is required + //----------------------------------------------------------------------- + if (!b_invalidCTPRob) { + sc = checkHltPrescaleUpdate(l1_hltCounters); + if(sc.isFailure()) { + if (pHltResult) { + std::vector<uint32_t>& vExtraData = pHltResult->getExtras(); + // set the HLT PSK flag to 0 to indicate error + vExtraData[vExtraData.size()-2] = 0; // one word for prescale counter (=1 ok, =0 error) + } + logStream() << MSG::FATAL << "HLT Conditions update failed" << endreq; + throw ers::HLTAbort(ERS_HERE, name()+": HLT Conditions update failed"); + } + } + + // Fire BeginEvent "Incident" + m_incidentSvc->fireIncident(EventIncident(*m_currentEvent, name(),"BeginEvent")); + + //----------------------------------------------------------------------- + // COOL updates for LB changes + //----------------------------------------------------------------------- + if ( m_currentLB != m_currentEvent->event_ID()->lumi_block() ) { // LB change + m_currentLB = m_currentEvent->event_ID()->lumi_block(); + + if ( m_coolHelper->hltCoolUpdate(m_currentLB, m_currentRun, + m_sorTime_stamp[0], m_sorTime_stamp[1]).isFailure() ) { + logStream() << MSG::FATAL << "COOL update failed. Aborting." << endreq; + throw ers::HLTAbort(ERS_HERE, name()+": Failure during COOL update"); + } + } + + // Execute Algorithms + bool eventFailed = false; + try { + sc = executeAlgorithms(); + } + catch ( const std::exception& e ) { + logStream() << MSG::ERROR << "Caught a standard exception " + << e.what() << endreq; + sc = StatusCode::FAILURE; + } + catch (...) { + logStream() << MSG::ERROR << "Unknown exception" << endreq; + sc = StatusCode::FAILURE; + } + + if (sc.isSuccess()) { + // Call the execute() method of all output streams + for (ListAlg::iterator ito = m_outStreamList.begin(); ito != m_outStreamList.end(); ito++ ) { + (*ito)->resetExecuted(); + sc = (*ito)->sysExecute(); + if(sc.isFailure()) { + logStream() << MSG::WARNING << "Execution of output stream " << (*ito)->name() << " failed" << endmsg; + eventFailed = true; + } + } + } + else { + eventFailed = true; + } + + // Fire EndEvent "Incident" + m_incidentSvc->fireIncident(EventIncident(*m_currentEvent, name(),"EndEvent")); + + return eventFailed ? StatusCode::FAILURE : StatusCode::SUCCESS; +} + +//========================================================================= +// prepare for run step +//========================================================================= +StatusCode HltEventLoopMgr::prepareForRun(const ptree & pt) +{ + try + { + + (void)TClass::GetClass("vector<unsigned short>"); // preload to overcome an issue with dangling references in serialization + (void)TClass::GetClass("vector<unsigned long>"); + + const SOR * sor; + if(internalPrepareResets().isFailure() || // do the necessary resets and + !(sor = processRunParams(pt))) // update SOR in det store and get it back + return StatusCode::FAILURE; + + auto & soral = getSorAttrList(sor); + updInternal(soral); // update internally kept info + updMetadaStore(soral); // update metadata store + + const EventInfo * evinfo; + if(updMagField(pt).isFailure() || // update mag field when appropriate + updHLTConfigSvc().isFailure() || // update config svc when appropriate + resetCoolValidity().isFailure() || // reset selected proxies/IOV folders + prepXAODEventInfo().isFailure() || // update xAOD event data in SG + !(evinfo = prepEventInfo())) // update old event data in SG + return StatusCode::FAILURE; + + bookAllHistograms(); + + if(prepareAlgs(*evinfo).isSuccess()) + return StatusCode::SUCCESS; + } + catch(const ptree_bad_path & e) + { + logStream() << MSG::ERROR << ST_WHERE + << "Bad ptree path: \"" + << e.path<ptree::path_type>().dump() << "\" - " << e.what() + << endreq; + } + catch(const ptree_bad_data & e) + { + logStream() << MSG::ERROR << ST_WHERE + << "Bad ptree data: \"" + << e.data<ptree::data_type>() << "\" - " << e.what() << endreq; + } + catch(const std::runtime_error& e) + { + logStream() << MSG::ERROR << ST_WHERE + << "Runtime error: " << e.what() << endreq; + } + + return StatusCode::FAILURE; +} + +//========================================================================= +// allow for updates after forking the workers and issue an incident +// to inform the clients +//========================================================================= +StatusCode HltEventLoopMgr::hltUpdateAfterFork(const ptree & pt) +{ + updateDFProps(); + + //----------------------------------------------------------------------- + // Fire "UpdateAfterFork" "Incident" + //----------------------------------------------------------------------- + int worker_id = atoi( (pt.get_child("workerId").data()).c_str() ); + int process_id = getpid(); + m_incidentSvc->fireIncident(HLT::Incidents::UpdateAfterFork(worker_id,process_id,name())); + + readyMsg(); // The event processing will start now + + return StatusCode::SUCCESS; +} + +//========================================================================= +// Hlt: process one event/RoI ---> for "online" running +//========================================================================= +StatusCode HltEventLoopMgr::processRoIs ( + const std::vector<eformat::ROBFragment<const uint32_t*>>& l1_result, + hltinterface::HLTResult& hlt_result, + const hltinterface::EventId& evId) +{ + PtrResetter<const EventInfo, std::mutex> currentEventResetter{m_currentEvent, + timeout_mutex}; + StatusCode sc; + + //----------------------------------------------------------------------- + // increase event counter + //----------------------------------------------------------------------- + m_total_evt++; + + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << " " << endreq; + logStream() << MSG::DEBUG << " +------------+" << endreq; + logStream() << MSG::DEBUG << " | processRoI | for " << name() + << " and event number = " << m_total_evt << " called." + << endreq; + logStream() << MSG::DEBUG << " +------------+" << endreq; + } + + //----------------------------------------------------------------------- + // If HLT THistSvc flush N-tuple buffer + //----------------------------------------------------------------------- + if ( m_hltTHistSvc.isValid() ) { + (m_hltTHistSvc->send()).ignore() ; + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << " ---> THistSvc->send(): m_hltTHistSvc = " + << m_hltTHistSvc << endreq; + } + } + + //----------------------------------------------------------------------- + // reset event qualifiers + //----------------------------------------------------------------------- + m_lvl1id = 0; // Level-1 ID=event no., 32 bit unsigned + m_run_no = 0; // run number, 32 bit unsigned + m_bunch_crossing_id = 0; // bunch crossing ID, 32 bit unsigned + m_l1_Status_Element = 0; + m_l1_Trigger_Type = 0; + m_l1_detev_type = 0; + m_time_stamp = 0; // time stamp - posix time in seconds from 1970, 32 bit unsigned + m_time_stamp_ns_offset = 0; // time stamp ns - ns time offset for time_stamp, 32 bit unsigned + m_lumi_block = 0; // luminosity block identifier, 32 bit unsigned + m_l1_Trigger_Info.assign(16,0); // triggerInfo + + // clear hlt_result structure + // ------------------------- + hlt_result.trigger_info.clear(); + hlt_result.stream_tag.clear(); + hlt_result.psc_errors.clear(); + (*hlt_result.fragment_pointer) = 0; + + //----------------------------------------------------------------------- + // Check received Lvl1 result (Integrity is checked by HLTPU) + // get basic event parameters + // Store LVL1 Result in ROBDataProviderSvc cache + // Get extended information from the CTP ROB + //----------------------------------------------------------------------- + if( l1_result.size() == 0 ) { // no Lvl1 result robs + m_invalid_lvl1_result++; + + failedEvent(hlt_result, + hltonl::PSC_ERROR_NO_L1_RESULT, + "No Lvl1 result ROBs received."); + + return StatusCode::RECOVERABLE; + } + + // *-- SubDetectors in received L1 ROB list + if (m_hist_l1_robs) { + scoped_lock_histogram lock; + for(const auto& rob : l1_result) + { + auto sid = eformat::helper::SourceIdentifier(rob.rob_source_id()); + auto label = std::string{UNEXPECTED_L1R_ROB_LABEL}; + if(std::find(begin(L1R_BINS), end(L1R_BINS), sid.subdetector_id()) + != end(L1R_BINS)) + label = sid.human_detector(); + + m_hist_l1_robs->Fill(label.c_str(), 1.); + } + } + + const OFFLINE_FRAGMENTS_NAMESPACE::DataType* buffer; + // at least 1 Lvl1 rob, set basic parameters + m_lvl1id = l1_result[0].rod_lvl1_id(); // Level-1 ID=event no., 32 bit unsigned + m_run_no = l1_result[0].rod_run_no(); // run number, 32 bit unsigned + m_bunch_crossing_id = l1_result[0].rod_bc_id(); // bunch crossing ID, 32 bit unsigned + l1_result[0].status(buffer); + m_l1_Status_Element = *buffer; + m_l1_Trigger_Type = l1_result[0].rod_lvl1_trigger_type(); + m_l1_detev_type = l1_result[0].rod_detev_type(); + m_time_stamp = 0; // time stamp - posix time in seconds from 1970, 32 bit unsigned + m_time_stamp_ns_offset = 0; // time stamp ns - ns time offset for time_stamp, 32 bit unsigned + m_lumi_block = 0; // luminosity block identifier, 32 bit unsigned + m_l1_Trigger_Info.assign(16,0); // triggerInfo can be obtained from CTP fragment + + // put Lvl1 result in ROBDataProviderSvc cache + m_robDataProviderSvc->setNextEvent(l1_result); + + // find the CTP ROB and get the complete event info data + std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*> ctpRobFragmentVec; + m_robDataProviderSvc->getROBData(m_ctpRobIdVec,ctpRobFragmentVec); + bool b_invalidCTPRob = false; + std::ostringstream ost; + if( ctpRobFragmentVec.size() == 1 ) { + try { + m_lvl1id = ctpRobFragmentVec[0]->rod_lvl1_id(); // Level-1 ID=event no., 32 bit unsigned + m_run_no = ctpRobFragmentVec[0]->rod_run_no(); // run number, 32 bit unsigned + m_bunch_crossing_id = ctpRobFragmentVec[0]->rod_bc_id(); // bunch crossing ID, 32 bit unsigned + ctpRobFragmentVec[0]->status(buffer); + m_l1_Status_Element = *buffer; + m_l1_Trigger_Type = ctpRobFragmentVec[0]->rod_lvl1_trigger_type(); + m_l1_detev_type = ctpRobFragmentVec[0]->rod_detev_type(); + // get time_stamp - posix time in seconds from 1970, and time_stamp_ns - ns time offset for time_stamp + CTPfragment::time( ctpRobFragmentVec[0], m_time_stamp, m_time_stamp_ns_offset ); + // luminosity block identifier, 32 bit unsigned + m_lumi_block = CTPfragment::lumiBlockNumber( ctpRobFragmentVec[0] ); + // get the L1 trigger info + m_l1_Trigger_Info = CTPfragment::triggerDecision( ctpRobFragmentVec[0] ); + + b_invalidCTPRob = !checkEventIdConsistency(evId); + } + catch (CTPfragment::NullFragmentPointer& ex) { + m_invalid_lvl1_result++; + if (m_lvl1CTPROBcheck) { + b_invalidCTPRob=true; + ost << " Invalid CTP fragment. Exception = " << ex.what(); + } + ISSUE(IssueSeverity::ERROR,ex.what()); + } + catch (CTPfragment::Inconsistency& ex) { + m_invalid_lvl1_result++; + if (m_lvl1CTPROBcheck) { + b_invalidCTPRob=true; + ost << " Invalid CTP fragment. Exception = " << ex.what(); + } + ISSUE(IssueSeverity::ERROR,ex.what()); + } + catch (CTPfragment::TimeOutOfRange& ex) { + m_invalid_lvl1_result++; + if (m_lvl1CTPROBcheck) { + b_invalidCTPRob=true; + ost << " Invalid CTP fragment. Exception = " << ex.what(); + } + ISSUE(IssueSeverity::ERROR,ex.what()); + } + catch (CTPfragment::TriggerWordsOutOfRange& ex) { + m_invalid_lvl1_result++; + if (m_lvl1CTPROBcheck) { + b_invalidCTPRob=true; + ost << " Invalid CTP fragment. Exception = " << ex.what(); + } + ISSUE(IssueSeverity::ERROR,ex.what()); + } + catch (CTPfragment::GenericIssue& ex) { + m_invalid_lvl1_result++; + if (m_lvl1CTPROBcheck) { + b_invalidCTPRob=true; + ost << " Invalid CTP fragment. Exception = " << ex.what(); + } + ISSUE(IssueSeverity::ERROR,ex.what()); + } + catch (eformat::Issue& ex) { + m_invalid_lvl1_result++; + std::string issue_msg = std::string("Uncaught eformat issue: ")+std::string(ex.what()); + if (m_lvl1CTPROBcheck) { + b_invalidCTPRob=true; + ost << " Invalid CTP fragment. Exception = " << ex.what(); + } + ISSUE(IssueSeverity::ERROR, issue_msg); + } + catch (ers::Issue& ex) { + m_invalid_lvl1_result++; + std::string issue_msg = std::string("Uncaught ERS issue: ")+std::string(ex.what()); + if (m_lvl1CTPROBcheck) { + b_invalidCTPRob=true; + ost << " Invalid CTP fragment. Exception = " << ex.what(); + } + ISSUE(IssueSeverity::ERROR, issue_msg); + } + catch (std::exception& ex) { + m_invalid_lvl1_result++; + std::string issue_msg = std::string("Uncaught std exception: ")+std::string(ex.what()); + if (m_lvl1CTPROBcheck) { + b_invalidCTPRob=true; + ost << " Invalid CTP fragment. Exception = " << ex.what(); + } + ISSUE(IssueSeverity::ERROR, issue_msg); + } + catch (...) { + m_invalid_lvl1_result++; + if (m_lvl1CTPROBcheck) { + b_invalidCTPRob=true; + ost << " Invalid CTP fragment. Uncaught unknown exception."; + } + ISSUE(IssueSeverity::ERROR,"Uncaught unknown exception."); + } + } else { + // no valid CTP fragment found + m_invalid_lvl1_result++; + if (m_hist_l1_robs) + lock_histogram_operation<TH1F>(m_hist_l1_robs)->Fill(MISSING_L1R_CTP_LABEL, 1.); + + std::string issue_msg = std::string("No valid CTP fragment found. ") ; + if (m_hltROBDataProviderSvc.isValid()) issue_msg = issue_msg + std::string("\n") + + m_hltROBDataProviderSvc->dumpROBcache() ; + if (m_lvl1CTPROBcheck) { + b_invalidCTPRob=true; + ost << " No valid CTP fragment found. " ; + } + ISSUE(IssueSeverity::ERROR, issue_msg); + } + + // in case a check of the CTP Rob is requested and an invalid fragment was found + // skip the event and put it on the debug stream + // ----------------------------------------------------------------------------- + if (m_lvl1CTPROBcheck && b_invalidCTPRob) { + ost << " Skip event requested. "; + failedEvent(hlt_result, + hltonl::PSC_ERROR_INVALID_CTP_RESULT, + ost.str()); + + return StatusCode::RECOVERABLE; + } + + // Check for other missing L1 ROBs + auto missing_l1_robs = missingL1Robs(l1_result); + if(!missing_l1_robs.empty()) + { + ++m_invalid_lvl1_result; + failedEvent(hlt_result, hltonl::PSC_ERROR_NO_L1_RESULT, + missingL1RobsMsg(missing_l1_robs)); + + return StatusCode::RECOVERABLE; + } + + //----------------------------------------------------------------------- + // Clear the event store, if used in the event loop + //----------------------------------------------------------------------- + sc = m_evtStore->clearStore(); + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << " ---> Clear of Event data store " << sc << endreq; + } + if(sc.isFailure()) { + failedEvent(hlt_result, hltonl::PSC_ERROR_SG_CLEAR_FAILED, + "Clear of Event data store failed."); + return sc; + } + + // create an EventInfo Object to fire the incidents and register in evt store + auto pEvent = new EventInfo(new EventID(m_run_no, + evId.globalId, + m_time_stamp, + m_time_stamp_ns_offset, + m_lumi_block, + m_bunch_crossing_id, + std::get<0>(m_detector_mask), + std::get<1>(m_detector_mask), + std::get<2>(m_detector_mask), + std::get<3>(m_detector_mask)), + new EventType(), + new TriggerInfo(m_l1_Status_Element, + m_lvl1id, + m_l1_Trigger_Type, + m_l1_Trigger_Info)); + + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << " +-----------+ " << endreq; + logStream() << MSG::DEBUG << " | New Event | Run = " << m_run_no + << " / Level-1 ID = " << m_lvl1id + << " / global Event ID = " << evId.globalId + << endreq; + logStream() << MSG::DEBUG << " +-----------+ " << endreq; + logStream() << MSG::DEBUG << " Complete EventID = " << *(pEvent->event_ID()) << endreq; + logStream() << MSG::DEBUG << " EventType = " << ((pEvent->event_type())->typeToString()) << endreq; + logStream() << MSG::DEBUG << " TriggerInfo = " << *(pEvent->trigger_info()) << endreq; + logStream() << MSG::DEBUG << " Current Run number = " << m_currentRun << endreq; + } + + // Record it in StoreGate + if(m_evtStore->record(pEvent, "EventInfo").isFailure()) + { + failedEvent(hlt_result, hltonl::PSC_ERROR_NO_EVENTINFO, + "Error recording EventInfo object in SG"); + + return StatusCode::FAILURE; + } + + //----------------------------------------------------------------------- + // process the RoI(s)/Event + //----------------------------------------------------------------------- + sc = executeEvent(NULL); + if(sc.isFailure()) { + failedEvent(hlt_result, hltonl::PSC_ERROR_UNCLASSIFIED, + "An unknown error occured during event processing", + false /* no empty result */); + } + + // Get the xAOD::EventInfo from SG + xAOD::EventInfo * xev{nullptr}; + if(m_evtStore->retrieve(xev, "EventInfo").isFailure()) + { + logStream() << MSG::WARNING << ST_WHERE + << "Could not retrieve xAOD::EventInfo in store gate. " + << "If running in HelloWorld algorithms, this is OK." + << endreq; + } + + logStream() << MSG::DEBUG << " new xAOD::EventInfo: " << xev << endreq; + + //----------------------------------------------------------------------- + // build HLT result + //----------------------------------------------------------------------- + HltResult(hlt_result, pEvent, xev); + // fill histograms + fillHltResultHistograms(hlt_result); + + return sc; +} + +//========================================================================= +// implementation of IService::stop() ---> for "online" running +//========================================================================= +StatusCode HltEventLoopMgr::stop() +{ + // Do nothing if we are already stopped + if ( FSMState() != Gaudi::StateMachine::RUNNING ) + return StatusCode::SUCCESS; + + if (logLevel() <= MSG::DEBUG) { + logStream() << MSG::DEBUG << " ---> HltEventLoopMgr = " << name() << " stop() " << endreq; + } + + //----------------------------------------------------------------------- + // Fire EndRun "Incident" + //----------------------------------------------------------------------- + m_incidentSvc->fireIncident(Incident(name(), IncidentType::EndRun)); + + //----------------------------------------------------------------------- + // Call endRun() and stop() of all algorithms + //----------------------------------------------------------------------- + auto suc1 = callOnAlgs(&IAlgorithm::sysEndRun, "sysEndRun").isSuccess(); + auto suc2 = callOnAlgs(&IAlgorithm::sysStop, "sysStop").isSuccess(); + + return (suc1 && suc2) ? StatusCode::SUCCESS : StatusCode::FAILURE; +} + +//========================================================================= +// implementation of ITrigEventLoopMgr::timeOutReached ---> for "online" running +//========================================================================= +/** + * Called by the PSC once the HLTPU signals the timeout warning. + * + * !!! This method is executed in the context of the timeout thread !!! + * !!! Make sure the code is thread-safe !!! + * + */ +StatusCode HltEventLoopMgr::timeOutReached(const ptree& pt) +{ + IAlgorithm* alg = m_algContextSvc ? m_algContextSvc->currentAlg() : 0; + + // add current algorithm info + std::ostringstream tmsg; + tmsg << "Timeout warning received" + << (alg ? (" while executing '"+alg->name()+"'. ") : ". "); + + // set timeout and add current event info + { + std::lock_guard<std::mutex>{timeout_mutex}; + + setTimeout(Athena::Timeout::instance()); + if (m_currentEvent) + tmsg << " On event " << *m_currentEvent->event_ID() << ". "; + else + tmsg << " Unknown event - outside of event processing? "; + } + + // add time interval info + auto starts = pt.get_optional<long long>("StartTime_s"); + if(starts) + { + auto ends = std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::steady_clock::now().time_since_epoch()).count(); + tmsg << (ends - *starts) << " seconds elapsed since "; + } + else + tmsg << "No information of when "; + + tmsg << "the HLTPU last started counting."; + + // log timeout message + ERS_HLT_WARNING(tmsg.str()); + + // Also fire timeout incident (this seems to cause problems, see #66066) + // m_incidentSvc->fireIncident( HLT::Incidents::EventTimeout(name()) ); + + return StatusCode::SUCCESS; +} + + + +//========================================================================= +// implementation of ITrigEventLoopMgr::checkHltPrescaleUpdate() ---> for "online" running +//========================================================================= +StatusCode HltEventLoopMgr::checkHltPrescaleUpdate(std::vector<uint32_t>& hltCounter) +{ + if (logLevel() <= MSG::DEBUG) { + logStream() << MSG::DEBUG << " ---> HltEventLoopMgr = " << name() + << " hltConditionsUpdate(std::vector<uint32_t>&): size of input = " << hltCounter.size() << ": "; + for (size_t i=0; i<hltCounter.size(); ++i) logStream() << hltCounter[i] << " "; + logStream() << endreq; + } + if ( hltCounter.empty() ) return StatusCode::SUCCESS; + + // First (and only used) element is LB of the prescale update + uint32_t new_hltPrescaleUpdateLB = hltCounter[0]; + + // Only update if counter (lumiblock for update) changed (or first event) + if ( m_l1_hltPrescaleUpdateLB != new_hltPrescaleUpdateLB ) { + m_l1_hltPrescaleUpdateLB = new_hltPrescaleUpdateLB; + + // Retrieve EventInfo object + const EventInfo* pEvent(0); + StatusCode sc = m_evtStore->retrieve(pEvent); + if(sc.isFailure()) { + logStream() << MSG::ERROR << "Unable to retrieve EventInfo object" << endreq; + return sc; + } + + logStream() << MSG::INFO << "Prescale update requested for lumiblock " + << m_l1_hltPrescaleUpdateLB << ". Current event: " << *pEvent->event_ID() << endreq; + + // Perform prescale update right away (including on first event) + sc = hltPrescaleUpdate(m_l1_hltPrescaleUpdateLB); + return sc; + } + + return StatusCode::SUCCESS; +} + + +//========================================================================= +// implementation of ITrigEventLoopMgr::hltPrescaleUpdate() ---> for "online" running +//========================================================================= +StatusCode HltEventLoopMgr::hltPrescaleUpdate(uint32_t lumiBlock) +{ + if ( !m_hltConfigSvc ) { + return StatusCode::SUCCESS; + } + + // ID must be unqiue across runs until DbProxy gets restarted + unsigned int id = m_currentRun*10000 + lumiBlock; + logStream() << MSG::INFO << " ---> HltEventLoopMgr = " << name() + << " calling HLTConfigSvc::updatePrescaleSets(" << id << ")" << endreq; + StatusCode sc = m_hltConfigSvc->updatePrescaleSets(id); + + return sc; +} + +//========================================================================= +// check that a ROB ID is enabled for readout in OKS ---> for "online" running +//========================================================================= +bool HltEventLoopMgr::isRobEnabled(uint32_t robid) const +{ + bool b_enabled = true; + + // check if given ROB is actually enabled for readout + // Consider some ROBs from SubDetectorGroup TDAQ as always enabled + if ((m_enabledROBs.value().size() != 0) && + !skipEnabledCheck(robid)) + { + auto rob_enabled_it = std::find(m_enabledROBs.value().begin(), + m_enabledROBs.value().end(), + robid); + if(rob_enabled_it == m_enabledROBs.value().end()) + { + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << "---> ROB Id : 0x" << MSG::hex << robid + << MSG::dec << " will not be retrieved, since it is not on " + "the list of enabled ROBs." << endreq; + + b_enabled = false; + } + } + + return b_enabled; +} + +//========================================================================= +// check that a Sub Detector ID is enabled for readout in OKS ---> for "online" running +//========================================================================= +bool HltEventLoopMgr::isSubDetectorEnabled(uint32_t subdetid) const +{ + bool b_enabled = true; + + // check if given subdetector is actually enabled for readout + if ((m_enabledSubDetectors.value().size() != 0) && + !skipEnabledCheck(static_cast<eformat::SubDetector>(subdetid))) + { + auto sd_enabled_it = std::find(m_enabledSubDetectors.value().begin(), + m_enabledSubDetectors.value().end(), + subdetid); + if(sd_enabled_it == m_enabledSubDetectors.value().end()) + { + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << "---> Sub Detector Id : 0x" << MSG::hex + << subdetid << MSG::dec << " will not be retrieved, since " + "it is not on the list of enabled Sub Detectors." << endreq; + b_enabled = false; + } + } + + return b_enabled; +} + +//========================================================================= +// filter a set of robs according to whether or not they are enabled +//========================================================================= +std::set<uint32_t> +HltEventLoopMgr::filterRobs(const std::set<uint32_t> robs) const +{ + auto ret = decltype(robs){}; + for(const auto& r : robs) + if(isRobEnabled(r)) + ret.insert(r); + + return ret; +} + +//========================================================================= +// filter a set of dets according to whether or not they are enabled +//========================================================================= +std::set<eformat::SubDetector> +HltEventLoopMgr::filterDets(const std::set<uint32_t> dets) const +{ + auto ret = std::set<eformat::SubDetector>{}; + for(const auto& d : dets) + if(isSubDetectorEnabled(d)) + ret.insert(static_cast<eformat::SubDetector>(d)); + + return ret; +} + +//========================================================================= +// Obsolete methods for online running +//========================================================================= +StatusCode HltEventLoopMgr::nextEvent(int maxevt) +{ + logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq; + logStream() << MSG::ERROR << " | method ---> HltEventLoopMgr::nextEvent(int maxevt) <--- called | " << endreq; + logStream() << MSG::ERROR << " | This method can not be used in trigger since the event loop is | " << endreq; + logStream() << MSG::ERROR << " | controlled by the data flow software. | " << endreq; + logStream() << MSG::ERROR << " | Method is not implemented | " << endreq; + logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq; + logStream() << MSG::ERROR << " maxevt = " << maxevt << endreq; + logStream() << MSG::ERROR << " Type info = " << System::typeinfoName(typeid(*this)) << endreq; + return StatusCode::FAILURE; +} + +StatusCode HltEventLoopMgr::executeRun(int) +{ + logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq; + logStream() << MSG::ERROR << " | method ---> HltEventLoopMgr::executeRun(int) <--- called | " << endreq; + logStream() << MSG::ERROR << " | This method can not be used in trigger since the event loop is | " << endreq; + logStream() << MSG::ERROR << " | controlled by the data flow software. | " << endreq; + logStream() << MSG::ERROR << " | Method is not implemented | " << endreq; + logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq; + logStream() << MSG::ERROR << " Type info = " << System::typeinfoName(typeid(*this)) << endreq; + return StatusCode::FAILURE; +} + +StatusCode HltEventLoopMgr::stopRun() +{ + logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq; + logStream() << MSG::ERROR << " | method ---> HltEventLoopMgr::stopRun() <--- called | " << endreq; + logStream() << MSG::ERROR << " | This method is not implemented for online usage. Call stop() instead. | " << endreq; + logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq; + logStream() << MSG::ERROR << " Type info = " << System::typeinfoName(typeid(*this)) << endreq; + return StatusCode::FAILURE; +} + +//========================================================================= +// HltEmptyResultROB() +//========================================================================= +void HltEventLoopMgr::HltEmptyResultROB(hltinterface::HLTResult& hlt_result, + uint32_t run_no, uint32_t lvl1_id, uint32_t bunch_crossing_id, + uint32_t l1_Trigger_Type, uint32_t l1_detev_type, + hltonl::PSCErrorCode pscErrorCode) +{ + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << "---> HltEmptyResultROB() for " << name() + << " and sub detector = " << eformat::helper::SubDetectorDictionary.string(eformat::TDAQ_HLT) + << " called " << endreq; + } + + // + // Set the PSC error words + // ----------------------- + // + HltSetPscError(hlt_result, pscErrorCode); + + // + // Create a dummy HLT result ROB + // ----------------------------- + // + + // the second status element + hltonl::ResultStatusCode hlt_status = hltonl::DUMMY_HLT_RESULT ; + + // Build the third status elements for the dummy HLT result + // number of status words used (in case of PSC error = 3, otherwise = 2) + uint32_t n_status_word = 3; + m_status_words[0] = SW_FAIL.code(); + m_status_words[1] = hlt_status; + m_status_words[2] = pscErrorCode; //this means "dummy HLT result, with no data due PSC error" + + if (!pscErrorCode) { + m_status_words[0] = SW_UNCLASSIFIED.code(); //this means "dummy HLT result, with no data, no PSC error" + n_status_word = 2; + } + + // Build an empty HLT result + eformat::helper::SourceIdentifier src(eformat::TDAQ_HLT, 0); + eformat::write::ROBFragment rob(src.code(), run_no, lvl1_id, bunch_crossing_id, l1_Trigger_Type, l1_detev_type, + 0, 0, eformat::STATUS_FRONT); + rob.status(n_status_word, m_status_words); + rob.rod_status(n_status_word, m_status_words); + + // find the maximum allowed payload + int hltr_max_payload = hlt_result.max_result_size - rob.size_word() ; + if ( hlt_result.max_result_size <= rob.size_word() ) { + logStream() << MSG::ERROR + << "Can not create empty HLT result ROB with available ROB buffer size ! Available buffer size = " + << hlt_result.max_result_size << " Number of header words used by empty ROB = " << rob.size_word() + << endreq; + return; + } + + // Create a dummy HLT result and check data size + uint32_t* hltr_data(0); + int hltr_data_size = 0; + HLT::HLTResult emptyHLTResult; + emptyHLTResult.setLvl1Id(lvl1_id); + + HLT::HLTExtraData& extraData = emptyHLTResult.getExtraData(); + extraData.appName = applicationName(); + extraData.statusCode &= ~hltonl::HLT_PRESCALE_UPDATE; // error (clear bit) + + bool serializationOk = emptyHLTResult.serialize( hltr_data, hltr_data_size, hltr_max_payload); + + if ( !serializationOk ) { + // Update status words for dummy HLT result + hlt_status = hltonl::DUMMY_HLT_RESULT_TRUNCATED; + m_status_words[0] = SW_TRUNCATION.code() ; + m_status_words[1] = hlt_status ; + } + + if (( hltr_data_size > hltr_max_payload)) { // consistency check + logStream() << MSG::ERROR + << "Inconsistency for created dummy HLT result ROB. Returned data size = " << hltr_data_size + << " is greater than allowed max. payload size = " << hltr_max_payload << "." + << endreq; + hltr_data_size = hltr_max_payload; + + // Update status words for dummy HLT result + hlt_status = hltonl::DUMMY_HLT_RESULT_TRUNCATED; + m_status_words[0] = SW_TRUNCATION.code(); + m_status_words[1] = hlt_status ; + } + + // build the fragment + rob.status(n_status_word, m_status_words); + rob.rod_status(n_status_word, m_status_words); + rob.rod_data(hltr_data_size, hltr_data); + + // + // store the dummy HLT ROB fragment in the hlt_result structure + // ------------------------------------------------------------ + // + // The maximum possible space is already allocated by the HLTMPPU + // copy the ROB contents into the allocated memory + auto next_fragment = hlt_result.fragment_pointer; + auto spaceleft = hlt_result.max_result_size; + addRobToHLTResult(hlt_result, rob, next_fragment, spaceleft); + + // delete the data array + if (hltr_data != 0) delete[] hltr_data; + + return; +} // end method HltEventLoopMgr::HltEmptyResultROB + +//========================================================================= +// HltEmptyResultROB() ---> for "online" running +//========================================================================= +void HltEventLoopMgr::HltEmptyResultROB(hltinterface::HLTResult& hlt_result, hltonl::PSCErrorCode pscErrorCode) +{ + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << "---> HltEmptyResultROB() for " + << name() << " called " << endreq; + } + + HltEmptyResultROB(hlt_result, + m_run_no, m_lvl1id, m_bunch_crossing_id, + m_l1_Trigger_Type, m_l1_detev_type, + pscErrorCode); + return; +} // end method HltEventLoopMgr::HltEmptyResult + +//========================================================================= +// HltResultROBs() +//========================================================================= +hltonl::PSCErrorCode HltEventLoopMgr::HltResultROBs( + hltinterface::HLTResult& hlt_result, + uint32_t run_no, uint32_t lvl1_id, uint32_t bunch_crossing_id, + uint32_t l1_Trigger_Type, uint32_t l1_detev_type, + const std::vector<TriggerInfo::number_type>& trigger_info, + const std::vector<TriggerInfo::StreamTag>& stream_tags, + const std::vector<xAOD::EventInfo::StreamTag>& xsts) +{ + HLT::HLTResult* dobj{0}; + auto hlt_decision = hltonl::PSC_FORCED_REJECT; + auto ecode = hltonl::PSC_ERROR_UNCLASSIFIED; + if(!m_forceHltReject) + { + // preliminary hlt_result setup + setStreamTags(hlt_result, stream_tags); + mergeStreamTags(hlt_result, xsts); + hlt_result.trigger_info = trigger_info; + + // Get Pesa HLT Result from Steering + StatusCode sc; + if(!(m_evtStore->transientContains<HLT::HLTResult>(m_HltResultName)) || + (sc = m_evtStore->retrieve(dobj,m_HltResultName)).isFailure()) + { + hlt_decision = hltonl::PSC_DEBUG; + logStream() << MSG::ERROR << ST_WHERE + << "Error retrieving HLTResult from StoreGate with key = " + << m_HltResultName << endreq; + + ecode = sc.isFailure() ? hltonl::PSC_ERROR_NO_HLTRESULT_RETRIEVED + : hltonl::PSC_ERROR_NO_HLTRESULT_FOUND; + } + else if((hlt_decision = processHltDecision(hlt_result)) != + hltonl::STEERING_REJECT) + { + // Got Steering's HLT Result and confirmed the event should be accepted + auto serializationOk = true; + ecode = serializeRobs(hlt_result, serializationOk, dobj, run_no, lvl1_id, + bunch_crossing_id, l1_Trigger_Type, l1_detev_type); + if(!ecode) + recordEDMSizeInfo(dobj->getNavigationResult().size(), serializationOk); + + // The HLT result got truncated, put the event on a special debug stream if requested + if (!serializationOk) { + m_truncated_hlt_result++; + if (m_hist_Hlt_truncated_result) { + scoped_lock_histogram lock; + m_hist_Hlt_truncated_result->Fill(1.); + } + if ((!m_HltTruncationDebugStreamName.value().empty()) && + (m_writeHltTruncationToDebug.value())) { + // check if event should be not send to the debug stream (e.g. Cost Monitoring) + bool sendToDebug(true); + for (auto it_st : hlt_result.stream_tag) { + auto p = std::find(m_excludeFromHltTruncationDebugStream.value().begin(), + m_excludeFromHltTruncationDebugStream.value().end(), + (it_st).name); + if (p != m_excludeFromHltTruncationDebugStream.value().end()) sendToDebug=false; + } + if (sendToDebug) { + m_truncated_hlt_result_to_debug++; + if (m_hist_Hlt_truncated_result) { + scoped_lock_histogram lock; + m_hist_Hlt_truncated_result->Fill(2.); + } + hlt_result.stream_tag.clear(); + addDebugStreamTag(hlt_result, m_HltTruncationDebugStreamName); + logStream() << MSG::ERROR << ST_WHERE + << "HLTResult was truncated. Event send to debug stream = " + << m_HltTruncationDebugStreamName << endreq; + } else { + m_truncated_hlt_result_not_to_debug++; + if (m_hist_Hlt_truncated_result) { + scoped_lock_histogram lock; + m_hist_Hlt_truncated_result->Fill(3.); + } + logStream() << MSG::WARNING << ST_WHERE + << "HLTResult was truncated. Event was NOT send to debug stream = " + << m_HltTruncationDebugStreamName + << " because an exclusion stream tag name matched from = " << m_excludeFromHltTruncationDebugStream.value() + << endreq; + } + } else { + m_truncated_hlt_result_not_to_debug++; + if (m_hist_Hlt_truncated_result) { + scoped_lock_histogram lock; + m_hist_Hlt_truncated_result->Fill(3.); + } + } + } + } + } + + if (m_hist_eventAcceptFlags) + lock_histogram_operation<TH1F>(m_hist_eventAcceptFlags)->Fill( + static_cast<float>(m_mapAccept.codeToHash(hlt_decision))); + + if(logLevel() <= MSG::DEBUG) + { + logStream() << MSG::DEBUG << ST_WHERE << "Decision = " + << hltonl::PrintHltAcceptFlag(hlt_decision) << "\n" + << hlt_result << endreq; + if(dobj) + { + const auto& extraData = dobj->getExtraData(); + logStream() << MSG::DEBUG << ST_WHERE + << "HltResult extra data: Host name = " << extraData.appName + << ", status code = " << extraData.statusCode << endreq; + } + } + + return ecode; +} // end method HltEventLoopMgr::HltResultROBs + +//========================================================================= +// HltResult() ---> for "online" running +//========================================================================= +void HltEventLoopMgr::HltResult(hltinterface::HLTResult& hlt_result, + const EventInfo* pEvent, + const xAOD::EventInfo * xev) +{ + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << "---> HltResult() for " << name() << " called " << endreq; + } + + using xev_stags_t = decltype(xev->streamTags()); + auto xev_stags = xev ? xev->streamTags() : xev_stags_t{}; + + hltonl::PSCErrorCode hlt_psc_error = HltResultROBs(hlt_result, + m_run_no, m_lvl1id, m_bunch_crossing_id, + m_l1_Trigger_Type, m_l1_detev_type, + pEvent->trigger_info()->eventFilterInfo(), + pEvent->trigger_info()->streamTags(), + xev_stags); + // If there was an error when building the HLT result ROB, + // put the event on the debug stream and try to create a dummy result ROB + if (hlt_psc_error) { + // put event on debug stream + addDebugStreamTag(hlt_result, m_HltDebugStreamName.value()); + // make empty HLT result ROB + HltEmptyResultROB(hlt_result,hlt_psc_error); + // increase counter + m_invalid_hlt_result++; + } + + return; +} // end method HltEventLoopMgr::HltResult + +//========================================================================= +void HltEventLoopMgr::bookHistograms() +{ + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << "---> bookHistograms() for " << name() + << " called. Do monitoring = " << m_doMonitoring.value() << endreq; + } + + // return if no monitoring is requested + if ( !m_doMonitoring.value() ) { return; } + + std::vector<TH1F**> regHistsTH1F; + regHistsTH1F.reserve(14); + std::vector<TProfile**> regHistsTProfile; + regHistsTProfile.reserve(4); + + // monitoring information root directory + const std::string histPath = std::string("/EXPERT/") + getGaudiThreadGenericName(name()) + "/"; + + // +--------------------+ + // *-- | Event accept flags | + // +--------------------+ + uint32_t n_bins_eventAcceptFlags = hltonl::NUM_ACCEPTANCE_FLAGS; + m_hist_eventAcceptFlags = new TH1F ("EventAcceptFlags", + "EventAcceptFlags;;entries", n_bins_eventAcceptFlags, 0.5, n_bins_eventAcceptFlags+0.5); + + if (m_hist_eventAcceptFlags) { + for (hltonl::MapAcceptFlag::EnumMap::const_iterator map_it = m_mapAccept.begin(); map_it != m_mapAccept.end(); map_it++) { + m_hist_eventAcceptFlags->GetXaxis()->SetBinLabel( ((*map_it).second).second , (((*map_it).second).first).c_str() ); + } + regHistsTH1F.push_back(&m_hist_eventAcceptFlags); + } + + // +-----------------------+ + // *-- | HLT result properties | + // +-----------------------+ + // *-- HLT result size plot + m_hist_Hlt_result_size = new TH1F ((m_histProp_Hlt_result_size.value().title()).c_str(), + (m_histProp_Hlt_result_size.value().title() + ";words;entries").c_str(), + m_histProp_Hlt_result_size.value().bins(), + m_histProp_Hlt_result_size.value().lowEdge(), + m_histProp_Hlt_result_size.value().highEdge()); + if (m_hist_Hlt_result_size) { + CAN_REBIN(m_hist_Hlt_result_size); + regHistsTH1F.push_back(&m_hist_Hlt_result_size); + } + + // *-- HLT result status codes + uint32_t n_bins_ResultStatus = hltonl::NUM_HLT_STATUS_CODES; + m_hist_Hlt_result_status = new TH1F ("HltResultStatusCodes", + "HltResultStatusCodes;;entries", n_bins_ResultStatus, 0.5, n_bins_ResultStatus+0.5); + + if (m_hist_Hlt_result_status) { + // do not print label for normal HLT result with no errors, it is not filled + for (hltonl::MapResultStatusCode::EnumMap::const_iterator map_it = m_mapResultStatus.begin(); map_it != m_mapResultStatus.end(); map_it++) { + if ( (*map_it).first == hltonl ::NORMAL_HLT_RESULT ) { + m_hist_Hlt_result_status->GetXaxis()->SetBinLabel( ((*map_it).second).second, (((*map_it).second).first+" (bin not filled)").c_str() ); + } else { + m_hist_Hlt_result_status->GetXaxis()->SetBinLabel( ((*map_it).second).second, (((*map_it).second).first).c_str() ); + } + } + regHistsTH1F.push_back(&m_hist_Hlt_result_status); + } + + // *-- HLT result truncation + uint32_t n_bins_ResultTruncation = 3; + m_hist_Hlt_truncated_result = new TH1F ("HltResultTruncation", + "HltResultTruncation;;entries", n_bins_ResultTruncation, 0.5, n_bins_ResultTruncation+0.5); + + if (m_hist_Hlt_truncated_result) { + m_hist_Hlt_truncated_result->GetXaxis()->SetBinLabel( 1, std::string("Truncated HLT result").c_str() ); + m_hist_Hlt_truncated_result->GetXaxis()->SetBinLabel( 2, std::string("Truncated HLT result (send to debug stream)").c_str() ); + m_hist_Hlt_truncated_result->GetXaxis()->SetBinLabel( 3, std::string("Truncated HLT result (not send to debug stream)").c_str() ); + regHistsTH1F.push_back(&m_hist_Hlt_truncated_result); + } + + // *-- HLT result size plot (Stream Physiscs Main) + m_hist_Hlt_result_size_physics = new TH1F (((m_histProp_Hlt_result_size.value().title()) + "-(Stream (Main,physiscs))").c_str(), + (m_histProp_Hlt_result_size.value().title() + "-(StreamType Physiscs)" + ";words;entries").c_str(), + m_histProp_Hlt_result_size.value().bins(), + m_histProp_Hlt_result_size.value().lowEdge(), + m_histProp_Hlt_result_size.value().highEdge()); + if (m_hist_Hlt_result_size_physics) { + CAN_REBIN(m_hist_Hlt_result_size_physics); + regHistsTH1F.push_back(&m_hist_Hlt_result_size_physics); + } + + // *-- HLT result size plot (Stream Express) + m_hist_Hlt_result_size_express = new TH1F (((m_histProp_Hlt_result_size.value().title()) + "-(Stream (express,express))").c_str(), + (m_histProp_Hlt_result_size.value().title() + "-(StreamType Express)" + ";words;entries").c_str(), + m_histProp_Hlt_result_size.value().bins(), + m_histProp_Hlt_result_size.value().lowEdge(), + m_histProp_Hlt_result_size.value().highEdge()); + if (m_hist_Hlt_result_size_express) { + CAN_REBIN(m_hist_Hlt_result_size_express); + regHistsTH1F.push_back(&m_hist_Hlt_result_size_express); + } + + // *-- HLT result size plot (Stream calibration, DataScouting results) + m_hist_Hlt_result_size_DataScouting = new TH1F (((m_histProp_Hlt_result_size.value().title()) + "-(Streams (DataScouting_*,calibration))").c_str(), + (m_histProp_Hlt_result_size.value().title() + "-(StreamType Calibration, DataScouting)" + ";words;entries").c_str(), + m_histProp_Hlt_result_size.value().bins(), + m_histProp_Hlt_result_size.value().lowEdge(), + m_histProp_Hlt_result_size.value().highEdge()); + if (m_hist_Hlt_result_size_DataScouting) { + CAN_REBIN(m_hist_Hlt_result_size_DataScouting); + regHistsTH1F.push_back(&m_hist_Hlt_result_size_DataScouting); + } + + // *-- HLT result size profile plot for all stream types "physiscs" + m_hist_HltResultSizes_Stream_physics = new TProfile( std::string("Average Hlt Result size for physics streams").c_str(), + std::string("Stream Name;;Average size in words").c_str(), + 1, + (double) 0., (double) 1., + (double) 0., (double) 3000000.); + if (m_hist_HltResultSizes_Stream_physics) { + m_hist_HltResultSizes_Stream_physics->GetXaxis()->SetBinLabel(1,std::string("NoTag").c_str() ); + CAN_REBIN(m_hist_HltResultSizes_Stream_physics); + regHistsTProfile.push_back(&m_hist_HltResultSizes_Stream_physics); + } + + // *-- HLT result size profile plot for all stream names "DataScouting" + m_hist_HltResultSizes_Stream_DataScouting = new TProfile( std::string("Average Hlt Result size for data scouting streams").c_str(), + std::string("Stream Name;;Average size in words").c_str(), + 1, + (double) 0., (double) 1., + (double) 0., (double) 3000000.); + if (m_hist_HltResultSizes_Stream_DataScouting) { + m_hist_HltResultSizes_Stream_DataScouting->GetXaxis()->SetBinLabel(1,std::string("NoTag").c_str() ); + CAN_REBIN(m_hist_HltResultSizes_Stream_DataScouting); + regHistsTProfile.push_back(&m_hist_HltResultSizes_Stream_DataScouting); + } + + // +-----------------------+ + // *-- | framework error codes | + // +-----------------------+ + uint32_t n_bins_error = hltonl::NUM_PSC_ERROR_CODES; + m_hist_frameworkErrorCodes = new TH1F ("FrameworkErrorCodes", + "FrameworkErrorCodes;;entries", n_bins_error, 0.5, n_bins_error+0.5); + + if (m_hist_frameworkErrorCodes) { + for (hltonl::MapPscErrorCode::EnumMap::const_iterator map_it = m_mapPscError.begin(); map_it != m_mapPscError.end(); map_it++) { + m_hist_frameworkErrorCodes->GetXaxis()->SetBinLabel( ((*map_it).second).second , (((*map_it).second).first).c_str() ); + } + regHistsTH1F.push_back(&m_hist_frameworkErrorCodes); + } + + // +-------------+ + // *-- | Stream Tags | + // +-------------+ + // *-- number of set stream tags + m_hist_numStreamTags = new TH1F ((m_histProp_numStreamTags.value().title()).c_str(), + (m_histProp_numStreamTags.value().title() + ";tags;entries").c_str(), + m_histProp_numStreamTags.value().bins(), + m_histProp_numStreamTags.value().lowEdge(), + m_histProp_numStreamTags.value().highEdge()); + if (m_hist_numStreamTags) { + CAN_REBIN(m_hist_numStreamTags); + regHistsTH1F.push_back(&m_hist_numStreamTags); + } + + // *-- stream tag types + uint32_t n_bins_tag = eformat::helper::TagTypeDictionary.size() + 1; + m_hist_streamTagTypes = new TH1F ("StreamTagTypes", + "StreamTagTypes;tags;entries", n_bins_tag, -0.5 , n_bins_tag-0.5); + if (m_hist_streamTagTypes) { + using eformat::helper::tagtype_to_string; + for(uint32_t i=0; i < n_bins_tag; i++ ) { // StreamTag labels + uint32_t bit = (1u << i); + m_hist_streamTagTypes->GetXaxis()->SetBinLabel( i+1, tagtype_to_string( static_cast<eformat::TagType>(bit) ).c_str() ); + } + m_hist_streamTagTypes->GetXaxis()->SetBinLabel(n_bins_tag, "NoTag(=Rejected)"); + regHistsTH1F.push_back(&m_hist_streamTagTypes); + } + + // *-- stream tag names + m_hist_streamTagNames = new TH1F ((m_histProp_streamTagNames.value().title()).c_str(), + (m_histProp_streamTagNames.value().title() + ";tags;entries").c_str(), + m_histProp_streamTagNames.value().bins(), + m_histProp_streamTagNames.value().lowEdge(), + m_histProp_streamTagNames.value().highEdge()); + if (m_hist_streamTagNames) { + if (m_histProp_streamTagNames.value().bins()>0) m_hist_streamTagNames->GetXaxis()->SetBinLabel(1,std::string("NoTag").c_str() ); + CAN_REBIN(m_hist_streamTagNames); + regHistsTH1F.push_back(&m_hist_streamTagNames); + } + + // +------------------------+ + // *-- | Partial event building | + // +------------------------+ + // *-- number of bins for sub detector plots (55 SubDet max.) + uint32_t n_bins_partEBSubDet = eformat::helper::SubDetectorDictionary.size(); + + // *-- number of ROBs for partial event building + m_hist_num_partial_eb_robs = new TH1F ((m_histProp_num_partial_eb_robs.value().title()).c_str(), + (m_histProp_num_partial_eb_robs.value().title() + ";robs;entries").c_str(), + m_histProp_num_partial_eb_robs.value().bins(), + m_histProp_num_partial_eb_robs.value().lowEdge(), + m_histProp_num_partial_eb_robs.value().highEdge()); + if (m_hist_num_partial_eb_robs) { + CAN_REBIN(m_hist_num_partial_eb_robs); + regHistsTH1F.push_back(&m_hist_num_partial_eb_robs); + } + + // *-- number of SubDetectors used in partial event building + m_hist_num_partial_eb_SubDetectors = new TH1F ("NumberSubDetectorsPartialEB", + "NumberSubDetectorsPartialEB;subdet;entries", + n_bins_partEBSubDet,-0.5,(float) n_bins_partEBSubDet-0.5); + if (m_hist_num_partial_eb_SubDetectors) { + CAN_REBIN(m_hist_num_partial_eb_SubDetectors); + regHistsTH1F.push_back(&m_hist_num_partial_eb_SubDetectors); + } + + // *-- SubDetectors used in partial event building: ROB list + m_hist_partial_eb_SubDetectors_ROBs = new TH1F ("SubDetectorsPartialEBFromROBList", + "SubDetectorsPartialEBFromROBList;;entries", + n_bins_partEBSubDet,0.,(float) n_bins_partEBSubDet); + if (m_hist_partial_eb_SubDetectors_ROBs) { + uint32_t n_tmp_bin = 1; + for (eformat::helper::EnumClass<eformat::SubDetector>::const_iterator it_sub=eformat::helper::SubDetectorDictionary.begin(); + it_sub != eformat::helper::SubDetectorDictionary.end(); it_sub++ ) { + m_hist_partial_eb_SubDetectors_ROBs->GetXaxis()->SetBinLabel( n_tmp_bin, (it_sub->second).c_str() ); + n_tmp_bin++; + } + CAN_REBIN(m_hist_partial_eb_SubDetectors_ROBs); + regHistsTH1F.push_back(&m_hist_partial_eb_SubDetectors_ROBs); + } + + // *-- SubDetectors used in partial event building: SD list + m_hist_partial_eb_SubDetectors_SDs = new TH1F ("SubDetectorsPartialEBFromSDList", + "SubDetectorsPartialEBFromSDList;;entries", + n_bins_partEBSubDet,0.,(float) n_bins_partEBSubDet); + if (m_hist_partial_eb_SubDetectors_SDs) { + uint32_t n_tmp_bin = 1; + for (eformat::helper::EnumClass<eformat::SubDetector>::const_iterator it_sub=eformat::helper::SubDetectorDictionary.begin(); + it_sub != eformat::helper::SubDetectorDictionary.end(); it_sub++ ) { + m_hist_partial_eb_SubDetectors_SDs->GetXaxis()->SetBinLabel( n_tmp_bin, (it_sub->second).c_str() ); + n_tmp_bin++; + } + CAN_REBIN(m_hist_partial_eb_SubDetectors_SDs); + regHistsTH1F.push_back(&m_hist_partial_eb_SubDetectors_SDs); + } + + // +---------------+ + // *-- | HLT EDM Sizes | + // +---------------+ + // *-- EDM sizes for all events without a truncated HLT result + m_hist_HltEdmSizes_No_Truncation = new TProfile( (m_histProp_Hlt_Edm_Sizes.value().title()+":Events_Without_Truncation").c_str(), + (m_histProp_Hlt_Edm_Sizes.value().title()+":Events_Without_Truncation;;Average size in words").c_str(), + m_histProp_Hlt_Edm_Sizes.value().bins(), + (double) 0., (double) m_histProp_Hlt_Edm_Sizes.value().bins(), + (double) m_histProp_Hlt_Edm_Sizes.value().lowEdge(), + (double) m_histProp_Hlt_Edm_Sizes.value().highEdge()); + if (m_hist_HltEdmSizes_No_Truncation) { + uint32_t n_tmp_bin = 1; + for (std::vector<std::string>::const_iterator it_col_name = m_hltEdmCollectionNames.value().begin(); + it_col_name != m_hltEdmCollectionNames.value().end(); it_col_name++ ) { + m_hist_HltEdmSizes_No_Truncation->GetXaxis()->SetBinLabel( n_tmp_bin, (*it_col_name).c_str() ); + n_tmp_bin++; + } + // m_hist_HltEdmSizes_No_Truncation->SetBit(TProfile::kCanRebin); + regHistsTProfile.push_back(&m_hist_HltEdmSizes_No_Truncation); + } + // *-- EDM sizes for all events with a truncated HLT result + m_hist_HltEdmSizes_With_Truncation = new TProfile( (m_histProp_Hlt_Edm_Sizes.value().title()+":Events_With_Truncation").c_str(), + (m_histProp_Hlt_Edm_Sizes.value().title()+":Events_With_Truncation;;Average size in words").c_str(), + m_histProp_Hlt_Edm_Sizes.value().bins(), + (double) 0., (double) m_histProp_Hlt_Edm_Sizes.value().bins(), + (double) m_histProp_Hlt_Edm_Sizes.value().lowEdge(), + (double) m_histProp_Hlt_Edm_Sizes.value().highEdge()); + if (m_hist_HltEdmSizes_With_Truncation) { + uint32_t n_tmp_bin = 1; + for (std::vector<std::string>::const_iterator it_col_name = m_hltEdmCollectionNames.value().begin(); + it_col_name != m_hltEdmCollectionNames.value().end(); it_col_name++ ) { + m_hist_HltEdmSizes_With_Truncation->GetXaxis()->SetBinLabel( n_tmp_bin, (*it_col_name).c_str() ); + n_tmp_bin++; + } + // m_hist_HltEdmSizes_With_Truncation->SetBit(TProfile::kCanRebin); + regHistsTProfile.push_back(&m_hist_HltEdmSizes_With_Truncation); + } + // *-- Sizes of collections which were retained for events with a truncated HLT result + m_hist_HltEdmSizes_TruncatedResult_Retained_Collections = new TProfile( "Events_With_HLTResult_Truncation:Size_of_Not_Truncated_Collections", + "Events_With_HLTResult_Truncation:Size_of_Not_Truncated_Collections;;Average size in words", + m_histProp_Hlt_Edm_Sizes.value().bins(), + (double) 0., (double) m_histProp_Hlt_Edm_Sizes.value().bins(), + (double) m_histProp_Hlt_Edm_Sizes.value().lowEdge(), + (double) m_histProp_Hlt_Edm_Sizes.value().highEdge()); + if (m_hist_HltEdmSizes_TruncatedResult_Retained_Collections) { + uint32_t n_tmp_bin = 1; + for (std::vector<std::string>::const_iterator it_col_name = m_hltEdmCollectionNames.value().begin(); + it_col_name != m_hltEdmCollectionNames.value().end(); it_col_name++ ) { + m_hist_HltEdmSizes_TruncatedResult_Retained_Collections->GetXaxis()->SetBinLabel( n_tmp_bin, (*it_col_name).c_str() ); + n_tmp_bin++; + } + // m_hist_HltEdmSizes_TruncatedResult_Retained_Collections->SetBit(TProfile::kCanRebin); + regHistsTProfile.push_back(&m_hist_HltEdmSizes_TruncatedResult_Retained_Collections); + } + // *-- Sizes of collections which were truncated for events with a truncated HLT result + m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections = new TProfile( "Events_With_HLTResult_Truncation:Size_of_Truncated_Collections", + "Events_With_HLTResult_Truncation:Size_of_Truncated_Collections;;Average size in words", + m_histProp_Hlt_Edm_Sizes.value().bins(), + (double) 0., (double) m_histProp_Hlt_Edm_Sizes.value().bins(), + (double) m_histProp_Hlt_Edm_Sizes.value().lowEdge(), + (double) m_histProp_Hlt_Edm_Sizes.value().highEdge()); + if (m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections) { + uint32_t n_tmp_bin = 1; + for (std::vector<std::string>::const_iterator it_col_name = m_hltEdmCollectionNames.value().begin(); + it_col_name != m_hltEdmCollectionNames.value().end(); it_col_name++ ) { + m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections->GetXaxis()->SetBinLabel( n_tmp_bin, (*it_col_name).c_str() ); + n_tmp_bin++; + } + // m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections->SetBit(TProfile::kCanRebin); + regHistsTProfile.push_back(&m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections); + } + // +---------------------+ + // *-- | register histograms | + // +---------------------+ + // *-- TH1F + for (std::vector<TH1F**>::iterator it_hist=regHistsTH1F.begin(); it_hist != regHistsTH1F.end(); ++it_hist) { + if ( (*it_hist) && m_THistSvc->regHist(histPath + (**it_hist)->GetName(), (**it_hist)).isFailure() ) { + logStream() << MSG::WARNING << "Cannot register histogram " << (**it_hist)->GetName() << endreq; + delete (**it_hist); + **it_hist = 0; + } + } + // *-- TProfile + for (std::vector<TProfile**>::iterator it_hist=regHistsTProfile.begin(); it_hist != regHistsTProfile.end(); ++it_hist) { + if ( (**it_hist) && m_THistSvc->regHist(histPath + (**it_hist)->GetName(), (**it_hist)).isFailure() ) { + logStream() << MSG::WARNING << "Cannot register histogram " << (**it_hist)->GetName() << endreq; + delete (**it_hist); + **it_hist = 0; + } + } +} + +//========================================================================= +void HltEventLoopMgr::HltBookHistograms() +{ + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << "---> HltBookHistograms() for " << name() + << " called. Do monitoring = " << m_doMonitoring.value() << endreq; + } + + // return if no monitoring is requested + if ( !m_doMonitoring.value() ) { return; } + + // monitoring information root directory + std::string path = std::string("/EXPERT/")+getGaudiThreadGenericName(name())+"/"; + + // *-- SubDetectors from l1 ROBs + auto nbins = L1R_BINS.size() + 2; + m_hist_l1_robs = new TH1F ("HLTROBsReceivedFromL1", + "HLTROBsReceivedFromL1;;entries", + nbins, + 0., + static_cast<double>(nbins)); + + // Set labels from L1R_BINS + unsigned short i = 0; + while(i < L1R_BINS.size()) + { + auto sid = eformat::helper::SourceIdentifier(L1R_BINS[i], 0); + m_hist_l1_robs->GetXaxis()->SetBinLabel(++i, sid.human_detector().c_str()); + } + + // Add a label for unexpected robs and another for missing CTP fragment + m_hist_l1_robs->GetXaxis()->SetBinLabel(++i, UNEXPECTED_L1R_ROB_LABEL); + m_hist_l1_robs->GetXaxis()->SetBinLabel(++i, MISSING_L1R_CTP_LABEL); + + // Register it + if(m_THistSvc->regHist(path + m_hist_l1_robs->GetName(), m_hist_l1_robs).isFailure()) + { + logStream() << MSG::WARNING << "Can not register monitoring histogram: " + << m_hist_l1_robs->GetName() << endreq; + } +} // end method HltEventLoopMgr::HltBookHistograms + +//========================================================================= +void HltEventLoopMgr::fillHltResultHistograms(const hltinterface::HLTResult& hlt_result) +{ + if ( logLevel() <= MSG::DEBUG ) { + logStream() << MSG::DEBUG << "---> fillHltResultHistograms(hltinterface::HLTResult& hlt_result) for " << name() << " called " << endreq; + } + + // return if no monitoring is requested + if ( !m_doMonitoring.value() ) { return; } + + // +-----------------------+ + // *-- | HLT result properties | + // +-----------------------+ + if ( (hlt_result.fragment_pointer != 0) && ( (*hlt_result.fragment_pointer) != 0 ) ) { + eformat::ROBFragment<uint32_t*> hltrob(hlt_result.fragment_pointer); + uint16_t hltrob_moduleID = eformat::helper::SourceIdentifier( hltrob.rob_source_id() ).module_id(); + + // *-- HLT result size plots + if ((m_hist_Hlt_result_size) && (hltrob_moduleID == 0)) lock_histogram_operation<TH1F>(m_hist_Hlt_result_size)->Fill( (float) hltrob.fragment_size_word() ) ; + + if ( (m_hist_Hlt_result_size_physics) || (m_hist_Hlt_result_size_express) || (m_hist_Hlt_result_size_DataScouting) || + (m_hist_HltResultSizes_Stream_physics) || (m_hist_HltResultSizes_Stream_DataScouting) ) { + scoped_lock_histogram lock; + for(std::vector<eformat::read::ROBFragment>::const_iterator it_rob = hlt_result.hltResult_robs.begin(); it_rob != hlt_result.hltResult_robs.end(); it_rob++) { + uint16_t moduleID = eformat::helper::SourceIdentifier( (*it_rob).rob_source_id() ).module_id(); + for(std::vector<eformat::helper::StreamTag>::const_iterator it = hlt_result.stream_tag.begin(); it != hlt_result.stream_tag.end(); it++) { + // only normal HLT Results + if (moduleID == 0) { + if ((*it).type == "physics") { + if (((*it).name == "Main") && (m_hist_Hlt_result_size_physics)) m_hist_Hlt_result_size_physics->Fill( (float) (*it_rob).fragment_size_word() ) ; + if (m_hist_HltResultSizes_Stream_physics) m_hist_HltResultSizes_Stream_physics->Fill( ((*it).name).c_str(), (double) (*it_rob).fragment_size_word() ) ; + } + if ((*it).type == "express") { + if (m_hist_Hlt_result_size_express) m_hist_Hlt_result_size_express->Fill( (float) (*it_rob).fragment_size_word() ) ; + } + } + // DataScouting HLT ROBs + if (moduleID != 0) { + if (((*it).type == "calibration") && (((*it).name).find("DataScouting_") != std::string::npos)) { + if (m_hist_Hlt_result_size_DataScouting) m_hist_Hlt_result_size_DataScouting->Fill( (float) (*it_rob).fragment_size_word() ) ; + if (m_hist_HltResultSizes_Stream_DataScouting) m_hist_HltResultSizes_Stream_DataScouting->Fill( ((*it).name).c_str(), (double) (*it_rob).fragment_size_word() ) ; + } + } + } + } + // deflate bins for profile histograms + m_hist_HltResultSizes_Stream_physics->LabelsDeflate("X"); + m_hist_HltResultSizes_Stream_DataScouting->LabelsDeflate("X"); + } + + // *-- HLT result status codes + if ((hltrob.nstatus() > 1) && (m_hist_Hlt_result_status) && (hltrob_moduleID == 0)) { + scoped_lock_histogram lock; + const uint32_t* it; + hltrob.status(it); + m_hist_Hlt_result_status->Fill( (float) m_mapResultStatus.codeToHash( (hltonl::ResultStatusCode) *(it+1)) ); + } + } + + // +-----------------------+ + // *-- | framework error codes | + // +-----------------------+ + if ((hlt_result.psc_errors.size() > 0) && (m_hist_frameworkErrorCodes)) { + scoped_lock_histogram lock; + for (std::vector<uint32_t>::const_iterator it=hlt_result.psc_errors.begin();it!=hlt_result.psc_errors.end();it++) { + m_hist_frameworkErrorCodes->Fill( (float) m_mapPscError.codeToHash( (hltonl::PSCErrorCode) (*it)) ); + } + } + + // +-------------+ + // *-- | Stream Tags | + // +-------------+ + // number of set stream tags + if (m_hist_numStreamTags) lock_histogram_operation<TH1F>(m_hist_numStreamTags)->Fill( (float) hlt_result.stream_tag.size() ); + + // stream tag types + if (m_hist_streamTagTypes) { + scoped_lock_histogram lock; + if(hlt_result.stream_tag.empty()) + m_hist_streamTagTypes->Fill( (float) m_hist_streamTagTypes->GetXaxis()->GetNbins() - 1. ); + using namespace eformat::helper; + for(int32_t i=0; i < m_hist_streamTagTypes->GetXaxis()->GetNbins(); i++) { + uint32_t bit = (1u<<i); + if( contains_type(hlt_result.stream_tag, static_cast<eformat::TagType>(bit)) ) { + m_hist_streamTagTypes->Fill( (float) i); + } + } + } + + // stream tag names + if (m_hist_streamTagNames) { + scoped_lock_histogram lock; + if(hlt_result.stream_tag.empty()) { + m_hist_streamTagNames->Fill(0.); + } else { + for(std::vector<eformat::helper::StreamTag>::const_iterator it = hlt_result.stream_tag.begin(); it != hlt_result.stream_tag.end(); it++) { + m_hist_streamTagNames->Fill((*it).name.c_str(),1.); + } + } + m_hist_streamTagNames->LabelsDeflate("X"); + } + + // +------------------------+ + // *-- | Partial Event Building | + // +------------------------+ + // *-- loop over stream tags and get total number of ROBs and SDs + uint32_t num_robs(0), num_sd(0); + std::set<uint32_t> peb_robs; + std::set<eformat::SubDetector> peb_sd; + for(std::vector<eformat::helper::StreamTag>::const_iterator it = hlt_result.stream_tag.begin(); it != hlt_result.stream_tag.end(); it++) { + num_robs = num_robs + (it->robs).size(); + num_sd = num_sd + (it->dets).size(); + peb_robs.insert( (it->robs).begin(),(it->robs).end() ); + peb_sd.insert( (it->dets).begin(),(it->dets).end() ); + } + + // *-- number of ROBs for partial event building + if (m_hist_num_partial_eb_robs) lock_histogram_operation<TH1F>(m_hist_num_partial_eb_robs)->Fill( (float) num_robs); + + // *-- number of SubDetectors for partial event building + if (m_hist_num_partial_eb_SubDetectors) lock_histogram_operation<TH1F>(m_hist_num_partial_eb_SubDetectors)->Fill( (float) num_sd); + + // *-- SubDetectors for partial event building in ROB list + if (m_hist_partial_eb_SubDetectors_ROBs) { + scoped_lock_histogram lock; + for(std::set<uint32_t>::const_iterator it = peb_robs.begin(); it != peb_robs.end(); it++) { + m_hist_partial_eb_SubDetectors_ROBs->Fill(eformat::helper::SourceIdentifier(*it).human_detector().c_str(),1.); + m_hist_partial_eb_SubDetectors_ROBs->LabelsDeflate("X"); + } + } + + // *-- SubDetectors for partial event building in SD list + if (m_hist_partial_eb_SubDetectors_SDs) { + scoped_lock_histogram lock; + for(std::set<eformat::SubDetector>::const_iterator it = peb_sd.begin(); it != peb_sd.end(); it++) { + m_hist_partial_eb_SubDetectors_SDs->Fill(eformat::helper::SourceIdentifier(*it,0).human_detector().c_str(),1.); + m_hist_partial_eb_SubDetectors_SDs->LabelsDeflate("X"); + } + } + + return; +} // end method HltEventLoopMgr::fillHltResultHistograms + +//========================================================================= +void HltEventLoopMgr::bookAllHistograms() +{ + // Book the monitoring histograms + HltBookHistograms(); // (histograms that were booked differently in l2/ef) + // Book own histograms + bookHistograms(); +} + +//========================================================================= +StatusCode +HltEventLoopMgr::callOnAlgs(const function<StatusCode(IAlgorithm&)> & func, + const string & fname, bool failureIsError) +{ + logStream() << MSG::DEBUG << ST_WHERE + << "calling " << fname << "() on all algorithms" << endreq; + + StatusCode sc; + for(auto alg : m_topAlgList) + { + if(func(*alg).isFailure()) + { + logStream() << (failureIsError ? MSG::ERROR : MSG::WARNING) << ST_WHERE + << "Calling " << fname << "() on algorithm " << alg->name() + << " failed" << endreq; + sc = StatusCode::FAILURE; + if(failureIsError) + break; + } + } + + return sc; +} + +//========================================================================= +StatusCode HltEventLoopMgr::prepareAlgs(const EventInfo& evinfo) +{ + auto suc1 = callOnAlgs(&IAlgorithm::sysStart, "sysStart").isSuccess(); + m_incidentSvc->fireIncident(EventIncident(evinfo, name(), + IncidentType::BeginRun)); + auto suc2 = callOnAlgs(&IAlgorithm::sysBeginRun, "sysBeginRun").isSuccess(); + m_incidentSvc->fireIncident(EventIncident(evinfo, name(), "EndOfBeginRun")); + + return (suc1 && suc2) ? StatusCode::SUCCESS : StatusCode::FAILURE; +} + +//========================================================================= +StatusCode HltEventLoopMgr::internalPrepareResets() +{ + m_currentEvent = nullptr; // no time out would make sense here, so not locking + m_currentLB = 0; + if (m_predefinedLumiBlock > 0) + { + m_currentLB = m_predefinedLumiBlock; + logStream() << MSG::DEBUG << ST_WHERE + << "Using predefined lumi block " << m_currentLB << endreq; + } + + // The real CTP counter only has 16 bits and never reaches this value + m_l1_hltPrescaleUpdateLB = 0xffffffff; + + return clearTemporaryStores(); +} + +//========================================================================= +const SOR * HltEventLoopMgr::processRunParams(const ptree & pt) +{ + // update the run number + m_currentRun = pt.get<uint32_t>("RunParams.run_number"); + + // Fill SOR parameters from the ptree + TrigSORFromPtreeHelper sorhelp{logStream()}; + auto sor = sorhelp.fillSOR(pt.get_child("RunParams")); + if(!sor) + logStream() << MSG::ERROR << ST_WHERE + << "setup of SOR from ptree failed" << endreq; + + return sor; +} + +//========================================================================= +void HltEventLoopMgr::updInternal(const coral::AttributeList & sor_attrlist) +{ + auto detMaskFst = sor_attrlist["DetectorMaskFst"].data<unsigned long long>(); + auto detMaskSnd = sor_attrlist["DetectorMaskSnd"].data<unsigned long long>(); + updDetMask({detMaskFst, detMaskSnd}); + + auto sorTime = sor_attrlist["SORTime"].data<unsigned long long>(); + updSorTime(sorTime); + + if(logLevel() <= MSG::DEBUG) + { + // save current stream flags for later reset + // cast needed (stream thing returns long, but doesn't take it back) + auto previous_stream_flags = + static_cast<std::ios::fmtflags>(logStream().flags()); + logStream() << MSG::DEBUG << ST_WHERE + << "Full detector mask (128 bits) = 0x" + << MSG::hex << std::setfill('0') + << std::setw(8) << std::get<3>(m_detector_mask) + << std::setw(8) << std::get<2>(m_detector_mask) + << std::setw(8) << std::get<1>(m_detector_mask) + << std::setw(8) << std::get<0>(m_detector_mask) << endreq; + logStream().flags(previous_stream_flags); + + logStream() << MSG::DEBUG << ST_WHERE + << "sorTimeStamp[0] [sec] = " << m_sorTime_stamp[0] << endreq; + logStream() << MSG::DEBUG << ST_WHERE + << "sorTimeStamp[1] [ns] = " << m_sorTime_stamp[1] << endreq; + } +} + +//========================================================================= +void HltEventLoopMgr::updMetadaStore(const coral::AttributeList & sor_attrlist) +{ + // least significant part is "snd" in sor but "fst" for ByteStreamMetadata + auto bs_dm_fst = sor_attrlist["DetectorMaskSnd"].data<unsigned long long>(); + // most significant part is "fst" in sor but "snd" for ByteStreamMetadata + auto bs_dm_snd = sor_attrlist["DetectorMaskFst"].data<unsigned long long>(); + + auto metadata = new ByteStreamMetadata( + sor_attrlist["RunNumber"].data<unsigned int>(), + 0, + 0, + sor_attrlist["RecordingEnabled"].data<bool>(), + 0, + bs_dm_fst, + bs_dm_snd, + 0, + 0, + "", + "", + "", + 0, + std::vector<std::string>()); + + // Record ByteStreamMetadata in MetaData Store + if(m_inputMetaDataStore->record(metadata,"ByteStreamMetadata").isFailure()) + { + logStream() << MSG::WARNING << ST_WHERE + << "Unable to record MetaData in InputMetaDataStore." + << endreq; + delete metadata; + } + else + logStream() << MSG::DEBUG << ST_WHERE + << "Recorded MetaData in InputMetaDataStore." << endreq; +} + +//========================================================================= +StatusCode HltEventLoopMgr::clearTemporaryStores() +{ + //----------------------------------------------------------------------- + // Clear the event store, if used in the event loop + //----------------------------------------------------------------------- + auto sc = m_evtStore->clearStore(); + logStream() << MSG::DEBUG << ST_WHERE + << "clear of Event Store " << sc << endreq; + if(sc.isFailure()) { + logStream() << MSG::ERROR << ST_WHERE + << "clear of Event Store failed" << endreq; + return sc; + } + + //----------------------------------------------------------------------- + // Clear the InputMetaDataStore + //----------------------------------------------------------------------- + sc = m_inputMetaDataStore->clearStore(); + logStream() << MSG::DEBUG << ST_WHERE + << "clear of InputMetaDataStore store " << sc << endreq; + if(sc.isFailure()) + logStream() << MSG::ERROR << ST_WHERE + << "clear of InputMetaDataStore failed" << endreq; + + return sc; +} + +//========================================================================= +void HltEventLoopMgr::updDetMask(const std::pair<uint64_t, uint64_t>& dm) +{ + m_detector_mask = std::make_tuple( + // least significant 4 bytes + static_cast<EventID::number_type>(dm.second), + // next least significant 4 bytes + static_cast<EventID::number_type>(dm.second >> 32), + // next least significant 4 bytes + static_cast<EventID::number_type>(dm.first), + // most significant 4 bytes + static_cast<EventID::number_type>(dm.first >> 32)); +} + +//========================================================================= +void HltEventLoopMgr::updSorTime(unsigned long long st) +{ + m_sorTime_stamp[0]=0; + m_sorTime_stamp[1]=0; + if(st) + { + m_sorTime_stamp[0] = (unsigned int)(st/1000000000); + m_sorTime_stamp[1] = (unsigned int)(st-m_sorTime_stamp[0]*1000000000); + } +} + +namespace +{ + // Helper to print SOR record + void printSORAttrList(const coral::AttributeList& atr, + MsgStream& log, const MSG::Level& lvl) + { + unsigned long long sorTime_ns(atr["SORTime"].data<unsigned long long>()); + + // Human readable format of SOR time if available + time_t sorTime_sec = sorTime_ns/1000000000; + const auto sorTime_readable = OWLTime(sorTime_sec); + + log << lvl << "SOR parameters:" << endreq; + log << " RunNumber = " + << atr["RunNumber"].data<unsigned int>() << endreq; + log << " SORTime [ns] = " + << sorTime_ns << " (" << sorTime_readable << ") " << endreq; + + // save current stream flags for later reset + // cast needed (stream thing returns long, but doesn't take it back) + auto previous_stream_flags = static_cast<std::ios::fmtflags>(log.flags()); + auto dmfst = atr["DetectorMaskFst"].data<unsigned long long>(); + auto dmsnd = atr["DetectorMaskSnd"].data<unsigned long long>(); + log << MSG::hex << std::setfill('0'); + log << " DetectorMaskFst = 0x" << std::setw(16) << dmfst << endreq; + log << " DetectorMaskSnd = 0x" << std::setw(16) << dmsnd << endreq; + log << " (complete DetectorMask = 0x" + << std::setw(16) << dmfst << std::setw(16) << dmsnd << ")" << endreq; + // reset stream flags + log.flags(previous_stream_flags); + + log << " RunType = " + << atr["RunType"].data<std::string>() << endreq; + log << " RecordingEnabled = " + << (atr["RecordingEnabled"].data<bool>() ? "true" : "false") << endreq; + } +} + +//========================================================================= +const coral::AttributeList & +HltEventLoopMgr::getSorAttrList(const SOR * sor) const +{ + if(sor->size() != 1) + { + // This branch should never be entered (the CondAttrListCollection + //corresponding to the SOR should contain one single AttrList). Since + //that's required by code ahead but not checked at compile time, we + //explicitly guard against any potential future mistake with this check + logStream() << MSG::ERROR << ST_WHERE + << "Wrong SOR: size = " << sor->size() << endreq; + throw std::runtime_error("SOR record should have one and one only attribute" + " list, but it has " + sor->size()); + } + + const auto & soral = sor->begin()->second; + printSORAttrList(soral, logStream(), MSG::INFO); + return soral; +} + +//========================================================================= +StatusCode HltEventLoopMgr::updHLTConfigSvc() +{ + // Get HLTConfigSvc if available and do sanity check + service("TrigConf::HLTConfigSvc/HLTConfigSvc", + m_hltConfigSvc, /*createIf=*/false).ignore(); + + if ( (m_hltConfigSvc==0) && (m_jobOptionsType.value()=="DB") ) { + logStream() << MSG::ERROR << ST_WHERE + << "JobOptionsType==DB but could not retrieve HLTConfigSvc" + << endreq; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +//========================================================================= +const EventInfo * HltEventLoopMgr::prepEventInfo() const +{ + const EventInfo * pEvent = + new EventInfo(new EventID(m_currentRun, + 0, + m_sorTime_stamp[0], + m_sorTime_stamp[1], + m_currentLB, + 0, + std::get<0>(m_detector_mask), + std::get<1>(m_detector_mask), + std::get<2>(m_detector_mask), + std::get<3>(m_detector_mask)), + new EventType()); + + // Record it in StoreGate + if(m_evtStore->record(pEvent,"EventInfo").isFailure()) + { + logStream() << MSG::ERROR << ST_WHERE + << "Could not record EventInfo object" << endreq; + return nullptr; + } + + logStream() << MSG::DEBUG << ST_WHERE + << "Recorded EventInfo object: " + << *pEvent->event_ID() << endreq; + + return pEvent; +} + +//========================================================================= +StatusCode HltEventLoopMgr::prepXAODEventInfo() const +{ + auto aux = new xAOD::EventAuxInfo; + auto ev = new xAOD::EventInfo; + ev->setStore(aux); + ev->setRunNumber(m_currentRun); + ev->setEventNumber(0); + ev->setLumiBlock(m_currentLB); + ev->setTimeStamp(m_sorTime_stamp[0]); + ev->setTimeStampNSOffset(m_sorTime_stamp[1]); + ev->setBCID(0); + ev->setDetectorMask0(std::get<0>(m_detector_mask)); + ev->setDetectorMask1(std::get<1>(m_detector_mask)); + ev->setDetectorMask2(std::get<2>(m_detector_mask)); + ev->setDetectorMask3(std::get<3>(m_detector_mask)); + + // Record it in StoreGate + if(m_evtStore->record(aux, "EventInfoAux.").isFailure() || + m_evtStore->record(ev, "EventInfo").isFailure()) + { + logStream() << MSG::ERROR << ST_WHERE + << "Could not record xAOD::EventInfo object" << endreq; + + return StatusCode::FAILURE; + } + + logStream() << MSG::DEBUG << ST_WHERE + << "Recorded xAOD::EventInfo object: " + << *ev << endreq; + + return StatusCode::SUCCESS; +} + +//========================================================================= +StatusCode HltEventLoopMgr::updMagField(const ptree& pt) const +{ + if(m_setMagFieldFromPtree && validPartition()) + { + try + { + auto tor_cur = pt.get<float>("Magnets.ToroidsCurrent.value"); + auto sol_cur = pt.get<float>("Magnets.SolenoidCurrent.value"); + + IProperty* magfsvc(0); + service("AtlasFieldSvc", magfsvc, /*createIf=*/false).ignore(); + if ( magfsvc==0 ) { + logStream() << MSG::ERROR << ST_WHERE + << "Cannot retrieve AtlasFieldSvc" << endreq; + return StatusCode::FAILURE; + } + + auto sc = Gaudi::Utils::setProperty(magfsvc, "UseSoleCurrent", sol_cur); + if ( sc.isFailure() ) { + logStream() << MSG::ERROR << ST_WHERE + << "Cannot set property AtlasFieldSvc.UseSoleCurrent" + << endreq; + return StatusCode::FAILURE; + } + + sc = Gaudi::Utils::setProperty(magfsvc, "UseToroCurrent", tor_cur); + if ( sc.isFailure() ) { + logStream() << MSG::ERROR << ST_WHERE + << "Cannot set property AtlasFieldSvc.UseToroCurrent" + << endreq; + return StatusCode::FAILURE; + } + + logStream() << MSG::INFO << "*****************************************" << endreq; + logStream() << MSG::INFO << " Auto-configuration of magnetic field: " << endreq; + logStream() << MSG::INFO << " solenoid current from IS = " << sol_cur << endreq; + logStream() << MSG::INFO << " torroid current from IS = " << tor_cur << endreq; + logStream() << MSG::INFO << "*****************************************" << endreq; + } + catch(ptree_bad_path& e) + { + logStream() << MSG::ERROR << ST_WHERE + << "Magnet auto-configuration failed: " << e.what() << endreq; + return StatusCode::FAILURE; + } + } + else + { + logStream() << MSG::DEBUG << ST_WHERE + << "Magnetic fields not available" << endreq; + } + + return StatusCode::SUCCESS; +} + +//========================================================================= +StatusCode HltEventLoopMgr::resetCoolValidity() +{ + if ( m_coolHelper->resetBeginRunFolders(m_currentRun).isFailure() ) { + logStream() << MSG::ERROR << ST_WHERE + << "Reset of at least one proxy failed" << endreq; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +//========================================================================= +void HltEventLoopMgr::readyMsg() const +{ + if (logLevel() <= MSG::INFO) + { + LumiBlock lb; + lb.LumiBlockNumber = 0; + if(validPartition() && + m_isHelper->findValue(TrigISHelper::LumiBlock, lb).isFailure()) + { // Lumiblock only used for information. Do not make this a failure. + logStream() << MSG::WARNING << ST_WHERE + << "Cannot read lumiblock number from IS" << endreq; + } + + const auto& ilbn = lb.LumiBlockNumber; + logStream() << MSG::INFO << ST_WHERE + << "Ready to start event processing. Run = " + << m_currentRun << " (LB = " + << (ilbn ? boost::lexical_cast<string>(ilbn) : string{"??"}) + << ")" << endreq; + } +} + +//========================================================================= +void HltEventLoopMgr:: +setStreamTags(hltinterface::HLTResult& hltr, + const std::vector<TriggerInfo::StreamTag>& stream_tags) const +{ + hltr.stream_tag.reserve(stream_tags.size()); + for(const auto& st : stream_tags) + { + // get robs, filtering disabled ones + auto robs = filterRobs(st.robs()); + // get subdetectors, filtering disabled ones + auto dets = filterDets(st.dets()); + + hltr.stream_tag.emplace_back(st.name(), st.type(), st.obeysLumiblock(), + robs, dets); + } +} + +//========================================================================= +void HltEventLoopMgr:: +mergeStreamTags(hltinterface::HLTResult& hltr, + const std::vector<xAOD::EventInfo::StreamTag>& xsts) const +{ + auto& stags = hltr.stream_tag; + for(const auto& st : xsts) + { + // get robs, filtering disabled ones + auto robs = filterRobs(st.robs()); + // get subdetectors, filtering disabled ones + auto dets = filterDets(st.dets()); + + // is there already a tag with the same type, name and obeysLumi flag? + auto it = find_if(begin(stags), end(stags), + [&st](const eformat::helper::StreamTag& current){ + return current.name == st.name() && + current.type == st.type() && + current.obeys_lumiblock == st.obeysLumiblock(); + }); + + if(it != stags.end()) // if so, unite robs and dets + { + it->robs.insert(begin(robs), end(robs)); + it->dets.insert(begin(dets), end(dets)); + } + else // otherwise, add the tag + stags.emplace_back(st.name(), st.type(), st.obeysLumiblock(), robs, dets); + } +} + +//========================================================================= +hltonl::AcceptFlag +HltEventLoopMgr::processHltDecision(hltinterface::HLTResult& hltr) const +{ + if(m_forceHltAccept) + { + // we force accept independently of what the Steering decided for the event + addDebugStreamTag(hltr, m_HltForcedStreamName.value()); + return hltonl::PSC_FORCED_ACCEPT; + } + + return hltr.stream_tag.size() ? hltonl::STEERING_ACCEPT + : hltonl::STEERING_REJECT; +} + +//========================================================================= +hltonl::PSCErrorCode +HltEventLoopMgr::serializeRobs(hltinterface::HLTResult& hltr, bool& serOk, + HLT::HLTResult* dobj, uint32_t rn, uint32_t l1id, + uint32_t bcid, uint32_t l1tt, uint32_t dett) +{ + auto fp = hltr.fragment_pointer; + auto spaceleft = hltr.max_result_size; + + // obtain the module ids that need serialization + auto modids = dobj->listOfModIDs(); // hope for copy ellision + + if(find(begin(modids), end(modids), 0) == end(modids)) + { + const auto& sts = hltr.stream_tag; + using ST = decltype(sts[0]); + auto pred = [](const ST& st){ return st.type == "debug"; }; + + if (m_forceHltAccept || + find_if(begin(sts), end(sts), pred) != end(sts)) + { + modids.push_back(0); + } + } + + // loop over module ids and build a rob for each one + for(const auto& modid : modids) + { + // Initialize a ROB + auto robp = initRob(modid, rn, l1id, bcid, l1tt, dett, m_status_words); + auto initial_robsize = robp->size_word() + INITIAL_ROB_SIZE_MARGIN; + if(!checkRobSize(initial_robsize, spaceleft, hltr.max_result_size)) + return hltonl::PSC_ERROR_ROB_BUILD_FAILED; + + // serialize data and fill rob up + uint32_t* tmp{nullptr}; + serOk &= serializeRob(tmp, *robp, *dobj, modid, + spaceleft - initial_robsize); + + // Hold this until we've copied it into the HLTResult + auto tmpstor = std::unique_ptr<uint32_t[]>{tmp}; + + // copy it in and delete temporary data, updating spaceleft + addRobToHLTResult(hltr, *robp, fp, spaceleft); + } + + return hltonl::PSC_ERROR_UNCLASSIFIED; +} + +//========================================================================= +bool HltEventLoopMgr::serializeRob(uint32_t*& tmpstor, + eformat::write::ROBFragment& rob, + HLT::HLTResult& dobj, + unsigned int modid, + int payload_max) +{ + // find the remaining space for this rob's payload + int payload = 0; + + // serialize current rob + auto ret = dobj.serialize(tmpstor, payload, payload_max, modid); + + if(payload > payload_max) + { + logStream() << MSG::ERROR << ST_WHERE + << "Serialized ROB's size (" << payload << ") is bigger " + "than max allowed size (" << payload_max << ")" + << endreq; + + payload = payload_max; + ret = false; + } + + if(!ret) // otherwise, it's already correct + { + m_status_words[0] = SW_TRUNCATION.code(); + m_status_words[1] = hltonl::NORMAL_HLT_RESULT_TRUNCATED; + rob.status(2, m_status_words); + rob.rod_status(2, m_status_words); + } + + rob.rod_data(payload, tmpstor); + + return ret; +} + +//========================================================================= +void HltEventLoopMgr::addRobToHLTResult(hltinterface::HLTResult& hltr, + eformat::write::ROBFragment& rob, + uint32_t*& next_fragment, // don't pass original fragment pointer! + uint32_t& spaceleft) +{ + // Store the HLT ROB fragment in the HLT result + // (Maximum possible space is already allocated by the HLTMPPU) + auto copied = eformat::write::copy(*rob.bind(), next_fragment, rob.size_word()); + hltr.hltResult_robs.emplace_back(next_fragment); + + next_fragment += copied; + spaceleft -= copied; + + if(copied == 0 || copied != rob.size_word()) { + logStream() << MSG::ERROR + << "Memory copy operation for HLT result ROB failed. " + "Returned number of copied words = " << copied + << ". Number of words in ROB which should be copied = " + << rob.size_word() << "." << endreq; + } +} + +//========================================================================= +void HltEventLoopMgr::recordEDMSizeInfo(size_t nav_size, + bool serializationOk) const +{ + const HLT::TrigEDMSizes* dobjNavSizes(0); + + if (m_evtStore->transientContains<HLT::TrigEDMSizes>("TrigEDMSizes")) { + if ( m_evtStore->retrieve(dobjNavSizes).isSuccess() ) { + for(const auto& navSizeInfo : dobjNavSizes->info()) + { + std::string colname(navSizeInfo.collection+"__"+navSizeInfo.label); + // Protection for invalid collection names in TProfile + // (avoid bug in TProfile memory alloc) + auto it_col_name = std::find(m_hltEdmCollectionNames.value().begin(), + m_hltEdmCollectionNames.value().end(), + colname); + if(it_col_name == m_hltEdmCollectionNames.value().end()) + { + if ( logLevel() <= MSG::DEBUG ) + logStream() << MSG::DEBUG << "EDM collection name = " << colname + << " is not in the configured list of EDM collections." + << endreq; + + colname=m_hltEdmCollectionNames.value().back(); + } + + auto * edmhist = serializationOk ? m_hist_HltEdmSizes_No_Truncation + : m_hist_HltEdmSizes_With_Truncation; + fillEdmHist(edmhist, colname, navSizeInfo); + + if(!serializationOk) + { + edmhist = navSizeInfo.isTruncated(nav_size) ? + m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections : + m_hist_HltEdmSizes_TruncatedResult_Retained_Collections; + fillEdmHist(edmhist, colname, navSizeInfo); + } + } + } + else + logStream() << MSG::WARNING << "cannot access EDM sizes information" + << endreq; + } +} + +//========================================================================= +bool HltEventLoopMgr::checkRobSize(uint32_t robsize, uint32_t spaceleft, + uint32_t maxsize) +{ + if(spaceleft <= robsize) + { + logStream() << MSG::ERROR << ST_WHERE + << "Can not create HLT result ROB with available ROB " + "buffer size ! Total available buffer size = " + << maxsize << "; buffer size left = " << spaceleft + << "; Number of header words used by empty ROB = " + << robsize << endreq; + + return false; + } + + return true; +} + +//========================================================================= +bool HltEventLoopMgr:: +checkEventIdConsistency(const hltinterface::EventId& evId) const +{ + if(evId.l1Id != m_lvl1id || evId.lbNumber != m_lumi_block) + { + logStream() << MSG::WARNING << ST_WHERE + << "EventId information does not match CTP fragment contents: " + << "EventId = {globalId: " << evId.globalId << ", l1Id: " + << evId.l1Id << ", lbNumber: " << evId.lbNumber + << "}, but the CTP fragment included l1Id = " << m_lvl1id + << " and lumiblock = " << m_lumi_block << "." << endreq; + return false; + } + + return true; +} + +//========================================================================= +void HltEventLoopMgr::failedEvent(hltinterface::HLTResult& hlt_result, + hltonl::PSCErrorCode ecode, + const std::string& emsg, + bool empty_result) +{ + m_failed_evt++; + + addDebugStreamTag(hlt_result, m_HltDebugStreamName.value()); + if(empty_result) + { + HltEmptyResultROB(hlt_result, ecode); + fillHltResultHistograms(hlt_result); + } + + logStream() << MSG::ERROR << ST_WHERE + << emsg << " PSC error code = " + << hltonl::PrintPscErrorCode(ecode) + << "\n" << hlt_result << "\n" << endreq; +} + +//========================================================================= +std::vector<uint32_t> HltEventLoopMgr:: +missingL1Robs(const std::vector<eformat::ROBFragment<const uint32_t*>>& l1r) +const +{ + using eformat::helper::SourceIdentifier; + using ROB = eformat::ROBFragment<const uint32_t*>; + + std::vector<uint32_t> ret{}; + for(const auto& robid : m_mandatoryL1ROBs.value()) + { + if(isSubDetectorIn(SourceIdentifier(robid).subdetector_id())) + { + auto it = std::find_if(begin(l1r), end(l1r), [robid](const ROB& rob){ + return rob.rob_source_id() == robid; + }); + if(it == end(l1r)) + ret.push_back(robid); + } + } + + return ret; +} + +//========================================================================= +bool HltEventLoopMgr::isSubDetectorIn(eformat::SubDetector sd) const +{ + uint64_t most = std::get<3>(m_detector_mask); + most <<= 32; + most |= std::get<2>(m_detector_mask); + + uint64_t least = std::get<1>(m_detector_mask); + least <<= 32; + least |= std::get<0>(m_detector_mask); + + return eformat::helper::DetectorMask{least, most}.is_set(sd); +} diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx new file mode 100644 index 00000000000..1ce8e9342bd --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx @@ -0,0 +1,1279 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Include files. +#include "TrigServices/HltROBDataProviderSvc.h" +#include "TrigMonitorBase/TrigLockedHist.h" +#include "StoreGate/StoreGateSvc.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/ThreadGaudi.h" +#include "GaudiKernel/ITHistSvc.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "GaudiKernel/Property.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/IAlgContextSvc.h" +#include "GaudiKernel/IAlgorithm.h" +#include "hltinterface/DataCollector.h" +#include "eformat/Version.h" + +#include <iostream> +#include <sstream> +#include <iomanip> +#include <cassert> +#include <bitset> +#include <TH1F.h> +#include <TH2F.h> + +#if ROOT_VERSION_CODE >= ROOT_VERSION(6,0,0) +# define CAN_REBIN(hist) hist->SetCanExtend(TH1::kAllAxes) +#else +# define CAN_REBIN(hist) hist->SetBit(TH1::kCanRebin) +#endif + +namespace HltROBDataProviderConstants { + // reserve a number of ROB monitor collections + static const int Number_of_Rob_Monitor_Structs = 10; + // number of ROBs in an event, used to reserve space in an array + static const int Max_Number_Of_ROBs = 1800; +} + +// Constructor. +HltROBDataProviderSvc::HltROBDataProviderSvc(const std::string& name, ISvcLocator* svcloc) +:ROBDataProviderSvc(name,svcloc), + m_storeGateSvc( "StoreGateSvc", name ), + m_algContextSvc(0), + m_onlineRunning(false), + m_removeEmptyROB(false), + m_isEventComplete(false), + m_callerName("UNKNOWN"), + m_msg(0), + m_histProp_requestedROBsPerCall(Gaudi::Histo1DDef("RequestedROBsPerCall" ,0,300,50)), + m_histProp_receivedROBsPerCall(Gaudi::Histo1DDef("ReceivedROBsPerCall" ,0,300,50)), + m_histProp_timeROBretrieval(Gaudi::Histo1DDef("TimeForROBretrieval" ,0.,500.,50)), + m_hist_requestedROBsPerCall(0), + m_hist_receivedROBsPerCall(0), + m_hist_timeROBretrieval(0), + m_hist_genericStatusForROB(0), + m_hist_specificStatusForROB(0) +{ + declareProperty("ignoreROB", m_ignoreROB,"List of ROBs to ignore for retrieval"); + declareProperty("enabledROBs", m_enabledROBs,"List of enabled detector ROBs"); + declareProperty("LArMetROBs", m_enabledLArMetROBs,"List of enabled LAr MET ROBs"); + declareProperty("TileMetROBs", m_enabledTileMetROBs,"List of enabled Tile MET ROBs"); + declareProperty("readROBfromOKS", m_readROBfromOKS=true,"Read enabled ROBs from OKS"); + declareProperty("doMonitoring", m_doMonitoring=false,"Enable histograms"); + declareProperty("doDetailedROBMonitoring", m_doDetailedROBMonitoring=false,"Produce ROB cost data"); + declareProperty("ROBDataMonitorCollectionSGName", m_ROBDataMonitorCollection_SG_Name="ROBDataMonitorCollection","Name of cost monitoring collection in SG"); + declareProperty("HistRequestedROBsPerCall", m_histProp_requestedROBsPerCall,"Number of ROBs requested"); + declareProperty("HistReceivedROBsPerCall", m_histProp_receivedROBsPerCall,"Number of ROBs received"); + declareProperty("HistTimeROBretrieval", m_histProp_timeROBretrieval,"Timing for ROB retrieval"); + declareProperty("ModuleIDGenericLArMetROB", m_genericLArMetModuleID=0xffff,"Generic module id for LAr MET ROB retrieval"); + declareProperty("ModuleIDGenericTileMetROB", m_genericTileMetModuleID=0xffff,"Generic module id for Tile MET ROB retrieval"); + declareProperty("SeparateMETandDetROBRetrieval", m_separateMETandDetROBRetrieval=true,"Separate retrieval of MET and detector ROBs"); + + // fill map with generic status codes + m_map_GenericStatus[eformat::UNCLASSIFIED] = "UNCLASSIFIED"; + m_map_GenericStatus[eformat::BCID_CHECK_FAIL] = "BCID_CHECK_FAIL"; + m_map_GenericStatus[eformat::LVL1ID_CHECK_FAIL] = "LVL1ID_CHECK_FAIL"; + m_map_GenericStatus[eformat::TIMEOUT] = "TIMEOUT"; + m_map_GenericStatus[eformat::DATA_CORRUPTION] = "DATA_CORRUPTION"; + m_map_GenericStatus[eformat::INTERNAL_OVERFLOW] = "INTERNAL_OVERFLOW"; + m_map_GenericStatus[eformat::DUMMY_FRAGMENT] = "DUMMY_FRAGMENT"; + + // fill vector with specific status codes + m_vec_SpecificStatus.reserve(16); + m_vec_SpecificStatus.push_back("TRIGGER_TYPE_SYNC_ERROR/DATAFLOW_DUMMY"); + m_vec_SpecificStatus.push_back("FRAGMENT_SIZE_ERROR"); + m_vec_SpecificStatus.push_back("DATABLOCK_ERROR"); + m_vec_SpecificStatus.push_back("CTRL_WORD_ERROR"); + m_vec_SpecificStatus.push_back("MISSING_BOF"); + m_vec_SpecificStatus.push_back("MISSING_EOF"); + m_vec_SpecificStatus.push_back("INVALID_HEADER_MARKER"); + m_vec_SpecificStatus.push_back("FORMAT_ERROR"); + m_vec_SpecificStatus.push_back("DUPLICATE_EVENT"); + m_vec_SpecificStatus.push_back("SEQUENCE_ERROR"); + m_vec_SpecificStatus.push_back("TRANSMISSION_ERROR"); + m_vec_SpecificStatus.push_back("TRUNCATION"); + m_vec_SpecificStatus.push_back("SHORT_FRAGMENT"); + m_vec_SpecificStatus.push_back("FRAGMENT_LOST"); + m_vec_SpecificStatus.push_back("FRAGMENT_PENDING"); + m_vec_SpecificStatus.push_back("ROBIN_DISCARD_MODE"); +} + +// Destructor. +HltROBDataProviderSvc::~HltROBDataProviderSvc() +{ +} + +// Initialization +StatusCode HltROBDataProviderSvc::initialize() +{ + StatusCode sc = ROBDataProviderSvc::initialize(); + + // set message stream + m_msg = new MsgStream( msgSvc(), name() ); + + MsgStream log(msgSvc(), name()); + log << MSG::INFO << " ---> HltROBDataProviderSvc = " << name() << " initialize " + << " - package version " << PACKAGE_VERSION << endreq ; + + // get Property filterEmptyROB from base class + if ( !sc.isSuccess() ) { + log << MSG::ERROR << " ROBDataProviderSvc::initialize() failed." << endreq; + return sc; + } else { + BooleanProperty filterEmptyROB; + filterEmptyROB.setName("filterEmptyROB"); + if (filterEmptyROB.assign(getProperty("filterEmptyROB"))) { + m_removeEmptyROB = filterEmptyROB.value() ; + log << MSG::INFO << " ---> getProperty('filterEmptyROB') = " << filterEmptyROB << endreq; + } else { + log << MSG::WARNING << " ROBDataProviderSvc::getProperty('filterEmptyROB') failed." << endreq; + } + } + + // get the list of enabled ROBs from OKS + bool robOKSconfigFound = false; + bool robLArMetOKSconfigFound = false; + bool robTileMetOKSconfigFound = false; + + if ( m_readROBfromOKS.value() ) { + ServiceHandle<IJobOptionsSvc> p_jobOptionsSvc("JobOptionsSvc", name()); + if ((p_jobOptionsSvc.retrieve()).isFailure()) { + log << MSG::ERROR << "Could not find JobOptionsSvc" << endreq; + } else { + const std::vector<const Property*>* dataFlowProps = p_jobOptionsSvc->getProperties("DataFlowConfig"); + if(!dataFlowProps) + log << MSG::ERROR << "Could not find DataFlowConfig properties" << endreq; + else + { + for ( std::vector<const Property*>::const_iterator cur = dataFlowProps->begin(); + cur != dataFlowProps->end(); cur++) { + // the enabled ROB list is found + if ( (*cur)->name() == "DF_Enabled_ROB_IDs" ) { + if (m_enabledROBs.assign(**cur)) { + robOKSconfigFound = true; + log << MSG::INFO << " ---> Read from OKS = " << m_enabledROBs.value().size() << " enabled ROB IDs." << endreq; + } else { + log << MSG::WARNING << " Could not set Property 'enabledROBs' from OKS." << endreq; + } + } + + // the LAr MET ROB list is found + if ( (*cur)->name() == "DF_LAr_MET_ROB_IDs" ) { + if (m_enabledLArMetROBs.assign(**cur)) { + robLArMetOKSconfigFound = true; + log << MSG::INFO << " ---> Read from OKS = " << m_enabledLArMetROBs.value().size() << " LAr MET ROB IDs." << endreq; + } else { + log << MSG::WARNING << " Could not set Property 'LArMetROBs' from OKS." << endreq; + } + } + + // the Tile MET ROB list is found + if ( (*cur)->name() == "DF_Tile_MET_ROB_IDs" ) { + if (m_enabledTileMetROBs.assign(**cur)) { + robTileMetOKSconfigFound = true; + log << MSG::INFO << " ---> Read from OKS = " << m_enabledTileMetROBs.value().size() << " Tile MET ROB IDs." << endreq; + } else { + log << MSG::WARNING << " Could not set Property 'TileMetROBs' from OKS." << endreq; + } + } + } + } + p_jobOptionsSvc.release().ignore(); + } + } + + log << MSG::INFO << " ---> HltROBDataProviderSvc = " << name() << " special properties <---" << endreq; + log << MSG::INFO << " ---> Filter out empty ROB fragments = " << m_removeEmptyROB << endreq; + log << MSG::INFO << " ---> Fill monitoring histograms = " << m_doMonitoring << endreq; + log << MSG::INFO << " Hist:RequestedROBsPerCall = " << m_histProp_requestedROBsPerCall << endreq; + log << MSG::INFO << " Hist:ReceivedROBsPerCall = " << m_histProp_receivedROBsPerCall << endreq; + log << MSG::INFO << " Hist:TimeROBretrieval = " << m_histProp_timeROBretrieval << endreq; + log << MSG::INFO << " ---> Do detailed ROB monitoring = " << m_doDetailedROBMonitoring << endreq; + log << MSG::INFO << " ---> SG name for ROB monitoring collect. = " << m_ROBDataMonitorCollection_SG_Name << endreq; + log << MSG::INFO << " ---> Read list of enabled ROBs from OKS = " << m_readROBfromOKS << endreq; + if (m_enabledROBs.value().size() == 0) { + log << MSG::INFO << " ---> The list of enabled ROBs has size = 0. No check will be performed " << endreq; + } else { + if (m_readROBfromOKS.value() && robOKSconfigFound) { + log << MSG::INFO << " ---> The list of enabled ROBs has size = " << m_enabledROBs.value().size() + << ". It was read from the partition database." << endreq; + } else { + log << MSG::INFO << " ---> The list of enabled ROBs has size = " << m_enabledROBs.value().size() + << ". It was read from job options." << endreq; + } + } + + log << MSG::INFO << " ---> Generic Module ID for LAr MET ROB = " << m_genericLArMetModuleID << endreq; + if (m_enabledLArMetROBs.value().size() == 0) { + log << MSG::INFO << " ---> The list of LAr MET ROBs has size = 0. No LAr MET ROB access will be done." << endreq; + } else { + if (m_readROBfromOKS.value() && robLArMetOKSconfigFound) { + log << MSG::INFO << " ---> The list of LAr MET ROBs has size = " << m_enabledLArMetROBs.value().size() + << ". It was read from the partition database." << endreq; + } else { + log << MSG::INFO << " ---> The list of LAr MET ROBs has size = " << m_enabledLArMetROBs.value().size() + << ". It was read from job options." << endreq; + } + } + + log << MSG::INFO << " ---> Generic Module ID for Tile MET ROB = " << m_genericTileMetModuleID << endreq; + if (m_enabledTileMetROBs.value().size() == 0) { + log << MSG::INFO << " ---> The list of Tile MET ROBs has size = 0. No Tile MET ROB access will be done." << endreq; + } else { + if (m_readROBfromOKS.value() && robTileMetOKSconfigFound) { + log << MSG::INFO << " ---> The list of Tile MET ROBs has size = " << m_enabledTileMetROBs.value().size() + << ". It was read from the partition database." << endreq; + } else { + log << MSG::INFO << " ---> The list of Tile MET ROBs has size = " << m_enabledTileMetROBs.value().size() + << ". It was read from job options." << endreq; + } + } + + log << MSG::INFO << " ---> Separate MET and Det ROB Retrieval = " << m_separateMETandDetROBRetrieval << endreq; + + if (m_ignoreROB.value().size() == 0) { + log << MSG::INFO << " ---> The list of ROBs to ignore has size = 0. No check will be performed " << endreq; + } else { + log << MSG::INFO << " ---> The list of ROBs to ignore has size = " << m_ignoreROB.value().size() << endreq; + } + + for (unsigned int i=0; i<m_ignoreROB.value().size(); i++) { + log << MSG::INFO << " ---> do not retrieve ROB[" << i << "]: hex(id)=0x" + << MSG::hex << m_ignoreROB.value()[i]<<MSG::dec + << " dec(id)="<< m_ignoreROB.value()[i] << endreq; + } + + // register incident handler for begin run + ServiceHandle<IIncidentSvc> incidentSvc("IncidentSvc", name()); + if ((incidentSvc.retrieve()).isFailure()) { + log << MSG::ERROR << "Unable to locate IncidentSvc" << endreq; + incidentSvc.release().ignore(); + return StatusCode::FAILURE; + } + long int pri=100; + incidentSvc->addListener(this,"BeginRun",pri); + incidentSvc.release().ignore(); + + // Setup the StoreGateSvc + if( (m_storeGateSvc.retrieve()).isFailure() ) { + log << MSG::ERROR << "Error retrieving StoreGateSvc " << m_storeGateSvc << endreq; + m_storeGateSvc.release().ignore(); + return StatusCode::FAILURE; + } + + return sc; +} + +// Initialization +StatusCode HltROBDataProviderSvc::finalize() +{ + StatusCode sc = ROBDataProviderSvc::finalize(); + MsgStream log(msgSvc(), name()); + log << MSG::DEBUG << "finalize()" << endreq; + if ( !sc.isSuccess() ) { + log << MSG::ERROR << " ROBDataProviderSvc::finalize() failed." << endreq; + } + + // delete message stream + if ( m_msg ) delete m_msg; + + // release the AlgContextSvc if used + if ( m_algContextSvc ) m_algContextSvc->release(); + + return sc; +} + +/// Query interface +StatusCode HltROBDataProviderSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) +{ + if ( IROBDataProviderSvc::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IROBDataProviderSvc*)this; + } else if ( ITrigROBDataProviderSvc::interfaceID().versionMatch(riid) ) { + *ppvInterface = (ITrigROBDataProviderSvc*)this; + } else if ( IIncidentListener::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IIncidentListener*)this; + } else { + return Service::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} + +/** - in online add ROB fragments for given ROB ids to the map + call the DataCollector to retrieve the ROB fragments + + - in offline only check that given ROB ids are in the map, issue an + error if not + */ +void HltROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, const std::string callerName) +{ + //------------------- + // remove empty calls + //------------------- + if (robIds.size() == 0) return; + + //-------------------- + // set the caller name + //-------------------- + if (callerName != "UNKNOWN") m_callerName = callerName; + + //-------------------- + // make unique ROB IDs + //-------------------- + std::vector<uint32_t>::iterator remove_duplicate; + std::vector<uint32_t> robIdsUnique(robIds); + + sort(robIdsUnique.begin(), robIdsUnique.end()); + remove_duplicate = unique(robIdsUnique.begin(), robIdsUnique.end()); + robIdsUnique.erase(remove_duplicate, robIdsUnique.end()); + + //------------------------------------------------------------------ + // Replace the generic MET ROB ID with the full list of all MET ROBs + //------------------------------------------------------------------ + // LAr MET ROBs + uint32_t generic_LAr_MET_id = eformat::helper::SourceIdentifier(eformat::TDAQ_LAR_MET,m_genericLArMetModuleID.value()).code(); + std::vector<uint32_t>::iterator rob_LAr_Met_it = std::find(robIdsUnique.begin(), robIdsUnique.end(), generic_LAr_MET_id); + if (rob_LAr_Met_it != robIdsUnique.end()) { + robIdsUnique.erase(rob_LAr_Met_it); + if (m_enabledLArMetROBs.value().size() != 0) robIdsUnique.insert(robIdsUnique.end(),m_enabledLArMetROBs.value().begin(),m_enabledLArMetROBs.value().end()); + } + + // Tile MET ROBs + uint32_t generic_Tile_MET_id = eformat::helper::SourceIdentifier(eformat::TDAQ_TILE_MET,m_genericTileMetModuleID.value()).code(); + std::vector<uint32_t>::iterator rob_Tile_Met_it = std::find(robIdsUnique.begin(), robIdsUnique.end(), generic_Tile_MET_id); + if (rob_Tile_Met_it != robIdsUnique.end()) { + robIdsUnique.erase(rob_Tile_Met_it); + if (m_enabledTileMetROBs.value().size() != 0) robIdsUnique.insert(robIdsUnique.end(),m_enabledTileMetROBs.value().begin(),m_enabledTileMetROBs.value().end()); + } + + //------------------- + //--- offline running + //------------------- + if (!m_onlineRunning) { + + // for offline running all requested ROBs should be found in cache + // if not issue error + ROBDataProviderSvc::addROBData(robIdsUnique); + //------------------ + //--- online running + //------------------ + } else { + // detailed ROB monitoring + //------------------------ + // Create a ROB monitoring collection and register it to StoreGate + ROBDataMonitorCollection* p_robMonCollection(0); + if ( m_doDetailedROBMonitoring.value() ) { + if ( !(m_storeGateSvc->transientContains<ROBDataMonitorCollection>(m_ROBDataMonitorCollection_SG_Name.value())) ) { + p_robMonCollection = new ROBDataMonitorCollection; + if ( p_robMonCollection ) { + p_robMonCollection->reserve( HltROBDataProviderConstants::Number_of_Rob_Monitor_Structs ) ; + if ( (m_storeGateSvc->record(p_robMonCollection, m_ROBDataMonitorCollection_SG_Name.value(), true)).isFailure() ) { + logStream() << MSG::WARNING << " Registering ROB Monitoring collection in StoreGate failed." << endreq; + delete p_robMonCollection; + p_robMonCollection = 0; + } + } + } else { + if ( m_storeGateSvc->retrieve(p_robMonCollection).isFailure() ) { + logStream() << MSG::WARNING << " Retrieval of ROB Monitoring collection from StoreGate failed." << endreq; + p_robMonCollection = 0; + } + } + } + + // create a new ROBDataMonitorStruct and fill it + robmonitor::ROBDataMonitorStruct* p_robMonStruct(0); + if ( p_robMonCollection ) { + // caller name + std::string caller_name("UNKNOWN"); + if (callerName != "UNKNOWN") { + caller_name = callerName; + } else if ((callerName == "UNKNOWN") && (m_callerName != "UNKNOWN")) { + caller_name = m_callerName; + } else { + IAlgorithm* alg(0); + if ( m_algContextSvc ) { + alg = m_algContextSvc->currentAlg(); + caller_name = (alg ? alg->name() : "<NONE>"); + } + } + + // initialize new ROBDataMonitorStruct + p_robMonStruct = new robmonitor::ROBDataMonitorStruct(m_currentLvl1ID, robIdsUnique, caller_name); + } + + // for online running the requested ROBs should be not found in cache + // ------------------------------------------------------------------ + // vector with missing ROB ids for DataCollector + std::vector<uint32_t> vRobIds; + vRobIds.reserve( robIdsUnique.size() ) ; + + // find missing ROB ids which should be retrieved + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << " ---> addROBData: Number of ROB Ids requested : " << robIdsUnique.size() << endreq; + + for(std::vector<uint32_t>::const_iterator it=robIdsUnique.begin(); it!=robIdsUnique.end(); ++it){ + uint32_t id = (*it); + + // check if ROB is already in cache + ONLINE_ROBMAP::iterator map_it = m_online_robmap.find(id) ; + if(map_it != m_online_robmap.end()) { + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << " ---> addROBData: Found ROB Id : 0x" << MSG::hex << (*map_it).second.source_id() << MSG::dec + <<" in cache "<< endreq; + //* detailed monitoring + if ( p_robMonStruct ) { + (p_robMonStruct->requested_ROBs)[id].rob_history = robmonitor::CACHED; + (p_robMonStruct->requested_ROBs)[id].rob_size = ((*map_it).second).fragment_size_word(); + if ( (*map_it).second.nstatus() != 0 ) { + const uint32_t* it_status; + (*map_it).second.status(it_status); + for (uint32_t k=0; k < (*map_it).second.nstatus(); k++) { + (p_robMonStruct->requested_ROBs)[id].rob_status_words.push_back( *(it_status+k) ); + } + } + } + continue; + } + + // check if ROB should be ignored + if (m_ignoreROB.value().size() != 0) { + std::vector<uint32_t>::const_iterator rob_ignore_it = + std::find(m_ignoreROB.value().begin(), m_ignoreROB.value().end(),id); + if(rob_ignore_it != m_ignoreROB.value().end()) { + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << " ---> addROBData: ROB Id : 0x" << MSG::hex << id << MSG::dec + << " will be not retrieved, since it is on the veto list."<< endreq; + //* detailed monitoring + if ( p_robMonStruct ) { + (p_robMonStruct->requested_ROBs)[id].rob_history = robmonitor::IGNORED; + } + continue; + } + } + + // check if ROB is actually enabled for readout + // do not perform this check for MET ROBs + if ( (m_enabledROBs.value().size() != 0) && + (eformat::helper::SourceIdentifier(id).subdetector_id() != eformat::TDAQ_LAR_MET) && + (eformat::helper::SourceIdentifier(id).subdetector_id() != eformat::TDAQ_TILE_MET) ){ + std::vector<uint32_t>::const_iterator rob_enabled_it = + std::find(m_enabledROBs.value().begin(), m_enabledROBs.value().end(),id); + if(rob_enabled_it == m_enabledROBs.value().end()) { + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << " ---> addROBData: ROB Id : 0x" << MSG::hex << id << MSG::dec + << " will be not retrieved, since it is not on the list of enabled ROBs."<< endreq; + //* detailed monitoring + if ( p_robMonStruct ) { + (p_robMonStruct->requested_ROBs)[id].rob_history = robmonitor::DISABLED; + } + continue; + } + } + + // the ROB should be retrieved from the ROS + if (logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << " ---> addROBData: Request ROB Id : 0x" << MSG::hex << id << MSG::dec + <<" from ROS "<< endreq; + vRobIds.push_back( *it ) ; + } // end loop over requested input ROBs + + if (vRobIds.size() == 0) { + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG + << " ---> addROBData: either all requested ROBs are found in cache for running mode ONLINE, \n" + << " or input ROB Id list was empty, \n" + << " or all requested ROBs were not retrieved due to the veto list.\n" + << " Number of requested ROB Ids = " << robIdsUnique.size() << "\n" + << " Lvl1 id = " << m_currentLvl1ID + << endreq; + // Set ROB request time also in the case when no DataCollector request is necessary + // to allow correlation with RoI request times + // start and stop times will be equal + if ( p_robMonStruct ) { + struct timeval time_start; + struct timeval time_stop; + + gettimeofday(&time_start, 0); + gettimeofday(&time_stop, 0); + + p_robMonStruct->start_time_of_ROB_request = time_start; + p_robMonStruct->end_time_of_ROB_request = time_stop; + } + } else { + // + // Tell the DCM that these ROBs may be needed + // --------------------------------------------------------------- + // + if(logLevel() <= MSG::DEBUG) { + std::ostringstream ost; + ost << " Number of scheduled ROB Ids = " << vRobIds.size() << "\n" ; + unsigned int rob_counter = 1; + for (std::vector<uint32_t>::const_iterator rob_it=vRobIds.begin(); rob_it!=vRobIds.end(); ++rob_it,++rob_counter) + ost << " # = "<< std::setw(5) << rob_counter << " ROB id = 0x" << std::hex << (*rob_it) << std::dec << "\n"; + + logStream() << MSG::DEBUG + << " ---> addROBData: The following ROB Ids are scheduled for retrieval and are reserved in the DCM: \n" + << " Lvl1 id = " << m_currentLvl1ID << "\n" + << ost.str() + << endreq; + } + // reserve the ROBs in the DCM + hltinterface::DataCollector::instance()->reserveROBData(m_currentLvl1ID, vRobIds); + } + + // add the ROB monitoring structure to the collection + if ( p_robMonCollection && p_robMonStruct ) p_robMonCollection->push_back( p_robMonStruct ); + } // end online running + return; +} + +/** - in online add the LVL1/HLT result + - rebuild the map + - set flag for online running + */ +void HltROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result) +{ + // clear the ROB map + m_online_robmap.clear(); + m_currentLvl1ID = 0; + + // set the online flag + m_onlineRunning = true ; + + // set the complete event flag + m_isEventComplete = false; + + if ( result.size() == 0 ) { + logStream()<<MSG::ERROR<< " ---> setNextEvent online for "<< name() + <<" failed: Size of received vector of ROB fragments = " << result.size() + <<endreq; + return; + } + + // set the LVL1 id + m_currentLvl1ID = result[0].rod_lvl1_id(); + + // add fragments to map + std::vector<ROBF>::const_iterator it_robf = result.begin(); + std::vector<ROBF>::const_iterator it_robf_end = result.end(); + for(; it_robf!=it_robf_end; ++it_robf) { + uint32_t id = it_robf->source_id() ; + // check current L1 ID against CTP fragment when possible + if ( (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_CTP) && + (it_robf->rod_lvl1_id() != m_currentLvl1ID) ) { + logStream() << MSG::ERROR << " ---> Lvl1 ID mismatch for CTP fragment with SourceId = 0x" << MSG::hex << id << MSG::dec + << " and L1 Id = " << it_robf->rod_lvl1_id() + << " to currently used L1 Id = " << m_currentLvl1ID + << " -> Use CTP version from now on."<< endreq; + m_currentLvl1ID = it_robf->rod_lvl1_id() ; + } + // remove empty ROB fragments or ones with bad status, if requested + if ((it_robf->rod_ndata() == 0) && (m_removeEmptyROB)) { + if(logLevel() <= MSG::DEBUG) { + logStream() << MSG::DEBUG << " ---> Empty ROB Id = 0x" << MSG::hex << id << MSG::dec + << " removed for L1 Id = " << m_currentLvl1ID << endreq; + } + } else if ( ROBDataProviderSvc::filterRobWithStatus(&*it_robf) ) { + if ((logLevel() <= MSG::DEBUG) && (it_robf->nstatus() > 0)) { + const uint32_t* it_status; + it_robf->status(it_status); + eformat::helper::Status tmpstatus( (*it_status) ) ; + logStream() << MSG::DEBUG << " ---> ROB Id = 0x" << MSG::hex << id + << std::setfill( '0' ) + << " with Generic Status Code = 0x" << std::setw(4) << tmpstatus.generic() + << " and Specific Status Code = 0x" << std::setw(4) << tmpstatus.specific() + << MSG::dec + << " removed for L1 Id = " << m_currentLvl1ID << endreq; + } + } else { + m_online_robmap[id]= (*it_robf) ; + } + + //* fill monitoring histogram for ROB generic status + if ( ( m_hist_genericStatusForROB ) && ( it_robf->nstatus() != 0 ) ) { + const uint32_t* it_status; + it_robf->status(it_status); + if ((*it_status) != 0) { + scoped_lock_histogram lock; + m_hist_genericStatusForROB->Fill(eformat::helper::SourceIdentifier(it_robf->source_id()).human_detector().c_str(), + m_map_GenericStatus[eformat::helper::Status(*it_status).generic()].c_str(),1.); + } + } + + //* fill monitoring histogram for ROB specific status + if ( ( m_hist_specificStatusForROB ) && ( it_robf->nstatus() != 0 ) ) { + const uint32_t* it_status; + it_robf->status(it_status); + if ((*it_status) != 0) { + scoped_lock_histogram lock; + std::bitset<16> specificBits(eformat::helper::Status(*it_status).specific()); + for (unsigned int index=0; index < 16; ++index) { + if (specificBits[index]) m_hist_specificStatusForROB->Fill(eformat::helper::SourceIdentifier(it_robf->source_id()).human_detector().c_str(), + m_vec_SpecificStatus[index].c_str(),1.); + } + } + } + } + + if(logLevel() <= MSG::DEBUG) { + logStream()<<MSG::DEBUG<< " ---> setNextEvent online for "<< name()<<endreq; + logStream()<<MSG::DEBUG<< " online running = " << m_onlineRunning <<endreq; + logStream()<<MSG::DEBUG<< " current LVL1 id = " << m_currentLvl1ID <<endreq; + logStream()<<MSG::DEBUG<< " # LVL1 ROBs = " << result.size() <<endreq; + logStream()<<MSG::DEBUG<< " size of ROB cache = " << m_online_robmap.size() <<endreq; + logStream()<<MSG::DEBUG<< dumpROBcache() <<endreq; + } + return; +} + +/** - add a new Raw event + - rebuild the map + - set flag for offline running + */ +void HltROBDataProviderSvc::setNextEvent(const RawEvent* re) +{ + // set the offline flag + m_onlineRunning = false ; + + // set the event complete flag + m_isEventComplete = true ; + + ROBDataProviderSvc::setNextEvent(re); + return ; +} + +/** return ROBData for ROBID + */ +void HltROBDataProviderSvc::getROBData(const std::vector<uint32_t>& robIds, std::vector<const ROBF*>& robFragments, std::string callerName) +{ + //-------------------- + // set the caller name + //-------------------- + if (callerName != "UNKNOWN") m_callerName = callerName; + + //------------------- + //--- offline running + //------------------- + if (!m_onlineRunning) { + ROBDataProviderSvc::getROBData(robIds,robFragments); + //------------------ + //--- online running + //------------------ + } else { + //-------------------- + // make unique ROB IDs + //-------------------- + std::vector<uint32_t>::iterator remove_duplicate; + std::vector<uint32_t> robIdsUnique(robIds); + + sort(robIdsUnique.begin(), robIdsUnique.end()); + remove_duplicate = unique(robIdsUnique.begin(), robIdsUnique.end()); + robIdsUnique.erase(remove_duplicate, robIdsUnique.end()); + + //------------------------------------------------------------------ + // Replace the generic MET ROB ID with the full list of all MET ROBs + //------------------------------------------------------------------ + // LAr MET ROBs + uint32_t generic_LAr_MET_id = eformat::helper::SourceIdentifier(eformat::TDAQ_LAR_MET,m_genericLArMetModuleID.value()).code(); + std::vector<uint32_t>::iterator rob_LAr_Met_it = std::find(robIdsUnique.begin(), robIdsUnique.end(), generic_LAr_MET_id); + if (rob_LAr_Met_it != robIdsUnique.end()) { + robIdsUnique.erase(rob_LAr_Met_it); + if (m_enabledLArMetROBs.value().size() != 0) robIdsUnique.insert(robIdsUnique.end(),m_enabledLArMetROBs.value().begin(),m_enabledLArMetROBs.value().end()); + } + + // Tile MET ROBs + uint32_t generic_Tile_MET_id = eformat::helper::SourceIdentifier(eformat::TDAQ_TILE_MET,m_genericTileMetModuleID.value()).code(); + std::vector<uint32_t>::iterator rob_Tile_Met_it = std::find(robIdsUnique.begin(), robIdsUnique.end(), generic_Tile_MET_id); + if (rob_Tile_Met_it != robIdsUnique.end()) { + robIdsUnique.erase(rob_Tile_Met_it); + if (m_enabledTileMetROBs.value().size() != 0) robIdsUnique.insert(robIdsUnique.end(),m_enabledTileMetROBs.value().begin(),m_enabledTileMetROBs.value().end()); + } + + // detailed ROB monitoring + //------------------------ + // Create a ROB monitoring collection and register it to StoreGate + ROBDataMonitorCollection* p_robMonCollection(0); + if ((m_doDetailedROBMonitoring.value()) && (robIdsUnique.size() != 0)) { + if ( !(m_storeGateSvc->transientContains<ROBDataMonitorCollection>(m_ROBDataMonitorCollection_SG_Name.value())) ) { + p_robMonCollection = new ROBDataMonitorCollection; + if ( p_robMonCollection ) { + p_robMonCollection->reserve( HltROBDataProviderConstants::Number_of_Rob_Monitor_Structs ) ; + if ( (m_storeGateSvc->record(p_robMonCollection, m_ROBDataMonitorCollection_SG_Name.value(), true)).isFailure() ) { + logStream() << MSG::WARNING << " getROBData: Registering ROB Monitoring collection in StoreGate failed." << endreq; + delete p_robMonCollection; + p_robMonCollection = 0; + } + } + } else { + if ( m_storeGateSvc->retrieve(p_robMonCollection).isFailure() ) { + logStream() << MSG::WARNING << " getROBData: Retrieval of ROB Monitoring collection from StoreGate failed." << endreq; + p_robMonCollection = 0; + } + } + } + + // create a new ROBDataMonitorStruct and fill it + robmonitor::ROBDataMonitorStruct* p_robMonStruct(0); + if ( p_robMonCollection ) { + // caller name + std::string caller_name("UNKNOWN"); + if (callerName != "UNKNOWN") { + caller_name = callerName; + } else if ((callerName == "UNKNOWN") && (m_callerName != "UNKNOWN")) { + caller_name = m_callerName; + } else { + IAlgorithm* alg(0); + if ( m_algContextSvc ) { + alg = m_algContextSvc->currentAlg(); + caller_name = (alg ? alg->name() : "<NONE>"); + } + } + + // initialize new ROBDataMonitorStruct + p_robMonStruct = new robmonitor::ROBDataMonitorStruct(m_currentLvl1ID, robIdsUnique, caller_name); + } + + //-------------------------- + // update internal ROB cache + //-------------------------- + addROBDataToCache(robIdsUnique, p_robMonStruct); + + // add the ROB monitoring structure to the collection + if ( p_robMonCollection && p_robMonStruct ) p_robMonCollection->push_back( p_robMonStruct ); + + + //------------------------------------------------------------------ + // Return requested ROBs from internal cache + //------------------------------------------------------------------ + for(std::vector<uint32_t>::const_iterator it = robIdsUnique.begin(); it != robIdsUnique.end(); ++it){ + uint32_t id = (*it); + ONLINE_ROBMAP::iterator map_it = m_online_robmap.find(id) ; + if(map_it != m_online_robmap.end()) { + robFragments.push_back( &((*map_it).second) ); + } else { + if(logLevel() <= MSG::DEBUG) { + logStream()<<MSG::DEBUG<<" ---> getROBData: Failed to find ROB for id 0x" + <<MSG::hex<< id <<MSG::dec<<endreq; + if(logLevel() <= MSG::VERBOSE) { logStream()<<MSG::VERBOSE<< dumpROBcache() <<endreq; } + } + } + } + } + + return ; +} + +/// Retrieve the whole event. +const RawEvent* HltROBDataProviderSvc::getEvent(){ + if (m_onlineRunning) return 0; + return ROBDataProviderSvc::getEvent(); +} + +/// Return vector with all ROBFragments stored in the cache +void HltROBDataProviderSvc::getAllROBData(std::vector<const ROBF*>& robFragments) +{ + //------------------ + //--- online running + //------------------ + if (m_onlineRunning) { + for(ONLINE_ROBMAP::iterator it=m_online_robmap.begin(); it!=m_online_robmap.end(); ++it) { + robFragments.push_back( &((*it).second) ); + } + } + return ; +} + +// Dump ROB cache +std::string HltROBDataProviderSvc::dumpROBcache() const { + + ONLINE_ROBMAP::const_iterator cache_it = m_online_robmap.begin() ; + ONLINE_ROBMAP::const_iterator cache_end = m_online_robmap.end() ; + int nrob = 0; + + std::ostringstream ost; + ost << " --- Dump of ROB cache ids --- total size = " + << m_online_robmap.size() <<"\n"; + for(; cache_it!=cache_end; ++cache_it){ + ++nrob; + ost <<" # = "<< std::setw(5) << nrob << " cache id = 0x" << std::hex << (*cache_it).first + << " hex: source id = 0x" << std::hex << (*cache_it).second.source_id() + << std::dec << " decimal: source id = " << (*cache_it).second.source_id() << "\n"; + } + std::string ret(ost.str()); + return ret; +} + +/// Collect all data for an event from the ROS and put them into the cache +/// Return value: number of ROBs which were retrieved to complete event +int HltROBDataProviderSvc::collectCompleteEventData(const std::string callerName) { + + // return if call was already issued + if (m_isEventComplete) return 0; + + //-------------------- + // set the caller name + //-------------------- + if (callerName != "UNKNOWN") m_callerName = callerName; + + typedef std::vector<hltinterface::DCM_ROBInfo> ROBInfoVec; + ROBInfoVec vRobInfos ; + if (m_enabledROBs.value().size() != 0) { + vRobInfos.reserve( m_enabledROBs.value().size() ) ; + } else { + vRobInfos.reserve( HltROBDataProviderConstants::Max_Number_Of_ROBs ) ; + } + + struct timeval time_start; + struct timeval time_stop; + if ( m_doMonitoring || m_doDetailedROBMonitoring.value() ) gettimeofday(&time_start, 0); + + // Get ROB Fragments for complete event with DataCollector + hltinterface::DataCollector::instance()->collect(vRobInfos, m_currentLvl1ID); + + if ( m_doMonitoring || m_doDetailedROBMonitoring.value() ) gettimeofday(&time_stop, 0); + + if (logLevel() <= MSG::DEBUG) { + std::ostringstream ost; + unsigned int rob_counter = 1; + for (ROBInfoVec::const_iterator rob_it = vRobInfos.begin(); rob_it != vRobInfos.end(); ++rob_it,++rob_counter) + ost << " # = "<< std::setw(5) << rob_counter << " ROB id = 0x" << std::hex << rob_it->robFragment.source_id() << std::dec << "\n" ; + logStream() << MSG::DEBUG + << " ---> collectCompleteEventData: The following ROB Ids were received from DataCollector : \n" + << " Lvl1 id = " << m_currentLvl1ID << "\n" + << " Number of actually received ROB Ids = " << vRobInfos.size() << "\n" + << ost.str() + << endreq; + } + + // detailed ROB monitoring + //------------------------ + // Create a ROB monitoring collection and register it to StoreGate + ROBDataMonitorCollection* p_robMonCollection(0); + if ( m_doDetailedROBMonitoring.value() ) { + if ( !(m_storeGateSvc->transientContains<ROBDataMonitorCollection>(m_ROBDataMonitorCollection_SG_Name.value())) ) { + p_robMonCollection = new ROBDataMonitorCollection; + if ( p_robMonCollection ) { + p_robMonCollection->reserve( HltROBDataProviderConstants::Number_of_Rob_Monitor_Structs ) ; + if ( (m_storeGateSvc->record(p_robMonCollection, m_ROBDataMonitorCollection_SG_Name.value(), true)).isFailure() ) { + logStream() << MSG::WARNING << " Registering ROB Monitoring collection in StoreGate failed." << endreq; + delete p_robMonCollection; + p_robMonCollection = 0; + } + } + } else { + if ( m_storeGateSvc->retrieve(p_robMonCollection).isFailure() ) { + logStream() << MSG::WARNING << " Retrieval of ROB Monitoring collection from StoreGate failed." << endreq; + p_robMonCollection = 0; + } + } + } + + // create a new ROBDataMonitorStruct and fill it + robmonitor::ROBDataMonitorStruct* p_robMonStruct(0); + if ( p_robMonCollection ) { + // caller name + std::string caller_name("UNKNOWN"); + if (callerName != "UNKNOWN") { + caller_name = callerName; + } else if ((callerName == "UNKNOWN") && (m_callerName != "UNKNOWN")) { + caller_name = m_callerName; + } else { + IAlgorithm* alg(0); + if ( m_algContextSvc ) { + alg = m_algContextSvc->currentAlg(); + caller_name = (alg ? alg->name() : "<NONE>"); + } + } + + // get ROB Ids + std::vector<uint32_t> robIds; + robIds.reserve(vRobInfos.size()); + for(ROBInfoVec::const_iterator it=vRobInfos.begin(); it!=vRobInfos.end(); ++it) { + robIds.push_back( it->robFragment.source_id() ) ; + } + + // initialize new ROBDataMonitorStruct + p_robMonStruct = new robmonitor::ROBDataMonitorStruct(m_currentLvl1ID, robIds, caller_name); + } + + if ( m_doMonitoring || p_robMonStruct ) { + int secs = 0 ; + if (time_stop.tv_sec >= time_start.tv_sec) + secs = time_stop.tv_sec - time_start.tv_sec; + + int usecs = time_stop.tv_usec - time_start.tv_usec; + float mtime = static_cast<float>(secs)*1000 + static_cast<float>(usecs)/1000; + + //* timing histogram + if (m_hist_timeROBretrieval) { + scoped_lock_histogram lock; + m_hist_timeROBretrieval->Fill(mtime); + m_hist_timeROBretrieval->LabelsDeflate("X"); + } + //* number of received ROBs + if ( m_hist_receivedROBsPerCall ) { + scoped_lock_histogram lock; + m_hist_receivedROBsPerCall->Fill(vRobInfos.size()); + m_hist_receivedROBsPerCall->LabelsDeflate("X"); + } + + //* detailed monitoring + if ( p_robMonStruct ) { + p_robMonStruct->start_time_of_ROB_request = time_start; + p_robMonStruct->end_time_of_ROB_request = time_stop; + } + } + + // add ROBs to cache + updateROBDataCache(vRobInfos,p_robMonStruct); + + // add the ROB monitoring structure to the collection + if ( p_robMonCollection && p_robMonStruct ) p_robMonCollection->push_back( p_robMonStruct ); + + // update event complete flag + m_isEventComplete = true; + + return vRobInfos.size(); +} // end int collectCompleteEventData(...) + +/// set the name of the program which uses the ROBDataProviderSvc +void HltROBDataProviderSvc::setCallerName(const std::string callerName) { + m_callerName = callerName; +} + +// handler for BeginRun +void HltROBDataProviderSvc::handle(const Incident& incident) { + if (incident.type()!="BeginRun") return; + if(logLevel() <= MSG::DEBUG) + logStream() <<MSG::DEBUG << "In BeginRun incident." << endreq; + + // if detailed ROB monitoring is requested, check if the AlgContextSvc is running, + // if yes use it to obtain the calling algorithm name + if ( m_doDetailedROBMonitoring.value() ) { + if ( service("AlgContextSvc", m_algContextSvc, /*createIf=*/ false).isFailure() ) { + logStream() << MSG::ERROR << "Error retrieving AlgContextSvc." + << "Calling algorithm name not available in detailed ROB monitoring" << endreq; + m_algContextSvc=0; + } + } + + // define histograms if monitoring is requested + if ( !m_doMonitoring.value() ) return; + + // find histogramming service + ServiceHandle<ITHistSvc> rootHistSvc("THistSvc", name()); + if ((rootHistSvc.retrieve()).isFailure()) { + logStream() << MSG::ERROR << "Unable to locate THistSvc" << endreq; + rootHistSvc.release().ignore(); + return; + } + + // *-- booking path + std::string path = std::string("/EXPERT/")+getGaudiThreadGenericName(name())+"/"; + + // *-- number of bins for sub detector plots (55 SubDet max.) + uint32_t n_bins_partEBSubDet = eformat::helper::SubDetectorDictionary.size(); + + // *-- number of requested ROBs per call + m_hist_requestedROBsPerCall = new TH1F (m_histProp_requestedROBsPerCall.value().title().c_str(), + (m_histProp_requestedROBsPerCall.value().title()+";number of ROBs").c_str(), + m_histProp_requestedROBsPerCall.value().bins(), + m_histProp_requestedROBsPerCall.value().lowEdge(), + m_histProp_requestedROBsPerCall.value().highEdge()); + if (m_hist_requestedROBsPerCall) { + CAN_REBIN(m_hist_requestedROBsPerCall); + if( rootHistSvc->regHist(path + m_hist_requestedROBsPerCall->GetName(), m_hist_requestedROBsPerCall).isFailure() ) { + logStream() << MSG::WARNING << "Can not register monitoring histogram: " << m_hist_requestedROBsPerCall->GetName() << endreq; + } + } + + // *-- number of received ROBs per call + m_hist_receivedROBsPerCall = new TH1F (m_histProp_receivedROBsPerCall.value().title().c_str(), + (m_histProp_receivedROBsPerCall.value().title()+";number of ROBs").c_str(), + m_histProp_receivedROBsPerCall.value().bins(), + m_histProp_receivedROBsPerCall.value().lowEdge(), + m_histProp_receivedROBsPerCall.value().highEdge()); + if (m_hist_receivedROBsPerCall) { + CAN_REBIN(m_hist_receivedROBsPerCall); + if( rootHistSvc->regHist(path + m_hist_receivedROBsPerCall->GetName(), m_hist_receivedROBsPerCall).isFailure() ) { + logStream() << MSG::WARNING << "Can not register monitoring histogram: " << m_hist_receivedROBsPerCall->GetName() << endreq; + } + } + + // *-- timing of ROB retrieval + m_hist_timeROBretrieval = new TH1F (m_histProp_timeROBretrieval.value().title().c_str(), + (m_histProp_timeROBretrieval.value().title()+";time [ms]").c_str(), + m_histProp_timeROBretrieval.value().bins(), + m_histProp_timeROBretrieval.value().lowEdge(), + m_histProp_timeROBretrieval.value().highEdge()); + if (m_hist_timeROBretrieval) { + CAN_REBIN(m_hist_timeROBretrieval); + if( rootHistSvc->regHist(path + m_hist_timeROBretrieval->GetName(), m_hist_timeROBretrieval).isFailure() ) { + logStream() << MSG::WARNING << "Can not register monitoring histogram: " << m_hist_timeROBretrieval->GetName() << endreq; + } + } + + // *-- Generic Status for ROBs per sub detector + m_hist_genericStatusForROB = new TH2F ("GenericStatusForROBsFromSubDetectors", + "GenericStatusForROBsFromSubDetectors;;", + n_bins_partEBSubDet,0.,(float) n_bins_partEBSubDet, + m_map_GenericStatus.size(),0., (float) m_map_GenericStatus.size()); + if (m_hist_genericStatusForROB) { + uint32_t n_tmp_bin = 1; + for (eformat::helper::EnumClass<eformat::SubDetector>::const_iterator it_sub=eformat::helper::SubDetectorDictionary.begin(); + it_sub != eformat::helper::SubDetectorDictionary.end(); it_sub++ ) { + m_hist_genericStatusForROB->GetXaxis()->SetBinLabel( n_tmp_bin, (it_sub->second).c_str() ); + n_tmp_bin++; + } + + n_tmp_bin = 1; + for (std::map<eformat::GenericStatus, std::string>::const_iterator it = m_map_GenericStatus.begin();it != m_map_GenericStatus.end();++it) { + m_hist_genericStatusForROB->GetYaxis()->SetBinLabel( n_tmp_bin, (*it).second.c_str() ); + n_tmp_bin++; + } + if( rootHistSvc->regHist(path + m_hist_genericStatusForROB->GetName(), m_hist_genericStatusForROB).isFailure() ) { + logStream() << MSG::WARNING << "Can not register monitoring histogram: " << m_hist_genericStatusForROB->GetName() << endreq; + } + } + + // *-- Specific Status Bits for ROBs per sub detector + m_hist_specificStatusForROB = new TH2F ("SpecificStatusBitsForROBsFromSubDetectors", + "SpecificStatusBitsForROBsFromSubDetectors;;", + n_bins_partEBSubDet,0.,(float) n_bins_partEBSubDet, + m_vec_SpecificStatus.size(),0., (float) m_vec_SpecificStatus.size()); + if (m_hist_specificStatusForROB) { + uint32_t n_tmp_bin = 1; + for (eformat::helper::EnumClass<eformat::SubDetector>::const_iterator it_sub=eformat::helper::SubDetectorDictionary.begin(); + it_sub != eformat::helper::SubDetectorDictionary.end(); it_sub++ ) { + m_hist_specificStatusForROB->GetXaxis()->SetBinLabel( n_tmp_bin, (it_sub->second).c_str() ); + n_tmp_bin++; + } + + n_tmp_bin = 1; + for (std::vector<std::string>::const_iterator it = m_vec_SpecificStatus.begin();it != m_vec_SpecificStatus.end();++it) { + m_hist_specificStatusForROB->GetYaxis()->SetBinLabel( n_tmp_bin, (*it).c_str() ); + n_tmp_bin++; + } + if( rootHistSvc->regHist(path + m_hist_specificStatusForROB->GetName(), m_hist_specificStatusForROB).isFailure() ) { + logStream() << MSG::WARNING << "Can not register monitoring histogram: " << m_hist_specificStatusForROB->GetName() << endreq; + } + } + + // release histogramming service + rootHistSvc.release().ignore(); +} // end handler for BeginRun + +// helper function to retrieve ROB fragments over the network and to add them to the cache +void HltROBDataProviderSvc::addROBDataToCache(std::vector<uint32_t>& robIdsForRetrieval, + robmonitor::ROBDataMonitorStruct* p_robMonStruct) { + + struct timeval time_start; + struct timeval time_stop; + + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << " ---> addROBDataToCache: Number of ROB Ids requested for retrieval : " << robIdsForRetrieval.size() + << ", Lvl1 id = " << m_currentLvl1ID << endreq; + + // return if no ROBs are requested + if (robIdsForRetrieval.size() == 0) return; + + std::vector<uint32_t> vRobIds, vMETRobIds; + vRobIds.reserve( robIdsForRetrieval.size() ); + vMETRobIds.reserve( robIdsForRetrieval.size() ); + + // Check requested ROBs + for (std::vector<uint32_t>::const_iterator rob_it=robIdsForRetrieval.begin(); rob_it!=robIdsForRetrieval.end(); ++rob_it) { + + // check first if ROB is already in cache + ONLINE_ROBMAP::iterator map_it = m_online_robmap.find(*rob_it) ; + if(map_it != m_online_robmap.end()) { + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << " ---> addROBDataToCache: Found ROB Id : 0x" << MSG::hex << (*map_it).second.source_id() << MSG::dec + <<" in cache "<< endreq; + continue; + } + + // check if ROB is actually enabled for readout + // do not perform this check for MET ROBs + if ( (m_enabledROBs.value().size() != 0) && + (eformat::helper::SourceIdentifier(*rob_it).subdetector_id() != eformat::TDAQ_LAR_MET) && + (eformat::helper::SourceIdentifier(*rob_it).subdetector_id() != eformat::TDAQ_TILE_MET) ){ + std::vector<uint32_t>::const_iterator rob_enabled_it = + std::find(m_enabledROBs.value().begin(), m_enabledROBs.value().end(),(*rob_it)); + if(rob_enabled_it == m_enabledROBs.value().end()) { + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << " ---> addROBDataToCache: ROB Id : 0x" << MSG::hex << (*rob_it) << MSG::dec + << " will be not retrieved, since it is not on the list of enabled ROBs."<< endreq; + continue; + } + } + + // separate MET and detector ROBs if requested + if ( (m_separateMETandDetROBRetrieval.value()) && + ( (eformat::helper::SourceIdentifier(*rob_it).subdetector_id() == eformat::TDAQ_LAR_MET) || + (eformat::helper::SourceIdentifier(*rob_it).subdetector_id() == eformat::TDAQ_TILE_MET) ) ) { + vMETRobIds.push_back( *rob_it ) ; + } else { + vRobIds.push_back( *rob_it ); + } + } + + typedef std::vector<hltinterface::DCM_ROBInfo> ROBInfoVec; + ROBInfoVec vRobInfos ; + + // Get ROB Fragments with DataCollector + if ( m_doMonitoring || p_robMonStruct ) gettimeofday(&time_start, 0); + if ( vRobIds.size() != 0 ) { + vRobInfos.reserve( vRobIds.size() ) ; + hltinterface::DataCollector::instance()->collect(vRobInfos, m_currentLvl1ID, vRobIds); + } + + // Do a separate data collect call for MET ROBs if required + if ( (m_separateMETandDetROBRetrieval.value()) && (vMETRobIds.size() != 0) ) { + ROBInfoVec vMETRobInfos; + vMETRobInfos.reserve( vMETRobIds.size() ) ; + // retrieve MET ROBs + hltinterface::DataCollector::instance()->collect(vMETRobInfos, m_currentLvl1ID, vMETRobIds); + + // add MET ROBs to Det ROBs + vRobInfos.insert( vRobInfos.end(), vMETRobInfos.begin(), vMETRobInfos.end() ); + } + + if((logLevel() <= MSG::DEBUG) && ((vRobIds.size()!=0) || (vMETRobIds.size()!=0))) { + std::ostringstream ost; + unsigned int rob_counter = 1; + for (ROBInfoVec::const_iterator rob_it = vRobInfos.begin(); rob_it != vRobInfos.end(); ++rob_it,++rob_counter) + ost << " # = "<< std::setw(5) << rob_counter << " ROB id = 0x" << std::hex << rob_it->robFragment.source_id() << std::dec << "\n" ; + logStream() << MSG::DEBUG + << " ---> addROBDataToCache: The following ROB Ids were received from DataCollector : \n" + << " Lvl1 id = " << m_currentLvl1ID << "\n" + << " Number of detector ROB Ids requested for retrieval = " << vRobIds.size() << "\n" + << " Number of MET ROB Ids requested for retrieval = " << vMETRobIds.size() << "\n" + << " Number of actually received ROB Ids = " << vRobInfos.size() << "\n" + << ost.str() + << endreq; + } + + if ( m_doMonitoring || p_robMonStruct ) { + gettimeofday(&time_stop, 0); + int secs = 0 ; + if (time_stop.tv_sec >= time_start.tv_sec) + secs = time_stop.tv_sec - time_start.tv_sec; + + int usecs = time_stop.tv_usec - time_start.tv_usec; + float mtime = static_cast<float>(secs)*1000 + static_cast<float>(usecs)/1000; + + //* timing histogram + if (m_hist_timeROBretrieval) { + scoped_lock_histogram lock; + m_hist_timeROBretrieval->Fill(mtime); + m_hist_timeROBretrieval->LabelsDeflate("X"); + } + + //* detailed monitoring + if ( p_robMonStruct ) { + p_robMonStruct->start_time_of_ROB_request = time_start; + p_robMonStruct->end_time_of_ROB_request = time_stop; + } + } + + //* histograms for number of requested/received ROBs + if ( m_hist_requestedROBsPerCall ) { + scoped_lock_histogram lock; + m_hist_requestedROBsPerCall->Fill(robIdsForRetrieval.size()); + m_hist_requestedROBsPerCall->LabelsDeflate("X"); + } + if ( m_hist_receivedROBsPerCall ) { + scoped_lock_histogram lock; + m_hist_receivedROBsPerCall->Fill(vRobInfos.size()); + m_hist_receivedROBsPerCall->LabelsDeflate("X"); + } + + // add ROBs to cache + updateROBDataCache(vRobInfos,p_robMonStruct); + + return; +} // end void addROBDataToCache(...) + + +// helper function to put retrieved ROB fragments into the local cache and update the monitoring records +void HltROBDataProviderSvc::updateROBDataCache(std::vector<hltinterface::DCM_ROBInfo>& vRobInfo, + robmonitor::ROBDataMonitorStruct* p_robMonStruct) { + + if(logLevel() <= MSG::DEBUG) + logStream() << MSG::DEBUG << " ---> updateROBDataCache: Number of ROB Info records for cache update : " << vRobInfo.size() + << ", Lvl1 id = " << m_currentLvl1ID << endreq; + + // return if no ROB Info records are available + if (vRobInfo.size() == 0) return; + + // add ROBs to cache + typedef std::vector<hltinterface::DCM_ROBInfo> ROBInfoVec; + for(ROBInfoVec::const_iterator it=vRobInfo.begin(); it!=vRobInfo.end(); ++it) { + uint32_t id = it->robFragment.source_id() ; + if ((it->robFragment.rod_ndata() == 0) && (m_removeEmptyROB)) { + if(logLevel() <= MSG::DEBUG) { + logStream() << MSG::DEBUG << " ---> addROBDataToCache: Empty ROB Id = 0x" << MSG::hex << id << MSG::dec + << " removed for L1 Id = " << m_currentLvl1ID << endreq; + } + } else if ( ROBDataProviderSvc::filterRobWithStatus(&it->robFragment)) { + if ((logLevel() <= MSG::DEBUG) && (it->robFragment.nstatus() > 0)) { + const uint32_t* it_status; + it->robFragment.status(it_status); + eformat::helper::Status tmpstatus( (*it_status) ) ; + logStream() << MSG::DEBUG << " ---> addROBDataToCache: ROB Id = 0x" << MSG::hex << id + << std::setfill( '0' ) + << " with Generic Status Code = 0x" << std::setw(4) << tmpstatus.generic() + << " and Specific Status Code = 0x" << std::setw(4) << tmpstatus.specific() + << MSG::dec + << " removed for L1 Id = " << m_currentLvl1ID << endreq; + } + } else { + m_online_robmap[id]= (it->robFragment); + } + + //* fill monitoring histogram for ROB generic status + if ( ( m_hist_genericStatusForROB ) && ( it->robFragment.nstatus() != 0 ) ) { + const uint32_t* it_status; + it->robFragment.status(it_status); + if ((*it_status) != 0) { + scoped_lock_histogram lock; + m_hist_genericStatusForROB->Fill(eformat::helper::SourceIdentifier(it->robFragment.source_id()).human_detector().c_str(), + m_map_GenericStatus[eformat::helper::Status(*it_status).generic()].c_str(),1.); + } + } + + //* fill monitoring histogram for ROB specific status + if ( ( m_hist_specificStatusForROB ) && ( it->robFragment.nstatus() != 0 ) ) { + const uint32_t* it_status; + it->robFragment.status(it_status); + if ((*it_status) != 0) { + scoped_lock_histogram lock; + std::bitset<16> specificBits(eformat::helper::Status(*it_status).specific()); + for (unsigned int index=0; index < 16; ++index) { + if (specificBits[index]) m_hist_specificStatusForROB->Fill(eformat::helper::SourceIdentifier(it->robFragment.source_id()).human_detector().c_str(), + m_vec_SpecificStatus[index].c_str(),1.); + } + } + } + + //* detailed monitoring + if ( p_robMonStruct ) { + (p_robMonStruct->requested_ROBs)[id].rob_history = robmonitor::RETRIEVED; + (p_robMonStruct->requested_ROBs)[id].rob_size = it->robFragment.fragment_size_word(); + if ( it->robFragment.nstatus() != 0 ) { + const uint32_t* it_status; + it->robFragment.status(it_status); + for (uint32_t k=0; k < it->robFragment.nstatus(); k++) { + (p_robMonStruct->requested_ROBs)[id].rob_status_words.push_back( *(it_status+k) ); + } + } + } // end detailed monitoring + } // end loop over ROBInfo records + return; +} // end void updateROBDataCache(...) diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx new file mode 100644 index 00000000000..47a3bf6730b --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx @@ -0,0 +1,2089 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifdef __ICC +// disable icc remark #2259: non-pointer conversion from "X" to "Y" may lose significant bits +// TODO: To be removed, since it comes from ROOT TMathBase.h +#pragma warning(disable:2259) +#endif + +#include "THistSvcHLT.h" + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/AttribStringParser.h" +#include "GaudiKernel/GaudiException.h" +#include "GaudiKernel/Property.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/FileIncident.h" +#include "GaudiKernel/IEventProcessor.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "GaudiKernel/IIoComponentMgr.h" +#include "GaudiKernel/IFileMgr.h" +#include "boost/algorithm/string/case_conv.hpp" + +#include "TROOT.h" +#include "TFile.h" +#include "TDirectory.h" +#include "TKey.h" +#include "TError.h" +#include "TGraph.h" + +#include <sstream> +#include <streambuf> +#include <cstdio> + +using namespace std; + + +DECLARE_COMPONENT(THistSvcHLT) + +namespace { + +template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename UnaryPredicate> +OutputIterator transform_if( InputIterator first, InputIterator last, + OutputIterator result, + UnaryOperation op, + UnaryPredicate pred) { + while (first != last) { + if (pred(*first)) *result++ = op(*first); + ++first; + } + return result; +} + +constexpr struct select1st_t { + template <typename T, typename S> + const T& operator()(const std::pair<T,S>& p) const { return p.first; } +} select1st {} ; + + +} + + +//*************************************************************************// + +THistSvcHLT::THistSvcHLT( const std::string& name, ISvcLocator* svc ) + : base_class(name, svc), m_log(msgSvc(), name ) +{ + declareProperty ("AutoSave", m_autoSave=0 ); + declareProperty ("AutoFlush", m_autoFlush=0 ); + declareProperty ("PrintAll", m_print=false); + declareProperty ("MaxFileSize", m_maxFileSize=10240, + "maximum file size in MB. if exceeded, will cause an abort. -1 to never check."); + declareProperty ("CompressionLevel", m_compressionLevel=1 )->declareUpdateHandler( &THistSvcHLT::setupCompressionLevel, this ); + declareProperty ("Output", m_outputfile )->declareUpdateHandler( &THistSvcHLT::setupOutputFile, this ); + declareProperty ("Input", m_inputfile )->declareUpdateHandler ( &THistSvcHLT::setupInputFile, this ); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::initialize() { + GlobalDirectoryRestore restore; + + // Super ugly hack to make sure we have the OutputLevel set first, so we + // can see DEBUG printouts in update handlers. + auto jos = serviceLocator()->service<IJobOptionsSvc>( "JobOptionsSvc", true ); + if( jos ) { + const auto props = jos->getProperties( name() ); + + if ( props ) { + auto i = std::find_if(std::begin(*props),std::end(*props), + [](const Property* p) { return p->name() == "OutputLevel"; } ); + if ( i != std::end(*props)) { + setProperty( **i ).ignore(); + m_log.setLevel( m_outputLevel.value() ); + } + } + } + + + StatusCode status = Service::initialize(); + m_log.setLevel( m_outputLevel.value() ); + + if (status.isFailure()) { + m_log << MSG::ERROR << "initializing service" << endmsg; + return status; + } + + StatusCode st(StatusCode::SUCCESS); + + try { + setupOutputFile( m_outputfile ); + } catch ( GaudiException& err ) { + m_log << MSG::ERROR + << "Caught: " << err << endmsg; + st = StatusCode::FAILURE; + } + + try { + setupInputFile( m_inputfile ); + } catch ( GaudiException& err ) { + m_log << MSG::ERROR + << "Caught: " << err << endmsg; + st = StatusCode::FAILURE; + } + + // Protect against multiple instances of TROOT + if ( !gROOT ) { + static TROOT root("root","ROOT I/O"); + // gDebug = 99; + } else { + if (m_log.level() <= MSG::VERBOSE) + m_log << MSG::VERBOSE << "ROOT already initialized, debug = " + << gDebug<< endmsg; + } + + if (service("IncidentSvc", p_incSvc, true).isFailure()) { + m_log << MSG::ERROR << "unable to get the IncidentSvc" << endmsg; + st = StatusCode::FAILURE; + } else { + p_incSvc->addListener( this, "EndEvent", 100, true); + } + + if (service("FileMgr",p_fileMgr,true).isFailure()) { + m_log << MSG::ERROR << "unable to get the FileMgr" << endmsg; + st = StatusCode::FAILURE; + } else { + m_log << MSG::DEBUG << "got the FileMgr" << endmsg; + } + + + // Register open/close callback actions + + using namespace std::placeholders; + auto boa = [this](const Io::FileAttr* fa, const std::string& caller) { return this->rootOpenAction(fa,caller); }; + if (p_fileMgr->regAction(boa, Io::OPEN, Io::ROOT).isFailure()) { + m_log << MSG::ERROR + << "unable to register ROOT file open action with FileMgr" + << endmsg; + } + auto bea = [this](const Io::FileAttr* fa, const std::string& caller) { return this->rootOpenErrAction(fa,caller); }; + if (p_fileMgr->regAction(bea, Io::OPEN_ERR, Io::ROOT).isFailure()) { + m_log << MSG::ERROR + << "unable to register ROOT file open Error action with FileMgr" + << endmsg; + } + + + m_okToConnect = true; + + if (m_delayConnect) { + if (!m_inputfile.value().empty()) { setupInputFile(m_inputfile); } + if (!m_outputfile.value().empty()) { setupOutputFile(m_outputfile); } + + m_delayConnect = false; + + } + m_alreadyConnectedOutFiles.clear(); + m_alreadyConnectedInFiles.clear(); + + + IIoComponentMgr* iomgr = nullptr; + + if (service("IoComponentMgr", iomgr, true).isFailure()) { + m_log << MSG::ERROR << "unable to get the IoComponentMgr" << endmsg; + st = StatusCode::FAILURE; + } else { + + if ( !iomgr->io_register (this).isSuccess() ) { + m_log << MSG::ERROR + << "could not register with the I/O component manager !" + << endmsg; + st = StatusCode::FAILURE; + } else { + bool all_good = true; + // register input/output files... + for ( const auto& reg : m_files ) { + const std::string& fname = reg.second.first->GetName(); + const IIoComponentMgr::IoMode::Type iomode = + ( reg.second.second==THistSvcHLT::READ + ? IIoComponentMgr::IoMode::READ + : IIoComponentMgr::IoMode::WRITE ); + if ( !iomgr->io_register (this, iomode, fname).isSuccess () ) { + m_log << MSG::WARNING << "could not register file [" + << fname << "] with the I/O component manager..." << endmsg; + all_good = false; + } else { + m_log << MSG::INFO << "registered file [" << fname << "]... [ok]" + << endmsg; + } + } + if (!all_good) { + m_log << MSG::ERROR + << "problem while registering input/output files with " + << "the I/O component manager !" << endmsg; + st = StatusCode::FAILURE; + } + } + + } + + if (st.isFailure()) { + m_log << MSG::FATAL << "Unable to initialize THistSvcHLT" << endmsg; + } + + return st; + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::reinitialize() { + + GlobalDirectoryRestore restore; + m_log << MSG::WARNING << "reinitialize not implemented" << endmsg; + return StatusCode::SUCCESS; + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::finalize() { + + GlobalDirectoryRestore restore; + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "THistSvcHLT::finalize" << endmsg; + +#ifndef NDEBUG + if (m_log.level() <= MSG::DEBUG) { + for (const auto& uid : m_uids ) { + + TObject* to = uid.second.obj; + + string dirname("none"); + if (to && to->IsA()->InheritsFrom("TTree")) { + TTree* tr = dynamic_cast<TTree*>(to); + if (tr->GetDirectory() != 0) { + dirname = tr->GetDirectory()->GetPath(); + } + } else if (to && to->IsA()->InheritsFrom("TGraph")) { + if (!uid.second.temp) { + dirname = uid.second.file->GetPath(); + string id2(uid.second.id); + id2.erase(0,id2.find("/",1)); + id2.erase(id2.rfind("/"), id2.length()); + if (id2.find("/") == 0) { + id2.erase(0,1); + } + dirname += id2; + } else { + dirname = "/tmp"; + } + } else if (to && to->IsA()->InheritsFrom("TH1")) { + TH1* th = dynamic_cast<TH1*>(to); + if (th == 0) { + m_log << MSG::ERROR << "Couldn't dcast: " << uid.first << endmsg; + } else { + if (th->GetDirectory() != 0) { + dirname = th->GetDirectory()->GetPath(); + } + } + } else if (! to ) { + m_log << MSG::WARNING << uid.first << " has NULL TObject ptr" + << endmsg; + } + + m_log << MSG::DEBUG << "uid: \"" << uid.first << "\" temp: " + << uid.second.temp << " dir: " << dirname + << endmsg; + } + } +#endif + + StatusCode sc = write(); + if (sc.isFailure()) { + m_log << MSG::ERROR << "problems writing histograms" << endmsg; + } + + if (m_print) { + m_log << MSG::INFO << "Listing contents of ROOT files: " << endmsg; + } + vector<TFile*> deleted_files; + for (auto& itr : m_files ) { + + if (find(deleted_files.begin(), deleted_files.end(), itr.second.first) == + deleted_files.end()) { + deleted_files.push_back(itr.second.first); + +#ifndef NDEBUG + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "finalizing stream/file " << itr.first << ":" + << itr.second.first->GetName() + << endmsg; +#endif + } else { +#ifndef NDEBUG + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "already finalized stream " << itr.first << endmsg; +#endif + continue; + } + + + if (m_print && m_log.level() <= MSG::INFO) { + + m_log << MSG::INFO; + m_log << "==> File: " << itr.second.first->GetName() + << " stream: " << itr.first << endmsg; + + itr.second.first->Print("base"); + } + + string tmpfn=itr.second.first->GetName(); + + p_fileMgr->close(itr.second.first, name()); + + IIncidentSvc *pi = nullptr; + if (service("IncidentSvc",pi).isFailure()) { + m_log << MSG::ERROR << "Unable to get the IncidentSvc" << endmsg; + return StatusCode::FAILURE; + } + + if (itr.second.second==SHARE) { + + //Merge File + void* vf = nullptr; + int r = p_fileMgr->open(Io::ROOT,name(), m_sharedFiles[itr.first], + Io::WRITE|Io::APPEND,vf,"HIST"); + + if (r) { + m_log << MSG::ERROR << "unable to open Final Output File: \"" + << m_sharedFiles[itr.first] << "\" for merging" + << endmsg; + return StatusCode::FAILURE; + } + + TFile *outputfile = (TFile*) vf; + pi->fireIncident(FileIncident(name(), IncidentType::WroteToOutputFile, + m_sharedFiles[itr.first])); + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "THistSvcHLT::write()::Merging Rootfile "<<endmsg; + + vf = nullptr; + r = p_fileMgr->open(Io::ROOT,name(),tmpfn,Io::READ,vf,"HIST"); + + if (r) { + m_log << MSG::ERROR << "unable to open temporary file: \"" + << tmpfn << endmsg; + return StatusCode::FAILURE; + } + + TFile *inputfile = (TFile*) vf; + + outputfile->SetCompressionLevel( inputfile->GetCompressionLevel() ); + + MergeRootFile(outputfile, inputfile); + + outputfile->Write(); + p_fileMgr->close(outputfile,name()); + p_fileMgr->close(inputfile,name()); + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "Trying to remove temporary file \"" << tmpfn + << "\""<<endmsg; + + std::remove(tmpfn.c_str()); + } + delete itr.second.first; + } + + m_sharedFiles.clear(); + m_fileStreams.clear(); + m_files.clear(); + m_uids.clear(); + m_ids.clear(); + m_tobjs.clear(); + + return Service::finalize(); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +bool +THistSvcHLT::browseTDir(TDirectory *dir) const { + + if (!dir) { + std::cerr << "TDirectory == 0" << std::endl; + return false; + } + + GlobalDirectoryRestore restore; + + dir->cd(); + + + cout << "-> " << dir->GetPath() << " " + << dir->GetListOfKeys()->GetSize() << endl; + + // TIter nextkey(dir->GetListOfKeys()); + TIter nextkey(dir->GetList()); + while (TKey *key = (TKey*)nextkey()) { + + TObject *obj = key->ReadObj(); + if (!obj) { cout << key->GetName() << " obj==0"<< endl; continue; } + // if (obj->IsA()->InheritsFrom("TDirectory")) { + cout << " Key: " << key->GetName() << " " + << " tit: " << obj->GetTitle() << " " + << " (" << key->GetClassName() << ")" << endl; + // } + } + + nextkey = dir->GetListOfKeys(); + while (TKey *key = (TKey*)nextkey()) { + + TObject *obj = key->ReadObj(); + if (!obj) { cout << key->GetName() << " obj==0"<< endl; continue; } + if (obj->IsA()->InheritsFrom("TDirectory")) { + TDirectory *tt = dynamic_cast<TDirectory*>(obj); + browseTDir(tt); + } + } + + return true; +} + + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getTHists(TDirectory *td, TList & tl, bool rcs) const { + GlobalDirectoryRestore restore; + + gErrorIgnoreLevel = kBreak; + + if (!td->cd()) { + m_log << MSG::ERROR << "getTHists: No such TDirectory \"" << td->GetPath() + << "\"" << endmsg; + return StatusCode::FAILURE; + } + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTHists: \"" << td->GetPath() << "\": found " + << td->GetListOfKeys()->GetSize() << " keys" << endmsg; + + TIter nextkey(td->GetListOfKeys()); + while (TKey *key = (TKey*)nextkey()) { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << " key: " << key->GetName(); + TObject *obj = key->ReadObj(); + if (obj != 0 && obj->IsA()->InheritsFrom("TDirectory")) { + if (m_log.level() <= MSG::DEBUG) + m_log << " (" << obj->IsA()->GetName() << ")"; + } else if (obj != 0 && obj->IsA()->InheritsFrom("TH1")) { + if (m_log.level() <= MSG::DEBUG) + m_log << " (" << obj->IsA()->GetName() << ")"; + tl.Add(obj); + } else if (obj != 0) { + if (m_log.level() <= MSG::DEBUG) + m_log << " [" << obj->IsA()->GetName() << "]"; + } + if (m_log.level() <= MSG::DEBUG) + m_log << endmsg; + } + + // operate recursively + if (rcs) { + nextkey = td->GetListOfKeys(); + while (TKey *key = (TKey*)nextkey()) { + TObject *obj = key->ReadObj(); + if (obj && obj->IsA()->InheritsFrom("TDirectory")) { + TDirectory *tt = dynamic_cast<TDirectory*>(obj); + getTHists(tt, tl, rcs); + } + } + } + + return StatusCode::SUCCESS; + + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getTHists(const std::string& dir, TList & tl, bool rcs) const { + + GlobalDirectoryRestore restore; + + gErrorIgnoreLevel = kBreak; + + StatusCode sc; + + std::string stream,rem,r2; + parseString(dir,stream,rem); + + auto itr = m_files.find(stream); + if (itr != m_files.end()) { + r2 = itr->second.first->GetName(); + r2 += ":/"; + r2 += rem; + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTHists: \"" << dir + << "\" looks like a stream name." << " associated TFile: \"" + << itr->second.first->GetName() << "\"" << endmsg; + + if (gDirectory->cd(r2.c_str())) { + m_curstream = stream; + sc = getTHists(gDirectory,tl,rcs); + m_curstream = ""; + return sc; + } else { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTHists: no such TDirectory \"" + << r2 << "\"" << endmsg; + } + + } else { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTHists: stream \"" << stream << "\" not found" + << endmsg; + } + + if (!gDirectory->cd(dir.c_str())) { + m_log << MSG::ERROR << "getTHists: No such TDirectory/stream \"" << dir + << "\"" << endmsg; + sc = StatusCode::FAILURE; + } else { + sc = getTHists(gDirectory,tl,rcs); + } + + return sc; + +} +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getTTrees(TDirectory *td, TList & tl, bool rcs) const { + GlobalDirectoryRestore restore; + + gErrorIgnoreLevel = kBreak; + + if (!td->cd()) { + m_log << MSG::ERROR << "getTTrees: No such TDirectory \"" + << td->GetPath() << "\"" << endmsg; + return StatusCode::FAILURE; + } + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTHists: \"" << td->GetPath() << "\": found " + << td->GetListOfKeys()->GetSize() << " keys" << endmsg; + + TIter nextkey(td->GetListOfKeys()); + while (TKey *key = (TKey*)nextkey()) { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << " key: " << key->GetName(); + TObject *obj = key->ReadObj(); + if (obj != 0 && obj->IsA()->InheritsFrom("TDirectory")) { + if (m_log.level() <= MSG::DEBUG) + m_log << " (" << obj->IsA()->GetName() << ")"; + } else if (obj != 0 && obj->IsA()->InheritsFrom("TTree")) { + if (m_log.level() <= MSG::DEBUG) + m_log << " (" << obj->IsA()->GetName() << ")"; + tl.Add(obj); + } else if (obj != 0) { + if (m_log.level() <= MSG::DEBUG) + m_log << " [" << obj->IsA()->GetName() << "]"; + } + m_log << endmsg; + } + + // operate recursively + if (rcs) { + nextkey = td->GetListOfKeys(); + while (TKey *key = (TKey*)nextkey()) { + TObject *obj = key->ReadObj(); + if (obj && obj->IsA()->InheritsFrom("TDirectory")) { + TDirectory *tt = dynamic_cast<TDirectory*>(obj); + getTTrees(tt, tl, rcs); + } + } + } + + return StatusCode::SUCCESS; + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getTTrees(const std::string& dir, TList & tl, bool rcs) const { + GlobalDirectoryRestore restore; + + gErrorIgnoreLevel = kBreak; + + StatusCode sc; + + std::string stream,rem,r2; + parseString(dir,stream,rem); + + auto itr = m_files.find(stream); + if (itr != m_files.end()) { + r2 = itr->second.first->GetName(); + r2 += ":/"; + r2 += rem; + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTTrees: \"" << dir + << "\" looks like a stream name." << " associated TFile: \"" + << itr->second.first->GetName() << "\"" << endmsg; + + if (gDirectory->cd(r2.c_str())) { + return getTTrees(gDirectory,tl,rcs); + } + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTTrees: no such TDirectory \"" + << r2 << "\"" << endmsg; + } else { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTTrees: stream \"" << stream << "\" not found" + << endmsg; + } + + if (!gDirectory->cd(dir.c_str())) { + m_log << MSG::ERROR << "getTTrees: No such TDirectory/stream \"" << dir + << "\"" << endmsg; + sc = StatusCode::FAILURE; + } else { + sc = getTTrees(gDirectory,tl,rcs); + } + return sc; +} + + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getTHists(TDirectory *td, TList & tl, bool rcs, bool reg) { + + GlobalDirectoryRestore restore; + + gErrorIgnoreLevel = kBreak; + + if (!td->cd()) { + m_log << MSG::ERROR << "getTHists: No such TDirectory \"" << td->GetPath() + << "\"" << endmsg; + return StatusCode::FAILURE; + } + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTHists: \"" << td->GetPath() << "\": found " + << td->GetListOfKeys()->GetSize() << " keys" << endmsg; + + TIter nextkey(td->GetListOfKeys()); + while (TKey *key = (TKey*)nextkey()) { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << " key: " << key->GetName(); + TObject *obj = key->ReadObj(); + if (obj && obj->IsA()->InheritsFrom("TDirectory")) { + if (m_log.level() <= MSG::DEBUG) + m_log << " (" << obj->IsA()->GetName() << ")"; + } else if (obj && obj->IsA()->InheritsFrom("TH1")) { + if (m_log.level() <= MSG::DEBUG) + m_log << " (" << obj->IsA()->GetName() << ")"; + tl.Add(obj); + if (reg && m_curstream != "") { + string dir = td->GetPath(); + string fil = td->GetFile()->GetName(); + dir.erase(0,fil.length()+1); + string id = "/" + m_curstream; + if ( dir == "/" ) { + id = id + "/" + key->GetName(); + } else { + id = id + dir + "/" + key->GetName(); + } + if (!exists(id)) { + if (m_log.level() <= MSG::DEBUG) + m_log << " reg as \"" << id << "\""; + regHist(id).ignore(); + } else { + if (m_log.level() <= MSG::DEBUG) + m_log << " already registered"; + } + } + } else if (obj) { + if (m_log.level() <= MSG::DEBUG) + m_log << " [" << obj->IsA()->GetName() << "]"; + } + if (m_log.level() <= MSG::DEBUG) + m_log << endmsg; + } + + // operate recursively + if (rcs) { + nextkey = td->GetListOfKeys(); + while (TKey *key = (TKey*)nextkey()) { + TObject *obj = key->ReadObj(); + if (obj && obj->IsA()->InheritsFrom("TDirectory")) { + TDirectory *tt = dynamic_cast<TDirectory*>(obj); + getTHists(tt, tl, rcs, reg); + } + } + } + + return StatusCode::SUCCESS; + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getTHists(const std::string& dir, TList & tl, bool rcs, bool reg) { + + GlobalDirectoryRestore restore; + + gErrorIgnoreLevel = kBreak; + + StatusCode sc; + + std::string stream,rem,r2; + parseString(dir,stream,rem); + + auto itr = m_files.find(stream); + if (itr != m_files.end()) { + r2 = itr->second.first->GetName(); + r2 += ":/"; + r2 += rem; + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTHists: \"" << dir + << "\" looks like a stream name." << " associated TFile: \"" + << itr->second.first->GetName() << "\"" << endmsg; + + if (gDirectory->cd(r2.c_str())) { + m_curstream = stream; + sc = getTHists(gDirectory,tl,rcs,reg); + m_curstream.clear(); + return sc; + } + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTHists: no such TDirectory \"" + << r2 << "\"" << endmsg; + + } else { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTHists: stream \"" << stream << "\" not found" + << endmsg; + } + + if (!gDirectory->cd(dir.c_str())) { + m_log << MSG::ERROR << "getTHists: No such TDirectory/stream \"" << dir + << "\"" << endmsg; + sc = StatusCode::FAILURE; + } else { + if (reg) { + m_log << MSG::WARNING << "Unable to register histograms automatically " + << "without a valid stream name" << endmsg; + reg = false; + } + sc = getTHists(gDirectory,tl,rcs,reg); + } + + return sc; + +} +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getTTrees(TDirectory *td, TList & tl, bool rcs, bool reg) { + + GlobalDirectoryRestore restore; + + gErrorIgnoreLevel = kBreak; + + if (!td->cd()) { + m_log << MSG::ERROR << "getTTrees: No such TDirectory \"" + << td->GetPath() << "\"" << endmsg; + return StatusCode::FAILURE; + } + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTHists: \"" << td->GetPath() << "\": found " + << td->GetListOfKeys()->GetSize() << " keys" << endmsg; + + TIter nextkey(td->GetListOfKeys()); + while (TKey *key = (TKey*)nextkey()) { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << " key: " << key->GetName(); + TObject *obj = key->ReadObj(); + if (obj && obj->IsA()->InheritsFrom("TDirectory")) { + if (m_log.level() <= MSG::DEBUG) + m_log << " (" << obj->IsA()->GetName() << ")"; + } else if (obj && obj->IsA()->InheritsFrom("TTree")) { + if (m_log.level() <= MSG::DEBUG) + m_log << " (" << obj->IsA()->GetName() << ")"; + tl.Add(obj); + if (reg && m_curstream != "") { + string dir = td->GetPath(); + string fil = td->GetFile()->GetName(); + dir.erase(0,fil.length()+1); + string id = "/" + m_curstream; + if ( dir == "/" ) { + id = id + "/" + key->GetName(); + } else { + id = id + dir + "/" + key->GetName(); + } + if (!exists(id)) { + if (m_log.level() <= MSG::DEBUG) + m_log << " reg as \"" << id << "\""; + regHist(id).ignore(); + } else { + if (m_log.level() <= MSG::DEBUG) + m_log << " already registered"; + } + } + } else if (obj != 0) { + if (m_log.level() <= MSG::DEBUG) + m_log << " [" << obj->IsA()->GetName() << "]"; + } + if (m_log.level() <= MSG::DEBUG) + m_log << endmsg; + } + + // operate recursively + if (rcs) { + nextkey = td->GetListOfKeys(); + while (TKey *key = (TKey*)nextkey()) { + TObject *obj = key->ReadObj(); + if (obj && obj->IsA()->InheritsFrom("TDirectory")) { + TDirectory *tt = dynamic_cast<TDirectory*>(obj); + getTTrees(tt, tl, rcs, reg); + } + } + } + + return StatusCode::SUCCESS; + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getTTrees(const std::string& dir, TList & tl, bool rcs, bool reg) { + + GlobalDirectoryRestore restore; + + gErrorIgnoreLevel = kBreak; + + StatusCode sc; + + std::string stream,rem,r2; + parseString(dir,stream,rem); + + auto itr = m_files.find(stream); + if (itr != m_files.end()) { + r2 = itr->second.first->GetName(); + r2 += ":/"; + r2 += rem; + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTTrees: \"" << dir + << "\" looks like a stream name." << " associated TFile: \"" + << itr->second.first->GetName() << "\"" << endmsg; + + if (gDirectory->cd(r2.c_str())) { + return getTTrees(gDirectory,tl,rcs,reg); + } else { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTTrees: no such TDirectory \"" + << r2 << "\"" << endmsg; + } + + } else { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "getTTrees: stream \"" << stream << "\" not found" + << endmsg; + } + + if (!gDirectory->cd(dir.c_str())) { + m_log << MSG::ERROR << "getTTrees: No such TDirectory/stream \"" << dir + << "\"" << endmsg; + return StatusCode::FAILURE; + } + + return getTTrees(gDirectory,tl,rcs,reg); + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::deReg(TObject* obj) { + + auto itr = m_tobjs.find(obj); + if (itr != m_tobjs.end()) { + THistID hid = itr->second; + + auto itr2 = m_uids.find(hid.id); + if (itr2 == m_uids.end()) { + m_log << MSG::ERROR << "Problems deregistering TObject \"" + << obj->GetName() + << "\" with id \"" << hid.id << "\"" << endmsg; + return StatusCode::FAILURE; + } + + std::string id,root,rem; + parseString(hid.id, root, rem); + + auto mitr = m_ids.equal_range(rem); + auto itr3 = std::find_if( mitr.first, mitr.second, [&](idMap::const_reference i) + { return i.second.obj == obj; } ) ; + if (itr3 != mitr.second ) { + m_log << MSG::ERROR << "Problems deregistering TObject \"" + << obj->GetName() + << "\" with id \"" << hid.id << "\"" << endmsg; + return StatusCode::FAILURE; + } + + m_tobjs.erase(itr); + m_uids.erase(itr2); + m_ids.erase(itr3); + + return StatusCode::SUCCESS; + + } else { + m_log << MSG::ERROR << "Cannot unregister TObject \"" << obj->GetName() + << "\": not known to THistSvcHLT" << endmsg; + return StatusCode::FAILURE; + } + +} + + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::deReg(const std::string& id) { + + auto itr = m_uids.find(id); + if (itr == m_uids.end()) { + m_log << MSG::ERROR << "Problems deregistering id \"" + << id << "\"" << endmsg; + return StatusCode::FAILURE; + } + + TObject* obj = itr->second.obj; + return deReg(obj); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::regHist(const std::string& id) { + + TH1 *hist = nullptr; + return regHist_i(hist, id); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::regHist(const std::string& id, TH1* hist) { + return regHist_i(hist, id); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::regHist(const std::string& id, TH2* hist) { + return regHist_i(hist, id); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::regHist(const std::string& id, TH3* hist) { + return regHist_i(hist, id); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::regTree(const std::string& id) { + TTree *hist = nullptr; + return regHist_i(hist, id); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::regTree(const std::string& id, TTree* hist) { + StatusCode sc = regHist_i(hist, id); + if (hist && sc.isSuccess()) { + if (m_autoSave != 0) hist->SetAutoSave(m_autoSave); + hist->SetAutoFlush(m_autoFlush); + } + return sc; +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::regGraph(const std::string& id) { + TGraph *hist = nullptr; + return regHist_i(hist, id); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::regGraph(const std::string& id, TGraph* hist) { + if ( strcmp(hist->GetName(),"Graph") == 0 ) { + + std::string id2(id); + string::size_type i = id2.rfind("/"); + if (i != string::npos) { + id2.erase(0,i+1); + } + + m_log << MSG::INFO << "setting name of TGraph id: \"" << id << "\" to \"" + << id2 << "\" since it is unset" << endmsg; + hist->SetName(id2.c_str()); + } + + return regHist_i(hist, id); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getHist(const std::string& id, TH1*& hist) const { + return getHist_i(id, hist); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getHist(const std::string& id, TH2*& hist) const { + return getHist_i(id, hist); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getHist(const std::string& id, TH3*& hist) const { + return getHist_i(id, hist); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +std::vector<std::string> +THistSvcHLT::getHists() const { + + std::vector<std::string> names; + names.reserve(m_uids.size()); + transform_if( std::begin(m_uids), std::end(m_uids), + std::back_inserter(names), select1st, + [](uidMap::const_reference i) { + return i.second.obj->IsA()->InheritsFrom("TH11"); } + ); + return names; + +} +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getTree(const std::string& id, TTree*& hist) const { + return getHist_i(id, hist); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +std::vector<std::string> +THistSvcHLT::getTrees() const { + + std::vector<std::string> names; + names.reserve(m_uids.size()); + transform_if( std::begin(m_uids), std::end(m_uids), + std::back_inserter(names), + select1st, + [](uidMap::const_reference i) { + return i.second.obj->IsA()->InheritsFrom("TTree"); } + ); + return names; + +} +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::getGraph(const std::string& id, TGraph*& hist) const { + return getHist_i(id, hist); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +std::vector<std::string> +THistSvcHLT::getGraphs() const { + + std::vector<std::string> names; + names.reserve(m_uids.size()); + transform_if( std::begin(m_uids), std::end(m_uids), + std::back_inserter(names), select1st, + [](uidMap::const_reference i) { + return i.second.obj->IsA()->InheritsFrom("TTree"); } + ); + return names; + +} +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::readHist(const std::string& id, TH1*& hist) const { + return readHist_i(id, hist); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::readHist(const std::string& id, TH2*& hist) const { + return readHist_i(id, hist); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::readHist(const std::string& id, TH3*& hist) const { + return readHist_i(id, hist); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::readTree(const std::string& id, TTree*& hist) const { + return readHist_i(id, hist); +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +bool +THistSvcHLT::findStream(const string& id, string& stream, string& rem, + TFile*& file) const { + + auto pos = id.find("/"); + + if (pos == string::npos) { + stream = "temp"; + rem = id; + } else if (pos != 0) { + stream = "temp"; + rem = id; + } else { + + auto pos2 = id.find("/",pos+1); + + if (pos2 == string::npos) { + m_log << MSG::ERROR << "badly formed Hist/Tree id: \"" << id << "\"" + << endmsg; + return false; + } + + parseString(id,stream,rem); + + } + + if (stream == "temp") { + file = nullptr; + return true; + } + + auto itr = m_files.find(stream); + file = (itr != m_files.end() ? itr->second.first : nullptr ); + if (!file) { + m_log << MSG::WARNING << "no stream \"" << stream + << "\" associated with id: \"" << id << "\"" + << endmsg; + } + + return true; +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +void +THistSvcHLT::parseString(const string& id, string& root, string& rem) const { + auto pos = id.find("/"); + + if (pos == string::npos) { + root.clear(); + rem = id; + } else if (pos == 0) { + parseString(id.substr(1),root,rem); + } else { + root = id.substr(0,pos); + rem = id.substr(pos+1); + } + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +void +THistSvcHLT::setupCompressionLevel( Property& /* cl */ ) +{ + + m_log << MSG::WARNING << "\"CompressionLevel\" Property has been deprecated. " + << "Set it via the \"CL=\" parameter in the \"Output\" Property" + << endmsg; + +} + + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +void +THistSvcHLT::setupInputFile( Property& /*m_inputfile*/ ) +{ + + if (FSMState() < Gaudi::StateMachine::CONFIGURED || !m_okToConnect ) { + + m_log <<MSG::DEBUG << "Delaying connection of Input Files until Initialize" + << ". now in " << FSMState() + << endmsg; + + m_delayConnect = true; + } else { + + m_log <<MSG::DEBUG << "Now connecting of Input Files" + << endmsg; + + StatusCode sc = StatusCode::SUCCESS; + + for ( const auto& itr : m_inputfile.value() ) { + if ( m_alreadyConnectedInFiles.end() != + m_alreadyConnectedInFiles.find( itr ) ) continue; + if ( connect(itr).isFailure() ) { + sc = StatusCode::FAILURE; + } else { + m_alreadyConnectedInFiles.insert( itr ); + } + + } + + if ( !sc.isSuccess() ) { + throw GaudiException( "Problem connecting inputfile !!", name(), + StatusCode::FAILURE ); + } + + } +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +void +THistSvcHLT::setupOutputFile( Property& /*m_outputfile*/ ) +{ + if (FSMState() < Gaudi::StateMachine::CONFIGURED || !m_okToConnect) { + m_log <<MSG::DEBUG << "Delaying connection of Input Files until Initialize" + << ". now in " << FSMState() + << endmsg; + m_delayConnect = true; + } else { + + StatusCode sc = StatusCode::SUCCESS; + for ( const auto & itr : m_outputfile.value() ) { + if ( m_alreadyConnectedOutFiles.end() != + m_alreadyConnectedOutFiles.find( itr ) ) continue; + if ( connect(itr).isFailure() ) { + sc = StatusCode::FAILURE; + } else { + m_alreadyConnectedOutFiles.insert( itr ); + } + } + + if ( !sc.isSuccess() ) { + throw GaudiException( "Problem connecting outputfile !!", name(), + StatusCode::FAILURE ); + } + } +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +void +THistSvcHLT::updateFiles() { + + // If TTrees grow beyond TTree::fgMaxTreeSize, a new file is + // automatically created by root, and the old one closed. We + // need to migrate all the UIDs over to show the correct file + // pointer. This is ugly. + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "updateFiles()" << endmsg; + + + for (auto uitr=m_uids.begin(); uitr != m_uids.end(); ++uitr) { +#ifndef NDEBUG + if (m_log.level() <= MSG::VERBOSE) + m_log << MSG::VERBOSE << " update: " << uitr->first << " " + << uitr->second.id << " " << uitr->second.mode << endmsg; +#endif + TObject* to = uitr->second.obj; + TFile* oldFile = uitr->second.file; + if (!to) { + m_log << MSG::WARNING << uitr->first << ": TObject == 0" << endmsg; + } else if ( uitr->second.temp || uitr->second.mode == READ ) { + // do nothing - no need to check how big the file is since we + // are just reading it. +#ifndef NDEBUG + if (m_log.level() <= MSG::VERBOSE) + m_log << MSG::VERBOSE << " skipping" << endmsg; +#endif + + } else if (to->IsA()->InheritsFrom("TTree")) { + TTree* tr = dynamic_cast<TTree*>(to); + TFile* newFile = tr->GetCurrentFile(); + + if (oldFile != newFile) { + std::string newFileName = newFile->GetName(); + std::string oldFileName, streamName, rem; + TFile* dummy = nullptr; + findStream(uitr->second.id, streamName, rem, dummy); + + for (auto& itr : m_files ) { + if (itr.second.first == oldFile) itr.second.first = newFile; + } + + for (auto uitr2 = uitr; uitr2 != m_uids.end(); ++uitr2) { + if (uitr2->second.file == oldFile) { + uitr2->second.file = newFile; + } + } + + auto sitr = std::find_if( std::begin(m_fileStreams), std::end(m_fileStreams), + [&](streamMap::const_reference s) { + return s.second == streamName; + }); + if (sitr!=std::end(m_fileStreams)) oldFileName = sitr->first; + +#ifndef NDEBUG + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "migrating uid: " << uitr->second.id + << " stream: " << streamName + << " oldFile: " << oldFileName + << " newFile: " << newFileName + << endmsg; +#endif + + + if (!oldFileName.empty()) { + auto i = m_fileStreams.lower_bound(oldFileName); + while (i != std::end(m_fileStreams) && i->first == oldFileName) { + +#ifndef NDEBUG + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "changing filename \"" << i->first + << "\" to \"" << newFileName << "\" for stream \"" + << i->second << "\"" << endmsg; +#endif + std::string nm = std::move(i->second); + i = m_fileStreams.erase(i); + m_fileStreams.emplace( newFileName, std::move(nm) ); + } + + + } else { + m_log << MSG::ERROR + << "Problems updating fileStreams with new file name" << endmsg; + } + + } + } + } +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::write() { + + updateFiles(); + + std::for_each( m_files.begin(), m_files.end(), [](std::pair<const std::string,std::pair<TFile*,Mode>>& i) { + auto mode = i.second.second; + auto file = i.second.first; + if ( mode == WRITE || mode == UPDATE || mode == SHARE ) { + file->Write("",TObject::kOverwrite); + } else if ( mode == APPEND ) { + file->Write(""); + } + } ); + + if (m_log.level() <= MSG::DEBUG) { + m_log << MSG::DEBUG << "THistSvcHLT::write()::List of Files connected in ROOT " + << endmsg; + TSeqCollection *filelist=gROOT->GetListOfFiles(); + for (int ii=0; ii<filelist->GetEntries(); ii++) { + m_log << MSG::DEBUG + << "THistSvcHLT::write()::List of Files connected in ROOT: \"" + << filelist->At(ii)->GetName()<<"\""<<endmsg; + } + } + + return StatusCode::SUCCESS; + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::connect(const std::string& ident) { + + auto loc = ident.find(" "); + string stream = ident.substr(0,loc); + char typ(0); + typedef std::pair<std::string,std::string> Prop; + std::vector<Prop> props; + string filename, db_typ("ROOT"); + int cl(1); + + if (loc != string::npos) { + using Parser = Gaudi::Utils::AttribStringParser; + for (auto attrib: Parser(ident.substr(loc + 1))) { + auto TAG = boost::algorithm::to_upper_copy(attrib.tag); + auto VAL = boost::algorithm::to_upper_copy(attrib.value); + + if (TAG == "FILE" || TAG == "DATAFILE") { + filename = attrib.value; + removeDoubleSlash( filename ); + } else if ( TAG == "OPT" ) { + if ( VAL == "APPEND" || VAL == "UPDATE" ) { + typ = 'A'; + } else if ( VAL == "CREATE" || VAL == "NEW" || VAL == "WRITE" ) { + typ = 'N'; + } else if ( VAL == "RECREATE" ) { + typ = 'R'; + } else if (VAL == "SHARE") { + typ = 'S'; + } else if ( VAL == "OLD" || VAL == "READ" ) { + typ = 'O'; + } else { + m_log << MSG::ERROR << "Unknown OPT: \"" << attrib.value << "\"" + << endmsg; + typ = 0; + } + } else if (TAG == "TYP") { + db_typ = std::move(attrib.value); + } else if (TAG == "CL") { + cl = std::stoi(attrib.value); + } else { + props.emplace_back( attrib.tag, attrib.value); + } + + } + } + + if (stream == "temp") { + m_log << MSG::ERROR << "in JobOption \"" << ident + << "\": stream name \"temp\" reserved." + << endmsg; + return StatusCode::FAILURE; + } + + if (db_typ != "ROOT") { + m_log << MSG::ERROR << "in JobOption \"" << ident + << "\": technology type \"" << db_typ << "\" not supported." + << endmsg; + return StatusCode::FAILURE; + } + + + if (m_files.find(stream) != m_files.end()) { + m_log << MSG::ERROR << "in JobOption \"" << ident + << "\":\n stream \"" << stream << "\" already connected to file: \"" + << m_files[stream].first->GetName() << "\"" + << endmsg; + return StatusCode::FAILURE; + } + + Mode newMode; + if (typ == 'O') { + newMode = THistSvcHLT::READ; + } else if (typ == 'N') { + newMode = THistSvcHLT::WRITE; + } else if (typ == 'A') { + newMode = THistSvcHLT::APPEND; + } else if (typ == 'R') { + newMode = THistSvcHLT::UPDATE; + } else if (typ == 'S') { + newMode = THistSvcHLT::SHARE; + } else { + // something else? + m_log << MSG::ERROR << "No OPT= specified or unknown access mode in: " + << ident << endmsg; + return StatusCode::FAILURE; + } + + // Is this file already connected to another stream? + if (m_fileStreams.find(filename) != m_fileStreams.end()) { + auto fitr = m_fileStreams.equal_range(filename); + + const std::string& oldstream = fitr.first->second; + + const auto& f_info = m_files[oldstream]; + + if (newMode != f_info.second) { + m_log << MSG::ERROR << "in JobOption \"" << ident + << "\":\n file \"" << filename << "\" already opened by stream: \"" + << oldstream << "\" with different access mode." + << endmsg; + return StatusCode::FAILURE; + } else { + TFile *f2 = f_info.first; + m_files[stream] = make_pair(f2,newMode); + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "Connecting stream: \"" << stream + << "\" to previously opened TFile: \"" << filename << "\"" + << endmsg; + return StatusCode::SUCCESS; + } + } + + + IIncidentSvc *pi = nullptr; + if (service("IncidentSvc",pi).isFailure()) { + m_log << MSG::ERROR << "Unable to get the IncidentSvc" << endmsg; + return StatusCode::FAILURE; + } + + void* vf = nullptr; + TFile *f = nullptr; + + if (newMode == THistSvcHLT::READ) { + // old file + + int r = p_fileMgr->open(Io::ROOT,name(), filename,Io::READ,vf,"HIST"); + + if (r != 0) { + m_log << "Unable to open ROOT file " << filename << " for reading" + << endmsg; + return StatusCode::FAILURE; + } + + + f = (TFile*) vf; + + // FIX ME! + pi->fireIncident(FileIncident(name(), "BeginHistFile", filename)); + + + } else if (newMode == THistSvcHLT::WRITE) { + // new file. error if file exists + + int r = p_fileMgr->open(Io::ROOT,name(),filename, (Io::WRITE|Io::CREATE|Io::EXCL), + vf,"HIST"); + + if (r != 0) { + m_log << "Unable to open ROOT file " << filename << " for writing" + << endmsg; + return StatusCode::FAILURE; + } + + f = (TFile*)vf; + + } else if (newMode == THistSvcHLT::APPEND) { + // update file + + int r = p_fileMgr->open(Io::ROOT,name(),filename, (Io::WRITE | Io::APPEND), + vf,"HIST"); + if (r != 0) { + m_log << MSG::ERROR << "unable to open file \"" << filename + << "\" for appending" << endmsg; + return StatusCode::FAILURE; + } + + f = (TFile*) vf; + + + } else if (newMode == THistSvcHLT::SHARE) { + // SHARE file type + //For SHARE files, all data will be stored in a temp file and will be merged into the target file + //in write() when finalize(), this help to solve some confliction. e.g. with storegate + + static int ishared = 0; + string realfilename=filename; + filename = "tmp_THistSvcHLT_"+ std::to_string(ishared++)+".root"; + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "Creating temp file \"" << filename + << "\" and realfilename="<<realfilename << endmsg; + m_sharedFiles[stream]=realfilename; + + + int r = p_fileMgr->open(Io::ROOT,name(), filename, (Io::WRITE|Io::CREATE|Io::EXCL), + vf,"HIST"); + + if (r != 0) { + m_log << "Unable to open ROOT file " << filename << " for writing" + << endmsg; + return StatusCode::FAILURE; + } + + f = (TFile*)vf; + + } else if (newMode == THistSvcHLT::UPDATE) { + // update file + + int r = p_fileMgr->open(Io::ROOT,name(), filename, (Io::WRITE|Io::CREATE), + vf, "HIST"); + + if (r != 0) { + m_log << "Unable to open ROOT file " << filename << " for appending" + << endmsg; + return StatusCode::FAILURE; + } + + f = (TFile*)vf; + + } + + m_files[stream] = make_pair(f,newMode); + m_fileStreams.insert(make_pair(filename,stream)); + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "Opening TFile \"" << filename << "\" stream: \"" + << stream << "\" mode: \"" << typ << "\"" << " comp level: " << cl + << endmsg; + + return StatusCode::SUCCESS; +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +TDirectory* +THistSvcHLT::changeDir(const THistSvcHLT::THistID& hid) const { + + string uid = hid.id; + TFile* file = hid.file; + string stream, fdir, bdir, dir, id; + + if (file) { + file->cd("/"); + } else { + gROOT->cd(); + } + + fdir = uid; + bdir = dirname(fdir); + + while ( (dir = dirname(fdir)) != "") { + if (! gDirectory->GetKey(dir.c_str())) { + gDirectory->mkdir(dir.c_str()); + } + gDirectory->cd(dir.c_str()); + } + + return gDirectory; + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +std::string +THistSvcHLT::dirname(std::string& dir) const { + + + string::size_type i = dir.find("/"); + + if (i == string::npos) return {}; + + if ( i == 0 ) { + dir.erase(0,1); + return dirname(dir); + } + + string root = dir.substr(0,i); + dir.erase(0,i); + + return root; + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +THistSvcHLT::GlobalDirectoryRestore::GlobalDirectoryRestore() { + m_gd = gDirectory; + m_gf = gFile; + m_ge = gErrorIgnoreLevel; +} + +THistSvcHLT::GlobalDirectoryRestore::~GlobalDirectoryRestore() { + gDirectory = m_gd; + gFile = m_gf; + gErrorIgnoreLevel = m_ge; +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +void +THistSvcHLT::removeDoubleSlash(std::string& id) const { + + while (id.find("//") != std::string::npos) { + id.replace(id.find("//"),2,"/"); + } + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +void THistSvcHLT::MergeRootFile(TDirectory *target, TDirectory *source) { + + if (m_log.level() <= MSG::DEBUG) + m_log <<MSG::DEBUG << "Target path: " << target->GetPath() << endmsg; + TString path( (char*)strstr(target->GetPath(), ":") ); + path.Remove( 0, 2); + + source->cd(path); + TDirectory *current_sourcedir = gDirectory; + + // loop over all keys in this directory + TList *lkeys=current_sourcedir->GetListOfKeys(); + int nkeys=lkeys->GetEntries(); + TKey *key; + for (int jj=0; jj<nkeys; jj++) { + key=(TKey*) lkeys->At(jj); + string pathnameinsource=current_sourcedir->GetPath()+string("/")+key->GetName(); + if (m_log.level() <= MSG::DEBUG) + m_log <<MSG::DEBUG << "Reading Key:" << pathnameinsource << endmsg; + //key->Dump(); + //TObject *obj=key->ReadObj(); + TObject *obj=source->Get(pathnameinsource.c_str()); + + if (obj) { + if (obj->IsA()->InheritsFrom("TDirectory") ) { + // it's a subdirectory + + if (m_log.level() <= MSG::DEBUG) + m_log <<MSG::DEBUG << "Found subdirectory " << obj->GetName() + << endmsg; + + // create a new subdir of same name and title in the target file + target->cd(); + TDirectory *newtargetdir = + target->mkdir(obj->GetName(), obj->GetTitle() ); + + MergeRootFile(newtargetdir, source); + + } else if (obj->IsA()->InheritsFrom("TTree")) { + if (m_log.level() <= MSG::DEBUG) + m_log <<MSG::DEBUG << "Found TTree " << obj->GetName() << endmsg; + TTree *mytree=dynamic_cast<TTree*>(obj); + int nentries=(int) mytree->GetEntries(); + mytree->SetBranchStatus("*",1); + + if (m_log.level() <= MSG::DEBUG) + m_log <<MSG::DEBUG << "Dumping TTree " << nentries <<" entries" + << endmsg; + //mytree->Print(); + //for (int ij=0; ij<nentries; ij++) { + //m_log <<MSG::DEBUG << "Dumping TTree Show( " << ij <<" )" + //<< endmsg; + //mytree->Show(ij); + //} + target->cd(); + mytree->CloneTree(); + + //m_log <<MSG::DEBUG << "Writing TTree to target file: ( " + //<< mycopiedtree->Write(key->GetName()) <<" ) bytes written" + //<< endmsg; + + } else { + target->cd(); + obj->Write(key->GetName() ); + } + } + + } // while ( ( TKey *key = (TKey*)nextkey() ) ) + + // save modifications to target file + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +bool +THistSvcHLT::exists( const std::string& name ) const { + + TH1* h; + return getHist_i(name,h,true).isSuccess(); + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +void +THistSvcHLT::handle( const Incident& /* inc */ ) { + + if (signaledStop) return ; + + if (m_maxFileSize.value() == -1) return; + + // convert to bytes. + Long64_t mfs = (Long64_t)m_maxFileSize.value() * (Long64_t)1048576; + Long64_t mfs_warn = mfs * 95 / 100; + + updateFiles(); + + map<string, pair<TFile*,Mode> >::const_iterator itr; + for (const auto& f : m_files) { + TFile* tf = f.second.first; + +#ifndef NDEBUG + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "stream: " << f.first << " name: " + << tf->GetName() << " size: " << tf->GetSize() + << endmsg; +#endif + + // Signal job to terminate if output file is too large + if (tf->GetSize() > mfs) { + + signaledStop = true; + + m_log << MSG::FATAL << "file \"" << tf->GetName() + << "\" associated with stream \"" << f.first + << "\" has exceeded the max file size of " + << m_maxFileSize.value() << "MB. Terminating Job." + << endmsg; + + IEventProcessor* evt = nullptr; + if (service("ApplicationMgr", evt, true).isSuccess()) { + evt->stopRun(); + evt->release(); + } else { + abort(); + } + } else if (tf->GetSize() > mfs_warn) { + m_log << MSG::WARNING << "file \"" << tf->GetName() + << "\" associated with stream \"" << f.first + << "\" is at 95% of its maximum allowable file size of " + << m_maxFileSize.value() << "MB" + << endmsg; + } + } +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +/** helper function to recursively copy the layout of a TFile into a new TFile + */ +void +THistSvcHLT::copyFileLayout (TDirectory *dst, TDirectory *src) { + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG + << "copyFileLayout() to dst path: " << dst->GetPath () << endmsg; + + // strip out URLs + TString path ((char*)strstr (dst->GetPath(), ":")); + path.Remove (0, 2); + + src->cd (path); + TDirectory *cur_src_dir = gDirectory; + + // loop over all keys in this directory + TList *key_list = cur_src_dir->GetListOfKeys (); + int n = key_list->GetEntries (); + for ( int j = 0; j < n; ++j ) { + TKey *k = (TKey*)key_list->At (j); + const std::string src_pathname = cur_src_dir->GetPath() + + std::string("/") + + k->GetName(); + TObject *o=src->Get (src_pathname.c_str()); + + if ( o && o->IsA()->InheritsFrom ("TDirectory")) { + if (m_log.level() <= MSG::VERBOSE) + m_log << MSG::VERBOSE << " subdir [" << o->GetName() << "]..." + << endmsg; + dst->cd (); + TDirectory * dst_dir = dst->mkdir (o->GetName(), o->GetTitle()); + copyFileLayout (dst_dir, src); + } + } // loop over keys + return; +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// +/** @brief callback method to reinitialize the internal state of + * the component for I/O purposes (e.g. upon @c fork(2)) + */ +StatusCode +THistSvcHLT::io_reinit () +{ + bool all_good = true; + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "reinitializing I/O..." << endmsg; + + // retrieve the I/O component manager... + + IIoComponentMgr* iomgr = nullptr; + + if (service("IoComponentMgr", iomgr, true).isFailure()) { + m_log << MSG::ERROR << "could not retrieve I/O component manager !" + << endmsg; + return StatusCode::FAILURE; + } + + GlobalDirectoryRestore restore; + // to hide the expected errors upon closing the files whose + // file descriptors have been swept under the rug... + gErrorIgnoreLevel = kFatal; + + typedef std::map<std::string, std::pair<TFile*,Mode> > FileReg_t; + + for (auto & ifile : m_files ) { + TFile *f = ifile.second.first; + std::string fname = f->GetName(); + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "file [" << fname << "] mode: [" + << f->GetOption() << "] r:" + << f->GetFileBytesRead() + << " w:" << f->GetFileBytesWritten() + << " cnt:" << f->GetFileCounter() + << endmsg; + + if ( ifile.second.second == READ ) { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG + << " TFile opened in READ mode: not reassigning names" << endmsg; + continue; + } + + if ( !iomgr->io_retrieve (this, fname).isSuccess () ) { + m_log << MSG::ERROR << "could not retrieve new name for [" << fname + << "] !!" << endmsg; + all_good = false; + continue; + } else { + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "got a new name [" << fname << "]..." << endmsg; + } + // create a new TFile + // TFile *newfile = TFile::Open (fname.c_str(), f->GetOption()); + + void* vf; + Option_t *opts = f->GetOption(); + int r = p_fileMgr->open(Io::ROOT,name(),fname,Io::WRITE,vf,"HIST"); + if (r != 0) { + m_log << MSG::ERROR << "unable to open file \"" << fname + << "\" for writing" << endmsg; + return StatusCode::FAILURE; + } + TFile *newfile = (TFile*) vf; + newfile->SetOption(opts); + + + if (ifile.second.second != THistSvcHLT::READ) { + copyFileLayout (newfile, f); + ifile.second.first = newfile; + } + + // loop over all uids and migrate them to the new file + // XXX FIXME: this double loop sucks... + for ( auto& uid : m_uids ) { + THistID& hid = uid.second; + if ( hid.file != f ) continue; + TDirectory *olddir = this->changeDir (hid); + hid.file = newfile; + // side-effect: create needed directories... + TDirectory *newdir = this->changeDir (hid); + TClass *cl = hid.obj->IsA(); + + // migrate the objects to the new file. + // thanks to the object model of ROOT, it is super easy. + if (cl->InheritsFrom ("TTree")) { + dynamic_cast<TTree*> (hid.obj)->SetDirectory (newdir); + dynamic_cast<TTree*> (hid.obj)->Reset(); + } + else if (cl->InheritsFrom ("TH1")) { + dynamic_cast<TH1*> (hid.obj)->SetDirectory (newdir); + dynamic_cast<TH1*> (hid.obj)->Reset(); + } + else if (cl->InheritsFrom ("TGraph")) { + olddir->Remove (hid.obj); + newdir->Append (hid.obj); + } else { + m_log << MSG::ERROR + << "id: \"" << hid.id << "\" is not a inheriting from a class " + << "we know how to handle (received [" << cl->GetName() + << "], " << "expected [TTree, TH1 or TGraph]) !" + << endmsg + << "attaching to current dir [" << newdir->GetPath() << "] " + << "nonetheless..." << endmsg; + olddir->Remove (hid.obj); + newdir->Append (hid.obj); + } + } + f->ReOpen ("READ"); + p_fileMgr->close(f,name()); + f = newfile; + } + + return all_good ? StatusCode::SUCCESS : StatusCode::FAILURE; +} + + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::rootOpenAction( const Io::FileAttr* fa, const std::string& caller) { + + if (fa->tech() != Io::ROOT) { + // This should never happen + return StatusCode::SUCCESS; + } + + if (fa->desc() != "HIST") { + return StatusCode::SUCCESS; + } + + p_incSvc->fireIncident(FileIncident(caller, "OpenHistFile", fa->name())); + + if ( fa->flags().isRead() ) { + p_incSvc->fireIncident(FileIncident(caller, "BeginHistFile", fa->name())); + } else if ( fa->flags().isWrite() ) { + p_incSvc->fireIncident(FileIncident(caller, IncidentType::BeginOutputFile, + fa->name())); + } else { + // for Io::RW + p_incSvc->fireIncident(FileIncident(caller, IncidentType::BeginOutputFile, + fa->name())); + } + + return StatusCode::SUCCESS; + + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +StatusCode +THistSvcHLT::rootOpenErrAction( const Io::FileAttr* fa, const std::string& caller) { + + if (fa->tech() != Io::ROOT) { + // This should never happen + return StatusCode::SUCCESS; + } + + if (fa->desc() != "HIST") { + return StatusCode::SUCCESS; + } + + if ( fa->flags().isRead() ) { + p_incSvc->fireIncident(FileIncident(caller, IncidentType::FailInputFile, + fa->name())); + } else if ( fa->flags().isWrite() ) { + p_incSvc->fireIncident(FileIncident(caller, IncidentType::FailOutputFile, + fa->name())); + } else { + // for Io::RW + p_incSvc->fireIncident(FileIncident(caller, "FailRWFile", fa->name())); + } + + return StatusCode::SUCCESS; +} diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h new file mode 100644 index 00000000000..cec1ef7d50e --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h @@ -0,0 +1,230 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef THISTSVCHLT_H +#define THISTSVCHLT_H + +#include "GaudiKernel/Service.h" +#include "GaudiKernel/ITHistSvc.h" +#include "GaudiKernel/IFileMgr.h" +#include "GaudiKernel/IIncidentListener.h" +#include "GaudiKernel/IIoComponent.h" +#include "GaudiKernel/MsgStream.h" + +#include "TObject.h" +#include "TH1.h" +#include "TH2.h" +#include "TH3.h" +#include "TTree.h" +#include "TGraph.h" +#include "TList.h" + + +#include <vector> +#include <string> +#include <set> +#include <map> + +class IIncidentSvc; +class THistSvcHLT: public extends3<Service, ITHistSvc, IIncidentListener, + IIoComponent> { + +public: + + StatusCode initialize() override; + StatusCode reinitialize() override; + StatusCode finalize() override; + + StatusCode regHist(const std::string& name) override; + StatusCode regHist(const std::string& name, TH1*) override; + StatusCode regHist(const std::string& name, TH2*) override; + StatusCode regHist(const std::string& name, TH3*) override; + + StatusCode getHist(const std::string& name, TH1*&) const override; + StatusCode getHist(const std::string& name, TH2*&) const override; + StatusCode getHist(const std::string& name, TH3*&) const override; + + StatusCode regTree(const std::string& name) override; + StatusCode regTree(const std::string& name, TTree*) override; + StatusCode getTree(const std::string& name, TTree*&) const override; + + StatusCode regGraph(const std::string& name) override; + StatusCode regGraph(const std::string& name, TGraph*) override; + StatusCode getGraph(const std::string& name, TGraph*&) const override; + + StatusCode deReg(TObject* obj) override; + StatusCode deReg(const std::string& name) override; + + std::vector<std::string> getHists() const override; + std::vector<std::string> getTrees() const override; + std::vector<std::string> getGraphs() const override; + + StatusCode getTHists(TDirectory *td, TList &, + bool recurse=false) const override; + StatusCode getTHists(const std::string& name, TList &, + bool recurse=false) const override; + + StatusCode getTHists(TDirectory *td, TList &tl, + bool recurse=false, bool reg=false) override; + StatusCode getTHists(const std::string& name, TList &tl, + bool recurse=false, bool reg=false) override; + + StatusCode getTTrees(TDirectory *td, TList &, + bool recurse=false) const override; + StatusCode getTTrees(const std::string& name, TList &, + bool recurse=false) const override; + + StatusCode getTTrees(TDirectory *td, TList & tl, + bool recurse=false, bool reg=false) override; + StatusCode getTTrees(const std::string& name, TList & tl, + bool recurse=false, bool reg=false) override; + + bool exists(const std::string& name) const override; + + THistSvcHLT(const std::string& name, ISvcLocator *svc ); + + void handle(const Incident&) override; + + // From IIoComponent + StatusCode io_reinit () override; + + +protected: + + ~THistSvcHLT() override = default; + +private: + + class GlobalDirectoryRestore { + public: + GlobalDirectoryRestore(); + ~GlobalDirectoryRestore(); + private: + TDirectory* m_gd; + TFile* m_gf; + int m_ge; + }; + + enum Mode { + READ, + WRITE, + UPDATE, + APPEND, + SHARE, + INVALID + }; + + struct THistID { + std::string id; + bool temp; + TObject* obj; + TFile* file; + Mode mode; + + THistID():id(""),temp(true),obj(0),file(0),mode(INVALID) {} + THistID(const THistID& rhs):id(rhs.id), temp(rhs.temp), + obj(rhs.obj), file(rhs.file), mode(rhs.mode) {} + THistID(std::string& i, bool& t, TObject* o, TFile* f) + : id(i), temp(t), obj(o), file(f), mode(INVALID){ + } + THistID(std::string& i, bool& t, TObject* o, TFile* f, Mode m) + : id(i), temp(t), obj(o), file(f), mode(m){ + } + + bool operator < (THistID const &rhs) const { + return (obj < rhs.obj); + } + }; + + + template <typename T> + StatusCode regHist_i(T* hist, const std::string& name); + template <typename T> + StatusCode getHist_i(const std::string& name, T*& hist, bool quiet=false) const; + template <typename T> + StatusCode readHist_i(const std::string& name, T*& hist) const; + + + StatusCode readHist(const std::string& name, TH1*&) const; + StatusCode readHist(const std::string& name, TH2*&) const; + StatusCode readHist(const std::string& name, TH3*&) const; + StatusCode readTree(const std::string& name, TTree*&) const; + + void updateFiles(); + StatusCode write(); + StatusCode connect(const std::string&); + TDirectory* changeDir(const THistSvcHLT::THistID& hid) const; + std::string dirname(std::string& dir) const; + void removeDoubleSlash(std::string&) const; + + bool browseTDir(TDirectory* dir) const; + + bool findStream(const std::string& name, std::string& root, + std::string& rem, TFile*& file) const; + void parseString(const std::string& id, std::string& root, std::string& rem) + const; + + /// call-back method to handle input stream property + void setupInputFile( Property& inputfile ); + + /// call-back method to handle output stream property + void setupOutputFile( Property& outputfile ); + + void setupCompressionLevel( Property& cmp ); + + void copyFileLayout(TDirectory*, TDirectory*); + + void MergeRootFile( TDirectory *target, TDirectory *source); + + //////// + + mutable MsgStream m_log; + + StringArrayProperty m_inputfile, m_outputfile; + std::vector<std::string> m_Rstream, m_Wstream; + IntegerProperty m_autoSave, m_autoFlush, m_compressionLevel, m_maxFileSize; + BooleanProperty m_print; + + /// list of already connected files. This is to keep track of files + /// registered by the setupInputFile callback method + std::set<std::string> m_alreadyConnectedInFiles; + + /// list of already connected files. This is to keep track of files + /// registered by the setupOutputFile callback method + std::set<std::string> m_alreadyConnectedOutFiles; + + + typedef std::map<std::string, THistID> uidMap; + typedef std::multimap<std::string, THistID> idMap; + typedef std::map<TObject*, THistID> objMap; + typedef std::multimap<std::string, std::string> streamMap; + + uidMap m_uids; + idMap m_ids; + objMap m_tobjs; + + std::map<std::string, std::pair<TFile*,Mode> > m_files; // stream->file + streamMap m_fileStreams; // fileName->streams + + std::map<std::string, std::string > m_sharedFiles; // stream->filename of shared files + + bool signaledStop = false; + bool m_delayConnect = false, m_okToConnect = false; + + mutable std::string m_curstream; + + IIncidentSvc* p_incSvc = nullptr; + IFileMgr* p_fileMgr = nullptr; + + StatusCode rootOpenAction( FILEMGR_CALLBACK_ARGS ); + StatusCode rootOpenErrAction( FILEMGR_CALLBACK_ARGS ); + +}; + +#ifndef THISTSVCHLT_ICC + #include "THistSvcHLT.icc" +#endif + + +#endif diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc new file mode 100644 index 00000000000..45c635ac545 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc @@ -0,0 +1,311 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef THISTSVCHLT_ICC +#define THISTSVCHLT_ICC + +#ifndef GAUDIKERNEL_MSGSTREAM_H + #include "GaudiKernel/MsgStream.h" +#endif + +#include "GaudiKernel/System.h" + +#include <string> +#include <map> + +#include "TObject.h" +#include "TFile.h" + +template <typename T> +StatusCode THistSvcHLT::regHist_i(T* hist, const std::string& id) { + + GlobalDirectoryRestore restore; + + std::string idr(id); + removeDoubleSlash( idr ); + + if (idr.find("/") == idr.length()) { + m_log << MSG::ERROR << "Badly formed identifier \"" << idr << "\": " + << "Must not end with a /" << endmsg; + return StatusCode::FAILURE; + } + + + TFile *f = nullptr; + std::string stream,rem; + if (!findStream(idr, stream, rem, f)) { + m_log << MSG::ERROR << "Could not register id: \"" << idr << "\"" + << endmsg; + return StatusCode::FAILURE; + } + + std::string uid = "/" + stream + "/" + rem; + auto itr = m_uids.find(uid); + if (itr != m_uids.end()) { + m_log << MSG::ERROR << "already registered an object with identifier \"" + << idr << "\"" << endmsg; + return StatusCode::FAILURE; + } + + + bool temp = false; + if ( !f ) { + temp = true; + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "Historgram with id \"" << idr << "\" is temporary" + << endmsg; + } + + + TObject *to = nullptr; + THistID hid; + + // check to see if this hist is to be read in; + if (!temp && m_files.find(stream)->second.second == READ) { + + if (hist != 0) { + m_log << MSG::WARNING << "Registering id: \"" << idr + << "\" with non zero pointer!" << endmsg; + } + + if (readHist_i(idr,hist).isFailure()) { + m_log << MSG::ERROR << "Unable to read in hist" << endmsg; + return StatusCode::FAILURE; + } + to = dynamic_cast<TObject*>(hist); + hid = THistID(uid,temp,to,f,m_files.find(stream)->second.second); + + } else if (hist == 0) { + m_log << MSG::ERROR << "Unable to read in hist with id: \"" + << idr << "\"" << endmsg; + return StatusCode::FAILURE; + + } else { + + to = dynamic_cast<TObject*>(hist); + if (to == 0) { + m_log << MSG::ERROR << "Could not dcast to TObject. id: \"" << idr + << "\"" << endmsg; + return StatusCode::FAILURE; + } + + auto oitr = m_tobjs.find(to); + if (oitr != m_tobjs.end()) { + m_log << MSG::ERROR << "already registered id: \"" << idr + << "\" with identifier \"" << oitr->second.id << "\"" << endmsg; + return StatusCode::FAILURE; + } + + hid = THistID(uid,temp,to,f,m_files.find(stream)->second.second); + TDirectory* dir = changeDir(hid); + + if ( dynamic_cast<TTree*>(hist) ) { + dynamic_cast<TTree*>(hist)->SetDirectory(dir); + } else if ( dynamic_cast<TH1*>(hist) ) { + dynamic_cast<TH1*>(hist)->SetDirectory(dir); + } else if ( dynamic_cast<TGraph*>(hist) ) { + dir->Append(hist); + } else { + m_log << MSG::ERROR << "id: \"" << idr + << "\" is not a TH, TTree, or TGraph. Attaching it to current dir." + << endmsg; + dir->Append(hist); + } + + } + + std::string fname; + if ( !f ) { + fname = "none"; + } else { + fname = f->GetName(); + } + + if (m_log.level() <= MSG::DEBUG) + m_log << MSG::DEBUG << "Registering " << System::typeinfoName(typeid(*hist)) + << " title: \"" << hist->GetTitle() + << "\" id: \"" << uid << "\" dir: " + // << hist->GetDirectory()->GetPath() << " " + << changeDir(hid)->GetPath() + << " file: " << fname + << endmsg; + + m_ids.emplace(rem, hid); + m_uids[uid] = hid; + m_tobjs[to] = hid; + + return StatusCode::SUCCESS; + +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +template <typename T> +StatusCode +THistSvcHLT::getHist_i(const std::string& id, T*& hist, bool quiet) const { + // id starts with "/": unique + + GlobalDirectoryRestore restore; + + std::string idr(id); + removeDoubleSlash( idr ); + + if (idr.find("/") == 0) { + auto itr = m_uids.find(id); + if (itr == m_uids.end()) { + if (!quiet) { + m_log << MSG::ERROR << "Could not locate Hist with id \"" << idr << "\"" + << endmsg; + } + hist = nullptr; + return StatusCode::FAILURE; + } + + THistID hid = itr->second; + if (!quiet) { + hist = dynamic_cast<T*>(hid.obj); + if ( !hist ) { + m_log << MSG::ERROR << "dcast failed, Hist id: \"" << idr << "\"" + << endmsg; + return StatusCode::FAILURE; + } + if (m_log.level() <= MSG::VERBOSE) { + m_log << MSG::VERBOSE << "found unique Hist title: \"" + << hist->GetTitle() + << "\" id: \"" << idr << "\"" << endmsg; + } + } else { + if (m_log.level() <= MSG::VERBOSE) { + m_log << MSG::VERBOSE << "found unique Hist id: \"" << idr + << "\" type: \"" << hid.obj->IsA()->GetName() << "\"" + << endmsg; + } + } + + return StatusCode::SUCCESS; + + + // not necessarily unique + } else { + + auto mitr = m_ids.equal_range(idr); + + + if (mitr.first == mitr.second) { + m_log << MSG::ERROR << "Could not locate Hist with id \"" << idr << "\"" + << endmsg; + hist = nullptr; + return StatusCode::FAILURE; + } else { + + if (distance(mitr.first,mitr.second) == 1) { + THistID hid = mitr.first->second; + if (!quiet) { + hist = dynamic_cast<T*>(hid.obj); + if (hist == 0) { + m_log << MSG::ERROR << "dcast failed" << endmsg; + return StatusCode::FAILURE; + } + if (m_log.level() <= MSG::VERBOSE) { + m_log << MSG::VERBOSE << "found Hist title: \"" << hist->GetTitle() + << "\" id: \"" << idr << "\"" << endmsg; + } + } else { + if (m_log.level() <= MSG::VERBOSE) { + m_log << MSG::VERBOSE << "found Hist id: \"" << idr << "\" type: \"" + << hid.obj->IsA()->GetName() << "\"" + << endmsg; + } + } + return StatusCode::SUCCESS; + } else { + if (!quiet) { + // return failure if trying to GET a single hist + m_log << MSG::ERROR << "Multiple matches with id \"" << idr << "\"." + << " Further specifications required." + << endmsg; + hist = nullptr; + return StatusCode::FAILURE; + } else { + // return a SUCCESS if just INQUIRING + m_log << MSG::INFO << "Found multiple matches with id \"" << idr + << "\"" << endmsg; + hist = nullptr; + return StatusCode::SUCCESS; + } + } + } + } +} + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *// + +template <typename T> +StatusCode +THistSvcHLT::readHist_i(const std::string& id, T*& hist) const { + + GlobalDirectoryRestore restore; + + std::string idr(id); + removeDoubleSlash( idr ); + + std::string stream, rem, dir, fdir, bdir, fdir2; + TFile *file; + + if (!findStream(idr, stream, rem, file) ) { + return StatusCode::FAILURE; + } + + if ( !file ) { + m_log << MSG::ERROR << "no associated file found" << endmsg; + return StatusCode::FAILURE; + } + + file->cd("/"); + + fdir = idr; + bdir = dirname(fdir); + fdir2 = fdir; + while ( (dir=dirname(fdir)) != "" ) { + if (! gDirectory->GetKey(dir.c_str())) { + m_log << MSG::ERROR << "Directory \"" << fdir2 << "\" doesnt exist in " + << file->GetName() << endmsg; + return StatusCode::FAILURE; + } + gDirectory->cd(dir.c_str()); + } + + TObject *to=nullptr; + gDirectory->GetObject(fdir.c_str(), to); + + if ( !to ) { + m_log << MSG::ERROR << "Could not get obj \"" << fdir << "\" in " + << gDirectory->GetPath() << endmsg; + return StatusCode::FAILURE; + } + + + + hist = dynamic_cast<T*>(to); + if ( !hist ) { + m_log << MSG::ERROR << "Could not convert \"" << idr << "\" to a " + << System::typeinfoName(typeid(*hist)) << " as is a " + << to->IsA()->GetName() + << endmsg; + return StatusCode::FAILURE; + } + + + if (m_log.level() <= MSG::DEBUG) { + m_log << MSG::DEBUG << "Read in " << hist->IsA()->GetName() << " \"" + << hist->GetName() << "\" from file " + << file->GetName() << endmsg; + hist->Print(); + } + + return StatusCode::SUCCESS; + +} + +#endif diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.cxx new file mode 100644 index 00000000000..9d632e7cd02 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.cxx @@ -0,0 +1,404 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file TrigCOOLUpdateHelper.h + * @brief Helper tool for COOL updates + * @author Frank Winklmeier + * + * $Id: TrigCOOLUpdateHelper.cxx 666321 2015-05-11 17:32:34Z fwinkl $ + */ + +#include "TrigCOOLUpdateHelper.h" + +#include "TrigServices/TrigHLTIssues.h" + +#include "GaudiKernel/INamedInterface.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/ITHistSvc.h" + +#include "AthenaKernel/errorcheck.h" +#include "AthenaKernel/IIOVDbSvc.h" +#include "AthenaKernel/IIOVSvc.h" +#include "AthenaKernel/IOVTime.h" +#include "AthenaKernel/IOVRange.h" +#include "EventInfo/EventIncident.h" +#include "EventInfo/EventInfo.h" +#include "EventInfo/EventType.h" +#include "AthenaPoolUtilities/CondAttrListCollection.h" + +#include "CoralBase/AttributeListException.h" + +#include "TH1F.h" + +#include <boost/foreach.hpp> +#include <boost/algorithm/string.hpp> + +using namespace std; + + +//========================================================================= +// Standard methods +//========================================================================= +TrigCOOLUpdateHelper::TrigCOOLUpdateHelper(const std::string &type, + const std::string &name, + const IInterface *parent) + : AthAlgTool(type, name, parent), + m_iovSvc(0), + m_iovDbSvc(0), + m_incidentSvc("IncidentSvc", name), + m_hist_timeCondUpdate(0) +{ + // No abstract interface + declareInterface<TrigCOOLUpdateHelper>(this); + + declareProperty("coolFolder", m_coolFolderName = "", "Name of COOL folder containing folder map"); + declareProperty("foldersToResetOnBeginRun", m_beginRunFolders, "COOL folders to reset at beginning of run"); +} + + +TrigCOOLUpdateHelper::~TrigCOOLUpdateHelper() +{} + + +StatusCode TrigCOOLUpdateHelper::initialize() +{ + // Do not create these services if they are not available already + service("IOVSvc", m_iovSvc, /*createIf=*/false).ignore(); + service("IOVDbSvc", m_iovDbSvc, /*createIf=*/false).ignore(); + + CHECK( m_incidentSvc.retrieve() ); + + ATH_MSG_INFO(" ---> foldersToResetOnBeginRun = [" + << boost::algorithm::join(m_beginRunFolders, ",") << "]"); + + // Register DataHandle with COOLUPDATE folder + if (!m_coolFolderName.empty()) { + CHECK( detStore()->regHandle(m_folderMapHandle, m_coolFolderName) ); + } + + // Register incident listener + m_incidentSvc->addListener(this, "EndOfBeginRun"); + + return StatusCode::SUCCESS; +} + + +StatusCode TrigCOOLUpdateHelper::start() +{ + m_folderInfo.clear(); + + // Book histograms + ServiceHandle<ITHistSvc> histSvc("THistSvc",name()); + if ( histSvc.retrieve().isFailure() ) { + ATH_MSG_ERROR("Histogram service can not be retrieved"); + return StatusCode::FAILURE; + } + + m_hist_timeCondUpdate = new TH1F("CoolFolderUpdateTime", + "Time for conditions update;time [ms]", + 100, 0, 200); + + // monitoring information root directory + string histPath = string("/EXPERT/"); + + const INamedInterface* p_parent = dynamic_cast<const INamedInterface*>(parent()); + if (p_parent != 0) { + histPath = histPath + p_parent->name() + string("/"); + } else { + histPath = histPath + name() + string("/"); + } + if ( (histSvc->regHist(histPath + m_hist_timeCondUpdate->GetName(), m_hist_timeCondUpdate)).isFailure() ) { + ATH_MSG_ERROR("Registration of histogram '" << (histPath + m_hist_timeCondUpdate->GetName()) << "' failed."); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +StatusCode TrigCOOLUpdateHelper::stop() +{ + std::ostringstream pending; + // Loop over folder updates + for (auto f : m_folderUpdates) { + if (f.second.needsUpdate) pending << "[" << f.second.lumiBlock << "," << f.second.folderIndex << "]"; + } + + if (pending.str().empty()) pending << "NONE"; + ATH_MSG_INFO("[LB,Folder] with pending COOL updates: " << pending.str()); + + return StatusCode::SUCCESS; +} + +void TrigCOOLUpdateHelper::handle(const Incident&) +{ + m_folderUpdates.clear(); + + // Triggered on EndOfBeginRun, i.e. when all folders are available + readFolderInfo(); + if (m_coolFolderName.empty()) return; + + if (!m_folderMapHandle.isInitialized()) { + ATH_MSG_ERROR("DataHandle for '" << m_coolFolderName << "' not initialized."); + } + else { + ATH_MSG_INFO("COOL folder map in " << m_coolFolderName << ":"); + for (CondAttrListCollection::const_iterator c = m_folderMapHandle->begin(); + c != m_folderMapHandle->end(); ++c) { + ATH_MSG_INFO(" (" << c->first << ") " << c->second["FolderName"].data<string>()); + } + } +} + + +//========================================================================= +// Read COOL folder info +// Loop over all registered keys and get folder name and CLID +//========================================================================= +void TrigCOOLUpdateHelper::readFolderInfo() +{ + if (m_iovDbSvc==0) return; + + // Loop over all keys registered with IOVDbSvc + vector<string> keyList(m_iovDbSvc->getKeyList()); + BOOST_FOREACH(string key, keyList) { + string foldername, tag; + IOVRange range; + bool retrieved; + unsigned long long bytesRead; + float readTime; + + // Get folder name and CLID for each key + bool found = m_iovDbSvc->getKeyInfo(key, foldername, tag, range, + retrieved, bytesRead, readTime); + + if ( !found || m_folderInfo.find(foldername)!=m_folderInfo.end() ) + continue; + + CLID clid = detStore()->clid(key); + if (clid!=CLID_NULL) + m_folderInfo.insert(FolderInfoMap::value_type(foldername,FolderInfo(clid, key))); + else + ATH_MSG_ERROR("Cannot find CLID for " << key); + } +} + + +//========================================================================= +// Reset COOL folders +//========================================================================= +StatusCode TrigCOOLUpdateHelper::resetBeginRunFolders(EventID::number_type currentRun) +{ + readFolderInfo(); // Folders might be only partially avaiable + return resetFolders(m_beginRunFolders, currentRun, false); +} + +StatusCode TrigCOOLUpdateHelper::resetFolders(const std::vector<std::string>& folders, + EventID::number_type currentRun, + bool dropObject) +{ + if (folders.empty()) return StatusCode::SUCCESS; + + StatusCode sc(StatusCode::SUCCESS); + BOOST_FOREACH(string folder, folders) { + if ( resetFolder(folder, currentRun, dropObject).isFailure() ) sc = StatusCode::FAILURE; + } + return sc; +} + +StatusCode TrigCOOLUpdateHelper::resetFolder(const std::string& folder, + EventID::number_type currentRun, + bool dropObject) +{ + // Force a reset of folders by setting an IOVRange in the past + + if (m_iovSvc==0 || m_iovDbSvc==0) return StatusCode::SUCCESS; + + // Set IOV in the past to trigger reload in IOVSvc + IOVRange iov_range(IOVTime(currentRun-2, 0), + IOVTime(currentRun-1, 0)); + + FolderInfoMap::const_iterator f = m_folderInfo.find(folder); + if ( f==m_folderInfo.end() ) { + ATH_MSG_DEBUG("Folder " << folder << " not registered with IOVDbSvc"); + return StatusCode::SUCCESS; + } + + const CLID& clid = f->second.clid; + const string& key = f->second.key; + // Check if proxy exists + if ( detStore()->proxy(clid, key)==0 ) { + ATH_MSG_DEBUG("No proxy for " << key << " found"); + return StatusCode::SUCCESS; // on purpose not a failure + } + + // Make sure we are not trying to reset a time-based folder + IOVRange iov; + if ( m_iovSvc->getRange(clid, key, iov).isSuccess() ) { + if ( iov.start().isTimestamp() || iov.start().isBoth() ) { + ATH_MSG_ERROR(folder << " is not a Run/LB based folder. Cannot perform COOL update."); + return StatusCode::FAILURE; + } + } + + // Invalidate IOV range + ATH_MSG_DEBUG("Setting IOV range of " << folder << " to " << iov_range); + + if ((m_iovSvc->setRange(clid, key, iov_range, "StoreGateSvc")).isFailure()) { + ATH_MSG_WARNING("Could not set IOV range for " << folder << " to " << iov_range); + return StatusCode::FAILURE; + } + + // Drop object and reset cache + if (dropObject) { + if (not m_iovDbSvc->dropObject(key, /*resetCache=*/true)) { + ATH_MSG_WARNING("IOVDbSvc could not drop " << folder); + return StatusCode::FAILURE; + } + } + + // All OK + ATH_MSG_INFO("Invalidated IOV" << (dropObject ? " and dropped payload " : " ") + << "of folder " << folder << (key!=folder ? " (key="+key+")" : "") ); + + return StatusCode::SUCCESS; +} + + +//========================================================================= +// Folder update during the run +//========================================================================= + +StatusCode TrigCOOLUpdateHelper::hltCoolUpdate(EventID::number_type currentLB, + EventID::number_type currentRun, + EventID::number_type sor_time_sec, + EventID::number_type sor_time_nsec) +{ + bool checkIOV_done = false; + + // Loop over folders to be updated + std::map<CTPfragment::FolderIndex, FolderUpdate>::iterator f = m_folderUpdates.begin(); + for (; f!=m_folderUpdates.end(); ++f) { + + if (f->second.needsUpdate) { + string folderName; + if (getFolderName(f->second.folderIndex, folderName).isFailure()) { + continue; // On purpose not a failure + } + + const EventInfo* currentEvent(0); + CHECK(evtStore()->retrieve(currentEvent)); + ATH_MSG_INFO("Reload of COOL folder " << folderName << " for IOV change in lumiblock " << f->second.lumiBlock + << ". Current event: " << *currentEvent->event_ID()); + + if ( hltCoolUpdate(folderName, currentLB, currentRun, + sor_time_sec, sor_time_nsec).isFailure() ) { + ATH_MSG_FATAL("COOL update failed for " << folderName << ". Aborting."); + throw ers::HLTAbort(ERS_HERE, name()+": Failure during COOL update of "+folderName); + } + // All OK + checkIOV_done = true; + f->second.needsUpdate = false; + } + } + + // Needs to be done on every LB change + if (!checkIOV_done) checkIOV(currentLB, currentRun, sor_time_sec, sor_time_nsec); + + return StatusCode::SUCCESS; +} + + +StatusCode TrigCOOLUpdateHelper::hltCoolUpdate(const std::string& folderName, + EventID::number_type currentLB, + EventID::number_type currentRun, + EventID::number_type sor_time_sec, + EventID::number_type sor_time_nsec) +{ + if ( m_iovSvc==0 || m_coolFolderName.empty() ) { + ATH_MSG_DEBUG("Passive mode. Not updating COOL folders"); + return StatusCode::SUCCESS; + } + + // Start timer + longlong t1_ms = System::currentTime(System::milliSec); + + // Reset folder and make IOVDbSvc drop objects + + if (resetFolder(folderName, currentRun, true).isFailure()) { + ATH_MSG_ERROR("Reset of " << folderName << " failed"); + return StatusCode::FAILURE; + } + + checkIOV(currentLB, currentRun, sor_time_sec, sor_time_nsec); + + // Stop timer and fill histogram + longlong t2_ms = System::currentTime(System::milliSec); + if (m_hist_timeCondUpdate) m_hist_timeCondUpdate->Fill(t2_ms-t1_ms); + + return StatusCode::SUCCESS; +} + +void TrigCOOLUpdateHelper::checkIOV(EventID::number_type currentLB, + EventID::number_type currentRun, + EventID::number_type sor_time_sec, + EventID::number_type sor_time_nsec) +{ + // Force IOVSvc to check IOV ranges + EventInfo eventInfo(new EventID(currentRun, /*event*/ 0, + sor_time_sec, sor_time_nsec, + currentLB, /*bcid*/ 0), + new EventType()); + + EventIncident incident(eventInfo, name(), "CheckIOV"); + m_incidentSvc->fireIncident(incident); +} + + +StatusCode TrigCOOLUpdateHelper::getFolderName(CTPfragment::FolderIndex idx, std::string& folderName) +{ + if (m_coolFolderName.empty()) return StatusCode::SUCCESS; + + if (!m_folderMapHandle.isInitialized()) { + ATH_MSG_ERROR("DataHandle for '" << m_coolFolderName << "' not initialized."); + return StatusCode::FAILURE; + } + try { + folderName = m_folderMapHandle->attributeList(idx)["FolderName"].data<string>(); + } + catch (coral::AttributeListException &) { + ATH_MSG_ERROR(m_coolFolderName << " does not contain a folder for index/channel " << idx + << ". Existing folders are:"); + m_folderMapHandle->dump(); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; +} + + +//========================================================================= +// Schedule COOL folder updates (called on every event by EventLoopMgr) +//========================================================================= +void TrigCOOLUpdateHelper::setFolderUpdates(const std::map<CTPfragment::FolderIndex, CTPfragment::FolderEntry>& folderUpdates) +{ + // Loop over potential new folder updates + std::map<CTPfragment::FolderIndex, CTPfragment::FolderEntry>::const_iterator i = folderUpdates.begin(); + for (; i!=folderUpdates.end(); ++i) { + + // Check if we already have an update for this folder + std::map<CTPfragment::FolderIndex, FolderUpdate>::const_iterator f = m_folderUpdates.find(i->first); + + // No updates yet or this update superseds the previous one + if (f==m_folderUpdates.end() || (f->second.lumiBlock != i->second.lumiBlock)) { + m_folderUpdates[i->first] = FolderUpdate(i->second); // new folder update + + ATH_MSG_DEBUG("Conditions update for folder " << i->second.folderIndex + << " on lumiblock " << i->second.lumiBlock); + } + /* The above could be optmized by handling events from a previous lumiblock in a special way + and not forcing a COOL update. However, this would complicate the code and in the merged HLT + system events from already seen LBs will be very rare (or even impossible). + */ + } +} diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.h new file mode 100644 index 00000000000..cd47aa31dd3 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.h @@ -0,0 +1,191 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGSERVICES_TRIGCOOLUPDATEHELPER_H +#define TRIGSERVICES_TRIGCOOLUPDATEHELPER_H +/** + * @file TrigCOOLUpdateHelper.h + * @brief Helper tool for COOL updates + * @author Frank Winklmeier + * + * $Id: $ + */ + +// STL includes +#include <string> +#include <vector> +#include <map> + +// Framework includes +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/IIncidentListener.h" + +#include "AthenaBaseComps/AthAlgTool.h" +#include "StoreGate/DataHandle.h" +#include "EventInfo/EventID.h" + +#include "CTPfragment/CTPExtraWordsFormat.h" + +class TH1F; +class IIOVSvc; +class IIOVDbSvc; +class IIncidentSvc; +class CondAttrListCollection; + +/** + * Struct to hold CLID <-> folder name mapping + */ +struct FolderInfo { + FolderInfo() : clid(CLID_NULL) {} + FolderInfo(const CLID& cl, const std::string& k) : clid(cl), key(k) {} + CLID clid; + std::string key; +}; + +/** + * Folder update entry + */ +struct FolderUpdate { + FolderUpdate() : lumiBlock(0), folderIndex(0), needsUpdate(true) {} + FolderUpdate(const CTPfragment::FolderEntry& entry) : + lumiBlock(entry.lumiBlock), + folderIndex(entry.folderIndex), + needsUpdate(true) {} + + EventID::number_type lumiBlock; + CTPfragment::FolderIndex folderIndex; + bool needsUpdate; +}; + +/** + * @brief Tool to perform COOL updates during the run + * + */ +class TrigCOOLUpdateHelper : public AthAlgTool, + public IIncidentListener +{ +public: + + TrigCOOLUpdateHelper(const std::string &type, const std::string &name, const IInterface *parent); + virtual ~TrigCOOLUpdateHelper(); + + static const InterfaceID& interfaceID(); + virtual StatusCode initialize(); + virtual StatusCode start(); + virtual StatusCode stop(); + virtual void handle (const Incident&); + + /** + * @brief Reset folders configured to be reset on BeginRun + * @param currentRun Current run number + */ + StatusCode resetBeginRunFolders(EventID::number_type currentRun); + + /** + * @brief Perform COOL udpates if needed + * @param currentLB Current lumiblock + * @param currentRun Current run number + * @param sor_time_sec Start-Of-Run time in seconds + * @param sor_time_nsec Start-Of-Run time offset in nanoseconds + */ + StatusCode hltCoolUpdate(EventID::number_type currentLB, + EventID::number_type currentRun, + EventID::number_type sor_time_sec, + EventID::number_type sor_time_nsec); + + /** + * @brief Update specified COOL folder + * @param folder COOL folder to reset + * @param currentLB Current lumiblock + * @param currentRun Current run number + * @param sor_time_sec Start-Of-Run time in seconds + * @param sor_time_nsec Start-Of-Run time offset in nanoseconds + * @param doProxyReset Drop object and reset cache + */ + StatusCode hltCoolUpdate(const std::string& folder, + EventID::number_type currentLB, + EventID::number_type currentRun, + EventID::number_type sor_time_sec, + EventID::number_type sor_time_nsec); + + /** + * @brief Force IOVSvc to recheck all IOVs (needs to be called on every LB change) + * @param currentLB Current lumiblock + * @param currentRun Current run number + * @param sor_time_sec Start-Of-Run time in seconds + * @param sor_time_nsec Start-Of-Run time offset in nanoseconds + */ + void checkIOV(EventID::number_type currentLB, + EventID::number_type currentRun, + EventID::number_type sor_time_sec, + EventID::number_type sor_time_nsec); + + /** + * @brief Return folder name to index + * @param idx Folder index + * @param folderName Returns folder name + */ + StatusCode getFolderName(CTPfragment::FolderIndex idx, std::string& folderName); + + /** + * @brief Set the folder updates as retrieved from the CTP fragment + * @param map returned by CTPfragment::ExtraPayload::getFolderUpdates() + */ + void setFolderUpdates(const std::map<CTPfragment::FolderIndex, CTPfragment::FolderEntry>& folderUpdates); + +private: + + /** + * @brief Reset COOL folder + * @param folder COOL folder name + * @param currentRun Current run number + * @param dropObject Drop object and reset cache + */ + StatusCode resetFolder(const std::string& folder, + EventID::number_type currentRun, + bool dropObject = false); + + /** + * @brief Reset list of COOL folders + * @param folders List of folder names + * @param currentRun Current run number + * @param dropObject Drop object and reset cache + */ + StatusCode resetFolders(const std::vector<std::string>& folders, + EventID::number_type currentRun, + bool dropObject = false); + + /** + * Read information about existing COOL folders + */ + void readFolderInfo(); + + typedef std::map<std::string, FolderInfo> FolderInfoMap; + FolderInfoMap m_folderInfo; //!< COOL folder info + + const DataHandle<CondAttrListCollection> m_folderMapHandle; + std::map<CTPfragment::FolderIndex, FolderUpdate> m_folderUpdates; + + // Services and Tools + IIOVSvc* m_iovSvc; + IIOVDbSvc* m_iovDbSvc; + ServiceHandle<IIncidentSvc> m_incidentSvc; + + // Histograms + TH1F* m_hist_timeCondUpdate; //!< Timing histogram for conditions updates + + // Properties + std::string m_coolFolderName; //!< COOL folder name + std::vector<std::string> m_beginRunFolders; //!< Folders to reset before BeginRun +}; + + +inline const InterfaceID& TrigCOOLUpdateHelper::interfaceID() +{ + static const InterfaceID _IID("TrigCOOLUpdateHelper", 1, 0); + return _IID; +} + +#endif diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigIS.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigIS.cxx new file mode 100644 index 00000000000..e4a39857e59 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigIS.cxx @@ -0,0 +1,85 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file TrigIS.cxx + * @brief Implementation of TrigIS service + * @author Frank Winklmeier + * + * $Id: TrigIS.cxx 5 2013-05-14 10:33:04Z ricab $ + */ + +#include "TrigServices/TrigIS.h" +#include "is/info.h" + +TrigIS::TrigIS(const std::string& name, ISvcLocator* pSvcLocator) : + AthService(name, pSvcLocator), + m_validPartition(false) +{ + declareProperty("Partition", m_partitionName = "NONE", "Partition name"); +} + +TrigIS::~TrigIS() +{ +} + +StatusCode TrigIS::queryInterface(const InterfaceID& riid, void** ppvInterface) +{ + if ( ppvInterface==0 ) return StatusCode::FAILURE; + + if ( ITrigIS::interfaceID().versionMatch(riid) ) { + *ppvInterface = static_cast<ITrigIS*>(this); + addRef(); + return StatusCode::SUCCESS; + } + else { + return AthService::queryInterface(riid, ppvInterface); + } +} + +StatusCode TrigIS::initialize() +{ + if (m_partitionName=="NONE") { + msg() << MSG::WARNING << "No partition specified. Will not publish any data to IS." << endreq; + return StatusCode::SUCCESS; + } + + // Try to initialize IPC core + try { + int nIPCOpts = 0; + IPCCore::init(nIPCOpts, 0); + m_partition = IPCPartition(m_partitionName); + m_isDict = ISInfoDictionary(m_partition); + } + catch ( daq::ipc::Exception & ex ) { + msg() << MSG::ERROR << "Failure during initialize: " << ex.what() << endreq; + return StatusCode::FAILURE; + } + + m_validPartition = true; + return StatusCode::SUCCESS; +} + + +StatusCode TrigIS::publish(const std::string& name, const ISInfo& info, bool keep_history) +{ + if (m_validPartition) { + try { + m_isDict.checkin(name, info, keep_history); + } + catch ( daq::is::Exception& ex ) { + msg() << MSG::ERROR << "Failure publishing " << name << ": " << ex.what() << endreq; + return StatusCode::FAILURE; + } + } + return StatusCode::SUCCESS; +} + +// Dummy implementation for now +void TrigIS::publish_async(const std::string& name, ISInfo* info, bool keep_history) +{ + publish(name, *info, keep_history).ignore(); + delete info; +} + diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigISHelper.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigISHelper.cxx new file mode 100644 index 00000000000..23a5159c2b5 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigISHelper.cxx @@ -0,0 +1,139 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file TrigISHelper.cxx + * @brief Helper tool for IS access + * @author Frank Winklmeier, Werner Wiedenmann + * + * $Id: TrigISHelper.cxx 5 2013-05-14 10:33:04Z ricab $ + */ + +#include "TrigServices/TrigISHelper.h" + + +using namespace std; + +//========================================================================= +// Standard methods +//========================================================================= +TrigISHelper::TrigISHelper(const std::string &type, + const std::string &name, + const IInterface *parent) + : AthAlgTool(type, name, parent) +{ + // No abstract interface due to templates + declareInterface<TrigISHelper>(this); + + declareProperty("PartitionName", m_partitionName = "NONE", + "Default partition name if not explicitly specified in IS identifier properties"); + m_partitionName.declareUpdateHandler(&TrigISHelper::initPartitionName, this); + + declareProperty("ignoreIfMissing", m_ignoreIfMissing = false, + "Return SUCCESS if IS object is missing (for testing only)"); + + const string& help = "IS identifier: [Partition/]ISServer.ISInfoName"; + + declareProperty("RunParams", + m_isprop[RunParams] = "RunParams.RunParams", + help); + + declareProperty("LumiBlock", + m_isprop[LumiBlock] = "RunParams.LumiBlock", + help); + + declareProperty("SolenoidCurrent", + m_isprop[SolenoidCurrent] = "initial/DCS_GENERAL.MagnetSolenoidCurrent.value", + help); + + declareProperty("ToroidCurrent", + m_isprop[ToroidCurrent] = "initial/DCS_GENERAL.MagnetToroidsCurrent.value", + help); +} + + +TrigISHelper::~TrigISHelper() +{} + + +StatusCode TrigISHelper::initialize() +{ + if (m_ignoreIfMissing ) { + msg() << MSG::WARNING << "Will ignore any missing IS objects and return SUCCESS" << endreq; + } + + return StatusCode::SUCCESS; +} + + + +void TrigISHelper::initPartitionName(Property& /*prop*/) +{ + m_isid.clear(); + + if (msgLvl(MSG::DEBUG)) + msg() << MSG::DEBUG << "Configured ISInfo objects (partition : name):" << endreq; + + // Fill map with partition and IS names + map<ISObject, string>::const_iterator iter = m_isprop.begin(); + for (; iter != m_isprop.end(); ++iter ) { + m_isid[iter->first] = split(iter->second); + + if (msgLvl(MSG::DEBUG)) + msg() << MSG::DEBUG << " " << m_isid[iter->first].first + << " : " << m_isid[iter->first].second << endreq; + } +} + +//========================================================================= +// Read IS value +//========================================================================= +StatusCode TrigISHelper::findValue(ISObject obj, ISInfo& value) +{ + const string& partName = m_isid[obj].first; + const string& isName = m_isid[obj].second; + + // read values from IS + try { + IPCPartition part(partName); + ISInfoDictionary isInfoDict(part); + isInfoDict.findValue(isName, value); + } + catch (daq::is::Exception& e) { + msg() << MSG::WARNING << "IS Exception reading " << isName << " from partition " + << partName << ". Exception was: " << e << endreq; + + return m_ignoreIfMissing ? StatusCode::SUCCESS : StatusCode::FAILURE; + } + + if ( msgLvl(MSG::DEBUG) ) { + msg() << MSG::DEBUG << "Successfully read " << isName << " from IS: " << value << endreq; + } + return StatusCode::SUCCESS; +} + + +const std::string& TrigISHelper::partition(ISObject obj) const +{ + return m_isid.find(obj)->second.first; +} + + +const std::string& TrigISHelper::isName(ISObject obj) const +{ + return m_isid.find(obj)->second.second; +} + + + +//========================================================================= +// Helper to split ISObject property string +//========================================================================= +pair<string,string> TrigISHelper::split(const std::string& isid) +{ + size_t i = isid.find("/"); + if (i==string::npos) return make_pair(m_partitionName.value(), isid); + + return make_pair(isid.substr(0, i), isid.substr(i+1, isid.length()-i)); +} diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx new file mode 100644 index 00000000000..bfada2b9306 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx @@ -0,0 +1,1203 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: TrigMessageSvc.cxx 5 2013-05-14 10:33:04Z ricab $ + +#include "GaudiKernel/Kernel.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/ITHistSvc.h" +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/SvcFactory.h" +#include "GaudiKernel/Message.h" +#include "GaudiKernel/xtoa.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "EventInfo/EventInfo.h" +#include "EventInfo/EventID.h" +#include "TrigServices/TrigMessageSvc.h" +#include "TrigServices/TrigHLTIssues.h" +#include "TrigMonitorBase/TrigLockedHist.h" + +#include <TH1I.h> +#include <TH2I.h> + +#include <sstream> +#include <iostream> + +#include <pthread.h> +#include <boost/thread/recursive_mutex.hpp> + + +static pthread_mutex_t msgsvcmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + +using namespace std; + +static std::string levelNames[MSG::NUM_LEVELS]; + +// ERS debug level for which to enforce DEBUG OutputLevel +static int ersGaudiDebugOffset = 8; + +// Constructor +TrigMessageSvc::TrigMessageSvc( const std::string& name, ISvcLocator* svcloc ) + : Service(name, svcloc) + , m_doSuppress{false} + , m_running{false} + , m_canEnter{false} + , m_evtStore{"StoreGateSvc/StoreGateSvc", name} + , m_msgCountHist{nullptr} + , m_msgCountSrcHist{nullptr} +{ + m_defaultStream = &std::cout; + m_outputLevel = MSG::NIL; + declareProperty( "Format", m_defaultFormat = "% F%18W%S%7W%R%T %0W%M" ); + declareProperty( "timeFormat", m_defaultTimeFormat = "%Y-%m-%d %H:%M:%S,%f" ); + + declareProperty( "showStats", m_stats = false ); + declareProperty( "statLevel", m_statLevel = 0, "Show statistics for messages >= level" ); + declareProperty( "statLevelRun", m_statLevelRun = 0, "Show per-run statistics for messages >= level" ); + + declareProperty( "publishStats", m_publishStats = false, + "Publish message statistics as histogram"); + + declareProperty( "publishLevel", m_publishLevel = MSG::INFO, + "Publish message statistics for this and higher message levels"); + + declareProperty( "resetStatsAtBeginRun", m_resetStats = false ); + + declareProperty( "printEventIDLevel", m_eventIDLevel = MSG::WARNING, + "Print event ID for this and higher message levels"); + + // Special properties to control output level of individual sources + declareProperty( "setVerbose", m_thresholdProp[MSG::VERBOSE] ); + declareProperty( "setDebug", m_thresholdProp[MSG::DEBUG] ); + declareProperty( "setInfo", m_thresholdProp[MSG::INFO] ); + declareProperty( "setWarning", m_thresholdProp[MSG::WARNING] ); + declareProperty( "setError", m_thresholdProp[MSG::ERROR] ); + declareProperty( "setFatal", m_thresholdProp[MSG::FATAL] ); + declareProperty( "setAlways", m_thresholdProp[MSG::ALWAYS] ); + + declareProperty( "useColors", m_color=false); + m_color.declareUpdateHandler(&TrigMessageSvc::initColors, this); + + declareProperty( "fatalColorCode", m_logColors[MSG::FATAL] ); + declareProperty( "errorColorCode", m_logColors[MSG::ERROR] ); + declareProperty( "warningColorCode", m_logColors[MSG::WARNING] ); + declareProperty( "infoColorCode", m_logColors[MSG::INFO] ); + declareProperty( "debugColorCode", m_logColors[MSG::DEBUG] ); + declareProperty( "verboseColorCode", m_logColors[MSG::VERBOSE] ); + declareProperty( "alwaysColorCode", m_logColors[MSG::ALWAYS] ); + + m_defaultLimit = 500; + declareProperty( "fatalLimit", m_msgLimit[MSG::FATAL] = m_defaultLimit ); + declareProperty( "errorLimit", m_msgLimit[MSG::ERROR] = m_defaultLimit ); + declareProperty( "warningLimit", m_msgLimit[MSG::WARNING] = m_defaultLimit ); + declareProperty( "infoLimit", m_msgLimit[MSG::INFO] = m_defaultLimit ); + declareProperty( "debugLimit", m_msgLimit[MSG::DEBUG] = m_defaultLimit ); + declareProperty( "verboseLimit", m_msgLimit[MSG::VERBOSE] = m_defaultLimit ); + declareProperty( "alwaysLimit", m_msgLimit[MSG::ALWAYS] = 0 ); + + declareProperty( "defaultLimit", m_msgLimit[MSG::NIL] = m_defaultLimit ); + + declareProperty( "enableSuppression", m_suppress = false, + "Enable message suppression"); + + declareProperty( "suppressRunningOnly", m_suppressRunningOnly = true, + "Use message suppression only during RUNNING state"); + + m_suppress.declareUpdateHandler(&TrigMessageSvc::setupSuppression, this); + m_suppressRunningOnly.declareUpdateHandler(&TrigMessageSvc::setupSuppression, this); + + /* Special properties to control output to ERS of individual sources. + The syntax is as follows (these are NOT regular expressions): + + useErsFatal = [] # forward none (default) + useErsFatal = ['*'] # forward all + useErsFatal = ['CoreDumpSvc','MyAlg'] # forward these sources + useErsFatal = ['*','!MyAlg'] # forward all except MyAlg + */ + + const vector<string> defaultErsUse; + declareProperty( "useErsVerbose", m_useERS[MSG::VERBOSE] = defaultErsUse ); + declareProperty( "useErsDebug", m_useERS[MSG::DEBUG] = defaultErsUse ); + declareProperty( "useErsInfo", m_useERS[MSG::INFO] = defaultErsUse ); + declareProperty( "useErsWarning", m_useERS[MSG::WARNING] = defaultErsUse ); + declareProperty( "useErsError", m_useERS[MSG::ERROR] = defaultErsUse ); + declareProperty( "useErsFatal", m_useERS[MSG::FATAL] = defaultErsUse ); + declareProperty( "useErsAlways", m_useERS[MSG::ALWAYS] = defaultErsUse ); + + declareProperty( "alwaysUseMsgStream", m_alwaysUseMsgStream = true, + "Print all messages to MsgStream, even if forwarded to ERS"); + + declareProperty( "useErsRunningOnly", m_useErsRunningOnly = false, + "Forward messages to ERS only during RUNNING state"); + + declareProperty( "forceOutputLevel", m_forceOutputLevel = false, + "Enforce the global OutputLevel for all sources"); + + for (int ic=0; ic<MSG::NUM_LEVELS; ++ic) { + m_logColors[ic].declareUpdateHandler(&TrigMessageSvc::setupColors, this); + m_msgLimit[ic].declareUpdateHandler(&TrigMessageSvc::setupLimits, this); + m_thresholdProp[ic].declareUpdateHandler(&TrigMessageSvc::setupThreshold, this); + } + + levelNames[0] = "NIL"; + levelNames[1] = "VERBOSE"; + levelNames[2] = "DEBUG"; + levelNames[3] = "INFO"; + levelNames[4] = "WARNING"; + levelNames[5] = "ERROR"; + levelNames[6] = "FATAL"; + levelNames[7] = "ALWAYS"; + +} +//############################################################################# +// Destructor +TrigMessageSvc::~TrigMessageSvc() +{ + pthread_mutex_destroy(&msgsvcmutex); +} + +/// Initialize Service +StatusCode TrigMessageSvc::initialize() { + + StatusCode sc; + sc = Service::initialize(); + if( sc.isFailure() ) return sc; + + m_running = false; + m_canEnter = true; + +#ifdef _WIN32 + m_color = false; +#endif + + // Reset message counters + resetMsgStats(); + m_sourceMapTotal.clear(); + + // Initialize message suppression + setupSuppression(m_suppress); + + m_colMap["black"] = MSG::BLACK; + m_colMap["red"] = MSG::RED; + m_colMap["green"] = MSG::GREEN; + m_colMap["yellow"] = MSG::YELLOW; + m_colMap["blue"] = MSG::BLUE; + m_colMap["purple"] = MSG::PURPLE; + m_colMap["cyan"] = MSG::CYAN; + m_colMap["white"] = MSG::WHITE; + + /* + * m_state is set in the base class sysInitialize after initialize succeeded. + * However, we need to set it already here otherwise the following + * use of IncidentSvc/JobOptionsSvc creates a service initialization loop. + */ + m_state = Gaudi::StateMachine::INITIALIZED; + + /* + * This will force the OutputLevel of all components to be the global + * OutputLevel (m_outputLevel of this service). It should cover the use-cases: + * 1) 'MsgStream(msgSvc(),name())' + * 2) 'MsgStream::setLevel(m_outputLevel)' + * For 2) we rely on the fact that the MessageSvc is created/initialized after + * the JobOptionsSvc in ApplicationMgr::i_startup(). + */ + int ers_debug = ers::Configuration::instance().debug_level(); + if ( ers_debug >= ersGaudiDebugOffset+1 ) { + setOutputLevel(MSG::VERBOSE); + m_forceOutputLevel.setValue(true); + } + else if ( ers_debug >= ersGaudiDebugOffset ) { + setOutputLevel(MSG::DEBUG); + m_forceOutputLevel.setValue(true); + } + + if ( m_forceOutputLevel.value() ) { + resetOutputLevels(); // Clear all individual OutputLevels (to cover use-case 1) + setOutputLevelViaJobOptSvc(); // Set 'OutputLevel' in JobOptionsSvc (to cover use-case 2) + reportMessage(name(), MSG::INFO, "Enforcing global OutputLevel = "+levelNames[m_outputLevel.value()]); + } + + // Register incident handlers + ServiceHandle<IIncidentSvc> incSvc("IncidentSvc",name()); + sc = incSvc.retrieve(); + if (sc.isFailure()) { + reportMessage(name(), MSG::WARNING, "Cannot find IncidentSvc"); + } + else { + incSvc->addListener(this, "BeginRun", LONG_MAX); + incSvc->addListener(this, "EndOfBeginRun", LONG_MAX); + incSvc->addListener(this, "EndRun", LONG_MAX); + } + + return StatusCode::SUCCESS; +} + +//############################################################################# + +/// Reinitialize Service +StatusCode TrigMessageSvc::reinitialize() { + m_state = Gaudi::StateMachine::OFFLINE; + return initialize(); +} + + +//############################################################################# +void TrigMessageSvc::handle(const Incident& inc) { + + // We cannot use start/stop for the MessageSvc due to bug #46216 + if (inc.type()=="BeginRun") { + if (m_suppressRunningOnly.value()) { + m_doSuppress = m_suppress.value(); + } + if (m_publishStats) bookHistograms(); + } + else if (inc.type()=="EndOfBeginRun") { + if (m_resetStats) { + reportMessage(name(), MSG::INFO, "Resetting message counts"); + resetMsgStats(); + } + m_running = true; + } + else if (inc.type()=="EndRun") { + m_running = false; + if (m_resetStats) reportMsgStats(MSG::INFO); + if (m_suppressRunningOnly.value()) m_doSuppress = false; + } +} + + +//############################################################################# +void TrigMessageSvc::resetMsgStats() +{ + // Copy current counts to total counts map + std::map<std::string,msgAry>::const_iterator itr; + std::map<std::string,msgAry>::iterator tot; + for (itr=m_sourceMap.begin(); itr!=m_sourceMap.end(); ++itr) { + tot = m_sourceMapTotal.find(itr->first); + if (tot==m_sourceMapTotal.end()) { // new entry + for (int i=0; i<MSG::NUM_LEVELS; i++) m_sourceMapTotal[itr->first].msg[i] = itr->second.msg[i]; + } + else { // existing entry + for (int i=0; i<MSG::NUM_LEVELS; i++) tot->second.msg[i] += itr->second.msg[i]; + } + } + + m_sourceMap.clear(); + m_msgCountMap.clear(); + for (int i=0; i<MSG::NUM_LEVELS; i++) m_msgCount[i] = 0; +} + + +// --------------------------------------------------------------------------- +// Book the message stats histograms +// --------------------------------------------------------------------------- +void TrigMessageSvc::bookHistograms() +{ + ServiceHandle<ITHistSvc> histSvc("THistSvc",name()); + if ( histSvc.retrieve().isFailure() ) { + reportMessage(name(), MSG::WARNING, + "Cannot find THistSvc. Message stats will not be published."); + return; + } + + // monitoring information root directory + const string path = "/EXPERT/" + name() + "/"; + const int nLevelBins = MSG::NUM_LEVELS - m_publishLevel; + m_msgCountHist = new TH1I("MessageCount", "Messages while RUNNING;Severity;Count", + nLevelBins, 0, nLevelBins); + + const int nSrcBins = 1; + m_msgCountSrcHist = new TH2I("MessageCountBySource", "Messages while RUNNING;Severity;Source", + nLevelBins, 0, nLevelBins, nSrcBins, 0, nSrcBins); + + + for (int i=m_publishLevel; i<MSG::NUM_LEVELS; i++) { + m_msgCountHist->GetXaxis()->SetBinLabel(i-m_publishLevel+1, levelNames[i].c_str()); + m_msgCountSrcHist->GetXaxis()->SetBinLabel(i-m_publishLevel+1, levelNames[i].c_str()); + } + + if ( histSvc->regHist(path + m_msgCountHist->GetName(), m_msgCountHist).isFailure() ) { + reportMessage(name(), MSG::WARNING, "Cannot register monitoring histogram 'MessageCount'"); + } + if ( histSvc->regHist(path + m_msgCountSrcHist->GetName(), m_msgCountSrcHist).isFailure() ) { + reportMessage(name(), MSG::WARNING, "Cannot register monitoring histogram 'MessageCountBySource'"); + } +} + +void TrigMessageSvc::initColors(Property& /*prop*/) { + + if (m_color == true) { + + if (m_logColors[MSG::FATAL].value().size() == 0) { + vector<string> fatDef; + fatDef.push_back( "[94;101;1m" ); + m_logColors[MSG::FATAL].set( fatDef ); + } else { + TrigMessageSvc::setupColors( m_logColors[MSG::FATAL] ); + } + + if (m_logColors[MSG::ERROR].value().size() == 0) { + vector<string> errDef; + errDef.push_back( "[97;101;1m" ); + m_logColors[MSG::ERROR].set( errDef ); + } else { + TrigMessageSvc::setupColors( m_logColors[MSG::ERROR] ); + } + + if (m_logColors[MSG::WARNING].value().size() == 0) { + vector<string> warDef; + warDef.push_back( "[93;1m" ); + m_logColors[MSG::WARNING].set( warDef ); + } else { + TrigMessageSvc::setupColors( m_logColors[MSG::WARNING] ); + } + + } else { + + // reset all color codes; + for (int ic=0; ic<MSG::NUM_LEVELS; ++ic) { + vector<string> def; + m_logColors[ic].set( def ); + } + + } + +} + +//############################################################################# + +void TrigMessageSvc::setupColors(Property& prop) { + + if (! m_color) return; + + int ic; + if (prop.name() == "fatalColorCode") { + ic = MSG::FATAL; + } else if (prop.name() == "errorColorCode") { + ic = MSG::ERROR; + } else if (prop.name() == "warningColorCode") { + ic = MSG::WARNING; + } else if (prop.name() == "infoColorCode") { + ic = MSG::INFO; + } else if (prop.name() == "debugColorCode") { + ic = MSG::DEBUG; + } else if (prop.name() == "verboseColorCode") { + ic = MSG::VERBOSE; + } else if (prop.name() == "alwaysColorCode") { + ic = MSG::ALWAYS; + } else { + std::ostringstream internal_msg ; + internal_msg << "ERROR: Unknown message color parameter: " << prop.name(); + if (passErsFilter(name(), m_useERS[MSG::ERROR])) { + ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) ); + } else { + std::cerr << internal_msg.str() << std::endl; + } + return; + } + + string code; + vector<string>::const_iterator itr; + itr = m_logColors[ic].value().begin(); + + if ( m_logColors[ic].value().size() == 1 ) { + + if (*itr == "") { + code = ""; + } else if (itr->substr(0,1) == "[") { + code = "\033" + *itr; + } else { + code = "\033[" + colTrans(*itr, 90) + ";1m"; + } + + } else if (m_logColors[ic].value().size() == 2) { + vector<string>::const_iterator itr2 = itr + 1; + + code = "\033[" + colTrans(*itr, 90) + ";" + + colTrans(*itr2, 100) + ";1m"; + + } + + m_logColorCodes[ic] = code; + +} +//############################################################################# + +void TrigMessageSvc::setupLimits(Property& prop) { + const auto& pname = prop.name(); + if (pname == "alwaysLimit") { + IntegerProperty *p = dynamic_cast<IntegerProperty*>(&prop); + if (p && p->value() != 0) { + std::ostringstream internal_msg ; + internal_msg << "TrigMessageSvc ERROR: cannot suppress ALWAYS messages" ; + if (passErsFilter(name(), m_useERS[MSG::ERROR])) { + ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) ); + } else { + std::cerr << internal_msg.str() << std::endl; + } + p->setValue(0); + } + } else if (pname == "defaultLimit") { + // Only change the limits that are still on the default value + for (int i = MSG::VERBOSE; i< MSG::NUM_LEVELS; ++i) { + if ( (i != MSG::ALWAYS) && (m_msgLimit[i].value() == m_defaultLimit) ) { + m_msgLimit[i] = m_msgLimit[MSG::NIL].value(); + } + } + } else if (pname != "fatalLimit" && + pname != "errorLimit" && + pname != "warningLimit" && + pname != "infoLimit" && + pname != "debugLimit" && + pname != "verboseLimit") { + std::ostringstream internal_msg ; + internal_msg << "TrigMessageSvc ERROR: Unknown message limit parameter: " << prop.name() ; + if (passErsFilter(name(), m_useERS[MSG::ERROR])) { + ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) ); + } else { + std::cerr << internal_msg.str() << std::endl; + } + return; + } +} +//############################################################################# + +void TrigMessageSvc::setupThreshold(Property& prop) { + + int ic = 0; + if (prop.name() == "setFatal") { + ic = MSG::FATAL; + } else if (prop.name() == "setError") { + ic = MSG::ERROR; + } else if (prop.name() == "setWarning") { + ic = MSG::WARNING; + } else if (prop.name() == "setInfo") { + ic = MSG::INFO; + } else if (prop.name() == "setDebug") { + ic = MSG::DEBUG; + } else if (prop.name() == "setVerbose") { + ic = MSG::VERBOSE; + } else if (prop.name() == "setAlways") { + ic = MSG::ALWAYS; + } else { + std::ostringstream internal_msg ; + internal_msg << "TrigMessageSvc ERROR: Unknown message theshold parameter: " << prop.name(); + if (passErsFilter(name(), m_useERS[MSG::ERROR])) { + ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) ); + } else { + std::cerr << internal_msg.str() << std::endl; + } + return; + } + + StringArrayProperty *sap = dynamic_cast<StringArrayProperty*>( &prop); + if (sap == 0) { + std::ostringstream internal_msg ; + internal_msg << "could not dcast " << prop.name() + << " to a StringArrayProperty (which it should be!)"; + if (passErsFilter(name(),m_useERS[MSG::ERROR])) { + ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) ); + } else { + std::cerr << internal_msg.str() << std::endl; + } + return; + } else { + std::vector<std::string>::const_iterator itr; + for ( itr = sap->value().begin(); + itr != sap->value().end(); + ++itr) { + setOutputLevel( *itr, ic ); + } + } + +} + +//############################################################################# + +bool TrigMessageSvc::passErsFilter(const std::string& source, + const std::vector<std::string>& filter) +{ + if (m_useErsRunningOnly.value() and not m_running) return false; + if (filter.empty()) return false; // forward none + vector<string>::const_iterator it = filter.begin(); + if (filter.size()==1 && (*it)=="*") return true; // forward all + + bool pass(false); + for (; it!=filter.end(); ++it) { + if ((*it)=="*") pass=true; // forward except if there is a veto later + if (source==(*it)) return true; // forward specific source + if ("!"+source==(*it)) return false; // veto specific source + } + return pass; +} + + +//############################################################################# + +void TrigMessageSvc::setupSuppression(Property& /*prop*/) { + // (De)activate suppression + if ( m_suppressRunningOnly.value() ) { + m_doSuppress = (m_running && m_suppress.value()); + } + else { + m_doSuppress = m_suppress.value(); + } +} + +//############################################################################# +/// Finalize Service +StatusCode TrigMessageSvc::finalize() { + + m_running = false; + m_doSuppress = false; + resetMsgStats(); // to get the final total sum + reportMsgStats(m_statLevel.value(),true); + m_state = Gaudi::StateMachine::OFFLINE; + return StatusCode::SUCCESS; +} + + +//############################################################################# +/// Report message counts +void TrigMessageSvc::reportMsgStats(uint statLevel, bool total) { + + std::ostringstream os; + + if (m_stats) { + os << "Summarizing all message counts"; + if (!total){ + const EventInfo* pEvent(0); + if ( m_evtStore->retrieve(pEvent).isSuccess() ) { + os << " for run " << pEvent->event_ID()->run_number(); + } + } + os << " (severity >= " << levelNames[statLevel] << ")" << endl; + } else { + os << "Listing sources of suppressed message: " << endl; + } + + os << "==========================================================" << endl; + os << " Message Source | Level | Count" << endl; + os << "----------------------------------+---------+-------------" << endl; + + bool found(false); + + std::map<std::string,msgAry>::const_iterator itr = m_sourceMap.begin(); + std::map<std::string,msgAry>::const_iterator enditr = m_sourceMap.end(); + + if (total) { + itr = m_sourceMapTotal.begin(); + enditr = m_sourceMapTotal.end(); + } + + for (; itr!=enditr; ++itr) { + for (unsigned int ic = 0; ic < MSG::NUM_LEVELS; ++ic) { + if ( (m_suppress.value() && itr->second.msg[ic] >= abs(m_msgLimit[ic]) && m_msgLimit[ic] != 0 ) || + (m_stats && itr->second.msg[ic] > 0 && ic >= statLevel) ) { + os << " "; + os.width(33); + os.setf(ios_base::left,ios_base::adjustfield); + os << itr->first; + + os << "|"; + + os.width(8); + os.setf(ios_base::right,ios_base::adjustfield); + os << levelNames[ic]; + + os << " |"; + + os.width(9); + os << itr->second.msg[ic]; + + os << endl; + + found = true; + } + } + } + os << "==========================================================" << endl; + + if (found || m_stats) { + reportMessage(name(), MSG::INFO, os.str()); + } +} + +//############################################################################# +std::string TrigMessageSvc::colTrans(std::string col, int offset) { + ColorMap::const_iterator itr = m_colMap.find(col); + int icol; + if (itr != m_colMap.end()) { + icol = offset + itr->second; + } else { + icol = offset + 8; + } + std::ostringstream os1; + + os1 << icol; + + return os1.str(); + +} + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: reportMessage +// Purpose: dispatches a message to the relevant streams. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::reportMessage( const Message& msg, int outputLevel ) { + + int nmsg; + + pthread_mutex_lock(&msgsvcmutex); + int key = msg.getType(); + ++m_msgCount[key]; + + // Publish message statistics if enabled and only while RUNNING + if ( m_publishStats && m_running && key>=static_cast<int>(m_publishLevel) ) { + m_msgCountHist->Fill(key-m_publishLevel, 1); + { // Adding bins on the fly needs to be protected by mutex + scoped_lock_histogram lock; + m_msgCountSrcHist->Fill(key-m_publishLevel, msg.getSource().c_str(), 1); + m_msgCountSrcHist->LabelsDeflate("Y"); + } + } + + const Message *cmsg = &msg; + + if ( m_doSuppress || m_stats.value() ) { + + std::map<std::string,msgAry>::iterator itr = m_sourceMap.find(msg.getSource()); + if ( itr != m_sourceMap.end() ) { + nmsg = ++(itr->second.msg[key]); + } + else { + msgAry A; + for (int i=0; i<MSG::NUM_LEVELS; ++i) A.msg[i] = 0; + A.msg[key] = 1; + m_sourceMap[msg.getSource()] = A; + nmsg = 1; + } + + if (m_doSuppress) { + const int msgLimit = m_msgLimit[key].value(); + + if ( msgLimit > 0 ) { // regular suppression + if (nmsg == msgLimit) { + std::ostringstream os; + os << levelNames[key] << " message limit (" << msgLimit << ") reached for " + << msg.getSource() + ". Suppressing further output."; + cmsg = new Message(msg.getSource(), MSG::WARNING, os.str()); + cmsg->setFormat(msg.getFormat()); + cmsg->setTimeFormat(msg.getTimeFormat()); + } + else if (nmsg > msgLimit) { + pthread_mutex_unlock(&msgsvcmutex); + return; + } + } + else if ( msgLimit < 0 ) { // logarithmic suppression + + // Use source/level/message as identifier and calculate hash + const unsigned int msgKey = msgHash(*cmsg); + MsgCountMap::iterator itr = m_msgCountMap.find(msgKey); + + // Check if we saw this message already and increase counter + if (itr != m_msgCountMap.end()) + nmsg = ++itr->second; + else + nmsg = m_msgCountMap[msgKey] = 1; + + if ( nmsg == abs(msgLimit) ) { + std::ostringstream os; + os << msg.getMessage() << " [Message limit (" << abs(msgLimit) + << ") reached. Log-suppression of further output.]"; + cmsg = new Message(msg.getSource(), msg.getType(), os.str()); + cmsg->setFormat(msg.getFormat()); + cmsg->setTimeFormat(msg.getTimeFormat()); + } + else if ( nmsg > abs(msgLimit) ) { + const int everyNth = (int)exp10((int)log10(nmsg)); + if ((nmsg % everyNth)==0) { + std::ostringstream os; + os << msg.getMessage() << " [suppressed " << everyNth << " similar messages]"; + cmsg = new Message(msg.getSource(), msg.getType(), os.str()); + cmsg->setFormat(msg.getFormat()); + cmsg->setTimeFormat(msg.getTimeFormat()); + } + else { + pthread_mutex_unlock(&msgsvcmutex); + return; + } + } + } + } + } // suppression + + // Optional message trailer (ignored in hash) + std::ostringstream msgTrailer; + + // Avoid recursion in case StoreGateSvc::retrieve prints a message + if ( m_canEnter ) { + m_canEnter = false; + if ( m_running && + key >= static_cast<int>(m_eventIDLevel.value()) && + m_evtStore.retrieve().isSuccess() ) { + const EventInfo* pEvent(0); + if ( m_evtStore->retrieve(pEvent).isSuccess() ) { + // Add EventID + msgTrailer << " " << *pEvent->event_ID(); + } + } + m_canEnter = true; + } + + StreamMap::const_iterator first = m_streamMap.lower_bound( key ); + if ( first != m_streamMap.end() ) { + StreamMap::const_iterator last = m_streamMap.upper_bound( key ); + while( first != last ) { + std::ostream& stream = *( (*first).second.second ); + stream << *cmsg << msgTrailer.str() << std::endl; + first++; + } + } + else if ( key >= outputLevel ) { + cmsg->setFormat(m_defaultFormat); + cmsg->setTimeFormat(m_defaultTimeFormat); + std::ostringstream out_string_stream ; + if (!m_color) { + (out_string_stream) << *cmsg << msgTrailer.str(); + } else { + (out_string_stream) << m_logColorCodes[key] << *cmsg << msgTrailer.str() << "\033[m" ; + } + + bool useERS = passErsFilter(cmsg->getSource(), m_useERS[key]); + + if ( m_alwaysUseMsgStream.value() || !useERS ) { + // output to the default stream + (*m_defaultStream) << out_string_stream.str() << std::endl << std::flush; + } + + // output to ERS + if (useERS) { + + /* + * Create ERS context object + * + * The (cross-node) MRS throttling is based on filename+line_number, i.e. ignoring + * the message text itself. We therefor use the message source as filename and the + * message hash as line_number. That way the same message from different nodes + * gets properly throttled by MRS. + */ + const char* filename = cmsg->getSource().c_str(); + unsigned int line_number = msgHash(*cmsg); + const char* function_name = filename; + const char* package_name = "HLT"; + ers::LocalContext hlt_context_info(package_name, filename, line_number, function_name); + + /* + * Create ERS issue object + * + * Add the source to the ERS message text. Otherwise the source is not visible + * in the MRS monitor, for example. + * The "HLT" qualifier can be used to filter ERS messages from the log file. + */ + ers::HLTMessage ersMsg(hlt_context_info, cmsg->getSource() + ": " + cmsg->getMessage() + msgTrailer.str()); + ersMsg.add_qualifier("HLT"); // used for filtering + + // forward Gaudi message to ERS + switch (key) { + case MSG::NIL: ers::debug( ersMsg, 3 ); break; + case MSG::VERBOSE: ers::debug( ersMsg, 2 ); break; + case MSG::DEBUG: ers::debug( ersMsg, 1 ); break; + case MSG::INFO: ers::info( ersMsg ); break; + case MSG::WARNING: ers::warning( ersMsg ); break; + case MSG::ERROR: ers::error( ersMsg ); break; + case MSG::FATAL: ers::fatal( ersMsg ); break; + default: + std::ostringstream internal_msg ; + internal_msg << "ERROR: Unknown message severity level: " << key ; + ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) ); + } + } + } + + if (cmsg != &msg) { delete cmsg; } + pthread_mutex_unlock(&msgsvcmutex); +} + + +void TrigMessageSvc::reportMessage( const Message& msg ) +{ + reportMessage(msg, outputLevel(msg.getSource())); +} + +void TrigMessageSvc::reportMessage (const char* source, + int type, + const char* message) { + Message msg( source, type, message); + reportMessage( msg ); +} + + +void TrigMessageSvc::reportMessage (const std::string& source, + int type, + const std::string& message) { + Message msg( source, type, message); + reportMessage( msg ); +} + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: sendMessage +// Purpose: finds a message for a given status code and dispatches it. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::reportMessage (const StatusCode& key, + const std::string& source) +{ + pthread_mutex_lock(&msgsvcmutex); + MessageMap::const_iterator first = m_messageMap.lower_bound( key ); + if ( first != m_messageMap.end() ) { + MessageMap::const_iterator last = m_messageMap.upper_bound( key ); + while( first != last ) { + Message msg = (*first).second; + msg.setSource( source ); + std::ostringstream os1; + os1 << "Status Code " << key.getCode() << std::ends; + Message stat_code1( source, msg.getType(), os1.str() ); + reportMessage( stat_code1 ); + reportMessage( msg ); + first++; + } + } + else { + Message mesg = m_defaultMessage; + mesg.setSource( source ); + std::ostringstream os2; + os2 << "Status Code " << key.getCode() << std::ends; + Message stat_code2( source, mesg.getType(), os2.str() ); + reportMessage( stat_code2 ); + reportMessage( mesg ); + } + pthread_mutex_unlock(&msgsvcmutex); +} + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: insertStream +// Purpose: inserts a stream for a message type. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::insertStream (int key, + const std::string& name, + std::ostream *stream) +{ + typedef StreamMap::value_type value_type; + pthread_mutex_lock(&msgsvcmutex); + m_streamMap.insert( value_type( key, NamedStream(name,stream) ) ); + pthread_mutex_unlock(&msgsvcmutex); +} + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: eraseStream +// Purpose: erases all the streams for all the message types. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::eraseStream() +{ + pthread_mutex_lock(&msgsvcmutex); + m_streamMap.erase( m_streamMap.begin(), m_streamMap.end() ); + pthread_mutex_unlock(&msgsvcmutex); +} + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: eraseStream +// Purpose: erases all the streams for a message type. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::eraseStream( int message_type ) +{ + pthread_mutex_lock(&msgsvcmutex); + m_streamMap.erase( message_type ); + pthread_mutex_unlock(&msgsvcmutex); +} + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: eraseStream +// Purpose: erases one stream for a message type. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::eraseStream( int key, std::ostream* stream ) { + pthread_mutex_lock(&msgsvcmutex); + if ( 0 != stream ) { + bool changed = true; + while( changed ) { + changed = false; + StreamMap::iterator first = m_streamMap.lower_bound( key ); + StreamMap::iterator last = m_streamMap.upper_bound( key ); + while( first != last ) { + if ( (*first).second.second == stream ) { + m_streamMap.erase( first ); + changed = true; + break; + } + } + } + } + pthread_mutex_unlock(&msgsvcmutex); +} + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: eraseStream +// Purpose: erases one stream for all message types. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::eraseStream( std::ostream* stream ) { + pthread_mutex_lock(&msgsvcmutex); + if ( 0 != stream ) { + bool changed = true; + while( changed ) { + changed = false; + StreamMap::iterator first = m_streamMap.begin(); + while( first != m_streamMap.end() ) { + if ( (*first).second.second == stream ) { + m_streamMap.erase( first ); + changed = true; + break; + } + } + } + } + pthread_mutex_unlock(&msgsvcmutex); +} + + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: insertMessage +// Purpose: inserts a message for a status code. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::insertMessage( const StatusCode& key, const Message& msg ) +{ + typedef MessageMap::value_type value_type; + pthread_mutex_lock(&msgsvcmutex); + m_messageMap.insert( value_type( key, msg ) ); + pthread_mutex_unlock(&msgsvcmutex); +} + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: eraseMessage +// Purpose: erases all the messages for all the status codes. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::eraseMessage() +{ + pthread_mutex_lock(&msgsvcmutex); + m_messageMap.erase( m_messageMap.begin(), m_messageMap.end() ); + pthread_mutex_unlock(&msgsvcmutex); +} + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: eraseMessage +// Purpose: erases all the messages for a status code. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::eraseMessage( const StatusCode& key ) +{ + pthread_mutex_lock(&msgsvcmutex); + m_messageMap.erase( key ); + pthread_mutex_unlock(&msgsvcmutex); +} + +//############################################################################# +// --------------------------------------------------------------------------- +// Routine: eraseMessage +// Purpose: erases one message for a status code. +// --------------------------------------------------------------------------- +// + +void TrigMessageSvc::eraseMessage( const StatusCode& key, const Message& msg ) +{ + pthread_mutex_lock(&msgsvcmutex); + bool changed = true; + while( changed ) { + changed = false; + MessageMap::iterator first = m_messageMap.lower_bound( key ); + MessageMap::iterator last = m_messageMap.upper_bound( key ); + while( first != last ) { + const Message& message = (*first).second; + if ( message == msg ) { + m_messageMap.erase( first ); + changed = true; + break; + } + } + } + pthread_mutex_unlock(&msgsvcmutex); +} + +// --------------------------------------------------------------------------- +StatusCode TrigMessageSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) { +// --------------------------------------------------------------------------- + if ( IMessageSvc::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IMessageSvc*)this; + } + else if ( ITrigMessageSvc::interfaceID().versionMatch(riid) ) { + *ppvInterface = static_cast<ITrigMessageSvc*>(this); + } + else { + return Service::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} + +// --------------------------------------------------------------------------- +int TrigMessageSvc::outputLevel() const { +// --------------------------------------------------------------------------- + return m_outputLevel; +} +// --------------------------------------------------------------------------- +int TrigMessageSvc::outputLevel( const std::string& source ) const { +// --------------------------------------------------------------------------- + ThresholdMap::const_iterator it; + + pthread_mutex_lock(&msgsvcmutex); + it = m_thresholdMap.find( source ); + int level; + + if( it != m_thresholdMap.end() ) { + level = (*it).second; + } + else { + level = m_outputLevel; + } + pthread_mutex_unlock(&msgsvcmutex); + return level; +} + +// --------------------------------------------------------------------------- +void TrigMessageSvc::setOutputLevel(int new_level) { +// --------------------------------------------------------------------------- + pthread_mutex_lock(&msgsvcmutex); + m_outputLevel = new_level; + pthread_mutex_unlock(&msgsvcmutex); +} + +// --------------------------------------------------------------------------- +void TrigMessageSvc::setOutputLevel(const std::string& source, int level) { +// --------------------------------------------------------------------------- + // Ignore in case we enforce the global OutputLevel + if (m_forceOutputLevel.value()) return; + + pthread_mutex_lock(&msgsvcmutex); + std::pair<ThresholdMap::iterator, bool> p; + p = m_thresholdMap.insert(ThresholdMap::value_type( source, level) ); + if( p.second == false ) { + // Already existing an output level for that source. Erase and enter it again + m_thresholdMap.erase ( p.first ); + m_thresholdMap.insert(ThresholdMap::value_type( source, level) ); + } + pthread_mutex_unlock(&msgsvcmutex); +} + + +// --------------------------------------------------------------------------- +void TrigMessageSvc::setOutputLevelViaJobOptSvc() { +// --------------------------------------------------------------------------- + ServiceHandle<IJobOptionsSvc> jobOptSvc("JobOptionsSvc", name()); + if ( jobOptSvc.retrieve()==StatusCode::FAILURE ) { + reportMessage(name(), MSG::ERROR, "Cannot retrieve JobOptionsSvc"); + return; + } + + std::vector<std::string> clients = jobOptSvc->getClients(); + std::vector<std::string>::iterator cl; + std::vector<const Property*>::const_iterator pr; + + // Loop over all clients/properties and set OutputLevel accordingly + for (cl=clients.begin(); cl!=clients.end(); ++cl) { + const std::vector<const Property*> *props = jobOptSvc->getProperties(*cl); + for (pr=props->begin(); pr!=props->end(); ++pr) { + if ( (*pr)->name()=="OutputLevel" ) { + if ( jobOptSvc->addPropertyToCatalogue(*cl, m_outputLevel).isSuccess() ){ + std::ostringstream msg; + msg << "Setting " << (*pr)->name() << ".OutputLevel = " << m_outputLevel.value(); + reportMessage(name(), MSG::DEBUG, msg.str()); + } + else { + std::ostringstream msg; + msg << "Cannot set " << (*pr)->name() << ".OutputLevel"; + reportMessage(name(), MSG::WARNING, msg.str()); + } + } + } + } +} + +// --------------------------------------------------------------------------- +void TrigMessageSvc::resetOutputLevels() { +// --------------------------------------------------------------------------- + m_thresholdMap.clear(); +} + +// --------------------------------------------------------------------------- +std::string TrigMessageSvc::getLogColor(int logLevel) const { +// --------------------------------------------------------------------------- + if (logLevel < MSG::NUM_LEVELS) { + return m_logColorCodes[logLevel]; + } else { + return ""; + } +} + +// --------------------------------------------------------------------------- +int TrigMessageSvc::messageCount( MSG::Level level) const { + return m_msgCount[level]; +} +// --------------------------------------------------------------------------- + + +// --------------------------------------------------------------------------- +// Calculate message hash (ignoring any numbers) +// --------------------------------------------------------------------------- +unsigned int TrigMessageSvc::msgHash(const Message& msg) +{ + // Message type is lowest decimal + unsigned int hash = msg.getType(); + + // Add all characters of source + const std::string& src = msg.getSource(); + for (size_t i=0; i<src.length(); ++i) { + hash += 10*(int)src[i]; + } + + // Add all letters of message + const std::string& str = msg.getMessage(); + for (size_t i=0; i<str.length(); ++i) { + const char& ch = str[i]; + if (ch<',' || ch>'9') hash += 10*(int)ch; + } + + return hash; +} diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx new file mode 100644 index 00000000000..fde05437715 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx @@ -0,0 +1,403 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "GaudiKernel/SvcFactory.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/ThreadGaudi.h" + +#include "AthenaKernel/errorcheck.h" +#include "TrigMonTHistSvc.h" +#include "TrigMonitorBase/TrigLockedHist.h" + +#include "hltinterface/IInfoRegister.h" + +#include "TROOT.h" +#include "TError.h" +#include "TObject.h" +#include "TH1.h" +#include "TH2.h" +#include "TH3.h" +#include "TGraph.h" +#include "TTree.h" + +#include <iostream> +#include <sstream> +#include <streambuf> +#include <sstream> +#include <map> + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +TrigMonTHistSvc::TrigMonTHistSvc( const std::string& name, ISvcLocator* svc ) + : THistSvcHLT(name, svc), + AthMessaging(msgSvc(), name), + m_add(true), + m_excludeType("()"), + m_includeType(".+"), + m_excludeName(".*\\..*"), + m_includeName("^/((run_[0-9]+/lb_[0-9]+/LB)|(SHIFT)|(EXPERT)|(DEBUG)|(EXPRESS)|(RUNSTAT))/.+/.+") { + //m_includeName("^/((SHIFT)|(EXPERT)|(DEBUG)|(RUNSTAT))/.+/.+") { + declareProperty("SumUpHistograms", m_add, "In multi-threaded application decides to publish separate histograms for each thread or sum them up before publishing."); + declareProperty("ExcludeType", m_excludeType); + declareProperty("IncludeType", m_includeType); + declareProperty("ExcludeName", m_excludeName); + declareProperty("IncludeName", m_includeName); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +TrigMonTHistSvc::~TrigMonTHistSvc() { + +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TrigMonTHistSvc::queryInterface(const InterfaceID & riid, + void **ppvInterface) { + return THistSvcHLT::queryInterface(riid, ppvInterface); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TrigMonTHistSvc::initialize() { + + CHECK(THistSvcHLT::initialize()); + CHECK(setProperties()); + + AthMessaging::msg().setLevel(outputLevel()); + // fix summing up flag if not running in separate threads + if ( ! isGaudiThreaded(name()) ) + m_add = true; + + // Protect against multiple instances of TROOT + if ( 0 == gROOT ) { + static TROOT root("root","ROOT I/O"); + + } else { + ATH_MSG_VERBOSE("ROOT already initialized, debug = " << gDebug); + } + gErrorIgnoreLevel=kBreak; // ignore warnings see TError.h in ROOT base src + + // compile regexes + m_excludeTypeRegex = boost::regex(m_excludeType); + m_includeTypeRegex = boost::regex(m_includeType); + m_excludeNameRegex = boost::regex(m_excludeName); + m_includeNameRegex = boost::regex(m_includeName); + + // Retrieve and set OH mutex + ATH_MSG_INFO("Enabling use of OH histogram mutex"); + lock_histogram_mutex::set_histogram_mutex( + hltinterface::IInfoRegister::instance()->getPublicationMutex()); + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TrigMonTHistSvc::reinitialize() { + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TrigMonTHistSvc::finalize() { + + // Reset OH mutex + ATH_MSG_DEBUG("Resetting OH histogram mutex"); + lock_histogram_mutex::reset_histogram_mutex(); + + std::stringstream f; + hltinterface::IInfoRegister::THList thlist; + hltinterface::IInfoRegister::instance()->get(".*", thlist); + hltinterface::IInfoRegister::THList::iterator lIter; + // just listing + for ( lIter = thlist.begin() ; lIter != thlist.end(); ++lIter ){ + ATH_MSG_INFO("Histogram " << lIter->first << " "); + } + return StatusCode::SUCCESS; +} + + +StatusCode TrigMonTHistSvc::regHist(const std::string& id) { + ATH_MSG_DEBUG("registering histogram: " << id << " to get it"); + return THistSvcHLT::regHist(id); +} + +StatusCode TrigMonTHistSvc::regHist(const std::string& id, TH1* hist) { + return regHist_i(hist, id); +} + +StatusCode TrigMonTHistSvc::regHist(const std::string& id, TH2* hist) { + return regHist_i(hist, id); +} + +StatusCode TrigMonTHistSvc::regHist(const std::string& id, TH3* hist) { + return regHist_i(hist, id); +} + +StatusCode TrigMonTHistSvc::regTree(const std::string& id) { + return THistSvcHLT::regTree(id); +} + +StatusCode TrigMonTHistSvc::regTree(const std::string&, TTree* hist) { + // we do not support the trees; then let's make them not to be memory consumers + ATH_MSG_WARNING("The ROOT TTree is not supported by this service" + << " TTree \"" << hist->GetName() << "\" will be unsaved but will not consume all memory as well" + ); + hist->SetCircular(1); + return StatusCode::SUCCESS; +} + +StatusCode TrigMonTHistSvc::getHist(const std::string& id, TH1*& hist) const { + return THistSvcHLT::getHist(id, hist); +} + + +StatusCode TrigMonTHistSvc::getHist(const std::string& id, TH2*& hist) const { + return THistSvcHLT::getHist(id, hist); +} + + +StatusCode TrigMonTHistSvc::getHist(const std::string& id, TH3*& hist) const { + return THistSvcHLT::getHist(id, hist); +} + +StatusCode TrigMonTHistSvc::getTree(const std::string& id, TTree*& hist) const { + return THistSvcHLT::getTree(id, hist); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Needs proper implementation +// +StatusCode TrigMonTHistSvc::regGraph(const std::string& id) { + return THistSvcHLT::regGraph(id); +} + +StatusCode TrigMonTHistSvc::regGraph(const std::string&, TGraph*) { + ATH_MSG_WARNING("The regGraph is not suported by this service"); + return StatusCode::SUCCESS; +} + +StatusCode TrigMonTHistSvc::getGraph(const std::string& id, TGraph*& g) const { + return THistSvcHLT::getGraph(id, g); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +template <typename T> StatusCode TrigMonTHistSvc::regHist_i(T* hist, const std::string& id) { + + std::string regid; + if ( isObjectAllowed(id, hist).isFailure() ) { + return StatusCode::FAILURE; + } + // prepend by service name if the histograms are not going to be added + // this way they are registered under different unique names + // from each service + if ( m_add ) + regid = id; + else { + std::string n = getGaudiThreadIDfromName(name()); + + // strip blanks at the end of service name + std::string::size_type pos; + while ( (pos = n.find('\0', 0)) != std::string::npos) + n.erase(pos,1); + // build the name used for registration + regid = id+n; + } + + if (hist->Class()->InheritsFrom(TH1::Class())) { + hltinterface::IInfoRegister::instance()->registerTObject(name(), regid, hist); + ATH_MSG_DEBUG("Histogram " << hist->GetName() + << " registered under " << regid << " " << m_add << " " << name()); + } else { + ATH_MSG_ERROR("Trying to register " << hist->ClassName() + << " but this does not inherit from TH1 histogram"); + return StatusCode::SUCCESS; + } + return StatusCode::SUCCESS; +} + +StatusCode TrigMonTHistSvc::deReg(TObject* optr) { + + std::map<std::string, std::vector<TObject*> > allObjs; + std::map<std::string, std::vector<TObject*> >::const_iterator mapIt; + hltinterface::IInfoRegister::instance()->getUnsummed(".+", allObjs); + + // we need now to loop over all this histograms and find if the + for ( mapIt = allObjs.begin(); mapIt != allObjs.end(); ++mapIt ) { + for (std::vector<TObject*>::const_iterator tIt = mapIt->second.begin(); tIt != mapIt->second.end(); ++tIt ) { + if ( optr == *tIt ) { + ATH_MSG_DEBUG("Found histogram by pointer " << optr << " booked under " + << mapIt->first << " will deregister it"); + return deReg(mapIt->first); + } + } + } + return StatusCode::FAILURE; +} + +StatusCode TrigMonTHistSvc::deReg(const std::string& id ) { + + hltinterface::IInfoRegister::instance()->releaseTObject(name(), id); + ATH_MSG_DEBUG("Deregistration of " << id << " done"); + return StatusCode::SUCCESS; +} + +std::vector<std::string> TrigMonTHistSvc::getHists() const { + std::vector<std::string> l = THistSvcHLT::getHists(); // we need to update the list by objects holded by offline SVC + + hltinterface::IInfoRegister::THList thlist; + hltinterface::IInfoRegister::instance()->get(".+", thlist); + hltinterface::IInfoRegister::THList::iterator lIter; + + l.reserve(l.size()+thlist.size()); + for ( lIter = thlist.begin() ; lIter != thlist.end(); ++lIter ){ + l.push_back(lIter->first); // by ones from online + } + return l; +} + + +std::vector<std::string> TrigMonTHistSvc::getTrees() const { + + // we do not keep TTrees + ATH_MSG_DEBUG("TTres not suported by this implementation"); + std::vector<std::string> l; + return l; +} + + +StatusCode TrigMonTHistSvc::getTHists(TDirectory *td, TList &tl) const { + return getTHists_i(std::string(td->GetPath()), tl); +} + +StatusCode TrigMonTHistSvc::getTHists(const std::string& dir, TList &tl) const { + return getTHists_i(dir, tl); +} + + +StatusCode TrigMonTHistSvc::getTTrees(TDirectory *, TList &) const { + // we do not have TTrees + ATH_MSG_DEBUG("TTres not suported by this implementation"); + return StatusCode::SUCCESS; +} + +StatusCode TrigMonTHistSvc::getTTrees(const std::string&, TList &) const { + // we do not have TTrees + ATH_MSG_DEBUG("TTres not suported by this implementation"); + return StatusCode::SUCCESS; +} + + +// +//========================================================================== +// internal methods +//========================================================================== +// +StatusCode TrigMonTHistSvc::isObjectAllowed(std::string path, const TObject *o) { + + boost::cmatch what; + + if ( ! boost::regex_match(o->ClassName(), + what, m_includeTypeRegex) ) { + ATH_MSG_WARNING("Object " << path + << " of type " << o->ClassName() + << " does NOT match IncludeTypeRegex \"" + << m_includeType << "\""); + return StatusCode::FAILURE; + } + + if ( boost::regex_match(o->ClassName(), + what, m_excludeTypeRegex) ) { + ATH_MSG_WARNING("Object " << path + << " of type " << o->ClassName() + << " matches ExcludeTypeRegex \"" + << m_excludeType << "\""); + return StatusCode::FAILURE; + } + + if ( ! boost::regex_match(path.c_str(), what, m_includeNameRegex) ) { + ATH_MSG_WARNING("Object " << path + << " does NOT match IncludeNameRegex \"" + << m_includeName << "\""); + return StatusCode::FAILURE; + } + + if ( boost::regex_match(path.c_str(), what, m_excludeNameRegex) ) { + ATH_MSG_WARNING("Object " << path + << " matches ExcludeNameRegex \"" + << m_excludeName << "\""); + return StatusCode::FAILURE; + } + // temp hack + return StatusCode::SUCCESS; + +} + +StatusCode TrigMonTHistSvc::getTHists_i(const std::string& dir, TList &tl) const { + hltinterface::IInfoRegister::THList thlist; + hltinterface::IInfoRegister::instance()->get(".+", thlist); + hltinterface::IInfoRegister::THList::iterator lIter; + + std::vector<std::string> l; + for ( lIter = thlist.begin() ; lIter != thlist.end(); ++lIter ){ + if ( lIter->first.find(dir) == 0 ) { + // histogram booking path starts from the dir + tl.Add(lIter->second); + } + } + return StatusCode::SUCCESS; +} + +// +//========================================================================== +// Declarations to avoid compiler warning about hidden methods +//========================================================================== +// + +StatusCode TrigMonTHistSvc::getTHists(TDirectory *td, TList &tl, bool recurse) const { + if (recurse != false) + ATH_MSG_DEBUG("Recursive flag is not supported in this implementation"); + return getTHists_i(std::string(td->GetPath()), tl); +} + +StatusCode TrigMonTHistSvc::getTHists(const std::string& dir, TList &tl, bool recurse) const { + if (recurse != false) + ATH_MSG_DEBUG("Recursive flag is not supported in this implementation"); + return getTHists_i(dir, tl); +} + +StatusCode TrigMonTHistSvc::getTHists(TDirectory *td, TList &tl, bool recurse, bool reg) { + if ((recurse != false) || (reg != false)) + ATH_MSG_DEBUG("Recursive flag and automatic registration flag is not supported in this implementation"); + return getTHists_i(std::string(td->GetPath()), tl); +} + +StatusCode TrigMonTHistSvc::getTHists(const std::string& dir, TList &tl, bool recurse, bool reg) { + if ((recurse != false) || (reg != false)) + ATH_MSG_DEBUG("Recursive flag and automatic registration flag is not supported in this implementation"); + return getTHists_i(dir, tl); +} + +StatusCode TrigMonTHistSvc::getTTrees(TDirectory *, TList &, bool) const { + // we do not have TTrees + ATH_MSG_DEBUG("TTres not suported by this implementation"); + return StatusCode::SUCCESS; +} +StatusCode TrigMonTHistSvc::getTTrees(const std::string&, TList &, bool) const { + // we do not have TTrees + ATH_MSG_DEBUG("TTres not suported by this implementation"); + return StatusCode::SUCCESS; +} +StatusCode TrigMonTHistSvc::getTTrees(TDirectory *, TList &, bool, bool) { + // we do not have TTrees + ATH_MSG_DEBUG("TTres not suported by this implementation"); + return StatusCode::SUCCESS; +} +StatusCode TrigMonTHistSvc::getTTrees(const std::string&, TList &, bool, bool) { + // we do not have TTrees + ATH_MSG_DEBUG("TTres not suported by this implementation"); + return StatusCode::SUCCESS; +} + +bool TrigMonTHistSvc::exists( const std::string& name ) const { + return THistSvcHLT::exists(name); +} diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h new file mode 100644 index 00000000000..44747c4fca6 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h @@ -0,0 +1,134 @@ +// -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGMONTHISTSVC_THISTSVC_H +#define TRIGMONTHISTSVC_THISTSVC_H + + +/** + * @file TrigMonTHistSvc.h + * @author Tomasz Bold + * @date 2005-09-27 + * @brief The HLT histogramming service + * It forwards histograms to the monitoring infrastructure. + */ + + +#include "GaudiKernel/Service.h" +#include "THistSvcHLT.h" +#include "AthenaBaseComps/AthMessaging.h" + +class TObject; +class TH1; +class TH2; +class TH3; +class TGraph; +class TTree; + +#include <vector> +#include <string> + +#include <boost/regex.hpp> + +// Forward declarations +template <class TYPE> class SvcFactory; + +class TrigMonTHistSvc: virtual public THistSvcHLT, + public AthMessaging +{ +public: + + // fwd compat w/ gaudi-21 + using AthMessaging::msg; + + // implemenataion of the interface from TrigNetTHistSvc + virtual StatusCode initialize(); + virtual StatusCode reinitialize(); + virtual StatusCode finalize(); + + // Query the interfaces. + virtual StatusCode queryInterface( const InterfaceID& riid, + void** ppvInterface ); + + + virtual StatusCode regHist(const std::string& name); + virtual StatusCode regHist(const std::string& name, TH1*); + virtual StatusCode regHist(const std::string& name, TH2*); + virtual StatusCode regHist(const std::string& name, TH3*); + + virtual StatusCode getHist(const std::string& name, TH1*&) const; + virtual StatusCode getHist(const std::string& name, TH2*&) const; + virtual StatusCode getHist(const std::string& name, TH3*&) const; + + virtual StatusCode regTree(const std::string& name); + virtual StatusCode regTree(const std::string& name, TTree*); + virtual StatusCode getTree(const std::string& name, TTree*&) const; + + // new since Gaudi 0.16.1.11 + virtual StatusCode deReg(TObject* obj); //<! very slow + virtual StatusCode deReg(const std::string& name); //<! use this instead + + virtual std::vector<std::string> getHists() const; + virtual std::vector<std::string> getTrees() const; + + virtual StatusCode getTHists(TDirectory *td, TList &) const; + virtual StatusCode getTHists(const std::string& name, TList &) const; + + virtual StatusCode getTTrees(TDirectory *td, TList &) const; + virtual StatusCode getTTrees(const std::string& name, TList &) const; + + // new since Gaudi 19 + virtual StatusCode regGraph(const std::string& name); + virtual StatusCode regGraph(const std::string& name, TGraph*); + virtual StatusCode getGraph(const std::string& name, TGraph*&) const; + + TrigMonTHistSvc(const std::string& name, ISvcLocator *svc ); + + // new since Gaudi 20 + + virtual StatusCode getTHists(TDirectory *td, TList &, + bool recurse=false) const; + virtual StatusCode getTHists(const std::string& name, TList &, + bool recurse=false) const; + virtual StatusCode getTHists(TDirectory *td, TList &tl, + bool recurse=false, bool reg=false); + virtual StatusCode getTHists(const std::string& name, TList &tl, + bool recurse=false, bool reg=false); + + virtual StatusCode getTTrees(TDirectory *td, TList &, + bool recurse=false) const; + virtual StatusCode getTTrees(const std::string& name, TList &, + bool recurse=false) const; + virtual StatusCode getTTrees(TDirectory *td, TList & tl, + bool recurse=false, bool reg=false); + virtual StatusCode getTTrees(const std::string& name, TList & tl, + bool recurse=false, bool reg=false); + + virtual bool exists(const std::string& name) const; + +protected: + StatusCode isObjectAllowed(std::string path, const TObject *o); + + StatusCode getTHists_i(const std::string& name, TList &) const; + + virtual ~TrigMonTHistSvc(); + +private: + template <typename T> + StatusCode regHist_i(T* hist, const std::string& name); + bool m_add; + std::string m_excludeType; + std::string m_includeType; + std::string m_excludeName; + std::string m_includeName; + // compiled regexes + boost::regex m_excludeTypeRegex; + boost::regex m_includeTypeRegex; + boost::regex m_excludeNameRegex; + boost::regex m_includeNameRegex; +}; + +#endif // TRIGMONTHISTSVC_THISTSVC_H diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.cxx new file mode 100644 index 00000000000..99ed9f88f50 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.cxx @@ -0,0 +1,87 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file TrigPreFlightCheck.cxx + * @brief Does some generic checks to make sure we can run the HLT + * @author Frank Winklmeier + * + * $Id: TrigPreFlightCheck.cxx 5 2013-05-14 10:33:04Z ricab $ + */ + +#include "TrigPreFlightCheck.h" + +#include <boost/tokenizer.hpp> +#include <boost/filesystem.hpp> + +#include <stdlib.h> + +using namespace std; +namespace fs = boost::filesystem; + +//========================================================================= +// Standard methods +//========================================================================= +TrigPreFlightCheck::TrigPreFlightCheck(const std::string &type, + const std::string &name, + const IInterface *parent) + : AthAlgTool(type, name, parent) +{ + // No abstract interface + declareInterface<TrigPreFlightCheck>(this); + + declareProperty("ReleaseDirs", + m_releaseDirs, + "Directories within LD_LIBRARY_PATH to check for existence"); +} + + +TrigPreFlightCheck::~TrigPreFlightCheck() +{} + + +StatusCode TrigPreFlightCheck::initialize() +{ + return StatusCode::SUCCESS; +} + +StatusCode TrigPreFlightCheck::check(const MSG::Level& errLvl) +{ + // Only one check so far + return checkRelease(errLvl); +} + + +StatusCode TrigPreFlightCheck::checkRelease(const MSG::Level& errLvl) +{ + const char* ld_lib_path = getenv("LD_LIBRARY_PATH"); + if ( ld_lib_path==0 ) { + msg() << errLvl << "Cannot read LD_LIBRARY_PATH" << endreq; + return StatusCode::FAILURE; + } + + typedef boost::tokenizer<boost::char_separator<char> > Tokenizer; + string s(ld_lib_path); + Tokenizer tok(s, boost::char_separator<char>(":")); + + // Loop over elements of LD_LIBRARY_PATH + for (Tokenizer::iterator it = tok.begin(); it!=tok.end(); ++it) { + + // Loop over directories to check + for (vector<string>::const_iterator dir = m_releaseDirs.begin(); + dir != m_releaseDirs.end(); ++dir) { + + if ( it->find(*dir)!=string::npos ) { + if ( fs::exists(*it) ) { + msg() << MSG::DEBUG << "Checking " << (*it) << ": OK" << endreq; + } + else { + msg() << errLvl << (*it) << " does not exist" << endreq; + return StatusCode::FAILURE; + } + } + } + } + return StatusCode::SUCCESS; +} diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.h new file mode 100644 index 00000000000..21e5f8c893b --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGSERVICES_TRIGPREFLIGHTCHECK_H +#define TRIGSERVICES_TRIGPREFLIGHTCHECK_H +/** + * @file TrigPreFlightCheck.h + * @brief Does some generic checks to make sure we can run the HLT + * @author Frank Winklmeier + * + * $Id: TrigPreFlightCheck.h 5 2013-05-14 10:33:04Z ricab $ + */ + +// STL includes +#include <string> +#include <vector> + +// Framework includes +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/StatusCode.h" + +/** + * @brief Tool to do some basic checks ensuring the HLT is usable + * + * The tool has several checkXYZ() methods each returning a StatusCode for + * the specific check it is doing. In addition, the check() method performs + * all the checks and returns the logical AND of the individual checks. + */ +class TrigPreFlightCheck : public AthAlgTool { + +public: + + TrigPreFlightCheck(const std::string &type, const std::string &name, const IInterface *parent); + virtual ~TrigPreFlightCheck(); + + static const InterfaceID& interfaceID(); + virtual StatusCode initialize(); + + /** + * @brief Check whether the relase is installed properly + * + * @param errLvl Message level used for failure messages + * @return SUCCESS Release properly installed + * FAILURE Some parts of the release is missing + */ + StatusCode checkRelease(const MSG::Level& errLvl); + + /** + * @brief Perform all checks + * + * @param errLvl Message level used for failure messages + * @return SUCCESS All checks OK + * FAILURE At least one check failed + */ + StatusCode check(const MSG::Level& errLvl); + +private: + /** Directories to check for existence in checkRelease() */ + std::vector<std::string> m_releaseDirs; +}; + + +inline const InterfaceID& TrigPreFlightCheck::interfaceID() +{ + static const InterfaceID _IID("TrigPreFlightCheck", 1, 0); + return _IID; +} + +#endif diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx new file mode 100644 index 00000000000..ae00dfb92fe --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx @@ -0,0 +1,253 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file TrigSORFromPtreeHelper.cxx + * @author Ricardo Abreu + * + * @brief Helper class to retrieve the Start Of Run parameters from the + * prepareForRun ptree and put them into the detector store with whole-run + * validity. This class replaces it's old analogous TrigSORFromISHelper. + */ + +#include "TrigSORFromPtreeHelper.h" +#include "AthenaKernel/IIOVDbSvc.h" +#include "AthenaKernel/IAddressProvider.h" +#include "owl/time.h" +#include <eformat/DetectorMask.h> + +#define ST_WHERE CLNAME << "::" << __func__ << "(): " + +using namespace boost::property_tree; +using std::string; +using SORHelper = TrigSORFromPtreeHelper; + +namespace +{ + ////////////////////////////////////////////////////////////////////////////// + const string CLNAME{"TrigSORFromPtreeHelper"}; + const string SORPATH{"/TDAQ/RunCtrl/SOR_Params"}; + + ////////////////////////////////////////////////////////////////////////////// + void printSOR(MsgStream& log, const SORHelper::SOR * sor) + { + log << MSG::DEBUG << ST_WHERE + << "Dump SOR CondAttrListCollection: size=" << sor->size() << endreq; + sor->dump(); + } + + ////////////////////////////////////////////////////////////////////////////// + void setSpec(coral::AttributeListSpecification * attrSpec) + { + attrSpec->extend("RunNumber", "unsigned int"); + attrSpec->extend("SORTime", "unsigned long long"); + attrSpec->extend("RunType", "string"); + attrSpec->extend("DetectorMaskFst", "unsigned long long"); + attrSpec->extend("DetectorMaskSnd", "unsigned long long"); + attrSpec->extend("RecordingEnabled", "bool"); + } +} + +//////////////////////////////////////////////////////////////////////////////// +const SORHelper::SOR * SORHelper::fillSOR(const ptree & rparams) const +{ + m_log << MSG::DEBUG << ST_WHERE << "Setup SOR in DetectorStore" << endreq; + SG dstore("DetectorStore", CLNAME); + if((dstore.retrieve()).isFailure()) + m_log << MSG::ERROR << ST_WHERE << "could not find DetectorStore" << endreq; + + // get handle to the IOVDbSvc + ServiceHandle<IIOVDbSvc> iovdbsvc("IOVDbSvc", CLNAME); + if ((iovdbsvc.retrieve()).isFailure()) { + m_log << MSG::ERROR << ST_WHERE + << "could not find IOVDbSvc. Time dependent conditions data may be not properly handled." << endreq; + } else { + IOVTime currentIOVTime(rparams.get<unsigned int>("run_number"), + IOVTime::MINEVENT, + OWLTime{(rparams.get_child("timeSOR").data()).c_str()}.total_mksec_utc() * 1000); + + // Signal BeginRun directly to IOVDbSvc to set complete IOV start time + if (StatusCode::SUCCESS != iovdbsvc->signalBeginRun(currentIOVTime)) { + m_log << MSG::ERROR << ST_WHERE + << "Unable to signal begin run IOVTime to IOVDbSvc. IOVTime = " << currentIOVTime << endreq; + } else { + m_log << MSG::DEBUG << ST_WHERE + << "Set start of run time to IOVTime = " << currentIOVTime << endreq; + } + } + + auto sor = getSOR(dstore); + if(!sor || fillSor(rparams, sor).isFailure() || + updateProxy(dstore, sor).isFailure()) + { + m_log << MSG::ERROR << ST_WHERE << "could not properly setup SOR" << endreq; + return nullptr; + } + + m_log << MSG::DEBUG << ST_WHERE << "successfully setup SOR" << endreq; + printSOR(m_log, sor); + + return sor; +} + +//////////////////////////////////////////////////////////////////////////////// +SORHelper::SOR * SORHelper::getSOR(const SG & dstore) const +{ + auto sc = StatusCode{}; + auto sor = new SOR(true); + if(dstore->transientContains<SOR>(SORPATH)) + { + const SOR * oldsor = dstore->retrieve<const SOR>(SORPATH); + m_log << MSG::INFO << ST_WHERE + << "overwriting SOR contents (a dump of the old one follows)"<<endreq; + printSOR(m_log, oldsor); + sc = dstore->overwrite(sor, SORPATH, true); + } + else + { + m_log << MSG::INFO << ST_WHERE << "recording new SOR" << endreq; + sc = dstore->record(sor, SORPATH, true); + } + + if(sc.isFailure()) + { + m_log << MSG::ERROR << ST_WHERE + << "could not record SOR in DetectorStore\n" << dstore->dump() + << endreq; + delete sor; + sor = nullptr; + } + + return sor; +} + + +//////////////////////////////////////////////////////////////////////////////// +coral::AttributeList SORHelper::getAttrList(const ptree& rparams) const +{ + // First create attribute specification + // ugly new needed: + // dtor is protected, have to use ptr and release it explicitly... go figure + auto attrSpec = new coral::AttributeListSpecification{}; + setSpec(attrSpec); + + // now create the attribute list and fill it in + coral::AttributeList attrList(*attrSpec); + + attrList["RunNumber"].data<unsigned int>() = + rparams.get<unsigned int>("run_number"); + attrList["RunType"].data<string>() = + rparams.get<string>("run_type"); + attrList["RecordingEnabled"].data<bool>() = + rparams.get<bool>("recording_enabled"); + + const auto& t = rparams.get_child("timeSOR").data(); + attrList["SORTime"].data<unsigned long long>() = + OWLTime{t.c_str()}.total_mksec_utc() * 1000; + + auto dm = getDetMask(rparams); + attrList["DetectorMaskFst"].data<unsigned long long>() = dm.first; + attrList["DetectorMaskSnd"].data<unsigned long long>() = dm.second; + + // coral wants us to have to do this explicitly... + attrSpec->release(); // we don't delete because the dtor is private + // we have to hope the CORAL framework will + + return attrList; +} + +//////////////////////////////////////////////////////////////////////////////// +std::pair<uint64_t, uint64_t> +SORHelper::getDetMask(const ptree& rparams) const +{ + const auto& dmstr = rparams.get_child("det_mask").data(); + return eformat::helper::DetectorMask(dmstr).serialize(); +} + +//////////////////////////////////////////////////////////////////////////////// +StatusCode SORHelper::fillSor(const ptree & rparams, SOR * sor) const +{ + // obtain SOR contents from ptree + auto attrList = getAttrList(rparams); + + // Validity stuff + IOVTime iovTimeStart(attrList["RunNumber"].data<unsigned int>() ,0); + IOVTime iovTimeStop(attrList["RunNumber"].data<unsigned int>()+1,0); + IOVRange iovRange(iovTimeStart, iovTimeStop); + auto channum = SOR::ChanNum{0}; + + sor->add(channum, attrList); + sor->add(channum,iovRange); + sor->resetMinRange(); + sor->addNewStart(iovTimeStart); + sor->addNewStop(iovTimeStop); + + return setIOVRange(iovRange); +} + +//////////////////////////////////////////////////////////////////////////////// +StatusCode SORHelper::setIOVRange(IOVRange & iovRange) const +{ + // set IOVRange on the IOVSvc + ServiceHandle<IIOVSvc> iovsvc("IOVSvc", CLNAME); + if ((iovsvc.retrieve()).isFailure()) + { + m_log << MSG::ERROR << ST_WHERE << "could not find IOVSvc" << endreq; + return StatusCode::FAILURE; + } + + auto clid = ClassID_traits<SOR>::ID(); + if ((iovsvc->setRange(clid, SORPATH, iovRange, "StoreGateSvc")).isFailure()) + { + m_log << MSG::ERROR << ST_WHERE + << "could not set IOVRange for SOR folder in IOVSvc." << endreq; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +//////////////////////////////////////////////////////////////////////////////// +StatusCode +SORHelper::updateProxy(const SG & dstore, SOR * sor) const +{ + // check the SOR_Params proxy and add if necessary an IAddressProvider + //(typically for MC) + auto proxy = dstore->proxy(sor); + if (!proxy) { + m_log << MSG::ERROR << ST_WHERE + << "could not find proxy for SOR_Params folder." << endreq; + return StatusCode::FAILURE; + } + + auto transientAddr = proxy->transientAddress(); + if (!transientAddr) { + m_log << MSG::ERROR << ST_WHERE + << "could not find transient address for SOR_Params folder" << endreq; + return StatusCode::FAILURE; + } + + // check if the transient address has an IAddressProvider, if not set + //IOVDbSvc as provider + if (!transientAddr->provider()) { + // get handle to the IOVDbSvc + ServiceHandle<IIOVDbSvc> iovdbsvc("IOVDbSvc", CLNAME); + if ((iovdbsvc.retrieve()).isFailure()) { + m_log << MSG::ERROR << ST_WHERE << "could not find IOVDbSvc." << endreq; + return StatusCode::FAILURE; + } + + IAddressProvider* provider = dynamic_cast<IAddressProvider*>(&*iovdbsvc); + if (!provider) { + m_log << MSG::ERROR << ST_WHERE + << "could not cast to IAddressProvider interface and set the " + "provider for SOR_Params." << endreq; + return StatusCode::FAILURE; + } + transientAddr->setProvider(provider, transientAddr->storeID()); + } + + return StatusCode::SUCCESS; +} + diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.h new file mode 100644 index 00000000000..d32a297f27a --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file TrigSORFromPtreeHelper.h + * @author Ricardo Abreu + * + * @brief Helper class to retrieve the Start Of Run parameters from the + * prepareForRun ptree and put them into the detector store with whole-run + * validity. This class replaces it's old analogous TrigSORFromISHelper. + */ + +#ifndef TRIGSORFROMPTREEHELPER_H_ +#define TRIGSORFROMPTREEHELPER_H_ + +#include "AthenaPoolUtilities/CondAttrListCollection.h" +#include "StoreGate/StoreGateSvc.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/ServiceHandle.h" +#include <boost/property_tree/ptree.hpp> +#include <utility> + +class CondAttrListCollection; + +//////////////////////////////////////////////////////////////////////////////// +class TrigSORFromPtreeHelper +{ +public: + typedef CondAttrListCollection SOR; + + TrigSORFromPtreeHelper(const MsgStream & log); + + /* + * Fill SOR record in Detector Store, reusing if present or creating new one + * otherwise. SOR contents filled according to what is specified by rparams. + * Validity of SOR set to this run + */ + const SOR * fillSOR(const boost::property_tree::ptree & rparams) const; + +private: + typedef ServiceHandle<StoreGateSvc> SG; + typedef boost::property_tree::ptree PT; + + SOR * getSOR(const SG & dstore) const; + coral::AttributeList getAttrList(const PT & rparams) const; + std::pair<uint64_t, uint64_t> getDetMask(const PT & rparams) const; + + StatusCode fillSor(const PT & rparams, SOR * sor) const; + StatusCode setIOVRange(IOVRange & iovRange) const; + StatusCode updateProxy(const SG & dstore, SOR * sor) const; + + mutable MsgStream m_log; +}; + +//////////////////////////////////////////////////////////////////////////////// +inline TrigSORFromPtreeHelper:: +TrigSORFromPtreeHelper(const MsgStream & log) + : m_log(log) +{ +} + + +#endif /* TRIGSORFROMPTREEHELPER_H_ */ diff --git a/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_entries.cxx b/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_entries.cxx new file mode 100644 index 00000000000..cde6e20dfa0 --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_entries.cxx @@ -0,0 +1,30 @@ +#include "GaudiKernel/DeclareFactoryEntries.h" +#include "TrigServices/TrigMessageSvc.h" +#include "../TrigMonTHistSvc.h" +#include "TrigServices/HltEventLoopMgr.h" +#include "TrigServices/HltROBDataProviderSvc.h" +#include "TrigServices/TrigIS.h" +#include "TrigServices/TrigISHelper.h" +#include "../TrigPreFlightCheck.h" +#include "../TrigCOOLUpdateHelper.h" + +DECLARE_SERVICE_FACTORY( TrigMessageSvc ) +DECLARE_SERVICE_FACTORY( TrigMonTHistSvc ) +DECLARE_SERVICE_FACTORY( TrigIS ) +DECLARE_SERVICE_FACTORY( HltEventLoopMgr ) +DECLARE_SERVICE_FACTORY( HltROBDataProviderSvc ) +DECLARE_TOOL_FACTORY( TrigISHelper ) +DECLARE_TOOL_FACTORY( TrigPreFlightCheck ) +DECLARE_TOOL_FACTORY( TrigCOOLUpdateHelper ) + + +DECLARE_FACTORY_ENTRIES( TrigServices ) { + DECLARE_SERVICE( TrigMessageSvc ); + DECLARE_SERVICE( TrigMonTHistSvc ); + DECLARE_SERVICE( TrigIS ); + DECLARE_SERVICE( HltEventLoopMgr ); + DECLARE_SERVICE( HltROBDataProviderSvc ); + DECLARE_TOOL( TrigISHelper ); + DECLARE_TOOL( TrigPreFlightCheck ); + DECLARE_TOOL( TrigCOOLUpdateHelper ); +} diff --git a/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_load.cxx b/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_load.cxx new file mode 100644 index 00000000000..0e7b58ee4de --- /dev/null +++ b/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_load.cxx @@ -0,0 +1,3 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES( TrigServices ) -- GitLab