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