d97428bfb9
For "order_launch_lcores" function, wmb after that the main lcore updates the variable "t->err", which represents the end of the test signal, is unnecessary. Because after the main lcore updates this signal variable, it will jump out of the launch function loop, and wait other lcores stop or return error in the main function(evt_main.c). During this time, there is no storing operation and thus no need for wmb. Signed-off-by: Feifei Wang <feifei.wang2@arm.com> Reviewed-by: Ruifeng Wang <ruifeng.wang@arm.com> Reviewed-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com> Acked-by: Jerin Jacob <jerinj@marvell.com>
383 lines
9.0 KiB
C
383 lines
9.0 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2017 Cavium, Inc
|
|
*/
|
|
|
|
#include "test_order_common.h"
|
|
|
|
int
|
|
order_test_result(struct evt_test *test, struct evt_options *opt)
|
|
{
|
|
RTE_SET_USED(opt);
|
|
struct test_order *t = evt_test_priv(test);
|
|
|
|
return t->result;
|
|
}
|
|
|
|
static inline int
|
|
order_producer(void *arg)
|
|
{
|
|
struct prod_data *p = arg;
|
|
struct test_order *t = p->t;
|
|
struct evt_options *opt = t->opt;
|
|
const uint8_t dev_id = p->dev_id;
|
|
const uint8_t port = p->port_id;
|
|
struct rte_mempool *pool = t->pool;
|
|
const uint64_t nb_pkts = t->nb_pkts;
|
|
uint32_t *producer_flow_seq = t->producer_flow_seq;
|
|
const uint32_t nb_flows = t->nb_flows;
|
|
uint64_t count = 0;
|
|
struct rte_mbuf *m;
|
|
struct rte_event ev;
|
|
|
|
if (opt->verbose_level > 1)
|
|
printf("%s(): lcore %d dev_id %d port=%d queue=%d\n",
|
|
__func__, rte_lcore_id(), dev_id, port, p->queue_id);
|
|
|
|
ev.event = 0;
|
|
ev.op = RTE_EVENT_OP_NEW;
|
|
ev.queue_id = p->queue_id;
|
|
ev.sched_type = RTE_SCHED_TYPE_ORDERED;
|
|
ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
|
|
ev.event_type = RTE_EVENT_TYPE_CPU;
|
|
ev.sub_event_type = 0; /* stage 0 */
|
|
|
|
while (count < nb_pkts && t->err == false) {
|
|
m = rte_pktmbuf_alloc(pool);
|
|
if (m == NULL)
|
|
continue;
|
|
|
|
const flow_id_t flow = (uintptr_t)m % nb_flows;
|
|
/* Maintain seq number per flow */
|
|
*order_mbuf_seqn(t, m) = producer_flow_seq[flow]++;
|
|
order_flow_id_save(t, flow, m, &ev);
|
|
|
|
while (rte_event_enqueue_burst(dev_id, port, &ev, 1) != 1) {
|
|
if (t->err)
|
|
break;
|
|
rte_pause();
|
|
}
|
|
|
|
count++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
order_opt_check(struct evt_options *opt)
|
|
{
|
|
if (opt->prod_type != EVT_PROD_TYPE_SYNT) {
|
|
evt_err("Invalid producer type '%s' valid producer '%s'",
|
|
evt_prod_id_to_name(opt->prod_type),
|
|
evt_prod_id_to_name(EVT_PROD_TYPE_SYNT));
|
|
return -1;
|
|
}
|
|
|
|
/* 1 producer + N workers + main */
|
|
if (rte_lcore_count() < 3) {
|
|
evt_err("test need minimum 3 lcores");
|
|
return -1;
|
|
}
|
|
|
|
/* Validate worker lcores */
|
|
if (evt_lcores_has_overlap(opt->wlcores, rte_get_main_lcore())) {
|
|
evt_err("worker lcores overlaps with main lcore");
|
|
return -1;
|
|
}
|
|
|
|
if (evt_nr_active_lcores(opt->plcores) == 0) {
|
|
evt_err("missing the producer lcore");
|
|
return -1;
|
|
}
|
|
|
|
if (evt_nr_active_lcores(opt->plcores) != 1) {
|
|
evt_err("only one producer lcore must be selected");
|
|
return -1;
|
|
}
|
|
|
|
int plcore = evt_get_first_active_lcore(opt->plcores);
|
|
|
|
if (plcore < 0) {
|
|
evt_err("failed to find active producer");
|
|
return plcore;
|
|
}
|
|
|
|
if (evt_lcores_has_overlap(opt->wlcores, plcore)) {
|
|
evt_err("worker lcores overlaps producer lcore");
|
|
return -1;
|
|
}
|
|
if (evt_has_disabled_lcore(opt->wlcores)) {
|
|
evt_err("one or more workers lcores are not enabled");
|
|
return -1;
|
|
}
|
|
if (!evt_has_active_lcore(opt->wlcores)) {
|
|
evt_err("minimum one worker is required");
|
|
return -1;
|
|
}
|
|
|
|
/* Validate producer lcore */
|
|
if (plcore == (int)rte_get_main_lcore()) {
|
|
evt_err("producer lcore and main lcore should be different");
|
|
return -1;
|
|
}
|
|
if (!rte_lcore_is_enabled(plcore)) {
|
|
evt_err("producer lcore is not enabled");
|
|
return -1;
|
|
}
|
|
|
|
/* Fixups */
|
|
if (opt->nb_pkts == 0)
|
|
opt->nb_pkts = INT64_MAX;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
order_test_setup(struct evt_test *test, struct evt_options *opt)
|
|
{
|
|
void *test_order;
|
|
struct test_order *t;
|
|
static const struct rte_mbuf_dynfield flow_id_dynfield_desc = {
|
|
.name = "test_event_dynfield_flow_id",
|
|
.size = sizeof(flow_id_t),
|
|
.align = __alignof__(flow_id_t),
|
|
};
|
|
static const struct rte_mbuf_dynfield seqn_dynfield_desc = {
|
|
.name = "test_event_dynfield_seqn",
|
|
.size = sizeof(seqn_t),
|
|
.align = __alignof__(seqn_t),
|
|
};
|
|
|
|
test_order = rte_zmalloc_socket(test->name, sizeof(struct test_order),
|
|
RTE_CACHE_LINE_SIZE, opt->socket_id);
|
|
if (test_order == NULL) {
|
|
evt_err("failed to allocate test_order memory");
|
|
goto nomem;
|
|
}
|
|
test->test_priv = test_order;
|
|
t = evt_test_priv(test);
|
|
|
|
t->flow_id_dynfield_offset =
|
|
rte_mbuf_dynfield_register(&flow_id_dynfield_desc);
|
|
if (t->flow_id_dynfield_offset < 0) {
|
|
evt_err("failed to register mbuf field");
|
|
return -rte_errno;
|
|
}
|
|
|
|
t->seqn_dynfield_offset =
|
|
rte_mbuf_dynfield_register(&seqn_dynfield_desc);
|
|
if (t->seqn_dynfield_offset < 0) {
|
|
evt_err("failed to register mbuf field");
|
|
return -rte_errno;
|
|
}
|
|
|
|
t->producer_flow_seq = rte_zmalloc_socket("test_producer_flow_seq",
|
|
sizeof(*t->producer_flow_seq) * opt->nb_flows,
|
|
RTE_CACHE_LINE_SIZE, opt->socket_id);
|
|
|
|
if (t->producer_flow_seq == NULL) {
|
|
evt_err("failed to allocate t->producer_flow_seq memory");
|
|
goto prod_nomem;
|
|
}
|
|
|
|
t->expected_flow_seq = rte_zmalloc_socket("test_expected_flow_seq",
|
|
sizeof(*t->expected_flow_seq) * opt->nb_flows,
|
|
RTE_CACHE_LINE_SIZE, opt->socket_id);
|
|
|
|
if (t->expected_flow_seq == NULL) {
|
|
evt_err("failed to allocate t->expected_flow_seq memory");
|
|
goto exp_nomem;
|
|
}
|
|
rte_atomic64_set(&t->outstand_pkts, opt->nb_pkts);
|
|
t->err = false;
|
|
t->nb_pkts = opt->nb_pkts;
|
|
t->nb_flows = opt->nb_flows;
|
|
t->result = EVT_TEST_FAILED;
|
|
t->opt = opt;
|
|
return 0;
|
|
|
|
exp_nomem:
|
|
rte_free(t->producer_flow_seq);
|
|
prod_nomem:
|
|
rte_free(test->test_priv);
|
|
nomem:
|
|
return -ENOMEM;
|
|
}
|
|
|
|
void
|
|
order_test_destroy(struct evt_test *test, struct evt_options *opt)
|
|
{
|
|
RTE_SET_USED(opt);
|
|
struct test_order *t = evt_test_priv(test);
|
|
|
|
rte_free(t->expected_flow_seq);
|
|
rte_free(t->producer_flow_seq);
|
|
rte_free(test->test_priv);
|
|
}
|
|
|
|
int
|
|
order_mempool_setup(struct evt_test *test, struct evt_options *opt)
|
|
{
|
|
struct test_order *t = evt_test_priv(test);
|
|
|
|
t->pool = rte_pktmbuf_pool_create(test->name, opt->pool_sz,
|
|
256 /* Cache */, 0,
|
|
512, /* Use very small mbufs */
|
|
opt->socket_id);
|
|
if (t->pool == NULL) {
|
|
evt_err("failed to create mempool");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
order_mempool_destroy(struct evt_test *test, struct evt_options *opt)
|
|
{
|
|
RTE_SET_USED(opt);
|
|
struct test_order *t = evt_test_priv(test);
|
|
|
|
rte_mempool_free(t->pool);
|
|
}
|
|
|
|
void
|
|
order_eventdev_destroy(struct evt_test *test, struct evt_options *opt)
|
|
{
|
|
RTE_SET_USED(test);
|
|
|
|
rte_event_dev_stop(opt->dev_id);
|
|
rte_event_dev_close(opt->dev_id);
|
|
}
|
|
|
|
void
|
|
order_opt_dump(struct evt_options *opt)
|
|
{
|
|
evt_dump_producer_lcores(opt);
|
|
evt_dump("nb_wrker_lcores", "%d", evt_nr_active_lcores(opt->wlcores));
|
|
evt_dump_worker_lcores(opt);
|
|
evt_dump("nb_evdev_ports", "%d", order_nb_event_ports(opt));
|
|
}
|
|
|
|
int
|
|
order_launch_lcores(struct evt_test *test, struct evt_options *opt,
|
|
int (*worker)(void *))
|
|
{
|
|
int ret, lcore_id;
|
|
struct test_order *t = evt_test_priv(test);
|
|
|
|
int wkr_idx = 0;
|
|
/* launch workers */
|
|
RTE_LCORE_FOREACH_WORKER(lcore_id) {
|
|
if (!(opt->wlcores[lcore_id]))
|
|
continue;
|
|
|
|
ret = rte_eal_remote_launch(worker, &t->worker[wkr_idx],
|
|
lcore_id);
|
|
if (ret) {
|
|
evt_err("failed to launch worker %d", lcore_id);
|
|
return ret;
|
|
}
|
|
wkr_idx++;
|
|
}
|
|
|
|
/* launch producer */
|
|
int plcore = evt_get_first_active_lcore(opt->plcores);
|
|
|
|
ret = rte_eal_remote_launch(order_producer, &t->prod, plcore);
|
|
if (ret) {
|
|
evt_err("failed to launch order_producer %d", plcore);
|
|
return ret;
|
|
}
|
|
|
|
uint64_t cycles = rte_get_timer_cycles();
|
|
int64_t old_remaining = -1;
|
|
|
|
while (t->err == false) {
|
|
uint64_t new_cycles = rte_get_timer_cycles();
|
|
int64_t remaining = rte_atomic64_read(&t->outstand_pkts);
|
|
|
|
if (remaining <= 0) {
|
|
t->result = EVT_TEST_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if (new_cycles - cycles > rte_get_timer_hz() * 1) {
|
|
printf(CLGRN"\r%"PRId64""CLNRM, remaining);
|
|
fflush(stdout);
|
|
if (old_remaining == remaining) {
|
|
rte_event_dev_dump(opt->dev_id, stdout);
|
|
evt_err("No schedules for seconds, deadlock");
|
|
t->err = true;
|
|
break;
|
|
}
|
|
old_remaining = remaining;
|
|
cycles = new_cycles;
|
|
}
|
|
}
|
|
printf("\r");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
order_event_dev_port_setup(struct evt_test *test, struct evt_options *opt,
|
|
uint8_t nb_workers, uint8_t nb_queues)
|
|
{
|
|
int ret;
|
|
uint8_t port;
|
|
struct test_order *t = evt_test_priv(test);
|
|
struct rte_event_dev_info dev_info;
|
|
|
|
memset(&dev_info, 0, sizeof(struct rte_event_dev_info));
|
|
ret = rte_event_dev_info_get(opt->dev_id, &dev_info);
|
|
if (ret) {
|
|
evt_err("failed to get eventdev info %d", opt->dev_id);
|
|
return ret;
|
|
}
|
|
|
|
if (opt->wkr_deq_dep > dev_info.max_event_port_dequeue_depth)
|
|
opt->wkr_deq_dep = dev_info.max_event_port_dequeue_depth;
|
|
|
|
/* port configuration */
|
|
const struct rte_event_port_conf p_conf = {
|
|
.dequeue_depth = opt->wkr_deq_dep,
|
|
.enqueue_depth = dev_info.max_event_port_dequeue_depth,
|
|
.new_event_threshold = dev_info.max_num_events,
|
|
};
|
|
|
|
/* setup one port per worker, linking to all queues */
|
|
for (port = 0; port < nb_workers; port++) {
|
|
struct worker_data *w = &t->worker[port];
|
|
|
|
w->dev_id = opt->dev_id;
|
|
w->port_id = port;
|
|
w->t = t;
|
|
|
|
ret = rte_event_port_setup(opt->dev_id, port, &p_conf);
|
|
if (ret) {
|
|
evt_err("failed to setup port %d", port);
|
|
return ret;
|
|
}
|
|
|
|
ret = rte_event_port_link(opt->dev_id, port, NULL, NULL, 0);
|
|
if (ret != nb_queues) {
|
|
evt_err("failed to link all queues to port %d", port);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
struct prod_data *p = &t->prod;
|
|
|
|
p->dev_id = opt->dev_id;
|
|
p->port_id = port; /* last port */
|
|
p->queue_id = 0;
|
|
p->t = t;
|
|
|
|
ret = rte_event_port_setup(opt->dev_id, port, &p_conf);
|
|
if (ret) {
|
|
evt_err("failed to setup producer port %d", port);
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|