From 7a56ffb9fff710ecee5de69f108eeddb3f281b98 Mon Sep 17 00:00:00 2001
From: Aleksandra Poreba <aleksandra.poreba@cern.ch>
Date: Mon, 9 Nov 2020 19:57:15 +0000
Subject: [PATCH] Add ROS caching in TrigCostMonitorMT

---
 .../TrigControl/TrigServices/CMakeLists.txt   |  2 +-
 .../src/HltROBDataProviderSvc.cxx             | 15 +++++
 .../TrigServices/src/HltROBDataProviderSvc.h  |  8 +++
 .../TrigCostMonitorMT/CMakeLists.txt          |  2 +-
 .../TrigCostMonitorMT/ITrigCostMTSvc.h        | 12 +++-
 .../TrigCostMonitorMT/src/TrigCostDataStore.h | 11 ++-
 .../src/TrigCostDataStore.icc                 | 21 +++++-
 .../TrigCostMonitorMT/src/TrigCostMTSvc.cxx   | 67 ++++++++++++++++---
 .../TrigCostMonitorMT/src/TrigCostMTSvc.h     | 19 ++++--
 .../src/DecisionSummaryMakerAlg.cxx           |  6 +-
 .../src/DecisionSummaryMakerAlg.h             |  5 +-
 .../TrigEDMConfig/python/TriggerEDMRun3.py    |  2 +
 12 files changed, 147 insertions(+), 23 deletions(-)

