From patchwork Thu Mar 8 21:54:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Carrillo, Erik G" X-Patchwork-Id: 35791 X-Patchwork-Delegate: jerinj@marvell.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B188CAA92; Thu, 8 Mar 2018 22:54:38 +0100 (CET) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id 1E49B8E1C for ; Thu, 8 Mar 2018 22:54:33 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 08 Mar 2018 13:54:33 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.47,442,1515484800"; d="scan'208";a="40388894" Received: from txasoft-yocto.an.intel.com (HELO txasoft-yocto.an.intel.com.) ([10.123.72.111]) by orsmga002.jf.intel.com with ESMTP; 08 Mar 2018 13:54:32 -0800 From: Erik Gabriel Carrillo To: pbhagavatula@caviumnetworks.com Cc: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com, hemant.agrawal@nxp.com Date: Thu, 8 Mar 2018 15:54:04 -0600 Message-Id: <1520546046-6973-6-git-send-email-erik.g.carrillo@intel.com> X-Mailer: git-send-email 1.7.10 In-Reply-To: <1520546046-6973-1-git-send-email-erik.g.carrillo@intel.com> References: <1515630074-29020-1-git-send-email-erik.g.carrillo@intel.com> <1520546046-6973-1-git-send-email-erik.g.carrillo@intel.com> Subject: [dpdk-dev] [PATCH v7 5/7] test: add event timer adapter auto-test X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Signed-off-by: Erik Gabriel Carrillo --- test/test/Makefile | 1 + test/test/test_event_timer_adapter.c | 1234 ++++++++++++++++++++++++++++++++++ 2 files changed, 1235 insertions(+) create mode 100644 test/test/test_event_timer_adapter.c diff --git a/test/test/Makefile b/test/test/Makefile index a88cc38..c9c007c9 100644 --- a/test/test/Makefile +++ b/test/test/Makefile @@ -185,6 +185,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y) SRCS-y += test_eventdev.c SRCS-y += test_event_ring.c SRCS-y += test_event_eth_rx_adapter.c +SRCS-y += test_event_timer_adapter.c endif ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c new file mode 100644 index 0000000..936e662 --- /dev/null +++ b/test/test/test_event_timer_adapter.c @@ -0,0 +1,1234 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Intel Corporation + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" + +#define NB_TEST_EVENT_TIMERS 2050 +#define NB_TEST_PORTS 1 +#define NB_TEST_QUEUES 1 +#define TEST_PORT_ID 0 +#define ADAPTER_PORT_ID 1 +#define TEST_QUEUE_ID 0 +#define TEST_ADAPTER_ID 0 + +#define NSECPERSEC 1E9 + +#define BATCH_SIZE 16 + +/* Handle log statements in same manner as test macros */ +#define LOG_DBG(...) RTE_LOG(DEBUG, EAL, __VA_ARGS__) + +static int evdev; +static struct rte_mempool *g_event_timer_pool; +static struct rte_event_timer_adapter *g_adapter; +static uint32_t slcore_id; + +static struct rte_event_timer_adapter_conf g_adapter_conf = { + .event_dev_id = 0, + .timer_adapter_id = TEST_ADAPTER_ID, + .clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK, + .timer_tick_ns = NSECPERSEC / 10, // 100 milliseconds, 10 ticks/sec + .max_tmo_ns = 180 * NSECPERSEC, // 2 minutes + .nb_timers = NB_TEST_EVENT_TIMERS, + .flags = 0, +}; + +static inline void +devconf_set_test_values(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + memset(dev_conf, 0, sizeof(struct rte_event_dev_config)); + dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns; + dev_conf->nb_event_ports = NB_TEST_PORTS; + dev_conf->nb_event_queues = NB_TEST_QUEUES; + dev_conf->nb_event_queue_flows = info->max_event_queue_flows; + dev_conf->nb_event_port_dequeue_depth = + info->max_event_port_dequeue_depth; + dev_conf->nb_event_port_enqueue_depth = + info->max_event_port_enqueue_depth; + dev_conf->nb_event_port_enqueue_depth = + info->max_event_port_enqueue_depth; + dev_conf->nb_events_limit = + info->max_num_events; +} + +static int +configure_event_dev(void) +{ + const char *eventdev_name = "event_sw0"; + int ret; + struct rte_event_dev_config devconf; + struct rte_event_dev_info info; + + evdev = rte_event_dev_get_dev_id(eventdev_name); + if (evdev < 0) { + if (rte_vdev_init(eventdev_name, NULL) < 0) { + LOG_DBG("Error creating eventdev\n"); + return TEST_FAILED; + } + evdev = rte_event_dev_get_dev_id(eventdev_name); + if (evdev < 0) { + LOG_DBG("Error finding newly created eventdev\n"); + return TEST_FAILED; + } + } + + ret = rte_event_dev_info_get(evdev, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + + devconf_set_test_values(&devconf, &info); + + ret = rte_event_dev_configure(evdev, &devconf); + TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev"); + + /* Set up event queue */ + uint32_t queue_count; + TEST_ASSERT_SUCCESS(rte_event_dev_attr_get(evdev, + RTE_EVENT_DEV_ATTR_QUEUE_COUNT, &queue_count), + "Queue count get failed"); + TEST_ASSERT_EQUAL(queue_count, 1, "Unexpected queue count"); + ret = rte_event_queue_setup(evdev, TEST_QUEUE_ID, NULL); + TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", TEST_QUEUE_ID); + + /* Set up event port */ + uint32_t port_count; + uint8_t qid = TEST_QUEUE_ID; + TEST_ASSERT_SUCCESS(rte_event_dev_attr_get(evdev, + RTE_EVENT_DEV_ATTR_PORT_COUNT, + &port_count), "Port count get failed"); + TEST_ASSERT_EQUAL(port_count, 1, "Unexpected port count"); + ret = rte_event_port_setup(evdev, TEST_PORT_ID, NULL); + TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", TEST_PORT_ID); + ret = rte_event_port_link(evdev, TEST_PORT_ID, &qid, NULL, 1); + TEST_ASSERT(ret >= 0, "Failed to link queue port=%d", TEST_PORT_ID); + + return TEST_SUCCESS; +} + +/* ---------------- Setup / Teardown --------------------*/ + +static int +testsuite_setup(void) +{ + slcore_id = rte_get_next_lcore(-1, 1, 0); + + TEST_ASSERT_NOT_EQUAL(slcore_id, RTE_MAX_LCORE, "At least 2 lcores " + "are required to run this autotest"); + + /* Setup and start event device. */ + TEST_ASSERT_SUCCESS(configure_event_dev(), "Failed to configure event " + "dev"); + + /* Create a mempool of event timers. */ + g_event_timer_pool = rte_mempool_create("event_timer_mempool", + NB_TEST_EVENT_TIMERS * 2, + sizeof(struct rte_event_timer), 0, 0, NULL, NULL, NULL, + NULL, rte_socket_id(), 0); + + TEST_ASSERT_NOT_NULL(g_event_timer_pool, "Failed to configure event " + "timer mempool: %s\n", rte_strerror(rte_errno)); + + return TEST_SUCCESS; +} + +static void +testsuite_teardown(void) +{ + rte_mempool_free(g_event_timer_pool); +} + +static int +g_adapter_create(void) +{ + uint8_t event_dev_id; + int ret, started; + struct rte_eventdev *event_dev; + struct rte_event_dev_config event_dev_conf; + + /* Re-configure the event device ports to release ports allocated by + * previous instantiations of event timer adapters. + */ + event_dev = &rte_eventdevs[g_adapter_conf.event_dev_id]; + event_dev_id = event_dev->data->dev_id; + event_dev_conf = event_dev->data->dev_conf; + + started = event_dev->data->dev_started; + if (started) + rte_event_dev_stop(event_dev_id); + + event_dev_conf.nb_event_ports = NB_TEST_PORTS; + ret = rte_event_dev_configure(event_dev_id, &event_dev_conf); + + if (started) { + ret = rte_event_dev_start(event_dev_id); + if (ret < 0) { + LOG_DBG("failed to start event device after " + "reconfiguration\n"); + return TEST_FAILED; + } + } + + /* Now create adapter with default port creation callback */ + g_adapter = rte_event_timer_adapter_create(&g_adapter_conf); + TEST_ASSERT_NOT_NULL(g_adapter, "Failed to create event timer adapter"); + + return TEST_SUCCESS; +} +static void +g_adapter_free(void) +{ + uint16_t n; + int ret; + struct rte_event evs[BATCH_SIZE]; + + ret = rte_event_timer_adapter_free(g_adapter); + if (ret != 0) + LOG_DBG("%s: Failed to free adapter\n", __func__); + + /* Drain the eventdev of events, so subsequent tests are not affected */ + while ((n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, + RTE_DIM(evs), 0)) > 0) + rte_delay_ms(10); +} + +static int +g_adapter_create_start(void) +{ + uint32_t evdev_service_id, adapter_service_id; + + g_adapter_create(); + + /* retrieve service ids */ + TEST_ASSERT_SUCCESS(rte_event_dev_service_id_get(evdev, + &evdev_service_id), "Failed to get event device " + "service id"); + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(g_adapter, + &adapter_service_id), "Failed to get event timer " + "adapter service id"); + + /* add a service core and start it */ + TEST_ASSERT_SUCCESS(rte_service_lcore_add(slcore_id), + "Failed to add service core"); + TEST_ASSERT_SUCCESS(rte_service_lcore_start(slcore_id), + "Failed to start service core"); + + /* map services to it */ + TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(evdev_service_id, + slcore_id, 1), "Failed to map evdev service"); + TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(adapter_service_id, + slcore_id, 1), "Failed to map adapter service"); + + /* set services to running */ + TEST_ASSERT_SUCCESS(rte_service_runstate_set(evdev_service_id, 1), + "Failed to start evdev service"); + TEST_ASSERT_SUCCESS(rte_service_runstate_set(adapter_service_id, 1), + "Failed to start event timer adapter service"); + + /* start the eventdev */ + TEST_ASSERT_SUCCESS(rte_event_dev_start(evdev), + "Failed to start event device"); + + /* start the timer event adapter */ + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_start(g_adapter), + "Failed to start event timer adapter"); + + return TEST_SUCCESS; +} + +static void +g_adapter_stop_free(void) +{ + int ret; + uint32_t evdev_service_id, adapter_service_id; + + /* Stop the event timer adapter */ + ret = rte_event_timer_adapter_stop(g_adapter); + if (ret != 0) + LOG_DBG("%s: Failed to stop adapter, ret = %d\n", __func__, + ret); + + /* Stop the eventdev */ + rte_event_dev_stop(evdev); + + /* set services to stopped */ + ret = rte_event_dev_service_id_get(evdev, &evdev_service_id); + if (ret != 0) + LOG_DBG("%s: Failed to get event device service id\n", + __func__); + + ret = rte_event_timer_adapter_service_id_get(g_adapter, + &adapter_service_id); + if (ret != 0) + LOG_DBG("%s: Failed to get event timer adapter service id\n", + __func__); + + ret = rte_service_runstate_set(evdev_service_id, 0); + if (ret != 0) + LOG_DBG("%s: Failed to stop evdev service\n", __func__); + + ret = rte_service_runstate_set(adapter_service_id, 0); + if (ret != 0) + LOG_DBG("%s: Failed to stop event timer adapter service\n", + __func__); + + g_adapter_free(); + + /* unmap all the services and service cores */ + rte_service_lcore_reset_all(); +} + +/* ---------------- Tests --------------------*/ + +/* Check that the adapter can be created correctly */ +static int +adapter_create(void) +{ + int adapter_id = 0; + struct rte_event_timer_adapter *adapter, *adapter2; + + struct rte_event_timer_adapter_conf conf = { + .event_dev_id = evdev + 1, // invalid event dev id + .timer_adapter_id = adapter_id, + .clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK, + .timer_tick_ns = NSECPERSEC / 10, + .max_tmo_ns = 180 * NSECPERSEC, + .nb_timers = NB_TEST_EVENT_TIMERS, + .flags = 0, + }; + + /* Test invalid conf */ + adapter = rte_event_timer_adapter_create(&conf); + TEST_ASSERT_NULL(adapter, "Created adapter with invalid " + "event device id"); + TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Incorrect errno value for " + "invalid event device id"); + + /* Test valid conf */ + conf.event_dev_id = evdev; + adapter = rte_event_timer_adapter_create(&conf); + TEST_ASSERT_NOT_NULL(adapter, "Failed to create adapter with valid " + "configuration"); + + /* Test existing id */ + adapter2 = rte_event_timer_adapter_create(&conf); + TEST_ASSERT_NULL(adapter2, "Created adapter with in-use id"); + TEST_ASSERT(rte_errno == EEXIST, "Incorrect errno value for existing " + "id"); + + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapter), + "Failed to free adapter"); + + return TEST_SUCCESS; +} + +/* This port conf callback is used by the max adapter instance creation test. + * Because that test may be limited by the number of ports available in the + * event device, this callback allocates just one port and returns it each + * time a port is requested. + */ +static int +test_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id, + void *conf_arg) +{ + struct rte_eventdev *dev; + struct rte_event_dev_config dev_conf; + struct rte_event_port_conf *port_conf, def_port_conf = {0}; + int started; + static int port_allocated; + static uint8_t port_id; + uint8_t dev_id; + int ret; + + if (port_allocated) { + *event_port_id = port_id; + return 0; + } + + RTE_SET_USED(id); + + dev = &rte_eventdevs[event_dev_id]; + dev_id = dev->data->dev_id; + dev_conf = dev->data->dev_conf; + + started = dev->data->dev_started; + if (started) + rte_event_dev_stop(dev_id); + + port_id = dev_conf.nb_event_ports; + dev_conf.nb_event_ports += 1; + ret = rte_event_dev_configure(dev_id, &dev_conf); + if (ret < 0) { + if (started) + rte_event_dev_start(dev_id); + + return ret; + } + + if (conf_arg != NULL) + port_conf = conf_arg; + else { + port_conf = &def_port_conf; + ret = rte_event_port_default_conf_get(dev_id, port_id, + port_conf); + if (ret < 0) + return ret; + } + + ret = rte_event_port_setup(dev_id, port_id, port_conf); + if (ret < 0) + return ret; + + *event_port_id = port_id; + + if (started) + rte_event_dev_start(dev_id); + + port_allocated = 1; + + return 0; +} + +static int +adapter_create_max(void) +{ + int i; + uint32_t svc_start_count, svc_end_count; + struct rte_event_timer_adapter *adapters[ + RTE_EVENT_TIMER_ADAPTER_NUM_MAX + 1]; + + struct rte_event_timer_adapter_conf conf = { + .event_dev_id = evdev, + // timer_adapter_id set in loop + .clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK, + .timer_tick_ns = NSECPERSEC / 10, + .max_tmo_ns = 180 * NSECPERSEC, + .nb_timers = NB_TEST_EVENT_TIMERS, + .flags = 0, + }; + + svc_start_count = rte_service_get_count(); + + /* This test expects that there are sufficient service IDs available + * to be allocated. I.e., RTE_EVENT_TIMER_ADAPTER_NUM_MAX may need to + * be less than RTE_SERVICE_NUM_MAX if anything else uses a service + * (the SW event device, for example). + */ + for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) { + conf.timer_adapter_id = i; + adapters[i] = rte_event_timer_adapter_create_ext(&conf, + test_port_conf_cb, NULL); + TEST_ASSERT_NOT_NULL(adapters[i], "Failed to create adapter " + "%d", i); + } + + conf.timer_adapter_id = i; + adapters[i] = rte_event_timer_adapter_create(&conf); + TEST_ASSERT_NULL(adapters[i], "Created too many adapters"); + + /* Check that at least RTE_EVENT_TIMER_ADAPTER_NUM_MAX services + * have been created + */ + svc_end_count = rte_service_get_count(); + TEST_ASSERT_EQUAL(svc_end_count - svc_start_count, + RTE_EVENT_TIMER_ADAPTER_NUM_MAX, + "Failed to create expected number of services"); + + for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapters[i]), + "Failed to free adapter %d", i); + + /* Check that service count is back to where it was at start */ + svc_end_count = rte_service_get_count(); + TEST_ASSERT_EQUAL(svc_start_count, svc_end_count, "Failed to release " + "correct number of services"); + + return TEST_SUCCESS; +} + +/* Test that adapter can be freed correctly. */ +static int +adapter_free(void) +{ + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(g_adapter), + "Failed to free valid adapter"); + + /* Test free of already freed adapter */ + TEST_ASSERT_FAIL(rte_event_timer_adapter_free(g_adapter), + "Freed adapter that was already freed"); + + /* Test free of null adapter */ + g_adapter = NULL; + TEST_ASSERT_FAIL(rte_event_timer_adapter_free(g_adapter), + "Freed null adapter"); + + return TEST_SUCCESS; +} + +/* Test that adapter info can be retrieved and is correct. */ +static int +adapter_get_info(void) +{ + struct rte_event_timer_adapter_info info; + + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_get_info(g_adapter, &info), + "Failed to get adapter info"); + + TEST_ASSERT_EQUAL(info.event_dev_port_id, 1, "Expected port id = 1," + "got port id = %d", info.event_dev_port_id); + + return TEST_SUCCESS; +} + +/* Test adapter lookup via adapter ID. */ +static int +adapter_lookup(void) +{ + struct rte_event_timer_adapter *adapter; + + adapter = rte_event_timer_adapter_lookup(TEST_ADAPTER_ID); + TEST_ASSERT_NOT_NULL(adapter, "Failed to lookup adapter"); + + return TEST_SUCCESS; +} + +/* Test that adapter starts correctly. */ +static int +adapter_start(void) +{ + uint32_t evdev_service_id, adapter_service_id; + struct rte_event_timer_adapter *l_adapter = NULL; + + TEST_ASSERT_FAIL(rte_event_timer_adapter_start(l_adapter), + "Erroneously started null adapter"); + + /* Check that we fail when no service core is mapped */ + TEST_ASSERT_FAIL(rte_event_timer_adapter_start(g_adapter), + "Erroneously started adapter with no service core " + "mapped"); + + /* retrieve service ids */ + TEST_ASSERT_SUCCESS(rte_event_dev_service_id_get(evdev, + &evdev_service_id), "Failed to get event device " + "service id"); + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(g_adapter, + &adapter_service_id), "Failed to get event timer " + "adapter service id"); + + /* add a service core and start it */ + TEST_ASSERT_SUCCESS(rte_service_lcore_add(slcore_id), + "Failed to add service core"); + TEST_ASSERT_SUCCESS(rte_service_lcore_start(slcore_id), + "Failed to start service core"); + + /* map services to it */ + TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(evdev_service_id, + slcore_id, 1), "Failed to map evdev service"); + TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(adapter_service_id, + slcore_id, 1), "Failed to map adapter service"); + + /* set services to running */ + TEST_ASSERT_SUCCESS(rte_service_runstate_set(evdev_service_id, 1), + "Failed to start evdev service"); + TEST_ASSERT_SUCCESS(rte_service_runstate_set(adapter_service_id, 1), + "Failed to start event timer adapter service"); + + /* start the eventdev */ + TEST_ASSERT_SUCCESS(rte_event_dev_start(evdev), + "Failed to start event device"); + + /* test adapter start */ + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_start(g_adapter), + "Failed to start event timer adapter"); + + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_start(g_adapter), + "Failed to repeatedly start adapter"); + + return TEST_SUCCESS; +} + +/* Test that adapter stops correctly. */ +static int +adapter_stop(void) +{ + uint32_t evdev_service_id, adapter_service_id; + struct rte_event_timer_adapter *l_adapter = NULL; + + /* retrieve service ids */ + TEST_ASSERT_SUCCESS(rte_event_dev_service_id_get(evdev, + &evdev_service_id), "Failed to get event device " + "service id"); + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(g_adapter, + &adapter_service_id), "Failed to get event timer " + "adapter service id"); + + /* Test adapter stop */ + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(g_adapter), + "Failed to stop event adapter"); + + TEST_ASSERT_FAIL(rte_event_timer_adapter_stop(l_adapter), + "Erroneously stopped null event adapter"); + + /* Stop the eventdev */ + rte_event_dev_stop(evdev); + + /* set services to stopped */ + TEST_ASSERT_SUCCESS(rte_service_runstate_set(evdev_service_id, 0), + "Failed to stop evdev service"); + TEST_ASSERT_SUCCESS(rte_service_runstate_set(adapter_service_id, 0), + "Failed to stop event timer adapter service"); + + /* Undo all service and core mappings */ + rte_service_lcore_reset_all(); + + return TEST_SUCCESS; +} + +/* Test increment and reset of ev_enq_count stat */ +static int +stat_inc_reset_ev_enq(void) +{ + int ret, i, n; + int num_evtims = NB_TEST_EVENT_TIMERS; + struct rte_event_timer *evtims[num_evtims]; + struct rte_event evs[BATCH_SIZE]; + struct rte_event_timer_adapter_stats stats; + + ret = rte_mempool_get_bulk(g_event_timer_pool, (void **)evtims, + num_evtims); + TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d", + ret); + + for (i = 0; i < num_evtims; i++) { + rte_event_timer_init(evtims[i]); + evtims[i]->ev.event_ptr = evtims[i]; + evtims[i]->ev.queue_id = TEST_QUEUE_ID; + evtims[i]->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; + evtims[i]->timeout_ticks = 5; // expire in .5 sec + } + + ret = rte_event_timer_adapter_stats_get(g_adapter, &stats); + TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats"); + TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0, "Stats not clear at " + "startup"); + + /* Test with the max value for the adapter */ + ret = rte_event_timer_arm_burst(g_adapter, evtims, num_evtims); + TEST_ASSERT_EQUAL(ret, num_evtims, + "Failed to arm all event timers: attempted = %d, " + "succeeded = %d, rte_errno = %s", + num_evtims, ret, rte_strerror(rte_errno)); + + rte_delay_ms(1000); + +#define MAX_TRIES 1000 + 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); + + /* Make sure the eventdev is still empty */ + n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), + 10); + + TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry " + "events from event device"); + + /* Check stats again */ + ret = rte_event_timer_adapter_stats_get(g_adapter, &stats); + TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats"); + TEST_ASSERT_EQUAL((int)stats.ev_enq_count, num_evtims, + "Expected enqueue stat = %d; got %d", num_evtims, + (int)stats.ev_enq_count); + + /* Reset and check again */ + ret = rte_event_timer_adapter_stats_reset(g_adapter); + TEST_ASSERT_EQUAL(ret, 0, "Failed to reset stats"); + + ret = rte_event_timer_adapter_stats_get(g_adapter, &stats); + TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats"); + TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0, + "Expected enqueue stat = %d; got %d", 0, + (int)stats.ev_enq_count); + + rte_mempool_put_bulk(g_event_timer_pool, (void **)evtims, num_evtims); + + return TEST_SUCCESS; +} + +/* Test various cases in arming timers */ +static int +event_timer_arm(void) +{ + uint16_t n; + int ret; + struct rte_event_timer_adapter *adapter = g_adapter; + struct rte_event_timer *evtim = NULL; + struct rte_event evs[BATCH_SIZE]; + + rte_mempool_get(g_event_timer_pool, (void **)&evtim); + if (evtim == NULL) { + /* Failed to get an event timer object */ + return TEST_FAILED; + } + + /* Set up a timer */ + rte_event_timer_init(evtim); + evtim->ev.event_ptr = evtim; + evtim->ev.queue_id = TEST_QUEUE_ID; + evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; + evtim->timeout_ticks = 5; // expire in 0.5 sec + + /* Test single timer arm succeeds */ + ret = rte_event_timer_arm_burst(adapter, &evtim, 1); + TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n", + rte_strerror(rte_errno)); + TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event timer " + "in incorrect state"); + + /* Test arm of armed timer fails */ + ret = rte_event_timer_arm_burst(adapter, &evtim, 1); + TEST_ASSERT_EQUAL(ret, 0, "expected return value from " + "rte_event_timer_arm_burst: 0, got: %d", ret); + 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); + TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry " + "events from event device"); + + rte_mempool_put(g_event_timer_pool, evtim); + + return TEST_SUCCESS; +} + +/* This test checks that repeated references to the same event timer in the + * arm request work as expected; only the first one through should succeed. + */ +static int +event_timer_arm_double(void) +{ + uint16_t n; + int ret; + struct rte_event_timer_adapter *adapter = g_adapter; + struct rte_event_timer *evtim = NULL; + struct rte_event evs[BATCH_SIZE]; + + rte_mempool_get(g_event_timer_pool, (void **)&evtim); + if (evtim == NULL) { + /* Failed to get an event timer object */ + return TEST_FAILED; + } + + /* Set up a timer */ + rte_event_timer_init(evtim); + evtim->ev.event_ptr = evtim; + evtim->ev.queue_id = TEST_QUEUE_ID; + evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; + evtim->timeout_ticks = 5; // expire in 0.5 sec + + struct rte_event_timer *evtim_arr[] = {evtim, evtim}; + ret = rte_event_timer_arm_burst(adapter, evtim_arr, RTE_DIM(evtim_arr)); + TEST_ASSERT_EQUAL(ret, 1, "Unexpected return value from " + "rte_event_timer_arm_burst"); + 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); + TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number of expiry events - " + "expected: 1, actual: %d", n); + + rte_mempool_put(g_event_timer_pool, evtim); + + return TEST_SUCCESS; +} + +/* Test the timer expiry event is generated at the expected time. */ +static int +event_timer_arm_expiry(void) +{ + uint16_t n; + int ret; + struct rte_event_timer_adapter *adapter = g_adapter; + struct rte_event_timer *evtim = NULL; + struct rte_event_timer *evtim2 = NULL; + struct rte_event evs[BATCH_SIZE]; + + /* Set up an event timer */ + rte_mempool_get(g_event_timer_pool, (void **)&evtim); + if (evtim == NULL) { + /* Failed to get an event timer object */ + return TEST_FAILED; + } + + rte_event_timer_init(evtim); + evtim->ev.event_ptr = evtim; + evtim->ev.queue_id = TEST_QUEUE_ID; + evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; + evtim->timeout_ticks = 30; // expire in 3 sec + + ret = rte_event_timer_arm_burst(adapter, &evtim, 1); + TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s", + rte_strerror(rte_errno)); + 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); + 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); + 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, + "Dequeued unexpected type of event"); + + /* Check that we recover the original event timer and then free it */ + evtim2 = evs[0].event_ptr; + TEST_ASSERT_EQUAL(evtim, evtim2, + "Failed to recover pointer to original event timer"); + TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_NOT_ARMED, "Event " + "timer in incorrect state"); + rte_mempool_put(g_event_timer_pool, evtim2); + + return TEST_SUCCESS; +} + +/* Check that rearming a timer works as expected. */ +static int +event_timer_arm_rearm(void) +{ + uint16_t n; + int ret; + struct rte_event_timer *evtim = NULL; + struct rte_event_timer *evtim2 = NULL; + struct rte_event evs[BATCH_SIZE]; + + rte_mempool_get(g_event_timer_pool, (void **)&evtim); + if (evtim == NULL) { + /* Failed to get an event timer object */ + return TEST_FAILED; + } + + /* Set up a timer */ + rte_event_timer_init(evtim); + evtim->ev.event_ptr = evtim; + evtim->ev.queue_id = TEST_QUEUE_ID; + evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; + evtim->timeout_ticks = 1; // expire in 0.1 sec + + /* Arm it */ + ret = rte_event_timer_arm_burst(g_adapter, &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); + TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry " + "events from event device"); + + /* Recover the timer through the event that was dequeued. */ + evtim2 = evs[0].event_ptr; + TEST_ASSERT_EQUAL(evtim, evtim2, + "Failed to recover pointer to original event timer"); + + /* Rearm it */ + ret = rte_event_timer_arm_burst(g_adapter, &evtim2, 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); + TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry " + "events from event device"); + + /* Free it */ + evtim2 = evs[0].event_ptr; + TEST_ASSERT_EQUAL(evtim, evtim2, + "Failed to recover pointer to original event timer"); + rte_mempool_put(g_event_timer_pool, evtim2); + + return TEST_SUCCESS; +} + +/* Check that creating an event timer with incorrect event sched type fails. */ +static int +event_timer_arm_invalid_sched_type(void) +{ + int ret; + struct rte_event_timer *evtim = NULL; + + rte_mempool_get(g_event_timer_pool, (void **)&evtim); + if (evtim == NULL) { + /* Failed to get an event timer object */ + return TEST_FAILED; + } + + rte_event_timer_init(evtim); + evtim->ev.event_ptr = evtim; + evtim->ev.queue_id = TEST_QUEUE_ID; + evtim->ev.sched_type = RTE_SCHED_TYPE_PARALLEL; // bad sched type + evtim->timeout_ticks = 5; // expire in 0.5 sec + + ret = rte_event_timer_arm_burst(g_adapter, &evtim, 1); + TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid " + "sched type, but didn't"); + TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after" + " arm fail with invalid queue"); + + rte_mempool_put(g_event_timer_pool, &evtim); + + return TEST_SUCCESS; +} + +/* Check that creating an event timer with a timeout value that is too small or + * too big fails. + */ +static int +event_timer_arm_invalid_timeout(void) +{ + int ret; + struct rte_event_timer *evtim = NULL; + + rte_mempool_get(g_event_timer_pool, (void **)&evtim); + if (evtim == NULL) { + /* Failed to get an event timer object */ + return TEST_FAILED; + } + + rte_event_timer_init(evtim); + evtim->ev.event_ptr = evtim; + evtim->ev.queue_id = TEST_QUEUE_ID; + evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; + evtim->timeout_ticks = 0; // timeout too small + + ret = rte_event_timer_arm_burst(g_adapter, &evtim, 1); + TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid " + "timeout, but didn't"); + TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after" + " arm fail with invalid timeout"); + TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOEARLY, + "Unexpected event timer state"); + + rte_event_timer_init(evtim); + evtim->ev.event_ptr = evtim; + evtim->ev.queue_id = TEST_QUEUE_ID; + evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; + evtim->timeout_ticks = 1801; // timeout too big + + ret = rte_event_timer_arm_burst(g_adapter, &evtim, 1); + TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid " + "timeout, but didn't"); + TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after" + " arm fail with invalid timeout"); + TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOLATE, + "Unexpected event timer state"); + + rte_mempool_put(g_event_timer_pool, evtim); + + return TEST_SUCCESS; +} + +/* Check that the adapter handles the max specified number of timers as + * expected. + */ +static int +event_timer_arm_max(void) +{ + int ret, i, n; + int num_evtims = NB_TEST_EVENT_TIMERS; + struct rte_event_timer *evtims[num_evtims]; + struct rte_event evs[BATCH_SIZE]; + + ret = rte_mempool_get_bulk(g_event_timer_pool, (void **)evtims, + num_evtims); + TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d", + ret); + + for (i = 0; i < num_evtims; i++) { + rte_event_timer_init(evtims[i]); + evtims[i]->ev.event_ptr = evtims[i]; + evtims[i]->ev.queue_id = TEST_QUEUE_ID; + evtims[i]->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; + evtims[i]->timeout_ticks = 5; // expire in .5 sec + } + + /* Test with the max value for the adapter */ + ret = rte_event_timer_arm_burst(g_adapter, evtims, num_evtims); + TEST_ASSERT_EQUAL(ret, num_evtims, + "Failed to arm all event timers: attempted = %d, " + "succeeded = %d, rte_errno = %s", + num_evtims, ret, rte_strerror(rte_errno)); + + rte_delay_ms(1000); + +#define MAX_TRIES 1000 + 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); + + /* Make sure the eventdev is still empty */ + n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), + 10); + + TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry " + "events from event device"); + + rte_mempool_put_bulk(g_event_timer_pool, (void **)evtims, num_evtims); + + return TEST_SUCCESS; +} + +static int +event_timer_cancel(void) +{ + uint16_t n; + int ret; + struct rte_event_timer_adapter *adapter = g_adapter; + struct rte_event_timer *evtim = NULL; + struct rte_event evs[BATCH_SIZE]; + + rte_mempool_get(g_event_timer_pool, (void **)&evtim); + if (evtim == NULL) { + /* Failed to get an event timer object */ + return TEST_FAILED; + } + + /* Check that cancelling an uninited timer fails */ + ret = rte_event_timer_cancel_burst(adapter, &evtim, 1); + TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling " + "uninited timer"); + TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after " + "cancelling uninited timer"); + + /* Set up a timer */ + rte_event_timer_init(evtim); + evtim->ev.event_ptr = evtim; + evtim->ev.queue_id = TEST_QUEUE_ID; + evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; + evtim->timeout_ticks = 30; // expire in 3 sec + + /* Check that cancelling an inited but unarmed timer fails */ + ret = rte_event_timer_cancel_burst(adapter, &evtim, 1); + TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling " + "unarmed timer"); + TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after " + "cancelling unarmed timer"); + + ret = rte_event_timer_arm_burst(adapter, &evtim, 1); + TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n", + rte_strerror(rte_errno)); + TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, + "evtim in incorrect state"); + + /* Delay 1 sec */ + rte_delay_ms(1000); + + ret = rte_event_timer_cancel_burst(adapter, &evtim, 1); + TEST_ASSERT_EQUAL(ret, 1, "Failed to cancel event_timer: %s\n", + rte_strerror(rte_errno)); + 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); + TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n"); + + return TEST_SUCCESS; +} + +static int +event_timer_cancel_double(void) +{ + uint16_t n; + int ret; + struct rte_event_timer_adapter *adapter = g_adapter; + struct rte_event_timer *evtim = NULL; + struct rte_event evs[BATCH_SIZE]; + + rte_mempool_get(g_event_timer_pool, (void **)&evtim); + if (evtim == NULL) { + /* Failed to get an event timer object */ + return TEST_FAILED; + } + + /* Set up a timer */ + rte_event_timer_init(evtim); + evtim->ev.event_ptr = evtim; + evtim->ev.queue_id = TEST_QUEUE_ID; + evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; + evtim->timeout_ticks = 30; // 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", + rte_strerror(rte_errno)); + TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, + "timer in unexpected state"); + + /* Now, test that referencing the same timer twice in the same call + * fails + */ + struct rte_event_timer *evtim_arr[] = {evtim, evtim}; + ret = rte_event_timer_cancel_burst(adapter, evtim_arr, + RTE_DIM(evtim_arr)); + + /* Two requests to cancel same timer, only one should succeed */ + TEST_ASSERT_EQUAL(ret, 1, "Succeeded unexpectedly in canceling timer " + "twice"); + + 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); + TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n"); + + return TEST_SUCCESS; +} + +/* Check that event timer adapter tick resolution works as expected by testing + * the number of adapter ticks that occur within a particular time interval. + */ +static int +adapter_tick_resolution(void) +{ + struct rte_event_timer_adapter_stats stats; + uint64_t adapter_tick_count; + + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(g_adapter, + &stats), "Failed to get adapter stats"); + TEST_ASSERT_EQUAL(stats.adapter_tick_count, 0, "Adapter tick count " + "not zeroed out"); + + /* Delay 1 second; should let at least 10 ticks occur with the default + * adapter configuration used by this test. + */ + rte_delay_ms(1000); + + TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(g_adapter, + &stats), "Failed to get adapter stats"); + + adapter_tick_count = stats.adapter_tick_count; + TEST_ASSERT(adapter_tick_count >= 10 && adapter_tick_count <= 12, + "Expected 10-12 adapter ticks, got %"PRIu64"\n", + adapter_tick_count); + + return TEST_SUCCESS; +} + +static struct unit_test_suite adapter_tests = { + .suite_name = "event timer adapter test suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE(adapter_create), + TEST_CASE_ST(g_adapter_create, NULL, adapter_free), + TEST_CASE_ST(g_adapter_create, g_adapter_free, + adapter_get_info), + TEST_CASE_ST(g_adapter_create, g_adapter_free, + adapter_lookup), + TEST_CASE_ST(g_adapter_create, g_adapter_stop_free, + adapter_start), + TEST_CASE_ST(g_adapter_create_start, g_adapter_free, + adapter_stop), + TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free, + stat_inc_reset_ev_enq), + TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free, + event_timer_arm), + TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free, + event_timer_arm_double), + TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free, + event_timer_arm_expiry), + TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free, + event_timer_arm_rearm), + TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free, + event_timer_arm_max), + TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free, + event_timer_arm_invalid_sched_type), + TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free, + event_timer_arm_invalid_timeout), + TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free, + event_timer_cancel), + TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free, + event_timer_cancel_double), + TEST_CASE_ST(g_adapter_create_start, + g_adapter_stop_free, + adapter_tick_resolution), + /* This test is last because it can influence tests that follow + * it + */ + TEST_CASE(adapter_create_max), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static int +test_event_timer_adapter_common(void) +{ + return unit_test_suite_runner(&adapter_tests); +} + +REGISTER_TEST_COMMAND(event_timer_adapter_autotest, + test_event_timer_adapter_common);