diff options
-rw-r--r-- | config/odp-linux-dpdk.conf | 3 | ||||
-rw-r--r-- | platform/linux-dpdk/odp_timer.c | 193 |
2 files changed, 159 insertions, 37 deletions
diff --git a/config/odp-linux-dpdk.conf b/config/odp-linux-dpdk.conf index 4267ba61d..05347e116 100644 --- a/config/odp-linux-dpdk.conf +++ b/config/odp-linux-dpdk.conf @@ -191,6 +191,9 @@ timer: { # a higher resolution than this, the polling rate is increased # accordingly. inline_poll_interval_nsec = 500000 + + # Use experimental DPDK alternate timer API based implementation + alternate = 0 } ipsec: { diff --git a/platform/linux-dpdk/odp_timer.c b/platform/linux-dpdk/odp_timer.c index e6f4ffe86..68ce550f5 100644 --- a/platform/linux-dpdk/odp_timer.c +++ b/platform/linux-dpdk/odp_timer.c @@ -8,6 +8,7 @@ #include <odp_posix_extensions.h> #include <odp/api/shared_memory.h> +#include <odp/api/thread.h> #include <odp/api/ticketlock.h> #include <odp/api/timer.h> #include <odp/api/plat/queue_inlines.h> @@ -17,6 +18,7 @@ #include <odp_libconfig_internal.h> #include <odp_queue_if.h> #include <odp_ring_u32_internal.h> +#include <odp_thread_internal.h> #include <odp_timer_internal.h> #include <rte_cycles.h> @@ -99,6 +101,19 @@ typedef struct timer_pool_s { } timer_pool_t; +/* Wrappers for alternative DPDK timer implementation */ +typedef int (*timer_stop_fn)(struct rte_timer *tim); +typedef int (*timer_manage_fn)(void); +typedef int (*timer_reset_fn)(struct rte_timer *tim, uint64_t ticks, + enum rte_timer_type type, unsigned int tim_lcore, + rte_timer_cb_t fct, void *arg); + +typedef struct timer_ops_t { + timer_stop_fn stop; + timer_manage_fn manage; + timer_reset_fn reset; +} timer_ops_t; + typedef struct { timer_pool_t timer_pool[MAX_TIMER_POOLS]; odp_shm_t shm; @@ -108,12 +123,18 @@ typedef struct { odp_time_t poll_interval_time; int num_timer_pools; int poll_interval; + uint32_t data_id; + uint8_t use_alternate; + timer_ops_t ops; } timer_global_t; typedef struct timer_local_t { - odp_time_t last_run; - int run_cnt; + odp_time_t last_run; + uint64_t thrmask_epoch; + int run_cnt; + int num_poll_cores; + unsigned int poll_cores[ODP_THREAD_COUNT_MAX]; } timer_local_t; @@ -123,6 +144,87 @@ static timer_global_t *timer_global; /* Timer thread local data */ static __thread timer_local_t timer_local; +static void timer_cb(struct rte_timer *rte_timer, void *arg ODP_UNUSED) +{ + timer_entry_t *timer = rte_timer->arg; + odp_event_t event; + odp_queue_t queue; + + odp_ticketlock_lock(&timer->lock); + + if (timer->state != TICKING) { + ODP_ERR("Timer has been cancelled or freed.\n"); + odp_ticketlock_unlock(&timer->lock); + return; + } + + queue = timer->queue; + event = timer->tmo_event; + timer->tmo_event = ODP_EVENT_INVALID; + timer->state = EXPIRED; + + odp_ticketlock_unlock(&timer->lock); + + if (odp_unlikely(odp_queue_enq(queue, event))) { + ODP_ERR("Timeout event enqueue failed.\n"); + odp_event_free(event); + } +} + +static void timer_alt_manage_cb(struct rte_timer *rte_timer) +{ + timer_cb(rte_timer, NULL); +} + +static inline int timer_stop(struct rte_timer *tim) +{ + return rte_timer_stop(tim); +} + +static inline int timer_alt_stop(struct rte_timer *tim) +{ + return rte_timer_alt_stop(timer_global->data_id, tim); +} + +static inline int timer_manage(void) +{ + return rte_timer_manage(); +} + +static inline int timer_alt_manage(void) +{ + uint64_t thrmask_epoch = _odp_thread_thrmask_epoch(); + + if (odp_unlikely(timer_local.thrmask_epoch != thrmask_epoch)) { + int cpu_ids = _odp_thread_cpu_ids(timer_local.poll_cores, + ODP_THREAD_COUNT_MAX); + + timer_local.num_poll_cores = cpu_ids; + timer_local.thrmask_epoch = thrmask_epoch; + } + + return rte_timer_alt_manage(timer_global->data_id, + timer_local.poll_cores, + timer_local.num_poll_cores, + timer_alt_manage_cb); +} + +static inline int timer_reset(struct rte_timer *tim, uint64_t ticks, + enum rte_timer_type type, unsigned int tim_lcore, + rte_timer_cb_t fct, void *arg) +{ + return rte_timer_reset(tim, ticks, type, tim_lcore, fct, arg); +} + +static inline int timer_alt_reset(struct rte_timer *tim, uint64_t ticks, + enum rte_timer_type type, + unsigned int tim_lcore, rte_timer_cb_t fct, + void *arg) +{ + return rte_timer_alt_reset(timer_global->data_id, tim, ticks, type, + tim_lcore, fct, arg); +} + static inline timer_pool_t *timer_pool_from_hdl(odp_timer_pool_t hdl) { return (timer_pool_t *)(uintptr_t)hdl; @@ -168,6 +270,8 @@ int _odp_timer_init_global(const odp_init_t *params) timer_global->shm = shm; odp_ticketlock_init(&timer_global->lock); + ODP_PRINT("\nTimer config:\n"); + conf_str = "timer.inline_poll_interval"; if (!_odp_libconfig_lookup_int(conf_str, &val)) { ODP_ERR("Config option '%s' not found.\n", conf_str); @@ -175,6 +279,7 @@ int _odp_timer_init_global(const odp_init_t *params) return -1; } timer_global->poll_interval = val; + ODP_PRINT(" %s: %d\n", conf_str, val); conf_str = "timer.inline_poll_interval_nsec"; if (!_odp_libconfig_lookup_int(conf_str, &val)) { @@ -185,14 +290,53 @@ int _odp_timer_init_global(const odp_init_t *params) timer_global->poll_interval_nsec = val; timer_global->poll_interval_time = odp_time_global_from_ns(timer_global->poll_interval_nsec); + ODP_PRINT(" %s: %d\n", conf_str, val); + + conf_str = "timer.alternate"; + if (!_odp_libconfig_lookup_int(conf_str, &val)) { + ODP_ERR("Config option '%s' not found.\n", conf_str); + odp_shm_free(shm); + return -1; + } + timer_global->use_alternate = !!val; + ODP_PRINT(" %s: %" PRIu8 "\n", conf_str, timer_global->use_alternate); + + ODP_PRINT("\n"); - rte_timer_subsystem_init(); + if (rte_timer_subsystem_init()) { + ODP_ERR("Initializing DPDK timer library failed\n"); + odp_shm_free(shm); + return -1; + } + + if (timer_global->use_alternate) { + if (rte_timer_data_alloc(&timer_global->data_id)) { + ODP_ERR("Failed to allocate DPDK timer data instance\n"); + odp_shm_free(shm); + return -1; + } + timer_global->ops.stop = timer_alt_stop; + timer_global->ops.manage = timer_alt_manage; + timer_global->ops.reset = timer_alt_reset; + } else { + timer_global->ops.stop = timer_stop; + timer_global->ops.manage = timer_manage; + timer_global->ops.reset = timer_reset; + } return 0; } int _odp_timer_term_global(void) { + if (timer_global && timer_global->use_alternate) { + if (rte_timer_data_dealloc(timer_global->data_id)) { + ODP_ERR("Failed to deallocate DPDK timer data instance\n"); + return -1; + } + } + rte_timer_subsystem_finalize(); + if (timer_global && odp_shm_free(timer_global->shm)) { ODP_ERR("Shm free failed for odp_timer\n"); return -1; @@ -218,6 +362,7 @@ void _odp_timer_run_inline(int dec) { int poll_interval = timer_global->poll_interval; odp_time_t now; + int ret; /* Rate limit how often this thread checks the timer pools. */ @@ -239,7 +384,9 @@ void _odp_timer_run_inline(int dec) } /* Check timer pools */ - rte_timer_manage(); + ret = timer_global->ops.manage(); + if (odp_unlikely(ret)) + ODP_ERR("RTE timer manage failed: %d\n", ret); } static inline uint64_t tmo_ticks_to_ns_round_up(uint64_t tmo_ticks) @@ -352,7 +499,6 @@ odp_timer_pool_t odp_timer_pool_create(const char *name, else res_ns = GIGA_HZ / param->res_hz; - /* Scan timer pool twice during resolution interval */ if (res_ns > ODP_TIME_USEC_IN_NS) nsec_per_scan = res_ns / 2; @@ -416,6 +562,7 @@ odp_timer_pool_t odp_timer_pool_create(const char *name, odp_ticketlock_init(&timer->lock); rte_timer_init(&timer->rte_timer); + timer->rte_timer.arg = timer; timer->timer_pool = timer_pool; timer->timer_idx = i; @@ -583,7 +730,7 @@ retry: if (timer->state == TICKING) { ODP_DBG("Freeing active timer.\n"); - if (rte_timer_stop(&timer->rte_timer)) { + if (timer_global->ops.stop(&timer->rte_timer)) { /* Another core runs timer callback function. */ odp_ticketlock_unlock(&timer->lock); goto retry; @@ -618,34 +765,6 @@ static inline odp_timeout_hdr_t *timeout_to_hdr(odp_timeout_t tmo) return (odp_timeout_hdr_t *)(uintptr_t)tmo; } -static void timer_cb(struct rte_timer *rte_timer, void *arg) -{ - timer_entry_t *timer = arg; - odp_event_t event; - odp_queue_t queue; - (void)rte_timer; - - odp_ticketlock_lock(&timer->lock); - - if (timer->state != TICKING) { - ODP_ERR("Timer has been cancelled or freed.\n"); - odp_ticketlock_unlock(&timer->lock); - return; - } - - queue = timer->queue; - event = timer->tmo_event; - timer->tmo_event = ODP_EVENT_INVALID; - timer->state = EXPIRED; - - odp_ticketlock_unlock(&timer->lock); - - if (odp_unlikely(odp_queue_enq(queue, event))) { - ODP_ERR("Timeout event enqueue failed.\n"); - odp_event_free(event); - } -} - static inline int timer_set(odp_timer_t timer_hdl, uint64_t tick, odp_event_t *event, int absolute) { @@ -687,8 +806,8 @@ retry: return ODP_TIMER_FAIL; } - if (odp_unlikely(rte_timer_reset(&timer->rte_timer, rel_tick, SINGLE, - lcore, timer_cb, timer))) { + if (odp_unlikely(timer_global->ops.reset(&timer->rte_timer, rel_tick, + SINGLE, lcore, timer_cb, timer))) { int do_retry = 0; /* Another core is currently running the callback function. @@ -770,7 +889,7 @@ int odp_timer_cancel(odp_timer_t timer_hdl, odp_event_t *tmo_ev) return -1; } - if (odp_unlikely(rte_timer_stop(&timer->rte_timer))) { + if (odp_unlikely(timer_global->ops.stop(&timer->rte_timer))) { /* Another core runs timer callback function. */ odp_ticketlock_unlock(&timer->lock); return -1; |