1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2019 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <string.h> 7 8 #include <rte_eal.h> 9 #include <rte_lcore.h> 10 #include <rte_debug.h> 11 #include <rte_memzone.h> 12 #include <rte_timer.h> 13 #include <rte_cycles.h> 14 #include <rte_mempool.h> 15 #include <rte_random.h> 16 17 #include "test.h" 18 #include "process.h" 19 20 #define NUM_TIMERS (1 << 20) /* ~1M timers */ 21 #define NUM_LCORES_NEEDED 3 22 #define TEST_INFO_MZ_NAME "test_timer_info_mz" 23 #define MSECPERSEC 1E3 24 25 #define launch_proc(ARGV) process_dup(ARGV, RTE_DIM(ARGV), __func__) 26 27 struct test_info { 28 unsigned int main_lcore; 29 unsigned int mgr_lcore; 30 unsigned int sec_lcore; 31 uint32_t timer_data_id; 32 volatile int expected_count; 33 volatile int expired_count; 34 struct rte_mempool *tim_mempool; 35 struct rte_timer *expired_timers[NUM_TIMERS]; 36 int expired_timers_idx; 37 volatile int exit_flag; 38 }; 39 40 static int 41 timer_secondary_spawn_wait(unsigned int lcore) 42 { 43 char coremask[10]; 44 #ifdef RTE_EXEC_ENV_LINUXAPP 45 char tmp[PATH_MAX] = {0}; 46 char prefix[PATH_MAX] = {0}; 47 48 get_current_prefix(tmp, sizeof(tmp)); 49 50 snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); 51 #else 52 const char *prefix = ""; 53 #endif 54 char const *argv[] = { 55 prgname, 56 "-c", coremask, 57 "--proc-type=secondary", 58 prefix 59 }; 60 61 snprintf(coremask, sizeof(coremask), "%x", (1 << lcore)); 62 63 return launch_proc(argv); 64 } 65 66 static void 67 handle_expired_timer(struct rte_timer *tim) 68 { 69 struct test_info *test_info = tim->arg; 70 71 test_info->expired_count++; 72 test_info->expired_timers[test_info->expired_timers_idx++] = tim; 73 } 74 75 static int 76 timer_manage_loop(void *arg) 77 { 78 #define TICK_MSECS 1 79 uint64_t tick_cycles = TICK_MSECS * rte_get_timer_hz() / MSECPERSEC; 80 uint64_t prev_tsc = 0, cur_tsc, diff_tsc; 81 struct test_info *test_info = arg; 82 83 while (!test_info->exit_flag) { 84 cur_tsc = rte_rdtsc(); 85 diff_tsc = cur_tsc - prev_tsc; 86 87 if (diff_tsc > tick_cycles) { 88 /* Scan timer list for expired timers */ 89 rte_timer_alt_manage(test_info->timer_data_id, 90 NULL, 91 0, 92 handle_expired_timer); 93 94 /* Return expired timer objects back to mempool */ 95 rte_mempool_put_bulk(test_info->tim_mempool, 96 (void **)test_info->expired_timers, 97 test_info->expired_timers_idx); 98 99 test_info->expired_timers_idx = 0; 100 101 prev_tsc = cur_tsc; 102 } 103 104 rte_pause(); 105 } 106 107 return 0; 108 } 109 110 int 111 test_timer_secondary(void) 112 { 113 int proc_type = rte_eal_process_type(); 114 const struct rte_memzone *mz; 115 struct test_info *test_info; 116 int ret; 117 118 if (proc_type == RTE_PROC_PRIMARY) { 119 if (rte_lcore_count() < NUM_LCORES_NEEDED) { 120 printf("Not enough cores for test_timer_secondary, expecting at least %u\n", 121 NUM_LCORES_NEEDED); 122 return TEST_SKIPPED; 123 } 124 125 mz = rte_memzone_reserve(TEST_INFO_MZ_NAME, sizeof(*test_info), 126 SOCKET_ID_ANY, 0); 127 TEST_ASSERT_NOT_NULL(mz, "Couldn't allocate memory for " 128 "test data"); 129 test_info = mz->addr; 130 131 test_info->tim_mempool = rte_mempool_create("test_timer_mp", 132 NUM_TIMERS, sizeof(struct rte_timer), 0, 0, 133 NULL, NULL, NULL, NULL, rte_socket_id(), 0); 134 135 ret = rte_timer_data_alloc(&test_info->timer_data_id); 136 TEST_ASSERT_SUCCESS(ret, "Failed to allocate timer data " 137 "instance"); 138 139 unsigned int *main_lcorep = &test_info->main_lcore; 140 unsigned int *mgr_lcorep = &test_info->mgr_lcore; 141 unsigned int *sec_lcorep = &test_info->sec_lcore; 142 143 *main_lcorep = rte_get_main_lcore(); 144 *mgr_lcorep = rte_get_next_lcore(*main_lcorep, 1, 1); 145 *sec_lcorep = rte_get_next_lcore(*mgr_lcorep, 1, 1); 146 147 ret = rte_eal_remote_launch(timer_manage_loop, 148 (void *)test_info, 149 *mgr_lcorep); 150 TEST_ASSERT_SUCCESS(ret, "Failed to launch timer manage loop"); 151 152 ret = timer_secondary_spawn_wait(*sec_lcorep); 153 TEST_ASSERT_SUCCESS(ret, "Secondary process execution failed"); 154 155 rte_delay_ms(2000); 156 157 test_info->exit_flag = 1; 158 rte_eal_wait_lcore(*mgr_lcorep); 159 160 #ifdef RTE_LIBRTE_TIMER_DEBUG 161 rte_timer_alt_dump_stats(test_info->timer_data_id, stdout); 162 #endif 163 164 return test_info->expected_count == test_info->expired_count ? 165 TEST_SUCCESS : TEST_FAILED; 166 167 } else if (proc_type == RTE_PROC_SECONDARY) { 168 uint64_t ticks, timeout_ms; 169 struct rte_timer *tim; 170 int i; 171 172 mz = rte_memzone_lookup(TEST_INFO_MZ_NAME); 173 TEST_ASSERT_NOT_NULL(mz, "Couldn't lookup memzone for " 174 "test info"); 175 test_info = mz->addr; 176 177 for (i = 0; i < NUM_TIMERS; i++) { 178 rte_mempool_get(test_info->tim_mempool, (void **)&tim); 179 180 rte_timer_init(tim); 181 182 /* generate timeouts between 10 and 160 ms */ 183 timeout_ms = ((rte_rand() & 0xF) + 1) * 10; 184 ticks = timeout_ms * rte_get_timer_hz() / MSECPERSEC; 185 186 ret = rte_timer_alt_reset(test_info->timer_data_id, 187 tim, ticks, SINGLE, 188 test_info->mgr_lcore, NULL, 189 test_info); 190 if (ret < 0) 191 return TEST_FAILED; 192 193 test_info->expected_count++; 194 195 /* randomly leave timer running or stop it */ 196 if (rte_rand() & 1) 197 continue; 198 199 ret = rte_timer_alt_stop(test_info->timer_data_id, 200 tim); 201 if (ret == 0) { 202 test_info->expected_count--; 203 rte_mempool_put(test_info->tim_mempool, 204 (void *)tim); 205 } 206 207 } 208 209 return TEST_SUCCESS; 210 } 211 212 return TEST_FAILED; 213 } 214 215 REGISTER_TEST_COMMAND(timer_secondary_autotest, test_timer_secondary); 216