Skip to content

Commit

Permalink
eventdev/timer: fix timeout event wait behavior
Browse files Browse the repository at this point in the history
[ upstream commit fb9c213317b5e07918c9306f2036f8cc07126a85 ]

Improved the accuracy and consistency of timeout event wait behavior by
refactoring it. Previously, the delay function used for waiting could be
inaccurate, leading to inconsistent results. This commit updates the
wait behavior to use a timeout-based approach, enabling the wait for the
exact number of timer ticks before proceeding.

The new function timeout_event_dequeue mimics the behavior of the tested
systems closely. It dequeues timer expiry events until either the
expected number of events have been dequeued or the specified time has
elapsed. The WAIT_TICKS macro defines the waiting behavior based on the
type of timer being used (software or hardware).

Fixes: d1f3385 ("test: add event timer adapter auto-test")

Signed-off-by: Shijith Thotton <sthotton@marvell.com>
Acked-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
  • Loading branch information
Shijith Thotton authored and kevintraynor committed Jul 11, 2023
1 parent e248dac commit 84d280e
Showing 1 changed file with 67 additions and 98 deletions.
165 changes: 67 additions & 98 deletions app/test/test_event_timer_adapter.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ static uint64_t global_bkt_tck_ns;
static uint64_t global_info_bkt_tck_ns;
static volatile uint8_t arm_done;

#define CALC_TICKS(tks) \
ceil((double)(tks * global_bkt_tck_ns) / global_info_bkt_tck_ns)
#define CALC_TICKS(tks) ceil((double)((tks) * global_bkt_tck_ns) / global_info_bkt_tck_ns)

/* Wait double timeout ticks for software and an extra tick for hardware */
#define WAIT_TICKS(tks) (using_services ? 2 * (tks) : tks + 1)

static bool using_services;
static uint32_t test_lcore1;
Expand Down Expand Up @@ -419,10 +420,31 @@ timdev_teardown(void)
rte_mempool_free(eventdev_test_mempool);
}

static inline uint16_t
timeout_event_dequeue(struct rte_event *evs, uint64_t nb_evs, uint64_t ticks)
{
uint16_t ev_cnt = 0;
uint64_t end_cycle;

if (using_services && nb_evs == MAX_TIMERS)
ticks = 2 * ticks;

end_cycle = rte_rdtsc() + ticks * global_bkt_tck_ns * rte_get_tsc_hz() / 1E9;

while (ev_cnt < nb_evs && rte_rdtsc() < end_cycle) {
ev_cnt += rte_event_dequeue_burst(evdev, TEST_PORT_ID, &evs[ev_cnt], nb_evs, 0);
rte_pause();
}

return ev_cnt;
}

static inline int
test_timer_state(void)
{
struct rte_event_timer *ev_tim;
const uint64_t max_ticks = 100;
uint64_t ticks, wait_ticks;
struct rte_event ev;
const struct rte_event_timer tim = {
.ev.op = RTE_EVENT_OP_NEW,
Expand All @@ -433,20 +455,20 @@ test_timer_state(void)
.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;
ev_tim->timeout_ticks = CALC_TICKS(120);
ev_tim->timeout_ticks = CALC_TICKS(max_ticks + 20);

TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 0,
"Armed timer exceeding max_timeout.");
TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ERROR_TOOLATE,
"Improper timer state set expected %d returned %d",
RTE_EVENT_TIMER_ERROR_TOOLATE, ev_tim->state);

ticks = 10;
ev_tim->state = RTE_EVENT_TIMER_NOT_ARMED;
ev_tim->timeout_ticks = CALC_TICKS(10);
ev_tim->timeout_ticks = CALC_TICKS(ticks);

TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
"Failed to arm timer with proper timeout.");
Expand All @@ -455,14 +477,15 @@ test_timer_state(void)
RTE_EVENT_TIMER_ARMED, ev_tim->state);

if (!using_services)
rte_delay_us(20);
wait_ticks = 2 * ticks;
else
rte_delay_us(1000 + 200);
TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
"Armed timer failed to trigger.");
wait_ticks = ticks;

TEST_ASSERT_EQUAL(timeout_event_dequeue(&ev, 1, WAIT_TICKS(wait_ticks)), 1,
"Armed timer failed to trigger.");

ev_tim->state = RTE_EVENT_TIMER_NOT_ARMED;
ev_tim->timeout_ticks = CALC_TICKS(90);
ev_tim->timeout_ticks = CALC_TICKS(max_ticks - 10);
TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
"Failed to arm timer with proper timeout.");
TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(timdev, &ev_tim, 1),
Expand Down Expand Up @@ -1164,16 +1187,17 @@ stat_inc_reset_ev_enq(void)
int ret, i, n;
int num_evtims = MAX_TIMERS;
struct rte_event_timer *evtims[num_evtims];
struct rte_event evs[BATCH_SIZE];
struct rte_event evs[num_evtims];
struct rte_event_timer_adapter_stats stats;
uint64_t ticks = 5;
const struct rte_event_timer init_tim = {
.ev.op = RTE_EVENT_OP_NEW,
.ev.queue_id = TEST_QUEUE_ID,
.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,
.timeout_ticks = CALC_TICKS(5), // expire in .5 sec
.timeout_ticks = CALC_TICKS(ticks), /**< expire in .5 sec */
};

ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
Expand All @@ -1198,31 +1222,12 @@ stat_inc_reset_ev_enq(void)
"succeeded = %d, rte_errno = %s",
num_evtims, ret, rte_strerror(rte_errno));

