xref: /dpdk/doc/guides/prog_guide/metrics_lib.rst (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
1..  SPDX-License-Identifier: BSD-3-Clause
2    Copyright(c) 2017 Intel Corporation.
3
4.. _Metrics_Library:
5
6Metrics Library
7===============
8
9The Metrics library implements a mechanism by which *producers* can
10publish numeric information for later querying by *consumers*. In
11practice producers will typically be other libraries or primary
12processes, whereas consumers will typically be applications.
13
14Metrics themselves are statistics that are not generated by PMDs. Metric
15information is populated using a push model, where producers update the
16values contained within the metric library by calling an update function
17on the relevant metrics. Consumers receive metric information by querying
18the central metric data, which is held in shared memory.
19
20For each metric, a separate value is maintained for each port id, and
21when publishing metric values the producers need to specify which port is
22being updated. In addition there is a special id ``RTE_METRICS_GLOBAL``
23that is intended for global statistics that are not associated with any
24individual device. Since the metrics library is self-contained, the only
25restriction on port numbers is that they are less than ``RTE_MAX_ETHPORTS``
26- there is no requirement for the ports to actually exist.
27
28Initializing the library
29------------------------
30
31Before the library can be used, it has to be initialized by calling
32``rte_metrics_init()`` which sets up the metric store in shared memory.
33This is where producers will publish metric information to, and where
34consumers will query it from.
35
36.. code-block:: c
37
38    rte_metrics_init(rte_socket_id());
39
40This function **must** be called from a primary process, but otherwise
41producers and consumers can be in either primary or secondary processes.
42
43Registering metrics
44-------------------
45
46Metrics must first be *registered*, which is the way producers declare
47the names of the metrics they will be publishing. Registration can either
48be done individually, or a set of metrics can be registered as a group.
49Individual registration is done using ``rte_metrics_reg_name()``:
50
51.. code-block:: c
52
53    id_1 = rte_metrics_reg_name("mean_bits_in");
54    id_2 = rte_metrics_reg_name("mean_bits_out");
55    id_3 = rte_metrics_reg_name("peak_bits_in");
56    id_4 = rte_metrics_reg_name("peak_bits_out");
57
58or alternatively, a set of metrics can be registered together using
59``rte_metrics_reg_names()``:
60
61.. code-block:: c
62
63    const char * const names[] = {
64        "mean_bits_in", "mean_bits_out",
65        "peak_bits_in", "peak_bits_out",
66    };
67    id_set = rte_metrics_reg_names(&names[0], 4);
68
69If the return value is negative, it means registration failed. Otherwise
70the return value is the *key* for the metric, which is used when updating
71values. A table mapping together these key values and the metrics' names
72can be obtained using ``rte_metrics_get_names()``.
73
74Updating metric values
75----------------------
76
77Once registered, producers can update the metric for a given port using
78the ``rte_metrics_update_value()`` function. This uses the metric key
79that is returned when registering the metric, and can also be looked up
80using ``rte_metrics_get_names()``.
81
82.. code-block:: c
83
84    rte_metrics_update_value(port_id, id_1, values[0]);
85    rte_metrics_update_value(port_id, id_2, values[1]);
86    rte_metrics_update_value(port_id, id_3, values[2]);
87    rte_metrics_update_value(port_id, id_4, values[3]);
88
89if metrics were registered as a single set, they can either be updated
90individually using ``rte_metrics_update_value()``, or updated together
91using the ``rte_metrics_update_values()`` function:
92
93.. code-block:: c
94
95    rte_metrics_update_value(port_id, id_set, values[0]);
96    rte_metrics_update_value(port_id, id_set + 1, values[1]);
97    rte_metrics_update_value(port_id, id_set + 2, values[2]);
98    rte_metrics_update_value(port_id, id_set + 3, values[3]);
99
100    rte_metrics_update_values(port_id, id_set, values, 4);
101
102Note that ``rte_metrics_update_values()`` cannot be used to update
103metric values from *multiple* *sets*, as there is no guarantee two
104sets registered one after the other have contiguous id values.
105
106Querying metrics
107----------------
108
109Consumers can obtain metric values by querying the metrics library using
110the ``rte_metrics_get_values()`` function that return an array of
111``struct rte_metric_value``. Each entry within this array contains a metric
112value and its associated key. A key-name mapping can be obtained using the
113``rte_metrics_get_names()`` function that returns an array of
114``struct rte_metric_name`` that is indexed by the key. The following will
115print out all metrics for a given port:
116
117.. code-block:: c
118
119    void print_metrics() {
120        struct rte_metric_value *metrics;
121        struct rte_metric_name *names;
122        int len;
123
124        len = rte_metrics_get_names(NULL, 0);
125        if (len < 0) {
126            printf("Cannot get metrics count\n");
127            return;
128        }
129        if (len == 0) {
130            printf("No metrics to display (none have been registered)\n");
131            return;
132        }
133        metrics = malloc(sizeof(struct rte_metric_value) * len);
134        names =  malloc(sizeof(struct rte_metric_name) * len);
135        if (metrics == NULL || names == NULL) {
136            printf("Cannot allocate memory\n");
137            free(metrics);
138            free(names);
139            return;
140        }
141        ret = rte_metrics_get_values(port_id, metrics, len);
142        if (ret < 0 || ret > len) {
143            printf("Cannot get metrics values\n");
144            free(metrics);
145            free(names);
146            return;
147        }
148        printf("Metrics for port %i:\n", port_id);
149        for (i = 0; i < len; i++)
150            printf("  %s: %"PRIu64"\n",
151                names[metrics[i].key].name, metrics[i].value);
152        free(metrics);
153        free(names);
154    }
155
156
157Deinitialising the library
158--------------------------
159
160Once the library usage is done, it must be deinitialized by calling
161``rte_metrics_deinit()`` which will free the shared memory reserved
162during initialization.
163
164.. code-block:: c
165
166    err = rte_metrics_deinit(void);
167
168If the return value is negative, it means deinitialization failed.
169This function **must** be called from a primary process.
170
171Bit-rate statistics library
172---------------------------
173
174The bit-rate library calculates the exponentially-weighted moving
175average and peak bit-rates for each active port (i.e. network device).
176These statistics are reported via the metrics library using the
177following names:
178
179    - ``mean_bits_in``: Average inbound bit-rate
180    - ``mean_bits_out``:  Average outbound bit-rate
181    - ``ewma_bits_in``: Average inbound bit-rate (EWMA smoothed)
182    - ``ewma_bits_out``:  Average outbound bit-rate (EWMA smoothed)
183    - ``peak_bits_in``:  Peak inbound bit-rate
184    - ``peak_bits_out``:  Peak outbound bit-rate
185
186Once initialised and clocked at the appropriate frequency, these
187statistics can be obtained by querying the metrics library.
188
189Initialization
190~~~~~~~~~~~~~~
191
192Before the library can be used, it has to be initialised by calling
193``rte_stats_bitrate_create()``, which will return a bit-rate
194calculation object. Since the bit-rate library uses the metrics library
195to report the calculated statistics, the bit-rate library then needs to
196register the calculated statistics with the metrics library. This is
197done using the helper function ``rte_stats_bitrate_reg()``.
198
199.. code-block:: c
200
201    struct rte_stats_bitrates *bitrate_data;
202
203    bitrate_data = rte_stats_bitrate_create();
204    if (bitrate_data == NULL)
205        rte_exit(EXIT_FAILURE, "Could not allocate bit-rate data.\n");
206    rte_stats_bitrate_reg(bitrate_data);
207
208Controlling the sampling rate
209~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
210
211Since the library works by periodic sampling but does not use an
212internal thread, the application has to periodically call
213``rte_stats_bitrate_calc()``. The frequency at which this function
214is called should be the intended sampling rate required for the
215calculated statistics. For instance if per-second statistics are
216desired, this function should be called once a second.
217
218.. code-block:: c
219
220    tics_datum = rte_rdtsc();
221    tics_per_1sec = rte_get_timer_hz();
222
223    while( 1 ) {
224        /* ... */
225        tics_current = rte_rdtsc();
226	if (tics_current - tics_datum >= tics_per_1sec) {
227	    /* Periodic bitrate calculation */
228	    for (idx_port = 0; idx_port < cnt_ports; idx_port++)
229	            rte_stats_bitrate_calc(bitrate_data, idx_port);
230		tics_datum = tics_current;
231	    }
232        /* ... */
233    }
234
235
236Latency statistics library
237--------------------------
238
239The latency statistics library calculates the latency of packet
240processing by a DPDK application, reporting the minimum, average,
241and maximum nano-seconds that packet processing takes, as well as
242the jitter in processing delay. These statistics are then reported
243via the metrics library using the following names:
244
245    - ``min_latency_ns``: Minimum processing latency (nano-seconds)
246    - ``avg_latency_ns``:  Average  processing latency (nano-seconds)
247    - ``mac_latency_ns``:  Maximum  processing latency (nano-seconds)
248    - ``jitter_ns``: Variance in processing latency (nano-seconds)
249
250Once initialised and clocked at the appropriate frequency, these
251statistics can be obtained by querying the metrics library.
252
253Initialization
254~~~~~~~~~~~~~~
255
256Before the library can be used, it has to be initialised by calling
257``rte_latencystats_init()``.
258
259.. code-block:: c
260
261    lcoreid_t latencystats_lcore_id = -1;
262
263    int ret = rte_latencystats_init(1, NULL);
264    if (ret)
265        rte_exit(EXIT_FAILURE, "Could not allocate latency data.\n");
266
267
268Triggering statistic updates
269~~~~~~~~~~~~~~~~~~~~~~~~~~~~
270
271The ``rte_latencystats_update()`` function needs to be called
272periodically so that latency statistics can be updated.
273
274.. code-block:: c
275
276    if (latencystats_lcore_id == rte_lcore_id())
277        rte_latencystats_update();
278
279Library shutdown
280~~~~~~~~~~~~~~~~
281
282When finished, ``rte_latencystats_uninit()`` needs to be called to
283de-initialise the latency library.
284
285.. code-block:: c
286
287    rte_latencystats_uninit();
288
289Timestamp and latency calculation
290~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
291
292The Latency stats library marks the time in the timestamp field of the
293mbuf for the ingress packets and sets the ``RTE_MBUF_F_RX_TIMESTAMP`` flag of
294``ol_flags`` for the mbuf to indicate the marked time as a valid one.
295At the egress, the mbufs with the flag set are considered having valid
296timestamp and are used for the latency calculation.
297