dpdk/app/test-eventdev/test_perf_queue.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2017 Cavium, Inc
   3 */
   4
   5#include "test_perf_common.h"
   6
   7/* See http://doc.dpdk.org/guides/tools/testeventdev.html for test details */
   8
   9static inline int
  10perf_queue_nb_event_queues(struct evt_options *opt)
  11{
  12        /* nb_queues = number of producers * number of stages */
  13        uint8_t nb_prod = opt->prod_type == EVT_PROD_TYPE_ETH_RX_ADPTR ?
  14                rte_eth_dev_count_avail() : evt_nr_active_lcores(opt->plcores);
  15        return nb_prod * opt->nb_stages;
  16}
  17
  18static __rte_always_inline void
  19mark_fwd_latency(struct rte_event *const ev,
  20                const uint8_t nb_stages)
  21{
  22        if (unlikely((ev->queue_id % nb_stages) == 0)) {
  23                struct perf_elt *const m = ev->event_ptr;
  24
  25                m->timestamp = rte_get_timer_cycles();
  26        }
  27}
  28
  29static __rte_always_inline void
  30fwd_event(struct rte_event *const ev, uint8_t *const sched_type_list,
  31                const uint8_t nb_stages)
  32{
  33        ev->queue_id++;
  34        ev->sched_type = sched_type_list[ev->queue_id % nb_stages];
  35        ev->op = RTE_EVENT_OP_FORWARD;
  36        ev->event_type = RTE_EVENT_TYPE_CPU;
  37}
  38
  39static int
  40perf_queue_worker(void *arg, const int enable_fwd_latency)
  41{
  42        PERF_WORKER_INIT;
  43        struct rte_event ev;
  44
  45        while (t->done == false) {
  46                uint16_t event = rte_event_dequeue_burst(dev, port, &ev, 1, 0);
  47
  48                if (!event) {
  49                        rte_pause();
  50                        continue;
  51                }
  52                if (enable_fwd_latency && !prod_timer_type)
  53                /* first q in pipeline, mark timestamp to compute fwd latency */
  54                        mark_fwd_latency(&ev, nb_stages);
  55
  56                /* last stage in pipeline */
  57                if (unlikely((ev.queue_id % nb_stages) == laststage)) {
  58                        if (enable_fwd_latency)
  59                                cnt = perf_process_last_stage_latency(pool,
  60                                        &ev, w, bufs, sz, cnt);
  61                        else
  62                                cnt = perf_process_last_stage(pool,
  63                                        &ev, w, bufs, sz, cnt);
  64                } else {
  65                        fwd_event(&ev, sched_type_list, nb_stages);
  66                        while (rte_event_enqueue_burst(dev, port, &ev, 1) != 1)
  67                                rte_pause();
  68                }
  69        }
  70        return 0;
  71}
  72
  73static int
  74perf_queue_worker_burst(void *arg, const int enable_fwd_latency)
  75{
  76        PERF_WORKER_INIT;
  77        uint16_t i;
  78        /* +1 to avoid prefetch out of array check */
  79        struct rte_event ev[BURST_SIZE + 1];
  80
  81        while (t->done == false) {
  82                uint16_t const nb_rx = rte_event_dequeue_burst(dev, port, ev,
  83                                BURST_SIZE, 0);
  84
  85                if (!nb_rx) {
  86                        rte_pause();
  87                        continue;
  88                }
  89
  90                for (i = 0; i < nb_rx; i++) {
  91                        if (enable_fwd_latency && !prod_timer_type) {
  92                                rte_prefetch0(ev[i+1].event_ptr);
  93                                /* first queue in pipeline.
  94                                 * mark time stamp to compute fwd latency
  95                                 */
  96                                mark_fwd_latency(&ev[i], nb_stages);
  97                        }
  98                        /* last stage in pipeline */
  99                        if (unlikely((ev[i].queue_id % nb_stages) ==
 100                                                 laststage)) {
 101                                if (enable_fwd_latency)
 102                                        cnt = perf_process_last_stage_latency(
 103                                                pool, &ev[i], w, bufs, sz, cnt);
 104                                else
 105                                        cnt = perf_process_last_stage(pool,
 106                                                &ev[i], w, bufs, sz, cnt);
 107
 108                                ev[i].op = RTE_EVENT_OP_RELEASE;
 109                        } else {
 110                                fwd_event(&ev[i], sched_type_list, nb_stages);
 111                        }
 112                }
 113
 114                uint16_t enq;
 115
 116                enq = rte_event_enqueue_burst(dev, port, ev, nb_rx);
 117                while (enq < nb_rx) {
 118                        enq += rte_event_enqueue_burst(dev, port,
 119                                                        ev + enq, nb_rx - enq);
 120                }
 121        }
 122        return 0;
 123}
 124
 125static int
 126worker_wrapper(void *arg)
 127{
 128        struct worker_data *w  = arg;
 129        struct evt_options *opt = w->t->opt;
 130
 131        const bool burst = evt_has_burst_mode(w->dev_id);
 132        const int fwd_latency = opt->fwd_latency;
 133
 134        /* allow compiler to optimize */
 135        if (!burst && !fwd_latency)
 136                return perf_queue_worker(arg, 0);
 137        else if (!burst && fwd_latency)
 138                return perf_queue_worker(arg, 1);
 139        else if (burst && !fwd_latency)
 140                return perf_queue_worker_burst(arg, 0);
 141        else if (burst && fwd_latency)
 142                return perf_queue_worker_burst(arg, 1);
 143
 144        rte_panic("invalid worker\n");
 145}
 146
 147static int
 148perf_queue_launch_lcores(struct evt_test *test, struct evt_options *opt)
 149{
 150        return perf_launch_lcores(test, opt, worker_wrapper);
 151}
 152
 153static int
 154perf_queue_eventdev_setup(struct evt_test *test, struct evt_options *opt)
 155{
 156        uint8_t queue;
 157        int nb_stages = opt->nb_stages;
 158        int ret;
 159        int nb_ports;
 160        int nb_queues;
 161        uint16_t prod;
 162        struct rte_event_dev_info dev_info;
 163        struct test_perf *t = evt_test_priv(test);
 164
 165        nb_ports = evt_nr_active_lcores(opt->wlcores);
 166        nb_ports += opt->prod_type == EVT_PROD_TYPE_ETH_RX_ADPTR ||
 167                opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR ? 0 :
 168                evt_nr_active_lcores(opt->plcores);
 169
 170        nb_queues = perf_queue_nb_event_queues(opt);
 171
 172        memset(&dev_info, 0, sizeof(struct rte_event_dev_info));
 173        ret = rte_event_dev_info_get(opt->dev_id, &dev_info);
 174        if (ret) {
 175                evt_err("failed to get eventdev info %d", opt->dev_id);
 176                return ret;
 177        }
 178
 179        ret = evt_configure_eventdev(opt, nb_queues, nb_ports);
 180        if (ret) {
 181                evt_err("failed to configure eventdev %d", opt->dev_id);
 182                return ret;
 183        }
 184
 185        struct rte_event_queue_conf q_conf = {
 186                        .priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
 187                        .nb_atomic_flows = opt->nb_flows,
 188                        .nb_atomic_order_sequences = opt->nb_flows,
 189        };
 190        /* queue configurations */
 191        for (queue = 0; queue < nb_queues; queue++) {
 192                q_conf.schedule_type =
 193                        (opt->sched_type_list[queue % nb_stages]);
 194
 195                if (opt->q_priority) {
 196                        uint8_t stage_pos = queue % nb_stages;
 197                        /* Configure event queues(stage 0 to stage n) with
 198                         * RTE_EVENT_DEV_PRIORITY_LOWEST to
 199                         * RTE_EVENT_DEV_PRIORITY_HIGHEST.
 200                         */
 201                        uint8_t step = RTE_EVENT_DEV_PRIORITY_LOWEST /
 202                                        (nb_stages - 1);
 203                        /* Higher prio for the queues closer to last stage */
 204                        q_conf.priority = RTE_EVENT_DEV_PRIORITY_LOWEST -
 205                                        (step * stage_pos);
 206                }
 207                ret = rte_event_queue_setup(opt->dev_id, queue, &q_conf);
 208                if (ret) {
 209                        evt_err("failed to setup queue=%d", queue);
 210                        return ret;
 211                }
 212        }
 213
 214        if (opt->wkr_deq_dep > dev_info.max_event_port_dequeue_depth)
 215                opt->wkr_deq_dep = dev_info.max_event_port_dequeue_depth;
 216
 217        /* port configuration */
 218        const struct rte_event_port_conf p_conf = {
 219                        .dequeue_depth = opt->wkr_deq_dep,
 220                        .enqueue_depth = dev_info.max_event_port_dequeue_depth,
 221                        .new_event_threshold = dev_info.max_num_events,
 222        };
 223
 224        ret = perf_event_dev_port_setup(test, opt, nb_stages /* stride */,
 225                                        nb_queues, &p_conf);
 226        if (ret)
 227                return ret;
 228
 229        if (!evt_has_distributed_sched(opt->dev_id)) {
 230                uint32_t service_id;
 231                rte_event_dev_service_id_get(opt->dev_id, &service_id);
 232                ret = evt_service_setup(service_id);
 233                if (ret) {
 234                        evt_err("No service lcore found to run event dev.");
 235                        return ret;
 236                }
 237        }
 238
 239        ret = rte_event_dev_start(opt->dev_id);
 240        if (ret) {
 241                evt_err("failed to start eventdev %d", opt->dev_id);
 242                return ret;
 243        }
 244
 245        if (opt->prod_type == EVT_PROD_TYPE_ETH_RX_ADPTR) {
 246                RTE_ETH_FOREACH_DEV(prod) {
 247                        ret = rte_eth_dev_start(prod);
 248                        if (ret) {
 249                                evt_err("Ethernet dev [%d] failed to start. Using synthetic producer",
 250                                                prod);
 251                                return ret;
 252                        }
 253
 254                        ret = rte_event_eth_rx_adapter_start(prod);
 255                        if (ret) {
 256                                evt_err("Rx adapter[%d] start failed", prod);
 257                                return ret;
 258                        }
 259                        printf("%s: Port[%d] using Rx adapter[%d] started\n",
 260                                        __func__, prod, prod);
 261                }
 262        } else if (opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR) {
 263                for (prod = 0; prod < opt->nb_timer_adptrs; prod++) {
 264                        ret = rte_event_timer_adapter_start(
 265                                        t->timer_adptr[prod]);
 266                        if (ret) {
 267                                evt_err("failed to Start event timer adapter %d"
 268                                                , prod);
 269                                return ret;
 270                        }
 271                }
 272        }
 273
 274        return 0;
 275}
 276
 277static void
 278perf_queue_opt_dump(struct evt_options *opt)
 279{
 280        evt_dump_fwd_latency(opt);
 281        perf_opt_dump(opt, perf_queue_nb_event_queues(opt));
 282}
 283
 284static int
 285perf_queue_opt_check(struct evt_options *opt)
 286{
 287        return perf_opt_check(opt, perf_queue_nb_event_queues(opt));
 288}
 289
 290static bool
 291perf_queue_capability_check(struct evt_options *opt)
 292{
 293        struct rte_event_dev_info dev_info;
 294
 295        rte_event_dev_info_get(opt->dev_id, &dev_info);
 296        if (dev_info.max_event_queues < perf_queue_nb_event_queues(opt) ||
 297                        dev_info.max_event_ports < perf_nb_event_ports(opt)) {
 298                evt_err("not enough eventdev queues=%d/%d or ports=%d/%d",
 299                        perf_queue_nb_event_queues(opt),
 300                        dev_info.max_event_queues,
 301                        perf_nb_event_ports(opt), dev_info.max_event_ports);
 302        }
 303
 304        return true;
 305}
 306
 307static const struct evt_test_ops perf_queue =  {
 308        .cap_check          = perf_queue_capability_check,
 309        .opt_check          = perf_queue_opt_check,
 310        .opt_dump           = perf_queue_opt_dump,
 311        .test_setup         = perf_test_setup,
 312        .mempool_setup      = perf_mempool_setup,
 313        .ethdev_setup       = perf_ethdev_setup,
 314        .eventdev_setup     = perf_queue_eventdev_setup,
 315        .launch_lcores      = perf_queue_launch_lcores,
 316        .eventdev_destroy   = perf_eventdev_destroy,
 317        .mempool_destroy    = perf_mempool_destroy,
 318        .ethdev_destroy     = perf_ethdev_destroy,
 319        .test_result        = perf_test_result,
 320        .test_destroy       = perf_test_destroy,
 321};
 322
 323EVT_TEST_REGISTER(perf_queue);
 324