80e14c08dbd3511d594076e2e7aa231dd79e523d
[deb_dpdk.git] / app / test-eventdev / test_order_common.c
1 /*
2  *   BSD LICENSE
3  *
4  *   Copyright (C) Cavium, Inc 2017.
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in
14  *       the documentation and/or other materials provided with the
15  *       distribution.
16  *     * Neither the name of Cavium, Inc nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "test_order_common.h"
34
35 int
36 order_test_result(struct evt_test *test, struct evt_options *opt)
37 {
38         RTE_SET_USED(opt);
39         struct test_order *t = evt_test_priv(test);
40
41         return t->result;
42 }
43
44 static inline int
45 order_producer(void *arg)
46 {
47         struct prod_data *p  = arg;
48         struct test_order *t = p->t;
49         struct evt_options *opt = t->opt;
50         const uint8_t dev_id = p->dev_id;
51         const uint8_t port = p->port_id;
52         struct rte_mempool *pool = t->pool;
53         const uint64_t nb_pkts = t->nb_pkts;
54         uint32_t *producer_flow_seq = t->producer_flow_seq;
55         const uint32_t nb_flows = t->nb_flows;
56         uint64_t count = 0;
57         struct rte_mbuf *m;
58         struct rte_event ev;
59
60         if (opt->verbose_level > 1)
61                 printf("%s(): lcore %d dev_id %d port=%d queue=%d\n",
62                          __func__, rte_lcore_id(), dev_id, port, p->queue_id);
63
64         ev.event = 0;
65         ev.op = RTE_EVENT_OP_NEW;
66         ev.queue_id = p->queue_id;
67         ev.sched_type = RTE_SCHED_TYPE_ORDERED;
68         ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
69         ev.event_type =  RTE_EVENT_TYPE_CPU;
70         ev.sub_event_type = 0; /* stage 0 */
71
72         while (count < nb_pkts && t->err == false) {
73                 m = rte_pktmbuf_alloc(pool);
74                 if (m == NULL)
75                         continue;
76
77                 const uint32_t flow = (uintptr_t)m % nb_flows;
78                 /* Maintain seq number per flow */
79                 m->seqn = producer_flow_seq[flow]++;
80
81                 ev.flow_id = flow;
82                 ev.mbuf = m;
83
84                 while (rte_event_enqueue_burst(dev_id, port, &ev, 1) != 1) {
85                         if (t->err)
86                                 break;
87                         rte_pause();
88                 }
89
90                 count++;
91         }
92         return 0;
93 }
94
95 int
96 order_opt_check(struct evt_options *opt)
97 {
98         /* 1 producer + N workers + 1 master */
99         if (rte_lcore_count() < 3) {
100                 evt_err("test need minimum 3 lcores");
101                 return -1;
102         }
103
104         /* Validate worker lcores */
105         if (evt_lcores_has_overlap(opt->wlcores, rte_get_master_lcore())) {
106                 evt_err("worker lcores overlaps with master lcore");
107                 return -1;
108         }
109
110         if (evt_nr_active_lcores(opt->plcores) == 0) {
111                 evt_err("missing the producer lcore");
112                 return -1;
113         }
114
115         if (evt_nr_active_lcores(opt->plcores) != 1) {
116                 evt_err("only one producer lcore must be selected");
117                 return -1;
118         }
119
120         int plcore = evt_get_first_active_lcore(opt->plcores);
121
122         if (plcore < 0) {
123                 evt_err("failed to find active producer");
124                 return plcore;
125         }
126
127         if (evt_lcores_has_overlap(opt->wlcores, plcore)) {
128                 evt_err("worker lcores overlaps producer lcore");
129                 return -1;
130         }
131         if (evt_has_disabled_lcore(opt->wlcores)) {
132                 evt_err("one or more workers lcores are not enabled");
133                 return -1;
134         }
135         if (!evt_has_active_lcore(opt->wlcores)) {
136                 evt_err("minimum one worker is required");
137                 return -1;
138         }
139
140         /* Validate producer lcore */
141         if (plcore == (int)rte_get_master_lcore()) {
142                 evt_err("producer lcore and master lcore should be different");
143                 return -1;
144         }
145         if (!rte_lcore_is_enabled(plcore)) {
146                 evt_err("producer lcore is not enabled");
147                 return -1;
148         }
149
150         /* Fixups */
151         if (opt->nb_pkts == 0)
152                 opt->nb_pkts = INT64_MAX;
153
154         return 0;
155 }
156
157 int
158 order_test_setup(struct evt_test *test, struct evt_options *opt)
159 {
160         void *test_order;
161
162         test_order = rte_zmalloc_socket(test->name, sizeof(struct test_order),
163                                 RTE_CACHE_LINE_SIZE, opt->socket_id);
164         if (test_order  == NULL) {
165                 evt_err("failed to allocate test_order memory");
166                 goto nomem;
167         }
168         test->test_priv = test_order;
169
170         struct test_order *t = evt_test_priv(test);
171
172         t->producer_flow_seq = rte_zmalloc_socket("test_producer_flow_seq",
173                                  sizeof(*t->producer_flow_seq) * opt->nb_flows,
174                                 RTE_CACHE_LINE_SIZE, opt->socket_id);
175
176         if (t->producer_flow_seq  == NULL) {
177                 evt_err("failed to allocate t->producer_flow_seq memory");
178                 goto prod_nomem;
179         }
180
181         t->expected_flow_seq = rte_zmalloc_socket("test_expected_flow_seq",
182                                  sizeof(*t->expected_flow_seq) * opt->nb_flows,
183                                 RTE_CACHE_LINE_SIZE, opt->socket_id);
184
185         if (t->expected_flow_seq  == NULL) {
186                 evt_err("failed to allocate t->expected_flow_seq memory");
187                 goto exp_nomem;
188         }
189         rte_atomic64_set(&t->outstand_pkts, opt->nb_pkts);
190         t->err = false;
191         t->nb_pkts = opt->nb_pkts;
192         t->nb_flows = opt->nb_flows;
193         t->result = EVT_TEST_FAILED;
194         t->opt = opt;
195         return 0;
196
197 exp_nomem:
198         rte_free(t->producer_flow_seq);
199 prod_nomem:
200         rte_free(test->test_priv);
201 nomem:
202         return -ENOMEM;
203 }
204
205 void
206 order_test_destroy(struct evt_test *test, struct evt_options *opt)
207 {
208         RTE_SET_USED(opt);
209         struct test_order *t = evt_test_priv(test);
210
211         rte_free(t->expected_flow_seq);
212         rte_free(t->producer_flow_seq);
213         rte_free(test->test_priv);
214 }
215
216 int
217 order_mempool_setup(struct evt_test *test, struct evt_options *opt)
218 {
219         struct test_order *t = evt_test_priv(test);
220
221         t->pool  = rte_pktmbuf_pool_create(test->name, opt->pool_sz,
222                                         256 /* Cache */, 0,
223                                         512, /* Use very small mbufs */
224                                         opt->socket_id);
225         if (t->pool == NULL) {
226                 evt_err("failed to create mempool");
227                 return -ENOMEM;
228         }
229
230         return 0;
231 }
232
233 void
234 order_mempool_destroy(struct evt_test *test, struct evt_options *opt)
235 {
236         RTE_SET_USED(opt);
237         struct test_order *t = evt_test_priv(test);
238
239         rte_mempool_free(t->pool);
240 }
241
242 void
243 order_eventdev_destroy(struct evt_test *test, struct evt_options *opt)
244 {
245         RTE_SET_USED(test);
246
247         rte_event_dev_stop(opt->dev_id);
248         rte_event_dev_close(opt->dev_id);
249 }
250
251 void
252 order_opt_dump(struct evt_options *opt)
253 {
254         evt_dump_producer_lcores(opt);
255         evt_dump("nb_wrker_lcores", "%d", evt_nr_active_lcores(opt->wlcores));
256         evt_dump_worker_lcores(opt);
257         evt_dump("nb_evdev_ports", "%d", order_nb_event_ports(opt));
258 }
259
260 int
261 order_launch_lcores(struct evt_test *test, struct evt_options *opt,
262                         int (*worker)(void *))
263 {
264         int ret, lcore_id;
265         struct test_order *t = evt_test_priv(test);
266
267         int wkr_idx = 0;
268         /* launch workers */
269         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
270                 if (!(opt->wlcores[lcore_id]))
271                         continue;
272
273                 ret = rte_eal_remote_launch(worker, &t->worker[wkr_idx],
274                                          lcore_id);
275                 if (ret) {
276                         evt_err("failed to launch worker %d", lcore_id);
277                         return ret;
278                 }
279                 wkr_idx++;
280         }
281
282         /* launch producer */
283         int plcore = evt_get_first_active_lcore(opt->plcores);
284
285         ret = rte_eal_remote_launch(order_producer, &t->prod, plcore);
286         if (ret) {
287                 evt_err("failed to launch order_producer %d", plcore);
288                 return ret;
289         }
290
291         uint64_t cycles = rte_get_timer_cycles();
292         int64_t old_remaining  = -1;
293
294         while (t->err == false) {
295
296                 rte_event_schedule(opt->dev_id);
297
298                 uint64_t new_cycles = rte_get_timer_cycles();
299                 int64_t remaining = rte_atomic64_read(&t->outstand_pkts);
300
301                 if (remaining <= 0) {
302                         t->result = EVT_TEST_SUCCESS;
303                         break;
304                 }
305
306                 if (new_cycles - cycles > rte_get_timer_hz() * 1) {
307                         printf(CLGRN"\r%"PRId64""CLNRM, remaining);
308                         fflush(stdout);
309                         if (old_remaining == remaining) {
310                                 rte_event_dev_dump(opt->dev_id, stdout);
311                                 evt_err("No schedules for seconds, deadlock");
312                                 t->err = true;
313                                 rte_smp_wmb();
314                                 break;
315                         }
316                         old_remaining = remaining;
317                         cycles = new_cycles;
318                 }
319         }
320         printf("\r");
321
322         return 0;
323 }
324
325 int
326 order_event_dev_port_setup(struct evt_test *test, struct evt_options *opt,
327                                 uint8_t nb_workers, uint8_t nb_queues)
328 {
329         int ret;
330         uint8_t port;
331         struct test_order *t = evt_test_priv(test);
332
333         /* port configuration */
334         const struct rte_event_port_conf wkr_p_conf = {
335                         .dequeue_depth = opt->wkr_deq_dep,
336                         .enqueue_depth = 64,
337                         .new_event_threshold = 4096,
338         };
339
340         /* setup one port per worker, linking to all queues */
341         for (port = 0; port < nb_workers; port++) {
342                 struct worker_data *w = &t->worker[port];
343
344                 w->dev_id = opt->dev_id;
345                 w->port_id = port;
346                 w->t = t;
347
348                 ret = rte_event_port_setup(opt->dev_id, port, &wkr_p_conf);
349                 if (ret) {
350                         evt_err("failed to setup port %d", port);
351                         return ret;
352                 }
353
354                 ret = rte_event_port_link(opt->dev_id, port, NULL, NULL, 0);
355                 if (ret != nb_queues) {
356                         evt_err("failed to link all queues to port %d", port);
357                         return -EINVAL;
358                 }
359         }
360         /* port for producer, no links */
361         const struct rte_event_port_conf prod_conf = {
362                         .dequeue_depth = 8,
363                         .enqueue_depth = 32,
364                         .new_event_threshold = 1200,
365         };
366         struct prod_data *p = &t->prod;
367
368         p->dev_id = opt->dev_id;
369         p->port_id = port; /* last port */
370         p->queue_id = 0;
371         p->t = t;
372
373         ret = rte_event_port_setup(opt->dev_id, port, &prod_conf);
374         if (ret) {
375                 evt_err("failed to setup producer port %d", port);
376                 return ret;
377         }
378
379         return ret;
380 }