eventdev/timer: add API to get remaining ticks

Message ID 20221216215615.2158238-1-erik.g.carrillo@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Jerin Jacob
Headers
Series eventdev/timer: add API to get remaining ticks |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing success Unit Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-aarch64-unit-testing success Testing PASS
ci/Intel-compilation success Compilation OK
ci/iol-intel-Performance success Performance Testing PASS
ci/github-robot: build success github build: passed
ci/intel-Testing success Testing PASS
ci/iol-x86_64-compile-testing success Testing PASS
ci/iol-aarch64-compile-testing success Testing PASS
ci/iol-testing success Testing PASS
ci/iol-x86_64-unit-testing success Testing PASS

Commit Message

Carrillo, Erik G Dec. 16, 2022, 9:56 p.m. UTC
  Introduce an event timer adapter API which allows users to determine how
many adapter ticks remain until an event timer fires.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 app/test/test_event_timer_adapter.c    | 68 ++++++++++++++++++++++++++
 lib/eventdev/event_timer_adapter_pmd.h |  7 +++
 lib/eventdev/rte_event_timer_adapter.c | 52 ++++++++++++++++++++
 lib/eventdev/rte_event_timer_adapter.h | 27 ++++++++++
 lib/eventdev/version.map               |  3 ++
 5 files changed, 157 insertions(+)
  

Comments

