numam-dpdk/app/test-eventdev/test_order_common.c
Feifei Wang d97428bfb9 app/eventdev: remove unnecessary barrier from order test
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>
2021-06-30 08:48:55 +02:00

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;
}