From a4f16a0e570e663bdf6285b0ac5c4258fcd9ffd3 Mon Sep 17 00:00:00 2001 From: Sean Hope Date: Mon, 28 Mar 2016 13:11:31 -0400 Subject: [PATCH] Add API to get the dpdk interface stats delta. Internally change the clearing and displaying of the dpdk stats to be based on deltas. Change-Id: I76605ac67492a374ff5522ff44d4a0190cf94e18 Signed-off-by: Todd Foggoa (tfoggoa) --- vnet/vnet/devices/dpdk/device.c | 44 +++++++++++++++++++++++++++++++++----- vnet/vnet/devices/dpdk/dpdk.h | 5 +++++ vnet/vnet/devices/dpdk/dpdk_priv.h | 30 +++++++++++++++++++------- vnet/vnet/devices/dpdk/format.c | 28 ++++++++++++++++-------- 4 files changed, 85 insertions(+), 22 deletions(-) diff --git a/vnet/vnet/devices/dpdk/device.c b/vnet/vnet/devices/dpdk/device.c index 748fb829115..7821ebeb7c2 100644 --- a/vnet/vnet/devices/dpdk/device.c +++ b/vnet/vnet/devices/dpdk/device.c @@ -835,17 +835,27 @@ static void dpdk_clear_hw_interface_counters (u32 instance) */ if (xd->admin_up != 0xff) { - rte_eth_stats_reset (xd->device_index); - memset (&xd->last_stats, 0, sizeof (xd->last_stats)); + /* + * Set the "last_cleared_stats" to the current stats, so that + * things appear to clear from a display perspective. + */ dpdk_update_counters (xd, vlib_time_now (dm->vlib_main)); + + memcpy (&xd->last_cleared_stats, &xd->stats, sizeof(xd->stats)); + memcpy (xd->last_cleared_xstats, xd->xstats, + vec_len(xd->last_cleared_xstats) * + sizeof(xd->last_cleared_xstats[0])); } else { - rte_eth_stats_reset (xd->device_index); - memset(&xd->stats, 0, sizeof(xd->stats)); + /* + * Internally rte_eth_xstats_reset() is calling rte_eth_stats_reset(), + * so we're only calling xstats_reset() here. + */ + rte_eth_xstats_reset (xd->device_index); + memset (&xd->stats, 0, sizeof(xd->stats)); memset (&xd->last_stats, 0, sizeof (xd->last_stats)); } - rte_eth_xstats_reset(xd->device_index); if (PREDICT_FALSE(xd->dev_type == VNET_DPDK_DEV_VHOST_USER)) { int i; @@ -1225,3 +1235,27 @@ int rte_delay_us_override (unsigned us) { } return 0; // no override } + +/* + * Return a copy of the DPDK port stats in dest. + */ +clib_error_t* +dpdk_get_hw_interface_stats (u32 hw_if_index, struct rte_eth_stats* dest) +{ + dpdk_main_t * dm = &dpdk_main; + vnet_main_t * vnm = vnet_get_main(); + vnet_hw_interface_t * hi = vnet_get_hw_interface (vnm, hw_if_index); + dpdk_device_t * xd = vec_elt_at_index (dm->devices, hi->dev_instance); + + if (!dest) { + return clib_error_return (0, "Missing or NULL argument"); + } + if (!xd) { + return clib_error_return (0, "Unable to get DPDK device from HW interface"); + } + + dpdk_update_counters (xd, vlib_time_now (dm->vlib_main)); + + memcpy(dest, &xd->stats, sizeof(xd->stats)); + return (0); +} diff --git a/vnet/vnet/devices/dpdk/dpdk.h b/vnet/vnet/devices/dpdk/dpdk.h index e2bb1e2a107..bfe22795e0f 100644 --- a/vnet/vnet/devices/dpdk/dpdk.h +++ b/vnet/vnet/devices/dpdk/dpdk.h @@ -245,7 +245,9 @@ typedef struct { struct rte_eth_stats stats; struct rte_eth_stats last_stats; + struct rte_eth_stats last_cleared_stats; struct rte_eth_xstats * xstats; + struct rte_eth_xstats * last_cleared_xstats; f64 time_last_stats_update; dpdk_port_type_t port_type; @@ -567,6 +569,9 @@ u32 dpdk_get_admin_up_down_in_progress (void); uword dpdk_input_rss (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * f); +clib_error_t* +dpdk_get_hw_interface_stats (u32 hw_if_index, struct rte_eth_stats* dest); + format_function_t format_dpdk_device_name; format_function_t format_dpdk_device; format_function_t format_dpdk_tx_dma_trace; diff --git a/vnet/vnet/devices/dpdk/dpdk_priv.h b/vnet/vnet/devices/dpdk/dpdk_priv.h index a0fa38a4712..54d3803058d 100644 --- a/vnet/vnet/devices/dpdk/dpdk_priv.h +++ b/vnet/vnet/devices/dpdk/dpdk_priv.h @@ -141,6 +141,27 @@ dpdk_rx_burst ( dpdk_main_t * dm, dpdk_device_t * xd, u16 queue_id) } +static inline void +dpdk_get_xstats (dpdk_device_t * xd) +{ + int len; + if ((len = rte_eth_xstats_get(xd->device_index, NULL, 0)) > 0) + { + vec_validate(xd->xstats, len - 1); + vec_validate(xd->last_cleared_xstats, len - 1); + + len = rte_eth_xstats_get(xd->device_index, xd->xstats, vec_len(xd->xstats)); + + ASSERT(vec_len(xd->xstats) == len); + ASSERT(vec_len(xd->last_cleared_xstats) == len); + + _vec_len(xd->xstats) = len; + _vec_len(xd->last_cleared_xstats) = len; + + } +} + + static inline void dpdk_update_counters (dpdk_device_t * xd, f64 now) { @@ -148,7 +169,6 @@ dpdk_update_counters (dpdk_device_t * xd, f64 now) vnet_main_t * vnm = vnet_get_main(); u32 my_cpu = os_get_cpu_number(); u64 rxerrors, last_rxerrors; - int len; /* only update counters for PMD interfaces */ if (xd->dev_type != VNET_DPDK_DEV_ETH) @@ -207,11 +227,5 @@ dpdk_update_counters (dpdk_device_t * xd, f64 now) } } - if ((len = rte_eth_xstats_get(xd->device_index, NULL, 0)) > 0) - { - vec_validate(xd->xstats, len - 1); - len = rte_eth_xstats_get(xd->device_index, xd->xstats, vec_len(xd->xstats)); - ASSERT(vec_len(xd->xstats) == len); - _vec_len(xd->xstats) = len; - } + dpdk_get_xstats(xd); } diff --git a/vnet/vnet/devices/dpdk/format.c b/vnet/vnet/devices/dpdk/format.c index 447dfffb1b6..9c015d06272 100644 --- a/vnet/vnet/devices/dpdk/format.c +++ b/vnet/vnet/devices/dpdk/format.c @@ -529,27 +529,37 @@ u8 * format_dpdk_device (u8 * s, va_list * args) { #define _(N, V) \ - if (xd->stats.V != 0) \ - s = format (s, "\n%U%-40U%16Ld", \ - format_white_space, indent + 2, \ - format_c_identifier, #N, xd->stats.V); + if ((xd->stats.V - xd->last_cleared_stats.V) != 0) { \ + s = format (s, "\n%U%-40U%16Ld", \ + format_white_space, indent + 2, \ + format_c_identifier, #N, \ + xd->stats.V - xd->last_cleared_stats.V); \ + } \ foreach_dpdk_counter #undef _ } u8 * xs = 0; - struct rte_eth_xstats * xstat; + u32 i = 0; - vec_foreach(xstat, xd->xstats) + ASSERT(vec_len(xd->xstats) == vec_len(xd->last_cleared_xstats)); + + vec_foreach_index(i, xd->xstats) { - if (verbose == 2 || (verbose && xstat->value)) + u64 delta = 0; + struct rte_eth_xstats* xstat = vec_elt_at_index(xd->xstats, i); + struct rte_eth_xstats* last_xstat = + vec_elt_at_index(xd->last_cleared_xstats, i); + + delta = xstat->value - last_xstat->value; + if (verbose == 2 || (verbose && delta)) { - /* format_c_identifier don't like c strings inside vector */ + /* format_c_identifier doesn't like c strings inside vector */ u8 * name = format(0,"%s", xstat->name); xs = format(xs, "\n%U%-38U%16Ld", format_white_space, indent + 4, - format_c_identifier, name, xstat->value); + format_c_identifier, name, delta); vec_free(name); } } -- 2.16.6