rte_delay_ms(1000);

#define MAX_TRIES num_evtims
int sum = 0;
int tries = 0;
bool done = false;
while (!done) {
sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
RTE_DIM(evs), 10);
if (sum >= num_evtims || ++tries >= MAX_TRIES)
done = true;

rte_delay_ms(10);
}

TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
"got %d", num_evtims, sum);

TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");

rte_delay_ms(100);
n = timeout_event_dequeue(evs, RTE_DIM(evs), WAIT_TICKS(ticks));
TEST_ASSERT_EQUAL(n, num_evtims, "Expected %d timer expiry events, got %d",
num_evtims, n);

/* Make sure the eventdev is still empty */
n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
10);
n = timeout_event_dequeue(evs, 1, WAIT_TICKS(1));

TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
"events from event device");
Expand Down Expand Up @@ -1259,14 +1264,15 @@ event_timer_arm(void)
struct rte_event_timer_adapter *adapter = timdev;
struct rte_event_timer *evtim = NULL;
struct rte_event evs[BATCH_SIZE];
uint64_t ticks = 5;
const struct rte_event_timer init_tim = {
.ev.op = RTE_EVENT_OP_NEW,
.ev.queue_id = TEST_QUEUE_ID,
.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,
.timeout_ticks = CALC_TICKS(5), // expire in .5 sec
.timeout_ticks = CALC_TICKS(ticks), /**< expire in .5 sec */
};

rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
Expand All @@ -1293,10 +1299,7 @@ event_timer_arm(void)
TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
"after arming already armed timer");

/* Let timer expire */
rte_delay_ms(1000);

n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
n = timeout_event_dequeue(evs, RTE_DIM(evs), WAIT_TICKS(ticks));
TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
"events from event device");

Expand All @@ -1316,14 +1319,15 @@ event_timer_arm_double(void)
struct rte_event_timer_adapter *adapter = timdev;
struct rte_event_timer *evtim = NULL;
struct rte_event evs[BATCH_SIZE];
uint64_t ticks = 5;
const struct rte_event_timer init_tim = {
.ev.op = RTE_EVENT_OP_NEW,
.ev.queue_id = TEST_QUEUE_ID,
.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,
.timeout_ticks = CALC_TICKS(5), // expire in .5 sec
.timeout_ticks = CALC_TICKS(ticks), /**< expire in .5 sec */
};

rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
Expand All @@ -1343,10 +1347,7 @@ event_timer_arm_double(void)
TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
"after double-arm");

/* Let timer expire */
rte_delay_ms(600);

n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
n = timeout_event_dequeue(evs, RTE_DIM(evs), WAIT_TICKS(ticks));
TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number of expiry events - "
"expected: 1, actual: %d", n);

Expand All @@ -1373,6 +1374,7 @@ event_timer_arm_expiry(void)
.ev.event_type = RTE_EVENT_TYPE_TIMER,
.state = RTE_EVENT_TIMER_NOT_ARMED,
};
uint64_t ticks = 30;

rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
if (evtim == NULL) {
Expand All @@ -1382,7 +1384,7 @@ event_timer_arm_expiry(void)

/* Set up an event timer */
*evtim = init_tim;
evtim->timeout_ticks = CALC_TICKS(30), // expire in 3 secs
evtim->timeout_ticks = CALC_TICKS(ticks); /**< expire in 3 secs */
evtim->ev.event_ptr = evtim;

ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
Expand All @@ -1391,17 +1393,10 @@ event_timer_arm_expiry(void)
TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event "
"timer in incorrect state");

rte_delay_ms(2999);

n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
n = timeout_event_dequeue(evs, RTE_DIM(evs), ticks - 1);
TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event");

/* Delay 100 ms to account for the adapter tick window - should let us
* dequeue one event
*/
rte_delay_ms(100);

n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
n = timeout_event_dequeue(evs, RTE_DIM(evs), WAIT_TICKS(1));
TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number (%d) of timer "
"expiry events", n);
TEST_ASSERT_EQUAL(evs[0].event_type, RTE_EVENT_TYPE_TIMER,
Expand Down Expand Up @@ -1433,6 +1428,7 @@ event_timer_arm_rearm(void)
.ev.event_type = RTE_EVENT_TYPE_TIMER,
.state = RTE_EVENT_TIMER_NOT_ARMED,
};
uint64_t ticks = 1;

rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
if (evtim == NULL) {
Expand All @@ -1442,18 +1438,15 @@ event_timer_arm_rearm(void)

/* Set up a timer */
*evtim = init_tim;
evtim->timeout_ticks = CALC_TICKS(1); // expire in 0.1 sec
evtim->timeout_ticks = CALC_TICKS(ticks); /**< expire in 0.1 sec */
evtim->ev.event_ptr = evtim;

/* Arm it */
ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
rte_strerror(rte_errno));

/* Add 100ms to account for the adapter tick window */
rte_delay_ms(100 + 100);

n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
n = timeout_event_dequeue(evs, RTE_DIM(evs), WAIT_TICKS(ticks));
TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
"events from event device");

Expand All @@ -1470,10 +1463,7 @@ event_timer_arm_rearm(void)
TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
rte_strerror(rte_errno));

/* Add 100ms to account for the adapter tick window */
rte_delay_ms(100 + 100);

n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
n = timeout_event_dequeue(evs, RTE_DIM(evs), WAIT_TICKS(ticks));
TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
"events from event device");

Expand All @@ -1495,15 +1485,16 @@ event_timer_arm_max(void)
int ret, i, n;
int num_evtims = MAX_TIMERS;
struct rte_event_timer *evtims[num_evtims];
struct rte_event evs[BATCH_SIZE];
struct rte_event evs[num_evtims];
uint64_t ticks = 5;
const struct rte_event_timer init_tim = {
.ev.op = RTE_EVENT_OP_NEW,
.ev.queue_id = TEST_QUEUE_ID,
.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,
.timeout_ticks = CALC_TICKS(5), // expire in .5 sec
.timeout_ticks = CALC_TICKS(ticks), /**< expire in .5 sec */
};

ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
Expand All @@ -1523,31 +1514,12 @@ event_timer_arm_max(void)
"succeeded = %d, rte_errno = %s",
num_evtims, ret, rte_strerror(rte_errno));

rte_delay_ms(1000);

#define MAX_TRIES num_evtims
int sum = 0;
int tries = 0;
bool done = false;
while (!done) {
sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
RTE_DIM(evs), 10);
if (sum >= num_evtims || ++tries >= MAX_TRIES)
done = true;

rte_delay_ms(10);
}

TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
"got %d", num_evtims, sum);

TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");

rte_delay_ms(100);
n = timeout_event_dequeue(evs, RTE_DIM(evs), WAIT_TICKS(ticks));
TEST_ASSERT_EQUAL(n, num_evtims, "Expected %d timer expiry events, got %d",
num_evtims, n);

/* Make sure the eventdev is still empty */
n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
10);
n = timeout_event_dequeue(evs, 1, WAIT_TICKS(1));

TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
"events from event device");
Expand Down Expand Up @@ -1667,6 +1639,7 @@ event_timer_cancel(void)
.ev.event_type = RTE_EVENT_TYPE_TIMER,
.state = RTE_EVENT_TIMER_NOT_ARMED,
};
uint64_t ticks = 30;

rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
if (evtim == NULL) {
Expand All @@ -1684,7 +1657,7 @@ event_timer_cancel(void)
/* Set up a timer */
*evtim = init_tim;
evtim->ev.event_ptr = evtim;
evtim->timeout_ticks = CALC_TICKS(30); // expire in 3 sec
evtim->timeout_ticks = CALC_TICKS(ticks); /**< expire in 3 sec */

/* Check that cancelling an inited but unarmed timer fails */
ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
Expand All @@ -1708,10 +1681,8 @@ event_timer_cancel(void)
TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_CANCELED,
"evtim in incorrect state");

rte_delay_ms(3000);

/* Make sure that no expiry event was generated */
n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
n = timeout_event_dequeue(evs, RTE_DIM(evs), WAIT_TICKS(ticks));
TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");

rte_mempool_put(eventdev_test_mempool, evtim);
Expand All @@ -1734,8 +1705,8 @@ event_timer_cancel_double(void)
.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
.ev.event_type = RTE_EVENT_TYPE_TIMER,
.state = RTE_EVENT_TIMER_NOT_ARMED,
.timeout_ticks = CALC_TICKS(5), // expire in .5 sec
};
uint64_t ticks = 30;

rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
if (evtim == NULL) {
Expand All @@ -1746,7 +1717,7 @@ event_timer_cancel_double(void)
/* Set up a timer */
*evtim = init_tim;
evtim->ev.event_ptr = evtim;
evtim->timeout_ticks = CALC_TICKS(30); // expire in 3 sec
evtim->timeout_ticks = CALC_TICKS(ticks); /**< expire in 3 sec */

ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
Expand All @@ -1768,10 +1739,8 @@ event_timer_cancel_double(void)
TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
"after double-cancel: rte_errno = %d", rte_errno);

rte_delay_ms(3000);

/* Still make sure that no expiry event was generated */
n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
n = timeout_event_dequeue(evs, RTE_DIM(evs), WAIT_TICKS(ticks));
TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");

rte_mempool_put(eventdev_test_mempool, evtim);
Expand Down

0 comments on commit 84d280e

Please sign in to comment.