99a2dd955f
There is no reason for the DPDK libraries to all have 'librte_' prefix on the directory names. This prefix makes the directory names longer and also makes it awkward to add features referring to individual libraries in the build - should the lib names be specified with or without the prefix. Therefore, we can just remove the library prefix and use the library's unique name as the directory name, i.e. 'eal' rather than 'librte_eal' Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
315 lines
12 KiB
ReStructuredText
315 lines
12 KiB
ReStructuredText
.. SPDX-License-Identifier: BSD-3-Clause
|
|
Copyright(c) 2017 Intel Corporation. All rights reserved.
|
|
|
|
Event Timer Adapter Library
|
|
===========================
|
|
|
|
The DPDK :doc:`Event Device library <eventdev>`
|
|
introduces an event driven programming model which presents applications with
|
|
an alternative to the polling model traditionally used in DPDK
|
|
applications. Event devices can be coupled with arbitrary components to provide
|
|
new event sources by using **event adapters**. The Event Timer Adapter is one
|
|
such adapter; it bridges event devices and timer mechanisms.
|
|
|
|
The Event Timer Adapter library extends the event driven model
|
|
by introducing a :ref:`new type of event <timer_expiry_event>` that represents
|
|
a timer expiration, and providing an API with which adapters can be created or
|
|
destroyed, and :ref:`event timers <event_timer>` can be armed and canceled.
|
|
|
|
The Event Timer Adapter library is designed to interface with hardware or
|
|
software implementations of the timer mechanism; it will query an eventdev PMD
|
|
to determine which implementation should be used. The default software
|
|
implementation manages timers using the DPDK
|
|
:doc:`Timer library <timer_lib>`.
|
|
|
|
Examples of using the API are presented in the `API Overview`_ and
|
|
`Processing Timer Expiry Events`_ sections. Code samples are abstracted and
|
|
are based on the example of handling a TCP retransmission.
|
|
|
|
.. _event_timer:
|
|
|
|
Event Timer struct
|
|
------------------
|
|
Event timers are timers that enqueue a timer expiration event to an event
|
|
device upon timer expiration.
|
|
|
|
The Event Timer Adapter API represents each event timer with a generic struct,
|
|
which contains an event and user metadata. The ``rte_event_timer`` struct is
|
|
defined in ``lib/event/librte_event_timer_adapter.h``.
|
|
|
|
.. _timer_expiry_event:
|
|
|
|
Timer Expiry Event
|
|
~~~~~~~~~~~~~~~~~~
|
|
|
|
The event contained by an event timer is enqueued in the event device when the
|
|
timer expires, and the event device uses the attributes below when scheduling
|
|
it:
|
|
|
|
* ``event_queue_id`` - Application should set this to specify an event queue to
|
|
which the timer expiry event should be enqueued
|
|
* ``event_priority`` - Application can set this to indicate the priority of the
|
|
timer expiry event in the event queue relative to other events
|
|
* ``sched_type`` - Application can set this to specify the scheduling type of
|
|
the timer expiry event
|
|
* ``flow_id`` - Application can set this to indicate which flow this timer
|
|
expiry event corresponds to
|
|
* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter
|
|
* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer
|
|
adapter
|
|
|
|
Timeout Ticks
|
|
~~~~~~~~~~~~~
|
|
|
|
The number of ticks from now in which the timer will expire. The ticks value
|
|
has a resolution (``timer_tick_ns``) that is specified in the event timer
|
|
adapter configuration.
|
|
|
|
State
|
|
~~~~~
|
|
|
|
Before arming an event timer, the application should initialize its state to
|
|
RTE_EVENT_TIMER_NOT_ARMED. The event timer's state will be updated when a
|
|
request to arm or cancel it takes effect.
|
|
|
|
If the application wishes to rearm the timer after it has expired, it should
|
|
reset the state back to RTE_EVENT_TIMER_NOT_ARMED before doing so.
|
|
|
|
User Metadata
|
|
~~~~~~~~~~~~~
|
|
|
|
Memory to store user specific metadata. The event timer adapter implementation
|
|
will not modify this area.
|
|
|
|
API Overview
|
|
------------
|
|
|
|
This section will introduce the reader to the event timer adapter API, showing
|
|
how to create and configure an event timer adapter and use it to manage event
|
|
timers.
|
|
|
|
From a high level, the setup steps are:
|
|
|
|
* rte_event_timer_adapter_create()
|
|
* rte_event_timer_adapter_start()
|
|
|
|
And to start and stop timers:
|
|
|
|
* rte_event_timer_arm_burst()
|
|
* rte_event_timer_cancel_burst()
|
|
|
|
Create and Configure an Adapter Instance
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
To create an event timer adapter instance, initialize an
|
|
``rte_event_timer_adapter_conf`` struct with the desired values, and pass it
|
|
to ``rte_event_timer_adapter_create()``.
|
|
|
|
.. code-block:: c
|
|
|
|
#define NSECPERSEC 1E9 // No of ns in 1 sec
|
|
const struct rte_event_timer_adapter_conf adapter_config = {
|
|
.event_dev_id = event_dev_id,
|
|
.timer_adapter_id = 0,
|
|
.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
|
|
.timer_tick_ns = NSECPERSEC / 10, // 100 milliseconds
|
|
.max_tmo_nsec = 180 * NSECPERSEC // 2 minutes
|
|
.nb_timers = 40000,
|
|
.timer_adapter_flags = 0,
|
|
};
|
|
|
|
struct rte_event_timer_adapter *adapter = NULL;
|
|
adapter = rte_event_timer_adapter_create(&adapter_config);
|
|
|
|
if (adapter == NULL) { ... };
|
|
|
|
Before creating an instance of a timer adapter, the application should create
|
|
and configure an event device along with its event ports. Based on the event
|
|
device capability, it might require creating an additional event port to be
|
|
used by the timer adapter. If required, the
|
|
``rte_event_timer_adapter_create()`` function will use a default method to
|
|
configure an event port; it will examine the current event device
|
|
configuration, determine the next available port identifier number, and create
|
|
a new event port with a default port configuration.
|
|
|
|
If the application desires to have finer control of event port allocation
|
|
and setup, it can use the ``rte_event_timer_adapter_create_ext()`` function.
|
|
This function is passed a callback function that will be invoked if the
|
|
adapter needs to create an event port, giving the application the opportunity
|
|
to control how it is done.
|
|
|
|
Adapter modes
|
|
^^^^^^^^^^^^^
|
|
An event timer adapter can be configured in either periodic or non-periodic mode
|
|
to support timers of the respective type. A periodic timer expires at a fixed
|
|
time interval repeatedly till it is cancelled. A non-periodic timer expires only
|
|
once. The periodic capability flag, ``RTE_EVENT_TIMER_ADAPTER_CAP_PERIODIC``,
|
|
can be set for implementations that support periodic mode if desired. To
|
|
configure an adapter in periodic mode, ``timer_adapter_flags`` of
|
|
``rte_event_timer_adapter_conf`` is set to include the periodic flag
|
|
``RTE_EVENT_TIMER_ADAPTER_F_PERIODIC``. Maximum timeout (``max_tmo_nsec``) does
|
|
not apply to periodic mode.
|
|
|
|
Retrieve Event Timer Adapter Contextual Information
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
The event timer adapter implementation may have constraints on tick resolution
|
|
or maximum timer expiry timeout based on the given event timer adapter or
|
|
system. In this case, the implementation may adjust the tick resolution or
|
|
maximum timeout to the best possible configuration.
|
|
|
|
Upon successful event timer adapter creation, the application can get the
|
|
configured resolution and max timeout with
|
|
``rte_event_timer_adapter_get_info()``. This function will return an
|
|
``rte_event_timer_adapter_info`` struct, which contains the following members:
|
|
|
|
* ``min_resolution_ns`` - Minimum timer adapter tick resolution in ns.
|
|
* ``max_tmo_ns`` - Maximum timer timeout(expiry) in ns.
|
|
* ``adapter_conf`` - Configured event timer adapter attributes
|
|
|
|
Configuring the Service Component
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
If the adapter uses a service component, the application is required to map
|
|
the service to a service core before starting the adapter:
|
|
|
|
.. code-block:: c
|
|
|
|
uint32_t service_id;
|
|
|
|
if (rte_event_timer_adapter_service_id_get(adapter, &service_id) == 0)
|
|
rte_service_map_lcore_set(service_id, EVTIM_CORE_ID);
|
|
|
|
An event timer adapter uses a service component if the event device PMD
|
|
indicates that the adapter should use a software implementation.
|
|
|
|
Starting the Adapter Instance
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The application should call ``rte_event_timer_adapter_start()`` to start
|
|
running the event timer adapter. This function calls the start entry points
|
|
defined by eventdev PMDs for hardware implementations or puts a service
|
|
component into the running state in the software implementation.
|
|
|
|
.. Note::
|
|
|
|
The eventdev to which the event_timer_adapter is connected needs to
|
|
be started before calling rte_event_timer_adapter_start().
|
|
|
|
Arming Event Timers
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
Once an event timer adapter has been started, an application can begin to
|
|
manage event timers with it.
|
|
|
|
The application should allocate ``struct rte_event_timer`` objects from a
|
|
mempool or huge-page backed application buffers of required size. Upon
|
|
successful allocation, the application should initialize the event timer, and
|
|
then set any of the necessary event attributes described in the
|
|
`Timer Expiry Event`_ section. In the following example, assume ``conn``
|
|
represents a TCP connection and that ``event_timer_pool`` is a mempool that
|
|
was created previously:
|
|
|
|
.. code-block:: c
|
|
|
|
rte_mempool_get(event_timer_pool, (void **)&conn->evtim);
|
|
if (conn->evtim == NULL) { ... }
|
|
|
|
/* Set up the event timer. */
|
|
conn->evtim->ev.op = RTE_EVENT_OP_NEW;
|
|
conn->evtim->ev.queue_id = event_queue_id;
|
|
conn->evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
|
|
conn->evtim->ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
|
|
conn->evtim->ev.event_type = RTE_EVENT_TYPE_TIMER;
|
|
conn->evtim->ev.event_ptr = conn;
|
|
conn->evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
|
|
conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns)
|
|
|
|
Note that it is necessary to initialize the event timer state to
|
|
RTE_EVENT_TIMER_NOT_ARMED. Also note that we have saved a pointer to the
|
|
``conn`` object in the timer's event payload. This will allow us to locate
|
|
the connection object again once we dequeue the timer expiry event from the
|
|
event device later. As a convenience, the application may specify no value for
|
|
ev.event_ptr, and the adapter will by default set it to point at the event
|
|
timer itself.
|
|
|
|
Now we can arm the event timer with ``rte_event_timer_arm_burst()``:
|
|
|
|
.. code-block:: c
|
|
|
|
ret = rte_event_timer_arm_burst(adapter, &conn->evtim, 1);
|
|
if (ret != 1) { ... }
|
|
|
|
Once an event timer expires, the application may free it or rearm it as
|
|
necessary. If the application will rearm the timer, the state should be reset
|
|
to RTE_EVENT_TIMER_NOT_ARMED by the application before rearming it. Timer expiry
|
|
events will be generated once or periodically until the timer is cancelled based
|
|
on adapter mode.
|
|
|
|
Multiple Event Timers with Same Expiry Value
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
In the special case that there is a set of event timers that should all expire
|
|
at the same time, the application may call
|
|
``rte_event_timer_arm_tmo_tick_burst()``, which allows the implementation to
|
|
optimize the operation if possible.
|
|
|
|
Canceling Event Timers
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
An event timer that has been armed as described in `Arming Event Timers`_ can
|
|
be canceled by calling ``rte_event_timer_cancel_burst()``:
|
|
|
|
.. code-block:: c
|
|
|
|
/* Ack for the previous tcp data packet has been received;
|
|
* cancel the retransmission timer
|
|
*/
|
|
rte_event_timer_cancel_burst(adapter, &conn->timer, 1);
|
|
|
|
Processing Timer Expiry Events
|
|
------------------------------
|
|
|
|
Once an event timer has successfully enqueued a timer expiry event in the event
|
|
device, the application will subsequently dequeue it from the event device.
|
|
The application can use the event payload to retrieve a pointer to the object
|
|
associated with the event timer. It can then re-arm the event timer or free the
|
|
event timer object as desired:
|
|
|
|
.. code-block:: c
|
|
|
|
void
|
|
event_processing_loop(...)
|
|
{
|
|
while (...) {
|
|
/* Receive events from the configured event port. */
|
|
rte_event_dequeue_burst(event_dev_id, event_port, &ev, 1, 0);
|
|
...
|
|
switch(ev.event_type) {
|
|
...
|
|
case RTE_EVENT_TYPE_TIMER:
|
|
process_timer_event(ev);
|
|
...
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t
|
|
process_timer_event(...)
|
|
{
|
|
/* A retransmission timeout for the connection has been received. */
|
|
conn = ev.event_ptr;
|
|
/* Retransmit last packet (e.g. TCP segment). */
|
|
...
|
|
/* Re-arm timer using original values. */
|
|
rte_event_timer_arm_burst(adapter_id, &conn->timer, 1);
|
|
}
|
|
|
|
Summary
|
|
-------
|
|
|
|
The Event Timer Adapter library extends the DPDK event-based programming model
|
|
by representing timer expirations as events in the system and allowing
|
|
applications to use existing event processing loops to arm and cancel event
|
|
timers or handle timer expiry events.
|