Mattias Rönnblom Dec. 17, 2022, 9:21 a.m. UTC | #1
On 2022-12-16 22:56, Erik Gabriel Carrillo wrote:
> Introduce an event timer adapter API which allows users to determine how
> many adapter ticks remain until an event timer fires.
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>   app/test/test_event_timer_adapter.c    | 68 ++++++++++++++++++++++++++
>   lib/eventdev/event_timer_adapter_pmd.h |  7 +++
>   lib/eventdev/rte_event_timer_adapter.c | 52 ++++++++++++++++++++
>   lib/eventdev/rte_event_timer_adapter.h | 27 ++++++++++
>   lib/eventdev/version.map               |  3 ++
>   5 files changed, 157 insertions(+)
> 
> diff --git a/app/test/test_event_timer_adapter.c b/app/test/test_event_timer_adapter.c
> index 1a440dfd10..6529b14ff9 100644
> --- a/app/test/test_event_timer_adapter.c
> +++ b/app/test/test_event_timer_adapter.c
> @@ -1920,6 +1920,72 @@ adapter_create_max(void)
>   	return TEST_SUCCESS;
>   }
>   
> +static inline int
> +test_timer_ticks_remaining(void)
> +{
> +	uint64_t ticks_remaining = UINT64_MAX;
> +	struct rte_event_timer *ev_tim;
> +	struct rte_event ev;
> +	int ret, i;
> +	const struct rte_event_timer tim = {
> +		.ev.op = RTE_EVENT_OP_NEW,
> +		.ev.queue_id = 0,
> +		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
> +		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
> +		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
> +		.state = RTE_EVENT_TIMER_NOT_ARMED,
> +	};
> +
> +	rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
> +	*ev_tim = tim;
> +	ev_tim->ev.event_ptr = ev_tim;
> +#define TEST_TICKS 5
> +	ev_tim->timeout_ticks = CALC_TICKS(TEST_TICKS);
> +
> +	/* Test that unarmed timer returns error */
> +	TEST_ASSERT_FAIL(rte_event_timer_ticks_remaining_get(timdev, ev_tim,
> +							     &ticks_remaining),
> +			 "Didn't fail to get ticks for unarmed event timer");
> +
> +	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
> +			  "Failed to arm timer with proper timeout.");
> +	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
> +			  "Improper timer state set expected %d returned %d",
> +			  RTE_EVENT_TIMER_ARMED, ev_tim->state);
> +
> +	for (i = 0; i < TEST_TICKS; i++) {
> +		ret = rte_event_timer_ticks_remaining_get(timdev, ev_tim,
> +							  &ticks_remaining);
> +		if (ret < 0)
> +			return TEST_FAILED;
> +
> +		TEST_ASSERT_EQUAL((int)ticks_remaining, TEST_TICKS - i,
> +				  "Expected %d ticks remaining, got %"PRIu64"",
> +				  TEST_TICKS - i, ticks_remaining);
> +
> +		rte_delay_ms(100);
> +	}
> +
> +	rte_delay_ms(100);
> +
> +	TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
> +			  "Armed timer failed to trigger.");
> +	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_NOT_ARMED,
> +			  "Improper timer state set expected %d returned %d",
> +			  RTE_EVENT_TIMER_NOT_ARMED, ev_tim->state);
> +
> +	/* Test that timer that fired returns error */
> +	TEST_ASSERT_FAIL(rte_event_timer_ticks_remaining_get(timdev, ev_tim,
> +							   &ticks_remaining),
> +			 "Didn't fail to get ticks for unarmed event timer");
> +
> +	rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
> +
> +#undef TEST_TICKS
> +	return TEST_SUCCESS;
> +}
> +
> +
>   static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
>   	.suite_name = "event timer functional test suite",
>   	.setup = testsuite_setup,
> @@ -1982,6 +2048,8 @@ static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
>   		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
>   				adapter_tick_resolution),
>   		TEST_CASE(adapter_create_max),
> +		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
> +				test_timer_ticks_remaining),
>   		TEST_CASES_END() /**< NULL terminate unit test array */
>   	}
>   };
> diff --git a/lib/eventdev/event_timer_adapter_pmd.h b/lib/eventdev/event_timer_adapter_pmd.h
> index 189017b5c1..c19ff3576a 100644
> --- a/lib/eventdev/event_timer_adapter_pmd.h
> +++ b/lib/eventdev/event_timer_adapter_pmd.h
> @@ -52,6 +52,11 @@ typedef int (*rte_event_timer_adapter_stats_get_t)(
>   typedef int (*rte_event_timer_adapter_stats_reset_t)(
>   		const struct rte_event_timer_adapter *adapter);
>   /**< @internal Reset statistics for event timer adapter */
> +typedef int (*rte_event_timer_ticks_remaining_get_t)(
> +		const struct rte_event_timer_adapter *adapter,
> +		const struct rte_event_timer *evtim,
> +		uint64_t *ticks_remaining);
> +/**< @internal Get remaining ticks for event timer */
>   
>   /**
>    * @internal Structure containing the functions exported by an event timer
> @@ -74,6 +79,8 @@ struct event_timer_adapter_ops {
>   	/**< Arm event timers with same expiration time */
>   	rte_event_timer_cancel_burst_t		cancel_burst;
>   	/**< Cancel one or more event timers */
> +	rte_event_timer_ticks_remaining_get_t	ticks_remaining_get;
> +	/**< Get remaining ticks for event timer */
>   };
>   
>   /**
> diff --git a/lib/eventdev/rte_event_timer_adapter.c b/lib/eventdev/rte_event_timer_adapter.c
> index a0f14bf861..e2542e985c 100644
> --- a/lib/eventdev/rte_event_timer_adapter.c
> +++ b/lib/eventdev/rte_event_timer_adapter.c
> @@ -8,6 +8,7 @@
>   #include <inttypes.h>
>   #include <stdbool.h>
>   #include <stdlib.h>
> +#include <math.h>
>   
>   #include <rte_memzone.h>
>   #include <rte_errno.h>
> @@ -458,6 +459,21 @@ rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
>   	return adapter->ops->stats_reset(adapter);
>   }
>   
> +int
> +rte_event_timer_ticks_remaining_get(

I think the general pattern is
<class>[<"sub-class">]_get_<attribute>

rte_event_timer_get_remaining_ticks()

> +			const struct rte_event_timer_adapter *adapter,
> +			const struct rte_event_timer *evtim,
> +			uint64_t *ticks_remaining)
> +{
> +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> +	FUNC_PTR_OR_ERR_RET(adapter->ops->ticks_remaining_get, -ENOTSUP);
> +
> +	if (ticks_remaining == NULL)
> +		return -EINVAL;

Why is this not an RTE_ASSERT()?

Passing NULL is an API violation, likely due to a programming error.

> +
> +	return adapter->ops->ticks_remaining_get(adapter, evtim, ticks_remaining);
> +}
> +
>   /*
>    * Software event timer adapter buffer helper functions
>    */
> @@ -1072,6 +1088,41 @@ swtim_stats_reset(const struct rte_event_timer_adapter *adapter)
>   	return 0;
>   }
>   
> +static int
> +swtim_ticks_remaining_get(const struct rte_event_timer_adapter *adapter,
> +			  const struct rte_event_timer *evtim,
> +			  uint64_t *ticks_remaining)
> +{
> +	uint64_t nsecs_per_adapter_tick, opaque, cycles_remaining;
> +	enum rte_event_timer_state n_state;
> +	double nsecs_per_cycle;
> +	struct rte_timer *tim;
> +	uint64_t cur_cycles;
> +
> +	/* Check that timer is armed */
> +	n_state = __atomic_load_n(&evtim->state, __ATOMIC_ACQUIRE);
> +	if (n_state != RTE_EVENT_TIMER_ARMED)
> +		return -EINVAL;
> +
> +	opaque = evtim->impl_opaque[0];
> +	tim = (struct rte_timer *)(uintptr_t)opaque;
> +
> +	cur_cycles = rte_get_timer_cycles();
> +	if (cur_cycles > tim->expire) {
> +		*ticks_remaining = 0;
> +		return 0;
> +	}
> +
> +	cycles_remaining = tim->expire - cur_cycles;
> +	nsecs_per_cycle = (double)NSECPERSEC / rte_get_timer_hz();
> +	nsecs_per_adapter_tick = adapter->data->conf.timer_tick_ns;
> +
> +	*ticks_remaining = (uint64_t)ceil((cycles_remaining * nsecs_per_cycle) /
> +					  nsecs_per_adapter_tick);
> +
> +	return 0;
> +}
> +
>   static uint16_t
>   __swtim_arm_burst(const struct rte_event_timer_adapter *adapter,
>   		struct rte_event_timer **evtims,
> @@ -1286,6 +1337,7 @@ static const struct event_timer_adapter_ops swtim_ops = {
>   	.arm_burst = swtim_arm_burst,
>   	.arm_tmo_tick_burst = swtim_arm_tmo_tick_burst,
>   	.cancel_burst = swtim_cancel_burst,
> +	.ticks_remaining_get = swtim_ticks_remaining_get,
>   };
>   
>   static int
> diff --git a/lib/eventdev/rte_event_timer_adapter.h b/lib/eventdev/rte_event_timer_adapter.h
> index cd10db19e4..b05d9b400d 100644
> --- a/lib/eventdev/rte_event_timer_adapter.h
> +++ b/lib/eventdev/rte_event_timer_adapter.h
> @@ -678,6 +678,33 @@ rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
>   	return adapter->cancel_burst(adapter, evtims, nb_evtims);
>   }
>   
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice
> + *
> + * Get the number of ticks remaining until an event timer fires.
> + *
> + * @param adapter
> + *   A pointer to an event timer adapter structure
> + * @param evtim
> + *   A pointer to an rte_event_timer structure
> + * @param[out] ticks_remaining
> + *   Pointer to variable into which to write the number of ticks remaining
> + *   until the event timer fires
> + *
> + * @return
> + *   - 0: Success
> + *   - -EINVAL Invalid timer adapter identifier, ticks_remaining pointer is
> + *   NULL, or the event timer is not in the armed state
> + *   - -ENOTSUP The timer adapter implementation does not support this API.
> + */
> +__rte_experimental
> +int
> +rte_event_timer_ticks_remaining_get(
> +			const struct rte_event_timer_adapter *adapter,
> +			const struct rte_event_timer *evtim,
> +			uint64_t *ticks_remaining);
> +
>   #ifdef __cplusplus
>   }
>   #endif
> diff --git a/lib/eventdev/version.map b/lib/eventdev/version.map
> index dd63ec6f68..2a46fd27dc 100644
> --- a/lib/eventdev/version.map
> +++ b/lib/eventdev/version.map
> @@ -118,6 +118,9 @@ EXPERIMENTAL {
>   	rte_event_eth_tx_adapter_instance_get;
>   	rte_event_eth_tx_adapter_queue_start;
>   	rte_event_eth_tx_adapter_queue_stop;
> +
> +	# added in 23.03
> +	rte_event_timer_ticks_remaining_get;
>   };
>   
>   INTERNAL {
  
Carrillo, Erik G Dec. 17, 2022, 8:15 p.m. UTC | #2
> -----Original Message-----
> From: Mattias Rönnblom <hofors@lysator.liu.se>
> Sent: Saturday, December 17, 2022 3:22 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>; jerinj@marvell.com
> Cc: Naga Harish K, S V <s.v.naga.harish.k@intel.com>; Jayatheerthan, Jay
> <jay.jayatheerthan@intel.com>; pbhagavatula@marvell.com;
> sthotton@marvell.com; dev@dpdk.org
> Subject: Re: [PATCH] eventdev/timer: add API to get remaining ticks
> 
> On 2022-12-16 22:56, Erik Gabriel Carrillo wrote:
> > Introduce an event timer adapter API which allows users to determine
> > how many adapter ticks remain until an event timer fires.
> >
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > ---
> >   app/test/test_event_timer_adapter.c    | 68
> ++++++++++++++++++++++++++
> >   lib/eventdev/event_timer_adapter_pmd.h |  7 +++
> >   lib/eventdev/rte_event_timer_adapter.c | 52 ++++++++++++++++++++
> >   lib/eventdev/rte_event_timer_adapter.h | 27 ++++++++++
> >   lib/eventdev/version.map               |  3 ++
> >   5 files changed, 157 insertions(+)
> >
> > diff --git a/app/test/test_event_timer_adapter.c
> > b/app/test/test_event_timer_adapter.c
> > index 1a440dfd10..6529b14ff9 100644
> > --- a/app/test/test_event_timer_adapter.c
> > +++ b/app/test/test_event_timer_adapter.c
> > @@ -1920,6 +1920,72 @@ adapter_create_max(void)
> >   	return TEST_SUCCESS;
> >   }
> >
> > +static inline int
> > +test_timer_ticks_remaining(void)
> > +{
> > +	uint64_t ticks_remaining = UINT64_MAX;
> > +	struct rte_event_timer *ev_tim;
> > +	struct rte_event ev;
> > +	int ret, i;
> > +	const struct rte_event_timer tim = {
> > +		.ev.op = RTE_EVENT_OP_NEW,
> > +		.ev.queue_id = 0,
> > +		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
> > +		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
> > +		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
> > +		.state = RTE_EVENT_TIMER_NOT_ARMED,
> > +	};
> > +
> > +	rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
> > +	*ev_tim = tim;
> > +	ev_tim->ev.event_ptr = ev_tim;
> > +#define TEST_TICKS 5
> > +	ev_tim->timeout_ticks = CALC_TICKS(TEST_TICKS);
> > +
> > +	/* Test that unarmed timer returns error */
> > +	TEST_ASSERT_FAIL(rte_event_timer_ticks_remaining_get(timdev,
> ev_tim,
> > +							     &ticks_remaining),
> > +			 "Didn't fail to get ticks for unarmed event timer");
> > +
> > +	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev,
> &ev_tim, 1), 1,
> > +			  "Failed to arm timer with proper timeout.");
> > +	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
> > +			  "Improper timer state set expected %d returned
> %d",
> > +			  RTE_EVENT_TIMER_ARMED, ev_tim->state);
> > +
> > +	for (i = 0; i < TEST_TICKS; i++) {
> > +		ret = rte_event_timer_ticks_remaining_get(timdev, ev_tim,
> > +							  &ticks_remaining);
> > +		if (ret < 0)
> > +			return TEST_FAILED;
> > +
> > +		TEST_ASSERT_EQUAL((int)ticks_remaining, TEST_TICKS - i,
> > +				  "Expected %d ticks remaining, got
> %"PRIu64"",
> > +				  TEST_TICKS - i, ticks_remaining);
> > +
> > +		rte_delay_ms(100);
> > +	}
> > +
> > +	rte_delay_ms(100);
> > +
> > +	TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1,
> 0), 1,
> > +			  "Armed timer failed to trigger.");
> > +	TEST_ASSERT_EQUAL(ev_tim->state,
> RTE_EVENT_TIMER_NOT_ARMED,
> > +			  "Improper timer state set expected %d returned
> %d",
> > +			  RTE_EVENT_TIMER_NOT_ARMED, ev_tim->state);
> > +
> > +	/* Test that timer that fired returns error */
> > +	TEST_ASSERT_FAIL(rte_event_timer_ticks_remaining_get(timdev,
> ev_tim,
> > +							   &ticks_remaining),
> > +			 "Didn't fail to get ticks for unarmed event timer");
> > +
> > +	rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
> > +
> > +#undef TEST_TICKS
> > +	return TEST_SUCCESS;
> > +}
> > +
> > +
> >   static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
> >   	.suite_name = "event timer functional test suite",
> >   	.setup = testsuite_setup,
> > @@ -1982,6 +2048,8 @@ static struct unit_test_suite
> event_timer_adptr_functional_testsuite  = {
> >   		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
> >   				adapter_tick_resolution),
> >   		TEST_CASE(adapter_create_max),
> > +		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
> > +				test_timer_ticks_remaining),
> >   		TEST_CASES_END() /**< NULL terminate unit test array */
> >   	}
> >   };
> > diff --git a/lib/eventdev/event_timer_adapter_pmd.h
> > b/lib/eventdev/event_timer_adapter_pmd.h
> > index 189017b5c1..c19ff3576a 100644
> > --- a/lib/eventdev/event_timer_adapter_pmd.h
> > +++ b/lib/eventdev/event_timer_adapter_pmd.h
> > @@ -52,6 +52,11 @@ typedef int
> (*rte_event_timer_adapter_stats_get_t)(
> >   typedef int (*rte_event_timer_adapter_stats_reset_t)(
> >   		const struct rte_event_timer_adapter *adapter);
> >   /**< @internal Reset statistics for event timer adapter */
> > +typedef int (*rte_event_timer_ticks_remaining_get_t)(
> > +		const struct rte_event_timer_adapter *adapter,
> > +		const struct rte_event_timer *evtim,
> > +		uint64_t *ticks_remaining);
> > +/**< @internal Get remaining ticks for event timer */
> >
> >   /**
> >    * @internal Structure containing the functions exported by an event
> > timer @@ -74,6 +79,8 @@ struct event_timer_adapter_ops {
> >   	/**< Arm event timers with same expiration time */
> >   	rte_event_timer_cancel_burst_t		cancel_burst;
> >   	/**< Cancel one or more event timers */
> > +	rte_event_timer_ticks_remaining_get_t	ticks_remaining_get;
> > +	/**< Get remaining ticks for event timer */
> >   };
> >
> >   /**
> > diff --git a/lib/eventdev/rte_event_timer_adapter.c
> > b/lib/eventdev/rte_event_timer_adapter.c
> > index a0f14bf861..e2542e985c 100644
> > --- a/lib/eventdev/rte_event_timer_adapter.c
> > +++ b/lib/eventdev/rte_event_timer_adapter.c
> > @@ -8,6 +8,7 @@
> >   #include <inttypes.h>
> >   #include <stdbool.h>
> >   #include <stdlib.h>
> > +#include <math.h>
> >
> >   #include <rte_memzone.h>
> >   #include <rte_errno.h>
> > @@ -458,6 +459,21 @@ rte_event_timer_adapter_stats_reset(struct
> rte_event_timer_adapter *adapter)
> >   	return adapter->ops->stats_reset(adapter);
> >   }
> >
> > +int
> > +rte_event_timer_ticks_remaining_get(
> 
> I think the general pattern is
> <class>[<"sub-class">]_get_<attribute>
> 
> rte_event_timer_get_remaining_ticks()
> 
> > +			const struct rte_event_timer_adapter *adapter,
> > +			const struct rte_event_timer *evtim,
> > +			uint64_t *ticks_remaining)
> > +{
> > +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> > +	FUNC_PTR_OR_ERR_RET(adapter->ops->ticks_remaining_get, -
> ENOTSUP);
> > +
> > +	if (ticks_remaining == NULL)
> > +		return -EINVAL;
> 
> Why is this not an RTE_ASSERT()?
> 
> Passing NULL is an API violation, likely due to a programming error.
> 

Good points - I'll make this and the name change in v2.

> > +
> > +	return adapter->ops->ticks_remaining_get(adapter, evtim,
> > +ticks_remaining); }
> > +
> >   /*
> >    * Software event timer adapter buffer helper functions
> >    */
> > @@ -1072,6 +1088,41 @@ swtim_stats_reset(const struct
> rte_event_timer_adapter *adapter)
> >   	return 0;
> >   }
> >
> > +static int
> > +swtim_ticks_remaining_get(const struct rte_event_timer_adapter
> *adapter,
> > +			  const struct rte_event_timer *evtim,
> > +			  uint64_t *ticks_remaining)
> > +{
> > +	uint64_t nsecs_per_adapter_tick, opaque, cycles_remaining;
> > +	enum rte_event_timer_state n_state;
> > +	double nsecs_per_cycle;
> > +	struct rte_timer *tim;
> > +	uint64_t cur_cycles;
> > +
> > +	/* Check that timer is armed */
> > +	n_state = __atomic_load_n(&evtim->state, __ATOMIC_ACQUIRE);
> > +	if (n_state != RTE_EVENT_TIMER_ARMED)
> > +		return -EINVAL;
> > +
> > +	opaque = evtim->impl_opaque[0];
> > +	tim = (struct rte_timer *)(uintptr_t)opaque;
> > +
> > +	cur_cycles = rte_get_timer_cycles();
> > +	if (cur_cycles > tim->expire) {
> > +		*ticks_remaining = 0;
> > +		return 0;
> > +	}
> > +
> > +	cycles_remaining = tim->expire - cur_cycles;
> > +	nsecs_per_cycle = (double)NSECPERSEC / rte_get_timer_hz();
> > +	nsecs_per_adapter_tick = adapter->data->conf.timer_tick_ns;
> > +
> > +	*ticks_remaining = (uint64_t)ceil((cycles_remaining *
> nsecs_per_cycle) /
> > +					  nsecs_per_adapter_tick);
> > +
> > +	return 0;
> > +}
> > +
> >   static uint16_t
> >   __swtim_arm_burst(const struct rte_event_timer_adapter *adapter,
> >   		struct rte_event_timer **evtims,
> > @@ -1286,6 +1337,7 @@ static const struct event_timer_adapter_ops
> swtim_ops = {
> >   	.arm_burst = swtim_arm_burst,
> >   	.arm_tmo_tick_burst = swtim_arm_tmo_tick_burst,
> >   	.cancel_burst = swtim_cancel_burst,
> > +	.ticks_remaining_get = swtim_ticks_remaining_get,
> >   };
> >
> >   static int
> > diff --git a/lib/eventdev/rte_event_timer_adapter.h
> > b/lib/eventdev/rte_event_timer_adapter.h
> > index cd10db19e4..b05d9b400d 100644
> > --- a/lib/eventdev/rte_event_timer_adapter.h
> > +++ b/lib/eventdev/rte_event_timer_adapter.h
> > @@ -678,6 +678,33 @@ rte_event_timer_cancel_burst(const struct
> rte_event_timer_adapter *adapter,
> >   	return adapter->cancel_burst(adapter, evtims, nb_evtims);
> >   }
> >
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change without prior notice
> > + *
> > + * Get the number of ticks remaining until an event timer fires.
> > + *
> > + * @param adapter
> > + *   A pointer to an event timer adapter structure
> > + * @param evtim
> > + *   A pointer to an rte_event_timer structure
> > + * @param[out] ticks_remaining
> > + *   Pointer to variable into which to write the number of ticks remaining
> > + *   until the event timer fires
> > + *
> > + * @return
> > + *   - 0: Success
> > + *   - -EINVAL Invalid timer adapter identifier, ticks_remaining pointer is
> > + *   NULL, or the event timer is not in the armed state
> > + *   - -ENOTSUP The timer adapter implementation does not support this
> API.
> > + */
> > +__rte_experimental
> > +int
> > +rte_event_timer_ticks_remaining_get(
> > +			const struct rte_event_timer_adapter *adapter,
> > +			const struct rte_event_timer *evtim,
> > +			uint64_t *ticks_remaining);
> > +
> >   #ifdef __cplusplus
> >   }
> >   #endif
> > diff --git a/lib/eventdev/version.map b/lib/eventdev/version.map index
> > dd63ec6f68..2a46fd27dc 100644
> > --- a/lib/eventdev/version.map
> > +++ b/lib/eventdev/version.map
> > @@ -118,6 +118,9 @@ EXPERIMENTAL {
> >   	rte_event_eth_tx_adapter_instance_get;
> >   	rte_event_eth_tx_adapter_queue_start;
> >   	rte_event_eth_tx_adapter_queue_stop;
> > +
> > +	# added in 23.03
> > +	rte_event_timer_ticks_remaining_get;
> >   };
> >
> >   INTERNAL {
  

Patch

diff --git a/app/test/test_event_timer_adapter.c b/app/test/test_event_timer_adapter.c
index 1a440dfd10..6529b14ff9 100644
--- a/app/test/test_event_timer_adapter.c
+++ b/app/test/test_event_timer_adapter.c
@@ -1920,6 +1920,72 @@  adapter_create_max(void)
 	return TEST_SUCCESS;
 }
 
