Skip to content

Commit ccd2024

Browse files
author
Alexander Indenbaum
committed
nvmeof: refactor timer for exact frequency timing with drift correction
- Replace relative timing with absolute time calculation to prevent drift - Implement drift detection and correction mechanism - Add comprehensive logging for timer firing, execution duration, drift and rescheduling This refactoring ensures the nvmeof monitor client maintains exact frequency timing over long periods, even when individual tick executions are delayed. Signed-off-by: Alexander Indenbaum <[email protected]>
1 parent bf5ad2f commit ccd2024

File tree

2 files changed

+71
-8
lines changed

2 files changed

+71
-8
lines changed

src/nvmeof/NVMeofGwMonitorClient.cc

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,10 @@ int NVMeofGwMonitorClient::init()
184184

185185
{
186186
std::lock_guard bl(beacon_lock);
187-
tick();
187+
// Initialize timer state for exact frequency timing
188+
next_tick_time = ceph::mono_clock::now();
189+
// Start the timer after full initialization is complete
190+
schedule_next_tick();
188191
}
189192

190193
dout(10) << "Complete." << dendl;
@@ -283,19 +286,55 @@ void NVMeofGwMonitorClient::connect_panic()
283286
void NVMeofGwMonitorClient::tick()
284287
{
285288
dout(10) << dendl;
286-
289+
auto start_time = ceph::mono_clock::now();
287290
connect_panic();
288291
disconnect_panic();
289292
send_beacon();
290293
first_beacon = false;
291-
timer.add_event_after(
292-
g_conf().get_val<std::chrono::seconds>("nvmeof_mon_client_tick_period").count(),
293-
new LambdaContext([this](int r){
294-
tick();
295-
}
296-
));
294+
295+
// Log tick execution duration
296+
log_tick_execution_duration(start_time);
297+
298+
// Schedule next tick with exact frequency timing
299+
schedule_next_tick();
297300
}
298301

302+
void NVMeofGwMonitorClient::schedule_next_tick()
303+
{
304+
ceph_assert(ceph_mutex_is_locked_by_me(beacon_lock));
305+
306+
// Calculate next tick time based on configured interval
307+
auto tick_period = g_conf().get_val<std::chrono::seconds>("nvmeof_mon_client_tick_period");
308+
next_tick_time += tick_period;
309+
310+
// Get current time to check for drift
311+
auto now = ceph::mono_clock::now();
312+
313+
// If we're behind schedule, adjust next_tick_time to prevent drift accumulation
314+
if (next_tick_time < now) {
315+
dout(1) << "Timer drift detected, adjusting next_tick_time from "
316+
<< next_tick_time << " to " << now << dendl;
317+
next_tick_time = now;
318+
}
319+
320+
// Schedule the next tick
321+
auto callback = new LambdaContext([this](int r) {
322+
tick();
323+
});
324+
325+
auto tick_time = next_tick_time;
326+
if (!timer.add_event_at(tick_time, callback)) {
327+
throw std::runtime_error("Failed to schedule timer event (timer shutting down)");
328+
}
329+
330+
// Log scheduling information for frequency analysis
331+
auto delay_ns = (next_tick_time - now).count();
332+
dout(10) << "Scheduled next tick at " << next_tick_time
333+
<< " (delay: " << delay_ns << " ns, "
334+
<< (delay_ns / 1000000.0) << " ms)" << dendl;
335+
}
336+
337+
299338
void NVMeofGwMonitorClient::shutdown()
300339
{
301340
std::lock_guard l(lock);
@@ -475,3 +514,19 @@ int NVMeofGwMonitorClient::main(std::vector<const char *> args)
475514

476515
return 0;
477516
}
517+
518+
void NVMeofGwMonitorClient::log_tick_execution_duration(const ceph::mono_clock::time_point& start_time)
519+
{
520+
auto execution_time = ceph::mono_clock::now() - start_time;
521+
auto tick_period = g_conf().get_val<std::chrono::seconds>("nvmeof_mon_client_tick_period");
522+
auto max_allowed_time = tick_period * 0.1; // 10% of tick period
523+
524+
dout(10) << "Tick execution took " << execution_time.count() / 1000000.0
525+
<< "ms" << dendl;
526+
527+
if (execution_time > max_allowed_time) {
528+
dout(1) << "WARNING: Tick execution took " << execution_time.count() / 1000000.0
529+
<< "ms, exceeding 10% of tick period (" << max_allowed_time.count() / 1000000.0
530+
<< "ms)" << dendl;
531+
}
532+
}

src/nvmeof/NVMeofGwMonitorClient.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "common/Finisher.h"
2222
#include "common/Timer.h"
2323
#include "common/LogClient.h"
24+
#include "common/ceph_time.h"
2425

2526
#include "mon/MonClient.h"
2627
#include "osdc/Objecter.h"
@@ -71,11 +72,18 @@ class NVMeofGwMonitorClient: public Dispatcher,
7172
ceph::mutex beacon_lock = ceph::make_mutex("NVMeofGw::beacon_lock");
7273
SafeTimer timer;
7374

75+
// Timer state for exact frequency timing
76+
ceph::mono_clock::time_point next_tick_time;
77+
7478
int orig_argc;
7579
const char **orig_argv;
7680

7781
void send_config_beacon();
7882
void send_beacon();
83+
84+
// Timer management for exact frequency
85+
void schedule_next_tick();
86+
void log_tick_execution_duration(const ceph::mono_clock::time_point& start_time);
7987

8088
public:
8189
NVMeofGwMonitorClient(int argc, const char **argv);

0 commit comments

Comments
 (0)