event/cnxk: add option to configure getwork mode
[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 Initializing 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 Deinitialising the library
158 --------------------------
159
160 Once the library usage is done, it must be deinitialized by calling
161 ``rte_metrics_deinit()`` which will free the shared memory reserved
162 during initialization.
163
164 .. code-block:: c
165
166     err = rte_metrics_deinit(void);
167
168 If the return value is negative, it means deinitialization failed.
169 This function **must** be called from a primary process.
170
171 Bit-rate statistics library
172 ---------------------------
173
174 The bit-rate library calculates the exponentially-weighted moving
175 average and peak bit-rates for each active port (i.e. network device).
176 These statistics are reported via the metrics library using the
177 following 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
186 Once initialised and clocked at the appropriate frequency, these
187 statistics can be obtained by querying the metrics library.
188
189 Initialization
190 ~~~~~~~~~~~~~~
191
192 Before the library can be used, it has to be initialised by calling
193 ``rte_stats_bitrate_create()``, which will return a bit-rate
194 calculation object. Since the bit-rate library uses the metrics library
195 to report the calculated statistics, the bit-rate library then needs to
196 register the calculated statistics with the metrics library. This is
197 done 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
208 Controlling the sampling rate
209 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
210
211 Since the library works by periodic sampling but does not use an
212 internal thread, the application has to periodically call
213 ``rte_stats_bitrate_calc()``. The frequency at which this function
214 is called should be the intended sampling rate required for the
215 calculated statistics. For instance if per-second statistics are
216 desired, 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
236 Latency statistics library
237 --------------------------
238
239 The latency statistics library calculates the latency of packet
240 processing by a DPDK application, reporting the minimum, average,
241 and maximum nano-seconds that packet processing takes, as well as
242 the jitter in processing delay. These statistics are then reported
243 via 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
250 Once initialised and clocked at the appropriate frequency, these
251 statistics can be obtained by querying the metrics library.
252
253 Initialization
254 ~~~~~~~~~~~~~~
255
256 Before 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
268 Triggering statistic updates
269 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
270
271 The ``rte_latencystats_update()`` function needs to be called
272 periodically 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
279 Library shutdown
280 ~~~~~~~~~~~~~~~~
281
282 When finished, ``rte_latencystats_uninit()`` needs to be called to
283 de-initialise the latency library.
284
285 .. code-block:: c
286
287     rte_latencystats_uninit();
288
289 Timestamp and latency calculation
290 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
291
292 The Latency stats library marks the time in the timestamp field of the
293 mbuf for the ingress packets and sets the ``PKT_RX_TIMESTAMP`` flag of
294 ``ol_flags`` for the mbuf to indicate the marked time as a valid one.
295 At the egress, the mbufs with the flag set are considered having valid
296 timestamp and are used for the latency calculation.