From d0cfaf21f73a8733510fd22db04cb4d8429277ae Mon Sep 17 00:00:00 2001
From: Aleksandra Poreba <aleksandra.poreba@cern.ch>
Date: Fri, 20 Nov 2020 15:10:49 +0000
Subject: [PATCH] Refactor CostData

- add algIdx to rosIdx caching
- set cost and ros collection at once
---
 .../src/HltROBDataProviderSvc.cxx             | 34 ++++++++---
 .../TrigServices/src/HltROBDataProviderSvc.h  |  6 +-
 .../TrigCostAnalysis/src/CostData.cxx         | 21 ++++++-
 .../TrigCost/TrigCostAnalysis/src/CostData.h  | 12 +++-
 .../TrigCostAnalysis/src/TrigCostAnalysis.cxx | 11 +++-
 .../TrigCostAnalysis/src/TrigCostAnalysis.h   |  6 ++
 .../src/counters/CounterROS.cxx               | 44 +++++++++++++
 .../src/counters/CounterROS.h                 | 61 +++++++++++++++++++
 .../src/monitors/MonitorROS.cxx               | 21 +++++++
 .../src/monitors/MonitorROS.h                 | 58 ++++++++++++++++++
 .../TrigDataAccessMonitoring/ROBDataMonitor.h | 28 +++++----
 .../TrigCostMonitorMT/ITrigCostMTSvc.h        |  2 +-
 .../TrigCostMonitorMT/src/TrigCostMTSvc.cxx   | 37 ++++++++---
 .../TrigCostMonitorMT/src/TrigCostMTSvc.h     |  4 +-
 .../TrigEDMConfig/python/TriggerEDMRun3.py    |  2 +-
 15 files changed, 308 insertions(+), 39 deletions(-)
 create mode 100644 Trigger/TrigCost/TrigCostAnalysis/src/counters/CounterROS.cxx
 create mode 100644 Trigger/TrigCost/TrigCostAnalysis/src/counters/CounterROS.h
 create mode 100644 Trigger/TrigCost/TrigCostAnalysis/src/monitors/MonitorROS.cxx
 create mode 100644 Trigger/TrigCost/TrigCostAnalysis/src/monitors/MonitorROS.h

diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx
index 7550bdb5bb1..4dd612c3c56 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx
+++ b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx
@@ -3,6 +3,7 @@
 */
 #include "HltROBDataProviderSvc.h"
 #include "TrigKernel/HltExceptions.h"
+#include "TrigTimeAlgs/TrigTimeStamp.h"
 
 // Gaudi
 #include "Gaudi/Interfaces/IOptionsSvc.h"
