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