15630257fSFerruh Yigit.. SPDX-License-Identifier: BSD-3-Clause 25630257fSFerruh Yigit Copyright(c) 2017 Intel Corporation. 3349950ddSRemy Horton 4349950ddSRemy HortonMetrics Library 5349950ddSRemy Horton=============== 6349950ddSRemy Horton 7349950ddSRemy HortonThe Metrics library implements a mechanism by which *producers* can 8349950ddSRemy Hortonpublish numeric information for later querying by *consumers*. In 9349950ddSRemy Hortonpractice producers will typically be other libraries or primary 10349950ddSRemy Hortonprocesses, whereas consumers will typically be applications. 11349950ddSRemy Horton 12349950ddSRemy HortonMetrics themselves are statistics that are not generated by PMDs. Metric 13349950ddSRemy Hortoninformation is populated using a push model, where producers update the 14349950ddSRemy Hortonvalues contained within the metric library by calling an update function 15349950ddSRemy Hortonon the relevant metrics. Consumers receive metric information by querying 16349950ddSRemy Hortonthe central metric data, which is held in shared memory. 17349950ddSRemy Horton 18349950ddSRemy HortonFor each metric, a separate value is maintained for each port id, and 19349950ddSRemy Hortonwhen publishing metric values the producers need to specify which port is 20349950ddSRemy Hortonbeing updated. In addition there is a special id ``RTE_METRICS_GLOBAL`` 21349950ddSRemy Hortonthat is intended for global statistics that are not associated with any 22349950ddSRemy Hortonindividual device. Since the metrics library is self-contained, the only 23349950ddSRemy Hortonrestriction on port numbers is that they are less than ``RTE_MAX_ETHPORTS`` 24349950ddSRemy Horton- there is no requirement for the ports to actually exist. 25349950ddSRemy Horton 26d629b7b5SJohn McNamaraInitializing the library 27349950ddSRemy Horton------------------------ 28349950ddSRemy Horton 29349950ddSRemy HortonBefore the library can be used, it has to be initialized by calling 30349950ddSRemy Horton``rte_metrics_init()`` which sets up the metric store in shared memory. 31349950ddSRemy HortonThis is where producers will publish metric information to, and where 32349950ddSRemy Hortonconsumers will query it from. 33349950ddSRemy Horton 34349950ddSRemy Horton.. code-block:: c 35349950ddSRemy Horton 36349950ddSRemy Horton rte_metrics_init(rte_socket_id()); 37349950ddSRemy Horton 38349950ddSRemy HortonThis function **must** be called from a primary process, but otherwise 39349950ddSRemy Hortonproducers and consumers can be in either primary or secondary processes. 40349950ddSRemy Horton 41349950ddSRemy HortonRegistering metrics 42349950ddSRemy Horton------------------- 43349950ddSRemy Horton 44349950ddSRemy HortonMetrics must first be *registered*, which is the way producers declare 45349950ddSRemy Hortonthe names of the metrics they will be publishing. Registration can either 46349950ddSRemy Hortonbe done individually, or a set of metrics can be registered as a group. 47349950ddSRemy HortonIndividual registration is done using ``rte_metrics_reg_name()``: 48349950ddSRemy Horton 49349950ddSRemy Horton.. code-block:: c 50349950ddSRemy Horton 51349950ddSRemy Horton id_1 = rte_metrics_reg_name("mean_bits_in"); 52349950ddSRemy Horton id_2 = rte_metrics_reg_name("mean_bits_out"); 53349950ddSRemy Horton id_3 = rte_metrics_reg_name("peak_bits_in"); 54349950ddSRemy Horton id_4 = rte_metrics_reg_name("peak_bits_out"); 55349950ddSRemy Horton 56349950ddSRemy Hortonor alternatively, a set of metrics can be registered together using 57349950ddSRemy Horton``rte_metrics_reg_names()``: 58349950ddSRemy Horton 59349950ddSRemy Horton.. code-block:: c 60349950ddSRemy Horton 61349950ddSRemy Horton const char * const names[] = { 62349950ddSRemy Horton "mean_bits_in", "mean_bits_out", 63349950ddSRemy Horton "peak_bits_in", "peak_bits_out", 64349950ddSRemy Horton }; 65349950ddSRemy Horton id_set = rte_metrics_reg_names(&names[0], 4); 66349950ddSRemy Horton 67349950ddSRemy HortonIf the return value is negative, it means registration failed. Otherwise 68349950ddSRemy Hortonthe return value is the *key* for the metric, which is used when updating 69349950ddSRemy Hortonvalues. A table mapping together these key values and the metrics' names 70349950ddSRemy Hortoncan be obtained using ``rte_metrics_get_names()``. 71349950ddSRemy Horton 72349950ddSRemy HortonUpdating metric values 73349950ddSRemy Horton---------------------- 74349950ddSRemy Horton 75349950ddSRemy HortonOnce registered, producers can update the metric for a given port using 76349950ddSRemy Hortonthe ``rte_metrics_update_value()`` function. This uses the metric key 77349950ddSRemy Hortonthat is returned when registering the metric, and can also be looked up 78349950ddSRemy Hortonusing ``rte_metrics_get_names()``. 79349950ddSRemy Horton 80349950ddSRemy Horton.. code-block:: c 81349950ddSRemy Horton 82349950ddSRemy Horton rte_metrics_update_value(port_id, id_1, values[0]); 83349950ddSRemy Horton rte_metrics_update_value(port_id, id_2, values[1]); 84349950ddSRemy Horton rte_metrics_update_value(port_id, id_3, values[2]); 85349950ddSRemy Horton rte_metrics_update_value(port_id, id_4, values[3]); 86349950ddSRemy Horton 87349950ddSRemy Hortonif metrics were registered as a single set, they can either be updated 88349950ddSRemy Hortonindividually using ``rte_metrics_update_value()``, or updated together 89349950ddSRemy Hortonusing the ``rte_metrics_update_values()`` function: 90349950ddSRemy Horton 91349950ddSRemy Horton.. code-block:: c 92349950ddSRemy Horton 93349950ddSRemy Horton rte_metrics_update_value(port_id, id_set, values[0]); 94349950ddSRemy Horton rte_metrics_update_value(port_id, id_set + 1, values[1]); 95349950ddSRemy Horton rte_metrics_update_value(port_id, id_set + 2, values[2]); 96349950ddSRemy Horton rte_metrics_update_value(port_id, id_set + 3, values[3]); 97349950ddSRemy Horton 98349950ddSRemy Horton rte_metrics_update_values(port_id, id_set, values, 4); 99349950ddSRemy Horton 100349950ddSRemy HortonNote that ``rte_metrics_update_values()`` cannot be used to update 101349950ddSRemy Hortonmetric values from *multiple* *sets*, as there is no guarantee two 102349950ddSRemy Hortonsets registered one after the other have contiguous id values. 103349950ddSRemy Horton 104349950ddSRemy HortonQuerying metrics 105349950ddSRemy Horton---------------- 106349950ddSRemy Horton 107349950ddSRemy HortonConsumers can obtain metric values by querying the metrics library using 108349950ddSRemy Hortonthe ``rte_metrics_get_values()`` function that return an array of 109349950ddSRemy Horton``struct rte_metric_value``. Each entry within this array contains a metric 110349950ddSRemy Hortonvalue and its associated key. A key-name mapping can be obtained using the 111349950ddSRemy Horton``rte_metrics_get_names()`` function that returns an array of 112349950ddSRemy Horton``struct rte_metric_name`` that is indexed by the key. The following will 113349950ddSRemy Hortonprint out all metrics for a given port: 114349950ddSRemy Horton 115349950ddSRemy Horton.. code-block:: c 116349950ddSRemy Horton 117349950ddSRemy Horton void print_metrics() { 118c17c27e8SYong Wang struct rte_metric_value *metrics; 119349950ddSRemy Horton struct rte_metric_name *names; 120349950ddSRemy Horton int len; 121349950ddSRemy Horton 122349950ddSRemy Horton len = rte_metrics_get_names(NULL, 0); 123349950ddSRemy Horton if (len < 0) { 124349950ddSRemy Horton printf("Cannot get metrics count\n"); 125349950ddSRemy Horton return; 126349950ddSRemy Horton } 127349950ddSRemy Horton if (len == 0) { 128349950ddSRemy Horton printf("No metrics to display (none have been registered)\n"); 129349950ddSRemy Horton return; 130349950ddSRemy Horton } 131349950ddSRemy Horton metrics = malloc(sizeof(struct rte_metric_value) * len); 132349950ddSRemy Horton names = malloc(sizeof(struct rte_metric_name) * len); 133349950ddSRemy Horton if (metrics == NULL || names == NULL) { 134349950ddSRemy Horton printf("Cannot allocate memory\n"); 135349950ddSRemy Horton free(metrics); 136349950ddSRemy Horton free(names); 137349950ddSRemy Horton return; 138349950ddSRemy Horton } 139349950ddSRemy Horton ret = rte_metrics_get_values(port_id, metrics, len); 140349950ddSRemy Horton if (ret < 0 || ret > len) { 141349950ddSRemy Horton printf("Cannot get metrics values\n"); 142349950ddSRemy Horton free(metrics); 143349950ddSRemy Horton free(names); 144349950ddSRemy Horton return; 145349950ddSRemy Horton } 146349950ddSRemy Horton printf("Metrics for port %i:\n", port_id); 147349950ddSRemy Horton for (i = 0; i < len; i++) 148349950ddSRemy Horton printf(" %s: %"PRIu64"\n", 149349950ddSRemy Horton names[metrics[i].key].name, metrics[i].value); 150349950ddSRemy Horton free(metrics); 151349950ddSRemy Horton free(names); 152349950ddSRemy Horton } 1532ad7ba9aSRemy Horton 1542ad7ba9aSRemy Horton 15544dc7c0aSHarman KalraDeinitialising the library 15644dc7c0aSHarman Kalra-------------------------- 15744dc7c0aSHarman Kalra 15844dc7c0aSHarman KalraOnce the library usage is done, it must be deinitialized by calling 15944dc7c0aSHarman Kalra``rte_metrics_deinit()`` which will free the shared memory reserved 16044dc7c0aSHarman Kalraduring initialization. 16144dc7c0aSHarman Kalra 16244dc7c0aSHarman Kalra.. code-block:: c 16344dc7c0aSHarman Kalra 16444dc7c0aSHarman Kalra err = rte_metrics_deinit(void); 16544dc7c0aSHarman Kalra 16644dc7c0aSHarman KalraIf the return value is negative, it means deinitialization failed. 16744dc7c0aSHarman KalraThis function **must** be called from a primary process. 16844dc7c0aSHarman Kalra 1692ad7ba9aSRemy HortonBit-rate statistics library 1702ad7ba9aSRemy Horton--------------------------- 1712ad7ba9aSRemy Horton 1722ad7ba9aSRemy HortonThe bit-rate library calculates the exponentially-weighted moving 1732ad7ba9aSRemy Hortonaverage and peak bit-rates for each active port (i.e. network device). 1742ad7ba9aSRemy HortonThese statistics are reported via the metrics library using the 1752ad7ba9aSRemy Hortonfollowing names: 1762ad7ba9aSRemy Horton 1772ad7ba9aSRemy Horton - ``mean_bits_in``: Average inbound bit-rate 1782ad7ba9aSRemy Horton - ``mean_bits_out``: Average outbound bit-rate 1792ad7ba9aSRemy Horton - ``ewma_bits_in``: Average inbound bit-rate (EWMA smoothed) 1802ad7ba9aSRemy Horton - ``ewma_bits_out``: Average outbound bit-rate (EWMA smoothed) 1812ad7ba9aSRemy Horton - ``peak_bits_in``: Peak inbound bit-rate 1822ad7ba9aSRemy Horton - ``peak_bits_out``: Peak outbound bit-rate 1832ad7ba9aSRemy Horton 1842ad7ba9aSRemy HortonOnce initialised and clocked at the appropriate frequency, these 1852ad7ba9aSRemy Hortonstatistics can be obtained by querying the metrics library. 1862ad7ba9aSRemy Horton 1872ad7ba9aSRemy HortonInitialization 1882ad7ba9aSRemy Horton~~~~~~~~~~~~~~ 1892ad7ba9aSRemy Horton 1902ad7ba9aSRemy HortonBefore the library can be used, it has to be initialised by calling 1912ad7ba9aSRemy Horton``rte_stats_bitrate_create()``, which will return a bit-rate 1922ad7ba9aSRemy Hortoncalculation object. Since the bit-rate library uses the metrics library 1932ad7ba9aSRemy Hortonto report the calculated statistics, the bit-rate library then needs to 1942ad7ba9aSRemy Hortonregister the calculated statistics with the metrics library. This is 1952ad7ba9aSRemy Hortondone using the helper function ``rte_stats_bitrate_reg()``. 1962ad7ba9aSRemy Horton 1972ad7ba9aSRemy Horton.. code-block:: c 1982ad7ba9aSRemy Horton 1992ad7ba9aSRemy Horton struct rte_stats_bitrates *bitrate_data; 2002ad7ba9aSRemy Horton 2012ad7ba9aSRemy Horton bitrate_data = rte_stats_bitrate_create(); 2022ad7ba9aSRemy Horton if (bitrate_data == NULL) 2032ad7ba9aSRemy Horton rte_exit(EXIT_FAILURE, "Could not allocate bit-rate data.\n"); 2042ad7ba9aSRemy Horton rte_stats_bitrate_reg(bitrate_data); 2052ad7ba9aSRemy Horton 2062ad7ba9aSRemy HortonControlling the sampling rate 2072ad7ba9aSRemy Horton~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2082ad7ba9aSRemy Horton 2092ad7ba9aSRemy HortonSince the library works by periodic sampling but does not use an 2102ad7ba9aSRemy Hortoninternal thread, the application has to periodically call 2112ad7ba9aSRemy Horton``rte_stats_bitrate_calc()``. The frequency at which this function 2122ad7ba9aSRemy Hortonis called should be the intended sampling rate required for the 2132ad7ba9aSRemy Hortoncalculated statistics. For instance if per-second statistics are 2142ad7ba9aSRemy Hortondesired, this function should be called once a second. 2152ad7ba9aSRemy Horton 2162ad7ba9aSRemy Horton.. code-block:: c 2172ad7ba9aSRemy Horton 2182ad7ba9aSRemy Horton tics_datum = rte_rdtsc(); 2192ad7ba9aSRemy Horton tics_per_1sec = rte_get_timer_hz(); 2202ad7ba9aSRemy Horton 2212ad7ba9aSRemy Horton while( 1 ) { 2222ad7ba9aSRemy Horton /* ... */ 2232ad7ba9aSRemy Horton tics_current = rte_rdtsc(); 2242ad7ba9aSRemy Horton if (tics_current - tics_datum >= tics_per_1sec) { 2252ad7ba9aSRemy Horton /* Periodic bitrate calculation */ 2262ad7ba9aSRemy Horton for (idx_port = 0; idx_port < cnt_ports; idx_port++) 2272ad7ba9aSRemy Horton rte_stats_bitrate_calc(bitrate_data, idx_port); 2282ad7ba9aSRemy Horton tics_datum = tics_current; 2292ad7ba9aSRemy Horton } 2302ad7ba9aSRemy Horton /* ... */ 2312ad7ba9aSRemy Horton } 2325cd3cac9SReshma Pattan 2335cd3cac9SReshma Pattan 2345cd3cac9SReshma PattanLatency statistics library 2355cd3cac9SReshma Pattan-------------------------- 2365cd3cac9SReshma Pattan 2375cd3cac9SReshma PattanThe latency statistics library calculates the latency of packet 2385cd3cac9SReshma Pattanprocessing by a DPDK application, reporting the minimum, average, 2395cd3cac9SReshma Pattanand maximum nano-seconds that packet processing takes, as well as 2405cd3cac9SReshma Pattanthe jitter in processing delay. These statistics are then reported 2415cd3cac9SReshma Pattanvia the metrics library using the following names: 2425cd3cac9SReshma Pattan 2435cd3cac9SReshma Pattan - ``min_latency_ns``: Minimum processing latency (nano-seconds) 2445cd3cac9SReshma Pattan - ``avg_latency_ns``: Average processing latency (nano-seconds) 2455cd3cac9SReshma Pattan - ``mac_latency_ns``: Maximum processing latency (nano-seconds) 2465cd3cac9SReshma Pattan - ``jitter_ns``: Variance in processing latency (nano-seconds) 2475cd3cac9SReshma Pattan 2485cd3cac9SReshma PattanOnce initialised and clocked at the appropriate frequency, these 2495cd3cac9SReshma Pattanstatistics can be obtained by querying the metrics library. 2505cd3cac9SReshma Pattan 2515cd3cac9SReshma PattanInitialization 2525cd3cac9SReshma Pattan~~~~~~~~~~~~~~ 2535cd3cac9SReshma Pattan 2545cd3cac9SReshma PattanBefore the library can be used, it has to be initialised by calling 2555cd3cac9SReshma Pattan``rte_latencystats_init()``. 2565cd3cac9SReshma Pattan 2575cd3cac9SReshma Pattan.. code-block:: c 2585cd3cac9SReshma Pattan 2595cd3cac9SReshma Pattan lcoreid_t latencystats_lcore_id = -1; 2605cd3cac9SReshma Pattan 2615cd3cac9SReshma Pattan int ret = rte_latencystats_init(1, NULL); 2625cd3cac9SReshma Pattan if (ret) 2635cd3cac9SReshma Pattan rte_exit(EXIT_FAILURE, "Could not allocate latency data.\n"); 2645cd3cac9SReshma Pattan 2655cd3cac9SReshma Pattan 2665cd3cac9SReshma PattanTriggering statistic updates 2675cd3cac9SReshma Pattan~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2685cd3cac9SReshma Pattan 2695cd3cac9SReshma PattanThe ``rte_latencystats_update()`` function needs to be called 2705cd3cac9SReshma Pattanperiodically so that latency statistics can be updated. 2715cd3cac9SReshma Pattan 2725cd3cac9SReshma Pattan.. code-block:: c 2735cd3cac9SReshma Pattan 2745cd3cac9SReshma Pattan if (latencystats_lcore_id == rte_lcore_id()) 2755cd3cac9SReshma Pattan rte_latencystats_update(); 2765cd3cac9SReshma Pattan 2775cd3cac9SReshma PattanLibrary shutdown 2785cd3cac9SReshma Pattan~~~~~~~~~~~~~~~~ 2795cd3cac9SReshma Pattan 2805cd3cac9SReshma PattanWhen finished, ``rte_latencystats_uninit()`` needs to be called to 2815cd3cac9SReshma Pattande-initialise the latency library. 2825cd3cac9SReshma Pattan 2835cd3cac9SReshma Pattan.. code-block:: c 2845cd3cac9SReshma Pattan 2855cd3cac9SReshma Pattan rte_latencystats_uninit(); 286999aa063SReshma Pattan 287999aa063SReshma PattanTimestamp and latency calculation 288999aa063SReshma Pattan~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 289999aa063SReshma Pattan 290999aa063SReshma PattanThe Latency stats library marks the time in the timestamp field of the 291*daa02b5cSOlivier Matzmbuf for the ingress packets and sets the ``RTE_MBUF_F_RX_TIMESTAMP`` flag of 292999aa063SReshma Pattan``ol_flags`` for the mbuf to indicate the marked time as a valid one. 293999aa063SReshma PattanAt the egress, the mbufs with the flag set are considered having valid 294999aa063SReshma Pattantimestamp and are used for the latency calculation. 295