5cbe17c9037a41ef62c8b67bf0fa8b2da61ce4b7
[dpdk.git] / doc / guides / prog_guide / metrics_lib.rst
1 ..  SPDX-License-Identifier: BSD-3-Clause
2     Copyright(c) 2017 Intel Corporation.
3
4 .. _Metrics_Library:
5
6 Metrics Library
7 ===============
8
9 The Metrics library implements a mechanism by which *producers* can
10 publish numeric information for later querying by *consumers*. In
11 practice producers will typically be other libraries or primary
12 processes, whereas consumers will typically be applications.
13
14 Metrics themselves are statistics that are not generated by PMDs. Metric
15 information is populated using a push model, where producers update the
16 values contained within the metric library by calling an update function
17 on the relevant metrics. Consumers receive metric information by querying
18 the central metric data, which is held in shared memory.
19
20 For each metric, a separate value is maintained for each port id, and
21 when publishing metric values the producers need to specify which port is
22 being updated. In addition there is a special id ``RTE_METRICS_GLOBAL``
23 that is intended for global statistics that are not associated with any
24 individual device. Since the metrics library is self-contained, the only
25 restriction on port numbers is that they are less than ``RTE_MAX_ETHPORTS``
26 - there is no requirement for the ports to actually exist.
27
28 Initialising the library
29 ------------------------
30
31 Before 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.
33 This is where producers will publish metric information to, and where
34 consumers will query it from.
35
36 .. code-block:: c
37
38     rte_metrics_init(rte_socket_id());
39
40 This function **must** be called from a primary process, but otherwise
41 producers and consumers can be in either primary or secondary processes.
42
43 Registering metrics
44 -------------------
45
46 Metrics must first be *registered*, which is the way producers declare
47 the names of the metrics they will be publishing. Registration can either
48 be done individually, or a set of metrics can be registered as a group.
49 Individual 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
58 or 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
69 If the return value is negative, it means registration failed. Otherwise
70 the return value is the *key* for the metric, which is used when updating
71 values. A table mapping together these key values and the metrics' names
72 can be obtained using ``rte_metrics_get_names()``.
73
74 Updating metric values
75 ----------------------
76
77 Once registered, producers can update the metric for a given port using
78 the ``rte_metrics_update_value()`` function. This uses the metric key
79 that is returned when registering the metric, and can also be looked up
80 using ``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
89 if metrics were registered as a single set, they can either be updated
90 individually using ``rte_metrics_update_value()``, or updated together
91 using 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
102 Note that ``rte_metrics_update_values()`` cannot be used to update
103 metric values from *multiple* *sets*, as there is no guarantee two
104 sets registered one after the other have contiguous id values.
105
106 Querying metrics
107 ----------------
108
109 Consumers can obtain metric values by querying the metrics library using
110 the ``rte_metrics_get_values()`` function that return an array of
111 ``struct rte_metric_value``. Each entry within this array contains a metric
112 value 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
115 print 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
157 Bit-rate statistics library
158 ---------------------------
159
160 The bit-rate library calculates the exponentially-weighted moving
161 average and peak bit-rates for each active port (i.e. network device).
162 These statistics are reported via the metrics library using the
163 following 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
172 Once initialised and clocked at the appropriate frequency, these
173 statistics can be obtained by querying the metrics library.
174
175 Initialization
176 ~~~~~~~~~~~~~~
177
178 Before the library can be used, it has to be initialised by calling
179 ``rte_stats_bitrate_create()``, which will return a bit-rate
180 calculation object. Since the bit-rate library uses the metrics library
181 to report the calculated statistics, the bit-rate library then needs to
182 register the calculated statistics with the metrics library. This is
183 done 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
194 Controlling the sampling rate
195 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
196
197 Since the library works by periodic sampling but does not use an
198 internal thread, the application has to periodically call
199 ``rte_stats_bitrate_calc()``. The frequency at which this function
200 is called should be the intended sampling rate required for the
201 calculated statistics. For instance if per-second statistics are
202 desired, 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
222 Latency statistics library
223 --------------------------
224
225 The latency statistics library calculates the latency of packet
226 processing by a DPDK application, reporting the minimum, average,
227 and maximum nano-seconds that packet processing takes, as well as
228 the jitter in processing delay. These statistics are then reported
229 via 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
236 Once initialised and clocked at the appropriate frequency, these
237 statistics can be obtained by querying the metrics library.
238
239 Initialization
240 ~~~~~~~~~~~~~~
241
242 Before 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
254 Triggering statistic updates
255 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
256
257 The ``rte_latencystats_update()`` function needs to be called
258 periodically 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
265 Library shutdown
266 ~~~~~~~~~~~~~~~~
267
268 When finished, ``rte_latencystats_uninit()`` needs to be called to
269 de-initialise the latency library.
270
271 .. code-block:: c
272
273     rte_latencystats_uninit();