From: Remy Horton Date: Wed, 15 Jun 2016 15:25:27 +0000 (+0100) Subject: ethdev: fetch extended statistics with integer ids X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=bd6aa172cf35046e197b3a42a79069d4da15813a;p=dpdk.git ethdev: fetch extended statistics with integer ids The current extended ethernet statistics fetching involve doing several string operations, which causes performance issues if there are lots of statistics and/or network interfaces. This patch changes the xstats functions to instead use a numeric identifier rather than a string, and adds the ability to retrieve identifier-to-string mappings. Signed-off-by: Remy Horton --- diff --git a/doc/guides/prog_guide/poll_mode_drv.rst b/doc/guides/prog_guide/poll_mode_drv.rst index 76986924d0..802fb8f888 100644 --- a/doc/guides/prog_guide/poll_mode_drv.rst +++ b/doc/guides/prog_guide/poll_mode_drv.rst @@ -299,10 +299,27 @@ Extended Statistics API ~~~~~~~~~~~~~~~~~~~~~~~ The extended statistics API allows each individual PMD to expose a unique set -of statistics. The client of the API provides an array of -``struct rte_eth_xstats`` type. Each ``struct rte_eth_xstats`` contains a -string and value pair. The amount of xstats exposed, and position of the -statistic in the array must remain constant during runtime. +of statistics. Accessing these from application programs is done via two +functions: + +* ``rte_eth_xstats_get``: Fills in an array of ``struct rte_eth_xstat`` + with extended statistics. +* ``rte_eth_xstats_get_names``: Fills in an array of + ``struct rte_eth_xstat_name`` with extended statistic name lookup + information. + +Each ``struct rte_eth_xstat`` contains an identifier and value pair, and +each ``struct rte_eth_xstat_name`` contains an identifier and string pair. +Each identifier within ``struct rte_eth_xstat`` must have a corresponding +entry in ``struct rte_eth_xstat_name`` with a matching identifier. These +identifiers, as well as the number of extended statistic exposed, must +remain constant during runtime. + +Note that extended statistic identifiers are driver-specific, and hence +might not be the same for different ports. Although it is expected that +drivers will make the identifiers used within ``struct rte_eth_xstat`` and +``struct rte_eth_xstat_name`` entries match the entries' array index, this +property should not be relied on by applications for lookups. A naming scheme exists for the strings exposed to clients of the API. This is to allow scraping of the API for statistics of interest. The naming scheme uses diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index e148028f9c..98e5efb893 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -1502,6 +1502,85 @@ rte_eth_stats_reset(uint8_t port_id) dev->data->rx_mbuf_alloc_failed = 0; } +static int +get_xstats_count(uint8_t port_id) +{ + struct rte_eth_dev *dev; + int count; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL); + dev = &rte_eth_devices[port_id]; + if (dev->dev_ops->xstats_get_names != NULL) { + count = (*dev->dev_ops->xstats_get_names)(dev, NULL, 0); + if (count < 0) + return count; + } else + count = 0; + count += RTE_NB_STATS; + count += dev->data->nb_rx_queues * RTE_NB_RXQ_STATS; + count += dev->data->nb_tx_queues * RTE_NB_TXQ_STATS; + return count; +} + +int +rte_eth_xstats_get_names(uint8_t port_id, + struct rte_eth_xstat_name *xstats_names, + unsigned size) +{ + struct rte_eth_dev *dev; + int cnt_used_entries; + int cnt_expected_entries; + uint32_t idx, id_queue; + + cnt_expected_entries = get_xstats_count(port_id); + if (xstats_names == NULL || cnt_expected_entries < 0 || + (int)size < cnt_expected_entries) + return cnt_expected_entries; + + /* port_id checked in get_xstats_count() */ + dev = &rte_eth_devices[port_id]; + if (dev->dev_ops->xstats_get_names != NULL) { + cnt_used_entries = (*dev->dev_ops->xstats_get_names)( + dev, xstats_names, size); + if (cnt_used_entries < 0) + return cnt_used_entries; + } else + /* Driver itself does not support extended stats, but + * still have basic stats. + */ + cnt_used_entries = 0; + + for (idx = 0; idx < RTE_NB_STATS; idx++) { + xstats_names[cnt_used_entries].id = cnt_used_entries; + snprintf(xstats_names[cnt_used_entries].name, + sizeof(xstats_names[0].name), + "%s", rte_stats_strings[idx].name); + cnt_used_entries++; + } + for (id_queue = 0; id_queue < dev->data->nb_rx_queues; id_queue++) { + for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) { + xstats_names[cnt_used_entries].id = cnt_used_entries; + snprintf(xstats_names[cnt_used_entries].name, + sizeof(xstats_names[0].name), + "rx_q%u%s", + id_queue, rte_rxq_stats_strings[idx].name); + cnt_used_entries++; + } + + } + for (id_queue = 0; id_queue < dev->data->nb_tx_queues; id_queue++) { + for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) { + xstats_names[cnt_used_entries].id = cnt_used_entries; + snprintf(xstats_names[cnt_used_entries].name, + sizeof(xstats_names[0].name), + "tx_q%u%s", + id_queue, rte_txq_stats_strings[idx].name); + cnt_used_entries++; + } + } + return cnt_used_entries; +} + /* retrieve ethdev extended statistics */ int rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats, @@ -1546,8 +1625,8 @@ rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats, stats_ptr = RTE_PTR_ADD(ð_stats, rte_stats_strings[i].offset); val = *stats_ptr; - snprintf(xstats[count].name, sizeof(xstats[count].name), - "%s", rte_stats_strings[i].name); + xstats[count].name[0] = '\0'; + xstats[count].id = count + xcount; xstats[count++].value = val; } @@ -1558,9 +1637,8 @@ rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats, rte_rxq_stats_strings[i].offset + q * sizeof(uint64_t)); val = *stats_ptr; - snprintf(xstats[count].name, sizeof(xstats[count].name), - "rx_q%u_%s", q, - rte_rxq_stats_strings[i].name); + xstats[count].name[0] = '\0'; + xstats[count].id = count + xcount; xstats[count++].value = val; } } @@ -1572,9 +1650,8 @@ rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats, rte_txq_stats_strings[i].offset + q * sizeof(uint64_t)); val = *stats_ptr; - snprintf(xstats[count].name, sizeof(xstats[count].name), - "tx_q%u_%s", q, - rte_txq_stats_strings[i].name); + xstats[count].name[0] = '\0'; + xstats[count].id = count + xcount; xstats[count++].value = val; } } diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h index e5e91e448e..c344c2cda9 100644 --- a/lib/librte_ether/rte_ethdev.h +++ b/lib/librte_ether/rte_ethdev.h @@ -916,9 +916,21 @@ struct rte_eth_txq_info { */ struct rte_eth_xstats { char name[RTE_ETH_XSTATS_NAME_SIZE]; + uint64_t id; uint64_t value; }; +/** + * A name-key lookup element for extended statistics. + * + * This structure is used to map between names and ID numbers + * for extended ethernet statistics. + */ +struct rte_eth_xstat_name { + char name[RTE_ETH_XSTATS_NAME_SIZE]; + uint64_t id; +}; + #define ETH_DCB_NUM_TCS 8 #define ETH_MAX_VMDQ_POOL 64 @@ -1054,6 +1066,10 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev, typedef void (*eth_xstats_reset_t)(struct rte_eth_dev *dev); /**< @internal Reset extended stats of an Ethernet device. */ +typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev, + struct rte_eth_xstat_name *xstats_names, unsigned size); +/**< @internal Get names of extended stats of an Ethernet device. */ + typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev, uint16_t queue_id, uint8_t stat_idx, @@ -1401,6 +1417,8 @@ struct eth_dev_ops { eth_stats_reset_t stats_reset; /**< Reset generic device statistics. */ eth_xstats_get_t xstats_get; /**< Get extended device statistics. */ eth_xstats_reset_t xstats_reset; /**< Reset extended device statistics. */ + eth_xstats_get_names_t xstats_get_names; + /**< Get names of extended statistics. */ eth_queue_stats_mapping_set_t queue_stats_mapping_set; /**< Configure per queue stat counter mapping. */ eth_dev_infos_get_t dev_infos_get; /**< Get device info. */ @@ -2252,6 +2270,29 @@ int rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats); */ void rte_eth_stats_reset(uint8_t port_id); +/** + * Retrieve names of extended statistics of an Ethernet device. + * + * @param port_id + * The port identifier of the Ethernet device. + * @param xstats_names + * Block of memory to insert names into. Must be at least size in capacity. + * If set to NULL, function returns required capacity. + * @param size + * Capacity of xstats_names (number of names). + * @return + * - positive value lower or equal to size: success. The return value + * is the number of entries filled in the stats table. + * - positive value higher than size: error, the given statistics table + * is too small. The return value corresponds to the size that should + * be given to succeed. The entries in the table are not valid and + * shall not be used by the caller. + * - negative value on error (invalid port id) + */ +int rte_eth_xstats_get_names(uint8_t port_id, + struct rte_eth_xstat_name *xstats_names, + unsigned size); + /** * Retrieve extended statistics of an Ethernet device. * diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map index 214ecc7335..722b4d6a6a 100644 --- a/lib/librte_ether/rte_ether_version.map +++ b/lib/librte_ether/rte_ether_version.map @@ -132,3 +132,9 @@ DPDK_16.04 { rte_eth_tx_buffer_set_err_callback; } DPDK_2.2; + +DPDK_16.07 { + global: + + rte_eth_xstats_get_names; +} DPDK_16.04;