-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trigger latencies + monitoring (v5) #342
Changes from 17 commits
ab5812e
e6ef2a3
210456d
54c6a8a
8e270a6
84fe1fd
a004b17
3a51e70
9155d64
6bd087c
0dcc5f2
64e03f1
ec83c08
a1cbfc6
8120c0a
0822cc0
dc4ea9c
4201bdb
bbddc50
6b33efd
22f6687
da978b7
b05c8f2
45905a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/** | ||
* @file Latency.hpp | ||
* | ||
* This is part of the DUNE DAQ Application Framework, copyright 2021. | ||
* Licensing/copyright details are in the COPYING file that you should have | ||
* received with this code. | ||
*/ | ||
|
||
#ifndef TRIGGER_INCLUDE_TRIGGER_LATENCY_HPP_ | ||
#define TRIGGER_INCLUDE_TRIGGER_LATENCY_HPP_ | ||
|
||
#include <atomic> | ||
#include <chrono> | ||
|
||
namespace dunedaq { | ||
namespace trigger { | ||
|
||
class Latency { | ||
public: | ||
|
||
// Enumeration for selecting time units | ||
enum class TimeUnit { Milliseconds, Microseconds }; | ||
|
||
// Constructor with optional time unit selection (defaults to Milliseconds) | ||
Latency(TimeUnit time_unit = TimeUnit::Milliseconds) | ||
: m_latency_in(0), m_latency_out(0), m_time_unit(time_unit) | ||
{ | ||
// Set the clock tick conversion factor based on time unit | ||
if (m_time_unit == TimeUnit::Milliseconds) { | ||
m_clock_ticks_conversion = 16 * 1e-6; // For milliseconds: 1 tick = 16 * 10^-6 ms | ||
} else { | ||
m_clock_ticks_conversion = 16 * 1e-3; | ||
} | ||
// to convert 62.5MHz clock ticks to ms: 1/62500000 = 0.000000016 <- seconds per tick; 0.000016 <- ms per tick; | ||
// 16*1e-6 <- sci notation | ||
} | ||
|
||
// Function to get the current system time in ms or ns based on time unit | ||
uint64_t get_current_system_time() const | ||
{ | ||
if (m_time_unit == TimeUnit::Milliseconds) { | ||
return std::chrono::duration_cast<std::chrono::milliseconds>( | ||
std::chrono::system_clock::now().time_since_epoch()).count(); | ||
} else { | ||
return std::chrono::duration_cast<std::chrono::microseconds>( | ||
std::chrono::system_clock::now().time_since_epoch()).count(); | ||
} | ||
} | ||
|
||
// Function to update latency_in | ||
void update_latency_in(uint64_t latency) | ||
{ | ||
m_latency_in.store(latency * m_clock_ticks_conversion); | ||
} | ||
|
||
// Function to update latency_out | ||
void update_latency_out(uint64_t latency) | ||
{ | ||
m_latency_out.store(latency * m_clock_ticks_conversion); | ||
} | ||
|
||
// Function to get the value of latency_in | ||
uint64_t get_latency_in() const | ||
{ | ||
if (m_latency_in.load() != 0) { | ||
// in edge cases the TP time was more recent then current sys time... | ||
// this is a catch for that | ||
uint64_t diff = abs(int64_t(get_current_system_time()) - int64_t(m_latency_in.load())); | ||
return diff; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
|
||
// Function to get the value of latency_out | ||
uint64_t get_latency_out() const | ||
{ | ||
if (m_latency_out.load() != 0) { | ||
uint64_t diff = abs(int64_t(get_current_system_time()) - int64_t(m_latency_out.load())); | ||
return diff; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
|
||
private: | ||
std::atomic<uint64_t> m_latency_in; // Member variable to store latency_in | ||
std::atomic<uint64_t> m_latency_out; // Member variable to store latency_out | ||
double m_clock_ticks_conversion; // Dynamically adjusted conversion factor for clock ticks | ||
TimeUnit m_time_unit; // Member variable to store the selected time unit (ms or ns) | ||
}; | ||
|
||
} // namespace trigger | ||
} // namespace dunedaq | ||
|
||
#endif // TRIGGER_INCLUDE_TRIGGER_LATENCY_HPP_ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -107,6 +107,15 @@ CustomTCMaker::generate_opmon_data() | |
info.set_tc_failed_sent_count( m_tc_failed_sent_count.load() ); | ||
|
||
this->publish(std::move(info)); | ||
|
||
if ( m_running_flag.load() && m_latency_monitoring.load() ) { | ||
opmon::TriggerLatency lat_info; | ||
|
||
lat_info.set_latency_in( m_latency_instance.get_latency_in() ); | ||
lat_info.set_latency_out( m_latency_instance.get_latency_out() ); | ||
ArturSztuc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
this->publish(std::move(lat_info)); | ||
} | ||
} | ||
|
||
void | ||
|
@@ -125,13 +134,20 @@ CustomTCMaker::do_configure(const nlohmann::json& /*obj*/) | |
//// This parameter controls how many new timestamps are calculated when needed | ||
//// Currently precalculates events for the next 60 seconds | ||
//m_sorting_size_limit = 60 * m_conf0>clock_frequency_hz; | ||
|
||
m_latency_monitoring.store( m_conf->get_latency_monitoring_conf()->get_enable_latency_monitoring() ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Technically there's also a new |
||
} | ||
|
||
void | ||
CustomTCMaker::do_start(const nlohmann::json& obj) | ||
{ | ||
m_running_flag.store(true); | ||
|
||
// OpMon. | ||
m_tc_made_count.store(0); | ||
m_tc_sent_count.store(0); | ||
m_tc_failed_sent_count.store(0); | ||
|
||
auto start_params = obj.get<rcif::cmd::StartParams>(); | ||
|
||
std::string timestamp_method = m_conf->get_timestamp_method(); | ||
|
@@ -237,6 +253,7 @@ CustomTCMaker::send_trigger_candidates() | |
} | ||
|
||
triggeralgs::TriggerCandidate candidate = create_candidate(m_next_trigger_timestamp, m_tc_timestamps.front().first); | ||
if (m_latency_monitoring.load()) m_latency_instance.update_latency_in( candidate.time_candidate ); | ||
m_tc_made_count++; | ||
|
||
TLOG_DEBUG(1) << get_name() << " at timestamp " << m_timestamp_estimator->get_timestamp_estimate() | ||
|
@@ -245,6 +262,7 @@ CustomTCMaker::send_trigger_candidates() | |
TCWrapper tcw(candidate); | ||
try { | ||
m_trigger_candidate_sink->send(std::move(tcw), std::chrono::milliseconds(10)); | ||
if (m_latency_monitoring.load()) m_latency_instance.update_latency_out( candidate.time_candidate ); | ||
m_tc_sent_count++; | ||
m_tc_sent_count_type[m_tc_timestamps.front().first] += 1; | ||
} catch (const ers::Issue& e) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,12 +76,22 @@ RandomTCMakerModule::generate_opmon_data() | |
info.set_tc_failed_sent_count( m_tc_failed_sent_count.load() ); | ||
|
||
this->publish(std::move(info)); | ||
|
||
if ( m_running_flag.load() && m_latency_monitoring.load() ) { | ||
opmon::TriggerLatency lat_info; | ||
|
||
lat_info.set_latency_in( m_latency_instance.get_latency_in() ); | ||
lat_info.set_latency_out( m_latency_instance.get_latency_out() ); | ||
ArturSztuc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
this->publish(std::move(lat_info)); | ||
} | ||
} | ||
|
||
void | ||
RandomTCMakerModule::do_configure(const nlohmann::json& /*obj*/) | ||
{ | ||
//m_conf = obj.get<randomtriggercandidatemaker::Conf>(); | ||
m_latency_monitoring.store( m_conf->get_latency_monitoring_conf()->get_enable_latency_monitoring() ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto re. |
||
} | ||
|
||
void | ||
|
@@ -91,6 +101,11 @@ RandomTCMakerModule::do_start(const nlohmann::json& obj) | |
|
||
m_running_flag.store(true); | ||
|
||
// OpMon. | ||
m_tc_made_count.store(0); | ||
m_tc_sent_count.store(0); | ||
m_tc_failed_sent_count.store(0); | ||
|
||
std::string timestamp_method = m_conf->get_timestamp_method(); | ||
if (timestamp_method == "kTimeSync") { | ||
TLOG_DEBUG(0) << "Creating TimestampEstimator"; | ||
|
@@ -210,13 +225,16 @@ RandomTCMakerModule::send_trigger_candidates() | |
} | ||
next_trigger_timestamp = m_timestamp_estimator->get_timestamp_estimate(); | ||
triggeralgs::TriggerCandidate candidate = create_candidate(next_trigger_timestamp); | ||
|
||
if (m_latency_monitoring.load()) m_latency_instance.update_latency_in( candidate.time_candidate ); | ||
m_tc_made_count++; | ||
|
||
TLOG_DEBUG(1) << get_name() << " at timestamp " << m_timestamp_estimator->get_timestamp_estimate() | ||
<< ", pushing a candidate with timestamp " << candidate.time_candidate; | ||
TCWrapper tcw(candidate); | ||
try{ | ||
m_trigger_candidate_sink->send(std::move(tcw), std::chrono::milliseconds(10)); | ||
if (m_latency_monitoring.load()) m_latency_instance.update_latency_out( candidate.time_candidate ); | ||
m_tc_sent_count++; | ||
} catch (const ers::Issue& e) { | ||
ers::error(e); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
syntax = "proto3"; | ||
|
||
package dunedaq.trigger.opmon; | ||
|
||
// Message for latency variables | ||
// Latency represents the difference between current system (clock) time and the data time of particular (TX) data object | ||
// Units are ms | ||
ArturSztuc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Used by many trigger modules | ||
message TriggerLatency { | ||
uint32 latency_in = 1; | ||
uint32 latency_out = 2; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not an important comment, I'm only writing this because I've learned something new a few weeks back and want to share :) Unnecessary micro-optimisation, but in C++ order inside if statement can matter of operations like
&&
,||
(not true for all operators).So in your case, whilst we're running, we will always load 2 booleans, even if we don't want monitoring. With the suggestion above, if monitoring is off, we will only load 1 boolean. Matters more task-heavy workflows so probably not here, but maybe in e.g.
TPDataProcessor
where every little counts.