1*2bfe3f2eSlogwang /* 2*2bfe3f2eSlogwang * BSD LICENSE 3*2bfe3f2eSlogwang * 4*2bfe3f2eSlogwang * Copyright (C) Cavium, Inc 2017. 5*2bfe3f2eSlogwang * 6*2bfe3f2eSlogwang * Redistribution and use in source and binary forms, with or without 7*2bfe3f2eSlogwang * modification, are permitted provided that the following conditions 8*2bfe3f2eSlogwang * are met: 9*2bfe3f2eSlogwang * 10*2bfe3f2eSlogwang * * Redistributions of source code must retain the above copyright 11*2bfe3f2eSlogwang * notice, this list of conditions and the following disclaimer. 12*2bfe3f2eSlogwang * * Redistributions in binary form must reproduce the above copyright 13*2bfe3f2eSlogwang * notice, this list of conditions and the following disclaimer in 14*2bfe3f2eSlogwang * the documentation and/or other materials provided with the 15*2bfe3f2eSlogwang * distribution. 16*2bfe3f2eSlogwang * * Neither the name of Cavium, Inc nor the names of its 17*2bfe3f2eSlogwang * contributors may be used to endorse or promote products derived 18*2bfe3f2eSlogwang * from this software without specific prior written permission. 19*2bfe3f2eSlogwang * 20*2bfe3f2eSlogwang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21*2bfe3f2eSlogwang * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*2bfe3f2eSlogwang * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23*2bfe3f2eSlogwang * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24*2bfe3f2eSlogwang * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25*2bfe3f2eSlogwang * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26*2bfe3f2eSlogwang * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27*2bfe3f2eSlogwang * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28*2bfe3f2eSlogwang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29*2bfe3f2eSlogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30*2bfe3f2eSlogwang * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31*2bfe3f2eSlogwang */ 32*2bfe3f2eSlogwang 33*2bfe3f2eSlogwang #include "test_perf_common.h" 34*2bfe3f2eSlogwang 35*2bfe3f2eSlogwang /* See http://dpdk.org/doc/guides/tools/testeventdev.html for test details */ 36*2bfe3f2eSlogwang 37*2bfe3f2eSlogwang static inline int 38*2bfe3f2eSlogwang atq_nb_event_queues(struct evt_options *opt) 39*2bfe3f2eSlogwang { 40*2bfe3f2eSlogwang /* nb_queues = number of producers */ 41*2bfe3f2eSlogwang return evt_nr_active_lcores(opt->plcores); 42*2bfe3f2eSlogwang } 43*2bfe3f2eSlogwang 44*2bfe3f2eSlogwang static inline __attribute__((always_inline)) void 45*2bfe3f2eSlogwang atq_mark_fwd_latency(struct rte_event *const ev) 46*2bfe3f2eSlogwang { 47*2bfe3f2eSlogwang if (unlikely(ev->sub_event_type == 0)) { 48*2bfe3f2eSlogwang struct perf_elt *const m = ev->event_ptr; 49*2bfe3f2eSlogwang 50*2bfe3f2eSlogwang m->timestamp = rte_get_timer_cycles(); 51*2bfe3f2eSlogwang } 52*2bfe3f2eSlogwang } 53*2bfe3f2eSlogwang 54*2bfe3f2eSlogwang static inline __attribute__((always_inline)) void 55*2bfe3f2eSlogwang atq_fwd_event(struct rte_event *const ev, uint8_t *const sched_type_list, 56*2bfe3f2eSlogwang const uint8_t nb_stages) 57*2bfe3f2eSlogwang { 58*2bfe3f2eSlogwang ev->sub_event_type++; 59*2bfe3f2eSlogwang ev->sched_type = sched_type_list[ev->sub_event_type % nb_stages]; 60*2bfe3f2eSlogwang ev->op = RTE_EVENT_OP_FORWARD; 61*2bfe3f2eSlogwang ev->event_type = RTE_EVENT_TYPE_CPU; 62*2bfe3f2eSlogwang } 63*2bfe3f2eSlogwang 64*2bfe3f2eSlogwang static int 65*2bfe3f2eSlogwang perf_atq_worker(void *arg, const int enable_fwd_latency) 66*2bfe3f2eSlogwang { 67*2bfe3f2eSlogwang PERF_WORKER_INIT; 68*2bfe3f2eSlogwang struct rte_event ev; 69*2bfe3f2eSlogwang 70*2bfe3f2eSlogwang while (t->done == false) { 71*2bfe3f2eSlogwang uint16_t event = rte_event_dequeue_burst(dev, port, &ev, 1, 0); 72*2bfe3f2eSlogwang 73*2bfe3f2eSlogwang if (enable_fwd_latency) 74*2bfe3f2eSlogwang rte_prefetch0(ev.event_ptr); 75*2bfe3f2eSlogwang 76*2bfe3f2eSlogwang if (!event) { 77*2bfe3f2eSlogwang rte_pause(); 78*2bfe3f2eSlogwang continue; 79*2bfe3f2eSlogwang } 80*2bfe3f2eSlogwang 81*2bfe3f2eSlogwang if (enable_fwd_latency) 82*2bfe3f2eSlogwang /* first stage in pipeline, mark ts to compute fwd latency */ 83*2bfe3f2eSlogwang atq_mark_fwd_latency(&ev); 84*2bfe3f2eSlogwang 85*2bfe3f2eSlogwang /* last stage in pipeline */ 86*2bfe3f2eSlogwang if (unlikely((ev.sub_event_type % nb_stages) == laststage)) { 87*2bfe3f2eSlogwang if (enable_fwd_latency) 88*2bfe3f2eSlogwang cnt = perf_process_last_stage_latency(pool, 89*2bfe3f2eSlogwang &ev, w, bufs, sz, cnt); 90*2bfe3f2eSlogwang else 91*2bfe3f2eSlogwang cnt = perf_process_last_stage(pool, &ev, w, 92*2bfe3f2eSlogwang bufs, sz, cnt); 93*2bfe3f2eSlogwang } else { 94*2bfe3f2eSlogwang atq_fwd_event(&ev, sched_type_list, nb_stages); 95*2bfe3f2eSlogwang while (rte_event_enqueue_burst(dev, port, &ev, 1) != 1) 96*2bfe3f2eSlogwang rte_pause(); 97*2bfe3f2eSlogwang } 98*2bfe3f2eSlogwang } 99*2bfe3f2eSlogwang return 0; 100*2bfe3f2eSlogwang } 101*2bfe3f2eSlogwang 102*2bfe3f2eSlogwang static int 103*2bfe3f2eSlogwang perf_atq_worker_burst(void *arg, const int enable_fwd_latency) 104*2bfe3f2eSlogwang { 105*2bfe3f2eSlogwang PERF_WORKER_INIT; 106*2bfe3f2eSlogwang uint16_t i; 107*2bfe3f2eSlogwang /* +1 to avoid prefetch out of array check */ 108*2bfe3f2eSlogwang struct rte_event ev[BURST_SIZE + 1]; 109*2bfe3f2eSlogwang 110*2bfe3f2eSlogwang while (t->done == false) { 111*2bfe3f2eSlogwang uint16_t const nb_rx = rte_event_dequeue_burst(dev, port, ev, 112*2bfe3f2eSlogwang BURST_SIZE, 0); 113*2bfe3f2eSlogwang 114*2bfe3f2eSlogwang if (!nb_rx) { 115*2bfe3f2eSlogwang rte_pause(); 116*2bfe3f2eSlogwang continue; 117*2bfe3f2eSlogwang } 118*2bfe3f2eSlogwang 119*2bfe3f2eSlogwang for (i = 0; i < nb_rx; i++) { 120*2bfe3f2eSlogwang if (enable_fwd_latency) { 121*2bfe3f2eSlogwang rte_prefetch0(ev[i+1].event_ptr); 122*2bfe3f2eSlogwang /* first stage in pipeline. 123*2bfe3f2eSlogwang * mark time stamp to compute fwd latency 124*2bfe3f2eSlogwang */ 125*2bfe3f2eSlogwang atq_mark_fwd_latency(&ev[i]); 126*2bfe3f2eSlogwang } 127*2bfe3f2eSlogwang /* last stage in pipeline */ 128*2bfe3f2eSlogwang if (unlikely((ev[i].sub_event_type % nb_stages) 129*2bfe3f2eSlogwang == laststage)) { 130*2bfe3f2eSlogwang if (enable_fwd_latency) 131*2bfe3f2eSlogwang cnt = perf_process_last_stage_latency( 132*2bfe3f2eSlogwang pool, &ev[i], w, bufs, sz, cnt); 133*2bfe3f2eSlogwang else 134*2bfe3f2eSlogwang cnt = perf_process_last_stage(pool, 135*2bfe3f2eSlogwang &ev[i], w, bufs, sz, cnt); 136*2bfe3f2eSlogwang 137*2bfe3f2eSlogwang ev[i].op = RTE_EVENT_OP_RELEASE; 138*2bfe3f2eSlogwang } else { 139*2bfe3f2eSlogwang atq_fwd_event(&ev[i], sched_type_list, 140*2bfe3f2eSlogwang nb_stages); 141*2bfe3f2eSlogwang } 142*2bfe3f2eSlogwang } 143*2bfe3f2eSlogwang 144*2bfe3f2eSlogwang uint16_t enq; 145*2bfe3f2eSlogwang 146*2bfe3f2eSlogwang enq = rte_event_enqueue_burst(dev, port, ev, nb_rx); 147*2bfe3f2eSlogwang while (enq < nb_rx) { 148*2bfe3f2eSlogwang enq += rte_event_enqueue_burst(dev, port, 149*2bfe3f2eSlogwang ev + enq, nb_rx - enq); 150*2bfe3f2eSlogwang } 151*2bfe3f2eSlogwang } 152*2bfe3f2eSlogwang return 0; 153*2bfe3f2eSlogwang } 154*2bfe3f2eSlogwang 155*2bfe3f2eSlogwang static int 156*2bfe3f2eSlogwang worker_wrapper(void *arg) 157*2bfe3f2eSlogwang { 158*2bfe3f2eSlogwang struct worker_data *w = arg; 159*2bfe3f2eSlogwang struct evt_options *opt = w->t->opt; 160*2bfe3f2eSlogwang 161*2bfe3f2eSlogwang const bool burst = evt_has_burst_mode(w->dev_id); 162*2bfe3f2eSlogwang const int fwd_latency = opt->fwd_latency; 163*2bfe3f2eSlogwang 164*2bfe3f2eSlogwang /* allow compiler to optimize */ 165*2bfe3f2eSlogwang if (!burst && !fwd_latency) 166*2bfe3f2eSlogwang return perf_atq_worker(arg, 0); 167*2bfe3f2eSlogwang else if (!burst && fwd_latency) 168*2bfe3f2eSlogwang return perf_atq_worker(arg, 1); 169*2bfe3f2eSlogwang else if (burst && !fwd_latency) 170*2bfe3f2eSlogwang return perf_atq_worker_burst(arg, 0); 171*2bfe3f2eSlogwang else if (burst && fwd_latency) 172*2bfe3f2eSlogwang return perf_atq_worker_burst(arg, 1); 173*2bfe3f2eSlogwang 174*2bfe3f2eSlogwang rte_panic("invalid worker\n"); 175*2bfe3f2eSlogwang } 176*2bfe3f2eSlogwang 177*2bfe3f2eSlogwang static int 178*2bfe3f2eSlogwang perf_atq_launch_lcores(struct evt_test *test, struct evt_options *opt) 179*2bfe3f2eSlogwang { 180*2bfe3f2eSlogwang return perf_launch_lcores(test, opt, worker_wrapper); 181*2bfe3f2eSlogwang } 182*2bfe3f2eSlogwang 183*2bfe3f2eSlogwang static int 184*2bfe3f2eSlogwang perf_atq_eventdev_setup(struct evt_test *test, struct evt_options *opt) 185*2bfe3f2eSlogwang { 186*2bfe3f2eSlogwang int ret; 187*2bfe3f2eSlogwang uint8_t queue; 188*2bfe3f2eSlogwang 189*2bfe3f2eSlogwang const struct rte_event_dev_config config = { 190*2bfe3f2eSlogwang .nb_event_queues = atq_nb_event_queues(opt), 191*2bfe3f2eSlogwang .nb_event_ports = perf_nb_event_ports(opt), 192*2bfe3f2eSlogwang .nb_events_limit = 4096, 193*2bfe3f2eSlogwang .nb_event_queue_flows = opt->nb_flows, 194*2bfe3f2eSlogwang .nb_event_port_dequeue_depth = 128, 195*2bfe3f2eSlogwang .nb_event_port_enqueue_depth = 128, 196*2bfe3f2eSlogwang }; 197*2bfe3f2eSlogwang 198*2bfe3f2eSlogwang ret = rte_event_dev_configure(opt->dev_id, &config); 199*2bfe3f2eSlogwang if (ret) { 200*2bfe3f2eSlogwang evt_err("failed to configure eventdev %d", opt->dev_id); 201*2bfe3f2eSlogwang return ret; 202*2bfe3f2eSlogwang } 203*2bfe3f2eSlogwang 204*2bfe3f2eSlogwang struct rte_event_queue_conf q_conf = { 205*2bfe3f2eSlogwang .priority = RTE_EVENT_DEV_PRIORITY_NORMAL, 206*2bfe3f2eSlogwang .event_queue_cfg = RTE_EVENT_QUEUE_CFG_ALL_TYPES, 207*2bfe3f2eSlogwang .nb_atomic_flows = opt->nb_flows, 208*2bfe3f2eSlogwang .nb_atomic_order_sequences = opt->nb_flows, 209*2bfe3f2eSlogwang }; 210*2bfe3f2eSlogwang /* queue configurations */ 211*2bfe3f2eSlogwang for (queue = 0; queue < atq_nb_event_queues(opt); queue++) { 212*2bfe3f2eSlogwang ret = rte_event_queue_setup(opt->dev_id, queue, &q_conf); 213*2bfe3f2eSlogwang if (ret) { 214*2bfe3f2eSlogwang evt_err("failed to setup queue=%d", queue); 215*2bfe3f2eSlogwang return ret; 216*2bfe3f2eSlogwang } 217*2bfe3f2eSlogwang } 218*2bfe3f2eSlogwang 219*2bfe3f2eSlogwang ret = perf_event_dev_port_setup(test, opt, 1 /* stride */, 220*2bfe3f2eSlogwang atq_nb_event_queues(opt)); 221*2bfe3f2eSlogwang if (ret) 222*2bfe3f2eSlogwang return ret; 223*2bfe3f2eSlogwang 224*2bfe3f2eSlogwang ret = evt_service_setup(opt->dev_id); 225*2bfe3f2eSlogwang if (ret) { 226*2bfe3f2eSlogwang evt_err("No service lcore found to run event dev."); 227*2bfe3f2eSlogwang return ret; 228*2bfe3f2eSlogwang } 229*2bfe3f2eSlogwang 230*2bfe3f2eSlogwang ret = rte_event_dev_start(opt->dev_id); 231*2bfe3f2eSlogwang if (ret) { 232*2bfe3f2eSlogwang evt_err("failed to start eventdev %d", opt->dev_id); 233*2bfe3f2eSlogwang return ret; 234*2bfe3f2eSlogwang } 235*2bfe3f2eSlogwang 236*2bfe3f2eSlogwang return 0; 237*2bfe3f2eSlogwang } 238*2bfe3f2eSlogwang 239*2bfe3f2eSlogwang static void 240*2bfe3f2eSlogwang perf_atq_opt_dump(struct evt_options *opt) 241*2bfe3f2eSlogwang { 242*2bfe3f2eSlogwang perf_opt_dump(opt, atq_nb_event_queues(opt)); 243*2bfe3f2eSlogwang } 244*2bfe3f2eSlogwang 245*2bfe3f2eSlogwang static int 246*2bfe3f2eSlogwang perf_atq_opt_check(struct evt_options *opt) 247*2bfe3f2eSlogwang { 248*2bfe3f2eSlogwang return perf_opt_check(opt, atq_nb_event_queues(opt)); 249*2bfe3f2eSlogwang } 250*2bfe3f2eSlogwang 251*2bfe3f2eSlogwang static bool 252*2bfe3f2eSlogwang perf_atq_capability_check(struct evt_options *opt) 253*2bfe3f2eSlogwang { 254*2bfe3f2eSlogwang struct rte_event_dev_info dev_info; 255*2bfe3f2eSlogwang 256*2bfe3f2eSlogwang rte_event_dev_info_get(opt->dev_id, &dev_info); 257*2bfe3f2eSlogwang if (dev_info.max_event_queues < atq_nb_event_queues(opt) || 258*2bfe3f2eSlogwang dev_info.max_event_ports < perf_nb_event_ports(opt)) { 259*2bfe3f2eSlogwang evt_err("not enough eventdev queues=%d/%d or ports=%d/%d", 260*2bfe3f2eSlogwang atq_nb_event_queues(opt), dev_info.max_event_queues, 261*2bfe3f2eSlogwang perf_nb_event_ports(opt), dev_info.max_event_ports); 262*2bfe3f2eSlogwang } 263*2bfe3f2eSlogwang if (!evt_has_all_types_queue(opt->dev_id)) 264*2bfe3f2eSlogwang return false; 265*2bfe3f2eSlogwang 266*2bfe3f2eSlogwang return true; 267*2bfe3f2eSlogwang } 268*2bfe3f2eSlogwang 269*2bfe3f2eSlogwang static const struct evt_test_ops perf_atq = { 270*2bfe3f2eSlogwang .cap_check = perf_atq_capability_check, 271*2bfe3f2eSlogwang .opt_check = perf_atq_opt_check, 272*2bfe3f2eSlogwang .opt_dump = perf_atq_opt_dump, 273*2bfe3f2eSlogwang .test_setup = perf_test_setup, 274*2bfe3f2eSlogwang .mempool_setup = perf_mempool_setup, 275*2bfe3f2eSlogwang .eventdev_setup = perf_atq_eventdev_setup, 276*2bfe3f2eSlogwang .launch_lcores = perf_atq_launch_lcores, 277*2bfe3f2eSlogwang .eventdev_destroy = perf_eventdev_destroy, 278*2bfe3f2eSlogwang .mempool_destroy = perf_mempool_destroy, 279*2bfe3f2eSlogwang .test_result = perf_test_result, 280*2bfe3f2eSlogwang .test_destroy = perf_test_destroy, 281*2bfe3f2eSlogwang }; 282*2bfe3f2eSlogwang 283*2bfe3f2eSlogwang EVT_TEST_REGISTER(perf_atq); 284