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