diff --git a/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt b/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt
index 3bcc59c935c..2228ea3f250 100644
--- a/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt
+++ b/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt
@@ -22,7 +22,7 @@ atlas_add_component( TrigServices
                      ${TDAQ-COMMON_LIBRARIES} ${TDAQ_LIBRARIES} ${CORAL_LIBRARIES}
                      AthenaBaseComps AthenaInterprocess AthenaKernel AthenaMonitoringKernelLib AthenaPoolUtilities
                      ByteStreamCnvSvcBaseLib ByteStreamData EventInfoUtils GaudiKernel RDBAccessSvcLib StoreGateLib TrigKernel
-                     TrigOutputHandlingLib TrigSteeringEvent TrigSteerMonitorLib xAODEventInfo xAODTrigger )
+                     TrigDataAccessMonitoringLib TrigOutputHandlingLib TrigSteeringEvent TrigSteerMonitorLib xAODEventInfo xAODTrigger )
 
 # Install files from the package:
 atlas_install_python_modules( python/*.py
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx
index a9d7030af49..8e05cc2711e 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx
+++ b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx
@@ -143,6 +143,8 @@ StatusCode HltROBDataProviderSvc::initialize()
   // Retrieve the monitoring tool
   if (!m_monTool.empty()) ATH_CHECK(m_monTool.retrieve());
 
+  if (m_doCostMonitoring) ATH_CHECK(m_trigCostSvcHandle.retrieve());
+
   return(StatusCode::SUCCESS);
 }
 
@@ -327,6 +329,19 @@ void HltROBDataProviderSvc::getROBData(const EventContext& context,
   // check input ROB list against cache
   eventCache_checkRobListToCache(cache, robIds, robFragments, robIds_missing) ;
 
+  // check if event should be monitored
+  if (m_doCostMonitoring && m_trigCostSvcHandle->isMonitoredEvent(context, /*includeMultiSlot =*/ false)) {
+
+    for (const uint32_t id : robIds) {
+      auto ROBData = robmonitor::ROBDataStruct(id);
+
+      if (m_trigCostSvcHandle->monitorROS(context, std::move(ROBData)).isFailure()) {
+        ATH_MSG_WARNING("TrigCost ROS monitoring failed!");
+      }
+    }
+  }
+
+
   // no missing ROB fragments, return the found ROB fragments 
   if (robIds_missing.size() == 0) {
     ATH_MSG_DEBUG( __FUNCTION__ << ": All requested ROB Ids were found in the cache. "); 
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.h b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.h
index 1a526c415c4..ea7aac93832 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.h
+++ b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.h
@@ -18,6 +18,8 @@
 #include "AthenaBaseComps/AthService.h"
 #include "AthenaKernel/SlotSpecificObj.h"
 #include "AthenaMonitoringKernel/Monitored.h"
+#include "TrigCostMonitorMT/ITrigCostMTSvc.h"
+#include "TrigDataAccessMonitoring/ROBDataMonitor.h"
 
 // STL includes
 #include <string>
@@ -165,6 +167,12 @@ private:
   Gaudi::Property<bool> m_prefetchAllROBsfromROS{
     this, "prefetchAllROBsfromROS", false , "When ROBs from a ROS are requested then prefetch all ROBs in this ROS"};
 
+  Gaudi::Property<bool> m_doCostMonitoring{
+    this, "DoCostMonitoring", true, "Enables start-of-event cost monitoring behavior."};
+
+  ServiceHandle<ITrigCostMTSvc> m_trigCostSvcHandle{ 
+    this, "TrigCostMTSvc", "TrigCostMTSvc", "The trigger cost service" };
+
   /*------------------------+
    * Methods acting on ROBs |
    *------------------------+ 
diff --git a/Trigger/TrigMonitoring/TrigCostMonitorMT/CMakeLists.txt b/Trigger/TrigMonitoring/TrigCostMonitorMT/CMakeLists.txt
index 21d91f2167f..6340548a0b2 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitorMT/CMakeLists.txt
+++ b/Trigger/TrigMonitoring/TrigCostMonitorMT/CMakeLists.txt
@@ -12,7 +12,7 @@ atlas_add_library( TrigCostMonitorMTLib
                    TrigCostMonitorMT/*.h
                    src/lib/AlgorithmIdentifier.cxx
                    PUBLIC_HEADERS TrigCostMonitorMT
-                   LINK_LIBRARIES AthenaBaseComps GaudiKernel StoreGateLib xAODTrigger AthViews )
+                   LINK_LIBRARIES AthenaBaseComps GaudiKernel StoreGateLib TrigDataAccessMonitoringLib xAODTrigger AthViews )
 
 atlas_add_component( TrigCostMonitorMT
                      src/*.cxx
diff --git a/Trigger/TrigMonitoring/TrigCostMonitorMT/TrigCostMonitorMT/ITrigCostMTSvc.h b/Trigger/TrigMonitoring/TrigCostMonitorMT/TrigCostMonitorMT/ITrigCostMTSvc.h
index a4017d42328..a5806b9dff2 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitorMT/TrigCostMonitorMT/ITrigCostMTSvc.h
+++ b/Trigger/TrigMonitoring/TrigCostMonitorMT/TrigCostMonitorMT/ITrigCostMTSvc.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
  /*
  */
@@ -12,6 +12,7 @@
 
 #include "xAODTrigger/TrigCompositeContainer.h"
 #include "StoreGate/WriteHandle.h"
+#include "TrigDataAccessMonitoring/ROBDataMonitor.h"
 
 #include <string>
 
@@ -47,12 +48,17 @@ public:
   /**
    * @brief To be used to signal end of an event in a given slot, and to write an output payload to a given handle.
    */
-  virtual StatusCode endEvent(const EventContext&, SG::WriteHandle<xAOD::TrigCompositeContainer>&) = 0; 
+  virtual StatusCode endEvent(const EventContext&, SG::WriteHandle<xAOD::TrigCompositeContainer>&, SG::WriteHandle<xAOD::TrigCompositeContainer>&) = 0; 
 
   /**
    * @brief To be used by external suppliers of data to know if they should spend the CPU to collate their monitoring data
    */
-  virtual bool isMonitoredEvent(const EventContext& context) const = 0;
+  virtual bool isMonitoredEvent(const EventContext& context, const bool includeMultiSlot) const = 0;
+
+  /**
+   * @brief To be used to cache ROBs for ROS
+   */
+  virtual StatusCode monitorROS(const EventContext& context, robmonitor::ROBDataStruct payload) = 0;
 
 };
 