+static inline int
+test_timer_ticks_remaining(void)
+{
+	uint64_t ticks_remaining = UINT64_MAX;
+	struct rte_event_timer *ev_tim;
+	struct rte_event ev;
+	int ret, i;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
+	*ev_tim = tim;
+	ev_tim->ev.event_ptr = ev_tim;
+#define TEST_TICKS 5
+	ev_tim->timeout_ticks = CALC_TICKS(TEST_TICKS);
+
+	/* Test that unarmed timer returns error */
+	TEST_ASSERT_FAIL(rte_event_timer_ticks_remaining_get(timdev, ev_tim,
+							     &ticks_remaining),
+			 "Didn't fail to get ticks for unarmed event timer");
+
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+			  "Failed to arm timer with proper timeout.");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+			  "Improper timer state set expected %d returned %d",
+			  RTE_EVENT_TIMER_ARMED, ev_tim->state);
+
+	for (i = 0; i < TEST_TICKS; i++) {
+		ret = rte_event_timer_ticks_remaining_get(timdev, ev_tim,
+							  &ticks_remaining);
+		if (ret < 0)
+			return TEST_FAILED;
+
+		TEST_ASSERT_EQUAL((int)ticks_remaining, TEST_TICKS - i,
+				  "Expected %d ticks remaining, got %"PRIu64"",
+				  TEST_TICKS - i, ticks_remaining);
+
+		rte_delay_ms(100);
+	}
+
+	rte_delay_ms(100);
+
+	TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
+			  "Armed timer failed to trigger.");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_NOT_ARMED,
+			  "Improper timer state set expected %d returned %d",
+			  RTE_EVENT_TIMER_NOT_ARMED, ev_tim->state);
+
+	/* Test that timer that fired returns error */
+	TEST_ASSERT_FAIL(rte_event_timer_ticks_remaining_get(timdev, ev_tim,
+							   &ticks_remaining),
+			 "Didn't fail to get ticks for unarmed event timer");
+
+	rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+
+#undef TEST_TICKS
+	return TEST_SUCCESS;
+}
+
+
 static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
 	.suite_name = "event timer functional test suite",
 	.setup = testsuite_setup,
