Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2017 Cavium, Inc
3 : : */
4 : :
5 : : #include "test_order_common.h"
6 : :
7 : : int
8 : 0 : order_test_result(struct evt_test *test, struct evt_options *opt)
9 : : {
10 : : RTE_SET_USED(opt);
11 : : struct test_order *t = evt_test_priv(test);
12 : :
13 : 0 : return t->result;
14 : : }
15 : :
16 : : static inline int
17 : 0 : order_producer(void *arg)
18 : : {
19 : : struct prod_data *p = arg;
20 : 0 : struct test_order *t = p->t;
21 : 0 : struct evt_options *opt = t->opt;
22 : 0 : const uint8_t dev_id = p->dev_id;
23 : 0 : const uint8_t port = p->port_id;
24 : 0 : struct rte_mempool *pool = t->pool;
25 : 0 : const uint64_t nb_pkts = t->nb_pkts;
26 : 0 : uint32_t *producer_flow_seq = t->producer_flow_seq;
27 : 0 : const uint32_t nb_flows = t->nb_flows;
28 : : uint64_t count = 0;
29 : : struct rte_mbuf *m;
30 : : struct rte_event ev;
31 : :
32 : 0 : if (opt->verbose_level > 1)
33 : 0 : printf("%s(): lcore %d dev_id %d port=%d queue=%d\n",
34 : 0 : __func__, rte_lcore_id(), dev_id, port, p->queue_id);
35 : :
36 : 0 : ev.event = 0;
37 : : ev.op = RTE_EVENT_OP_NEW;
38 : 0 : ev.queue_id = p->queue_id;
39 : : ev.sched_type = RTE_SCHED_TYPE_ORDERED;
40 : 0 : ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
41 : 0 : ev.event_type = RTE_EVENT_TYPE_CPU;
42 : : ev.sub_event_type = 0; /* stage 0 */
43 : :
44 : 0 : while (count < nb_pkts && t->err == false) {
45 : 0 : m = rte_pktmbuf_alloc(pool);
46 : 0 : if (m == NULL)
47 : 0 : continue;
48 : :
49 : 0 : const flow_id_t flow = (uintptr_t)m % nb_flows;
50 : : /* Maintain seq number per flow */
51 : 0 : *order_mbuf_seqn(t, m) = producer_flow_seq[flow]++;
52 : : order_flow_id_save(t, flow, m, &ev);
53 : :
54 : 0 : while (rte_event_enqueue_burst(dev_id, port, &ev, 1) != 1) {
55 : 0 : if (t->err)
56 : : break;
57 : : rte_pause();
58 : : }
59 : :
60 : 0 : count++;
61 : : }
62 : 0 : return 0;
63 : : }
64 : :
65 : : int
66 : 0 : order_opt_check(struct evt_options *opt)
67 : : {
68 : 0 : if (opt->prod_type != EVT_PROD_TYPE_SYNT) {
69 : 0 : evt_err("Invalid producer type '%s' valid producer '%s'",
70 : : evt_prod_id_to_name(opt->prod_type),
71 : : evt_prod_id_to_name(EVT_PROD_TYPE_SYNT));
72 : 0 : return -1;
73 : : }
74 : :
75 : : /* 1 producer + N workers + main */
76 : 0 : if (rte_lcore_count() < 3) {
77 : 0 : evt_err("test need minimum 3 lcores");
78 : 0 : return -1;
79 : : }
80 : :
81 : : /* Validate worker lcores */
82 : 0 : if (evt_lcores_has_overlap(opt->wlcores, rte_get_main_lcore())) {
83 : 0 : evt_err("worker lcores overlaps with main lcore");
84 : 0 : return -1;
85 : : }
86 : :
87 : 0 : if (evt_nr_active_lcores(opt->plcores) == 0) {
88 : 0 : evt_err("missing the producer lcore");
89 : 0 : return -1;
90 : : }
91 : :
92 : 0 : if (evt_nr_active_lcores(opt->plcores) != 1) {
93 : 0 : evt_err("only one producer lcore must be selected");
94 : 0 : return -1;
95 : : }
96 : :
97 : : int plcore = evt_get_first_active_lcore(opt->plcores);
98 : :
99 : 0 : if (plcore < 0) {
100 : 0 : evt_err("failed to find active producer");
101 : 0 : return plcore;
102 : : }
103 : :
104 : : if (evt_lcores_has_overlap(opt->wlcores, plcore)) {
105 : 0 : evt_err("worker lcores overlaps producer lcore");
106 : 0 : return -1;
107 : : }
108 : 0 : if (evt_has_disabled_lcore(opt->wlcores)) {
109 : 0 : evt_err("one or more workers lcores are not enabled");
110 : 0 : return -1;
111 : : }
112 : 0 : if (!evt_has_active_lcore(opt->wlcores)) {
113 : 0 : evt_err("minimum one worker is required");
114 : 0 : return -1;
115 : : }
116 : :
117 : : /* Validate producer lcore */
118 : 0 : if (plcore == (int)rte_get_main_lcore()) {
119 : 0 : evt_err("producer lcore and main lcore should be different");
120 : 0 : return -1;
121 : : }
122 : 0 : if (!rte_lcore_is_enabled(plcore)) {
123 : 0 : evt_err("producer lcore is not enabled");
124 : 0 : return -1;
125 : : }
126 : :
127 : : /* Fixups */
128 : 0 : if (opt->nb_pkts == 0)
129 : 0 : opt->nb_pkts = INT64_MAX;
130 : :
131 : : return 0;
132 : : }
133 : :
134 : : int
135 : 0 : order_test_setup(struct evt_test *test, struct evt_options *opt)
136 : : {
137 : : void *test_order;
138 : : struct test_order *t;
139 : : static const struct rte_mbuf_dynfield flow_id_dynfield_desc = {
140 : : .name = "test_event_dynfield_flow_id",
141 : : .size = sizeof(flow_id_t),
142 : : .align = __alignof__(flow_id_t),
143 : : };
144 : : static const struct rte_mbuf_dynfield seqn_dynfield_desc = {
145 : : .name = "test_event_dynfield_seqn",
146 : : .size = sizeof(seqn_t),
147 : : .align = __alignof__(seqn_t),
148 : : };
149 : :
150 : 0 : test_order = rte_zmalloc_socket(test->name, sizeof(struct test_order),
151 : : RTE_CACHE_LINE_SIZE, opt->socket_id);
152 : 0 : if (test_order == NULL) {
153 : 0 : evt_err("failed to allocate test_order memory");
154 : 0 : goto nomem;
155 : : }
156 : 0 : test->test_priv = test_order;
157 : : t = evt_test_priv(test);
158 : :
159 : 0 : t->flow_id_dynfield_offset =
160 : 0 : rte_mbuf_dynfield_register(&flow_id_dynfield_desc);
161 : 0 : if (t->flow_id_dynfield_offset < 0) {
162 : 0 : evt_err("failed to register mbuf field");
163 : 0 : return -rte_errno;
164 : : }
165 : :
166 : 0 : t->seqn_dynfield_offset =
167 : 0 : rte_mbuf_dynfield_register(&seqn_dynfield_desc);
168 : 0 : if (t->seqn_dynfield_offset < 0) {
169 : 0 : evt_err("failed to register mbuf field");
170 : 0 : return -rte_errno;
171 : : }
172 : :
173 : 0 : t->producer_flow_seq = rte_zmalloc_socket("test_producer_flow_seq",
174 : 0 : sizeof(*t->producer_flow_seq) * opt->nb_flows,
175 : : RTE_CACHE_LINE_SIZE, opt->socket_id);
176 : :
177 : 0 : if (t->producer_flow_seq == NULL) {
178 : 0 : evt_err("failed to allocate t->producer_flow_seq memory");
179 : 0 : goto prod_nomem;
180 : : }
181 : :
182 : 0 : t->expected_flow_seq = rte_zmalloc_socket("test_expected_flow_seq",
183 : 0 : sizeof(*t->expected_flow_seq) * opt->nb_flows,
184 : : RTE_CACHE_LINE_SIZE, opt->socket_id);
185 : :
186 : 0 : if (t->expected_flow_seq == NULL) {
187 : 0 : evt_err("failed to allocate t->expected_flow_seq memory");
188 : 0 : goto exp_nomem;
189 : : }
190 : 0 : __atomic_store_n(&t->outstand_pkts, opt->nb_pkts, __ATOMIC_RELAXED);
191 : 0 : t->err = false;
192 : 0 : t->nb_pkts = opt->nb_pkts;
193 : 0 : t->nb_flows = opt->nb_flows;
194 : 0 : t->result = EVT_TEST_FAILED;
195 : 0 : t->opt = opt;
196 : 0 : return 0;
197 : :
198 : : exp_nomem:
199 : 0 : rte_free(t->producer_flow_seq);
200 : 0 : prod_nomem:
201 : 0 : rte_free(test->test_priv);
202 : : nomem:
203 : : return -ENOMEM;
204 : : }
205 : :
206 : : void
207 : 0 : order_test_destroy(struct evt_test *test, struct evt_options *opt)
208 : : {
209 : : RTE_SET_USED(opt);
210 : : struct test_order *t = evt_test_priv(test);
211 : :
212 : 0 : rte_free(t->expected_flow_seq);
213 : 0 : rte_free(t->producer_flow_seq);
214 : 0 : rte_free(test->test_priv);
215 : 0 : }
216 : :
217 : : int
218 : 0 : order_mempool_setup(struct evt_test *test, struct evt_options *opt)
219 : : {
220 : : struct test_order *t = evt_test_priv(test);
221 : :
222 : 0 : t->pool = rte_pktmbuf_pool_create(test->name, opt->pool_sz,
223 : : 256 /* Cache */, 0,
224 : : 512, /* Use very small mbufs */
225 : : opt->socket_id);
226 : 0 : if (t->pool == NULL) {
227 : 0 : evt_err("failed to create mempool");
228 : 0 : return -ENOMEM;
229 : : }
230 : :
231 : : return 0;
232 : : }
233 : :
234 : : void
235 : 0 : order_mempool_destroy(struct evt_test *test, struct evt_options *opt)
236 : : {
237 : : RTE_SET_USED(opt);
238 : : struct test_order *t = evt_test_priv(test);
239 : :
240 : 0 : rte_mempool_free(t->pool);
241 : 0 : }
242 : :
243 : : void
244 : 0 : order_eventdev_destroy(struct evt_test *test, struct evt_options *opt)
245 : : {
246 : : RTE_SET_USED(test);
247 : :
248 : 0 : rte_event_dev_stop(opt->dev_id);
249 : 0 : rte_event_dev_close(opt->dev_id);
250 : 0 : }
251 : :
252 : : void
253 : 0 : order_opt_dump(struct evt_options *opt)
254 : : {
255 : 0 : evt_dump_producer_lcores(opt);
256 : 0 : evt_dump("nb_worker_lcores", "%d", evt_nr_active_lcores(opt->wlcores));
257 : 0 : evt_dump_worker_lcores(opt);
258 : : evt_dump("nb_evdev_ports", "%d", order_nb_event_ports(opt));
259 : 0 : }
260 : :
261 : : int
262 : 0 : order_launch_lcores(struct evt_test *test, struct evt_options *opt,
263 : : int (*worker)(void *))
264 : : {
265 : : int ret, lcore_id;
266 : : struct test_order *t = evt_test_priv(test);
267 : :
268 : : int wkr_idx = 0;
269 : : /* launch workers */
270 : 0 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
271 : 0 : if (!(opt->wlcores[lcore_id]))
272 : 0 : continue;
273 : :
274 : 0 : ret = rte_eal_remote_launch(worker, &t->worker[wkr_idx],
275 : : lcore_id);
276 : 0 : if (ret) {
277 : 0 : evt_err("failed to launch worker %d", lcore_id);
278 : 0 : return ret;
279 : : }
280 : 0 : wkr_idx++;
281 : : }
282 : :
283 : : /* launch producer */
284 : 0 : int plcore = evt_get_first_active_lcore(opt->plcores);
285 : :
286 : 0 : ret = rte_eal_remote_launch(order_producer, &t->prod, plcore);
287 : 0 : if (ret) {
288 : 0 : evt_err("failed to launch order_producer %d", plcore);
289 : 0 : return ret;
290 : : }
291 : :
292 : : uint64_t cycles = rte_get_timer_cycles();
293 : : int64_t old_remaining = -1;
294 : :
295 : 0 : while (t->err == false) {
296 : : uint64_t new_cycles = rte_get_timer_cycles();
297 : 0 : int64_t remaining = __atomic_load_n(&t->outstand_pkts, __ATOMIC_RELAXED);
298 : :
299 : 0 : if (remaining <= 0) {
300 : 0 : t->result = EVT_TEST_SUCCESS;
301 : 0 : break;
302 : : }
303 : :
304 : 0 : if (new_cycles - cycles > rte_get_timer_hz() * 1) {
305 : : printf(CLGRN"\r%"PRId64""CLNRM, remaining);
306 : 0 : fflush(stdout);
307 : 0 : if (old_remaining == remaining) {
308 : 0 : rte_event_dev_dump(opt->dev_id, stdout);
309 : 0 : evt_err("No schedules for seconds, deadlock");
310 : 0 : t->err = true;
311 : 0 : break;
312 : : }
313 : : old_remaining = remaining;
314 : : cycles = new_cycles;
315 : : }
316 : : }
317 : : printf("\r");
318 : :
319 : 0 : return 0;
320 : : }
321 : :
322 : : int
323 : 0 : order_event_dev_port_setup(struct evt_test *test, struct evt_options *opt,
324 : : uint8_t nb_workers, uint8_t nb_queues)
325 : : {
326 : : int ret;
327 : : uint8_t port;
328 : : struct test_order *t = evt_test_priv(test);
329 : : struct rte_event_dev_info dev_info;
330 : :
331 : 0 : ret = rte_event_dev_info_get(opt->dev_id, &dev_info);
332 : 0 : if (ret) {
333 : 0 : evt_err("failed to get eventdev info %d", opt->dev_id);
334 : 0 : return ret;
335 : : }
336 : :
337 : 0 : if (opt->wkr_deq_dep > dev_info.max_event_port_dequeue_depth)
338 : 0 : opt->wkr_deq_dep = dev_info.max_event_port_dequeue_depth;
339 : :
340 : : /* port configuration */
341 : 0 : const struct rte_event_port_conf p_conf = {
342 : 0 : .dequeue_depth = opt->wkr_deq_dep,
343 : : .enqueue_depth = dev_info.max_event_port_dequeue_depth,
344 : 0 : .new_event_threshold = dev_info.max_num_events,
345 : : };
346 : :
347 : : /* setup one port per worker, linking to all queues */
348 : 0 : for (port = 0; port < nb_workers; port++) {
349 : 0 : struct worker_data *w = &t->worker[port];
350 : :
351 : 0 : w->dev_id = opt->dev_id;
352 : 0 : w->port_id = port;
353 : 0 : w->t = t;
354 : :
355 : 0 : ret = rte_event_port_setup(opt->dev_id, port, &p_conf);
356 : 0 : if (ret) {
357 : 0 : evt_err("failed to setup port %d", port);
358 : 0 : return ret;
359 : : }
360 : :
361 : 0 : ret = rte_event_port_link(opt->dev_id, port, NULL, NULL, 0);
362 : 0 : if (ret != nb_queues) {
363 : 0 : evt_err("failed to link all queues to port %d", port);
364 : 0 : return -EINVAL;
365 : : }
366 : : }
367 : : struct prod_data *p = &t->prod;
368 : :
369 : 0 : p->dev_id = opt->dev_id;
370 : 0 : p->port_id = port; /* last port */
371 : 0 : p->queue_id = 0;
372 : 0 : p->t = t;
373 : :
374 : 0 : ret = rte_event_port_setup(opt->dev_id, port, &p_conf);
375 : 0 : if (ret) {
376 : 0 : evt_err("failed to setup producer port %d", port);
377 : 0 : return ret;
378 : : }
379 : :
380 : : return ret;
381 : : }
|