diff --git a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostDataStore.h b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostDataStore.h
index a2ae233ddbd..426b57b1cb7 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostDataStore.h
+++ b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostDataStore.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef TRIGCOSTMONITORMT_TRIGCOSTDATASTORE_H
@@ -52,6 +52,15 @@ class TrigCostDataStore {
    */
   StatusCode insert(const AlgorithmIdentifier& ai, const PAYLOAD& payload);
 
+  /**
+   * @brief Inserts the entry in the vector payload into the map
+   * @param[in] ai The AlgorithmIdentifier to insert for (the key)
+   * @param[in] entry The entry to record
+   * @returns Success unless and class is not initialized, then Failure
+   */
+  template<typename ENTRY>
+  StatusCode push_back(const AlgorithmIdentifier& ai, const ENTRY& entry);
+
   /**
    * @brief Retrieve a payload from the map given an AlgorithmIdentifier
    * @param[in] ai The AlgorithmIdentifier to fetch (the key)
diff --git a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostDataStore.icc b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostDataStore.icc
index 615552518e9..d3b77b522ff 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostDataStore.icc
+++ b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostDataStore.icc
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "AthenaBaseComps/AthCheckMacros.h"
@@ -32,6 +32,25 @@ StatusCode TrigCostDataStore<PAYLOAD>::insert(const AlgorithmIdentifier& ai, con
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
+template<typename PAYLOAD>
+template<typename ENTRY>
+StatusCode TrigCostDataStore<PAYLOAD>::push_back(const AlgorithmIdentifier& ai, const ENTRY& entry) {
+  MsgStream& msg = *(ai.m_msg);
+  ATH_CHECK( checkSlot(ai.m_slotToSaveInto, msg) );
+  tbb::concurrent_hash_map<AlgorithmIdentifier, std::vector<ENTRY>, AlgorithmIdentifierHashCompare>& mapReference = m_store.at( ai.m_slotToSaveInto );
+  typename tbb::concurrent_hash_map< AlgorithmIdentifier, std::vector<ENTRY>, AlgorithmIdentifierHashCompare>::accessor acc;
+
+  // Adds new value to store entries. If the AI is already there function will return false
+  // and duplicate will not be added. Otherwise new payload will be created
+  // Also obtains write lock on the key value 'name' until 'acc' goes out of scope
+  mapReference.insert(acc, ai);
+  acc->second.push_back(entry);
+
+  return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
 template<typename PAYLOAD>
 StatusCode TrigCostDataStore<PAYLOAD>::retrieve(const AlgorithmIdentifier& ai, 
   typename tbb::concurrent_hash_map<AlgorithmIdentifier, PAYLOAD, AlgorithmIdentifierHashCompare>::const_accessor& payload) const
diff --git a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.cxx b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.cxx
index 22376cf6194..7317c3279b4 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.cxx
+++ b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "GaudiKernel/ConcurrencyFlags.h"
@@ -56,6 +56,7 @@ StatusCode TrigCostMTSvc::initialize() {
 
   ATH_CHECK(m_algStartInfo.initialize(m_eventSlots));
   ATH_CHECK(m_algStopTime.initialize(m_eventSlots));
+  ATH_CHECK(m_rosData.initialize(m_eventSlots));
 
   return StatusCode::SUCCESS;
 }
@@ -86,6 +87,7 @@ StatusCode TrigCostMTSvc::startEvent(const EventContext& context, const bool ena
       // Empty transient thread-safe stores in preparation for recording this event's cost data
       ATH_CHECK(m_algStartInfo.clear(context, msg()));
       ATH_CHECK(m_algStopTime.clear(context, msg()));
+      ATH_CHECK(m_rosData.clear(context, msg()));
     }
 
     // Enable collection of data in this slot for monitoredEvents
@@ -149,9 +151,11 @@ StatusCode TrigCostMTSvc::monitor(const EventContext& context, const AlgorithmId
     ATH_CHECK( m_algStartInfo.insert(ai, ap) );
 
     // Cache the AlgorithmIdentifier which has just started executing on this thread
-    tbb::concurrent_hash_map<std::thread::id, AlgorithmIdentifier, ThreadHashCompare>::accessor acc;
-    m_threadToAlgMap.insert(acc, ap.m_algThreadID);
-    acc->second = ai;
+    if (ai.m_realSlot == ai.m_slotToSaveInto) {
+      tbb::concurrent_hash_map<std::thread::id, AlgorithmIdentifier, ThreadHashCompare>::accessor acc;
+      m_threadToAlgMap.insert(acc, ap.m_algThreadID);
+      acc->second = ai;
+    }
 
   } else if (type == AuditType::After) {
 
@@ -170,7 +174,28 @@ StatusCode TrigCostMTSvc::monitor(const EventContext& context, const AlgorithmId
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
-StatusCode TrigCostMTSvc::endEvent(const EventContext& context, SG::WriteHandle<xAOD::TrigCompositeContainer>& outputHandle) { 
+StatusCode TrigCostMTSvc::monitorROS(const EventContext& /*context*/, robmonitor::ROBDataStruct payload){
+  ATH_MSG_DEBUG( "Received ROB payload " << payload );
+
+  // Associate payload with an algorithm
+  AlgorithmIdentifier theAlg;
+  {
+    tbb::concurrent_hash_map<std::thread::id, AlgorithmIdentifier, ThreadHashCompare>::const_accessor acc;
+    ATH_CHECK( m_threadToAlgMap.find(acc, std::this_thread::get_id()) );
+    theAlg = acc->second;
+  }
+
+  // Record data in TrigCostDataStore
+  ATH_MSG_DEBUG( "Adding " << payload.rob_id << " to " << theAlg.m_hash );
+  ATH_CHECK( m_rosData.push_back(theAlg, payload) );
+
+  return StatusCode::SUCCESS;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+StatusCode TrigCostMTSvc::endEvent(const EventContext& context, SG::WriteHandle<xAOD::TrigCompositeContainer>& costOutputHandle, SG::WriteHandle<xAOD::TrigCompositeContainer>& rosOutputHandle) { 
   ATH_CHECK(checkSlot(context));
   if (m_eventMonitored[ context.slot() ] == false) {
     // This event was not monitored - nothing to do.
@@ -228,6 +253,7 @@ StatusCode TrigCostMTSvc::endEvent(const EventContext& context, SG::WriteHandle<
 
   ATH_MSG_DEBUG("Monitored event with " << std::distance(beginIt, endIt) << " AlgorithmPayload objects.");
 
+  std::map<size_t, size_t> aiToHandleIndex;
   for (it = beginIt; it != endIt; ++it) {
     const AlgorithmIdentifier& ai = it->first;
     const AlgorithmPayload& ap = it->second;
@@ -284,7 +310,7 @@ StatusCode TrigCostMTSvc::endEvent(const EventContext& context, SG::WriteHandle<
 
     // Make a new TrigComposite to persist monitoring payload for this alg
     xAOD::TrigComposite* tc = new xAOD::TrigComposite();
-    outputHandle->push_back( tc ); 
+    costOutputHandle->push_back( tc ); 
     // tc is now owned by storegate and, and has an aux store provided by the TrigCompositeCollection
 
     const uint32_t threadID = static_cast<uint32_t>( std::hash< std::thread::id >()(ap.m_algThreadID) );
@@ -312,11 +338,34 @@ StatusCode TrigCostMTSvc::endEvent(const EventContext& context, SG::WriteHandle<
     result &= tc->setDetail("start", startTime);
     result &= tc->setDetail("stop", stopTime);
     if (!result) ATH_MSG_WARNING("Failed to append one or more details to trigger cost TC");
+
+    aiToHandleIndex[ai.m_hash] = costOutputHandle->size() - 1;
+  }
+
+  typedef tbb::concurrent_hash_map< AlgorithmIdentifier, std::vector<robmonitor::ROBDataStruct>, AlgorithmIdentifierHashCompare>::const_iterator ROBConstIt;
+  ROBConstIt beginRob;
+  ROBConstIt endRob;
+  
+  ATH_CHECK(m_rosData.getIterators(context, msg(), beginRob, endRob));
+  
+  for (ROBConstIt it = beginRob; it != endRob; ++it) {
+    // TrigComposite for ROS caching
+    xAOD::TrigComposite* tcr = new xAOD::TrigComposite();
+    rosOutputHandle->push_back( tcr ); 
+
+    size_t aiHash = it->first.m_hash;
+    if (aiToHandleIndex.count(aiHash) == 0) {
+      ATH_MSG_WARNING("Algorithm with hash " << TrigConf::HLTUtils::hash2string( aiHash, "ALG") << " not found!");
+    }
+
+    bool result = true;
+    result &= tcr->setDetail("alg_idx", aiToHandleIndex[aiHash]);
+    if (!result) ATH_MSG_WARNING("Failed to append one or more details to trigger cost ROS TC");
   }
 
   if (msg().level() <= MSG::VERBOSE) {
     ATH_MSG_VERBOSE("--- Trig Cost Event Summary ---");
-    for ( const xAOD::TrigComposite* tc : *outputHandle ) {
+    for ( const xAOD::TrigComposite* tc : *costOutputHandle ) {
       ATH_MSG_VERBOSE("Algorithm:'" << TrigConf::HLTUtils::hash2string( tc->getDetail<TrigConf::HLTHash>("alg"), "ALG") << "'");
       ATH_MSG_VERBOSE("  Store:'" << TrigConf::HLTUtils::hash2string( tc->getDetail<TrigConf::HLTHash>("store"), "STORE") << "'");
       ATH_MSG_VERBOSE("  View ID:" << tc->getDetail<int16_t>("view"));
@@ -354,11 +403,11 @@ int32_t TrigCostMTSvc::getROIID(const EventContext& context) {
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
-bool TrigCostMTSvc::isMonitoredEvent(const EventContext& context) const {
+bool TrigCostMTSvc::isMonitoredEvent(const EventContext& context, const bool includeMultiSlot) const {
   if (m_eventMonitored[ context.slot() ]) {
     return true;
   }
-  if (m_enableMultiSlot) {
+  if (includeMultiSlot && m_enableMultiSlot) {
     return m_eventMonitored[ m_masterSlot ];
   }
   return false;
diff --git a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.h b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.h
index c4dbb7ea586..6cc891368f6 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.h
+++ b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef TRIGCOSTMONITORMT_TRIGCOSTMTSVC_H
@@ -8,6 +8,7 @@
 #include <atomic>
 #include <shared_mutex>
 #include <thread>
+#include <vector>
 
 #include "GaudiKernel/ToolHandle.h"
 
@@ -76,15 +77,23 @@ class TrigCostMTSvc : public extends <AthService, ITrigCostMTSvc> {
   /**
    * @brief Implementation of ITrigCostMTSvc::endEvent.
    * @param[in] context The event context
-   * @param[out] outputHandle Write handle to fill with execution summary if the event was monitored
+   * @param[out] costOutputHandle Write handle to fill with execution summary if the event was monitored
+   * @param[out] rosOutputHandle Write handle to fill with ROS requests summary if the event was monitored
    */
-  virtual StatusCode endEvent(const EventContext& context, SG::WriteHandle<xAOD::TrigCompositeContainer>& outputHandle) override; 
+  virtual StatusCode endEvent(const EventContext& context, SG::WriteHandle<xAOD::TrigCompositeContainer>& costOutputHandle, SG::WriteHandle<xAOD::TrigCompositeContainer>& rosOutputHandle) override; 
 
   /**
    * @return If the current context is flagged as being monitored. 
    * @param[in] context The event context
    */
-  virtual bool isMonitoredEvent(const EventContext& context) const override;
+  virtual bool isMonitoredEvent(const EventContext& context, const bool includeMultiSlot = true) const override;
+
+  /**
+   * @brief Implementation of ITrigCostMTSvc::monitorROS.
+   * @param[in] context The event context
+   * @param[in] payload ROB data to be associated with ROS
+   */
+  virtual StatusCode monitorROS(const EventContext& context, robmonitor::ROBDataStruct payload) override;
 
   private: 
 
@@ -127,12 +136,14 @@ class TrigCostMTSvc : public extends <AthService, ITrigCostMTSvc> {
   std::mutex m_globalMutex; //!< Used to protect all-slot modifications.
   TrigCostDataStore<AlgorithmPayload> m_algStartInfo; //!< Thread-safe store of algorithm start payload.
   TrigCostDataStore<TrigTimeStamp> m_algStopTime; //!< Thread-safe store of algorithm stop times.
+  TrigCostDataStore<std::vector<robmonitor::ROBDataStruct>> m_rosData; //!< Thread-safe store of ROS data
 
   tbb::concurrent_hash_map<std::thread::id, AlgorithmIdentifier, ThreadHashCompare> m_threadToAlgMap; //!< Keeps track of what is running right now in each thread.
 
   std::unordered_map<uint32_t, uint32_t> m_threadToCounterMap; //!< Map thread's hash ID to a counting numeral
   size_t m_threadCounter; //!< Count how many unique thread ID we have seen 
 
+
   Gaudi::Property<bool>        m_monitorAllEvents{this, "MonitorAllEvents", false, "Monitor every HLT event, e.g. for offline validation."};
   Gaudi::Property<bool>        m_enableMultiSlot{this, "EnableMultiSlot", true, "Monitored events in the MasterSlot collect data from events running in other slots."};
   Gaudi::Property<bool>        m_saveHashes{this, "SaveHashes", false, "Store a copy of the hash dictionary for easier debugging"};
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.cxx b/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.cxx
index 0dd30a96a50..531fc13566e 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 #include "TrigCompositeUtils/HLTIdentifier.h"
 #include "DecisionSummaryMakerAlg.h"
@@ -22,6 +22,7 @@ StatusCode DecisionSummaryMakerAlg::initialize() {
   }
 
   ATH_CHECK( m_costWriteHandleKey.initialize( m_doCostMonitoring ) );
+  ATH_CHECK( m_rosWriteHandleKey.initialize( m_doCostMonitoring ) );
   if (m_doCostMonitoring) {
     ATH_CHECK( m_trigCostSvcHandle.retrieve() );
   }
@@ -138,8 +139,9 @@ StatusCode DecisionSummaryMakerAlg::execute(const EventContext& context) const {
   // Do cost monitoring
   if (m_doCostMonitoring) {
     SG::WriteHandle<xAOD::TrigCompositeContainer> costMonOutput = createAndStore(m_costWriteHandleKey, context);
+    SG::WriteHandle<xAOD::TrigCompositeContainer> rosMonOutput = createAndStore(m_rosWriteHandleKey, context);
     // Populate collection (assuming monitored event, otherwise collection will remain empty)
-    ATH_CHECK(m_trigCostSvcHandle->endEvent(context, costMonOutput));
+    ATH_CHECK(m_trigCostSvcHandle->endEvent(context, costMonOutput, rosMonOutput));
   }
 
   // Set the algorithm's filter status. This controlls the running of finalisation algs which we only want to execute
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.h b/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.h
index 96e4bd9b4b7..7b050aac8d3 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.h
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 #ifndef TRIGOUTPUTHANDLING_DECISIONSUMMARYMAKERALG_H
 #define TRIGOUTPUTHANDLING_DECISIONSUMMARYMAKERALG_H
@@ -35,6 +35,9 @@ private:
   SG::WriteHandleKey<xAOD::TrigCompositeContainer> m_costWriteHandleKey { this, "CostWriteHandleKey", "HLT_TrigCostContainer",
     "TrigComposite collections summarising the HLT execution" };
 
+  SG::WriteHandleKey<xAOD::TrigCompositeContainer> m_rosWriteHandleKey { this, "ROSWriteHandleKey", "HLT_TrigCostROSContainer",
+    "TrigComposite collections summarising the ROS requests" };
+
   SG::ReadHandleKey<xAOD::TrigCompositeContainer> m_l1SummaryKey { this, "L1DecoderSummaryKey", "L1DecoderSummary",
     "Chains status after L1 and prescaling" };
 
diff --git a/Trigger/TriggerCommon/TrigEDMConfig/python/TriggerEDMRun3.py b/Trigger/TriggerCommon/TrigEDMConfig/python/TriggerEDMRun3.py
index 5a58b88f36b..89ba6f1e84f 100644
--- a/Trigger/TriggerCommon/TrigEDMConfig/python/TriggerEDMRun3.py
+++ b/Trigger/TriggerCommon/TrigEDMConfig/python/TriggerEDMRun3.py
@@ -96,6 +96,8 @@ TriggerHLTListRun3 = [
 
     ('xAOD::TrigCompositeContainer#HLT_TrigCostContainer',   'CostMonDS ESD', 'Steer'),
     ('xAOD::TrigCompositeAuxContainer#HLT_TrigCostContainerAux.alg.store.view.thread.thash.slot.roi.start.stop', 'CostMonDS ESD', 'Steer'),
+    ('xAOD::TrigCompositeContainer#HLT_TrigCostROSContainer',   'CostMonDS ESD', 'Steer'),
+    ('xAOD::TrigCompositeAuxContainer#HLT_TrigCostROSContainerAux.alg_idx', 'CostMonDS ESD', 'Steer'),
 
     # Run-2 L1 (temporary)
     ('xAOD::MuonRoIContainer#LVL1MuonRoIs' ,                 'ESD AODFULL AODSLIM AODVERYSLIM AODBLSSLIM', 'L1'),
-- 
GitLab