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 = static_cast<TCType>(dunedaq::trgdataformats::string_to_trigger_candidate_type(m_conf->get_candidate_type_name()));
109 :
110 : // Throw error if unknown TC type
111 0 : if (m_tcout_type == TCType::kUnknown) {
112 0 : throw(InvalidConfiguration(ERS_HERE, "Provided an unknown TC type output to RandomTCMakerModule!"));
113 : }
114 :
115 0 : m_latency_monitoring.store(m_conf->get_latency_monitoring());
116 0 : m_trigger_rate_hz.store(m_conf->get_trigger_rate_hz());
117 :
118 0 : TLOG() << "RandomTCMaker will output TC of type: " << m_conf->get_candidate_type_name();
119 0 : TLOG() << "TC window center offset: " << m_tcout_time_backshift_ts;
120 0 : TLOG() << "TC window time before: " << m_tcout_time_before_ts << " time after: " << m_tcout_time_after_ts;
121 0 : TLOG() << "Clock speed is: " << m_clock_speed_hz;
122 0 : TLOG() << "Output trigger rate is: " << m_trigger_rate_hz.load();
123 :
124 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << ": Exiting conf() method";
125 0 : }
126 :
127 : void
128 0 : RandomTCMakerModule::do_start(const CommandData_t& obj)
129 : {
130 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Entering start() method";
131 0 : m_run_number = obj.value<dunedaq::daqdataformats::run_number_t>("run", 0);
132 :
133 0 : m_running_flag.store(true);
134 :
135 : // OpMon.
136 0 : m_tc_made_count.store(0);
137 0 : m_tc_sent_count.store(0);
138 0 : m_tc_failed_sent_count.store(0);
139 :
140 0 : std::string timestamp_method = m_conf->get_timestamp_method();
141 0 : if (timestamp_method == "kTimeSync") {
142 0 : TLOG_DEBUG(0) << "Creating TimestampEstimatorTimeSync";
143 0 : m_timestamp_estimator.reset(new utilities::TimestampEstimatorTimeSync(m_run_number, m_clock_speed_hz));
144 0 : m_time_sync_source->add_callback(
145 0 : std::bind(&utilities::TimestampEstimatorTimeSync::timesync_callback<dfmessages::TimeSync>,
146 0 : reinterpret_cast<utilities::TimestampEstimatorTimeSync*>(m_timestamp_estimator.get()),
147 : std::placeholders::_1));
148 0 : } else if (timestamp_method == "kSystemClock") {
149 0 : TLOG_DEBUG(0) << "Creating TimestampEstimatorSystem";
150 0 : m_timestamp_estimator.reset(new utilities::TimestampEstimatorSystem(m_clock_speed_hz));
151 : } else {
152 : // TODO: write some error message
153 : }
154 :
155 : // Check if the trigger rate was changed in the starting parameters, and set it if so
156 0 : auto start_params = obj.get<rcif::cmd::StartParams>();
157 0 : if (start_params.trigger_rate > 0) {
158 0 : TLOG() << "Changing trigger rate from " << m_trigger_rate_hz.load() << " to " << start_params.trigger_rate;
159 0 : m_trigger_rate_hz.store(start_params.trigger_rate);
160 : }
161 :
162 0 : m_send_trigger_candidates_thread = std::thread(&RandomTCMakerModule::send_trigger_candidates, this);
163 0 : pthread_setname_np(m_send_trigger_candidates_thread.native_handle(), "random-tc-maker");
164 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << ": Exiting start() method";
165 0 : }
166 :
167 : void
168 0 : RandomTCMakerModule::do_stop(const CommandData_t& /*obj*/)
169 : {
170 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Entering stop() method";
171 0 : m_running_flag.store(false);
172 :
173 0 : m_send_trigger_candidates_thread.join();
174 :
175 0 : if (m_conf->get_timestamp_method() == "kTimeSync") {
176 0 : m_time_sync_source->remove_callback();
177 : }
178 :
179 0 : m_timestamp_estimator.reset(nullptr); // Calls TimestampEstimator dtor
180 :
181 0 : print_opmon_stats();
182 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << ": Exiting stop() method";
183 0 : }
184 :
185 : void
186 0 : RandomTCMakerModule::do_scrap(const CommandData_t& /*obj*/)
187 : {
188 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Entering scrap() method";
189 0 : m_time_sync_source.reset();
190 0 : m_trigger_candidate_sink.reset();
191 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << ": Exiting scrap() method";
192 0 : }
193 :
194 : void
195 0 : RandomTCMakerModule::do_change_trigger_rate(const CommandData_t& obj)
196 : {
197 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << get_name() << ": Entering change-rate() method";
198 0 : auto change_rate_params = obj.get<rcif::cmd::ChangeRateParams>();
199 :
200 0 : TLOG() << "Changing trigger rate from " << m_trigger_rate_hz.load() << " to " << change_rate_params.trigger_rate;
201 :
202 0 : m_trigger_rate_hz.store(change_rate_params.trigger_rate);
203 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << ": Exiting change-rate() method";
204 0 : }
205 :
206 : triggeralgs::TriggerCandidate
207 0 : RandomTCMakerModule::create_candidate(dfmessages::timestamp_t timestamp)
208 : {
209 0 : triggeralgs::TriggerCandidate candidate;
210 0 : candidate.time_candidate = timestamp - m_tcout_time_backshift_ts;
211 0 : candidate.time_start = candidate.time_candidate-m_tcout_time_before_ts;
212 0 : candidate.time_end = candidate.time_candidate+m_tcout_time_after_ts;
213 0 : candidate.detid = { 0 };
214 0 : candidate.type = m_tcout_type;
215 :
216 : // TODO: Originally kHSIEventToTriggerCandidate
217 0 : candidate.algorithm = triggeralgs::TriggerCandidate::Algorithm::kCustom;
218 :
219 0 : return candidate;
220 : }
221 :
222 : uint64_t
223 0 : RandomTCMakerModule::get_interval(std::mt19937& gen)
224 : {
225 0 : std::string time_distribution = m_conf->get_time_distribution();
226 :
227 0 : uint64_t interval = m_clock_speed_hz / m_trigger_rate_hz.load();
228 :
229 0 : if (time_distribution == "kUniform") {
230 : return interval;
231 0 : } else if (time_distribution == "kPoisson") {
232 0 : std::exponential_distribution<double> d(1.0 / interval);
233 0 : return static_cast<uint64_t>(0.5 + d(gen));
234 : } else {
235 0 : TLOG_DEBUG(1) << get_name() << " unknown distribution! Using kUniform.";
236 : }
237 0 : return interval;
238 0 : }
239 :
240 : void
241 0 : RandomTCMakerModule::send_trigger_candidates()
242 : {
243 : // OpMon.
244 0 : m_tc_sent_count.store(0);
245 :
246 0 : std::mt19937 gen(m_run_number);
247 0 : dfmessages::timestamp_t initial_timestamp;
248 : // Wait for there to be a valid timestamp estimate before we start
249 0 : if (m_timestamp_estimator->wait_for_valid_timestamp(m_running_flag, initial_timestamp) ==
250 : utilities::TimestampEstimatorBase::kInterrupted) {
251 0 : return;
252 : }
253 :
254 0 : dfmessages::timestamp_t next_trigger_timestamp = initial_timestamp;
255 0 : TLOG_DEBUG(1) << get_name() << " initial timestamp estimate is " << initial_timestamp;
256 :
257 0 : while (m_running_flag.load()) {
258 : // If trigger rate is 0, just sleep. Need to use small number here because
259 : // of floating point precision...
260 0 : constexpr float epsilon = 1e-9;
261 0 : if (m_trigger_rate_hz.load() <= epsilon) {
262 0 : std::this_thread::sleep_for(std::chrono::milliseconds(100));
263 0 : continue;
264 : }
265 :
266 0 : dfmessages::timestamp_t actual_timestamp;
267 0 : if (m_timestamp_estimator->wait_for_requested_timestamp(next_trigger_timestamp, m_running_flag, actual_timestamp) ==
268 : utilities::TimestampEstimatorBase::kInterrupted) {
269 : break;
270 : }
271 0 : triggeralgs::TriggerCandidate candidate = create_candidate(actual_timestamp);
272 :
273 0 : m_tc_made_count++;
274 :
275 0 : TLOG_DEBUG(1) << get_name() << " at timestamp " << actual_timestamp
276 0 : << ", pushing a candidate with timestamp " << candidate.time_candidate;
277 :
278 0 : if (m_latency_monitoring.load())
279 0 : m_latency_instance.update_latency_out(candidate.time_candidate);
280 0 : try {
281 0 : m_trigger_candidate_sink->send(std::move(candidate), std::chrono::milliseconds(10));
282 0 : m_tc_sent_count++;
283 0 : } catch (const ers::Issue& e) {
284 0 : ers::error(e);
285 0 : m_tc_failed_sent_count++;
286 0 : }
287 :
288 0 : next_trigger_timestamp = actual_timestamp + get_interval(gen);
289 0 : }
290 : }
291 :
292 : void
293 0 : RandomTCMakerModule::print_opmon_stats()
294 : {
295 0 : TLOG() << "RandomTCMaker opmon counters summary:";
296 0 : TLOG() << "------------------------------";
297 0 : TLOG() << "Made TCs: \t\t\t" << m_tc_made_count;
298 0 : TLOG() << "Sent TCs: \t\t\t" << m_tc_sent_count;
299 0 : TLOG() << "Failed to send TCs: \t" << m_tc_failed_sent_count;
300 0 : TLOG();
301 0 : }
302 :
303 : } // namespace trigger
304 : } // namespace dunedaq
305 :
306 0 : DEFINE_DUNE_DAQ_MODULE(dunedaq::trigger::RandomTCMakerModule)
307 :
308 : // Local Variables:
309 : // c-basic-offset: 2
310 : // End:
|