@@ -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()
283286void 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+
299338void 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+ }
0 commit comments