opt->pool_sz = 16 * 1024;
opt->wkr_deq_dep = 16;
opt->nb_pkts = (1ULL << 26); /* do ~64M packets */
+ opt->nb_timers = 1E8;
+ opt->nb_timer_adptrs = 1;
+ opt->timer_tick_nsec = 1E3; /* 1000ns ~ 1us */
+ opt->max_tmo_nsec = 1E5; /* 100000ns ~100us */
+ opt->expiry_nsec = 1E4; /* 10000ns ~10us */
opt->prod_type = EVT_PROD_TYPE_SYNT;
}
return 0;
}
+static int
+evt_parse_timer_prod_type(struct evt_options *opt, const char *arg __rte_unused)
+{
+ opt->prod_type = EVT_PROD_TYPE_EVENT_TIMER_ADPTR;
+ return 0;
+}
+
static int
evt_parse_test_name(struct evt_options *opt, const char *arg)
{
"\t--worker_deq_depth : dequeue depth of the worker\n"
"\t--fwd_latency : perform fwd_latency measurement\n"
"\t--queue_priority : enable queue priority\n"
- "\t--prod_type_ethdev : use ethernet device as producer\n."
+ "\t--prod_type_ethdev : use ethernet device as producer.\n"
+ "\t--prod_type_timerdev : use event timer device as producer.\n"
+ "\t expity_nsec would be the timeout\n"
+ "\t in ns.\n"
);
printf("available tests:\n");
evt_test_dump_names();
}
static struct option lgopts[] = {
- { EVT_NB_FLOWS, 1, 0, 0 },
- { EVT_DEVICE, 1, 0, 0 },
- { EVT_VERBOSE, 1, 0, 0 },
- { EVT_TEST, 1, 0, 0 },
- { EVT_PROD_LCORES, 1, 0, 0 },
- { EVT_WORK_LCORES, 1, 0, 0 },
- { EVT_SOCKET_ID, 1, 0, 0 },
- { EVT_POOL_SZ, 1, 0, 0 },
- { EVT_NB_PKTS, 1, 0, 0 },
- { EVT_WKR_DEQ_DEP, 1, 0, 0 },
- { EVT_SCHED_TYPE_LIST, 1, 0, 0 },
- { EVT_FWD_LATENCY, 0, 0, 0 },
- { EVT_QUEUE_PRIORITY, 0, 0, 0 },
- { EVT_PROD_ETHDEV, 0, 0, 0 },
- { EVT_HELP, 0, 0, 0 },
- { NULL, 0, 0, 0 }
+ { EVT_NB_FLOWS, 1, 0, 0 },
+ { EVT_DEVICE, 1, 0, 0 },
+ { EVT_VERBOSE, 1, 0, 0 },
+ { EVT_TEST, 1, 0, 0 },
+ { EVT_PROD_LCORES, 1, 0, 0 },
+ { EVT_WORK_LCORES, 1, 0, 0 },
+ { EVT_SOCKET_ID, 1, 0, 0 },
+ { EVT_POOL_SZ, 1, 0, 0 },
+ { EVT_NB_PKTS, 1, 0, 0 },
+ { EVT_WKR_DEQ_DEP, 1, 0, 0 },
+ { EVT_SCHED_TYPE_LIST, 1, 0, 0 },
+ { EVT_FWD_LATENCY, 0, 0, 0 },
+ { EVT_QUEUE_PRIORITY, 0, 0, 0 },
+ { EVT_PROD_ETHDEV, 0, 0, 0 },
+ { EVT_PROD_TIMERDEV, 0, 0, 0 },
+ { EVT_HELP, 0, 0, 0 },
+ { NULL, 0, 0, 0 }
};
static int
{ EVT_FWD_LATENCY, evt_parse_fwd_latency},
{ EVT_QUEUE_PRIORITY, evt_parse_queue_priority},
{ EVT_PROD_ETHDEV, evt_parse_eth_prod_type},
+ { EVT_PROD_TIMERDEV, evt_parse_timer_prod_type},
};
for (i = 0; i < RTE_DIM(parsermap); i++) {
if (strncmp(lgopts[opt_idx].name, parsermap[i].lgopt_name,
- strlen(parsermap[i].lgopt_name)) == 0)
+ strlen(lgopts[opt_idx].name)) == 0)
return parsermap[i].parser_fn(opt, optarg);
}
evt_dump("pool_sz", "%d", opt->pool_sz);
evt_dump("master lcore", "%d", rte_get_master_lcore());
evt_dump("nb_pkts", "%"PRIu64, opt->nb_pkts);
+ evt_dump("nb_timers", "%"PRIu64, opt->nb_timers);
evt_dump_begin("available lcores");
RTE_LCORE_FOREACH(lcore_id)
printf("%d ", lcore_id);
#include <stdbool.h>
#include <rte_common.h>
+#include <rte_ethdev.h>
#include <rte_eventdev.h>
#include <rte_lcore.h>
#define EVT_FWD_LATENCY ("fwd_latency")
#define EVT_QUEUE_PRIORITY ("queue_priority")
#define EVT_PROD_ETHDEV ("prod_type_ethdev")
+#define EVT_PROD_TIMERDEV ("prod_type_timerdev")
#define EVT_HELP ("help")
enum evt_prod_type {
EVT_PROD_TYPE_NONE,
EVT_PROD_TYPE_SYNT, /* Producer type Synthetic i.e. CPU. */
EVT_PROD_TYPE_ETH_RX_ADPTR, /* Producer type Eth Rx Adapter. */
+ EVT_PROD_TYPE_EVENT_TIMER_ADPTR, /* Producer type Timer Adapter. */
EVT_PROD_TYPE_MAX,
};
int nb_stages;
int verbose_level;
uint64_t nb_pkts;
+ uint8_t nb_timer_adptrs;
+ uint64_t nb_timers;
+ uint64_t timer_tick_nsec;
+ uint64_t optm_timer_tick_nsec;
+ uint64_t max_tmo_nsec;
+ uint64_t expiry_nsec;
uint16_t wkr_deq_dep;
uint8_t dev_id;
uint32_t fwd_latency:1;
uint32_t q_priority:1;
enum evt_prod_type prod_type;
+ uint8_t timdev_cnt;
};
void evt_options_default(struct evt_options *opt);
case EVT_PROD_TYPE_ETH_RX_ADPTR:
snprintf(name, EVT_PROD_MAX_NAME_LEN,
"Ethdev Rx Adapter producers");
+ evt_dump("nb_ethdev", "%d", rte_eth_dev_count());
+ break;
+ case EVT_PROD_TYPE_EVENT_TIMER_ADPTR:
+ snprintf(name, EVT_PROD_MAX_NAME_LEN,
+ "Event timer adapter producer");
+ evt_dump("nb_timer_adapters", "%d", opt->nb_timer_adptrs);
+ evt_dump("max_tmo_nsec", "%"PRIu64"", opt->max_tmo_nsec);
+ evt_dump("expiry_nsec", "%"PRIu64"", opt->expiry_nsec);
+ if (opt->optm_timer_tick_nsec)
+ evt_dump("optm_timer_tick_ns", "%"PRIu64"",
+ opt->optm_timer_tick_nsec);
+ else
+ evt_dump("timer_tick_ns", "%"PRIu64"",
+ opt->timer_tick_nsec);
break;
}
evt_dump("prod_type", "%s", name);
while (t->done == false) {
uint16_t event = rte_event_dequeue_burst(dev, port, &ev, 1, 0);
- if (enable_fwd_latency)
- rte_prefetch0(ev.event_ptr);
-
if (!event) {
rte_pause();
continue;
}
- if (enable_fwd_latency)
+ if (enable_fwd_latency && !prod_timer_type)
/* first stage in pipeline, mark ts to compute fwd latency */
atq_mark_fwd_latency(&ev);
}
for (i = 0; i < nb_rx; i++) {
- if (enable_fwd_latency) {
+ if (enable_fwd_latency && !prod_timer_type) {
rte_prefetch0(ev[i+1].event_ptr);
/* first stage in pipeline.
* mark time stamp to compute fwd latency
struct rte_event_dev_info dev_info;
nb_ports = evt_nr_active_lcores(opt->wlcores);
- nb_ports += opt->prod_type == EVT_PROD_TYPE_ETH_RX_ADPTR ? 0 :
+ nb_ports += (opt->prod_type == EVT_PROD_TYPE_ETH_RX_ADPTR ||
+ opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR) ? 0 :
evt_nr_active_lcores(opt->plcores);
nb_queues = atq_nb_event_queues(opt);
return 0;
}
+static inline int
+perf_event_timer_producer(void *arg)
+{
+ struct prod_data *p = arg;
+ struct test_perf *t = p->t;
+ struct evt_options *opt = t->opt;
+ uint32_t flow_counter = 0;
+ uint64_t count = 0;
+ uint64_t arm_latency = 0;
+ const uint8_t nb_timer_adptrs = opt->nb_timer_adptrs;
+ const uint32_t nb_flows = t->nb_flows;
+ const uint64_t nb_timers = opt->nb_timers;
+ struct rte_mempool *pool = t->pool;
+ struct perf_elt *m;
+ struct rte_event_timer_adapter **adptr = t->timer_adptr;
+ uint64_t timeout_ticks = opt->expiry_nsec / opt->timer_tick_nsec;
+
+ timeout_ticks = opt->optm_timer_tick_nsec ?
+ (timeout_ticks * opt->timer_tick_nsec)
+ / opt->optm_timer_tick_nsec : timeout_ticks;
+ timeout_ticks += timeout_ticks ? 0 : 1;
+ const struct rte_event_timer tim = {
+ .ev.op = RTE_EVENT_OP_NEW,
+ .ev.queue_id = p->queue_id,
+ .ev.sched_type = t->opt->sched_type_list[0],
+ .ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+ .ev.event_type = RTE_EVENT_TYPE_TIMER,
+ .state = RTE_EVENT_TIMER_NOT_ARMED,
+ .timeout_ticks = timeout_ticks,
+ };
+
+ if (opt->verbose_level > 1)
+ printf("%s(): lcore %d\n", __func__, rte_lcore_id());
+
+ while (count < nb_timers && t->done == false) {
+ if (rte_mempool_get(pool, (void **)&m) < 0)
+ continue;
+
+ m->tim = tim;
+ m->tim.ev.flow_id = flow_counter++ % nb_flows;
+ m->tim.ev.event_ptr = m;
+ m->timestamp = rte_get_timer_cycles();
+ while (rte_event_timer_arm_burst(
+ adptr[flow_counter % nb_timer_adptrs],
+ (struct rte_event_timer **)&m, 1) != 1) {
+ if (t->done)
+ break;
+ rte_pause();
+ m->timestamp = rte_get_timer_cycles();
+ }
+ arm_latency += rte_get_timer_cycles() - m->timestamp;
+ count++;
+ }
+ fflush(stdout);
+ rte_delay_ms(1000);
+ printf("%s(): lcore %d Average event timer arm latency = %.3f us\n",
+ __func__, rte_lcore_id(), (float)(arm_latency / count) /
+ (rte_get_timer_hz() / 1000000));
+ return 0;
+}
+
static int
perf_producer_wrapper(void *arg)
{
/* Launch the producer function only in case of synthetic producer. */
if (t->opt->prod_type == EVT_PROD_TYPE_SYNT)
return perf_producer(arg);
+ else if (t->opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR)
+ return perf_event_timer_producer(arg);
return 0;
}
port_idx++;
}
- const uint64_t total_pkts = opt->nb_pkts *
- evt_nr_active_lcores(opt->plcores);
+ const uint64_t total_pkts = t->outstand_pkts;
uint64_t dead_lock_cycles = rte_get_timer_cycles();
int64_t dead_lock_remaining = total_pkts;
if (remaining <= 0) {
t->result = EVT_TEST_SUCCESS;
- if (opt->prod_type == EVT_PROD_TYPE_SYNT) {
+ if (opt->prod_type == EVT_PROD_TYPE_SYNT ||
+ opt->prod_type ==
+ EVT_PROD_TYPE_EVENT_TIMER_ADPTR) {
t->done = true;
rte_smp_wmb();
break;
return ret;
}
+static int
+perf_event_timer_adapter_setup(struct test_perf *t)
+{
+ int i;
+ int ret;
+ struct rte_event_timer_adapter_info adapter_info;
+ struct rte_event_timer_adapter *wl;
+ uint8_t nb_producers = evt_nr_active_lcores(t->opt->plcores);
+ uint8_t flags = RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES;
+
+ if (nb_producers == 1)
+ flags |= RTE_EVENT_TIMER_ADAPTER_F_SP_PUT;
+
+ for (i = 0; i < t->opt->nb_timer_adptrs; i++) {
+ struct rte_event_timer_adapter_conf config = {
+ .event_dev_id = t->opt->dev_id,
+ .timer_adapter_id = i,
+ .timer_tick_ns = t->opt->timer_tick_nsec,
+ .max_tmo_ns = t->opt->max_tmo_nsec,
+ .nb_timers = 2 * 1024 * 1024,
+ .flags = flags,
+ };
+
+ wl = rte_event_timer_adapter_create(&config);
+ if (wl == NULL) {
+ evt_err("failed to create event timer ring %d", i);
+ return rte_errno;
+ }
+
+ memset(&adapter_info, 0,
+ sizeof(struct rte_event_timer_adapter_info));
+ rte_event_timer_adapter_get_info(wl, &adapter_info);
+ t->opt->optm_timer_tick_nsec = adapter_info.min_resolution_ns;
+
+ if (!(adapter_info.caps &
+ RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+ uint32_t service_id;
+
+ rte_event_timer_adapter_service_id_get(wl,
+ &service_id);
+ ret = evt_service_setup(service_id);
+ if (ret) {
+ evt_err("Failed to setup service core"
+ " for timer adapter\n");
+ return ret;
+ }
+ rte_service_runstate_set(service_id, 1);
+ }
+
+ ret = rte_event_timer_adapter_start(wl);
+ if (ret) {
+ evt_err("failed to Start event timer adapter %d", i);
+ return ret;
+ }
+ t->timer_adptr[i] = wl;
+ }
+ return 0;
+}
+
int
perf_event_dev_port_setup(struct evt_test *test, struct evt_options *opt,
uint8_t stride, uint8_t nb_queues,
ret = perf_event_rx_adapter_setup(opt, stride, *port_conf);
if (ret)
return ret;
+ } else if (opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR) {
+ prod = 0;
+ for ( ; port < perf_nb_event_ports(opt); port++) {
+ struct prod_data *p = &t->prod[port];
+ p->queue_id = prod * stride;
+ p->t = t;
+ prod++;
+ }
+
+ ret = perf_event_timer_adapter_setup(t);
+ if (ret)
+ return ret;
} else {
prod = 0;
for ( ; port < perf_nb_event_ports(opt); port++) {
}
/* Fixups */
- if (opt->nb_stages == 1 && opt->fwd_latency) {
+ if ((opt->nb_stages == 1 &&
+ opt->prod_type != EVT_PROD_TYPE_EVENT_TIMER_ADPTR) &&
+ opt->fwd_latency) {
evt_info("fwd_latency is valid when nb_stages > 1, disabling");
opt->fwd_latency = 0;
}
+
if (opt->fwd_latency && !opt->q_priority) {
evt_info("enabled queue priority for latency measurement");
opt->q_priority = 1;
void
perf_eventdev_destroy(struct evt_test *test, struct evt_options *opt)
{
- RTE_SET_USED(test);
+ int i;
+ struct test_perf *t = evt_test_priv(test);
+ if (opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR) {
+ for (i = 0; i < opt->nb_timer_adptrs; i++)
+ rte_event_timer_adapter_stop(t->timer_adptr[i]);
+ }
rte_event_dev_stop(opt->dev_id);
rte_event_dev_close(opt->dev_id);
}
},
};
- if (opt->prod_type == EVT_PROD_TYPE_SYNT)
+ if (opt->prod_type == EVT_PROD_TYPE_SYNT ||
+ opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR)
return 0;
if (!rte_eth_dev_count()) {
{
struct test_perf *t = evt_test_priv(test);
- if (opt->prod_type == EVT_PROD_TYPE_SYNT) {
+ if (opt->prod_type == EVT_PROD_TYPE_SYNT ||
+ opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR) {
t->pool = rte_mempool_create(test->name, /* mempool name */
opt->pool_sz, /* number of elements*/
sizeof(struct perf_elt), /* element size*/
struct test_perf *t = evt_test_priv(test);
- t->outstand_pkts = opt->nb_pkts * evt_nr_active_lcores(opt->plcores);
+ if (opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR) {
+ t->outstand_pkts = opt->nb_timers *
+ evt_nr_active_lcores(opt->plcores);
+ t->nb_pkts = opt->nb_timers;
+ } else {
+ t->outstand_pkts = opt->nb_pkts *
+ evt_nr_active_lcores(opt->plcores);
+ t->nb_pkts = opt->nb_pkts;
+ }
+
t->nb_workers = evt_nr_active_lcores(opt->wlcores);
t->done = false;
- t->nb_pkts = opt->nb_pkts;
t->nb_flows = opt->nb_flows;
t->result = EVT_TEST_FAILED;
t->opt = opt;
#include <rte_ethdev.h>
#include <rte_eventdev.h>
#include <rte_event_eth_rx_adapter.h>
+#include <rte_event_timer_adapter.h>
#include <rte_lcore.h>
#include <rte_malloc.h>
#include <rte_mempool.h>
struct test_perf *t;
} __rte_cache_aligned;
+
struct test_perf {
/* Don't change the offset of "done". Signal handler use this memory
* to terminate all lcores work.
struct worker_data worker[EVT_MAX_PORTS];
struct evt_options *opt;
uint8_t sched_type_list[EVT_MAX_STAGES] __rte_cache_aligned;
+ struct rte_event_timer_adapter *timer_adptr[
+ RTE_EVENT_TIMER_ADAPTER_NUM_MAX] __rte_cache_aligned;
} __rte_cache_aligned;
struct perf_elt {
- uint64_t timestamp;
+ union {
+ struct rte_event_timer tim;
+ struct {
+ char pad[offsetof(struct rte_event_timer, user_meta)];
+ uint64_t timestamp;
+ };
+ };
} __rte_cache_aligned;
#define BURST_SIZE 16
struct evt_options *opt = t->opt;\
const uint8_t dev = w->dev_id;\
const uint8_t port = w->port_id;\
+ const uint8_t prod_timer_type = \
+ opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR;\
uint8_t *const sched_type_list = &t->sched_type_list[0];\
struct rte_mempool *const pool = t->pool;\
const uint8_t nb_stages = t->opt->nb_stages;\
rte_pause();
continue;
}
- if (enable_fwd_latency)
+ if (enable_fwd_latency && !prod_timer_type)
/* first q in pipeline, mark timestamp to compute fwd latency */
mark_fwd_latency(&ev, nb_stages);
}
for (i = 0; i < nb_rx; i++) {
- if (enable_fwd_latency) {
+ if (enable_fwd_latency && !prod_timer_type) {
rte_prefetch0(ev[i+1].event_ptr);
/* first queue in pipeline.
* mark time stamp to compute fwd latency
struct rte_event_dev_info dev_info;
nb_ports = evt_nr_active_lcores(opt->wlcores);
- nb_ports += opt->prod_type == EVT_PROD_TYPE_ETH_RX_ADPTR ? 0 :
+ nb_ports += opt->prod_type == EVT_PROD_TYPE_ETH_RX_ADPTR ||
+ opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR ? 0 :
evt_nr_active_lcores(opt->plcores);
nb_queues = perf_queue_nb_event_queues(opt);
Use ethernet device as producer.
+* ``--prod_type_timerdev``
+
+ Use event timer adapter as producer.
+
Eventdev Tests
--------------
--fwd_latency
--queue_priority
--prod_type_ethdev
+ --prod_type_timerdev
Example
^^^^^^^
sudo build/app/dpdk-test-eventdev --vdev=event_sw0 -- \
--test=perf_queue --plcores=2 --wlcore=3 --stlist=p --prod_type_ethdev
+Example command to run perf queue test with event timer adapter:
+
+.. code-block:: console
+
+ sudo build/app/dpdk-test-eventdev --vdev="event_octeontx" -- \
+ --wlcores 4 --plcores 12 --test perf_queue --stlist=a \
+ --prod_type_timerdev --fwd_latency
+
PERF_ATQ Test
~~~~~~~~~~~~~~~
--worker_deq_depth
--fwd_latency
--prod_type_ethdev
+ --prod_type_timerdev
Example
^^^^^^^
sudo build/app/dpdk-test-eventdev --vdev=event_octeontx -- \
--test=perf_atq --plcores=2 --wlcore=3 --stlist=p --nb_pkts=0
+Example command to run perf ``all types queue`` test with event timer adapter:
+
+.. code-block:: console
+
+ sudo build/app/dpdk-test-eventdev --vdev="event_octeontx" -- \
+ --wlcores 4 --plcores 12 --test perf_atq --verbose 20 \
+ --stlist=a --prod_type_timerdev --fwd_latency
+
PIPELINE_QUEUE Test
~~~~~~~~~~~~~~~~~~~