From ed4f2fc4177a81921b4e2a23939d0a8328891b9b Mon Sep 17 00:00:00 2001
From: Rafal Bielski <rafal.bielski@cern.ch>
Date: Wed, 21 Nov 2018 16:13:36 +0100
Subject: [PATCH] add time burning option to MTCalibPebHypoTool

also change the tool input from a vector to a single object (no need for multiple inputs)


Former-commit-id: 6ec3aabde193a328bef99ecbb9c4e190503cfb90
---
 .../TrigExPartialEB/share/MTCalibPeb.py       |  4 ++
 .../TrigExPartialEB/src/MTCalibPebHypoAlg.cxx |  9 +--
 .../src/MTCalibPebHypoTool.cxx                | 66 +++++++++++++++----
 .../TrigExPartialEB/src/MTCalibPebHypoTool.h  | 30 ++++++---
 4 files changed, 84 insertions(+), 25 deletions(-)

diff --git a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py
index dd5a507f2dc..599385c5751 100644
--- a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py
+++ b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py
@@ -55,9 +55,13 @@ hypo.HypoOutputDecisions = "MTCalibPebDecisions"
 
 hypoTool1 = MTCalibPebHypoTool("HLT_MTCalibPeb1")
 hypoTool1.RandomAcceptRate = 0.75
+hypoTool1.BurnTimePerCycleMillisec = 200
+hypoTool1.NumBurnCycles = 3
 
 hypoTool2 = MTCalibPebHypoTool("HLT_MTCalibPeb2")
 hypoTool2.RandomAcceptRate = 0.25
+hypoTool2.BurnTimePerCycleMillisec = 1000
+hypoTool2.NumBurnCycles = 10
 
 hypo.HypoTools = [hypoTool1, hypoTool2]
 
diff --git a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoAlg.cxx b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoAlg.cxx
index b752081e438..9d8a72ff20b 100644
--- a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoAlg.cxx
+++ b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoAlg.cxx
@@ -28,6 +28,7 @@ MTCalibPebHypoAlg::~MTCalibPebHypoAlg() {}
 // =============================================================================
 StatusCode MTCalibPebHypoAlg::initialize() {
   ATH_MSG_INFO("Initialising " << name());
+  ATH_CHECK(m_hypoTools.retrieve());
   return StatusCode::SUCCESS;
 }
 
