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