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/librte_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 141Retrieve Event Timer Adapter Contextual Information 142~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 143The event timer adapter implementation may have constraints on tick resolution 144or maximum timer expiry timeout based on the given event timer adapter or 145system. In this case, the implementation may adjust the tick resolution or 146maximum timeout to the best possible configuration. 147 148Upon successful event timer adapter creation, the application can get the 149configured resolution and max timeout with 150``rte_event_timer_adapter_get_info()``. This function will return an 151``rte_event_timer_adapter_info`` struct, which contains the following members: 152 153* ``min_resolution_ns`` - Minimum timer adapter tick resolution in ns. 154* ``max_tmo_ns`` - Maximum timer timeout(expiry) in ns. 155* ``adapter_conf`` - Configured event timer adapter attributes 156 157Configuring the Service Component 158~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 159 160If the adapter uses a service component, the application is required to map 161the service to a service core before starting the adapter: 162 163.. code-block:: c 164 165 uint32_t service_id; 166 167 if (rte_event_timer_adapter_service_id_get(adapter, &service_id) == 0) 168 rte_service_map_lcore_set(service_id, EVTIM_CORE_ID); 169 170An event timer adapter uses a service component if the event device PMD 171indicates that the adapter should use a software implementation. 172 173Starting the Adapter Instance 174~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 175 176The application should call ``rte_event_timer_adapter_start()`` to start 177running the event timer adapter. This function calls the start entry points 178defined by eventdev PMDs for hardware implementations or puts a service 179component into the running state in the software implementation. 180 181.. Note:: 182 183 The eventdev to which the event_timer_adapter is connected needs to 184 be started before calling rte_event_timer_adapter_start(). 185 186Arming Event Timers 187~~~~~~~~~~~~~~~~~~~ 188 189Once an event timer adapter has been started, an application can begin to 190manage event timers with it. 191 192The application should allocate ``struct rte_event_timer`` objects from a 193mempool or huge-page backed application buffers of required size. Upon 194successful allocation, the application should initialize the event timer, and 195then set any of the necessary event attributes described in the 196`Timer Expiry Event`_ section. In the following example, assume ``conn`` 197represents a TCP connection and that ``event_timer_pool`` is a mempool that 198was created previously: 199 200.. code-block:: c 201 202 rte_mempool_get(event_timer_pool, (void **)&conn->evtim); 203 if (conn->evtim == NULL) { ... } 204 205 /* Set up the event timer. */ 206 conn->evtim->ev.op = RTE_EVENT_OP_NEW; 207 conn->evtim->ev.queue_id = event_queue_id; 208 conn->evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC; 209 conn->evtim->ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL; 210 conn->evtim->ev.event_type = RTE_EVENT_TYPE_TIMER; 211 conn->evtim->ev.event_ptr = conn; 212 conn->evtim->state = RTE_EVENT_TIMER_NOT_ARMED; 213 conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns) 214 215Note that it is necessary to initialize the event timer state to 216RTE_EVENT_TIMER_NOT_ARMED. Also note that we have saved a pointer to the 217``conn`` object in the timer's event payload. This will allow us to locate 218the connection object again once we dequeue the timer expiry event from the 219event device later. As a convenience, the application may specify no value for 220ev.event_ptr, and the adapter will by default set it to point at the event 221timer itself. 222 223Now we can arm the event timer with ``rte_event_timer_arm_burst()``: 224 225.. code-block:: c 226 227 ret = rte_event_timer_arm_burst(adapter, &conn->evtim, 1); 228 if (ret != 1) { ... } 229 230Once an event timer expires, the application may free it or rearm it as 231necessary. If the application will rearm the timer, the state should be reset 232to RTE_EVENT_TIMER_NOT_ARMED by the application before rearming it. 233 234Multiple Event Timers with Same Expiry Value 235^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 236 237In the special case that there is a set of event timers that should all expire 238at the same time, the application may call 239``rte_event_timer_arm_tmo_tick_burst()``, which allows the implementation to 240optimize the operation if possible. 241 242Canceling Event Timers 243~~~~~~~~~~~~~~~~~~~~~~ 244 245An event timer that has been armed as described in `Arming Event Timers`_ can 246be canceled by calling ``rte_event_timer_cancel_burst()``: 247 248.. code-block:: c 249 250 /* Ack for the previous tcp data packet has been received; 251 * cancel the retransmission timer 252 */ 253 rte_event_timer_cancel_burst(adapter, &conn->timer, 1); 254 255Processing Timer Expiry Events 256------------------------------ 257 258Once an event timer has successfully enqueued a timer expiry event in the event 259device, the application will subsequently dequeue it from the event device. 260The application can use the event payload to retrieve a pointer to the object 261associated with the event timer. It can then re-arm the event timer or free the 262event timer object as desired: 263 264.. code-block:: c 265 266 void 267 event_processing_loop(...) 268 { 269 while (...) { 270 /* Receive events from the configured event port. */ 271 rte_event_dequeue_burst(event_dev_id, event_port, &ev, 1, 0); 272 ... 273 switch(ev.event_type) { 274 ... 275 case RTE_EVENT_TYPE_TIMER: 276 process_timer_event(ev); 277 ... 278 break; 279 } 280 } 281 } 282 283 uint8_t 284 process_timer_event(...) 285 { 286 /* A retransmission timeout for the connection has been received. */ 287 conn = ev.event_ptr; 288 /* Retransmit last packet (e.g. TCP segment). */ 289 ... 290 /* Re-arm timer using original values. */ 291 rte_event_timer_arm_burst(adapter_id, &conn->timer, 1); 292 } 293 294Summary 295------- 296 297The Event Timer Adapter library extends the DPDK event-based programming model 298by representing timer expirations as events in the system and allowing 299applications to use existing event processing loops to arm and cancel event 300timers or handle timer expiry events. 301