.. SPDX-License-Identifier: BSD-3-Clause
Copyright(c) 2017 Intel Corporation.
+ Copyright(c) 2018 Arm Limited.
Event Device Library
====================
application fills in to have the event scheduled as required:
* ``flow_id`` - The targeted flow identifier for the enq/deq operation.
-* ``event_type`` - The source of this event, eg RTE_EVENT_TYPE_ETHDEV or CPU.
+* ``event_type`` - The source of this event, e.g. RTE_EVENT_TYPE_ETHDEV or CPU.
* ``sub_event_type`` - Distinguishes events inside the application, that have
the same event_type (see above)
* ``op`` - This field takes one of the RTE_EVENT_OP_* values, and tells the
* ``uint64_t u64``
* ``void *event_ptr``
* ``struct rte_mbuf *mbuf``
+* ``struct rte_event_vector *vec``
-These three items in a union occupy the same 64 bits at the end of the rte_event
+These four items in a union occupy the same 64 bits at the end of the rte_event
structure. The application can utilize the 64 bits directly by accessing the
-u64 variable, while the event_ptr and mbuf are provided as convenience
+u64 variable, while the event_ptr, mbuf, vec are provided as a convenience
variables. For example the mbuf pointer in the union can used to schedule a
DPDK packet.
+Event Vector
+~~~~~~~~~~~~
+
+The rte_event_vector struct contains a vector of elements defined by the event
+type specified in the ``rte_event``. The event_vector structure contains the
+following data:
+
+* ``nb_elem`` - The number of elements held within the vector.
+
+Similar to ``rte_event`` the payload of event vector is also a union, allowing
+flexibility in what the actual vector is.
+
+* ``struct rte_mbuf *mbufs[0]`` - An array of mbufs.
+* ``void *ptrs[0]`` - An array of pointers.
+* ``uint64_t *u64s[0]`` - An array of uint64_t elements.
+
+The size of the event vector is related to the total number of elements it is
+configured to hold, this is achieved by making `rte_event_vector` a variable
+length structure.
+A helper function is provided to create a mempool that holds event vector, which
+takes name of the pool, total number of required ``rte_event_vector``,
+cache size, number of elements in each ``rte_event_vector`` and socket id.
+
+.. code-block:: c
+
+ rte_event_vector_pool_create("vector_pool", nb_event_vectors, cache_sz,
+ nb_elements_per_vector, socket_id);
+
+The function ``rte_event_vector_pool_create`` creates mempool with the best
+platform mempool ops.
+
Queues
~~~~~~
~~~~~
Ports are the points of contact between worker cores and the eventdev. The
-general use-case will see one CPU core using one port to enqueue and dequeue
+general use case will see one CPU core using one port to enqueue and dequeue
events from an eventdev. Ports are linked to queues in order to retrieve events
from those queues (more details in `Linking Queues and Ports`_ below).
This section will introduce the reader to the eventdev API, showing how to
create and configure an eventdev and use it for a two-stage atomic pipeline
-with a single core for TX. The diagram below shows the final state of the
-application after this walk-through:
+with one core each for RX and TX. RX and TX cores are shown here for
+illustration, refer to Eventdev Adapter documentation for further details.
+The diagram below shows the final state of the application after this
+walk-through:
.. _figure_eventdev-usage1:
.nb_atomic_flows = 1024,
.nb_atomic_order_sequences = 1024,
};
+ struct rte_event_queue_conf single_link_conf = {
+ .event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_LINK,
+ };
int dev_id = 0;
- int queue_id = 0;
- int err = rte_event_queue_setup(dev_id, queue_id, &atomic_conf);
+ int atomic_q_1 = 0;
+ int atomic_q_2 = 1;
+ int single_link_q = 2;
+ int err = rte_event_queue_setup(dev_id, atomic_q_1, &atomic_conf);
+ int err = rte_event_queue_setup(dev_id, atomic_q_2, &atomic_conf);
+ int err = rte_event_queue_setup(dev_id, single_link_q, &single_link_conf);
-The remainder of this walk-through assumes that the queues are configured as
-follows:
+As shown above, queue IDs are as follows:
* id 0, atomic queue #1
* id 1, atomic queue #2
* id 2, single-link queue
+These queues are used for the remainder of this walk-through.
+
Setting up Ports
~~~~~~~~~~~~~~~~
-Once queues are set up successfully, create the ports as required. Each port
-should be set up with its corresponding port_conf type, worker for worker cores,
-rx and tx for the RX and TX cores:
+Once queues are set up successfully, create the ports as required.
.. code-block:: c
.new_event_threshold = 4096,
};
int dev_id = 0;
- int port_id = 0;
- int err = rte_event_port_setup(dev_id, port_id, &CORE_FUNCTION_conf);
+ int rx_port_id = 0;
+ int worker_port_id;
+ int err = rte_event_port_setup(dev_id, rx_port_id, &rx_conf);
+
+ for (worker_port_id = 1; worker_port_id <= 4; worker_port_id++) {
+ int err = rte_event_port_setup(dev_id, worker_port_id, &worker_conf);
+ }
-It is now assumed that:
+ int tx_port_id = 5;
+ int err = rte_event_port_setup(dev_id, tx_port_id, &tx_conf);
+
+As shown above:
* port 0: RX core
* ports 1,2,3,4: Workers
* port 5: TX core
+These ports are used for the remainder of this walk-through.
+
Linking Queues and Ports
~~~~~~~~~~~~~~~~~~~~~~~~
The final step is to "wire up" the ports to the queues. After this, the
eventdev is capable of scheduling events, and when cores request work to do,
the correct events are provided to that core. Note that the RX core takes input
-from eg: a NIC so it is not linked to any eventdev queues.
+from e.g.: a NIC so it is not linked to any eventdev queues.
Linking all workers to atomic queues, and the TX core to the single-link queue
can be achieved like this:
.. code-block:: c
- uint8_t port_id = 0;
+ uint8_t rx_port_id = 0;
+ uint8_t tx_port_id = 5;
uint8_t atomic_qs[] = {0, 1};
uint8_t single_link_q = 2;
- uint8_t tx_port_id = 5;
- uin8t_t priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
+ uint8_t priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
+ int worker_port_id;
- for(int i = 0; i < 4; i++) {
- int worker_port = i + 1;
- int links_made = rte_event_port_link(dev_id, worker_port, atomic_qs, NULL, 2);
+ for (worker_port_id = 1; worker_port_id <= 4; worker_port_id++) {
+ int links_made = rte_event_port_link(dev_id, worker_port_id, atomic_qs, NULL, 2);
}
int links_made = rte_event_port_link(dev_id, tx_port_id, &single_link_q, &priority, 1);
int err = rte_event_dev_start(dev_id);
+.. Note::
+
+ EventDev needs to be started before starting the event producers such
+ as event_eth_rx_adapter, event_timer_adapter and event_crypto_adapter.
+
Ingress of New Events
~~~~~~~~~~~~~~~~~~~~~
ev[i].flow_id = mbufs[i]->hash.rss;
ev[i].op = RTE_EVENT_OP_NEW;
ev[i].sched_type = RTE_SCHED_TYPE_ATOMIC;
- ev[i].queue_id = 0;
+ ev[i].queue_id = atomic_q_1;
ev[i].event_type = RTE_EVENT_TYPE_ETHDEV;
ev[i].sub_event_type = 0;
ev[i].priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
ev[i].mbuf = mbufs[i];
}
- const int nb_tx = rte_event_enqueue_burst(dev_id, port_id, ev, nb_rx);
+ const int nb_tx = rte_event_enqueue_burst(dev_id, rx_port_id, ev, nb_rx);
if (nb_tx != nb_rx) {
for(i = nb_tx; i < nb_rx; i++)
rte_pktmbuf_free(mbufs[i]);
events[i].queue_id++;
}
- uint16_t nb_tx = rte_event_enqueue_burst(dev_id, port_id, events, nb_rx);
+ uint16_t nb_tx = rte_event_enqueue_burst(dev_id, worker_port_id, events, nb_rx);
Egress of Events
rte_event_enqueue_burst(...);
}
+Quiescing Event Ports
+~~~~~~~~~~~~~~~~~~~~~
+
+To migrate the event port to another lcore
+or while tearing down a worker core using an event port,
+``rte_event_port_quiesce()`` can be invoked to make sure that all the data
+associated with the event port are released from the worker core,
+this might also include any prefetched events.
+
+A flush callback can be passed to the function to handle any outstanding events.
+
+.. code-block:: c
+
+ rte_event_port_quiesce(dev_id, port_id, release_cb, NULL);
+
+.. Note::
+
+ Invocation of this API does not affect the existing port configuration.
+
+Stopping the EventDev
+~~~~~~~~~~~~~~~~~~~~~
+
+A single function call tells the eventdev instance to stop processing events.
+A flush callback can be registered to free any inflight events
+using ``rte_event_dev_stop_flush_callback_register()`` function.
+
+.. code-block:: c
+
+ int err = rte_event_dev_stop(dev_id);
+
+.. Note::
+
+ The event producers such as ``event_eth_rx_adapter``,
+ ``event_timer_adapter`` and ``event_crypto_adapter``
+ need to be stopped before stopping the event device.
Summary
-------