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