@@ -1982,6 +2048,8 @@  static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
 		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
 				adapter_tick_resolution),
 		TEST_CASE(adapter_create_max),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				test_timer_ticks_remaining),
 		TEST_CASES_END() /**< NULL terminate unit test array */
 	}
 };
diff --git a/lib/eventdev/event_timer_adapter_pmd.h b/lib/eventdev/event_timer_adapter_pmd.h
index 189017b5c1..c19ff3576a 100644
--- a/lib/eventdev/event_timer_adapter_pmd.h
+++ b/lib/eventdev/event_timer_adapter_pmd.h
@@ -52,6 +52,11 @@  typedef int (*rte_event_timer_adapter_stats_get_t)(
 typedef int (*rte_event_timer_adapter_stats_reset_t)(
 		const struct rte_event_timer_adapter *adapter);
 /**< @internal Reset statistics for event timer adapter */
+typedef int (*rte_event_timer_ticks_remaining_get_t)(
+		const struct rte_event_timer_adapter *adapter,
+		const struct rte_event_timer *evtim,
+		uint64_t *ticks_remaining);
+/**< @internal Get remaining ticks for event timer */
 
 /**
  * @internal Structure containing the functions exported by an event timer
@@ -74,6 +79,8 @@  struct event_timer_adapter_ops {
 	/**< Arm event timers with same expiration time */
 	rte_event_timer_cancel_burst_t		cancel_burst;
 	/**< Cancel one or more event timers */
+	rte_event_timer_ticks_remaining_get_t	ticks_remaining_get;
+	/**< Get remaining ticks for event timer */
 };
 
 /**
diff --git a/lib/eventdev/rte_event_timer_adapter.c b/lib/eventdev/rte_event_timer_adapter.c
index a0f14bf861..e2542e985c 100644
--- a/lib/eventdev/rte_event_timer_adapter.c
+++ b/lib/eventdev/rte_event_timer_adapter.c
@@ -8,6 +8,7 @@ 
 #include <inttypes.h>
 #include <stdbool.h>
 #include <stdlib.h>
+#include <math.h>
 
 #include <rte_memzone.h>
 #include <rte_errno.h>
@@ -458,6 +459,21 @@  rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
 	return adapter->ops->stats_reset(adapter);
 }
 
+int
+rte_event_timer_ticks_remaining_get(
+			const struct rte_event_timer_adapter *adapter,
+			const struct rte_event_timer *evtim,
+			uint64_t *ticks_remaining)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->ticks_remaining_get, -ENOTSUP);
+
+	if (ticks_remaining == NULL)
+		return -EINVAL;
+
+	return adapter->ops->ticks_remaining_get(adapter, evtim, ticks_remaining);
+}
+
 /*
  * Software event timer adapter buffer helper functions
  */
