eventdev/timer: support periodic event timer

Add support to configure and use periodic event timers in
software timer adapter.

The structure ``rte_event_timer_adapter_stats`` is extended
by adding a new field, ``evtim_drop_count``. This stat
represents the number of times an event_timer expiry event
is dropped by the event timer adapter.

Updated the software eventdev pmd timer_adapter_caps_get
callback function to report the support of periodic
event timer capability.

Signed-off-by: Naga Harish K S V <s.v.naga.harish.k@intel.com>
Acked-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
This commit is contained in:
Naga Harish K S V 2022-09-14 10:33:17 -05:00 committed by Jerin Jacob
parent f089d62895
commit 3d9d8adf8c
8 changed files with 121 additions and 49 deletions

View File

@ -386,11 +386,22 @@ timdev_setup_msec(void)
static int
timdev_setup_msec_periodic(void)
{
uint32_t caps = 0;
uint64_t max_tmo_ns;
uint64_t flags = RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES |
RTE_EVENT_TIMER_ADAPTER_F_PERIODIC;
TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
"failed to get adapter capabilities");
if (caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)
max_tmo_ns = 0;
else
max_tmo_ns = 180 * NSECPERSEC;
/* Periodic mode with 100 ms resolution */
return _timdev_setup(0, NSECPERSEC / 10, flags);
return _timdev_setup(max_tmo_ns, NSECPERSEC / 10, flags);
}
static int
@ -409,7 +420,7 @@ timdev_setup_sec_periodic(void)
RTE_EVENT_TIMER_ADAPTER_F_PERIODIC;
/* Periodic mode with 1 sec resolution */
return _timdev_setup(0, NSECPERSEC, flags);
return _timdev_setup(180 * NSECPERSEC, NSECPERSEC, flags);
}
static int
@ -561,12 +572,23 @@ test_timer_arm(void)
static inline int
test_timer_arm_periodic(void)
{
uint32_t caps = 0;
uint32_t timeout_count = 0;
TEST_ASSERT_SUCCESS(_arm_timers(1, MAX_TIMERS),
"Failed to arm timers");
/* With a resolution of 100ms and wait time of 1sec,
* there will be 10 * MAX_TIMERS periodic timer triggers.
*/
TEST_ASSERT_SUCCESS(_wait_timer_triggers(1, 10 * MAX_TIMERS, 0),
TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
"failed to get adapter capabilities");
if (caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)
timeout_count = 10;
else
timeout_count = 9;
TEST_ASSERT_SUCCESS(_wait_timer_triggers(1, timeout_count * MAX_TIMERS, 0),
"Timer triggered count doesn't match arm count");
return TEST_SUCCESS;
}
@ -649,12 +671,23 @@ test_timer_arm_burst(void)
static inline int
test_timer_arm_burst_periodic(void)
{
uint32_t caps = 0;
uint32_t timeout_count = 0;
TEST_ASSERT_SUCCESS(_arm_timers_burst(1, MAX_TIMERS),
"Failed to arm timers");
/* With a resolution of 100ms and wait time of 1sec,
* there will be 10 * MAX_TIMERS periodic timer triggers.
*/
TEST_ASSERT_SUCCESS(_wait_timer_triggers(1, 10 * MAX_TIMERS, 0),
TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
"failed to get adapter capabilities");
if (caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)
timeout_count = 10;
else
timeout_count = 9;
TEST_ASSERT_SUCCESS(_wait_timer_triggers(1, timeout_count * MAX_TIMERS, 0),
"Timer triggered count doesn't match arm count");
return TEST_SUCCESS;

View File

@ -162,13 +162,6 @@ Deprecation Notices
Event will be one of the configuration fields,
together with additional vector parameters.
* eventdev: The structure ``rte_event_timer_adapter_stats`` will be
extended by adding a new field ``evtim_drop_count``.
This counter will represent the number of times an event_timer expiry event
is dropped by the timer adapter.
This field will be used to add periodic mode support
to the software timer adapter in DPDK 22.11.
* eventdev: The function pointer declaration ``eventdev_stop_flush_t``
will be renamed to ``rte_eventdev_stop_flush_t`` in DPDK 22.11.

View File

@ -234,6 +234,9 @@ ABI Changes
* ethdev: enum ``RTE_FLOW_ACTION`` was affected by deprecation procedure.
* eventdev: Added ``evtim_drop_count`` field
to ``rte_event_timer_adapter_stats`` structure.
Known Issues
------------

View File

@ -565,7 +565,7 @@ sw_timer_adapter_caps_get(const struct rte_eventdev *dev, uint64_t flags,
{
RTE_SET_USED(dev);
RTE_SET_USED(flags);
*caps = 0;
*caps = RTE_EVENT_TIMER_ADAPTER_SW_CAP;
/* Use default SW ops */
*ops = NULL;

View File

@ -81,6 +81,9 @@ extern "C" {
* the ethdev to eventdev use a SW service function
*/
#define RTE_EVENT_TIMER_ADAPTER_SW_CAP \
RTE_EVENT_TIMER_ADAPTER_CAP_PERIODIC
#define RTE_EVENTDEV_DETACHED (0)
#define RTE_EVENTDEV_ATTACHED (1)

View File

@ -55,6 +55,14 @@ static const struct event_timer_adapter_ops swtim_ops;
#define EVTIM_SVC_LOG_DBG(...) (void)0
#endif
static inline enum rte_timer_type
get_timer_type(const struct rte_event_timer_adapter *adapter)
{
return (adapter->data->conf.flags &
RTE_EVENT_TIMER_ADAPTER_F_PERIODIC) ?
PERIODICAL : SINGLE;
}
static int
default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
void *conf_arg)
@ -197,13 +205,14 @@ rte_event_timer_adapter_create_ext(
adapter->data->conf = *conf; /* copy conf structure */
/* Query eventdev PMD for timer adapter capabilities and ops */
ret = dev->dev_ops->timer_adapter_caps_get(dev,
adapter->data->conf.flags,
&adapter->data->caps,
&adapter->ops);
if (ret < 0) {
rte_errno = -ret;
goto free_memzone;
if (dev->dev_ops->timer_adapter_caps_get) {
ret = dev->dev_ops->timer_adapter_caps_get(dev,
adapter->data->conf.flags,
&adapter->data->caps, &adapter->ops);
if (ret < 0) {
rte_errno = -ret;
goto free_memzone;
}
}
if (!(adapter->data->caps &
@ -350,13 +359,14 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
dev = &rte_eventdevs[adapter->data->event_dev_id];
/* Query eventdev PMD for timer adapter capabilities and ops */
ret = dev->dev_ops->timer_adapter_caps_get(dev,
adapter->data->conf.flags,
&adapter->data->caps,
&adapter->ops);
if (ret < 0) {
rte_errno = EINVAL;
return NULL;
if (dev->dev_ops->timer_adapter_caps_get) {
ret = dev->dev_ops->timer_adapter_caps_get(dev,
adapter->data->conf.flags,
&adapter->data->caps, &adapter->ops);
if (ret < 0) {
rte_errno = EINVAL;
return NULL;
}
}
/* If eventdev PMD did not provide ops, use default software
@ -614,35 +624,44 @@ swtim_callback(struct rte_timer *tim)
uint64_t opaque;
int ret;
int n_lcores;
enum rte_timer_type type;
opaque = evtim->impl_opaque[1];
adapter = (struct rte_event_timer_adapter *)(uintptr_t)opaque;
sw = swtim_pmd_priv(adapter);
type = get_timer_type(adapter);
if (unlikely(sw->in_use[lcore].v == 0)) {
sw->in_use[lcore].v = 1;
n_lcores = __atomic_fetch_add(&sw->n_poll_lcores, 1,
__ATOMIC_RELAXED);
__atomic_store_n(&sw->poll_lcores[n_lcores], lcore,
__ATOMIC_RELAXED);
}
ret = event_buffer_add(&sw->buffer, &evtim->ev);
if (ret < 0) {
/* If event buffer is full, put timer back in list with
* immediate expiry value, so that we process it again on the
* next iteration.
*/
ret = rte_timer_alt_reset(sw->timer_data_id, tim, 0, SINGLE,
lcore, NULL, evtim);
if (ret < 0) {
EVTIM_LOG_DBG("event buffer full, failed to reset "
"timer with immediate expiry value");
if (type == SINGLE) {
/* If event buffer is full, put timer back in list with
* immediate expiry value, so that we process it again
* on the next iteration.
*/
ret = rte_timer_alt_reset(sw->timer_data_id, tim, 0,
SINGLE, lcore, NULL, evtim);
if (ret < 0) {
EVTIM_LOG_DBG("event buffer full, failed to "
"reset timer with immediate "
"expiry value");
} else {
sw->stats.evtim_retry_count++;
EVTIM_LOG_DBG("event buffer full, resetting "
"rte_timer with immediate "
"expiry value");
}
} else {
sw->stats.evtim_retry_count++;
EVTIM_LOG_DBG("event buffer full, resetting rte_timer "
"with immediate expiry value");
sw->stats.evtim_drop_count++;
}
if (unlikely(sw->in_use[lcore].v == 0)) {
sw->in_use[lcore].v = 1;
n_lcores = __atomic_fetch_add(&sw->n_poll_lcores, 1,
__ATOMIC_RELAXED);
__atomic_store_n(&sw->poll_lcores[n_lcores], lcore,
__ATOMIC_RELAXED);
}
} else {
EVTIM_BUF_LOG_DBG("buffered an event timer expiry event");
@ -656,10 +675,15 @@ swtim_callback(struct rte_timer *tim)
sw->n_expired_timers = 0;
}
sw->expired_timers[sw->n_expired_timers++] = tim;
/* Don't free rte_timer for a periodic event timer until
* it is cancelled
*/
if (type == SINGLE)
sw->expired_timers[sw->n_expired_timers++] = tim;
sw->stats.evtim_exp_count++;
__atomic_store_n(&evtim->state, RTE_EVENT_TIMER_NOT_ARMED,
if (type == SINGLE)
__atomic_store_n(&evtim->state, RTE_EVENT_TIMER_NOT_ARMED,
__ATOMIC_RELEASE);
}
@ -949,6 +973,12 @@ swtim_uninit(struct rte_event_timer_adapter *adapter)
swtim_free_tim,
sw);
ret = rte_timer_data_dealloc(sw->timer_data_id);
if (ret < 0) {
EVTIM_LOG_ERR("failed to deallocate timer data instance");
return ret;
}
ret = rte_service_component_unregister(sw->service_id);
if (ret < 0) {
EVTIM_LOG_ERR("failed to unregister service component");
@ -1055,6 +1085,7 @@ __swtim_arm_burst(const struct rte_event_timer_adapter *adapter,
/* Timer list for this lcore is not in use. */
uint16_t exp_state = 0;
enum rte_event_timer_state n_state;
enum rte_timer_type type = SINGLE;
#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
/* Check that the service is running. */
@ -1094,6 +1125,9 @@ __swtim_arm_burst(const struct rte_event_timer_adapter *adapter,
return 0;
}
/* update timer type for periodic adapter */
type = get_timer_type(adapter);
for (i = 0; i < nb_evtims; i++) {
n_state = __atomic_load_n(&evtims[i]->state, __ATOMIC_ACQUIRE);
if (n_state == RTE_EVENT_TIMER_ARMED) {
@ -1137,7 +1171,7 @@ __swtim_arm_burst(const struct rte_event_timer_adapter *adapter,
cycles = get_timeout_cycles(evtims[i], adapter);
ret = rte_timer_alt_reset(sw->timer_data_id, tim, cycles,
SINGLE, lcore_id, NULL, evtims[i]);
type, lcore_id, NULL, evtims[i]);
if (ret < 0) {
/* tim was in RUNNING or CONFIG state */
__atomic_store_n(&evtims[i]->state,

View File

@ -193,6 +193,8 @@ struct rte_event_timer_adapter_stats {
/**< Event timer retry count */
uint64_t adapter_tick_count;
/**< Tick count for the adapter, at its resolution */
uint64_t evtim_drop_count;
/**< event timer expiries dropped */
};
struct rte_event_timer_adapter;

View File

@ -140,7 +140,11 @@ rte_event_timer_adapter_caps_get(uint8_t dev_id, uint32_t *caps)
if (caps == NULL)
return -EINVAL;
*caps = 0;
if (dev->dev_ops->timer_adapter_caps_get == NULL)
*caps = RTE_EVENT_TIMER_ADAPTER_SW_CAP;
else
*caps = 0;
return dev->dev_ops->timer_adapter_caps_get ?
(*dev->dev_ops->timer_adapter_caps_get)(dev,