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