time.h
trace_funcs.h
trace.h
+ tw_funcs.h
unix/mc_socket.h
unix/plugin.h
unix/unix.h
static void
process_timer_start (vlib_main_t *vm, vlib_process_t *p, u32 runtime_index)
{
- TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
vlib_tw_event_t e = { .type = VLIB_TW_EVENT_T_PROCESS_NODE,
.index = runtime_index };
if (p->resume_clock_interval == 0)
return;
- p->stop_timer_handle = TW (tw_timer_start) (tw, e.as_u32, 0 /* timer_id */,
- p->resume_clock_interval);
+ p->stop_timer_handle = vlib_tw_timer_start (vm, e, p->resume_clock_interval);
}
static u64
return t;
}
-static void
-process_expired_timer_cb (u32 *expired_timer_handles)
+static __clib_warn_unused_result u32 *
+process_expired_timers (u32 *v)
{
vlib_main_t *vm = vlib_get_main ();
vlib_node_main_t *nm = &vm->node_main;
u32 *handle;
- vec_foreach (handle, expired_timer_handles)
+ v = vlib_tw_timer_expire_timers (vm, v);
+
+ vec_foreach (handle, v)
{
vlib_tw_event_t e = { .as_u32 = *handle };
vlib_process_restore_t restore = {};
else
ASSERT (0);
}
-}
-
-static void
-vlib_tw_init (vlib_main_t *vm)
-{
- TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
- tw = clib_mem_alloc_aligned (sizeof (TWT (tw_timer_wheel)),
- CLIB_CACHE_LINE_BYTES);
- /* Create the process timing wheel */
- TW (tw_timer_wheel_init)
- (tw, process_expired_timer_cb /* callback */, 1 / VLIB_TW_TICKS_PER_SECOND,
- ~0 /* max expirations per call */);
- vm->timing_wheel = tw;
-}
-
-static void
-vlib_tw_expire_timers (vlib_main_t *vm)
-{
- TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
- TW (tw_timer_expire_timers) (tw, vlib_time_now (vm));
+ return v;
}
static_always_inline void
f64 now;
vlib_frame_queue_main_t *fqm;
u32 frame_queue_check_counter = 0;
+ u32 *expired_timers = 0;
/* Initialize pending node vector. */
if (is_main)
if (PREDICT_FALSE (vm->elog_trace_graph_dispatch))
ed = ELOG_DATA (&vlib_global_main.elog_main, es);
- vlib_tw_expire_timers (vm);
+ expired_timers = process_expired_timers (expired_timers);
ASSERT (nm->process_restore_current != 0);
}
}
else
- vlib_tw_expire_timers (vm);
+ expired_timers = process_expired_timers (expired_timers);
vlib_increment_main_loop_counter (vm);
/* Record time stamp in case there are no enabled nodes and above
/* Timing wheel for scheduling time-based node dispatch. */
void *timing_wheel;
+ u32 n_tw_timers;
#ifdef CLIB_SANITIZE_ADDR
/* address sanitizer stack save */
}
vlib_signal_timed_event_data_t;
-typedef enum
-{
- VLIB_TW_EVENT_T_PROCESS_NODE = 1,
- VLIB_TW_EVENT_T_TIMED_EVENT = 2,
- VLIB_TW_EVENT_T_SCHED_NODE = 3,
-} vlib_tw_event_type_t;
-
-typedef union
-{
- struct
- {
- u32 type : 2; /* vlib_tw_event_type_t */
- u32 index : 30;
- };
- u32 as_u32;
-} vlib_tw_event_t;
-
typedef struct
{
clib_march_variant_type_t index;
#include <vppinfra/clib.h>
#include <vppinfra/fifo.h>
-#include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
#include <vppinfra/interrupt.h>
-#define VLIB_TW_TICKS_PER_SECOND 1e5 /* 10 us */
-
#ifdef CLIB_SANITIZE_ADDR
#include <sanitizer/asan_interface.h>
#endif
always_inline void
vlib_node_schedule (vlib_main_t *vm, u32 node_index, f64 dt)
{
- TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
u64 ticks;
vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, node_index);
dt = flt_round_nearest (dt * VLIB_TW_TICKS_PER_SECOND);
ticks = clib_max ((u64) dt, 1);
- rt->stop_timer_handle_plus_1 =
- 1 + TW (tw_timer_start) (tw, e.as_u32, 0 /* timer_id */, ticks);
+ rt->stop_timer_handle_plus_1 = 1 + vlib_tw_timer_start (vm, e, ticks);
}
always_inline void
vlib_node_unschedule (vlib_main_t *vm, u32 node_index)
{
vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, node_index);
- TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
ASSERT (vm == vlib_get_main ());
ASSERT (vlib_node_is_scheduled (vm, node_index) == 1);
- TW (tw_timer_stop) (tw, rt->stop_timer_handle_plus_1);
-
+ vlib_tw_timer_stop (vm, rt->stop_timer_handle_plus_1 - 1);
rt->stop_timer_handle_plus_1 = 0;
}
vlib_node_t *n, vlib_process_t *p, uword t,
uword n_data_elts, uword n_data_elt_bytes)
{
- TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
uword add_to_pending = 0, delete_from_wheel = 0;
u8 *data_to_be_written_by_caller;
vec_attr_t va = { .elt_sz = n_data_elt_bytes };
break;
}
- if (TW (tw_timer_handle_is_free) (tw, p->stop_timer_handle))
+ if (vlib_tw_timer_handle_is_free (vm, p->stop_timer_handle))
delete_from_wheel = 0;
/* Never add current process to pending vector since current process is
if (delete_from_wheel)
{
- TW (tw_timer_stop) (tw, p->stop_timer_handle);
+ vlib_tw_timer_stop (vm, p->stop_timer_handle);
p->stop_timer_handle = ~0;
}
uword type_opaque,
uword n_data_elts, uword n_data_elt_bytes)
{
- TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
vlib_node_main_t *nm = &vm->node_main;
vlib_node_t *n = vlib_get_node (vm, node_index);
vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
te->event_type_index = t;
p->stop_timer_handle =
- TW (tw_timer_start) (tw,
+ vlib_tw_timer_start (vm,
(vlib_tw_event_t){
.type = VLIB_TW_EVENT_T_TIMED_EVENT,
.index = te - nm->signal_timed_event_data_pool,
- }
- .as_u32,
- 0 /* timer_id */, dt * VLIB_TW_TICKS_PER_SECOND);
+ },
+ dt * VLIB_TW_TICKS_PER_SECOND);
/* Inline data big enough to hold event? */
if (te->n_data_bytes < sizeof (te->inline_event_data))
#define included_vlib_time_h
#include <vlib/vlib.h>
-#include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
+#include <vlib/tw_funcs.h>
static inline f64
vlib_time_get_next_timer (vlib_main_t *vm)
{
TWT (tw_timer_wheel) *wheel = vm->timing_wheel;
- return TW (tw_timer_first_expires_in_ticks) (wheel) * wheel->timer_interval;
+ return vlib_tw_timer_first_expires_in_ticks (vm) * wheel->timer_interval;
}
static inline void
--- /dev/null
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2025 Cisco Systems, Inc.
+ */
+
+#ifndef __vlib_tw_funcs_h__
+#define __vlib_tw_funcs_h__
+
+#include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
+#define VLIB_TW_TICKS_PER_SECOND 1e5 /* 10 us */
+
+typedef enum
+{
+ VLIB_TW_EVENT_T_PROCESS_NODE = 1,
+ VLIB_TW_EVENT_T_TIMED_EVENT = 2,
+ VLIB_TW_EVENT_T_SCHED_NODE = 3,
+} vlib_tw_event_type_t;
+
+typedef union
+{
+ struct
+ {
+ u32 type : 2; /* vlib_tw_event_type_t */
+ u32 index : 30;
+ };
+ u32 as_u32;
+} vlib_tw_event_t;
+
+static_always_inline u32
+vlib_tw_timer_start (vlib_main_t *vm, vlib_tw_event_t e, u64 interval)
+{
+ TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
+ vm->n_tw_timers++;
+ return TW (tw_timer_start) (tw, e.as_u32, 0 /* timer_id */, interval);
+}
+
+static_always_inline void
+vlib_tw_timer_stop (vlib_main_t *vm, u32 handle)
+{
+ TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
+ ASSERT (vm->n_tw_timers > 0);
+ vm->n_tw_timers--;
+ TW (tw_timer_stop) (tw, handle);
+}
+
+static_always_inline int
+vlib_tw_timer_handle_is_free (vlib_main_t *vm, u32 handle)
+{
+ TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
+ return TW (tw_timer_handle_is_free) (tw, handle);
+}
+
+static_always_inline u32
+vlib_tw_timer_first_expires_in_ticks (vlib_main_t *vm)
+{
+ return TW (tw_timer_first_expires_in_ticks) (
+ (TWT (tw_timer_wheel) *) vm->timing_wheel);
+}
+
+static_always_inline void
+vlib_tw_init (vlib_main_t *vm)
+{
+ TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
+ tw = clib_mem_alloc_aligned (sizeof (TWT (tw_timer_wheel)),
+ CLIB_CACHE_LINE_BYTES);
+ /* Create the process timing wheel */
+ TW (tw_timer_wheel_init)
+ (tw, 0 /* callback */, 1 / VLIB_TW_TICKS_PER_SECOND,
+ ~0 /* max expirations per call */);
+ vm->timing_wheel = tw;
+ vm->n_tw_timers = 0;
+}
+
+static_always_inline u32 *
+vlib_tw_timer_expire_timers (vlib_main_t *vm, u32 *v)
+{
+ TWT (tw_timer_wheel) *tw = (TWT (tw_timer_wheel) *) vm->timing_wheel;
+
+ vec_reset_length (v);
+
+ if (vm->n_tw_timers > 0)
+ {
+ v = TW (tw_timer_expire_timers_vec) (tw, vlib_time_now (vm), v);
+ ASSERT (vec_len (v) <= vm->n_tw_timers);
+ vm->n_tw_timers -= vec_len (v);
+ }
+
+ return v;
+}
+
+#endif /* __vlib_tw_funcs_h__ */
else if (is_main && vector_rate < 2 && vm->api_queue_nonempty == 0
&& nm->input_node_counts_by_state[VLIB_NODE_STATE_POLLING] == 0)
{
- ticks_until_expiration = TW (tw_timer_first_expires_in_ticks) (
- (TWT (tw_timer_wheel) *) vm->timing_wheel);
+ ticks_until_expiration = vlib_tw_timer_first_expires_in_ticks (vm);
/* Nothing on the fast wheel, sleep 10ms */
if (ticks_until_expiration == TW_SLOTS_PER_RING)
#include <vlib/threads.h>
#include <vlib/physmem_funcs.h>
#include <vlib/buffer_funcs.h>
+#include <vlib/tw_funcs.h>
#include <vlib/error_funcs.h>
#include <vlib/format_funcs.h>
#include <vlib/node_funcs.h>