diff options
author | Christian Ehrhardt <christian.ehrhardt@canonical.com> | 2017-05-16 14:51:32 +0200 |
---|---|---|
committer | Christian Ehrhardt <christian.ehrhardt@canonical.com> | 2017-05-16 16:20:45 +0200 |
commit | 7595afa4d30097c1177b69257118d8ad89a539be (patch) | |
tree | 4bfeadc905c977e45e54a90c42330553b8942e4e /doc/guides/prog_guide/metrics_lib.rst | |
parent | ce3d555e43e3795b5d9507fcfc76b7a0a92fd0d6 (diff) |
Imported Upstream version 17.05
Change-Id: Id1e419c5a214e4a18739663b91f0f9a549f1fdc6
Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Diffstat (limited to 'doc/guides/prog_guide/metrics_lib.rst')
-rw-r--r-- | doc/guides/prog_guide/metrics_lib.rst | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/doc/guides/prog_guide/metrics_lib.rst b/doc/guides/prog_guide/metrics_lib.rst new file mode 100644 index 00000000..702c29d9 --- /dev/null +++ b/doc/guides/prog_guide/metrics_lib.rst @@ -0,0 +1,299 @@ +.. BSD LICENSE + Copyright(c) 2017 Intel Corporation. All rights reserved. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +.. _Metrics_Library: + +Metrics Library +=============== + +The Metrics library implements a mechanism by which *producers* can +publish numeric information for later querying by *consumers*. In +practice producers will typically be other libraries or primary +processes, whereas consumers will typically be applications. + +Metrics themselves are statistics that are not generated by PMDs. Metric +information is populated using a push model, where producers update the +values contained within the metric library by calling an update function +on the relevant metrics. Consumers receive metric information by querying +the central metric data, which is held in shared memory. + +For each metric, a separate value is maintained for each port id, and +when publishing metric values the producers need to specify which port is +being updated. In addition there is a special id ``RTE_METRICS_GLOBAL`` +that is intended for global statistics that are not associated with any +individual device. Since the metrics library is self-contained, the only +restriction on port numbers is that they are less than ``RTE_MAX_ETHPORTS`` +- there is no requirement for the ports to actually exist. + +Initialising the library +------------------------ + +Before the library can be used, it has to be initialized by calling +``rte_metrics_init()`` which sets up the metric store in shared memory. +This is where producers will publish metric information to, and where +consumers will query it from. + +.. code-block:: c + + rte_metrics_init(rte_socket_id()); + +This function **must** be called from a primary process, but otherwise +producers and consumers can be in either primary or secondary processes. + +Registering metrics +------------------- + +Metrics must first be *registered*, which is the way producers declare +the names of the metrics they will be publishing. Registration can either +be done individually, or a set of metrics can be registered as a group. +Individual registration is done using ``rte_metrics_reg_name()``: + +.. code-block:: c + + id_1 = rte_metrics_reg_name("mean_bits_in"); + id_2 = rte_metrics_reg_name("mean_bits_out"); + id_3 = rte_metrics_reg_name("peak_bits_in"); + id_4 = rte_metrics_reg_name("peak_bits_out"); + +or alternatively, a set of metrics can be registered together using +``rte_metrics_reg_names()``: + +.. code-block:: c + + const char * const names[] = { + "mean_bits_in", "mean_bits_out", + "peak_bits_in", "peak_bits_out", + }; + id_set = rte_metrics_reg_names(&names[0], 4); + +If the return value is negative, it means registration failed. Otherwise +the return value is the *key* for the metric, which is used when updating +values. A table mapping together these key values and the metrics' names +can be obtained using ``rte_metrics_get_names()``. + +Updating metric values +---------------------- + +Once registered, producers can update the metric for a given port using +the ``rte_metrics_update_value()`` function. This uses the metric key +that is returned when registering the metric, and can also be looked up +using ``rte_metrics_get_names()``. + +.. code-block:: c + + rte_metrics_update_value(port_id, id_1, values[0]); + rte_metrics_update_value(port_id, id_2, values[1]); + rte_metrics_update_value(port_id, id_3, values[2]); + rte_metrics_update_value(port_id, id_4, values[3]); + +if metrics were registered as a single set, they can either be updated +individually using ``rte_metrics_update_value()``, or updated together +using the ``rte_metrics_update_values()`` function: + +.. code-block:: c + + rte_metrics_update_value(port_id, id_set, values[0]); + rte_metrics_update_value(port_id, id_set + 1, values[1]); + rte_metrics_update_value(port_id, id_set + 2, values[2]); + rte_metrics_update_value(port_id, id_set + 3, values[3]); + + rte_metrics_update_values(port_id, id_set, values, 4); + +Note that ``rte_metrics_update_values()`` cannot be used to update +metric values from *multiple* *sets*, as there is no guarantee two +sets registered one after the other have contiguous id values. + +Querying metrics +---------------- + +Consumers can obtain metric values by querying the metrics library using +the ``rte_metrics_get_values()`` function that return an array of +``struct rte_metric_value``. Each entry within this array contains a metric +value and its associated key. A key-name mapping can be obtained using the +``rte_metrics_get_names()`` function that returns an array of +``struct rte_metric_name`` that is indexed by the key. The following will +print out all metrics for a given port: + +.. code-block:: c + + void print_metrics() { + struct rte_metric_name *names; + int len; + + len = rte_metrics_get_names(NULL, 0); + if (len < 0) { + printf("Cannot get metrics count\n"); + return; + } + if (len == 0) { + printf("No metrics to display (none have been registered)\n"); + return; + } + metrics = malloc(sizeof(struct rte_metric_value) * len); + names = malloc(sizeof(struct rte_metric_name) * len); + if (metrics == NULL || names == NULL) { + printf("Cannot allocate memory\n"); + free(metrics); + free(names); + return; + } + ret = rte_metrics_get_values(port_id, metrics, len); + if (ret < 0 || ret > len) { + printf("Cannot get metrics values\n"); + free(metrics); + free(names); + return; + } + printf("Metrics for port %i:\n", port_id); + for (i = 0; i < len; i++) + printf(" %s: %"PRIu64"\n", + names[metrics[i].key].name, metrics[i].value); + free(metrics); + free(names); + } + + +Bit-rate statistics library +--------------------------- + +The bit-rate library calculates the exponentially-weighted moving +average and peak bit-rates for each active port (i.e. network device). +These statistics are reported via the metrics library using the +following names: + + - ``mean_bits_in``: Average inbound bit-rate + - ``mean_bits_out``: Average outbound bit-rate + - ``ewma_bits_in``: Average inbound bit-rate (EWMA smoothed) + - ``ewma_bits_out``: Average outbound bit-rate (EWMA smoothed) + - ``peak_bits_in``: Peak inbound bit-rate + - ``peak_bits_out``: Peak outbound bit-rate + +Once initialised and clocked at the appropriate frequency, these +statistics can be obtained by querying the metrics library. + +Initialization +~~~~~~~~~~~~~~ + +Before the library can be used, it has to be initialised by calling +``rte_stats_bitrate_create()``, which will return a bit-rate +calculation object. Since the bit-rate library uses the metrics library +to report the calculated statistics, the bit-rate library then needs to +register the calculated statistics with the metrics library. This is +done using the helper function ``rte_stats_bitrate_reg()``. + +.. code-block:: c + + struct rte_stats_bitrates *bitrate_data; + + bitrate_data = rte_stats_bitrate_create(); + if (bitrate_data == NULL) + rte_exit(EXIT_FAILURE, "Could not allocate bit-rate data.\n"); + rte_stats_bitrate_reg(bitrate_data); + +Controlling the sampling rate +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since the library works by periodic sampling but does not use an +internal thread, the application has to periodically call +``rte_stats_bitrate_calc()``. The frequency at which this function +is called should be the intended sampling rate required for the +calculated statistics. For instance if per-second statistics are +desired, this function should be called once a second. + +.. code-block:: c + + tics_datum = rte_rdtsc(); + tics_per_1sec = rte_get_timer_hz(); + + while( 1 ) { + /* ... */ + tics_current = rte_rdtsc(); + if (tics_current - tics_datum >= tics_per_1sec) { + /* Periodic bitrate calculation */ + for (idx_port = 0; idx_port < cnt_ports; idx_port++) + rte_stats_bitrate_calc(bitrate_data, idx_port); + tics_datum = tics_current; + } + /* ... */ + } + + +Latency statistics library +-------------------------- + +The latency statistics library calculates the latency of packet +processing by a DPDK application, reporting the minimum, average, +and maximum nano-seconds that packet processing takes, as well as +the jitter in processing delay. These statistics are then reported +via the metrics library using the following names: + + - ``min_latency_ns``: Minimum processing latency (nano-seconds) + - ``avg_latency_ns``: Average processing latency (nano-seconds) + - ``mac_latency_ns``: Maximum processing latency (nano-seconds) + - ``jitter_ns``: Variance in processing latency (nano-seconds) + +Once initialised and clocked at the appropriate frequency, these +statistics can be obtained by querying the metrics library. + +Initialization +~~~~~~~~~~~~~~ + +Before the library can be used, it has to be initialised by calling +``rte_latencystats_init()``. + +.. code-block:: c + + lcoreid_t latencystats_lcore_id = -1; + + int ret = rte_latencystats_init(1, NULL); + if (ret) + rte_exit(EXIT_FAILURE, "Could not allocate latency data.\n"); + + +Triggering statistic updates +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``rte_latencystats_update()`` function needs to be called +periodically so that latency statistics can be updated. + +.. code-block:: c + + if (latencystats_lcore_id == rte_lcore_id()) + rte_latencystats_update(); + +Library shutdown +~~~~~~~~~~~~~~~~ + +When finished, ``rte_latencystats_uninit()`` needs to be called to +de-initialise the latency library. + +.. code-block:: c + + rte_latencystats_uninit(); |