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