1.. SPDX-License-Identifier: BSD-3-Clause 2 Copyright(c) 2017 Intel Corporation. All rights reserved. 3 4Event Timer Adapter Library 5=========================== 6 7The DPDK :doc:`Event Device library <eventdev>` 8introduces an event driven programming model which presents applications with 9an alternative to the polling model traditionally used in DPDK 10applications. Event devices can be coupled with arbitrary components to provide 11new event sources by using **event adapters**. The Event Timer Adapter is one 12such adapter; it bridges event devices and timer mechanisms. 13 14The Event Timer Adapter library extends the event driven model 15by introducing a :ref:`new type of event <timer_expiry_event>` that represents 16a timer expiration, and providing an API with which adapters can be created or 17destroyed, and :ref:`event timers <event_timer>` can be armed and canceled. 18 19The Event Timer Adapter library is designed to interface with hardware or 20software implementations of the timer mechanism; it will query an eventdev PMD 21to determine which implementation should be used. The default software 22implementation manages timers using the DPDK :doc:`../timer_lib`. 23 24Examples of using the API are presented in the `API Overview`_ and 25`Processing Timer Expiry Events`_ sections. Code samples are abstracted and 26are based on the example of handling a TCP retransmission. 27 28.. _event_timer: 29 30Event Timer struct 31------------------ 32Event timers are timers that enqueue a timer expiration event to an event 33device upon timer expiration. 34 35The Event Timer Adapter API represents each event timer with a generic struct, 36which contains an event and user metadata. The ``rte_event_timer`` struct is 37defined in ``rte_event_timer_adapter.h``. 38 39.. _timer_expiry_event: 40 41Timer Expiry Event 42~~~~~~~~~~~~~~~~~~ 43 44The event contained by an event timer is enqueued in the event device when the 45timer expires, and the event device uses the attributes below when scheduling 46it: 47 48* ``event_queue_id`` - Application should set this to specify an event queue to 49 which the timer expiry event should be enqueued 50* ``event_priority`` - Application can set this to indicate the priority of the 51 timer expiry event in the event queue relative to other events 52* ``sched_type`` - Application can set this to specify the scheduling type of 53 the timer expiry event 54* ``flow_id`` - Application can set this to indicate which flow this timer 55 expiry event corresponds to 56* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter 57* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer 58 adapter 59 60Timeout Ticks 61~~~~~~~~~~~~~ 62 63The number of ticks from now in which the timer will expire. The ticks value 64has a resolution (``timer_tick_ns``) that is specified in the event timer 65adapter configuration. 66 67State 68~~~~~ 69 70Before arming an event timer, the application should initialize its state to 71RTE_EVENT_TIMER_NOT_ARMED. The event timer's state will be updated when a 72request to arm or cancel it takes effect. 73 74If the application wishes to rearm the timer after it has expired, it should 75reset the state back to RTE_EVENT_TIMER_NOT_ARMED before doing so. 76 77User Metadata 78~~~~~~~~~~~~~ 79 80Memory to store user specific metadata. The event timer adapter implementation 81will not modify this area. 82 83API Overview 84------------ 85 86This section will introduce the reader to the event timer adapter API, showing 87how to create and configure an event timer adapter and use it to manage event 88timers. 89 90From a high level, the setup steps are: 91 92* rte_event_timer_adapter_create() 93* rte_event_timer_adapter_start() 94 95And to start and stop timers: 96 97* rte_event_timer_arm_burst() 98* rte_event_timer_cancel_burst() 99 100Create and Configure an Adapter Instance 101~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 102 103To create an event timer adapter instance, initialize an 104``rte_event_timer_adapter_conf`` struct with the desired values, and pass it 105to ``rte_event_timer_adapter_create()``. 106 107.. code-block:: c 108 109 #define NSECPERSEC 1E9 110 const struct rte_event_timer_adapter_conf adapter_config = { 111 .event_dev_id = event_dev_id, 112 .timer_adapter_id = 0, 113 .socket_id = rte_socket_id(), 114 .clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK, 115 .timer_tick_ns = NSECPERSEC / 10, 116 .max_tmo_ns = 180 * NSECPERSEC, 117 .nb_timers = 40000, 118 .flags = 0, 119 }; 120 121 struct rte_event_timer_adapter *adapter; 122 adapter = rte_event_timer_adapter_create(&adapter_config); 123 124 if (adapter == NULL) { ... }; 125 126Before creating an instance of a timer adapter, the application should create 127and configure an event device along with its event ports. Based on the event 128device capability, it might require creating an additional event port to be 129used by the timer adapter. If required, the 130``rte_event_timer_adapter_create()`` function will use a default method to 131configure an event port; it will examine the current event device 132configuration, determine the next available port identifier number, and create 133a new event port with a default port configuration. 134 135If the application desires to have finer control of event port allocation 136and setup, it can use the ``rte_event_timer_adapter_create_ext()`` function. 137This function is passed a callback function that will be invoked if the 138adapter needs to create an event port, giving the application the opportunity 139to control how it is done. 140 141Event device configuration for service based adapter 142^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 143 144When ``rte_event_timer_adapter_create()`` is used for creating 145adapter instance, ``rte_event_dev_config::nb_event_ports`` is 146automatically incremented, and the event device is reconfigured 147with additional event port during service initialization. 148This event device reconfigure logic also increments the 149``rte_event_dev_config::nb_single_link_event_port_queues`` 150parameter if the adapter event port config is of type 151``RTE_EVENT_PORT_CFG_SINGLE_LINK``. 152 153Application no longer needs to account for the 154``rte_event_dev_config::nb_event_ports`` and 155``rte_event_dev_config::nb_single_link_event_port_queues`` 156parameters required for timer adapter in event device configuration, 157when the adapter is created using the above-mentioned API. 158 159Adapter modes 160^^^^^^^^^^^^^ 161An event timer adapter can be configured in either periodic or non-periodic mode 162to support timers of the respective type. A periodic timer expires at a fixed 163time interval repeatedly till it is cancelled. A non-periodic timer expires only 164once. The periodic capability flag, ``RTE_EVENT_TIMER_ADAPTER_CAP_PERIODIC``, 165can be set for implementations that support periodic mode if desired. To 166configure an adapter in periodic mode, ``flags`` of 167``rte_event_timer_adapter_conf`` is set to include the periodic flag 168``RTE_EVENT_TIMER_ADAPTER_F_PERIODIC``. Maximum timeout (``max_tmo_ns``) does 169not apply to periodic mode. 170 171Retrieve Event Timer Adapter Contextual Information 172~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 173The event timer adapter implementation may have constraints on tick resolution 174or maximum timer expiry timeout based on the given event timer adapter or 175system. In this case, the implementation may adjust the tick resolution or 176maximum timeout to the best possible configuration. 177 178Upon successful event timer adapter creation, the application can get the 179configured resolution and max timeout with 180``rte_event_timer_adapter_get_info()``. This function will return an 181``rte_event_timer_adapter_info`` struct, which contains the following members: 182 183* ``min_resolution_ns`` - Minimum timer adapter tick resolution in ns. 184* ``max_tmo_ns`` - Maximum timer timeout(expiry) in ns. 185* ``adapter_conf`` - Configured event timer adapter attributes 186 187Configuring the Service Component 188~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 189 190If the adapter uses a service component, the application is required to map 191the service to a service core before starting the adapter: 192 193.. code-block:: c 194 195 uint32_t service_id; 196 197 if (rte_event_timer_adapter_service_id_get(adapter, &service_id) == 0) 198 rte_service_map_lcore_set(service_id, EVTIM_CORE_ID); 199 200An event timer adapter uses a service component if the event device PMD 201indicates that the adapter should use a software implementation. 202 203Starting the Adapter Instance 204~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 205 206The application should call ``rte_event_timer_adapter_start()`` to start 207running the event timer adapter. This function calls the start entry points 208defined by eventdev PMDs for hardware implementations or puts a service 209component into the running state in the software implementation. 210 211.. Note:: 212 213 The eventdev to which the event_timer_adapter is connected needs to 214 be started before calling rte_event_timer_adapter_start(). 215 216Arming Event Timers 217~~~~~~~~~~~~~~~~~~~ 218 219Once an event timer adapter has been started, an application can begin to 220manage event timers with it. 221 222The application should allocate ``struct rte_event_timer`` objects from a 223mempool or huge-page backed application buffers of required size. Upon 224successful allocation, the application should initialize the event timer, and 225then set any of the necessary event attributes described in the 226`Timer Expiry Event`_ section. In the following example, assume ``conn`` 227represents a TCP connection and that ``event_timer_pool`` is a mempool that 228was created previously: 229 230.. code-block:: c 231 232 rte_mempool_get(event_timer_pool, (void **)&conn->evtim); 233 if (conn->evtim == NULL) { ... } 234 235 /* Set up the event timer. */ 236 conn->evtim->ev.op = RTE_EVENT_OP_NEW; 237 conn->evtim->ev.queue_id = event_queue_id; 238 conn->evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; 239 conn->evtim->ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL; 240 conn->evtim->ev.event_type = RTE_EVENT_TYPE_TIMER; 241 conn->evtim->ev.event_ptr = conn; 242 conn->evtim->state = RTE_EVENT_TIMER_NOT_ARMED; 243 conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns) 244 245Note that it is necessary to initialize the event timer state to 246RTE_EVENT_TIMER_NOT_ARMED. Also note that we have saved a pointer to the 247``conn`` object in the timer's event payload. This will allow us to locate 248the connection object again once we dequeue the timer expiry event from the 249event device later. 250 251Now we can arm the event timer with ``rte_event_timer_arm_burst()``: 252 253.. code-block:: c 254 255 ret = rte_event_timer_arm_burst(adapter, &conn->evtim, 1); 256 if (ret != 1) { ... } 257 258Once an event timer expires, the application may free it or rearm it as 259necessary. If the application will rearm the timer, the state should be reset 260to RTE_EVENT_TIMER_NOT_ARMED by the application before rearming it. Timer expiry 261events will be generated once or periodically until the timer is cancelled based 262on adapter mode. 263 264Multiple Event Timers with Same Expiry Value 265^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 266 267In the special case that there is a set of event timers that should all expire 268at the same time, the application may call 269``rte_event_timer_arm_tmo_tick_burst()``, which allows the implementation to 270optimize the operation if possible. 271 272Canceling Event Timers 273~~~~~~~~~~~~~~~~~~~~~~ 274 275An event timer that has been armed as described in `Arming Event Timers`_ can 276be canceled by calling ``rte_event_timer_cancel_burst()``: 277 278.. code-block:: c 279 280 /* Ack for the previous tcp data packet has been received; 281 * cancel the retransmission timer 282 */ 283 rte_event_timer_cancel_burst(adapter, &conn->timer, 1); 284 285Processing Timer Expiry Events 286------------------------------ 287 288Once an event timer has successfully enqueued a timer expiry event in the event 289device, the application will subsequently dequeue it from the event device. 290The application can use the event payload to retrieve a pointer to the object 291associated with the event timer. It can then re-arm the event timer or free the 292event timer object as desired: 293 294.. code-block:: c 295 296 void 297 event_processing_loop(...) 298 { 299 while (...) { 300 /* Receive events from the configured event port. */ 301 rte_event_dequeue_burst(event_dev_id, event_port, &ev, 1, 0); 302 ... 303 switch(ev.event_type) { 304 ... 305 case RTE_EVENT_TYPE_TIMER: 306 process_timer_event(ev); 307 ... 308 break; 309 } 310 } 311 } 312 313 uint8_t 314 process_timer_event(...) 315 { 316 /* A retransmission timeout for the connection has been received. */ 317 conn = ev.event_ptr; 318 /* Retransmit last packet (e.g. TCP segment). */ 319 ... 320 /* Re-arm timer using original values. */ 321 rte_event_timer_arm_burst(adapter_id, &conn->timer, 1); 322 } 323 324Summary 325------- 326 327The Event Timer Adapter library extends the DPDK event-based programming model 328by representing timer expirations as events in the system and allowing 329applications to use existing event processing loops to arm and cancel event 330timers or handle timer expiry events. 331