@@ -36,6 +37,7 @@ StatusCode MTCalibPebHypoAlg::initialize() {
 // =============================================================================
 StatusCode MTCalibPebHypoAlg::finalize() {
   ATH_MSG_INFO("Finalising " << name());
+  ATH_CHECK(m_hypoTools.release());
   return StatusCode::SUCCESS;
 }
 
@@ -50,12 +52,11 @@ StatusCode MTCalibPebHypoAlg::execute_r(const EventContext& eventContext) const
   auto aux = std::make_unique<DecisionAuxContainer>();
   decisions->setStore(aux.get());
 
-  // Prepare input for hypo tools
-  std::vector<MTCalibPebHypoTool::Input> toolInput;
-
   // Create new decision
   Decision* newd = newDecisionIn(decisions.get()); // DecisionContainer decisions owns the pointer
-  toolInput.emplace_back(newd);
+
+  // Prepare input for hypo tools
+  MTCalibPebHypoTool::Input toolInput(newd, eventContext);
 
   // Call the hypo tools
   for (const auto& tool: m_hypoTools) {
diff --git a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.cxx b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.cxx
index ecb5371e293..c94abfa7cfe 100644
--- a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.cxx
+++ b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.cxx
@@ -2,15 +2,37 @@
   Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
 */
 
+// Trigger includes
 #include "MTCalibPebHypoTool.h"
+
+// Athena includes
+#include "AthenaKernel/Timeout.h"
+
+// System includes
 #include <random>
+#include <thread>
 
 // Local implementation-specific helper methods
 namespace {
+  /// Returns a reference to static thread-local random number generator
+  std::mt19937& threadLocalGenerator() {
+    static thread_local std::random_device rd; // used only to ensure different seeds for mt19937
+    static thread_local std::mt19937 generator(rd());
+    return generator;
+  }
+  /// Basic random real number generation
+  template<typename T> T randomRealNumber(const T min, const T max) {
+    std::uniform_real_distribution<T> distribution(min, max);
+    return distribution(threadLocalGenerator());
+  }
+  /// Basic random integer generation
+  template<typename T> T randomInteger(const T min, const T max) {
+    std::uniform_int_distribution<T> distribution(min, max);
+    return distribution(threadLocalGenerator());
+  }
+  /// Random bool with a given true rate
   bool randomAccept(const double acceptRate) {
-      static thread_local std::mt19937 generator;
-      std::uniform_real_distribution<double> distribution(0.0, 1.0);
-      return (distribution(generator) < acceptRate);
+      return (randomRealNumber(0.0, 1.0) < acceptRate);
   }
 }
 
@@ -35,17 +57,37 @@ StatusCode MTCalibPebHypoTool::initialize() {
 }
 
 // =============================================================================
-StatusCode MTCalibPebHypoTool::decide(const std::vector<MTCalibPebHypoTool::Input>& inputs) const {
+StatusCode MTCalibPebHypoTool::decide(const MTCalibPebHypoTool::Input& input) const {
 
-  bool accept = randomAccept(m_acceptRate);
-  for (auto& in : inputs) {
-    if (accept) {
-      ATH_MSG_DEBUG("Decision " << m_decisionId << " is accept");
-      TrigCompositeUtils::addDecisionID(m_decisionId, in.decision);
-    }
-    else {
-      ATH_MSG_DEBUG("Decision " << m_decisionId << " is reject");
+  // ---------------------------------------------------------------------------
+  // Burn CPU time
+  // ---------------------------------------------------------------------------
+  for (unsigned int iCycle = 0; iCycle < m_numBurnCycles; ++iCycle) {
+    if (Athena::Timeout::instance(input.eventContext).reached()) {
+      if (m_failOnTimeout) {
+        ATH_MSG_ERROR("Timeout reached in CPU time burning cycle # " << iCycle+1 << " and FailOnTimeout is true");
+        return StatusCode::FAILURE;
+      }
+      ATH_MSG_INFO("Timeout reached in CPU time burning cycle # " << iCycle+1);
+      break;
     }
+    unsigned int burnTime = m_burnTimeRandomly
+                            ? randomInteger<unsigned int>(0, m_burnTimePerCycleMillisec)
+                            : m_burnTimePerCycleMillisec.value();
+    ATH_MSG_VERBOSE("CPU time burning cycle # " << iCycle+1 << ", burn time [ms] = " << burnTime);
+    std::this_thread::sleep_for(std::chrono::milliseconds(burnTime));
+  }
+
+  // ---------------------------------------------------------------------------
+  // Random accept decision
+  // ---------------------------------------------------------------------------
+  bool accept = randomAccept(m_acceptRate);
+  if (accept) {
+    ATH_MSG_DEBUG("Decision " << m_decisionId << " is accept");
+    TrigCompositeUtils::addDecisionID(m_decisionId, input.decision);
+  }
+  else {
+    ATH_MSG_DEBUG("Decision " << m_decisionId << " is reject");
   }
 
   return StatusCode::SUCCESS;
diff --git a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.h b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.h
index 2fa92ae5974..d46d97904a8 100644
--- a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.h
+++ b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.h
@@ -15,9 +15,6 @@
 // TDAQ includes
 #include "eformat/StreamTag.h"
 
-// System includes
-#include <random>
-
 /** @class MTCalibPebHypoTool
  *  @brief Base class for tools used by MTCalibPebHypoAlg
  **/
@@ -33,23 +30,38 @@ public:
 
   // ------------------------- Public types ------------------------------------
   struct Input {
-    Input(TrigCompositeUtils::Decision* d)
-    : decision(d) {}
+    Input(TrigCompositeUtils::Decision* d, const EventContext& ctx)
+    : decision(d), eventContext(ctx) {}
     TrigCompositeUtils::Decision* decision;
+    const EventContext& eventContext;
   };
 
   // ------------------------- Specific methods of this class ------------------
   /// Decides whether to accept the event
-  StatusCode decide(const std::vector<Input>& inputs) const;
+  StatusCode decide(const Input& input) const;
 
 private:
   // ------------------------- Properties --------------------------------------
   Gaudi::Property<double> m_acceptRate {
-    this,
-    "RandomAcceptRate",
-    -1,
+    this, "RandomAcceptRate", -1,
     "Rate of random accepts, <=0 is never, >=1 is always"
   };
+  Gaudi::Property<unsigned int> m_burnTimePerCycleMillisec {
+    this, "BurnTimePerCycleMillisec", 0,
+    "Burn time per cycle in milliseconds"
+  };
+  Gaudi::Property<unsigned int> m_numBurnCycles {
+    this, "NumBurnCycles", 0,
+    "Number of time burning cycles"
+  };
+  Gaudi::Property<bool> m_burnTimeRandomly {
+    this, "BurnTimeRandomly", true,
+    "If true, burn time per cycle is a random value from uniform distribution between 0 and the given value"
+  };
+  Gaudi::Property<bool> m_failOnTimeout {
+    this, "FailOnTimeout", true,
+    "If true, the execution will return StatusCode::FAILURE when Athena timeout is detected"
+  };
 
   // ------------------------- Other private members ---------------------------
   /// The decision id of the tool instance
-- 
GitLab