DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
TimestampEstimator.cpp
Go to the documentation of this file.
1
10#include "utilities/Issues.hpp"
11
12#include "logging/Logging.hpp"
13
14#include <memory>
15#include <unistd.h>
16
17#define TRACE_NAME "TimestampEstimator" // NOLINT
18
19namespace dunedaq {
20namespace utilities {
21TimestampEstimator::TimestampEstimator(uint32_t run_number, uint64_t clock_frequency_hz) // NOLINT(build/unsigned)
22 : TimestampEstimator(clock_frequency_hz)
23{
24 m_run_number = run_number;
25}
26
27TimestampEstimator::TimestampEstimator(uint64_t clock_frequency_hz) // NOLINT(build/unsigned)
28 : m_current_timestamp_estimate(
29 TimeSyncPoint{ std::numeric_limits<uint64_t>::max(), std::chrono::time_point<std::chrono::steady_clock>() })
30 , m_clock_frequency_hz(clock_frequency_hz)
31 , m_most_recent_daq_time(0)
32 , m_most_recent_system_time(0)
33 , m_run_number(0)
34 , m_received_timesync_count(0)
35{
36 m_current_process_id = static_cast<uint32_t>(getpid());
37}
38
40
46uint64_t
48{
49 using namespace std::chrono;
50
52 // 27-May-2025, KAB: added check if a valid timestamp is available and, if not, return early
53 // with the special value that indicates that none is available.
54 if (estimate.daq_time == std::numeric_limits<uint64_t>::max()) {return estimate.daq_time;}
55
56 auto delta_time_us = duration_cast<microseconds>(steady_clock::now() - estimate.system_time).count();
57
58 const uint64_t new_timestamp = estimate.daq_time + delta_time_us * m_clock_frequency_hz / 1000000;
59
60 return new_timestamp;
61}
62
63std::chrono::microseconds
65{
67 if (now > ts)
68 return std::chrono::microseconds(0);
69 auto diff = ts - now;
70 return std::chrono::microseconds(static_cast<long>(diff * 1000000. / m_clock_frequency_hz));
71}
72
73void
74TimestampEstimator::add_timestamp_datapoint(uint64_t daq_time, uint64_t system_time)
75{
76 using namespace std::chrono;
77
78 std::scoped_lock<std::mutex> lk(m_datapoint_mutex);
79
80 // First, update the latest timestamp
82 int64_t diff = estimate.daq_time - daq_time;
83 TLOG_DEBUG(TLVL_TIME_SYNC_PROPERTIES) << "Got a TimeSync timestamp = " << daq_time
84 << ", system time = " << system_time << " when current timestamp estimate was "
85 << estimate.daq_time << ". diff=" << diff;
86
87 if (m_most_recent_daq_time == std::numeric_limits<uint64_t>::max() || daq_time > m_most_recent_daq_time) {
88 m_most_recent_daq_time = daq_time;
89 m_most_recent_system_time = system_time;
90 }
91
92 if (m_most_recent_daq_time != std::numeric_limits<uint64_t>::max()) {
93 // Update the current timestamp estimate, based on the most recently-read TimeSync
94 using namespace std::chrono;
95
96 auto time_now =
97 static_cast<uint64_t>(duration_cast<microseconds>(system_clock::now().time_since_epoch()).count()); // NOLINT
98 auto steady_time_now = steady_clock::now();
99
100 // (PAR 2021-07-22) We only want to _increase_ our timestamp
101 // estimate, not _decrease_ it, so we only attempt the update if
102 // our system time is later than the latest time sync's system
103 // time. We can get TimeSync messages from the "future" if
104 // they're coming from another host whose clock is not exactly
105 // synchronized with ours: that's fine, but if the discrepancy
106 // is large, then badness could happen, so emit a warning
107
108 if (time_now < m_most_recent_system_time - 10000) {
109 ers::warning(EarlyTimeSync(ERS_HERE, m_most_recent_system_time - time_now));
110 }
111
112 if (time_now > m_most_recent_system_time) {
113
114 auto delta_time = time_now - m_most_recent_system_time;
116 << "Time diff between current system and latest TimeSync system time [us]: " << delta_time;
117
118 // Warn user if current system time is more than 1s ahead of latest TimeSync system time. This could be a sign of
119 // an issue, e.g. machine times out of sync
120 if (delta_time > 1e6)
121 ers::warning(LateTimeSync(ERS_HERE, delta_time));
122
123 const uint64_t new_timestamp = m_most_recent_daq_time + delta_time * m_clock_frequency_hz / 1000000;
124
125 // Don't ever decrease the timestamp; just wait until enough
126 // time passes that we want to increase it
127 if (estimate.daq_time == std::numeric_limits<uint64_t>::max() || new_timestamp >= estimate.daq_time) {
129 << "Storing new timestamp estimate of " << new_timestamp << " ticks (..." << std::fixed
130 << std::setprecision(8)
131 << (static_cast<double>(new_timestamp % (m_clock_frequency_hz * 1000)) /
132 static_cast<double>(m_clock_frequency_hz))
133 << " sec), mrt.daq_time is " << m_most_recent_daq_time << " ticks (..."
134 << (static_cast<double>(m_most_recent_daq_time % (m_clock_frequency_hz * 1000)) /
135 static_cast<double>(m_clock_frequency_hz))
136 << " sec), delta_time is " << delta_time << " usec, clock_freq is " << m_clock_frequency_hz << " Hz";
137 m_current_timestamp_estimate.store(TimeSyncPoint{ new_timestamp, steady_time_now });
138 } else {
139 TLOG_DEBUG(TLVL_TIME_SYNC_NOTES) << "Not updating timestamp estimate backwards from "
140 << m_current_timestamp_estimate.load().daq_time << " to " << new_timestamp;
141 }
142 }
143 }
144}
145
146} // namespace utilities
147} // namespace dunedaq
#define ERS_HERE
TimestampEstimator is an implementation of TimestampEstimatorBase that uses TimeSync messages from an...
std::atomic< TimeSyncPoint > m_current_timestamp_estimate
uint64_t get_timestamp_estimate() const override
Returns the current timestamp estimate or a special value if no valid timestamp is available.
std::chrono::microseconds get_wait_estimate(uint64_t ts) const override
void add_timestamp_datapoint(uint64_t daq_time, uint64_t system_time)
TimestampEstimator(uint32_t run_number, uint64_t clock_frequency_hz)
static int64_t now()
#define TLOG_DEBUG(lvl,...)
Definition Logging.hpp:112
Including Qt Headers.
PDS Frame with unphysical timestamp detected with ts
void warning(const Issue &issue)
Definition ers.hpp:115
std::chrono::time_point< std::chrono::steady_clock > system_time
#define TLVL_TIME_SYNC_PROPERTIES
Definition Issues.hpp:16
#define TLVL_TIME_SYNC_NEW_ESTIMATE
Definition Issues.hpp:18
#define TLVL_TIME_SYNC_NOTES
Definition Issues.hpp:17