xref: /dpdk/doc/guides/prog_guide/metrics_lib.rst (revision 90197eb0945b50c9cd6e11f310cfc5078b28f75e)
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
157Bit-rate statistics library
158---------------------------
159
160The bit-rate library calculates the exponentially-weighted moving
161average and peak bit-rates for each active port (i.e. network device).
162These statistics are reported via the metrics library using the
163following names:
164
165    - ``mean_bits_in``: Average inbound bit-rate
166    - ``mean_bits_out``:  Average outbound bit-rate
167    - ``ewma_bits_in``: Average inbound bit-rate (EWMA smoothed)
168    - ``ewma_bits_out``:  Average outbound bit-rate (EWMA smoothed)
169    - ``peak_bits_in``:  Peak inbound bit-rate
170    - ``peak_bits_out``:  Peak outbound bit-rate
171
172Once initialised and clocked at the appropriate frequency, these
173statistics can be obtained by querying the metrics library.
174
175Initialization
176~~~~~~~~~~~~~~
177
178Before the library can be used, it has to be initialised by calling
179``rte_stats_bitrate_create()``, which will return a bit-rate
180calculation object. Since the bit-rate library uses the metrics library
181to report the calculated statistics, the bit-rate library then needs to
182register the calculated statistics with the metrics library. This is
183done using the helper function ``rte_stats_bitrate_reg()``.
184
185.. code-block:: c
186
187    struct rte_stats_bitrates *bitrate_data;
188
189    bitrate_data = rte_stats_bitrate_create();
190    if (bitrate_data == NULL)
191        rte_exit(EXIT_FAILURE, "Could not allocate bit-rate data.\n");
192    rte_stats_bitrate_reg(bitrate_data);
193
194Controlling the sampling rate
195~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
196
197Since the library works by periodic sampling but does not use an
198internal thread, the application has to periodically call
199``rte_stats_bitrate_calc()``. The frequency at which this function
200is called should be the intended sampling rate required for the
201calculated statistics. For instance if per-second statistics are
202desired, this function should be called once a second.
203
204.. code-block:: c
205
206    tics_datum = rte_rdtsc();
207    tics_per_1sec = rte_get_timer_hz();
208
209    while( 1 ) {
210        /* ... */
211        tics_current = rte_rdtsc();
212	if (tics_current - tics_datum >= tics_per_1sec) {
213	    /* Periodic bitrate calculation */
214	    for (idx_port = 0; idx_port < cnt_ports; idx_port++)
215	            rte_stats_bitrate_calc(bitrate_data, idx_port);
216		tics_datum = tics_current;
217	    }
218        /* ... */
219    }
220
221
222Latency statistics library
223--------------------------
224
225The latency statistics library calculates the latency of packet
226processing by a DPDK application, reporting the minimum, average,
227and maximum nano-seconds that packet processing takes, as well as
228the jitter in processing delay. These statistics are then reported
229via the metrics library using the following names:
230
231    - ``min_latency_ns``: Minimum processing latency (nano-seconds)
232    - ``avg_latency_ns``:  Average  processing latency (nano-seconds)
233    - ``mac_latency_ns``:  Maximum  processing latency (nano-seconds)
234    - ``jitter_ns``: Variance in processing latency (nano-seconds)
235
236Once initialised and clocked at the appropriate frequency, these
237statistics can be obtained by querying the metrics library.
238
239Initialization
240~~~~~~~~~~~~~~
241
242Before the library can be used, it has to be initialised by calling
243``rte_latencystats_init()``.
244
245.. code-block:: c
246
247    lcoreid_t latencystats_lcore_id = -1;
248
249    int ret = rte_latencystats_init(1, NULL);
250    if (ret)
251        rte_exit(EXIT_FAILURE, "Could not allocate latency data.\n");
252
253
254Triggering statistic updates
255~~~~~~~~~~~~~~~~~~~~~~~~~~~~
256
257The ``rte_latencystats_update()`` function needs to be called
258periodically so that latency statistics can be updated.
259
260.. code-block:: c
261
262    if (latencystats_lcore_id == rte_lcore_id())
263        rte_latencystats_update();
264
265Library shutdown
266~~~~~~~~~~~~~~~~
267
268When finished, ``rte_latencystats_uninit()`` needs to be called to
269de-initialise the latency library.
270
271.. code-block:: c
272
273    rte_latencystats_uninit();
274
275Timestamp and latency calculation
276~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
277
278The Latency stats library marks the time in the timestamp field of the
279mbuf for the ingress packets and sets the ``PKT_RX_TIMESTAMP`` flag of
280``ol_flags`` for the mbuf to indicate the marked time as a valid one.
281At the egress, the mbufs with the flag set are considered having valid
282timestamp and are used for the latency calculation.
283