From 50247fe03fe0476746b1ecdb540d44e24a28cece Mon Sep 17 00:00:00 2001 From: Erik Gabriel Carrillo Date: Thu, 18 Apr 2019 16:00:04 -0500 Subject: [PATCH] test/timer: exercise new APIs in secondary process This commit adds an autotest which exercises new timer reset/stop APIs in a secondary process. Timers are created, and sometimes stopped, in the secondary process, and their expiration is checked for and handled in the primary process. Signed-off-by: Erik Gabriel Carrillo --- app/test/Makefile | 1 + app/test/meson.build | 1 + app/test/test.c | 6 +- app/test/test.h | 1 + app/test/test_timer_secondary.c | 215 ++++++++++++++++++++++++++++++++ lib/librte_timer/rte_timer.c | 5 - 6 files changed, 223 insertions(+), 6 deletions(-) create mode 100644 app/test/test_timer_secondary.c diff --git a/app/test/Makefile b/app/test/Makefile index b28bed2d47..54f7067928 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -96,6 +96,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_STACK) += test_stack_perf.c SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer.c SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer_perf.c SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer_racecond.c +SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer_secondary.c SRCS-y += test_mempool.c SRCS-y += test_mempool_perf.c diff --git a/app/test/meson.build b/app/test/meson.build index 5e056eb599..80cdea5d13 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -109,6 +109,7 @@ test_sources = files('commands.c', 'test_timer.c', 'test_timer_perf.c', 'test_timer_racecond.c', + 'test_timer_secondary.c', 'test_ticketlock.c', 'test_version.c', 'virtual_pmd.c' diff --git a/app/test/test.c b/app/test/test.c index 1c91ed675c..fbe446440f 100644 --- a/app/test/test.c +++ b/app/test/test.c @@ -67,6 +67,7 @@ do_recursive_call(void) { "test_memory_flags", no_action }, { "test_file_prefix", no_action }, { "test_no_huge_flag", no_action }, + { "timer_secondary_spawn_wait", test_timer_secondary }, }; if (recursive_call == NULL) @@ -130,7 +131,10 @@ main(int argc, char **argv) } #ifdef RTE_LIBRTE_TIMER - rte_timer_subsystem_init(); + if (rte_timer_subsystem_init() < 0) { + ret = -1; + goto out; + } #endif if (commands_init() < 0) { diff --git a/app/test/test.h b/app/test/test.h index 9b3846b1ed..ac0c50616c 100644 --- a/app/test/test.h +++ b/app/test/test.h @@ -156,6 +156,7 @@ extern const char *prgname; int commands_init(void); int test_mp_secondary(void); +int test_timer_secondary(void); int test_set_rxtx_conf(cmdline_fixed_string_t mode); int test_set_rxtx_anchor(cmdline_fixed_string_t type); diff --git a/app/test/test_timer_secondary.c b/app/test/test_timer_secondary.c new file mode 100644 index 0000000000..31e4a7f083 --- /dev/null +++ b/app/test/test_timer_secondary.c @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" +#include "process.h" + +#define NUM_TIMERS (1 << 20) /* ~1M timers */ +#define NUM_LCORES_NEEDED 3 +#define TEST_INFO_MZ_NAME "test_timer_info_mz" +#define MSECPERSEC 1E3 + +#define launch_proc(ARGV) \ + process_dup(ARGV, sizeof(ARGV)/(sizeof(ARGV[0])), __func__) + +struct test_info { + unsigned int mstr_lcore; + unsigned int mgr_lcore; + unsigned int sec_lcore; + uint32_t timer_data_id; + volatile int expected_count; + volatile int expired_count; + struct rte_mempool *tim_mempool; + struct rte_timer *expired_timers[NUM_TIMERS]; + int expired_timers_idx; + volatile int exit_flag; +}; + +static int +timer_secondary_spawn_wait(unsigned int lcore) +{ + char coremask[10]; +#ifdef RTE_EXEC_ENV_LINUXAPP + char tmp[PATH_MAX] = {0}; + char prefix[PATH_MAX] = {0}; + + get_current_prefix(tmp, sizeof(tmp)); + + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); +#else + const char *prefix = ""; +#endif + char const *argv[] = { + prgname, + "-c", coremask, + "--proc-type=secondary", + prefix + }; + + snprintf(coremask, sizeof(coremask), "%x", (1 << lcore)); + + return launch_proc(argv); +} + +static void +handle_expired_timer(struct rte_timer *tim) +{ + struct test_info *test_info = tim->arg; + + test_info->expired_count++; + test_info->expired_timers[test_info->expired_timers_idx++] = tim; +} + +static int +timer_manage_loop(void *arg) +{ +#define TICK_MSECS 1 + uint64_t tick_cycles = TICK_MSECS * rte_get_timer_hz() / MSECPERSEC; + uint64_t prev_tsc = 0, cur_tsc, diff_tsc; + struct test_info *test_info = arg; + + while (!test_info->exit_flag) { + cur_tsc = rte_rdtsc(); + diff_tsc = cur_tsc - prev_tsc; + + if (diff_tsc > tick_cycles) { + /* Scan timer list for expired timers */ + rte_timer_alt_manage(test_info->timer_data_id, + NULL, + 0, + handle_expired_timer); + + /* Return expired timer objects back to mempool */ + rte_mempool_put_bulk(test_info->tim_mempool, + (void **)test_info->expired_timers, + test_info->expired_timers_idx); + + test_info->expired_timers_idx = 0; + + prev_tsc = cur_tsc; + } + + rte_pause(); + } + + return 0; +} + +int +test_timer_secondary(void) +{ + int proc_type = rte_eal_process_type(); + const struct rte_memzone *mz; + struct test_info *test_info; + int ret; + + if (proc_type == RTE_PROC_PRIMARY) { + mz = rte_memzone_reserve(TEST_INFO_MZ_NAME, sizeof(*test_info), + SOCKET_ID_ANY, 0); + test_info = mz->addr; + TEST_ASSERT_NOT_NULL(test_info, "Couldn't allocate memory for " + "test data"); + + TEST_ASSERT(rte_lcore_count() >= NUM_LCORES_NEEDED, + "at least %d lcores needed to run tests", + NUM_LCORES_NEEDED); + + test_info->tim_mempool = rte_mempool_create("test_timer_mp", + NUM_TIMERS, sizeof(struct rte_timer), 0, 0, + NULL, NULL, NULL, NULL, rte_socket_id(), 0); + + ret = rte_timer_data_alloc(&test_info->timer_data_id); + TEST_ASSERT_SUCCESS(ret, "Failed to allocate timer data " + "instance"); + + unsigned int *mstr_lcorep = &test_info->mstr_lcore; + unsigned int *mgr_lcorep = &test_info->mgr_lcore; + unsigned int *sec_lcorep = &test_info->sec_lcore; + + *mstr_lcorep = rte_get_master_lcore(); + *mgr_lcorep = rte_get_next_lcore(*mstr_lcorep, 1, 1); + *sec_lcorep = rte_get_next_lcore(*mgr_lcorep, 1, 1); + + ret = rte_eal_remote_launch(timer_manage_loop, + (void *)test_info, + *mgr_lcorep); + TEST_ASSERT_SUCCESS(ret, "Failed to launch timer manage loop"); + + ret = timer_secondary_spawn_wait(*sec_lcorep); + TEST_ASSERT_SUCCESS(ret, "Secondary process execution failed"); + + rte_delay_ms(2000); + + test_info->exit_flag = 1; + rte_eal_wait_lcore(*mgr_lcorep); + +#ifdef RTE_LIBRTE_TIMER_DEBUG + rte_timer_alt_dump_stats(test_info->timer_data_id, stdout); +#endif + + return test_info->expected_count == test_info->expired_count ? + TEST_SUCCESS : TEST_FAILED; + + } else if (proc_type == RTE_PROC_SECONDARY) { + uint64_t ticks, timeout_ms; + struct rte_timer *tim; + int i; + + mz = rte_memzone_lookup(TEST_INFO_MZ_NAME); + test_info = mz->addr; + TEST_ASSERT_NOT_NULL(test_info, "Couldn't lookup memzone for " + "test info"); + + for (i = 0; i < NUM_TIMERS; i++) { + rte_mempool_get(test_info->tim_mempool, (void **)&tim); + + rte_timer_init(tim); + + /* generate timeouts between 10 and 160 ms */ + timeout_ms = ((rte_rand() & 0xF) + 1) * 10; + ticks = timeout_ms * rte_get_timer_hz() / MSECPERSEC; + + ret = rte_timer_alt_reset(test_info->timer_data_id, + tim, ticks, SINGLE, + test_info->mgr_lcore, NULL, + test_info); + if (ret < 0) + return TEST_FAILED; + + test_info->expected_count++; + + /* randomly leave timer running or stop it */ + if (rte_rand() & 1) + continue; + + ret = rte_timer_alt_stop(test_info->timer_data_id, + tim); + if (ret == 0) { + test_info->expected_count--; + rte_mempool_put(test_info->tim_mempool, + (void *)tim); + } + + } + + return TEST_SUCCESS; + } + + return TEST_FAILED; +} + +REGISTER_TEST_COMMAND(timer_secondary_autotest, test_timer_secondary); diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c index ae5d2369ce..eb460098b6 100644 --- a/lib/librte_timer/rte_timer.c +++ b/lib/librte_timer/rte_timer.c @@ -582,11 +582,6 @@ rte_timer_alt_reset(uint32_t timer_data_id, struct rte_timer *tim, TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL); - if (unlikely((tim_lcore != (unsigned int)LCORE_ID_ANY) && - !(rte_lcore_is_enabled(tim_lcore) || - rte_lcore_has_role(tim_lcore, ROLE_SERVICE)))) - return -1; - if (type == PERIODICAL) period = ticks; else -- 2.20.1