LCOV - code coverage report
Current view: top level - trigger/plugins - RandomTCMakerModule.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 160 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 45 0

            Line data    Source code
       1              : /**
       2              :  * @file RandomTCMakerModule.cpp RandomTCMakerModule class
       3              :  * implementation
       4              :  *
       5              :  * This is part of the DUNE DAQ Software Suite, copyright 2020.
       6              :  * Licensing/copyright details are in the COPYING file that you should have
       7              :  * received with this code.
       8              :  */
       9              : 
      10              : #include "RandomTCMakerModule.hpp"
      11              : 
      12              : #include "trigger/Issues.hpp"
      13              : 
      14              : #include "daqdataformats/ComponentRequest.hpp"
      15              : #include "dfmessages/TimeSync.hpp"
      16              : #include "dfmessages/TriggerDecision.hpp"
      17              : #include "dfmessages/TriggerInhibit.hpp"
      18              : #include "dfmessages/Types.hpp"
      19              : #include "iomanager/IOManager.hpp"
      20              : #include "logging/Logging.hpp"
      21              : #include "trgdataformats/Types.hpp"
      22              : #include "triggeralgs/TriggerCandidate.hpp"
      23              : #include "utilities/TimestampEstimatorSystem.hpp"
      24              : #include "utilities/TimestampEstimatorTimeSync.hpp"
      25              : 
      26              : #include <algorithm>
      27              : #include <cassert>
      28              : #include <pthread.h>
      29              : #include <random>
      30              : #include <string>
      31              : #include <vector>
      32              : 
      33              : namespace dunedaq {
      34              : 
      35              : namespace trigger {
      36              : 
      37            0 : RandomTCMakerModule::RandomTCMakerModule(const std::string& name)
      38              :   : DAQModule(name)
      39            0 :   , m_time_sync_source(nullptr)
      40            0 :   , m_trigger_candidate_sink(nullptr)
      41            0 :   , m_run_number(0)
      42              : {
      43            0 :   register_command("conf", &RandomTCMakerModule::do_configure);
      44            0 :   register_command("start", &RandomTCMakerModule::do_start);
      45            0 :   register_command("stop_trigger_sources", &RandomTCMakerModule::do_stop);
      46            0 :   register_command("scrap", &RandomTCMakerModule::do_scrap);
      47            0 :   register_command("change_rate", &RandomTCMakerModule::do_change_trigger_rate);
      48            0 : }
      49              : 
      50              : void
      51            0 : RandomTCMakerModule::init(std::shared_ptr<appfwk::ConfigurationManager> mcfg)
      52              : {
      53            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Entering init() method";
      54              : 
      55            0 :   m_mtrg = mcfg->get_dal<appmodel::RandomTCMakerModule>(get_name());
      56              : 
      57              :   // Get the clock speed from detector configuration
      58            0 :   m_clock_speed_hz = mcfg->get_session()->get_detector_configuration()->get_clock_speed_hz();
      59              : 
      60            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Exiting init() method";
      61            0 : }
      62              : 
      63              : void
      64            0 : RandomTCMakerModule::generate_opmon_data()
      65              : {
      66            0 :   opmon::RandomTCMakerInfo info;
      67              : 
      68            0 :   info.set_tc_made_count(m_tc_made_count.load());
      69            0 :   info.set_tc_sent_count(m_tc_sent_count.load());
      70            0 :   info.set_tc_failed_sent_count(m_tc_failed_sent_count.load());
      71              : 
      72            0 :   this->publish(std::move(info));
      73              : 
      74            0 :   if (m_latency_monitoring.load() && m_running_flag.load()) {
      75            0 :     opmon::TriggerLatencyStandalone lat_info;
      76              : 
      77            0 :     lat_info.set_latency_out(m_latency_instance.get_latency_out());
      78              : 
      79            0 :     this->publish(std::move(lat_info));
      80            0 :   }
      81            0 : }
      82              : 
      83              : void
      84            0 : RandomTCMakerModule::do_configure(const CommandData_t& /*obj*/)
      85              : {
      86            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Entering conf() method";
      87              : 
      88              :   // Get the output connections
      89            0 :   for (auto con : m_mtrg->get_outputs()) {
      90            0 :     TLOG() << "TC sink is " << con->class_name() << "@" << con->UID();
      91            0 :     m_trigger_candidate_sink = get_iom_sender<triggeralgs::TriggerCandidate>(con->UID());
      92              :   }
      93              : 
      94              :   // Get the input connections
      95            0 :   for (auto con : m_mtrg->get_inputs()) {
      96              :     // Get the time sync source
      97            0 :     TLOG() << "TimeSync receiver connection is " << con->class_name() << "@" << con->UID() << " with tag "
      98            0 :            << get_name();
      99            0 :     m_time_sync_source = get_iomanager()->get_receiver<dfmessages::TimeSync>(con->UID(), get_name());
     100              :   }
     101            0 :   m_conf = m_mtrg->get_configuration();
     102              : 
     103              :   // Get the TC out configuration
     104            0 :   m_tcout_time_backshift_ts = m_conf->get_candidate_backshift_ts();
     105            0 :   m_tcout_time_before_ts = m_conf->get_candidate_window_before_ts();
     106            0 :   m_tcout_time_after_ts = m_conf->get_candidate_window_after_ts();
     107              : 
     108            0 :   m_tcout_type =
     109            0 :     static_cast<TCType>(dunedaq::trgdataformats::string_to_trigger_candidate_type(m_conf->get_candidate_type_name()));
     110              : 
     111              :   // Throw error if unknown TC type
     112            0 :   if (m_tcout_type == TCType::kUnknown) {
     113            0 :     throw(InvalidConfiguration(ERS_HERE, "Provided an unknown TC type output to RandomTCMakerModule!"));
     114              :   }
     115              : 
     116            0 :   m_latency_monitoring.store(m_conf->get_latency_monitoring());
     117            0 :   m_trigger_rate_hz.store(m_conf->get_trigger_rate_hz());
     118              : 
     119            0 :   TLOG() << "RandomTCMaker will output TC of type: " << m_conf->get_candidate_type_name();
     120            0 :   TLOG() << "TC window center offset: " << m_tcout_time_backshift_ts;
     121            0 :   TLOG() << "TC window time before: " << m_tcout_time_before_ts << " time after: " << m_tcout_time_after_ts;
     122            0 :   TLOG() << "Clock speed is: " << m_clock_speed_hz;
     123            0 :   TLOG() << "Output trigger rate is: " << m_trigger_rate_hz.load();
     124              : 
     125            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << ": Exiting conf() method";
     126            0 : }
     127              : 
     128              : void
     129            0 : RandomTCMakerModule::do_start(const CommandData_t& obj)
     130              : {
     131            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Entering start() method";
     132            0 :   m_run_number = obj.value<dunedaq::daqdataformats::run_number_t>("run", 0);
     133              : 
     134            0 :   m_running_flag.store(true);
     135              : 
     136              :   // OpMon.
     137            0 :   m_tc_made_count.store(0);
     138            0 :   m_tc_sent_count.store(0);
     139            0 :   m_tc_failed_sent_count.store(0);
     140              : 
     141            0 :   std::string timestamp_method = m_conf->get_timestamp_method();
     142            0 :   if (timestamp_method == "kTimeSync") {
     143            0 :     TLOG_DEBUG(0) << "Creating TimestampEstimatorTimeSync";
     144            0 :     m_timestamp_estimator.reset(new utilities::TimestampEstimatorTimeSync(m_run_number, m_clock_speed_hz));
     145            0 :     m_time_sync_source->add_callback(
     146            0 :       std::bind(&utilities::TimestampEstimatorTimeSync::timesync_callback<dfmessages::TimeSync>,
     147            0 :                 reinterpret_cast<utilities::TimestampEstimatorTimeSync*>(m_timestamp_estimator.get()),
     148              :                 std::placeholders::_1));
     149            0 :   } else if (timestamp_method == "kSystemClock") {
     150            0 :     TLOG_DEBUG(0) << "Creating TimestampEstimatorSystem";
     151            0 :     m_timestamp_estimator.reset(new utilities::TimestampEstimatorSystem(m_clock_speed_hz));
     152              :   } else {
     153              :     // TODO: write some error message
     154              :   }
     155              : 
     156              :   // Check if the trigger rate was changed in the starting parameters, and set it if so
     157            0 :   auto start_params = obj.get<rcif::cmd::StartParams>();
     158            0 :   if (start_params.trigger_rate > 0) {
     159            0 :     TLOG() << "Changing trigger rate from " << m_trigger_rate_hz.load() << " to " << start_params.trigger_rate;
     160            0 :     m_trigger_rate_hz.store(start_params.trigger_rate);
     161              :   }
     162              : 
     163            0 :   m_send_trigger_candidates_thread = std::thread(&RandomTCMakerModule::send_trigger_candidates, this);
     164            0 :   pthread_setname_np(m_send_trigger_candidates_thread.native_handle(), "random-tc-maker");
     165            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << ": Exiting start() method";
     166            0 : }
     167              : 
     168              : void
     169            0 : RandomTCMakerModule::do_stop(const CommandData_t& /*obj*/)
     170              : {
     171            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Entering stop() method";
     172            0 :   m_running_flag.store(false);
     173              : 
     174            0 :   m_send_trigger_candidates_thread.join();
     175              : 
     176            0 :   if (m_conf->get_timestamp_method() == "kTimeSync") {
     177            0 :     m_time_sync_source->remove_callback();
     178              :   }
     179              : 
     180            0 :   m_timestamp_estimator.reset(nullptr); // Calls TimestampEstimator dtor
     181              : 
     182            0 :   print_opmon_stats();
     183            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << ": Exiting stop() method";
     184            0 : }
     185              : 
     186              : void
     187            0 : RandomTCMakerModule::do_scrap(const CommandData_t& /*obj*/)
     188              : {
     189            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Entering scrap() method";
     190            0 :   m_time_sync_source.reset();
     191            0 :   m_trigger_candidate_sink.reset();
     192            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << ": Exiting scrap() method";
     193            0 : }
     194              : 
     195              : void
     196            0 : RandomTCMakerModule::do_change_trigger_rate(const CommandData_t& obj)
     197              : {
     198            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Entering change-rate() method";
     199            0 :   auto change_rate_params = obj.get<rcif::cmd::ChangeRateParams>();
     200              : 
     201            0 :   TLOG() << "Changing trigger rate from " << m_trigger_rate_hz.load() << " to " << change_rate_params.trigger_rate;
     202              : 
     203            0 :   m_trigger_rate_hz.store(change_rate_params.trigger_rate);
     204            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << ": Exiting change-rate() method";
     205            0 : }
     206              : 
     207              : triggeralgs::TriggerCandidate
     208            0 : RandomTCMakerModule::create_candidate(dfmessages::timestamp_t timestamp)
     209              : {
     210            0 :   triggeralgs::TriggerCandidate candidate;
     211            0 :   candidate.time_candidate = timestamp - m_tcout_time_backshift_ts;
     212            0 :   candidate.time_start = candidate.time_candidate - m_tcout_time_before_ts;
     213            0 :   candidate.time_end = candidate.time_candidate + m_tcout_time_after_ts;
     214            0 :   candidate.detid = { 0 };
     215            0 :   candidate.type = m_tcout_type;
     216              : 
     217              :   // TODO: Originally kHSIEventToTriggerCandidate
     218            0 :   candidate.algorithm = triggeralgs::TriggerCandidate::Algorithm::kCustom;
     219              : 
     220            0 :   return candidate;
     221              : }
     222              : 
     223              : uint64_t
     224            0 : RandomTCMakerModule::get_interval(std::mt19937& gen)
     225              : {
     226            0 :   std::string time_distribution = m_conf->get_time_distribution();
     227              : 
     228            0 :   uint64_t interval = m_clock_speed_hz / m_trigger_rate_hz.load();
     229              : 
     230            0 :   if (time_distribution == "kUniform") {
     231              :     return interval;
     232            0 :   } else if (time_distribution == "kPoisson") {
     233            0 :     std::exponential_distribution<double> d(1.0 / interval);
     234            0 :     return static_cast<uint64_t>(0.5 + d(gen));
     235              :   } else {
     236            0 :     TLOG_DEBUG(1) << get_name() << " unknown distribution! Using kUniform.";
     237              :   }
     238            0 :   return interval;
     239            0 : }
     240              : 
     241              : void
     242            0 : RandomTCMakerModule::send_trigger_candidates()
     243              : {
     244              :   // OpMon.
     245            0 :   m_tc_sent_count.store(0);
     246              : 
     247            0 :   std::mt19937 gen(m_run_number);
     248            0 :   dfmessages::timestamp_t initial_timestamp;
     249              :   // Wait for there to be a valid timestamp estimate before we start
     250            0 :   if (m_timestamp_estimator->wait_for_valid_timestamp(m_running_flag, initial_timestamp) ==
     251              :       utilities::TimestampEstimatorBase::kInterrupted) {
     252            0 :     return;
     253              :   }
     254              : 
     255            0 :   dfmessages::timestamp_t next_trigger_timestamp = initial_timestamp;
     256            0 :   TLOG_DEBUG(1) << get_name() << " initial timestamp estimate is " << initial_timestamp;
     257              : 
     258            0 :   while (m_running_flag.load()) {
     259              :     // If trigger rate is 0, just sleep. Need to use small number here because
     260              :     // of floating point precision...
     261            0 :     constexpr float epsilon = 1e-9;
     262            0 :     if (m_trigger_rate_hz.load() <= epsilon) {
     263            0 :       std::this_thread::sleep_for(std::chrono::milliseconds(100));
     264            0 :       continue;
     265              :     }
     266              : 
     267            0 :     dfmessages::timestamp_t actual_timestamp;
     268            0 :     if (m_timestamp_estimator->wait_for_requested_timestamp(next_trigger_timestamp, m_running_flag, actual_timestamp) ==
     269              :         utilities::TimestampEstimatorBase::kInterrupted) {
     270              :       break;
     271              :     }
     272            0 :     triggeralgs::TriggerCandidate candidate = create_candidate(actual_timestamp);
     273              : 
     274            0 :     m_tc_made_count++;
     275              : 
     276            0 :     TLOG_DEBUG(1) << get_name() << " at timestamp " << actual_timestamp << ", pushing a candidate with timestamp "
     277            0 :                   << candidate.time_candidate;
     278              : 
     279            0 :     if (m_latency_monitoring.load())
     280            0 :       m_latency_instance.update_latency_out(candidate.time_candidate);
     281            0 :     try {
     282            0 :       m_trigger_candidate_sink->send(std::move(candidate), std::chrono::milliseconds(10));
     283            0 :       m_tc_sent_count++;
     284            0 :     } catch (const ers::Issue& e) {
     285            0 :       ers::error(e);
     286            0 :       m_tc_failed_sent_count++;
     287            0 :     }
     288              : 
     289            0 :     next_trigger_timestamp = actual_timestamp + get_interval(gen);
     290            0 :   }
     291              : }
     292              : 
     293              : void
     294            0 : RandomTCMakerModule::print_opmon_stats()
     295              : {
     296            0 :   TLOG() << "RandomTCMaker opmon counters summary:";
     297            0 :   TLOG() << "------------------------------";
     298            0 :   TLOG() << "Made TCs: \t\t\t" << m_tc_made_count;
     299            0 :   TLOG() << "Sent TCs: \t\t\t" << m_tc_sent_count;
     300            0 :   TLOG() << "Failed to send TCs: \t" << m_tc_failed_sent_count;
     301            0 :   TLOG();
     302            0 : }
     303              : 
     304              : } // namespace trigger
     305              : } // namespace dunedaq
     306              : 
     307            0 : DEFINE_DUNE_DAQ_MODULE(dunedaq::trigger::RandomTCMakerModule)
     308              : 
     309              : // Local Variables:
     310              : // c-basic-offset: 2
     311              : // End:
        

Generated by: LCOV version 2.0-1