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