@@ -319,6 +320,8 @@ void HltROBDataProviderSvc::getROBData(const EventContext& context,
 				       const std::vector<uint32_t>& robIds, std::vector<const ROBF*>& robFragments, 
 				       const std::string_view callerName)
 {
+  TrigTimeStamp rosStartTime;
+
   ATH_MSG_VERBOSE("start of " << __FUNCTION__ << ": Number of ROB Ids to get = " << robIds.size() 
 		  << " caller name = " << callerName);
   EventCache* cache = m_eventsCache.get( context );
@@ -372,15 +375,16 @@ void HltROBDataProviderSvc::getROBData(const EventContext& context,
   }
 
   // Check if event should be monitored and monitor ROB data
+  auto monitorData = robmonitor::ROBDataMonitorStruct(cache->currentLvl1ID, std::string(callerName));
   if (m_doCostMonitoring && m_trigCostSvcHandle->isMonitoredEvent(context, /*includeMultiSlot =*/ false)) {
     // Monitor HLT cached ROBs
     for (const ROBF* robFrag : robFragments) {
-      robmap_monitorRobFragment(context, *robFrag, robmonitor::HLT_CACHED);
+      monitorData.requested_ROBs[robFrag->source_id()] = robmap_getRobData(*robFrag, robmonitor::HLT_CACHED);
     }
 
     // Monitor DCM ROBs
     for (const hltinterface::DCM_ROBInfo& robInfo : vRobInfos) {
-      robmap_monitorRobFragment(context, robInfo.robFragment, 
+      monitorData.requested_ROBs[robInfo.robFragment.source_id()] = robmap_getRobData(robInfo.robFragment, 
         robInfo.robIsCached ? robmonitor::DCM_CACHED : robmonitor::RETRIEVED);
     }
   }
@@ -390,9 +394,23 @@ void HltROBDataProviderSvc::getROBData(const EventContext& context,
 
   // return all the requested ROB fragments from the cache
   eventCache_checkRobListToCache(cache, robIds, robFragments, robIds_missing) ;
+
+  // Save ROS processing time and pass ROS data to CostMonitor
+  if (m_doCostMonitoring && m_trigCostSvcHandle->isMonitoredEvent(context, /*includeMultiSlot =*/ false)) {
+    TrigTimeStamp rosEndTime;
+
+    monitorData.start_time = rosStartTime.microsecondsSinceEpoch();
+    monitorData.end_time = rosEndTime.microsecondsSinceEpoch();
+
+    // Check if ROBMonitorDataStruct is move-constructible
+    static_assert(std::is_nothrow_move_constructible<robmonitor::ROBDataMonitorStruct>::value);
+    if (m_trigCostSvcHandle->monitorROS(context, std::move(monitorData)).isFailure()) {
+      ATH_MSG_WARNING("TrigCost ROS monitoring failed!");
+    }  
+  }
 }
 
-void HltROBDataProviderSvc::robmap_monitorRobFragment(const EventContext& context, const ROBF& robFrag, robmonitor::ROBHistory robStatus)
+robmonitor::ROBDataStruct HltROBDataProviderSvc::robmap_getRobData(const ROBF& robFrag, robmonitor::ROBHistory robStatus)
 {
   auto robData = robmonitor::ROBDataStruct(robFrag.source_id());
   robData.rob_size = robFrag.fragment_size_word();
@@ -410,20 +428,16 @@ void HltROBDataProviderSvc::robmap_monitorRobFragment(const EventContext& contex
   }
   catch (const std::exception& ex) {
     ATH_MSG_ERROR("std::exception caught when reading status words: " << ex.what());
-    return;
+    return robmonitor::ROBDataStruct();
   }
   catch (...) {
     ATH_MSG_ERROR("Unknown exception caught when reading status words");
-    return;
+    return robmonitor::ROBDataStruct();
   }
 
   robData.rob_status_words = std::move(statusWords);
 
-  // Check if ROBDataStruct is move-constructible and pass data to CostMonitor
-  static_assert(std::is_nothrow_move_constructible<robmonitor::ROBDataStruct>::value);
-  if (m_trigCostSvcHandle->monitorROS(context, std::move(robData)).isFailure()) {
-    ATH_MSG_WARNING("TrigCost ROS monitoring failed!");
-  }
+  return robData;
 }
 
 /// Retrieve the full event fragment
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.h b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.h
index a451f6e620a..72ae025fffb 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.h
+++ b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.h
@@ -180,12 +180,12 @@ private:
   /// method to filter ROBs with given Status code
   bool robmap_filterRobWithStatus(const ROBF*);
 
-  /// method to monitor ROB fragments in Cost
+  /// method to get ROB fragment from ROBF
   /// input:
   ///     context
-  ///     ROB fragment to be monitored
+  ///     ROB fragment to be parsed
   ///     ROB history status
-  void robmap_monitorRobFragment(const EventContext&, const ROBF&, robmonitor::ROBHistory) ;
+  robmonitor::ROBDataStruct robmap_getRobData(const ROBF&, robmonitor::ROBHistory) ;
 
   /*------------------------------+
    * Methods acting on EventCache |
diff --git a/Trigger/TrigCost/TrigCostAnalysis/src/CostData.cxx b/Trigger/TrigCost/TrigCostAnalysis/src/CostData.cxx
index acb81d5348d..1dcc6a8535d 100644
--- a/Trigger/TrigCost/TrigCostAnalysis/src/CostData.cxx
+++ b/Trigger/TrigCost/TrigCostAnalysis/src/CostData.cxx
@@ -17,10 +17,21 @@ CostData::CostData() :
 }
 
 
-StatusCode CostData::set(const xAOD::TrigCompositeContainer* costCollection, uint32_t onlineSlot) {
+StatusCode CostData::set(const xAOD::TrigCompositeContainer* costCollection, const xAOD::TrigCompositeContainer* rosCollection, uint32_t onlineSlot) {
   m_costCollection = costCollection;
+  m_rosCollection = rosCollection;
+
   setOnlineSlot( onlineSlot );
   ATH_CHECK(cache());
+
+  // Create mapping from algorithm to associated ROS requests
+  m_algToRos.clear();
+  size_t rosIdx = 0;
+  for (const xAOD::TrigComposite* tc : *rosCollection) {
+    m_algToRos[tc->getDetail<size_t>("alg_idx")].push_back(rosIdx);
+    ++rosIdx;
+  }
+
   return StatusCode::SUCCESS;
 }
 
@@ -62,6 +73,14 @@ const xAOD::TrigCompositeContainer& CostData::costCollection() const {
 }
 
 
+const xAOD::TrigCompositeContainer& CostData::rosCollection() const {
+  if (!m_rosCollection) {
+    throw std::runtime_error("nullptr in CostData::rosCollection(). Make sure CostData::set() is called.");
+  }
+  return *m_rosCollection;
+}
+
+
 float CostData::algTotalTimeMilliSec() const {
   return m_algTotalTime * 1e-3; // microseconds to milliseconds
 }
diff --git a/Trigger/TrigCost/TrigCostAnalysis/src/CostData.h b/Trigger/TrigCost/TrigCostAnalysis/src/CostData.h
index 29413c5c7e8..a164eb25146 100644
--- a/Trigger/TrigCost/TrigCostAnalysis/src/CostData.h
+++ b/Trigger/TrigCost/TrigCostAnalysis/src/CostData.h
@@ -8,6 +8,9 @@
 #include "GaudiKernel/StatusCode.h"
 #include "xAODTrigger/TrigCompositeContainer.h"
 
+#include <map>
+#include <vector>
+
 /**
  * @class CostData
  * @brief Caches and propagates event data to be used by monitoring algorithms.
@@ -41,13 +44,18 @@ class CostData {
     /**
      * @brief Cache the cost collection, after formally requesting it from storegate.
      */
-    StatusCode set(const xAOD::TrigCompositeContainer* costCollection, uint32_t onlineSlot);
+    StatusCode set(const xAOD::TrigCompositeContainer* costCollection, const xAOD::TrigCompositeContainer* rosCollection, uint32_t onlineSlot);
 
     /**
      * @brief Getter of the cached algorithm cost collection pointer.
      */
     const xAOD::TrigCompositeContainer& costCollection() const;
 
+    /**
+     * @brief Getter of the cached ros cost collection pointer.
+     */
+    const xAOD::TrigCompositeContainer& rosCollection() const;
+
     /**
      * @brief Setter of effective P1 walltime represented by the current event.
      */
@@ -118,12 +126,14 @@ class CostData {
     StatusCode cache();
 
     const xAOD::TrigCompositeContainer* m_costCollection; //!< Cached non-owning pointer to main algorithm cost collection.
+    const xAOD::TrigCompositeContainer* m_rosCollection; //!< Cached non-owning pointer to ros cost collection.
     uint64_t m_algTotalTime; //!< Integrated CPU time of all algorithms in the event. Stored in discrete microseconds.
     float m_liveTime; //!< Effective walltime of either the event or the LB, in seconds (@see m_liveTimeIsPerEvent).
     uint32_t m_lb; //!< Current luminosity block number
     uint32_t m_slot; //!< Current online slot number
     bool m_liveTimeIsPerEvent; //!< If the livetime represents a single event or all of the current LB
     const std::unordered_map<uint32_t, std::string>* m_typeMapPtr; //!< Cached non-owning pointer mapping algorithm instance names to types
+    std::map<size_t, std::vector<size_t>> m_algToRos; //!< Mapping of indexes from m_costCollection to corresponding ROS requests made by algorithm
 };
 
 #endif // TRIGCOSTANALYSIS_COSTDATA_H
diff --git a/Trigger/TrigCost/TrigCostAnalysis/src/TrigCostAnalysis.cxx b/Trigger/TrigCost/TrigCostAnalysis/src/TrigCostAnalysis.cxx
index 9e61df473da..0095fa18343 100644
--- a/Trigger/TrigCost/TrigCostAnalysis/src/TrigCostAnalysis.cxx
+++ b/Trigger/TrigCost/TrigCostAnalysis/src/TrigCostAnalysis.cxx
@@ -14,6 +14,7 @@
 #include "monitors/MonitorAlgorithmClass.h"
 #include "monitors/MonitorGlobal.h"
 #include "monitors/MonitorThreadOccupancy.h"
+#include "monitors/MonitorROS.h"
 
 TrigCostAnalysis::TrigCostAnalysis( const std::string& name, ISvcLocator* pSvcLocator ) :
   AthHistogramAlgorithm(name, pSvcLocator),
@@ -27,6 +28,7 @@ StatusCode  TrigCostAnalysis::initialize() {
 
   ATH_MSG_DEBUG("Reading from " << m_costDataKey.key() << ", " << m_HLTMenuKey.key());
   ATH_CHECK( m_costDataKey.initialize() );
+  ATH_CHECK( m_rosDataKey.initialize() );
   ATH_CHECK( m_HLTMenuKey.initialize() );
 
   if (!m_enhancedBiasTool.name().empty()) {
@@ -144,9 +146,12 @@ StatusCode TrigCostAnalysis::execute() {
   SG::ReadHandle<xAOD::TrigCompositeContainer> costDataHandle(m_costDataKey, context);
   ATH_CHECK( costDataHandle.isValid() );
 
+  SG::ReadHandle<xAOD::TrigCompositeContainer> rosDataHandle(m_rosDataKey, context);
+  ATH_CHECK( rosDataHandle.isValid() );
+
   const uint32_t onlineSlot = getOnlineSlot( costDataHandle.get() );
   CostData costData;
-  ATH_CHECK( costData.set(costDataHandle.get(), onlineSlot) );
+  ATH_CHECK( costData.set(costDataHandle.get(), rosDataHandle.get(), onlineSlot) );
   costData.setLb( context.eventID().lumi_block() );
   costData.setTypeMap( m_algTypeMap );
   if (!m_enhancedBiasTool.name().empty()) {
@@ -199,6 +204,10 @@ StatusCode TrigCostAnalysis::registerMonitors(MonitoredRange* range) {
     ATH_CHECK( range->addMonitor(std::make_unique<MonitorThreadOccupancy>("Thread_Occupancy_HLT", range)) );
     ATH_MSG_DEBUG("Registering Thread_Occupancy_HLT Monitor for range " << range->getName() << ". Size:" << range->getMonitors().size());
   }
+  if (m_doMonitorROS) {
+    ATH_CHECK( range->addMonitor(std::make_unique<MonitorROS>("ROS_HLT", range)) );
+    ATH_MSG_DEBUG("Registering ROS_HLT Monitor for range " << range->getName() << ". Size:" << range->getMonitors().size());
+  }
   // if (m_do...) {}
   return StatusCode::SUCCESS;
 }
diff --git a/Trigger/TrigCost/TrigCostAnalysis/src/TrigCostAnalysis.h b/Trigger/TrigCost/TrigCostAnalysis/src/TrigCostAnalysis.h
index e822a37cde1..af2a9016f23 100644
--- a/Trigger/TrigCost/TrigCostAnalysis/src/TrigCostAnalysis.h
+++ b/Trigger/TrigCost/TrigCostAnalysis/src/TrigCostAnalysis.h
@@ -96,6 +96,9 @@ class TrigCostAnalysis: public ::AthHistogramAlgorithm {
     Gaudi::Property<bool> m_doMonitorThreadOccupancy { this, "DoMonitorThreadOccupancy", true,
       "Monitor algorithm occupancy load of individual threads in an MT execution environment" };
 
+    Gaudi::Property<bool> m_doMonitorROS { this, "DoMonitorROS", true,
+      "Monitor Read-Out System" };
+
     Gaudi::Property<bool> m_useEBWeights { this, "UseEBWeights", true,
       "Apply Enhanced Bias weights" };
 
@@ -111,6 +114,9 @@ class TrigCostAnalysis: public ::AthHistogramAlgorithm {
     SG::ReadHandleKey<xAOD::TrigCompositeContainer> m_costDataKey { this, "CostReadHandleKey", "HLT_TrigCostContainer",
       "Trigger cost payload container for algorithms" };
 
+    SG::ReadHandleKey<xAOD::TrigCompositeContainer> m_rosDataKey { this, "CostROSReadHandleKey", "HLT_TrigCostROSContainer",
+      "Trigger ROS cost payload container for algorithms" };
+
     SG::ReadHandleKey<TrigConf::HLTMenu> m_HLTMenuKey{this, "HLTTriggerMenu", "DetectorStore+HLTTriggerMenu",
       "HLT Menu"};
 
diff --git a/Trigger/TrigCost/TrigCostAnalysis/src/counters/CounterROS.cxx b/Trigger/TrigCost/TrigCostAnalysis/src/counters/CounterROS.cxx
new file mode 100644
index 00000000000..46fd5a1ec30
--- /dev/null
+++ b/Trigger/TrigCost/TrigCostAnalysis/src/counters/CounterROS.cxx
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "xAODTrigger/TrigCompositeContainer.h"
+
+#include "CounterROS.h"
+
+CounterROS::CounterROS(const std::string& name, const MonitorBase* parent) 
+  : CounterBase(name, parent)
+{}
+
+StatusCode CounterROS::newEvent(const CostData& /*data*/, size_t /*incrementWalltime*/, const float /*weight*/) {
+  return StatusCode::SUCCESS;
+}
+
+int CounterROS::getROBHistoryBin(const unsigned history){
+  int history_bin;
+  switch (history) {
+    case 1: // SCHEDULED
+      history_bin = 1;
+      break;
+    case 2: // RETRIEVED
+      history_bin = 1;
+      break;
+    case 4: // HLT_CACHED
+      history_bin = 3;
+      break;
+    case 8: // DCM_CACHED
+      history_bin = 4;
+      break;
+    case 16: // IGNORED
+      history_bin = 5;
+      break;
+    case 32: // DISABLED
+      history_bin = 6;
+      break;
+    default: // UNCLASSIFIED 
+      history_bin = 0;
+      break;
+  }
+  
+  return history_bin;
+}
diff --git a/Trigger/TrigCost/TrigCostAnalysis/src/counters/CounterROS.h b/Trigger/TrigCost/TrigCostAnalysis/src/counters/CounterROS.h
new file mode 100644
index 00000000000..96d6c6b5c04
--- /dev/null
+++ b/Trigger/TrigCost/TrigCostAnalysis/src/counters/CounterROS.h
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGCOSTANALYSIS_COUNTERROS_H
+#define TRIGCOSTANALYSIS_COUNTERROS_H 1
+
+#include "../CounterBase.h"
+
+/**
+ * @class CounterROS
+ * @brief Concrete implimentation of Counter to monitor the data requests for 
+ *        a single Read Out System request and corresponding Read Out Buffer requests.
+ */
+class CounterROS : public CounterBase {
+  public:
+    /**
+     * @brief Forbid default constructor.
+     */
+    CounterROS() = delete;
+
+    /**
+     * @brief Construct counter.
+     * @param[in] name Counter's name
+     * @param[in] parent Counter's parent monitor, cached non-owning pointer.
+     */
+    CounterROS(const std::string& name, const MonitorBase* parent);
+
+    /**
+     * @brief Default destructor.
+     */
+    virtual ~CounterROS() = default;
+
+    /**
+     * @brief Forbid assignment.
+     */
+    CounterROS& operator=(const CounterROS&) = delete;
+    
+    /**
+     * @brief Forbid copy.
+     */
+    CounterROS(const CounterROS&) = delete;
+
+    /**
+     * @brief Concrete implementation. Monitors global properties in a single LB, or over all LB in a Range
+     * @param[in] data Access to event data
+     * @param[in] incrementWalltime If 1, we should add the current events wall time to our internal histogram
+     * @param[in] weight Global event weight
+     */
+    virtual StatusCode newEvent(const CostData& data, size_t incrementWalltime, const float weight = 1.) override;
+
+  private:
+      /**
+     * @brief Get histogram bin for ROBHistory enum values
+     * @param[in] history ROBHistory value
+     */
+    int getROBHistoryBin(const unsigned history);
+    
+};
+
+#endif // TRIGCOSTANALYSIS_COUNTERROS_H
\ No newline at end of file
diff --git a/Trigger/TrigCost/TrigCostAnalysis/src/monitors/MonitorROS.cxx b/Trigger/TrigCost/TrigCostAnalysis/src/monitors/MonitorROS.cxx
new file mode 100644
index 00000000000..9352335b70e
--- /dev/null
+++ b/Trigger/TrigCost/TrigCostAnalysis/src/monitors/MonitorROS.cxx
@@ -0,0 +1,21 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "MonitorROS.h"
+#include "../counters/CounterROS.h"
+
+MonitorROS::MonitorROS(const std::string& name, const MonitoredRange* parent)
+  : MonitorBase(name, parent) {
+}
+
+
+StatusCode MonitorROS::newEvent(const CostData& /*data*/, const float /*weight*/) {
+
+  return StatusCode::SUCCESS;
+}
+
+
+std::unique_ptr<CounterBase> MonitorROS::newCounter(const std::string& name) {
+  return std::make_unique<CounterROS>(name, this);
+} 
diff --git a/Trigger/TrigCost/TrigCostAnalysis/src/monitors/MonitorROS.h b/Trigger/TrigCost/TrigCostAnalysis/src/monitors/MonitorROS.h
new file mode 100644
index 00000000000..610a0606d84
--- /dev/null
+++ b/Trigger/TrigCost/TrigCostAnalysis/src/monitors/MonitorROS.h
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGCOSTANALYSIS_MONITORROS_H
+#define TRIGCOSTANALYSIS_MONITORROS_H 1
+
+#include "../MonitorBase.h"
+
+/**
+ * @class MonitorROS
+ * @brief Concrete implimentation of Monitor to monitor Read Out System
+ */
+class MonitorROS : public MonitorBase {
+  public:
+    /**
+     * @brief Forbid default constructor.
+     */
+    MonitorROS() = delete;
+
+    /**
+     * @brief Construct monitor.
+     * @param[in] name Monitor's name
+     * @param[in] parent Monitor's parent Range, cached non-owning pointer.
+     */
+    MonitorROS(const std::string& name, const MonitoredRange* parent);
+
+    /**
+     * @brief Default destructor.
+     */
+    virtual ~MonitorROS() = default;
+
+    /**
+     * @brief Forbid assignment.
+     */
+    MonitorROS& operator=(const MonitorROS&) = delete;
+
+    /**
+     * @brief Forbid copy.
+     */
+    MonitorROS(const MonitorROS&) = delete;
+
+    /**
+     * @brief Concrete dispatch method. Iterate over all Algorithms in event data and dispatch to owned Counters based on class name lookup
+     * @param[in] data Access to event data
+     * @param[in] weight Global event weight
+     */
+    virtual StatusCode newEvent(const CostData& data, const float weight = 1.) override;
+
+    /**
+     * @brief Concrete counter instantiation. Mints named counter of CounterAlgorithm type.
+     * @param[in] name Name of Counter to mint.
+     * @return Owning unique ptr object typed on the CounterBase base class which points to concrete Counter of specialised type.
+     */
+    virtual std::unique_ptr<CounterBase> newCounter(const std::string& name) override; 
+};
+
+#endif // TRIGCOSTANALYSIS_MONITORROS_H
\ No newline at end of file
diff --git a/Trigger/TrigDataAccess/TrigDataAccessMonitoring/TrigDataAccessMonitoring/ROBDataMonitor.h b/Trigger/TrigDataAccess/TrigDataAccessMonitoring/TrigDataAccessMonitoring/ROBDataMonitor.h
index 8d6a167f5d3..5da82928168 100644
--- a/Trigger/TrigDataAccess/TrigDataAccessMonitoring/TrigDataAccessMonitoring/ROBDataMonitor.h
+++ b/Trigger/TrigDataAccess/TrigDataAccessMonitoring/TrigDataAccessMonitoring/ROBDataMonitor.h
@@ -48,14 +48,6 @@ namespace robmonitor {
      */                                   
     ROBDataStruct(const uint32_t);
 
-    ROBDataStruct(const ROBDataStruct&) = default;
-
-    ROBDataStruct(ROBDataStruct&&) noexcept = default;
-
-    ROBDataStruct& operator=(const ROBDataStruct&) = default;
-
-    ROBDataStruct& operator=(ROBDataStruct&&) noexcept = default;
-
     // data variables
     uint32_t rob_id;                           // rob source id
     uint32_t rob_size;                         // size of rob in words
@@ -108,13 +100,27 @@ namespace robmonitor {
      */                                   
     ROBDataMonitorStruct(const uint32_t, const std::vector<uint32_t>&, const std::string);
 
+    ROBDataMonitorStruct(const ROBDataMonitorStruct&) = default;
+
+    ROBDataMonitorStruct(ROBDataMonitorStruct&&) noexcept = default;
+
+    ROBDataMonitorStruct& operator=(const ROBDataMonitorStruct&) = default;
+
+    ROBDataMonitorStruct& operator=(ROBDataMonitorStruct&&) noexcept = default;
+
     // data variables
     uint32_t lvl1ID;                                                    //current L1 ID from L1 ROBs
     std::string requestor_name;                                         //name of requesting algorithm
     std::map<const uint32_t,robmonitor::ROBDataStruct> requested_ROBs;  //map of ROBs requested
+
+    // Legacy timestamps
     struct timeval start_time_of_ROB_request;                           //start time of ROB request 
     struct timeval end_time_of_ROB_request;                             //stop  time of ROB request
 
+    // Run3 TrigTimeStamp
+    uint64_t start_time;                                                //start time of ROB request
+    uint64_t end_time;                                                 //stop  time of ROB request
+
     // Accessor functions to ROB history summaries
     /** @brief number of ROBs in structure */
     unsigned allROBs() const;
@@ -139,7 +145,7 @@ namespace robmonitor {
     float elapsedTime() const;
 
     // Extraction operators
-    friend std::ostream& operator<<(std::ostream& os, robmonitor::ROBDataMonitorStruct& rhs);
+    friend std::ostream& operator<<(std::ostream& os, const robmonitor::ROBDataMonitorStruct& rhs);
   };
 
   // Extraction operator for ROBDataStruct 
@@ -177,7 +183,7 @@ namespace robmonitor {
   }
 
   // Extraction operator for ROBDataMonitorStruct
-  inline std::ostream& operator<<(std::ostream& os, robmonitor::ROBDataMonitorStruct& rhs) {
+  inline std::ostream& operator<<(std::ostream& os, const robmonitor::ROBDataMonitorStruct& rhs) {
     std::string prefix("   ");
     std::string prefix2("-> ");
     os << "ROB Request for L1 ID = " << std::dec << rhs.lvl1ID << " (decimal), L1 ID = 0x" 
@@ -207,7 +213,7 @@ namespace robmonitor {
     os << "\n" << prefix << prefix2 << "Disabled     " << rhs.disabledROBs()     ;
     os << "\n" << prefix << prefix2 << "Scheduled     " << rhs.scheduledROBs()     ;
     os << "\n" << prefix << prefix2 << "Status OK    " << rhs.statusOkROBs()     ;
-    for (std::map<const uint32_t,robmonitor::ROBDataStruct>::iterator it=rhs.requested_ROBs.begin();
+    for (std::map<const uint32_t,robmonitor::ROBDataStruct>::const_iterator it=rhs.requested_ROBs.begin();
 	 it != rhs.requested_ROBs.end(); ++it) {
       os << "\n" << prefix << prefix2 << (*it).second;
     }
diff --git a/Trigger/TrigMonitoring/TrigCostMonitorMT/TrigCostMonitorMT/ITrigCostMTSvc.h b/Trigger/TrigMonitoring/TrigCostMonitorMT/TrigCostMonitorMT/ITrigCostMTSvc.h
index a5806b9dff2..05267833416 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitorMT/TrigCostMonitorMT/ITrigCostMTSvc.h
+++ b/Trigger/TrigMonitoring/TrigCostMonitorMT/TrigCostMonitorMT/ITrigCostMTSvc.h
@@ -58,7 +58,7 @@ public:
   /**
    * @brief To be used to cache ROBs for ROS
    */
-  virtual StatusCode monitorROS(const EventContext& context, robmonitor::ROBDataStruct payload) = 0;
+  virtual StatusCode monitorROS(const EventContext& context, robmonitor::ROBDataMonitorStruct payload) = 0;
 
 };
 
diff --git a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.cxx b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.cxx
index c0be8979c69..1dba114a61b 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.cxx
+++ b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.cxx
@@ -174,7 +174,7 @@ StatusCode TrigCostMTSvc::monitor(const EventContext& context, const AlgorithmId
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
-StatusCode TrigCostMTSvc::monitorROS(const EventContext& /*context*/, robmonitor::ROBDataStruct payload){
+StatusCode TrigCostMTSvc::monitorROS(const EventContext& /*context*/, robmonitor::ROBDataMonitorStruct payload){
   ATH_MSG_DEBUG( "Received ROB payload " << payload );
 
   // Associate payload with an algorithm
@@ -186,7 +186,7 @@ StatusCode TrigCostMTSvc::monitorROS(const EventContext& /*context*/, robmonitor
   }
 
   // Record data in TrigCostDataStore
-  ATH_MSG_DEBUG( "Adding " << payload.rob_id << " to " << theAlg.m_hash );
+  ATH_MSG_DEBUG( "Adding ROBs from" << payload.requestor_name << " to " << theAlg.m_hash );
   ATH_CHECK( m_rosData.push_back(theAlg, std::move(payload)) );
 
   return StatusCode::SUCCESS;
@@ -342,7 +342,7 @@ StatusCode TrigCostMTSvc::endEvent(const EventContext& context, SG::WriteHandle<
     aiToHandleIndex[ai.m_hash] = costOutputHandle->size() - 1;
   }
 
-  typedef tbb::concurrent_hash_map< AlgorithmIdentifier, std::vector<robmonitor::ROBDataStruct>, AlgorithmIdentifierHashCompare>::const_iterator ROBConstIt;
+  typedef tbb::concurrent_hash_map< AlgorithmIdentifier, std::vector<robmonitor::ROBDataMonitorStruct>, AlgorithmIdentifierHashCompare>::const_iterator ROBConstIt;
   ROBConstIt beginRob;
   ROBConstIt endRob;
   
@@ -356,16 +356,37 @@ StatusCode TrigCostMTSvc::endEvent(const EventContext& context, SG::WriteHandle<
     }
 
     // Save ROB data via TrigComposite
-    for (const robmonitor::ROBDataStruct& robData : it->second) {
+    for (const robmonitor::ROBDataMonitorStruct& robData : it->second) {
       xAOD::TrigComposite* tc = new xAOD::TrigComposite();
       rosOutputHandle->push_back(tc); 
 
+      // Retrieve ROB requests data into primitives vectors
+      std::vector<uint32_t> robs_id;
+      std::vector<uint32_t> robs_size;
+      std::vector<unsigned> robs_history;
+      std::vector<uint32_t> robs_status;
+
+      robs_id.reserve(robData.requested_ROBs.size());
+      robs_size.reserve(robData.requested_ROBs.size());
+      robs_history.reserve(robData.requested_ROBs.size());
+      robs_status.reserve(robData.requested_ROBs.size());
+
+      for (const auto& rob : robData.requested_ROBs) {
+        robs_id.push_back(rob.second.rob_id);
+        robs_size.push_back(rob.second.rob_size);
+        robs_history.push_back(rob.second.rob_history);
+        robs_status.push_back(rob.second.rob_status_words.size() ? rob.second.rob_status_words.at(0) : 0);
+      }
+
       bool result = true;
       result &= tc->setDetail("alg_idx", aiToHandleIndex[aiHash]);
-      result &= tc->setDetail("rob_id", robData.rob_id);
-      result &= tc->setDetail("rob_size", robData.rob_size);
-      result &= tc->setDetail<unsigned>("rob_history", robData.rob_history);
-      result &= tc->setDetail("rob_status_words", robData.rob_status_words);
+      result &= tc->setDetail("lvl1ID", robData.lvl1ID);
+      result &= tc->setDetail<std::vector<uint32_t>>("robs_id", robs_id);
+      result &= tc->setDetail<std::vector<uint32_t>>("robs_size", robs_size);
+      result &= tc->setDetail<std::vector<unsigned>>("robs_history", robs_history);
+      result &= tc->setDetail<std::vector<uint32_t>>("robs_status_words", robs_status);
+      result &= tc->setDetail("start", robData.start_time);
+      result &= tc->setDetail("stop", robData.end_time);
 
       if (!result) ATH_MSG_WARNING("Failed to append one or more details to trigger cost ROS TC");
     }
diff --git a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.h b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.h
index 6cc891368f6..4ff5b1074c6 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.h
+++ b/Trigger/TrigMonitoring/TrigCostMonitorMT/src/TrigCostMTSvc.h
@@ -93,7 +93,7 @@ class TrigCostMTSvc : public extends <AthService, ITrigCostMTSvc> {
    * @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;
+  virtual StatusCode monitorROS(const EventContext& context, robmonitor::ROBDataMonitorStruct payload) override;
 
   private: 
 
@@ -136,7 +136,7 @@ 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
+  TrigCostDataStore<std::vector<robmonitor::ROBDataMonitorStruct>> 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.
 
diff --git a/Trigger/TriggerCommon/TrigEDMConfig/python/TriggerEDMRun3.py b/Trigger/TriggerCommon/TrigEDMConfig/python/TriggerEDMRun3.py
index cc932f86b60..cdfba7eec51 100644
--- a/Trigger/TriggerCommon/TrigEDMConfig/python/TriggerEDMRun3.py
+++ b/Trigger/TriggerCommon/TrigEDMConfig/python/TriggerEDMRun3.py
@@ -97,7 +97,7 @@ 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.rob_id.rob_size.rob_history.rob_status_words', 'CostMonDS ESD', 'Steer'),
+    ('xAOD::TrigCompositeAuxContainer#HLT_TrigCostROSContainerAux.alg_idx.lvl1ID.robs_is.robs_size.robs_history.robs_status_words.start.stop', 'CostMonDS ESD', 'Steer'),
 
     # Run-2 L1 (temporary)
     ('xAOD::MuonRoIContainer#LVL1MuonRoIs' ,                 'ESD AODFULL AODSLIM AODVERYSLIM AODBLSSLIM', 'L1'),
-- 
GitLab