@@ -1072,6 +1088,41 @@  swtim_stats_reset(const struct rte_event_timer_adapter *adapter)
 	return 0;
 }
 
+static int
+swtim_ticks_remaining_get(const struct rte_event_timer_adapter *adapter,
+			  const struct rte_event_timer *evtim,
+			  uint64_t *ticks_remaining)
+{
+	uint64_t nsecs_per_adapter_tick, opaque, cycles_remaining;
+	enum rte_event_timer_state n_state;
+	double nsecs_per_cycle;
+	struct rte_timer *tim;
+	uint64_t cur_cycles;
+
+	/* Check that timer is armed */
+	n_state = __atomic_load_n(&evtim->state, __ATOMIC_ACQUIRE);
+	if (n_state != RTE_EVENT_TIMER_ARMED)
+		return -EINVAL;
+
+	opaque = evtim->impl_opaque[0];
+	tim = (struct rte_timer *)(uintptr_t)opaque;
+
+	cur_cycles = rte_get_timer_cycles();
+	if (cur_cycles > tim->expire) {
+		*ticks_remaining = 0;
+		return 0;
+	}
+
+	cycles_remaining = tim->expire - cur_cycles;
+	nsecs_per_cycle = (double)NSECPERSEC / rte_get_timer_hz();
+	nsecs_per_adapter_tick = adapter->data->conf.timer_tick_ns;
+
+	*ticks_remaining = (uint64_t)ceil((cycles_remaining * nsecs_per_cycle) /
+					  nsecs_per_adapter_tick);
+
+	return 0;
+}
+
 static uint16_t
 __swtim_arm_burst(const struct rte_event_timer_adapter *adapter,
 		struct rte_event_timer **evtims,
@@ -1286,6 +1337,7 @@  static const struct event_timer_adapter_ops swtim_ops = {
 	.arm_burst = swtim_arm_burst,
 	.arm_tmo_tick_burst = swtim_arm_tmo_tick_burst,
 	.cancel_burst = swtim_cancel_burst,
+	.ticks_remaining_get = swtim_ticks_remaining_get,
 };
 
 static int
diff --git a/lib/eventdev/rte_event_timer_adapter.h b/lib/eventdev/rte_event_timer_adapter.h
index cd10db19e4..b05d9b400d 100644
--- a/lib/eventdev/rte_event_timer_adapter.h
+++ b/lib/eventdev/rte_event_timer_adapter.h
@@ -678,6 +678,33 @@  rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
 	return adapter->cancel_burst(adapter, evtims, nb_evtims);
 }
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Get the number of ticks remaining until an event timer fires.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure
+ * @param evtim
+ *   A pointer to an rte_event_timer structure
+ * @param[out] ticks_remaining
+ *   Pointer to variable into which to write the number of ticks remaining
+ *   until the event timer fires
+ *
+ * @return
+ *   - 0: Success
+ *   - -EINVAL Invalid timer adapter identifier, ticks_remaining pointer is
+ *   NULL, or the event timer is not in the armed state
+ *   - -ENOTSUP The timer adapter implementation does not support this API.
+ */
+__rte_experimental
+int
+rte_event_timer_ticks_remaining_get(
+			const struct rte_event_timer_adapter *adapter,
+			const struct rte_event_timer *evtim,
+			uint64_t *ticks_remaining);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/eventdev/version.map b/lib/eventdev/version.map
index dd63ec6f68..2a46fd27dc 100644
--- a/lib/eventdev/version.map
+++ b/lib/eventdev/version.map
@@ -118,6 +118,9 @@  EXPERIMENTAL {
 	rte_event_eth_tx_adapter_instance_get;
 	rte_event_eth_tx_adapter_queue_start;
 	rte_event_eth_tx_adapter_queue_stop;
+
+	# added in 23.03
+	rte_event_timer_ticks_remaining_get;
 };
 
 INTERNAL {