31e4a7f083a97c92e29f23a744fb89093d8b86f9
[dpdk.git] / app / test / test_timer_secondary.c
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                 mz = rte_memzone_reserve(TEST_INFO_MZ_NAME, sizeof(*test_info),
122                                          SOCKET_ID_ANY, 0);
123                 test_info = mz->addr;
124                 TEST_ASSERT_NOT_NULL(test_info, "Couldn't allocate memory for "
125                                      "test data");
126
127                 TEST_ASSERT(rte_lcore_count() >= NUM_LCORES_NEEDED,
128                             "at least %d lcores needed to run tests",
129                             NUM_LCORES_NEEDED);
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 *mstr_lcorep = &test_info->mstr_lcore;
140                 unsigned int *mgr_lcorep = &test_info->mgr_lcore;
141                 unsigned int *sec_lcorep = &test_info->sec_lcore;
142
143                 *mstr_lcorep = rte_get_master_lcore();
144                 *mgr_lcorep = rte_get_next_lcore(*mstr_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_info = mz->addr;
174                 TEST_ASSERT_NOT_NULL(test_info, "Couldn't lookup memzone for "
175                                      "test info");
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);