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

            Line data    Source code
       1              : /**
       2              :  * @file TCProcessor.hpp TPC TP specific Task based raw processor
       3              :  *
       4              :  * This is part of the DUNE DAQ , copyright 2023.
       5              :  * Licensing/copyright details are in the COPYING file that you should have
       6              :  * received with this code.
       7              :  */
       8              : #include "trigger/TCProcessor.hpp" // NOLINT(build/include)
       9              : 
      10              : #include "iomanager/Sender.hpp"
      11              : #include "logging/Logging.hpp"
      12              : 
      13              : #include "datahandlinglibs/DataHandlingIssues.hpp"
      14              : #include "datahandlinglibs/FrameErrorRegistry.hpp"
      15              : #include "datahandlinglibs/ReadoutLogging.hpp"
      16              : #include "datahandlinglibs/models/IterableQueueModel.hpp"
      17              : #include "trigger/TCWrapper.hpp"
      18              : #include "triggeralgs/TriggerCandidate.hpp"
      19              : 
      20              : #include "appmodel/TCDataProcessor.hpp"
      21              : #include "appmodel/TriggerDataHandlerModule.hpp"
      22              : 
      23              : using dunedaq::datahandlinglibs::logging::TLVL_BOOKKEEPING;
      24              : using dunedaq::datahandlinglibs::logging::TLVL_TAKE_NOTE;
      25              : 
      26              : // THIS SHOULDN'T BE HERE!!!!! But it is necessary.....
      27              : DUNE_DAQ_TYPESTRING(dunedaq::trigger::TCWrapper, "TriggerCandidate")
      28              : 
      29              : namespace dunedaq {
      30              : namespace trigger {
      31              : 
      32            0 : TCProcessor::TCProcessor(std::unique_ptr<datahandlinglibs::FrameErrorRegistry>& error_registry,
      33            0 :                          bool post_processing_enabled)
      34            0 :   : datahandlinglibs::TaskRawDataProcessorModel<TCWrapper>(error_registry, post_processing_enabled)
      35              : {
      36            0 : }
      37              : 
      38            0 : TCProcessor::~TCProcessor() {}
      39              : 
      40              : void
      41            0 : TCProcessor::start(const appfwk::DAQModule::CommandData_t& args)
      42              : {
      43            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "TCProcessor: Entering start() method";
      44              : 
      45            0 :   m_running_flag.store(true);
      46            0 :   m_send_trigger_decisions_thread = std::thread(&TCProcessor::send_trigger_decisions, this);
      47            0 :   pthread_setname_np(m_send_trigger_decisions_thread.native_handle(), "mlt-dec"); // TODO: originally mlt-trig-dec
      48              : 
      49              :   // Reset stats
      50            0 :   m_tds_created_count.store(0);
      51            0 :   m_tds_sent_count.store(0);
      52            0 :   m_tds_dropped_count.store(0);
      53            0 :   m_tds_failed_bitword_count.store(0);
      54            0 :   m_tds_cleared_count.store(0);
      55              :   // per TC
      56            0 :   m_tc_received_count.store(0);
      57            0 :   m_tds_created_tc_count.store(0);
      58            0 :   m_tds_sent_tc_count.store(0);
      59            0 :   m_tds_dropped_tc_count.store(0);
      60            0 :   m_tds_failed_bitword_tc_count.store(0);
      61            0 :   m_tds_cleared_tc_count.store(0);
      62            0 :   m_tc_ignored_count.store(0);
      63            0 :   inherited::start(args);
      64              : 
      65            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "TCProcessor: Exiting start() method";
      66            0 : }
      67              : 
      68              : void
      69            0 : TCProcessor::stop(const appfwk::DAQModule::CommandData_t& args)
      70              : {
      71            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "TCProcessor: Entering stop() method";
      72              : 
      73            0 :   inherited::stop(args);
      74            0 :   m_running_flag.store(false);
      75              : 
      76              :   // Make sure condition_variable knows we flipped running flag
      77            0 :   {
      78            0 :     std::lock_guard<std::mutex> lock(m_td_vector_mutex);
      79            0 :     m_cv.notify_all();
      80            0 :   }
      81              : 
      82              :   // Wait for the TD-sending thread to stop
      83            0 :   m_send_trigger_decisions_thread.join();
      84              : 
      85              :   // Drop all TDs in vectors at run stage change. Have to do this
      86              :   // after joining m_send_trigger_decisions_thread so we don't
      87              :   // concurrently access the vectors
      88            0 :   clear_td_vectors();
      89              : 
      90            0 :   print_opmon_stats();
      91              : 
      92            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "TCProcessor: Exiting stop() method";
      93            0 : }
      94              : 
      95              : void
      96            0 : TCProcessor::conf(const appmodel::DataHandlerModule* cfg)
      97              : {
      98            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "TCProcessor: Entering conf() method";
      99              : 
     100            0 :   auto mtrg = cfg->cast<appmodel::TriggerDataHandlerModule>();
     101            0 :   if (mtrg == nullptr) {
     102            0 :     throw(InvalidConfiguration(ERS_HERE, "Provided null TriggerDataHandlerModule configuration!"));
     103              :   }
     104            0 :   for (auto output : mtrg->get_outputs()) {
     105            0 :     try {
     106            0 :       if (output->get_data_type() == "TriggerDecision") {
     107            0 :         m_td_sink = get_iom_sender<dfmessages::TriggerDecision>(output->UID());
     108              :       }
     109            0 :     } catch (const ers::Issue& excpt) {
     110            0 :       ers::error(datahandlinglibs::ResourceQueueError(ERS_HERE, "td", "DefaultRequestHandlerModel", excpt));
     111            0 :     }
     112              :   }
     113              : 
     114            0 :   auto dp = mtrg->get_module_configuration()->get_data_processor();
     115            0 :   auto proc_conf = dp->cast<appmodel::TCDataProcessor>();
     116              : 
     117              :   // Add all Source IDs to mandatoy links for now...
     118            0 :   for (auto const& link : mtrg->get_mandatory_source_ids()) {
     119            0 :     m_mandatory_links.push_back(
     120            0 :       dfmessages::SourceID{ daqdataformats::SourceID::string_to_subsystem(link->get_subsystem()), link->get_sid() });
     121              :   }
     122            0 :   for (auto const& link : mtrg->get_enabled_source_ids()) {
     123            0 :     m_mandatory_links.push_back(
     124            0 :       dfmessages::SourceID{ daqdataformats::SourceID::string_to_subsystem(link->get_subsystem()), link->get_sid() });
     125              :   }
     126              : 
     127              :   // TODO: Group links!
     128              :   // m_group_links_data = conf->get_groups_links();
     129            0 :   parse_group_links(m_group_links_data);
     130            0 :   print_group_links();
     131            0 :   m_total_group_links = m_group_links.size();
     132            0 :   TLOG_DEBUG(3) << "Total group links: " << m_total_group_links;
     133              : 
     134            0 :   m_tc_merging = proc_conf->get_merge_overlapping_tcs();
     135            0 :   m_ignore_tc_pileup = proc_conf->get_ignore_overlapping_tcs();
     136            0 :   m_buffer_timeout = proc_conf->get_buffer_timeout();
     137            0 :   m_send_timed_out_tds = (m_ignore_tc_pileup) ? false : proc_conf->get_td_out_of_timeout();
     138            0 :   m_td_readout_limit = proc_conf->get_td_readout_limit();
     139            0 :   m_ignored_tc_types = proc_conf->get_ignore_tc();
     140            0 :   m_ignoring_tc_types = !m_ignored_tc_types.empty();
     141              : 
     142              :   // Trigger bitwords
     143            0 :   std::vector<const appmodel::TriggerBitword*> bitwords = proc_conf->get_trigger_bitwords();
     144            0 :   m_use_bitwords = !bitwords.empty();
     145            0 :   if (m_use_bitwords) {
     146            0 :     set_trigger_bitwords(bitwords);
     147            0 :     print_trigger_bitwords();
     148              :   }
     149            0 :   TLOG_DEBUG(3) << "Use bitwords: " << m_use_bitwords;
     150            0 :   TLOG_DEBUG(3) << "Allow merging: " << m_tc_merging;
     151            0 :   TLOG_DEBUG(3) << "Ignore pileup: " << m_ignore_tc_pileup;
     152            0 :   TLOG_DEBUG(3) << "Buffer timeout: " << m_buffer_timeout;
     153            0 :   TLOG_DEBUG(3) << "Should send timed out TDs: " << m_send_timed_out_tds;
     154            0 :   TLOG_DEBUG(3) << "TD readout limit: " << m_td_readout_limit;
     155              : 
     156              :   // ROI map
     157            0 :   m_roi_conf_data = proc_conf->get_roi_group_conf();
     158            0 :   m_use_roi_readout = !m_roi_conf_data.empty();
     159            0 :   if (m_use_roi_readout) {
     160            0 :     parse_roi_conf(m_roi_conf_data);
     161            0 :     print_roi_conf(m_roi_conf);
     162              :   }
     163            0 :   TLOG_DEBUG(3) << "Use ROI readout?: " << m_use_roi_readout;
     164              : 
     165              :   // Custom readout map
     166            0 :   m_readout_window_map_data = proc_conf->get_tc_readout_map();
     167            0 :   m_use_readout_map = !m_readout_window_map_data.empty();
     168            0 :   if (m_use_readout_map) {
     169            0 :     parse_readout_map(m_readout_window_map_data);
     170            0 :     print_readout_map(m_readout_window_map);
     171              :   }
     172            0 :   TLOG_DEBUG(3) << "Use readout map: " << m_use_readout_map;
     173              : 
     174              :   // Ignoring TC types
     175            0 :   TLOG_DEBUG(3) << "Ignoring TC types: " << m_ignoring_tc_types;
     176            0 :   if (m_ignoring_tc_types) {
     177            0 :     TLOG_DEBUG(3) << "TC types to ignore: ";
     178            0 :     for (std::vector<unsigned int>::iterator it = m_ignored_tc_types.begin(); it != m_ignored_tc_types.end();) {
     179            0 :       TLOG_DEBUG(3) << *it;
     180            0 :       ++it;
     181              :     }
     182              :   }
     183            0 :   m_latency_monitoring.store(dp->get_latency_monitoring());
     184            0 :   inherited::add_postprocess_task(std::bind(&TCProcessor::make_td, this, std::placeholders::_1));
     185              : 
     186            0 :   inherited::conf(mtrg);
     187              : 
     188            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "TCProcessor: Exiting conf() method";
     189            0 : }
     190              : 
     191              : void
     192            0 : TCProcessor::scrap(const appfwk::DAQModule::CommandData_t& args)
     193              : {
     194            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "TCProcessor: Entering scrap() method";
     195              : 
     196            0 :   m_mandatory_links.clear();
     197            0 :   m_group_links.clear();
     198            0 :   m_roi_conf.clear();
     199            0 :   m_roi_conf_data.clear();
     200            0 :   m_roi_conf_ids.clear();
     201            0 :   m_roi_conf_probs.clear();
     202            0 :   m_roi_conf_probs_c.clear();
     203            0 :   m_pending_tds.clear();
     204            0 :   m_readout_window_map_data.clear();
     205            0 :   m_readout_window_map.clear();
     206            0 :   m_ignored_tc_types.clear();
     207              : 
     208            0 :   m_td_sink.reset();
     209              : 
     210            0 :   m_group_links_data.clear();
     211              : 
     212            0 :   inherited::scrap(args);
     213              : 
     214            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "TCProcessor: Exiting scrap() method";
     215            0 : }
     216              : 
     217              : void
     218            0 : TCProcessor::generate_opmon_data()
     219              : {
     220            0 :   opmon::TCProcessorInfo info;
     221              : 
     222            0 :   info.set_tds_created_count(m_tds_created_count.load());
     223            0 :   info.set_tds_sent_count(m_tds_sent_count.load());
     224            0 :   info.set_tds_dropped_count(m_tds_dropped_count.load());
     225            0 :   info.set_tds_failed_bitword_count(m_tds_failed_bitword_count.load());
     226            0 :   info.set_tds_cleared_count(m_tds_cleared_count.load());
     227            0 :   info.set_tc_received_count(m_tc_received_count.load());
     228            0 :   info.set_tc_ignored_count(m_tc_ignored_count.load());
     229            0 :   info.set_tds_created_tc_count(m_tds_created_tc_count.load());
     230            0 :   info.set_tds_sent_tc_count(m_tds_sent_tc_count.load());
     231            0 :   info.set_tds_dropped_tc_count(m_tds_dropped_tc_count.load());
     232            0 :   info.set_tds_failed_bitword_tc_count(m_tds_failed_bitword_tc_count.load());
     233            0 :   info.set_tds_cleared_tc_count(m_tds_cleared_tc_count.load());
     234              : 
     235            0 :   this->publish(std::move(info));
     236              : 
     237            0 :   if (m_latency_monitoring.load() && m_running_flag.load()) {
     238            0 :     opmon::TriggerLatency lat_info;
     239              : 
     240            0 :     lat_info.set_latency_in(m_latency_instance.get_latency_in());
     241            0 :     lat_info.set_latency_out(m_latency_instance.get_latency_out());
     242              : 
     243            0 :     this->publish(std::move(lat_info));
     244            0 :   }
     245            0 : }
     246              : 
     247              : /**
     248              :  * Pipeline Stage 2.: put valid TCs in a vector for grouping and forming of TDs
     249              :  * */
     250              : void
     251            0 : TCProcessor::make_td(const TCWrapper* tcw)
     252              : {
     253              : 
     254            0 :   auto tc = tcw->candidate;
     255            0 :   if (m_latency_monitoring.load())
     256            0 :     m_latency_instance.update_latency_in(tc.time_start);
     257            0 :   m_tc_received_count++;
     258              : 
     259            0 :   if ((m_use_readout_map) && (m_readout_window_map.count(tc.type))) {
     260            0 :     TLOG_DEBUG(3) << "Got TC of type " << static_cast<int>(tc.type) << ", timestamp " << tc.time_candidate
     261            0 :                   << ", start/end " << tc.time_start << "/" << tc.time_end << ", readout start/end "
     262            0 :                   << tc.time_candidate - m_readout_window_map[tc.type].first << "/"
     263            0 :                   << tc.time_candidate + m_readout_window_map[tc.type].second;
     264              :   } else {
     265            0 :     TLOG_DEBUG(3) << "Got TC of type " << static_cast<int>(tc.type) << ", timestamp " << tc.time_candidate
     266            0 :                   << ", start/end " << tc.time_start << "/" << tc.time_end;
     267              :   }
     268              : 
     269              :   // Option to ignore TC types (if given by config)
     270            0 :   if (m_ignoring_tc_types == true && check_trigger_type_ignore(static_cast<unsigned int>(tc.type)) == true) {
     271            0 :     TLOG_DEBUG(3) << " Ignore TC type: " << static_cast<unsigned int>(tc.type);
     272            0 :     m_tc_ignored_count++;
     273              : 
     274              :     /*FIXME: comment out this block: if a TC is to be ignored it shall just be ignored!
     275              :       if (m_tc_merging) {
     276              :         // Still need to check for overlap with existing TD, if overlaps, include in the TD, but don't extend
     277              :         // readout
     278              :         std::lock_guard<std::mutex> lock(m_td_vector_mutex);
     279              :         add_tc_ignored(*tc);
     280              :       }
     281              :       */
     282              :   } else {
     283            0 :     std::lock_guard<std::mutex> lock(m_td_vector_mutex);
     284            0 :     add_tc(tc);
     285            0 :     m_cv.notify_one();
     286            0 :     TLOG_DEBUG(10) << "pending tds size: " << m_pending_tds.size();
     287            0 :   }
     288            0 :   m_last_processed_daq_ts = tc.time_start;
     289            0 :   return;
     290            0 : }
     291              : 
     292              : dfmessages::TriggerDecision
     293            0 : TCProcessor::create_decision(const PendingTD& pending_td)
     294              : {
     295            0 :   m_earliest_tc_index = get_earliest_tc_index(pending_td);
     296            0 :   TLOG_DEBUG(5) << "earliest TC index: " << m_earliest_tc_index;
     297              : 
     298            0 :   if (pending_td.contributing_tcs.size() > 1) {
     299            0 :     TLOG_DEBUG(5) << "!!! TD created from " << pending_td.contributing_tcs.size() << " TCs !!!";
     300              :   }
     301              : 
     302            0 :   dfmessages::TriggerDecision decision;
     303            0 :   decision.trigger_number = 0; // filled by MLT
     304            0 :   decision.run_number = 0;     // filled by MLT
     305            0 :   decision.trigger_timestamp = pending_td.contributing_tcs[m_earliest_tc_index].time_candidate;
     306            0 :   decision.readout_type = dfmessages::ReadoutType::kLocalized;
     307              : 
     308            0 :   TDBitset td_bitword = get_TD_bitword(pending_td);
     309            0 :   TLOG_DEBUG(5) << "[MLT] TD has bitword: " << td_bitword << " "
     310            0 :                 << static_cast<dfmessages::trigger_type_t>(td_bitword.to_ulong());
     311            0 :   decision.trigger_type = static_cast<dfmessages::trigger_type_t>(td_bitword.to_ulong()); // m_trigger_type;
     312              : 
     313              :   // decision.trigger_type = 1; // m_trigger_type;
     314              : 
     315            0 :   TLOG_DEBUG(3) << ", TC detid: " << pending_td.contributing_tcs[m_earliest_tc_index].detid
     316            0 :                 << ", TC type: " << static_cast<int>(pending_td.contributing_tcs[m_earliest_tc_index].type)
     317            0 :                 << ", TC cont number: " << pending_td.contributing_tcs.size()
     318            0 :                 << ", DECISION trigger type: " << decision.trigger_type
     319            0 :                 << ", DECISION timestamp: " << decision.trigger_timestamp
     320            0 :                 << ", request window begin: " << pending_td.readout_start
     321            0 :                 << ", request window end: " << pending_td.readout_end;
     322              : 
     323            0 :   std::vector<dfmessages::ComponentRequest> requests =
     324            0 :     create_all_decision_requests(m_mandatory_links, pending_td.readout_start, pending_td.readout_end);
     325            0 :   add_requests_to_decision(decision, requests);
     326              : 
     327            0 :   if (!m_use_roi_readout) {
     328            0 :     for (const auto& [key, value] : m_group_links) {
     329            0 :       std::vector<dfmessages::ComponentRequest> group_requests =
     330            0 :         create_all_decision_requests(value, pending_td.readout_start, pending_td.readout_end);
     331            0 :       add_requests_to_decision(decision, group_requests);
     332            0 :     }
     333              :   } else { // using ROI readout
     334            0 :     roi_readout_make_requests(decision);
     335              :   }
     336              : 
     337            0 :   m_tds_created_count++;
     338            0 :   m_tds_created_tc_count += pending_td.contributing_tcs.size();
     339              : 
     340            0 :   return decision;
     341            0 : }
     342              : 
     343              : void
     344            0 : TCProcessor::send_trigger_decisions()
     345              : {
     346              :   // A unique lock that can be locked and unlocked
     347            0 :   std::unique_lock<std::mutex> lock(m_td_vector_mutex);
     348              : 
     349            0 :   while (m_running_flag) {
     350              :     // TODO: think about better implementation (notify?, something event driven)
     351            0 :     m_cv.wait_for(lock, std::chrono::microseconds(100));
     352            0 :     auto ready_tds = get_ready_tds(m_pending_tds);
     353            0 :     TLOG_DEBUG(10) << "ready tds: " << ready_tds.size() << ", updated pending tds: " << m_pending_tds.size();
     354              : 
     355            0 :     for (std::vector<PendingTD>::iterator it = ready_tds.begin(); it != ready_tds.end();) {
     356            0 :       call_tc_decision(*it);
     357            0 :       ++it;
     358              :     }
     359            0 :   }
     360            0 : }
     361              : 
     362              : void
     363            0 : TCProcessor::call_tc_decision(const TCProcessor::PendingTD& pending_td)
     364              : {
     365              : 
     366            0 :   if (m_use_bitwords) {
     367              :     // Check trigger bitwords
     368            0 :     TDBitset td_bitword = get_TD_bitword(pending_td);
     369            0 :     if (!check_trigger_bitwords(td_bitword)) {
     370              :       // Don't process further if the bitword check failed
     371            0 :       m_tds_failed_bitword_count++;
     372            0 :       m_tds_failed_bitword_tc_count += pending_td.contributing_tcs.size();
     373            0 :       return;
     374              :     }
     375              :   }
     376              : 
     377            0 :   dfmessages::TriggerDecision decision = create_decision(pending_td);
     378            0 :   auto tn = decision.trigger_number;
     379            0 :   auto td_ts = decision.trigger_timestamp;
     380              : 
     381            0 :   if (m_latency_monitoring.load())
     382            0 :     m_latency_instance.update_latency_out(pending_td.contributing_tcs.front().time_start);
     383            0 :   if (!m_td_sink->try_send(std::move(decision), iomanager::Sender::s_no_block)) {
     384            0 :     ers::warning(TDDropped(ERS_HERE, tn, td_ts));
     385            0 :     m_tds_dropped_count++;
     386            0 :     m_tds_dropped_tc_count += pending_td.contributing_tcs.size();
     387              :   } else {
     388            0 :     m_tds_sent_count++;
     389            0 :     m_tds_sent_tc_count += pending_td.contributing_tcs.size();
     390              :   }
     391            0 : }
     392              : 
     393              : void
     394            0 : TCProcessor::add_tc(const triggeralgs::TriggerCandidate tc)
     395              : {
     396            0 :   bool tc_dealt = false;
     397            0 :   int64_t tc_wallclock_arrived =
     398            0 :     std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
     399              : 
     400            0 :   if (m_tc_merging || m_ignore_tc_pileup) {
     401              : 
     402            0 :     for (std::vector<PendingTD>::iterator it = m_pending_tds.begin(); it != m_pending_tds.end();) {
     403              :       // Don't deal with TC here if there's no overlap
     404            0 :       if (!check_overlap(tc, *it)) {
     405            0 :         it++;
     406            0 :         continue;
     407              :       }
     408              : 
     409              :       // If overlap and ignoring, we drop the TC and flag it as dealt with.
     410            0 :       if (m_ignore_tc_pileup) {
     411            0 :         m_tds_dropped_tc_count++;
     412            0 :         tc_dealt = true;
     413            0 :         TLOG_DEBUG(3) << "TC overlapping with a previous TD, dropping!";
     414            0 :         break;
     415              :       }
     416              : 
     417              :       // If we're here, TC merging must be on, in which case we're actually
     418              :       // going to merge the TC into the TD.
     419            0 :       it->contributing_tcs.push_back(tc);
     420            0 :       if ((m_use_readout_map) && (m_readout_window_map.count(tc.type))) {
     421            0 :         TLOG_DEBUG(3) << "TC with start/end times " << tc.time_candidate - m_readout_window_map[tc.type].first << "/"
     422            0 :                       << tc.time_candidate + m_readout_window_map[tc.type].second
     423            0 :                       << " overlaps with pending TD with start/end times " << it->readout_start << "/"
     424            0 :                       << it->readout_end;
     425            0 :         it->readout_start = ((tc.time_candidate - m_readout_window_map[tc.type].first) >= it->readout_start)
     426            0 :                               ? it->readout_start
     427            0 :                               : (tc.time_candidate - m_readout_window_map[tc.type].first);
     428            0 :         it->readout_end = ((tc.time_candidate + m_readout_window_map[tc.type].second) >= it->readout_end)
     429            0 :                             ? (tc.time_candidate + m_readout_window_map[tc.type].second)
     430              :                             : it->readout_end;
     431              :       } else {
     432            0 :         TLOG_DEBUG(3) << "TC with start/end times " << tc.time_start << "/" << tc.time_end
     433            0 :                       << " overlaps with pending TD with start/end times " << it->readout_start << "/"
     434            0 :                       << it->readout_end;
     435            0 :         it->readout_start = (tc.time_start >= it->readout_start) ? it->readout_start : tc.time_start;
     436            0 :         it->readout_end = (tc.time_end >= it->readout_end) ? tc.time_end : it->readout_end;
     437              :       }
     438            0 :       it->walltime_expiration = tc_wallclock_arrived + m_buffer_timeout;
     439            0 :       tc_dealt = true;
     440            0 :       break;
     441              :     }
     442              :   }
     443              : 
     444              :   // Don't do anything else if we've already dealt with the TC
     445            0 :   if (tc_dealt) {
     446            0 :     return;
     447              :   }
     448              : 
     449              :   // Create a new TD out of the TC
     450            0 :   PendingTD td_candidate;
     451            0 :   td_candidate.contributing_tcs.push_back(tc);
     452            0 :   if ((m_use_readout_map) && (m_readout_window_map.count(tc.type))) {
     453            0 :     td_candidate.readout_start = tc.time_candidate - m_readout_window_map[tc.type].first;
     454            0 :     td_candidate.readout_end = tc.time_candidate + m_readout_window_map[tc.type].second;
     455              :   } else {
     456            0 :     td_candidate.readout_start = tc.time_start;
     457            0 :     td_candidate.readout_end = tc.time_end;
     458              :   }
     459            0 :   td_candidate.walltime_expiration = tc_wallclock_arrived + m_buffer_timeout;
     460            0 :   m_pending_tds.push_back(td_candidate);
     461            0 : }
     462              : 
     463              : void
     464            0 : TCProcessor::add_tc_ignored(const triggeralgs::TriggerCandidate tc)
     465              : {
     466            0 :   for (std::vector<PendingTD>::iterator it = m_pending_tds.begin(); it != m_pending_tds.end();) {
     467            0 :     if (check_overlap(tc, *it)) {
     468            0 :       if ((m_use_readout_map) && (m_readout_window_map.count(tc.type))) {
     469            0 :         TLOG_DEBUG(3) << "!Ignored! TC with start/end times " << tc.time_candidate - m_readout_window_map[tc.type].first
     470            0 :                       << "/" << tc.time_candidate + m_readout_window_map[tc.type].second
     471            0 :                       << " overlaps with pending TD with start/end times " << it->readout_start << "/"
     472            0 :                       << it->readout_end;
     473              :       } else {
     474            0 :         TLOG_DEBUG(3) << "!Ignored! TC with start/end times " << tc.time_start << "/" << tc.time_end
     475            0 :                       << " overlaps with pending TD with start/end times " << it->readout_start << "/"
     476            0 :                       << it->readout_end;
     477              :       }
     478            0 :       it->contributing_tcs.push_back(tc);
     479              :       break;
     480              :     }
     481            0 :     ++it;
     482              :   }
     483            0 :   return;
     484              : }
     485              : 
     486              : bool
     487            0 : TCProcessor::check_overlap(const triggeralgs::TriggerCandidate& tc, const PendingTD& pending_td)
     488              : {
     489            0 :   if ((m_use_readout_map) && (m_readout_window_map.count(tc.type))) {
     490            0 :     return !(((tc.time_candidate + m_readout_window_map[tc.type].second) < pending_td.readout_start) ||
     491            0 :              ((tc.time_candidate - m_readout_window_map[tc.type].first > pending_td.readout_end)));
     492              :   } else {
     493            0 :     return !((tc.time_end < pending_td.readout_start) || (tc.time_start > pending_td.readout_end));
     494              :   }
     495              : }
     496              : 
     497              : std::vector<TCProcessor::PendingTD>
     498            0 : TCProcessor::get_ready_tds(std::vector<PendingTD>& pending_tds)
     499              : {
     500            0 :   std::vector<PendingTD> return_tds;
     501            0 :   for (std::vector<PendingTD>::iterator it = pending_tds.begin(); it != pending_tds.end();) {
     502            0 :     auto timestamp_now =
     503            0 :       std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch())
     504            0 :         .count();
     505            0 :     if (timestamp_now >= it->walltime_expiration) {
     506            0 :       return_tds.push_back(*it);
     507            0 :       it = pending_tds.erase(it);
     508            0 :     } else if (check_td_readout_length(*it)) { // Also pass on TDs with (too) long readout window
     509            0 :       return_tds.push_back(*it);
     510            0 :       it = pending_tds.erase(it);
     511              :     } else {
     512            0 :       ++it;
     513              :     }
     514              :   }
     515            0 :   return return_tds;
     516            0 : }
     517              : 
     518              : int
     519            0 : TCProcessor::get_earliest_tc_index(const PendingTD& pending_td)
     520              : {
     521            0 :   int earliest_tc_index = -1;
     522            0 :   triggeralgs::timestamp_t earliest_tc_time;
     523            0 :   for (int i = 0; i < static_cast<int>(pending_td.contributing_tcs.size()); i++) {
     524            0 :     if (earliest_tc_index == -1) {
     525            0 :       earliest_tc_time = pending_td.contributing_tcs[i].time_candidate;
     526            0 :       earliest_tc_index = i;
     527              :     } else {
     528            0 :       if (pending_td.contributing_tcs[i].time_candidate < earliest_tc_time) {
     529            0 :         earliest_tc_time = pending_td.contributing_tcs[i].time_candidate;
     530            0 :         earliest_tc_index = i;
     531              :       }
     532              :     }
     533              :   }
     534            0 :   return earliest_tc_index;
     535              : }
     536              : 
     537              : bool
     538            0 : TCProcessor::check_td_readout_length(const PendingTD& pending_td)
     539              : {
     540            0 :   bool td_too_long = false;
     541            0 :   if (static_cast<int64_t>(pending_td.readout_end - pending_td.readout_start) >= m_td_readout_limit) {
     542            0 :     td_too_long = true;
     543            0 :     TLOG_DEBUG(3) << "Too long readout window: " << (pending_td.readout_end - pending_td.readout_start)
     544            0 :                   << ", sending immediate TD!";
     545              :   }
     546            0 :   return td_too_long;
     547              : }
     548              : 
     549              : void
     550            0 : TCProcessor::clear_td_vectors()
     551              : {
     552            0 :   std::lock_guard<std::mutex> lock(m_td_vector_mutex);
     553            0 :   m_tds_cleared_count += m_pending_tds.size();
     554              :   // Use std::accumulate to sum up the sizes of all contributing_tcs vectors
     555            0 :   size_t tds_cleared_tc_count =
     556            0 :     std::accumulate(m_pending_tds.begin(), m_pending_tds.end(), 0, [](size_t sum, const PendingTD& ptd) {
     557            0 :       return sum + ptd.contributing_tcs.size();
     558            0 :     });
     559            0 :   m_tds_cleared_tc_count += tds_cleared_tc_count;
     560            0 :   m_pending_tds.clear();
     561            0 : }
     562              : bool
     563            0 : TCProcessor::check_trigger_type_ignore(unsigned int tc_type)
     564              : {
     565            0 :   bool ignore = false;
     566            0 :   for (std::vector<unsigned int>::iterator it = m_ignored_tc_types.begin(); it != m_ignored_tc_types.end();) {
     567            0 :     if (tc_type == *it) {
     568              :       ignore = true;
     569              :       break;
     570              :     }
     571            0 :     ++it;
     572              :   }
     573            0 :   return ignore;
     574              : }
     575              : 
     576              : void
     577            0 : TCProcessor::print_trigger_bitwords()
     578              : {
     579            0 :   TLOG_DEBUG(3) << "Configured trigger words:";
     580            0 :   for (const auto& bitword : m_trigger_bitwords) {
     581            0 :     TLOG_DEBUG(3) << bitword;
     582              :   }
     583            0 : }
     584              : 
     585              : bool
     586            0 : TCProcessor::check_trigger_bitwords(const TDBitset& td_bitword) const
     587              : {
     588            0 :   bool trigger_check = false;
     589            0 :   for (const auto& bitword : m_trigger_bitwords) {
     590            0 :     TLOG_DEBUG(15) << "TD word: " << td_bitword << ", bitword: " << bitword;
     591            0 :     trigger_check = ((td_bitword & bitword) == bitword);
     592            0 :     TLOG_DEBUG(15) << "&: " << (td_bitword & bitword);
     593            0 :     TLOG_DEBUG(15) << "trigger?: " << trigger_check;
     594            0 :     if (trigger_check == true)
     595              :       break;
     596              :   }
     597            0 :   return trigger_check;
     598              : }
     599              : 
     600              : void
     601            0 : TCProcessor::set_trigger_bitwords(const std::vector<const appmodel::TriggerBitword*>& _bitwords)
     602              : {
     603            0 :   for (const appmodel::TriggerBitword* bitword : _bitwords) {
     604            0 :     TDBitset temp_bitword;
     605              : 
     606            0 :     for (const std::string& tctype_str : bitword->get_bitword()) {
     607            0 :       TCType tc_type = static_cast<TCType>(dunedaq::trgdataformats::string_to_trigger_candidate_type(tctype_str));
     608              : 
     609            0 :       if (tc_type == TCType::kUnknown) {
     610            0 :         throw(InvalidConfiguration(ERS_HERE, "Provided an unknown/non-existent TC type as a trigger bitword!"));
     611              :       }
     612              : 
     613            0 :       temp_bitword.set(static_cast<uint64_t>(tc_type));
     614              :     }
     615              : 
     616            0 :     m_trigger_bitwords.push_back(temp_bitword);
     617              :   }
     618            0 : }
     619              : 
     620              : void
     621            0 : TCProcessor::parse_readout_map(const std::vector<const appmodel::TCReadoutMap*>& data)
     622              : {
     623            0 :   for (auto readout_type : data) {
     624            0 :     TCType tc_type =
     625            0 :       static_cast<TCType>(dunedaq::trgdataformats::string_to_trigger_candidate_type(readout_type->get_tc_type_name()));
     626              : 
     627              :     // Throw error if unknown TC type
     628            0 :     if (tc_type == TCType::kUnknown) {
     629            0 :       throw(InvalidConfiguration(ERS_HERE, "Provided an unknown TC type in the TCReadoutMap for the TCProcessor"));
     630              :     }
     631              : 
     632            0 :     m_readout_window_map[tc_type] = { readout_type->get_time_before(), readout_type->get_time_after() };
     633              :   }
     634            0 :   return;
     635              : }
     636              : void
     637            0 : TCProcessor::print_readout_map(std::map<TCType, std::pair<triggeralgs::timestamp_t, triggeralgs::timestamp_t>> map)
     638              : {
     639            0 :   TLOG_DEBUG(3) << "MLT TD Readout map:";
     640            0 :   for (auto const& [key, val] : map) {
     641            0 :     TLOG_DEBUG(3) << "Type: " << static_cast<int>(key) << ", before: " << val.first << ", after: " << val.second;
     642              :   }
     643            0 :   return;
     644              : }
     645              : 
     646              : void
     647            0 : TCProcessor::parse_group_links(const nlohmann::json& data)
     648              : {
     649            0 :   for (auto group : data) {
     650            0 :     const nlohmann::json& temp_links_data = group["links"];
     651            0 :     std::vector<dfmessages::SourceID> temp_links;
     652            0 :     for (auto link : temp_links_data) {
     653            0 :       temp_links.push_back(
     654            0 :         dfmessages::SourceID{ daqdataformats::SourceID::string_to_subsystem(link["subsystem"]), link["element"] });
     655            0 :     }
     656            0 :     m_group_links.insert({ group["group"], temp_links });
     657            0 :   }
     658            0 :   return;
     659              : }
     660              : 
     661              : void
     662            0 : TCProcessor::print_group_links()
     663              : {
     664            0 :   TLOG_DEBUG(3) << "MLT Group Links:";
     665            0 :   for (auto const& [key, val] : m_group_links) {
     666            0 :     TLOG_DEBUG(3) << "Group: " << key;
     667            0 :     for (auto const& link : val) {
     668            0 :       TLOG_DEBUG(3) << link;
     669              :     }
     670              :   }
     671            0 :   TLOG_DEBUG(3) << " ";
     672            0 :   return;
     673              : }
     674              : dfmessages::ComponentRequest
     675            0 : TCProcessor::create_request_for_link(dfmessages::SourceID link,
     676              :                                      triggeralgs::timestamp_t start,
     677              :                                      triggeralgs::timestamp_t end)
     678              : {
     679            0 :   dfmessages::ComponentRequest request;
     680            0 :   request.component = link;
     681            0 :   request.window_begin = start;
     682            0 :   request.window_end = end;
     683              : 
     684            0 :   TLOG_DEBUG(10) << "setting request start: " << request.window_begin;
     685            0 :   TLOG_DEBUG(10) << "setting request end: " << request.window_end;
     686              : 
     687            0 :   return request;
     688              : }
     689              : 
     690              : std::vector<dfmessages::ComponentRequest>
     691            0 : TCProcessor::create_all_decision_requests(std::vector<dfmessages::SourceID> links,
     692              :                                           triggeralgs::timestamp_t start,
     693              :                                           triggeralgs::timestamp_t end)
     694              : {
     695            0 :   std::vector<dfmessages::ComponentRequest> requests;
     696            0 :   for (auto link : links) {
     697            0 :     requests.push_back(create_request_for_link(link, start, end));
     698              :   }
     699            0 :   return requests;
     700            0 : }
     701              : 
     702              : void
     703            0 : TCProcessor::add_requests_to_decision(dfmessages::TriggerDecision& decision,
     704              :                                       std::vector<dfmessages::ComponentRequest> requests)
     705              : {
     706            0 :   for (auto request : requests) {
     707            0 :     decision.components.push_back(request);
     708              :   }
     709            0 : }
     710              : 
     711              : void
     712            0 : TCProcessor::parse_roi_conf(const std::vector<const appmodel::ROIGroupConf*>& data)
     713              : {
     714            0 :   int counter = 0;
     715            0 :   float run_sum = 0;
     716            0 :   for (auto group : data) {
     717            0 :     roi_group temp_roi_group;
     718            0 :     temp_roi_group.n_links = group->get_number_of_link_groups();
     719            0 :     temp_roi_group.prob = group->get_probability();
     720            0 :     temp_roi_group.time_window = group->get_time_window();
     721            0 :     temp_roi_group.mode = group->get_groups_selection_mode();
     722            0 :     m_roi_conf.insert({ counter, temp_roi_group });
     723            0 :     m_roi_conf_ids.push_back(counter);
     724            0 :     m_roi_conf_probs.push_back(group->get_probability());
     725            0 :     run_sum += static_cast<float>(group->get_probability());
     726            0 :     m_roi_conf_probs_c.push_back(run_sum);
     727            0 :     counter++;
     728            0 :   }
     729            0 :   return;
     730              : }
     731              : 
     732              : void
     733            0 : TCProcessor::print_roi_conf(std::map<int, roi_group> roi_conf)
     734              : {
     735            0 :   TLOG_DEBUG(3) << "ROI CONF";
     736            0 :   for (const auto& [key, value] : roi_conf) {
     737            0 :     TLOG_DEBUG(3) << "ID: " << key;
     738            0 :     TLOG_DEBUG(3) << "n links: " << value.n_links;
     739            0 :     TLOG_DEBUG(3) << "prob: " << value.prob;
     740            0 :     TLOG_DEBUG(3) << "time: " << value.time_window;
     741            0 :     TLOG_DEBUG(3) << "mode: " << value.mode;
     742              :   }
     743            0 :   TLOG_DEBUG(3) << " ";
     744            0 :   return;
     745              : }
     746              : 
     747              : float
     748            0 : TCProcessor::get_random_num_float(float limit)
     749              : {
     750            0 :   float rnd = (double)rand() / RAND_MAX;
     751            0 :   return rnd * (limit);
     752              : }
     753              : 
     754              : int
     755            0 : TCProcessor::pick_roi_group_conf()
     756              : {
     757            0 :   float rnd_num = get_random_num_float(m_roi_conf_probs_c.back());
     758            0 :   for (int i = 0; i < static_cast<int>(m_roi_conf_probs_c.size()); i++) {
     759            0 :     if (rnd_num < m_roi_conf_probs_c[i]) {
     760              :       return i;
     761              :     }
     762              :   }
     763              :   return -1;
     764              : }
     765              : 
     766              : int
     767            0 : TCProcessor::get_random_num_int()
     768              : {
     769            0 :   int range = m_total_group_links;
     770            0 :   int rnd = rand() % range;
     771            0 :   return rnd;
     772              : }
     773              : void
     774            0 : TCProcessor::roi_readout_make_requests(dfmessages::TriggerDecision& decision)
     775              : {
     776              :   // Get configuration at random (weighted)
     777            0 :   int group_pick = pick_roi_group_conf();
     778            0 :   if (group_pick != -1) {
     779            0 :     roi_group this_group = m_roi_conf[m_roi_conf_ids[group_pick]];
     780            0 :     std::vector<dfmessages::SourceID> links;
     781              : 
     782              :     // If mode is random, pick groups to request at random
     783            0 :     if (this_group.mode == "kRandom") {
     784            0 :       TLOG_DEBUG(10) << "RAND";
     785            0 :       std::set<int> groups;
     786            0 :       while (static_cast<int>(groups.size()) < this_group.n_links) {
     787            0 :         groups.insert(get_random_num_int());
     788              :       }
     789            0 :       for (auto r_id : groups) {
     790            0 :         links.insert(links.end(), m_group_links[r_id].begin(), m_group_links[r_id].end());
     791              :       }
     792              :       // Otherwise, read sequntially by IDs, starting at 0
     793            0 :     } else {
     794            0 :       TLOG_DEBUG(10) << "SEQ";
     795            0 :       int r_id = 0;
     796            0 :       while (r_id < this_group.n_links) {
     797            0 :         links.insert(links.end(), m_group_links[r_id].begin(), m_group_links[r_id].end());
     798            0 :         r_id++;
     799              :       }
     800              :     }
     801              : 
     802            0 :     TLOG_DEBUG(10) << "TD timestamp: " << decision.trigger_timestamp;
     803            0 :     TLOG_DEBUG(10) << "group window: " << this_group.time_window;
     804              : 
     805              :     // Once the components are prepared, create requests and append them to decision
     806            0 :     std::vector<dfmessages::ComponentRequest> requests = create_all_decision_requests(
     807            0 :       links, decision.trigger_timestamp - this_group.time_window, decision.trigger_timestamp + this_group.time_window);
     808            0 :     add_requests_to_decision(decision, requests);
     809            0 :     links.clear();
     810            0 :   }
     811            0 :   return;
     812              : }
     813              : 
     814              : TCProcessor::TDBitset
     815            0 : TCProcessor::get_TD_bitword(const PendingTD& ready_td) const
     816              : {
     817              :   // get only unique types
     818            0 :   std::vector<int> tc_types;
     819            0 :   for (auto tc : ready_td.contributing_tcs) {
     820            0 :     tc_types.push_back(static_cast<int>(tc.type));
     821            0 :   }
     822            0 :   tc_types.erase(std::unique(tc_types.begin(), tc_types.end()), tc_types.end());
     823              : 
     824              :   // form TD bitword
     825            0 :   TDBitset td_bitword;
     826            0 :   for (auto tc_type : tc_types) {
     827            0 :     td_bitword.set(tc_type);
     828              :   }
     829            0 :   return td_bitword;
     830            0 : }
     831              : 
     832              : void
     833            0 : TCProcessor::print_opmon_stats()
     834              : {
     835            0 :   TLOG() << "TCProcessor opmon counters summary:";
     836            0 :   TLOG() << "------------------------------";
     837            0 :   TLOG() << "TDs created: \t\t\t" << m_tds_created_count << " \t(" << m_tds_created_tc_count << " TCs)";
     838            0 :   TLOG() << "TDs sent: \t\t\t" << m_tds_sent_count << " \t(" << m_tds_sent_tc_count << " TCs)";
     839            0 :   TLOG() << "TDs dropped: \t\t\t" << m_tds_dropped_count << " \t(" << m_tds_dropped_tc_count << " TCs)";
     840            0 :   TLOG() << "TDs failed bitword check: \t" << m_tds_failed_bitword_count << " \t(" << m_tds_failed_bitword_tc_count
     841            0 :          << " TCs)";
     842            0 :   TLOG() << "TDs cleared: \t\t\t" << m_tds_cleared_count << " \t(" << m_tds_cleared_tc_count << " TCs)";
     843            0 :   TLOG() << "------------------------------";
     844            0 :   TLOG() << "TCs received: \t" << m_tc_received_count;
     845            0 :   TLOG() << "TCs ignored: \t" << m_tc_ignored_count;
     846            0 :   TLOG();
     847            0 : }
     848              : 
     849              : } // namespace fdreadoutlibs
     850              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1