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