DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/4] extend API to retriving xstats by group and xstats by name
@ 2017-03-03 12:54 Kuba Kozak
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 1/4] ethdev: add retrieving " Kuba Kozak
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Kuba Kozak @ 2017-03-03 12:54 UTC (permalink / raw)
  To: dev; +Cc: Kuba Kozak

Added three new functions to API: rte_eth_xstats_get_by_name(),
rte_eth_xstats_get_by_group(), rte_eth_xstats_get_names_by_group().

Extension of the 'rte_igb_xstats_name_off' structure
with additional field 'group_mask'. For each xstats there is now
specified group (e.g. TX_GROUP), one xstatistic can be in several groups.
To implement new functionality of retriving xstats by group
on e1000 driver level, there are two functions added:
eth_igb_xstats_get_by_group() and eth_igb_xstats_get_names_by_group(),
on ixgbe driver level, there are new functions added:
ixgbe_dev_xstats_get_by_group() and ixgbe_dev_xstats_get_names_by_group()

Extended functionality of proc_info application:
--xstats-name NAME: to display single xstat value by NAME
--xstats-group GROUPNAME: to display group of xstats by GROUPNAME

Jacek Piasecki (4):
  ethdev: add retrieving xstats by group and xstats by name
  net/e1000: add grouping of xstats for e1000 driver
  net/ixgbe: add grouping of xstats for ixgbe driver
  app/proc_info: add support for xstats-name and xstats-group

 app/proc_info/main.c             | 112 ++++++++-
 drivers/net/e1000/igb_ethdev.c   | 261 +++++++++++++++-----
 drivers/net/ixgbe/ixgbe_ethdev.c | 496 +++++++++++++++++++++++++++++++--------
 lib/librte_ether/rte_ethdev.c    | 310 +++++++++++++++++++++++-
 lib/librte_ether/rte_ethdev.h    | 105 ++++++++-
 5 files changed, 1114 insertions(+), 170 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 1/4] ethdev: add retrieving xstats by group and xstats by name
  2017-03-03 12:54 [dpdk-dev] [PATCH 0/4] extend API to retriving xstats by group and xstats by name Kuba Kozak
@ 2017-03-03 12:54 ` Kuba Kozak
  2017-03-06 10:17   ` Thomas Monjalon
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 2/4] net/e1000: add grouping of xstats for e1000 driver Kuba Kozak
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Kuba Kozak @ 2017-03-03 12:54 UTC (permalink / raw)
  To: dev; +Cc: Jacek Piasecki, Kuba Kozak

From: Jacek Piasecki <jacekx.piasecki@intel.com>

This patch extends library for retriving xstats by specified groups and
single xstat by given name.

Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>
Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>
---
 lib/librte_ether/rte_ethdev.c | 310 ++++++++++++++++++++++++++++++++++++++++--
 lib/librte_ether/rte_ethdev.h | 105 +++++++++++++-
 2 files changed, 401 insertions(+), 14 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index eb0a94a..aad8913 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -87,33 +87,37 @@
 struct rte_eth_xstats_name_off {
 	char name[RTE_ETH_XSTATS_NAME_SIZE];
 	unsigned offset;
+	uint64_t group_mask;
 };
 
 static const struct rte_eth_xstats_name_off rte_stats_strings[] = {
-	{"rx_good_packets", offsetof(struct rte_eth_stats, ipackets)},
-	{"tx_good_packets", offsetof(struct rte_eth_stats, opackets)},
-	{"rx_good_bytes", offsetof(struct rte_eth_stats, ibytes)},
-	{"tx_good_bytes", offsetof(struct rte_eth_stats, obytes)},
-	{"rx_errors", offsetof(struct rte_eth_stats, ierrors)},
-	{"tx_errors", offsetof(struct rte_eth_stats, oerrors)},
+	{"rx_good_packets", offsetof(struct rte_eth_stats, ipackets), RX_GROUP},
+	{"tx_good_packets", offsetof(struct rte_eth_stats, opackets), TX_GROUP},
+	{"rx_good_bytes", offsetof(struct rte_eth_stats, ibytes), RX_GROUP},
+	{"tx_good_bytes", offsetof(struct rte_eth_stats, obytes), TX_GROUP},
+	{"rx_errors", offsetof(struct rte_eth_stats, ierrors),
+			RX_GROUP | ERR_GROUP},
+	{"tx_errors", offsetof(struct rte_eth_stats, oerrors),
+			TX_GROUP | ERR_GROUP},
 	{"rx_mbuf_allocation_errors", offsetof(struct rte_eth_stats,
-		rx_nombuf)},
+		rx_nombuf), RX_GROUP | ERR_GROUP},
 };
 
 #define RTE_NB_STATS (sizeof(rte_stats_strings) / sizeof(rte_stats_strings[0]))
 
 static const struct rte_eth_xstats_name_off rte_rxq_stats_strings[] = {
-	{"packets", offsetof(struct rte_eth_stats, q_ipackets)},
-	{"bytes", offsetof(struct rte_eth_stats, q_ibytes)},
-	{"errors", offsetof(struct rte_eth_stats, q_errors)},
+	{"packets", offsetof(struct rte_eth_stats, q_ipackets), RXQ_GROUP},
+	{"bytes", offsetof(struct rte_eth_stats, q_ibytes), RXQ_GROUP},
+	{"errors", offsetof(struct rte_eth_stats, q_errors),
+			RXQ_GROUP | ERR_GROUP},
 };
 
 #define RTE_NB_RXQ_STATS (sizeof(rte_rxq_stats_strings) /	\
 		sizeof(rte_rxq_stats_strings[0]))
 
 static const struct rte_eth_xstats_name_off rte_txq_stats_strings[] = {
-	{"packets", offsetof(struct rte_eth_stats, q_opackets)},
-	{"bytes", offsetof(struct rte_eth_stats, q_obytes)},
+	{"packets", offsetof(struct rte_eth_stats, q_opackets), TXQ_GROUP},
+	{"bytes", offsetof(struct rte_eth_stats, q_obytes), TXQ_GROUP},
 };
 #define RTE_NB_TXQ_STATS (sizeof(rte_txq_stats_strings) /	\
 		sizeof(rte_txq_stats_strings[0]))
@@ -1448,6 +1452,110 @@ struct rte_eth_dev *
 	return count;
 }
 
+static int
+get_xstats_count_by_group(uint8_t port_id, uint64_t group_mask)
+{
+	struct rte_eth_dev *dev;
+	int count = 0;
+	int dcount = 0;
+	unsigned int i;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+	if (dev->dev_ops->xstats_get_names_by_group != NULL) {
+		dcount = (*dev->dev_ops->xstats_get_names_by_group)
+				(dev, NULL, 0, group_mask);
+		if (dcount < 0)
+			return dcount;
+	}
+
+
+
+
+	for (i = 0; i < RTE_NB_STATS; i++) {
+		if (rte_stats_strings[i].group_mask & group_mask)
+			count++;
+	}
+	for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
+		if (rte_rxq_stats_strings[i].group_mask & group_mask)
+			count += RTE_MIN(dev->data->nb_rx_queues,
+					RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	}
+	for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
+		if (rte_txq_stats_strings[i].group_mask & group_mask)
+			count += RTE_MIN(dev->data->nb_tx_queues,
+					RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	}
+	return count+dcount;
+}
+
+int
+rte_eth_xstats_get_by_name(uint8_t port_id, struct rte_eth_xstat *xstat,
+		const char *name)
+{
+	struct rte_eth_xstat *xstats;
+	int cnt_xstats, idx_xstat;
+	struct rte_eth_xstat_name *xstats_names;
+
+
+
+	/* Get count */
+	cnt_xstats = rte_eth_xstats_get_names(port_id, NULL, 0);
+	if (cnt_xstats  < 0) {
+		printf("Error: Cannot get count of xstats\n");
+		return -1;
+	}
+
+	/* Get id-name lookup table */
+	xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * cnt_xstats);
+	if (xstats_names == NULL) {
+		printf("Cannot allocate memory for xstats lookup\n");
+		return -1;
+	}
+	if (cnt_xstats != rte_eth_xstats_get_names(
+			port_id, xstats_names, cnt_xstats)) {
+		printf("Error: Cannot get xstats lookup\n");
+		free(xstats_names);
+		return -1;
+	}
+
+	/* Get stats themselves */
+	xstats = malloc(sizeof(struct rte_eth_xstat) * cnt_xstats);
+	if (xstats == NULL) {
+		printf("Cannot allocate memory for xstats\n");
+		free(xstats_names);
+		return -1;
+	}
+
+	if (cnt_xstats != rte_eth_xstats_get(port_id, xstats, cnt_xstats)) {
+		printf("Error: Unable to get xstats\n");
+		free(xstats_names);
+		free(xstats);
+		return -1;
+	}
+
+	if (!xstat) {
+		printf("Error: xstat pointer is NULL\n");
+		free(xstats_names);
+		free(xstats);
+		return -1;
+	}
+
+	/* Display xstats */
+	for (idx_xstat = 0; idx_xstat < cnt_xstats; idx_xstat++) {
+		if (!strcmp(xstats_names[idx_xstat].name, name)) {
+
+			xstat->id = xstats[idx_xstat].id;
+			xstat->value = xstats[idx_xstat].value;
+			return 0;
+		};
+	}
+
+	free(xstats_names);
+	free(xstats);
+	return -1;
+}
+
 int
 rte_eth_xstats_get_names(uint8_t port_id,
 	struct rte_eth_xstat_name *xstats_names,
@@ -1513,6 +1621,83 @@ struct rte_eth_dev *
 	return cnt_used_entries;
 }
 
+int
+rte_eth_xstats_get_names_by_group(uint8_t port_id,
+	struct rte_eth_xstat_name *xstats_names,
+	unsigned int size, __rte_unused uint64_t group_mask)
+{
+	struct rte_eth_dev *dev;
+	int cnt_used_entries;
+	int cnt_expected_entries;
+	int cnt_driver_entries;
+	uint32_t idx, id_queue;
+	uint16_t num_q;
+
+	cnt_expected_entries = get_xstats_count_by_group(port_id, group_mask);
+	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];
+	cnt_used_entries = 0;
+
+	for (idx = 0; idx < RTE_NB_STATS; idx++) {
+		if (rte_stats_strings[idx].group_mask & group_mask) {
+			snprintf(xstats_names[cnt_used_entries].name,
+				sizeof(xstats_names[0].name),
+				"%s", rte_stats_strings[idx].name);
+			cnt_used_entries++;
+		}
+	}
+	num_q = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	for (id_queue = 0; id_queue < num_q; id_queue++) {
+		for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) {
+			if (rte_rxq_stats_strings[idx].group_mask &
+					group_mask) {
+				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++;
+			}
+		}
+	}
+	num_q = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	for (id_queue = 0; id_queue < num_q; id_queue++) {
+		for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) {
+			if (rte_txq_stats_strings[idx].group_mask &
+					group_mask) {
+				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++;
+			}
+
+		}
+	}
+
+	if (dev->dev_ops->xstats_get_names != NULL) {
+		/* If there are any driver-specific xstats, append them
+		 * to end of list.
+		 */
+		cnt_driver_entries =
+				(*dev->dev_ops->xstats_get_names_by_group)(
+			dev,
+			xstats_names + cnt_used_entries,
+			size - cnt_used_entries,
+			group_mask);
+		if (cnt_driver_entries < 0)
+			return cnt_driver_entries;
+		cnt_used_entries += cnt_driver_entries;
+	}
+
+	return cnt_used_entries;
+}
+
 /* retrieve ethdev extended statistics */
 int
 rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstat *xstats,
@@ -1595,6 +1780,104 @@ struct rte_eth_dev *
 	return count + xcount;
 }
 
+/* retrieve ethdev extended statistics */
+int
+rte_eth_xstats_get_by_group(uint8_t port_id, struct rte_eth_xstat *xstats,
+	unsigned int n, uint64_t group_mask)
+{
+	struct rte_eth_stats eth_stats;
+	struct rte_eth_dev *dev;
+	unsigned int count = 0, i, q;
+	signed int xcount = 0;
+	uint64_t val, *stats_ptr;
+	uint16_t nb_rxqs, nb_txqs;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+
+	dev = &rte_eth_devices[port_id];
+
+	nb_rxqs = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	nb_txqs = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+
+	for (i = 0; i < RTE_NB_STATS; i++) {
+		if (rte_stats_strings[i].group_mask & group_mask)
+			count++;
+	}
+	for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
+		if (rte_rxq_stats_strings[i].group_mask & group_mask)
+			count += nb_rxqs;
+	}
+	for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
+		if (rte_txq_stats_strings[i].group_mask & group_mask)
+			count += nb_txqs;
+	}
+
+	/* implemented by the driver */
+	if (dev->dev_ops->xstats_get_by_group != NULL) {
+		/* Retrieve the xstats from the driver at the end of the
+		 * xstats struct.
+		 */
+		xcount = (*dev->dev_ops->xstats_get_by_group)(dev,
+				xstats ? xstats + count : NULL,
+				(n > count) ? n - count : 0,
+				group_mask);
+
+		if (xcount < 0)
+			return xcount;
+	}
+
+	if (n < count + xcount || xstats == NULL)
+		return count + xcount;
+
+	/* now fill the xstats structure */
+	count = 0;
+	rte_eth_stats_get(port_id, &eth_stats);
+
+	/* global stats */
+	for (i = 0; i < RTE_NB_STATS; i++) {
+		if (rte_stats_strings[i].group_mask & group_mask) {
+			stats_ptr = RTE_PTR_ADD(&eth_stats,
+						rte_stats_strings[i].offset);
+			val = *stats_ptr;
+			xstats[count++].value = val;
+		}
+	}
+
+	/* per-rxq stats */
+	for (q = 0; q < nb_rxqs; q++) {
+		for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
+			if (rte_rxq_stats_strings[i].group_mask & group_mask) {
+				stats_ptr = RTE_PTR_ADD(&eth_stats,
+						rte_rxq_stats_strings[i].offset
+						+ q * sizeof(uint64_t));
+				val = *stats_ptr;
+				xstats[count++].value = val;
+			}
+		}
+	}
+
+	/* per-txq stats */
+	for (q = 0; q < nb_txqs; q++) {
+		for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
+			if (rte_txq_stats_strings[i].group_mask & group_mask) {
+				stats_ptr = RTE_PTR_ADD(&eth_stats,
+						rte_txq_stats_strings[i].offset
+						+ q * sizeof(uint64_t));
+				val = *stats_ptr;
+				xstats[count++].value = val;
+			}
+		}
+	}
+
+	for (i = 0; i < count; i++)
+		xstats[i].id = i;
+	/* add an offset to driver-specific stats */
+	for ( ; i < count + xcount; i++)
+		xstats[i].id += count;
+
+	return count + xcount;
+}
+
 /* reset ethdev extended statistics */
 void
 rte_eth_xstats_reset(uint8_t port_id)
@@ -1624,7 +1907,8 @@ struct rte_eth_dev *
 
 	dev = &rte_eth_devices[port_id];
 
-	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_stats_mapping_set, -ENOTSUP);
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_stats_mapping_set,
+			-ENOTSUP);
 	return (*dev->dev_ops->queue_stats_mapping_set)
 			(dev, queue_id, stat_idx, is_rx);
 }
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index c17bbda..6c063aa 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -990,6 +990,17 @@ struct rte_eth_xstat_name {
 #define ETH_MAX_VMDQ_POOL  64
 
 /**
+ * Xstats groups by bit no. in 'group_mask'
+ */
+#define TX_GROUP	0x0001
+#define RX_GROUP	0x0002
+#define ERR_GROUP	0x0004
+#define TXQ_GROUP	0x0008
+#define RXQ_GROUP	0x0010
+#define VF_GROUP	0x0020
+#define MAC_GROUP	0x0040
+
+/**
  * A structure used to get the information of queue and
  * TC mapping on both TX and RX paths.
  */
@@ -1118,6 +1129,10 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+typedef int (*eth_xstats_get_by_group_t)(struct rte_eth_dev *dev,
+	struct rte_eth_xstat *stats, unsigned int n, uint64_t group_mask);
+/**< @internal Get extended stats of an Ethernet device. */
+
 typedef void (*eth_xstats_reset_t)(struct rte_eth_dev *dev);
 /**< @internal Reset extended stats of an Ethernet device. */
 
@@ -1125,6 +1140,17 @@ 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_xstats_get_names_by_group_t)(struct rte_eth_dev *dev,
+	struct rte_eth_xstat_name *xstats_names,
+	unsigned int size, uint64_t group_mask);
+/**< @internal Get names of extended stats of an Ethernet device. */
+
+typedef int (*eth_xstats_get_by_name_t)(struct rte_eth_dev *dev,
+		struct rte_eth_xstat_name *xstats_names,
+		struct rte_eth_xstat *xstat,
+		const char *name);
+/**< @internal Get xstat specified by name 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,
@@ -1456,8 +1482,13 @@ struct eth_dev_ops {
 	eth_stats_get_t            stats_get;     /**< Get generic device statistics. */
 	eth_stats_reset_t          stats_reset;   /**< Reset generic device statistics. */
 	eth_xstats_get_t           xstats_get;    /**< Get extended device statistics. */
+	eth_xstats_get_by_group_t  xstats_get_by_group;
+	/**< Get extended device statistics. */
 	eth_xstats_reset_t         xstats_reset;  /**< Reset extended device statistics. */
-	eth_xstats_get_names_t     xstats_get_names;
+	eth_xstats_get_names_t	   xstats_get_names;
+	eth_xstats_get_names_by_group_t xstats_get_names_by_group;
+	eth_xstats_get_by_name_t	xstats_get_by_name;
+
 	/**< Get names of extended statistics. */
 	eth_queue_stats_mapping_set_t queue_stats_mapping_set;
 	/**< Configure per queue stat counter mapping. */
@@ -2307,6 +2338,51 @@ int rte_eth_xstats_get_names(uint8_t port_id,
 		unsigned size);
 
 /**
+ * Get extended statistics of an Ethernet device matching specified name.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param name
+ *   Phrase used to search extended statistics
+ * @param name *xstat
+ *   Pointer to allocated memory for rte_eth_xstat structure
+ * @return
+ *   - 0 when xstat was successfully found and value and id were returned
+ *   using pointer to rte_eth_xstat,
+ *   - A negative value when xstat wasn't found.
+ */
+int
+rte_eth_xstats_get_by_name(uint8_t port_id, struct rte_eth_xstat *xstat,
+		const char *name);
+
+
+/**
+ * Retrieve names of extended grouped statistics of an Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. If set to NULL, the function returns the required number
+ *   of elements.
+ * @param size
+ *   The size of the xstats_names array (number of elements).
+ * @param group_id
+ *   Group identificator
+ * @return
+ *   - A positive value lower or equal to size: success. The return value
+ *     is the number of entries filled in the stats table.
+ *   - A 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.
+ */
+int
+rte_eth_xstats_get_names_by_group(uint8_t port_id,
+	struct rte_eth_xstat_name *xstats_names,
+	unsigned int size, uint64_t group_mask);
+
+/**
  * Retrieve extended statistics of an Ethernet device.
  *
  * @param port_id
@@ -2332,6 +2408,33 @@ int rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstat *xstats,
 		unsigned n);
 
 /**
+ * Retrieve extended grouped statistics of an Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param xstats
+ *   A pointer to a table of structure of type *rte_eth_xstat*
+ *   to be filled with device statistics ids and values: id is the
+ *   index of the name string in xstats_names (see rte_eth_xstats_get_names()),
+ *   and value is the statistic counter.
+ *   This parameter can be set to NULL if n is 0.
+ * @param n
+ *   The size of the xstats array (number of elements).
+ * @param group_id
+ *   Group identificator
+ * @return
+ *   - A positive value lower or equal to n: success. The return value
+ *     is the number of entries filled in the stats table.
+ *   - A positive value higher than n: 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.
+ *   - A negative value on error (invalid port id).
+ */
+int rte_eth_xstats_get_by_group(uint8_t port_id, struct rte_eth_xstat *xstats,
+		unsigned int n, uint64_t group_mask);
+
+/**
  * Reset extended statistics of an Ethernet device.
  *
  * @param port_id
-- 
1.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 2/4] net/e1000: add grouping of xstats for e1000 driver
  2017-03-03 12:54 [dpdk-dev] [PATCH 0/4] extend API to retriving xstats by group and xstats by name Kuba Kozak
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 1/4] ethdev: add retrieving " Kuba Kozak
@ 2017-03-03 12:54 ` Kuba Kozak
  2017-03-06  2:05   ` Lu, Wenzhuo
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 3/4] net/ixgbe: add grouping of xstats for ixgbe driver Kuba Kozak
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 4/4] app/proc_info: add support for xstats-name and xstats-group Kuba Kozak
  3 siblings, 1 reply; 8+ messages in thread
From: Kuba Kozak @ 2017-03-03 12:54 UTC (permalink / raw)
  To: dev; +Cc: Jacek Piasecki, Kuba Kozak

From: Jacek Piasecki <jacekx.piasecki@intel.com>

This patch extends the 'rte_igb_xstats_name_off' structure
with additional field 'group_mask'. For each xstats there is now
specified group (e.g. TX_GROUP), one xstatistic can be in several groups.
To implement new functionality of retriving xstats by group
on driver level, there are two functions added:
eth_igb_xstats_get_by_group() and eth_igb_xstats_get_names_by_group()

Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>
Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 261 +++++++++++++++++++++++++++++++----------
 1 file changed, 199 insertions(+), 62 deletions(-)

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index a112b38..28eced6 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -115,9 +115,18 @@ static void eth_igb_stats_get(struct rte_eth_dev *dev,
 				struct rte_eth_stats *rte_stats);
 static int eth_igb_xstats_get(struct rte_eth_dev *dev,
 			      struct rte_eth_xstat *xstats, unsigned n);
+static
+int eth_igb_xstats_get_by_group(struct rte_eth_dev *dev,
+		struct rte_eth_xstat *xstats,
+		unsigned int n, uint64_t group_mask);
 static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
 				    struct rte_eth_xstat_name *xstats_names,
 				    unsigned limit);
+static int
+eth_igb_xstats_get_names_by_group(__rte_unused struct rte_eth_dev *dev,
+	struct rte_eth_xstat_name *xstats_names,
+	__rte_unused unsigned int limit,
+	uint64_t group_mask);
 static void eth_igb_stats_reset(struct rte_eth_dev *dev);
 static void eth_igb_xstats_reset(struct rte_eth_dev *dev);
 static int eth_igb_fw_version_get(struct rte_eth_dev *dev,
@@ -390,7 +399,9 @@ static void eth_igbvf_interrupt_handler(struct rte_intr_handle *handle,
 	.link_update          = eth_igb_link_update,
 	.stats_get            = eth_igb_stats_get,
 	.xstats_get           = eth_igb_xstats_get,
+	.xstats_get_by_group  = eth_igb_xstats_get_by_group,
 	.xstats_get_names     = eth_igb_xstats_get_names,
+	.xstats_get_names_by_group = eth_igb_xstats_get_names_by_group,
 	.stats_reset          = eth_igb_stats_reset,
 	.xstats_reset         = eth_igb_xstats_reset,
 	.fw_version_get       = eth_igb_fw_version_get,
@@ -473,78 +484,128 @@ static void eth_igbvf_interrupt_handler(struct rte_intr_handle *handle,
 struct rte_igb_xstats_name_off {
 	char name[RTE_ETH_XSTATS_NAME_SIZE];
 	unsigned offset;
+	uint64_t group_mask;
 };
 
 static const struct rte_igb_xstats_name_off rte_igb_stats_strings[] = {
-	{"rx_crc_errors", offsetof(struct e1000_hw_stats, crcerrs)},
-	{"rx_align_errors", offsetof(struct e1000_hw_stats, algnerrc)},
-	{"rx_symbol_errors", offsetof(struct e1000_hw_stats, symerrs)},
-	{"rx_missed_packets", offsetof(struct e1000_hw_stats, mpc)},
-	{"tx_single_collision_packets", offsetof(struct e1000_hw_stats, scc)},
-	{"tx_multiple_collision_packets", offsetof(struct e1000_hw_stats, mcc)},
+	{"rx_crc_errors", offsetof(struct e1000_hw_stats, crcerrs),
+			RX_GROUP | ERR_GROUP},
+	{"rx_align_errors", offsetof(struct e1000_hw_stats, algnerrc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_symbol_errors", offsetof(struct e1000_hw_stats, symerrs),
+			RX_GROUP | ERR_GROUP},
+	{"rx_missed_packets", offsetof(struct e1000_hw_stats, mpc),
+			RX_GROUP},
+	{"tx_single_collision_packets", offsetof(struct e1000_hw_stats, scc),
+			TX_GROUP},
+	{"tx_multiple_collision_packets", offsetof(struct e1000_hw_stats, mcc),
+			TX_GROUP},
 	{"tx_excessive_collision_packets", offsetof(struct e1000_hw_stats,
-		ecol)},
-	{"tx_late_collisions", offsetof(struct e1000_hw_stats, latecol)},
-	{"tx_total_collisions", offsetof(struct e1000_hw_stats, colc)},
-	{"tx_deferred_packets", offsetof(struct e1000_hw_stats, dc)},
-	{"tx_no_carrier_sense_packets", offsetof(struct e1000_hw_stats, tncrs)},
-	{"rx_carrier_ext_errors", offsetof(struct e1000_hw_stats, cexterr)},
-	{"rx_length_errors", offsetof(struct e1000_hw_stats, rlec)},
-	{"rx_xon_packets", offsetof(struct e1000_hw_stats, xonrxc)},
-	{"tx_xon_packets", offsetof(struct e1000_hw_stats, xontxc)},
-	{"rx_xoff_packets", offsetof(struct e1000_hw_stats, xoffrxc)},
-	{"tx_xoff_packets", offsetof(struct e1000_hw_stats, xofftxc)},
+		ecol), TX_GROUP},
+	{"tx_late_collisions", offsetof(struct e1000_hw_stats, latecol),
+			TX_GROUP},
+	{"tx_total_collisions", offsetof(struct e1000_hw_stats, colc),
+			TX_GROUP},
+	{"tx_deferred_packets", offsetof(struct e1000_hw_stats, dc),
+			TX_GROUP},
+	{"tx_no_carrier_sense_packets", offsetof(struct e1000_hw_stats, tncrs),
+			TX_GROUP},
+	{"rx_carrier_ext_errors", offsetof(struct e1000_hw_stats, cexterr),
+			RX_GROUP | ERR_GROUP},
+	{"rx_length_errors", offsetof(struct e1000_hw_stats, rlec),
+			RX_GROUP | ERR_GROUP},
+	{"rx_xon_packets", offsetof(struct e1000_hw_stats, xonrxc),
+			RX_GROUP},
+	{"tx_xon_packets", offsetof(struct e1000_hw_stats, xontxc),
+			TX_GROUP},
+	{"rx_xoff_packets", offsetof(struct e1000_hw_stats, xoffrxc),
+			RX_GROUP},
+	{"tx_xoff_packets", offsetof(struct e1000_hw_stats, xofftxc),
+			TX_GROUP},
 	{"rx_flow_control_unsupported_packets", offsetof(struct e1000_hw_stats,
-		fcruc)},
-	{"rx_size_64_packets", offsetof(struct e1000_hw_stats, prc64)},
-	{"rx_size_65_to_127_packets", offsetof(struct e1000_hw_stats, prc127)},
-	{"rx_size_128_to_255_packets", offsetof(struct e1000_hw_stats, prc255)},
-	{"rx_size_256_to_511_packets", offsetof(struct e1000_hw_stats, prc511)},
+		fcruc), RX_GROUP},
+	{"rx_size_64_packets", offsetof(struct e1000_hw_stats, prc64),
+			RX_GROUP},
+	{"rx_size_65_to_127_packets", offsetof(struct e1000_hw_stats, prc127),
+			RX_GROUP},
+	{"rx_size_128_to_255_packets", offsetof(struct e1000_hw_stats, prc255),
+			RX_GROUP},
+	{"rx_size_256_to_511_packets", offsetof(struct e1000_hw_stats, prc511),
+			RX_GROUP},
 	{"rx_size_512_to_1023_packets", offsetof(struct e1000_hw_stats,
-		prc1023)},
+		prc1023), RX_GROUP},
 	{"rx_size_1024_to_max_packets", offsetof(struct e1000_hw_stats,
-		prc1522)},
-	{"rx_broadcast_packets", offsetof(struct e1000_hw_stats, bprc)},
-	{"rx_multicast_packets", offsetof(struct e1000_hw_stats, mprc)},
-	{"rx_undersize_errors", offsetof(struct e1000_hw_stats, ruc)},
-	{"rx_fragment_errors", offsetof(struct e1000_hw_stats, rfc)},
-	{"rx_oversize_errors", offsetof(struct e1000_hw_stats, roc)},
-	{"rx_jabber_errors", offsetof(struct e1000_hw_stats, rjc)},
-	{"rx_management_packets", offsetof(struct e1000_hw_stats, mgprc)},
-	{"rx_management_dropped", offsetof(struct e1000_hw_stats, mgpdc)},
-	{"tx_management_packets", offsetof(struct e1000_hw_stats, mgptc)},
-	{"rx_total_packets", offsetof(struct e1000_hw_stats, tpr)},
-	{"tx_total_packets", offsetof(struct e1000_hw_stats, tpt)},
-	{"rx_total_bytes", offsetof(struct e1000_hw_stats, tor)},
-	{"tx_total_bytes", offsetof(struct e1000_hw_stats, tot)},
-	{"tx_size_64_packets", offsetof(struct e1000_hw_stats, ptc64)},
-	{"tx_size_65_to_127_packets", offsetof(struct e1000_hw_stats, ptc127)},
-	{"tx_size_128_to_255_packets", offsetof(struct e1000_hw_stats, ptc255)},
-	{"tx_size_256_to_511_packets", offsetof(struct e1000_hw_stats, ptc511)},
+		prc1522), RX_GROUP},
+	{"rx_broadcast_packets", offsetof(struct e1000_hw_stats, bprc),
+			RX_GROUP},
+	{"rx_multicast_packets", offsetof(struct e1000_hw_stats, mprc),
+			RX_GROUP},
+	{"rx_undersize_errors", offsetof(struct e1000_hw_stats, ruc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_fragment_errors", offsetof(struct e1000_hw_stats, rfc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_oversize_errors", offsetof(struct e1000_hw_stats, roc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_jabber_errors", offsetof(struct e1000_hw_stats, rjc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_management_packets", offsetof(struct e1000_hw_stats, mgprc),
+			RX_GROUP},
+	{"rx_management_dropped", offsetof(struct e1000_hw_stats, mgpdc),
+			RX_GROUP},
+	{"tx_management_packets", offsetof(struct e1000_hw_stats, mgptc),
+			TX_GROUP},
+	{"rx_total_packets", offsetof(struct e1000_hw_stats, tpr),
+			RX_GROUP},
+	{"tx_total_packets", offsetof(struct e1000_hw_stats, tpt),
+			TX_GROUP},
+	{"rx_total_bytes", offsetof(struct e1000_hw_stats, tor),
+			RX_GROUP},
+	{"tx_total_bytes", offsetof(struct e1000_hw_stats, tot),
+			TX_GROUP},
+	{"tx_size_64_packets", offsetof(struct e1000_hw_stats, ptc64),
+			TX_GROUP},
+	{"tx_size_65_to_127_packets", offsetof(struct e1000_hw_stats, ptc127),
+			TX_GROUP},
+	{"tx_size_128_to_255_packets", offsetof(struct e1000_hw_stats, ptc255),
+			TX_GROUP},
+	{"tx_size_256_to_511_packets", offsetof(struct e1000_hw_stats, ptc511),
+			TX_GROUP},
 	{"tx_size_512_to_1023_packets", offsetof(struct e1000_hw_stats,
-		ptc1023)},
+		ptc1023), TX_GROUP},
 	{"tx_size_1023_to_max_packets", offsetof(struct e1000_hw_stats,
-		ptc1522)},
-	{"tx_multicast_packets", offsetof(struct e1000_hw_stats, mptc)},
-	{"tx_broadcast_packets", offsetof(struct e1000_hw_stats, bptc)},
-	{"tx_tso_packets", offsetof(struct e1000_hw_stats, tsctc)},
-	{"tx_tso_errors", offsetof(struct e1000_hw_stats, tsctfc)},
-	{"rx_sent_to_host_packets", offsetof(struct e1000_hw_stats, rpthc)},
-	{"tx_sent_by_host_packets", offsetof(struct e1000_hw_stats, hgptc)},
-	{"rx_code_violation_packets", offsetof(struct e1000_hw_stats, scvpc)},
-
-	{"interrupt_assert_count", offsetof(struct e1000_hw_stats, iac)},
+		ptc1522), TX_GROUP},
+	{"tx_multicast_packets", offsetof(struct e1000_hw_stats, mptc),
+			TX_GROUP},
+	{"tx_broadcast_packets", offsetof(struct e1000_hw_stats, bptc),
+			TX_GROUP},
+	{"tx_tso_packets", offsetof(struct e1000_hw_stats, tsctc),
+			TX_GROUP},
+	{"tx_tso_errors", offsetof(struct e1000_hw_stats, tsctfc),
+			TX_GROUP | ERR_GROUP},
+	{"rx_sent_to_host_packets", offsetof(struct e1000_hw_stats, rpthc),
+			RX_GROUP},
+	{"tx_sent_by_host_packets", offsetof(struct e1000_hw_stats, hgptc),
+			TX_GROUP},
+	{"rx_code_violation_packets", offsetof(struct e1000_hw_stats, scvpc),
+			TX_GROUP},
+	{"interrupt_assert_count", offsetof(struct e1000_hw_stats, iac),
+			RX_GROUP},
 };
 
 #define IGB_NB_XSTATS (sizeof(rte_igb_stats_strings) / \
 		sizeof(rte_igb_stats_strings[0]))
 
 static const struct rte_igb_xstats_name_off rte_igbvf_stats_strings[] = {
-	{"rx_multicast_packets", offsetof(struct e1000_vf_stats, mprc)},
-	{"rx_good_loopback_packets", offsetof(struct e1000_vf_stats, gprlbc)},
-	{"tx_good_loopback_packets", offsetof(struct e1000_vf_stats, gptlbc)},
-	{"rx_good_loopback_bytes", offsetof(struct e1000_vf_stats, gorlbc)},
-	{"tx_good_loopback_bytes", offsetof(struct e1000_vf_stats, gotlbc)},
+	{"rx_multicast_packets", offsetof(struct e1000_vf_stats, mprc),
+			RX_GROUP | VF_GROUP},
+	{"rx_good_loopback_packets", offsetof(struct e1000_vf_stats, gprlbc),
+			RX_GROUP | VF_GROUP},
+	{"tx_good_loopback_packets", offsetof(struct e1000_vf_stats, gptlbc),
+			TX_GROUP | VF_GROUP},
+	{"rx_good_loopback_bytes", offsetof(struct e1000_vf_stats, gorlbc),
+			RX_GROUP | VF_GROUP},
+	{"tx_good_loopback_bytes", offsetof(struct e1000_vf_stats, gotlbc),
+			TX_GROUP | VF_GROUP},
 };
 
 #define IGBVF_NB_XSTATS (sizeof(rte_igbvf_stats_strings) / \
@@ -1846,10 +1907,43 @@ static int eth_igb_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 }
 
 static int
-eth_igb_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
-		   unsigned n)
+eth_igb_xstats_get_names_by_group(__rte_unused struct rte_eth_dev *dev,
+	struct rte_eth_xstat_name *xstats_names,
+	__rte_unused unsigned int limit,
+	uint64_t group_mask)
 {
-	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	unsigned int i;
+	unsigned int count = 0;
+
+	if (xstats_names == NULL) {
+		for (i = 0; i < IGB_NB_XSTATS; i++) {
+			if (rte_igb_stats_strings[i].group_mask & group_mask)
+				count++;
+		}
+		return count;
+	}
+
+	/* Note: limit checked in rte_eth_xstats_names() */
+
+	count = 0;
+	for (i = 0; i < IGB_NB_XSTATS; i++) {
+		if (rte_igb_stats_strings[i].group_mask & group_mask) {
+			snprintf(xstats_names[count].name,
+					sizeof(xstats_names[0].name),
+				 "%s", rte_igb_stats_strings[i].name);
+			count++;
+		}
+	}
+	return count;
+}
+
+static
+int eth_igb_xstats_get(struct rte_eth_dev *dev,
+		struct rte_eth_xstat *xstats,
+		unsigned int n)
+{
+	struct e1000_hw *hw =
+			E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct e1000_hw_stats *hw_stats =
 			E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
 	unsigned i;
@@ -1875,8 +1969,50 @@ static int eth_igb_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	return IGB_NB_XSTATS;
 }
 
+static
+int eth_igb_xstats_get_by_group(struct rte_eth_dev *dev,
+		struct rte_eth_xstat *xstats,
+		unsigned int n, uint64_t group_mask)
+{
+	struct e1000_hw *hw =
+			E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_hw_stats *hw_stats =
+			E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
+	unsigned int i;
+	unsigned int count = 0;
+
+
+	for (i = 0; i < IGB_NB_XSTATS; i++) {
+		if (rte_igb_stats_strings[i].group_mask & group_mask)
+			count++;
+	}
+
+	if (n < IGB_NB_XSTATS)
+		return count;
+
+	igb_read_stats_registers(hw, hw_stats);
+
+	/* If this is a reset xstats is NULL, and we have cleared the
+	 * registers by reading them.
+	 */
+	if (!xstats)
+		return 0;
+
+	/* Extended stats */
+	for (i = 0; i < IGB_NB_XSTATS; i++) {
+		if (rte_igb_stats_strings[i].group_mask & group_mask) {
+			xstats[i].id = i;
+			xstats[i].value = *(uint64_t *)(((char *)hw_stats) +
+				rte_igb_stats_strings[i].offset);
+		}
+	}
+
+	return count;
+}
+
 static void
-igbvf_read_stats_registers(struct e1000_hw *hw, struct e1000_vf_stats *hw_stats)
+igbvf_read_stats_registers(struct e1000_hw *hw,
+		struct e1000_vf_stats *hw_stats)
 {
 	/* Good Rx packets, include VF loopback */
 	UPDATE_VF_STAT(E1000_VFGPRC,
@@ -2314,7 +2450,8 @@ static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 
 	/* Let firmware know the driver has taken over */
 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
-	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext |
+			E1000_CTRL_EXT_DRV_LOAD);
 }
 
 /*
-- 
1.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 3/4] net/ixgbe: add grouping of xstats for ixgbe driver
  2017-03-03 12:54 [dpdk-dev] [PATCH 0/4] extend API to retriving xstats by group and xstats by name Kuba Kozak
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 1/4] ethdev: add retrieving " Kuba Kozak
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 2/4] net/e1000: add grouping of xstats for e1000 driver Kuba Kozak
@ 2017-03-03 12:54 ` Kuba Kozak
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 4/4] app/proc_info: add support for xstats-name and xstats-group Kuba Kozak
  3 siblings, 0 replies; 8+ messages in thread
From: Kuba Kozak @ 2017-03-03 12:54 UTC (permalink / raw)
  To: dev; +Cc: Jacek Piasecki, Kuba Kozak

From: Jacek Piasecki <jacekx.piasecki@intel.com>

This patch extends the 'rte_ixgbe_xstats_name_off' structure
with additional field 'group_mask'. For each xstats there is
now specified group (e.g. MAC_GROUP), one xstatistic can be in
several groups. To implement new functionality of retriving
xstats by group on driver level, there are two functions added:
ixgbe_dev_xstats_get_by_group() and ixgbe_dev_xstats_get_names_by_group()

Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>
Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 496 +++++++++++++++++++++++++++++++--------
 1 file changed, 403 insertions(+), 93 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 7169007..69731ce 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -124,7 +124,8 @@
 
 #define IXGBEVF_PMD_NAME "rte_ixgbevf_pmd" /* PMD name */
 
-#define IXGBE_QUEUE_STAT_COUNTERS (sizeof(hw_stats->qprc) / sizeof(hw_stats->qprc[0]))
+#define IXGBE_QUEUE_STAT_COUNTERS (sizeof(hw_stats->qprc) \
+		/ sizeof(hw_stats->qprc[0]))
 
 #define IXGBE_HKEY_MAX_INDEX 10
 
@@ -187,12 +188,25 @@ static void ixgbe_dev_stats_get(struct rte_eth_dev *dev,
 				struct rte_eth_stats *stats);
 static int ixgbe_dev_xstats_get(struct rte_eth_dev *dev,
 				struct rte_eth_xstat *xstats, unsigned n);
+static int ixgbe_dev_xstats_get_by_group(struct rte_eth_dev *dev,
+		struct rte_eth_xstat *xstats,
+		unsigned int n, uint64_t group_mask);
 static int ixgbevf_dev_xstats_get(struct rte_eth_dev *dev,
 				  struct rte_eth_xstat *xstats, unsigned n);
 static void ixgbe_dev_stats_reset(struct rte_eth_dev *dev);
 static void ixgbe_dev_xstats_reset(struct rte_eth_dev *dev);
+static int ixgbe_xstats_get_by_name(struct rte_eth_dev *dev,
+		struct rte_eth_xstat_name *xstats_names,
+		struct rte_eth_xstat *xstat,
+		const char *name);
 static int ixgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, __rte_unused unsigned limit);
+static
+int ixgbe_dev_xstats_get_names_by_group(__rte_unused
+		struct rte_eth_dev *dev,
+		struct rte_eth_xstat_name *xstats_names,
+		unsigned int limit,
+		uint64_t group_mask);
 static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, __rte_unused unsigned limit);
 static int ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
@@ -532,10 +546,13 @@ static int ixgbe_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
 	.link_update          = ixgbe_dev_link_update,
 	.stats_get            = ixgbe_dev_stats_get,
 	.xstats_get           = ixgbe_dev_xstats_get,
+	.xstats_get_by_name   = ixgbe_xstats_get_by_name,
+	.xstats_get_by_group  = ixgbe_dev_xstats_get_by_group,
 	.stats_reset          = ixgbe_dev_stats_reset,
 	.xstats_reset         = ixgbe_dev_xstats_reset,
 	.xstats_get_names     = ixgbe_dev_xstats_get_names,
 	.queue_stats_mapping_set = ixgbe_dev_queue_stats_mapping_set,
+	.xstats_get_names_by_group = ixgbe_dev_xstats_get_names_by_group,
 	.fw_version_get       = ixgbe_fw_version_get,
 	.dev_infos_get        = ixgbe_dev_info_get,
 	.dev_supported_ptypes_get = ixgbe_dev_supported_ptypes_get,
@@ -653,87 +670,118 @@ static int ixgbe_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
 struct rte_ixgbe_xstats_name_off {
 	char name[RTE_ETH_XSTATS_NAME_SIZE];
 	unsigned offset;
+	uint64_t group_mask;
 };
 
 static const struct rte_ixgbe_xstats_name_off rte_ixgbe_stats_strings[] = {
-	{"rx_crc_errors", offsetof(struct ixgbe_hw_stats, crcerrs)},
-	{"rx_illegal_byte_errors", offsetof(struct ixgbe_hw_stats, illerrc)},
-	{"rx_error_bytes", offsetof(struct ixgbe_hw_stats, errbc)},
-	{"mac_local_errors", offsetof(struct ixgbe_hw_stats, mlfc)},
-	{"mac_remote_errors", offsetof(struct ixgbe_hw_stats, mrfc)},
-	{"rx_length_errors", offsetof(struct ixgbe_hw_stats, rlec)},
-	{"tx_xon_packets", offsetof(struct ixgbe_hw_stats, lxontxc)},
-	{"rx_xon_packets", offsetof(struct ixgbe_hw_stats, lxonrxc)},
-	{"tx_xoff_packets", offsetof(struct ixgbe_hw_stats, lxofftxc)},
-	{"rx_xoff_packets", offsetof(struct ixgbe_hw_stats, lxoffrxc)},
-	{"rx_size_64_packets", offsetof(struct ixgbe_hw_stats, prc64)},
-	{"rx_size_65_to_127_packets", offsetof(struct ixgbe_hw_stats, prc127)},
-	{"rx_size_128_to_255_packets", offsetof(struct ixgbe_hw_stats, prc255)},
-	{"rx_size_256_to_511_packets", offsetof(struct ixgbe_hw_stats, prc511)},
+	{"rx_crc_errors", offsetof(struct ixgbe_hw_stats, crcerrs),
+			RX_GROUP | ERR_GROUP},
+	{"rx_illegal_byte_errors",
+			offsetof(struct ixgbe_hw_stats, illerrc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_error_bytes", offsetof(struct ixgbe_hw_stats, errbc),
+			RX_GROUP | ERR_GROUP},
+	{"mac_local_errors", offsetof(struct ixgbe_hw_stats, mlfc), ERR_GROUP},
+	{"mac_remote_errors", offsetof(struct ixgbe_hw_stats, mrfc), ERR_GROUP},
+	{"rx_length_errors", offsetof(struct ixgbe_hw_stats, rlec),
+			RX_GROUP | ERR_GROUP},
+	{"tx_xon_packets", offsetof(struct ixgbe_hw_stats, lxontxc), TX_GROUP},
+	{"rx_xon_packets", offsetof(struct ixgbe_hw_stats, lxonrxc), RX_GROUP},
+	{"tx_xoff_packets", offsetof(struct ixgbe_hw_stats, lxofftxc),
+			TX_GROUP},
+	{"rx_xoff_packets", offsetof(struct ixgbe_hw_stats, lxoffrxc),
+			RX_GROUP},
+	{"rx_size_64_packets", offsetof(struct ixgbe_hw_stats, prc64),
+			RX_GROUP},
+	{"rx_size_65_to_127_packets",
+			offsetof(struct ixgbe_hw_stats, prc127), RX_GROUP},
+	{"rx_size_128_to_255_packets",
+			offsetof(struct ixgbe_hw_stats, prc255), RX_GROUP},
+	{"rx_size_256_to_511_packets",
+			offsetof(struct ixgbe_hw_stats, prc511), RX_GROUP},
 	{"rx_size_512_to_1023_packets", offsetof(struct ixgbe_hw_stats,
-		prc1023)},
+		prc1023), RX_GROUP},
 	{"rx_size_1024_to_max_packets", offsetof(struct ixgbe_hw_stats,
-		prc1522)},
-	{"rx_broadcast_packets", offsetof(struct ixgbe_hw_stats, bprc)},
-	{"rx_multicast_packets", offsetof(struct ixgbe_hw_stats, mprc)},
-	{"rx_fragment_errors", offsetof(struct ixgbe_hw_stats, rfc)},
-	{"rx_undersize_errors", offsetof(struct ixgbe_hw_stats, ruc)},
-	{"rx_oversize_errors", offsetof(struct ixgbe_hw_stats, roc)},
-	{"rx_jabber_errors", offsetof(struct ixgbe_hw_stats, rjc)},
-	{"rx_management_packets", offsetof(struct ixgbe_hw_stats, mngprc)},
-	{"rx_management_dropped", offsetof(struct ixgbe_hw_stats, mngpdc)},
-	{"tx_management_packets", offsetof(struct ixgbe_hw_stats, mngptc)},
-	{"rx_total_packets", offsetof(struct ixgbe_hw_stats, tpr)},
-	{"rx_total_bytes", offsetof(struct ixgbe_hw_stats, tor)},
-	{"tx_total_packets", offsetof(struct ixgbe_hw_stats, tpt)},
-	{"tx_size_64_packets", offsetof(struct ixgbe_hw_stats, ptc64)},
-	{"tx_size_65_to_127_packets", offsetof(struct ixgbe_hw_stats, ptc127)},
-	{"tx_size_128_to_255_packets", offsetof(struct ixgbe_hw_stats, ptc255)},
-	{"tx_size_256_to_511_packets", offsetof(struct ixgbe_hw_stats, ptc511)},
-	{"tx_size_512_to_1023_packets", offsetof(struct ixgbe_hw_stats,
-		ptc1023)},
+		prc1522), RX_GROUP},
+	{"rx_broadcast_packets", offsetof(struct ixgbe_hw_stats, bprc),
+			RX_GROUP},
+	{"rx_multicast_packets", offsetof(struct ixgbe_hw_stats, mprc),
+			RX_GROUP},
+	{"rx_fragment_errors", offsetof(struct ixgbe_hw_stats, rfc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_undersize_errors", offsetof(struct ixgbe_hw_stats, ruc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_oversize_errors", offsetof(struct ixgbe_hw_stats, roc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_jabber_errors", offsetof(struct ixgbe_hw_stats, rjc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_management_packets", offsetof(struct ixgbe_hw_stats, mngprc),
+			RX_GROUP},
+	{"rx_management_dropped", offsetof(struct ixgbe_hw_stats, mngpdc),
+			RX_GROUP},
+	{"tx_management_packets", offsetof(struct ixgbe_hw_stats, mngptc),
+			TX_GROUP},
+	{"rx_total_packets", offsetof(struct ixgbe_hw_stats, tpr), RX_GROUP},
+	{"rx_total_bytes", offsetof(struct ixgbe_hw_stats, tor), RX_GROUP},
+	{"tx_total_packets", offsetof(struct ixgbe_hw_stats, tpt), TX_GROUP},
+	{"tx_size_64_packets", offsetof(struct ixgbe_hw_stats, ptc64),
+			TX_GROUP},
+	{"tx_size_65_to_127_packets",
+			offsetof(struct ixgbe_hw_stats, ptc127), TX_GROUP},
+	{"tx_size_128_to_255_packets",
+			offsetof(struct ixgbe_hw_stats, ptc255), TX_GROUP},
+	{"tx_size_256_to_511_packets",
+			offsetof(struct ixgbe_hw_stats, ptc511), TX_GROUP},
+	{"tx_size_512_to_1023_packets",
+			offsetof(struct ixgbe_hw_stats,
+		ptc1023), TX_GROUP},
 	{"tx_size_1024_to_max_packets", offsetof(struct ixgbe_hw_stats,
-		ptc1522)},
-	{"tx_multicast_packets", offsetof(struct ixgbe_hw_stats, mptc)},
-	{"tx_broadcast_packets", offsetof(struct ixgbe_hw_stats, bptc)},
-	{"rx_mac_short_packet_dropped", offsetof(struct ixgbe_hw_stats, mspdc)},
-	{"rx_l3_l4_xsum_error", offsetof(struct ixgbe_hw_stats, xec)},
-
+		ptc1522), TX_GROUP},
+	{"tx_multicast_packets", offsetof(struct ixgbe_hw_stats, mptc),
+			TX_GROUP},
+	{"tx_broadcast_packets", offsetof(struct ixgbe_hw_stats, bptc),
+			TX_GROUP},
+	{"rx_mac_short_packet_dropped",
+			offsetof(struct ixgbe_hw_stats, mspdc), RX_GROUP},
+	{"rx_l3_l4_xsum_error", offsetof(struct ixgbe_hw_stats, xec),
+			RX_GROUP | ERR_GROUP},
 	{"flow_director_added_filters", offsetof(struct ixgbe_hw_stats,
-		fdirustat_add)},
+		fdirustat_add), 0},
 	{"flow_director_removed_filters", offsetof(struct ixgbe_hw_stats,
-		fdirustat_remove)},
+		fdirustat_remove), 0},
 	{"flow_director_filter_add_errors", offsetof(struct ixgbe_hw_stats,
-		fdirfstat_fadd)},
+		fdirfstat_fadd), ERR_GROUP},
 	{"flow_director_filter_remove_errors", offsetof(struct ixgbe_hw_stats,
-		fdirfstat_fremove)},
+		fdirfstat_fremove), ERR_GROUP},
 	{"flow_director_matched_filters", offsetof(struct ixgbe_hw_stats,
-		fdirmatch)},
+		fdirmatch), 0},
 	{"flow_director_missed_filters", offsetof(struct ixgbe_hw_stats,
-		fdirmiss)},
+		fdirmiss), 0},
 
-	{"rx_fcoe_crc_errors", offsetof(struct ixgbe_hw_stats, fccrc)},
-	{"rx_fcoe_dropped", offsetof(struct ixgbe_hw_stats, fcoerpdc)},
+	{"rx_fcoe_crc_errors", offsetof(struct ixgbe_hw_stats, fccrc),
+			RX_GROUP | ERR_GROUP},
+	{"rx_fcoe_dropped", offsetof(struct ixgbe_hw_stats, fcoerpdc),
+			RX_GROUP},
 	{"rx_fcoe_mbuf_allocation_errors", offsetof(struct ixgbe_hw_stats,
-		fclast)},
-	{"rx_fcoe_packets", offsetof(struct ixgbe_hw_stats, fcoeprc)},
-	{"tx_fcoe_packets", offsetof(struct ixgbe_hw_stats, fcoeptc)},
-	{"rx_fcoe_bytes", offsetof(struct ixgbe_hw_stats, fcoedwrc)},
-	{"tx_fcoe_bytes", offsetof(struct ixgbe_hw_stats, fcoedwtc)},
+		fclast), RX_GROUP | ERR_GROUP},
+	{"rx_fcoe_packets", offsetof(struct ixgbe_hw_stats, fcoeprc), RX_GROUP},
+	{"tx_fcoe_packets", offsetof(struct ixgbe_hw_stats, fcoeptc), TX_GROUP},
+	{"rx_fcoe_bytes", offsetof(struct ixgbe_hw_stats, fcoedwrc), RX_GROUP},
+	{"tx_fcoe_bytes", offsetof(struct ixgbe_hw_stats, fcoedwtc), TX_GROUP},
 	{"rx_fcoe_no_direct_data_placement", offsetof(struct ixgbe_hw_stats,
-		fcoe_noddp)},
+		fcoe_noddp), RX_GROUP},
 	{"rx_fcoe_no_direct_data_placement_ext_buff",
-		offsetof(struct ixgbe_hw_stats, fcoe_noddp_ext_buff)},
-
+		offsetof(struct ixgbe_hw_stats, fcoe_noddp_ext_buff), RX_GROUP},
 	{"tx_flow_control_xon_packets", offsetof(struct ixgbe_hw_stats,
-		lxontxc)},
+		lxontxc), TX_GROUP},
 	{"rx_flow_control_xon_packets", offsetof(struct ixgbe_hw_stats,
-		lxonrxc)},
+		lxonrxc), RX_GROUP},
 	{"tx_flow_control_xoff_packets", offsetof(struct ixgbe_hw_stats,
-		lxofftxc)},
+		lxofftxc), TX_GROUP},
 	{"rx_flow_control_xoff_packets", offsetof(struct ixgbe_hw_stats,
-		lxoffrxc)},
-	{"rx_total_missed_packets", offsetof(struct ixgbe_hw_stats, mpctotal)},
+		lxoffrxc), RX_GROUP},
+	{"rx_total_missed_packets",
+			offsetof(struct ixgbe_hw_stats, mpctotal), RX_GROUP},
 };
 
 #define IXGBE_NB_HW_STATS (sizeof(rte_ixgbe_stats_strings) / \
@@ -742,43 +790,43 @@ struct rte_ixgbe_xstats_name_off {
 /* MACsec statistics */
 static const struct rte_ixgbe_xstats_name_off rte_ixgbe_macsec_strings[] = {
 	{"out_pkts_untagged", offsetof(struct ixgbe_macsec_stats,
-		out_pkts_untagged)},
+		out_pkts_untagged), MAC_GROUP},
 	{"out_pkts_encrypted", offsetof(struct ixgbe_macsec_stats,
-		out_pkts_encrypted)},
+		out_pkts_encrypted), MAC_GROUP},
 	{"out_pkts_protected", offsetof(struct ixgbe_macsec_stats,
-		out_pkts_protected)},
+		out_pkts_protected), MAC_GROUP},
 	{"out_octets_encrypted", offsetof(struct ixgbe_macsec_stats,
-		out_octets_encrypted)},
+		out_octets_encrypted), MAC_GROUP},
 	{"out_octets_protected", offsetof(struct ixgbe_macsec_stats,
-		out_octets_protected)},
+		out_octets_protected), MAC_GROUP},
 	{"in_pkts_untagged", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_untagged)},
+		in_pkts_untagged), MAC_GROUP},
 	{"in_pkts_badtag", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_badtag)},
+		in_pkts_badtag), MAC_GROUP},
 	{"in_pkts_nosci", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_nosci)},
+		in_pkts_nosci), MAC_GROUP},
 	{"in_pkts_unknownsci", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_unknownsci)},
+		in_pkts_unknownsci), MAC_GROUP},
 	{"in_octets_decrypted", offsetof(struct ixgbe_macsec_stats,
-		in_octets_decrypted)},
+		in_octets_decrypted), MAC_GROUP},
 	{"in_octets_validated", offsetof(struct ixgbe_macsec_stats,
-		in_octets_validated)},
+		in_octets_validated), MAC_GROUP},
 	{"in_pkts_unchecked", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_unchecked)},
+		in_pkts_unchecked), MAC_GROUP},
 	{"in_pkts_delayed", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_delayed)},
+		in_pkts_delayed), MAC_GROUP},
 	{"in_pkts_late", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_late)},
+		in_pkts_late), MAC_GROUP},
 	{"in_pkts_ok", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_ok)},
+		in_pkts_ok), MAC_GROUP},
 	{"in_pkts_invalid", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_invalid)},
+		in_pkts_invalid), MAC_GROUP},
 	{"in_pkts_notvalid", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_notvalid)},
+		in_pkts_notvalid), MAC_GROUP},
 	{"in_pkts_unusedsa", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_unusedsa)},
+		in_pkts_unusedsa), MAC_GROUP},
 	{"in_pkts_notusingsa", offsetof(struct ixgbe_macsec_stats,
-		in_pkts_notusingsa)},
+		in_pkts_notusingsa), MAC_GROUP},
 };
 
 #define IXGBE_NB_MACSEC_STATS (sizeof(rte_ixgbe_macsec_strings) / \
@@ -786,10 +834,11 @@ struct rte_ixgbe_xstats_name_off {
 
 /* Per-queue statistics */
 static const struct rte_ixgbe_xstats_name_off rte_ixgbe_rxq_strings[] = {
-	{"mbuf_allocation_errors", offsetof(struct ixgbe_hw_stats, rnbc)},
-	{"dropped", offsetof(struct ixgbe_hw_stats, mpc)},
-	{"xon_packets", offsetof(struct ixgbe_hw_stats, pxonrxc)},
-	{"xoff_packets", offsetof(struct ixgbe_hw_stats, pxoffrxc)},
+	{"mbuf_allocation_errors", offsetof(struct ixgbe_hw_stats, rnbc),
+			ERR_GROUP | RXQ_GROUP},
+	{"dropped", offsetof(struct ixgbe_hw_stats, mpc), RXQ_GROUP},
+	{"xon_packets", offsetof(struct ixgbe_hw_stats, pxonrxc), RXQ_GROUP},
+	{"xoff_packets", offsetof(struct ixgbe_hw_stats, pxoffrxc), RXQ_GROUP},
 };
 
 #define IXGBE_NB_RXQ_PRIO_STATS (sizeof(rte_ixgbe_rxq_strings) / \
@@ -797,10 +846,10 @@ struct rte_ixgbe_xstats_name_off {
 #define IXGBE_NB_RXQ_PRIO_VALUES 8
 
 static const struct rte_ixgbe_xstats_name_off rte_ixgbe_txq_strings[] = {
-	{"xon_packets", offsetof(struct ixgbe_hw_stats, pxontxc)},
-	{"xoff_packets", offsetof(struct ixgbe_hw_stats, pxofftxc)},
+	{"xon_packets", offsetof(struct ixgbe_hw_stats, pxontxc), TXQ_GROUP},
+	{"xoff_packets", offsetof(struct ixgbe_hw_stats, pxofftxc), TXQ_GROUP},
 	{"xon_to_xoff_packets", offsetof(struct ixgbe_hw_stats,
-		pxon2offc)},
+		pxon2offc), TXQ_GROUP},
 };
 
 #define IXGBE_NB_TXQ_PRIO_STATS (sizeof(rte_ixgbe_txq_strings) / \
@@ -808,7 +857,8 @@ struct rte_ixgbe_xstats_name_off {
 #define IXGBE_NB_TXQ_PRIO_VALUES 8
 
 static const struct rte_ixgbe_xstats_name_off rte_ixgbevf_stats_strings[] = {
-	{"rx_multicast_packets", offsetof(struct ixgbevf_hw_stats, vfmprc)},
+	{"rx_multicast_packets",
+			offsetof(struct ixgbevf_hw_stats, vfmprc), RX_GROUP},
 };
 
 #define IXGBEVF_NB_XSTATS (sizeof(rte_ixgbevf_stats_strings) /	\
@@ -2414,8 +2464,9 @@ static int ixgbe_l2_tn_filter_init(struct rte_eth_dev *eth_dev)
 	*    - fixed speed: TODO implement
 	*/
 	if (dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED) {
-		PMD_INIT_LOG(ERR, "Invalid link_speeds for port %hhu; fix speed not supported",
-			     dev->data->port_id);
+		PMD_INIT_LOG(ERR,
+				"Invalid link_speeds for port %hhu; fix speed not supported",
+				dev->data->port_id);
 		return -EINVAL;
 	}
 
@@ -3038,6 +3089,104 @@ static int ixgbe_l2_tn_filter_init(struct rte_eth_dev *eth_dev)
 		(IXGBE_NB_TXQ_PRIO_STATS * IXGBE_NB_TXQ_PRIO_VALUES);
 }
 
+static unsigned
+ixgbe_xstats_calc_num_by_group(uint64_t group_mask) {
+	unsigned int i;
+	unsigned int count = 0;
+
+	for (i = 0; i < IXGBE_NB_HW_STATS; i++) {
+		if (rte_ixgbe_stats_strings[i].group_mask & group_mask)
+			count++;
+	}
+	for (i = 0; i < IXGBE_NB_MACSEC_STATS; i++) {
+		if (rte_ixgbe_macsec_strings[i].group_mask & group_mask)
+			count++;
+	}
+	for (i = 0; i < IXGBE_NB_RXQ_PRIO_STATS; i++) {
+		if (rte_ixgbe_rxq_strings[i].group_mask & group_mask)
+			count += IXGBE_NB_TXQ_PRIO_VALUES;
+	}
+	for (i = 0; i < IXGBE_NB_TXQ_PRIO_STATS; i++) {
+		if (rte_ixgbe_txq_strings[i].group_mask & group_mask)
+			count += IXGBE_NB_TXQ_PRIO_VALUES;
+	}
+
+	return count;
+}
+
+static int ixgbe_xstats_get_by_name(struct rte_eth_dev *dev,
+		struct rte_eth_xstat_name *xstats_names,
+		struct rte_eth_xstat *xstat,
+		const char *name)
+{
+	struct ixgbe_hw_stats *hw_stats =
+			IXGBE_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
+
+	unsigned int i;
+
+
+	const unsigned int cnt_stats = ixgbe_xstats_calc_num();
+	if (xstats_names == NULL)
+		return cnt_stats;
+
+	unsigned int current = 0;
+
+	for (i = 0; i < IXGBE_NB_HW_STATS; i++) {
+		if (!strncmp(rte_ixgbe_stats_strings[i].name, name,
+				sizeof(rte_ixgbe_stats_strings[i].name))) {
+			snprintf(xstats_names[current].name,
+					sizeof(xstats_names[current].name),
+					"%s", rte_ixgbe_stats_strings[i].name);
+			xstat[current].id = current;
+			xstat[current].value =
+					*(uint64_t *)(((char *)hw_stats) +
+					rte_ixgbe_stats_strings[i].offset);
+			break;
+		};
+	}
+	for (i = 0; i < IXGBE_NB_MACSEC_STATS; i++) {
+		if (!strncmp(rte_ixgbe_macsec_strings[i].name, name,
+				sizeof(rte_ixgbe_macsec_strings[i].name))) {
+			snprintf(xstats_names[current].name,
+					sizeof(xstats_names[current].name),
+					"%s",
+					rte_ixgbe_macsec_strings[i].name);
+			xstat[current].id = current;
+			xstat[current].value =
+					*(uint64_t *)(((char *)hw_stats) +
+					rte_ixgbe_macsec_strings[i].offset);
+			break;
+		};
+	}
+	for (i = 0; i < IXGBE_NB_RXQ_PRIO_STATS; i++) {
+		if (!strncmp(rte_ixgbe_rxq_strings[i].name, name,
+				sizeof(rte_ixgbe_rxq_strings[i].name))) {
+			snprintf(xstats_names[current].name,
+					sizeof(xstats_names[current].name),
+					"%s", rte_ixgbe_rxq_strings[i].name);
+			xstat[current].id = current;
+			xstat[current].value =
+					*(uint64_t *)(((char *)hw_stats) +
+					rte_ixgbe_rxq_strings[i].offset);
+			break;
+		};
+	}
+	for (i = 0; i < IXGBE_NB_TXQ_PRIO_STATS; i++) {
+		if (!strncmp(rte_ixgbe_txq_strings[i].name, name,
+				sizeof(rte_ixgbe_txq_strings[i].name))) {
+			snprintf(xstats_names[current].name,
+					sizeof(xstats_names[current].name),
+					"%s", rte_ixgbe_txq_strings[i].name);
+			xstat[current].id = current;
+			xstat[current].value =
+					*(uint64_t *)(((char *)hw_stats) +
+					rte_ixgbe_txq_strings[i].offset);
+			break;
+		};
+	}
+	return cnt_stats;
+}
+
 static int ixgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, __rte_unused unsigned limit)
 {
@@ -3094,6 +3243,77 @@ static int ixgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	return cnt_stats;
 }
 
+static
+int ixgbe_dev_xstats_get_names_by_group(__rte_unused struct rte_eth_dev *dev,
+	struct rte_eth_xstat_name *xstats_names,
+	__rte_unused unsigned int limit, uint64_t group_mask)
+{
+	const unsigned int
+	cnt_stats = ixgbe_xstats_calc_num_by_group(group_mask);
+	unsigned int stat, i, count;
+
+	if (xstats_names != NULL) {
+		count = 0;
+
+		/* Note: limit >= cnt_stats checked upstream
+		 * in rte_eth_xstats_names()
+		 */
+
+		/* Extended stats from ixgbe_hw_stats */
+		for (i = 0; i < IXGBE_NB_HW_STATS; i++) {
+			if (rte_ixgbe_stats_strings[i].group_mask &
+					group_mask)	{
+				snprintf(xstats_names[count].name,
+					sizeof(xstats_names[count].name),
+					"%s",
+					rte_ixgbe_stats_strings[i].name);
+				count++;
+			}
+		}
+
+		/* MACsec Stats */
+		for (i = 0; i < IXGBE_NB_MACSEC_STATS; i++) {
+			if (rte_ixgbe_macsec_strings[i].group_mask &
+					group_mask){
+				snprintf(xstats_names[count].name,
+					sizeof(xstats_names[count].name),
+					"%s",
+					rte_ixgbe_macsec_strings[i].name);
+				count++;
+			}
+		}
+
+		/* RX Priority Stats */
+		for (stat = 0; stat < IXGBE_NB_RXQ_PRIO_STATS; stat++) {
+			for (i = 0; i < IXGBE_NB_RXQ_PRIO_VALUES; i++) {
+				if (rte_ixgbe_rxq_strings[stat].group_mask &
+					    group_mask) {
+					snprintf(xstats_names[count].name,
+					    sizeof(xstats_names[count].name),
+					    "rx_priority%u_%s", i,
+					    rte_ixgbe_rxq_strings[stat].name);
+					count++;
+				}
+			}
+		}
+
+		/* TX Priority Stats */
+		for (stat = 0; stat < IXGBE_NB_TXQ_PRIO_STATS; stat++) {
+			for (i = 0; i < IXGBE_NB_TXQ_PRIO_VALUES; i++) {
+				if (rte_ixgbe_txq_strings[stat].group_mask &
+					    group_mask) {
+					snprintf(xstats_names[count].name,
+					    sizeof(xstats_names[count].name),
+					    "tx_priority%u_%s", i,
+					    rte_ixgbe_txq_strings[stat].name);
+					count++;
+				}
+			}
+		}
+	}
+	return cnt_stats;
+}
+
 static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned limit)
 {
@@ -3184,6 +3404,94 @@ static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	return count;
 }
 
+static int
+ixgbe_dev_xstats_get_by_group(struct rte_eth_dev *dev,
+		struct rte_eth_xstat *xstats,
+		unsigned int n, uint64_t group_mask)
+{
+	struct ixgbe_hw *hw =
+			IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_hw_stats *hw_stats =
+			IXGBE_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
+	struct ixgbe_macsec_stats *macsec_stats =
+			IXGBE_DEV_PRIVATE_TO_MACSEC_STATS(
+				dev->data->dev_private);
+	uint64_t total_missed_rx, total_qbrc, total_qprc, total_qprdc;
+	unsigned int i, stat, count = 0;
+
+	count = ixgbe_xstats_calc_num_by_group(group_mask);
+
+	if (n < count)
+		return count;
+
+	total_missed_rx = 0;
+	total_qbrc = 0;
+	total_qprc = 0;
+	total_qprdc = 0;
+
+	ixgbe_read_stats_registers(hw, hw_stats, macsec_stats, &total_missed_rx,
+			&total_qbrc, &total_qprc, &total_qprdc);
+
+	/* If this is a reset xstats is NULL, and we have cleared the
+	 * registers by reading them.
+	 */
+	if (!xstats)
+		return 0;
+
+	/* Extended stats from ixgbe_hw_stats */
+	count = 0;
+	for (i = 0; i < IXGBE_NB_HW_STATS; i++) {
+		if (rte_ixgbe_stats_strings[i].group_mask & group_mask) {
+			xstats[count].value = *(uint64_t *)(((char *)hw_stats) +
+					rte_ixgbe_stats_strings[i].offset);
+			xstats[count].id = count;
+			count++;
+		}
+	}
+
+	/* MACsec Stats */
+	for (i = 0; i < IXGBE_NB_MACSEC_STATS; i++) {
+		if (rte_ixgbe_macsec_strings[i].group_mask & group_mask) {
+			xstats[count].value =
+					*(uint64_t *)(((char *)macsec_stats) +
+					rte_ixgbe_macsec_strings[i].offset);
+			xstats[count].id = count;
+			count++;
+		}
+	}
+
+	/* RX Priority Stats */
+	for (stat = 0; stat < IXGBE_NB_RXQ_PRIO_STATS; stat++) {
+		for (i = 0; i < IXGBE_NB_RXQ_PRIO_VALUES; i++) {
+			if (rte_ixgbe_rxq_strings[stat].group_mask &
+					group_mask) {
+				xstats[count].value =
+					*(uint64_t *)(((char *)hw_stats) +
+					rte_ixgbe_rxq_strings[stat].offset +
+					(sizeof(uint64_t) * i));
+				xstats[count].id = count;
+				count++;
+			}
+		}
+	}
+
+	/* TX Priority Stats */
+	for (stat = 0; stat < IXGBE_NB_TXQ_PRIO_STATS; stat++) {
+		for (i = 0; i < IXGBE_NB_TXQ_PRIO_VALUES; i++) {
+			if (rte_ixgbe_txq_strings[stat].group_mask &
+					group_mask) {
+				xstats[count].value =
+					*(uint64_t *)(((char *)hw_stats) +
+					rte_ixgbe_txq_strings[stat].offset +
+					(sizeof(uint64_t) * i));
+				xstats[count].id = count;
+				count++;
+			}
+		}
+	}
+	return count;
+}
+
 static void
 ixgbe_dev_xstats_reset(struct rte_eth_dev *dev)
 {
@@ -4097,7 +4405,8 @@ static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 
 	/* Disable any previous flow control settings */
 	mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN);
-	mflcn_reg &= ~(IXGBE_MFLCN_RPFCE_SHIFT | IXGBE_MFLCN_RFCE|IXGBE_MFLCN_RPFCE);
+	mflcn_reg &= ~(IXGBE_MFLCN_RPFCE_SHIFT |
+			IXGBE_MFLCN_RFCE | IXGBE_MFLCN_RPFCE);
 
 	fccfg_reg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
 	fccfg_reg &= ~(IXGBE_FCCFG_TFCE_802_3X | IXGBE_FCCFG_TFCE_PRIORITY);
@@ -4206,7 +4515,8 @@ static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 }
 
 static int
-ixgbe_priority_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_pfc_conf *pfc_conf)
+ixgbe_priority_flow_ctrl_set(struct rte_eth_dev *dev,
+		struct rte_eth_pfc_conf *pfc_conf)
 {
 	int err;
 	uint32_t rx_buf_size;
-- 
1.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 4/4] app/proc_info: add support for xstats-name and xstats-group
  2017-03-03 12:54 [dpdk-dev] [PATCH 0/4] extend API to retriving xstats by group and xstats by name Kuba Kozak
                   ` (2 preceding siblings ...)
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 3/4] net/ixgbe: add grouping of xstats for ixgbe driver Kuba Kozak
@ 2017-03-03 12:54 ` Kuba Kozak
  3 siblings, 0 replies; 8+ messages in thread
From: Kuba Kozak @ 2017-03-03 12:54 UTC (permalink / raw)
  To: dev; +Cc: Jacek Piasecki, Kuba Kozak

From: Jacek Piasecki <jacekx.piasecki@intel.com>

This patch provides support for proc_info application
to allow printing single xstat value specified by its
name and printing xstats values specified by its group name.
New proc_info arguments:
--xstats-name NAME: to display single xstat value by NAME
--xstats-group GROUPNAME: to display group of xstats by GROUPNAME

Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>
Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>
---
 app/proc_info/main.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 1 deletion(-)

diff --git a/app/proc_info/main.c b/app/proc_info/main.c
index 2c56d10..8826090 100644
--- a/app/proc_info/main.c
+++ b/app/proc_info/main.c
@@ -74,6 +74,11 @@
 static uint32_t reset_xstats;
 /**< Enable memory info. */
 static uint32_t mem_info;
+/**< Enable displaying xstat name. */
+static uint32_t enable_xstats_name;
+static char *xstats_name;
+/**< Enable displaying xstat group name. */
+static uint64_t enable_xstats_group;
 
 /**< display usage */
 static void
@@ -85,6 +90,8 @@
 		"  --stats: to display port statistics, enabled by default\n"
 		"  --xstats: to display extended port statistics, disabled by "
 			"default\n"
+		"  --xstats-name NAME: to display single xstat value by NAME\n"
+		"  --xstats-group GROUPNAME: to display group of xstats by GROUPNAME\n"
 		"  --stats-reset: to reset port statistics\n"
 		"  --xstats-reset: to reset port extended statistics\n",
 		prgname);
@@ -128,6 +135,8 @@
 		{"stats-reset", 0, NULL, 0},
 		{"xstats", 0, NULL, 0},
 		{"xstats-reset", 0, NULL, 0},
+		{"xstats-name", required_argument, NULL, 1},
+		{"xstats-group", required_argument, NULL, 1},
 		{NULL, 0, 0, 0}
 	};
 
@@ -168,7 +177,27 @@
 					MAX_LONG_OPT_SZ))
 				reset_xstats = 1;
 			break;
-
+		case 1:
+			/* Print xstat single value given by name*/
+			if (!strncmp(long_option[option_index].name,
+					"xstats-name",
+					MAX_LONG_OPT_SZ))	{
+				enable_xstats_name = 1;
+				xstats_name = optarg;
+				printf("name:%s:%s\n",
+						long_option[option_index].name,
+						optarg);
+			}
+			/* Print xstat group values given by group name*/
+			else if (!strncmp(long_option[option_index].name,
+					"xstats-group",
+					MAX_LONG_OPT_SZ))	{
+				enable_xstats_group = atoi(optarg);
+				printf("name:%s:%s\n",
+						long_option[option_index].name,
+						optarg);
+			}
+			break;
 		default:
 			proc_info_usage(prgname);
 			return -1;
@@ -241,6 +270,82 @@
 }
 
 static void
+nic_xstats_by_name_display(__rte_unused uint8_t port_id,
+		__rte_unused char *name)
+{
+	struct rte_eth_xstat xstat;
+
+	printf("###### NIC statistics for port %-2d, statistic name '%s':\n",
+			   port_id, name);
+
+	if (rte_eth_xstats_get_by_name(port_id, &xstat, name) == 0)
+		printf("%s: %"PRIu64"\n", name, xstat.value);
+	else
+		printf("Statistic not found...\n");
+
+}
+
+static void
+nic_xstats_by_group_display(__rte_unused uint8_t port_id,
+		__rte_unused uint64_t group_mask)
+{
+	struct rte_eth_xstat *xstats;
+	int cnt_xstats, idx_xstat;
+	struct rte_eth_xstat_name *xstats_names;
+
+	printf("###### NIC extended statistics for port %-2d,"
+			" group %-2lu #########\n",
+			   port_id, group_mask);
+
+	/* Get count */
+	cnt_xstats = rte_eth_xstats_get_names_by_group(port_id, NULL, 0,
+			group_mask);
+	if (cnt_xstats  < 0) {
+		printf("Error: Cannot get count of xstats\n");
+		return;
+	}
+
+	/* Get id-name lookup table */
+	xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * cnt_xstats);
+	if (xstats_names == NULL) {
+		printf("Cannot allocate memory for xstats lookup\n");
+		return;
+	}
+
+	if (cnt_xstats != rte_eth_xstats_get_names_by_group(
+			port_id, xstats_names, cnt_xstats, group_mask)) {
+		printf("Error: Cannot get xstats lookup\n");
+		free(xstats_names);
+		return;
+	}
+
+	/* Get stats themselves */
+	xstats = malloc(sizeof(struct rte_eth_xstat) * cnt_xstats);
+	if (xstats == NULL) {
+		printf("Cannot allocate memory for xstats\n");
+		free(xstats_names);
+		return;
+	}
+
+	if (cnt_xstats != rte_eth_xstats_get_by_group(port_id, xstats,
+			cnt_xstats, group_mask)) {
+		printf("Error: Unable to get xstats\n");
+		free(xstats_names);
+		free(xstats);
+		return;
+	}
+
+	/* Display xstats */
+	for (idx_xstat = 0; idx_xstat < cnt_xstats; idx_xstat++)
+		printf("%s: %"PRIu64"\n",
+			xstats_names[idx_xstat].name,
+			xstats[idx_xstat].value);
+	free(xstats_names);
+	free(xstats);
+
+}
+
+static void
 nic_xstats_display(uint8_t port_id)
 {
 	struct rte_eth_xstat_name *xstats_names;
@@ -360,6 +465,11 @@
 				nic_stats_clear(i);
 			else if (reset_xstats)
 				nic_xstats_clear(i);
+			else if (enable_xstats_group)
+				nic_xstats_by_group_display(i,
+						enable_xstats_group);
+			else if (enable_xstats_name)
+				nic_xstats_by_name_display(i, xstats_name);
 		}
 	}
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [dpdk-dev] [PATCH 2/4] net/e1000: add grouping of xstats for e1000 driver
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 2/4] net/e1000: add grouping of xstats for e1000 driver Kuba Kozak
@ 2017-03-06  2:05   ` Lu, Wenzhuo
  0 siblings, 0 replies; 8+ messages in thread
From: Lu, Wenzhuo @ 2017-03-06  2:05 UTC (permalink / raw)
  To: Kozak, KubaX, dev; +Cc: Piasecki, JacekX, Kozak, KubaX

Hi,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Kuba Kozak
> Sent: Friday, March 3, 2017 8:55 PM
> To: dev@dpdk.org
> Cc: Piasecki, JacekX; Kozak, KubaX
> Subject: [dpdk-dev] [PATCH 2/4] net/e1000: add grouping of xstats for e1000
> driver
> 
> From: Jacek Piasecki <jacekx.piasecki@intel.com>
> 
> This patch extends the 'rte_igb_xstats_name_off' structure with additional field
> 'group_mask'. For each xstats there is now specified group (e.g. TX_GROUP),
> one xstatistic can be in several groups.
> To implement new functionality of retriving xstats by group on driver level, there
> are two functions added:
> eth_igb_xstats_get_by_group() and eth_igb_xstats_get_names_by_group()
> 
> Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>
> Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>
Acked-by: Wenzhuo Lu <wenzhuo.lu@intel.com>

Just a reminder, the tittle need to add v2 when sending a new version, like ' [dpdk-dev] [v2 PATCH 2/4]'

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [dpdk-dev] [PATCH 1/4] ethdev: add retrieving xstats by group and xstats by name
  2017-03-03 12:54 ` [dpdk-dev] [PATCH 1/4] ethdev: add retrieving " Kuba Kozak
@ 2017-03-06 10:17   ` Thomas Monjalon
  0 siblings, 0 replies; 8+ messages in thread
From: Thomas Monjalon @ 2017-03-06 10:17 UTC (permalink / raw)
  To: Kuba Kozak, Jacek Piasecki; +Cc: dev

Hi,

2017-03-03 13:54, Kuba Kozak:
> From: Jacek Piasecki <jacekx.piasecki@intel.com>
> 
> This patch extends library for retriving xstats by specified groups and
> single xstat by given name.
> 
> Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>
> Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>

As you probably know, it is difficult to have a good review
(or a simple review at all).
The most difficult part in such a change is not writing the code,
it is explaining your idea and getting people to agree.
Please show you have thought about the API, seen an issue or a lack,
and propose an idea with a clear target.
In short, we are missing a "why" and "how".

You must also explain what is a group, better than a list of #define.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 1/4] ethdev: add retrieving xstats by group and xstats by name
  2017-03-02 16:07 [dpdk-dev] [PATCH 0/4] extend API to retriving xstats by group and xstats by name Kuba Kozak
@ 2017-03-02 16:07 ` Kuba Kozak
  0 siblings, 0 replies; 8+ messages in thread
From: Kuba Kozak @ 2017-03-02 16:07 UTC (permalink / raw)
  To: dev; +Cc: Jacek Piasecki, Kuba Kozak

From: Jacek Piasecki <jacekx.piasecki@intel.com>

This patch extends library for retriving xstats by specified groups and
single xstat by given name.

Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>
Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>
---
 lib/librte_ether/rte_ethdev.c | 310 ++++++++++++++++++++++++++++++++++++++++--
 lib/librte_ether/rte_ethdev.h | 105 +++++++++++++-
 2 files changed, 401 insertions(+), 14 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index eb0a94a..e18ca1d 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -87,33 +87,37 @@
 struct rte_eth_xstats_name_off {
 	char name[RTE_ETH_XSTATS_NAME_SIZE];
 	unsigned offset;
+	uint64_t group_mask;
 };
 
 static const struct rte_eth_xstats_name_off rte_stats_strings[] = {
-	{"rx_good_packets", offsetof(struct rte_eth_stats, ipackets)},
-	{"tx_good_packets", offsetof(struct rte_eth_stats, opackets)},
-	{"rx_good_bytes", offsetof(struct rte_eth_stats, ibytes)},
-	{"tx_good_bytes", offsetof(struct rte_eth_stats, obytes)},
-	{"rx_errors", offsetof(struct rte_eth_stats, ierrors)},
-	{"tx_errors", offsetof(struct rte_eth_stats, oerrors)},
+	{"rx_good_packets", offsetof(struct rte_eth_stats, ipackets), RX_GROUP},
+	{"tx_good_packets", offsetof(struct rte_eth_stats, opackets), TX_GROUP},
+	{"rx_good_bytes", offsetof(struct rte_eth_stats, ibytes), RX_GROUP},
+	{"tx_good_bytes", offsetof(struct rte_eth_stats, obytes), TX_GROUP},
+	{"rx_errors", offsetof(struct rte_eth_stats, ierrors),
+			RX_GROUP | ERR_GROUP},
+	{"tx_errors", offsetof(struct rte_eth_stats, oerrors),
+			TX_GROUP | ERR_GROUP},
 	{"rx_mbuf_allocation_errors", offsetof(struct rte_eth_stats,
-		rx_nombuf)},
+		rx_nombuf), RX_GROUP | ERR_GROUP},
 };
 
 #define RTE_NB_STATS (sizeof(rte_stats_strings) / sizeof(rte_stats_strings[0]))
 
 static const struct rte_eth_xstats_name_off rte_rxq_stats_strings[] = {
-	{"packets", offsetof(struct rte_eth_stats, q_ipackets)},
-	{"bytes", offsetof(struct rte_eth_stats, q_ibytes)},
-	{"errors", offsetof(struct rte_eth_stats, q_errors)},
+	{"packets", offsetof(struct rte_eth_stats, q_ipackets), RXQ_GROUP},
+	{"bytes", offsetof(struct rte_eth_stats, q_ibytes), RXQ_GROUP},
+	{"errors", offsetof(struct rte_eth_stats, q_errors),
+			RXQ_GROUP | ERR_GROUP},
 };
 
 #define RTE_NB_RXQ_STATS (sizeof(rte_rxq_stats_strings) /	\
 		sizeof(rte_rxq_stats_strings[0]))
 
 static const struct rte_eth_xstats_name_off rte_txq_stats_strings[] = {
-	{"packets", offsetof(struct rte_eth_stats, q_opackets)},
-	{"bytes", offsetof(struct rte_eth_stats, q_obytes)},
+	{"packets", offsetof(struct rte_eth_stats, q_opackets), TXQ_GROUP},
+	{"bytes", offsetof(struct rte_eth_stats, q_obytes), TXQ_GROUP},
 };
 #define RTE_NB_TXQ_STATS (sizeof(rte_txq_stats_strings) /	\
 		sizeof(rte_txq_stats_strings[0]))
@@ -1448,6 +1452,110 @@ struct rte_eth_dev *
 	return count;
 }
 
+static int
+get_xstats_count_by_group(uint8_t port_id, uint64_t group_mask)
+{
+	struct rte_eth_dev *dev;
+	int count = 0;
+	int dcount = 0;
+	unsigned i;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+	if (dev->dev_ops->xstats_get_names_by_group != NULL) {
+		dcount = (*dev->dev_ops->xstats_get_names_by_group)
+				(dev, NULL, 0, group_mask);
+		if (dcount < 0)
+			return dcount;
+	}
+
+
+
+
+	for (i = 0; i < RTE_NB_STATS; i++) {
+		if (rte_stats_strings[i].group_mask & group_mask)
+			count++;
+	}
+	for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
+		if (rte_rxq_stats_strings[i].group_mask & group_mask)
+			count += RTE_MIN(dev->data->nb_rx_queues,
+					RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	}
+	for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
+		if (rte_txq_stats_strings[i].group_mask & group_mask)
+			count += RTE_MIN(dev->data->nb_tx_queues,
+					RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	}
+	return count+dcount;
+}
+
+int
+rte_eth_xstats_get_by_name(uint8_t port_id, struct rte_eth_xstat *xstat,
+		const char *name)
+{
+	struct rte_eth_xstat *xstats;
+	int cnt_xstats, idx_xstat;
+	struct rte_eth_xstat_name *xstats_names;
+
+
+
+	/* Get count */
+	cnt_xstats = rte_eth_xstats_get_names(port_id, NULL, 0);
+	if (cnt_xstats  < 0) {
+		printf("Error: Cannot get count of xstats\n");
+		return -1;
+	}
+
+	/* Get id-name lookup table */
+	xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * cnt_xstats);
+	if (xstats_names == NULL) {
+		printf("Cannot allocate memory for xstats lookup\n");
+		return -1;
+	}
+	if (cnt_xstats != rte_eth_xstats_get_names(
+			port_id, xstats_names, cnt_xstats)) {
+		printf("Error: Cannot get xstats lookup\n");
+		free(xstats_names);
+		return -1;
+	}
+
+	/* Get stats themselves */
+	xstats = malloc(sizeof(struct rte_eth_xstat) * cnt_xstats);
+	if (xstats == NULL) {
+		printf("Cannot allocate memory for xstats\n");
+		free(xstats_names);
+		return -1;
+	}
+
+	if (cnt_xstats != rte_eth_xstats_get(port_id, xstats, cnt_xstats)) {
+		printf("Error: Unable to get xstats\n");
+		free(xstats_names);
+		free(xstats);
+		return -1;
+	}
+
+	if (!xstat) {
+		printf("Error: xstat pointer is NULL\n");
+		free(xstats_names);
+		free(xstats);
+		return -1;
+	}
+
+	/* Display xstats */
+	for (idx_xstat = 0; idx_xstat < cnt_xstats; idx_xstat++) {
+		if (!strcmp(xstats_names[idx_xstat].name, name)) {
+
+			xstat->id = xstats[idx_xstat].id;
+			xstat->value = xstats[idx_xstat].value;
+			return 0;
+		};
+	}
+
+	free(xstats_names);
+	free(xstats);
+	return -1;
+}
+
 int
 rte_eth_xstats_get_names(uint8_t port_id,
 	struct rte_eth_xstat_name *xstats_names,
@@ -1513,6 +1621,83 @@ struct rte_eth_dev *
 	return cnt_used_entries;
 }
 
+int
+rte_eth_xstats_get_names_by_group(uint8_t port_id,
+	struct rte_eth_xstat_name *xstats_names,
+	unsigned size, __rte_unused uint64_t group_mask)
+{
+	struct rte_eth_dev *dev;
+	int cnt_used_entries;
+	int cnt_expected_entries;
+	int cnt_driver_entries;
+	uint32_t idx, id_queue;
+	uint16_t num_q;
+
+	cnt_expected_entries = get_xstats_count_by_group(port_id, group_mask);
+	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];
+	cnt_used_entries = 0;
+
+	for (idx = 0; idx < RTE_NB_STATS; idx++) {
+		if (rte_stats_strings[idx].group_mask & group_mask) {
+			snprintf(xstats_names[cnt_used_entries].name,
+				sizeof(xstats_names[0].name),
+				"%s", rte_stats_strings[idx].name);
+			cnt_used_entries++;
+		}
+	}
+	num_q = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	for (id_queue = 0; id_queue < num_q; id_queue++) {
+		for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) {
+			if (rte_rxq_stats_strings[idx].group_mask &
+					group_mask) {
+				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++;
+			}
+		}
+	}
+	num_q = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	for (id_queue = 0; id_queue < num_q; id_queue++) {
+		for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) {
+			if (rte_txq_stats_strings[idx].group_mask &
+					group_mask) {
+				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++;
+			}
+
+		}
+	}
+
+	if (dev->dev_ops->xstats_get_names != NULL) {
+		/* If there are any driver-specific xstats, append them
+		 * to end of list.
+		 */
+		cnt_driver_entries =
+				(*dev->dev_ops->xstats_get_names_by_group)(
+			dev,
+			xstats_names + cnt_used_entries,
+			size - cnt_used_entries,
+			group_mask);
+		if (cnt_driver_entries < 0)
+			return cnt_driver_entries;
+		cnt_used_entries += cnt_driver_entries;
+	}
+
+	return cnt_used_entries;
+}
+
 /* retrieve ethdev extended statistics */
 int
 rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstat *xstats,
@@ -1595,6 +1780,104 @@ struct rte_eth_dev *
 	return count + xcount;
 }
 
+/* retrieve ethdev extended statistics */
+int
+rte_eth_xstats_get_by_group(uint8_t port_id, struct rte_eth_xstat *xstats,
+	unsigned n, uint64_t group_mask)
+{
+	struct rte_eth_stats eth_stats;
+	struct rte_eth_dev *dev;
+	unsigned count = 0, i, q;
+	signed xcount = 0;
+	uint64_t val, *stats_ptr;
+	uint16_t nb_rxqs, nb_txqs;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+
+	dev = &rte_eth_devices[port_id];
+
+	nb_rxqs = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	nb_txqs = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+
+	for (i = 0; i < RTE_NB_STATS; i++) {
+		if (rte_stats_strings[i].group_mask & group_mask)
+			count++;
+	}
+	for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
+		if (rte_rxq_stats_strings[i].group_mask & group_mask)
+			count += nb_rxqs;
+	}
+	for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
+		if (rte_txq_stats_strings[i].group_mask & group_mask)
+			count += nb_txqs;
+	}
+
+	/* implemented by the driver */
+	if (dev->dev_ops->xstats_get_by_group != NULL) {
+		/* Retrieve the xstats from the driver at the end of the
+		 * xstats struct.
+		 */
+		xcount = (*dev->dev_ops->xstats_get_by_group)(dev,
+				xstats ? xstats + count : NULL,
+				(n > count) ? n - count : 0,
+				group_mask);
+
+		if (xcount < 0)
+			return xcount;
+	}
+
+	if (n < count + xcount || xstats == NULL)
+		return count + xcount;
+
+	/* now fill the xstats structure */
+	count = 0;
+	rte_eth_stats_get(port_id, &eth_stats);
+
+	/* global stats */
+	for (i = 0; i < RTE_NB_STATS; i++) {
+		if (rte_stats_strings[i].group_mask & group_mask) {
+			stats_ptr = RTE_PTR_ADD(&eth_stats,
+						rte_stats_strings[i].offset);
+			val = *stats_ptr;
+			xstats[count++].value = val;
+		}
+	}
+
+	/* per-rxq stats */
+	for (q = 0; q < nb_rxqs; q++) {
+		for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
+			if (rte_rxq_stats_strings[i].group_mask & group_mask) {
+				stats_ptr = RTE_PTR_ADD(&eth_stats,
+						rte_rxq_stats_strings[i].offset
+						+ q * sizeof(uint64_t));
+				val = *stats_ptr;
+				xstats[count++].value = val;
+			}
+		}
+	}
+
+	/* per-txq stats */
+	for (q = 0; q < nb_txqs; q++) {
+		for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
+			if (rte_txq_stats_strings[i].group_mask & group_mask) {
+				stats_ptr = RTE_PTR_ADD(&eth_stats,
+						rte_txq_stats_strings[i].offset
+						+ q * sizeof(uint64_t));
+				val = *stats_ptr;
+				xstats[count++].value = val;
+			}
+		}
+	}
+
+	for (i = 0; i < count; i++)
+		xstats[i].id = i;
+	/* add an offset to driver-specific stats */
+	for ( ; i < count + xcount; i++)
+		xstats[i].id += count;
+
+	return count + xcount;
+}
+
 /* reset ethdev extended statistics */
 void
 rte_eth_xstats_reset(uint8_t port_id)
@@ -1624,7 +1907,8 @@ struct rte_eth_dev *
 
 	dev = &rte_eth_devices[port_id];
 
-	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_stats_mapping_set, -ENOTSUP);
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_stats_mapping_set,
+			-ENOTSUP);
 	return (*dev->dev_ops->queue_stats_mapping_set)
 			(dev, queue_id, stat_idx, is_rx);
 }
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index c17bbda..d7cdca2 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -990,6 +990,17 @@ struct rte_eth_xstat_name {
 #define ETH_MAX_VMDQ_POOL  64
 
 /**
+ * Xstats groups by bit no. in 'group_mask'
+ */
+#define TX_GROUP	0x0001
+#define RX_GROUP	0x0002
+#define ERR_GROUP	0x0004
+#define TXQ_GROUP	0x0008
+#define RXQ_GROUP	0x0010
+#define VF_GROUP	0x0020
+#define MAC_GROUP	0x0040
+
+/**
  * A structure used to get the information of queue and
  * TC mapping on both TX and RX paths.
  */
@@ -1118,6 +1129,10 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+typedef int (*eth_xstats_get_by_group_t)(struct rte_eth_dev *dev,
+	struct rte_eth_xstat *stats, unsigned n, uint64_t group_mask);
+/**< @internal Get extended stats of an Ethernet device. */
+
 typedef void (*eth_xstats_reset_t)(struct rte_eth_dev *dev);
 /**< @internal Reset extended stats of an Ethernet device. */
 
@@ -1125,6 +1140,17 @@ 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_xstats_get_names_by_group_t)(struct rte_eth_dev *dev,
+	struct rte_eth_xstat_name *xstats_names,
+	unsigned size, uint64_t group_mask);
+/**< @internal Get names of extended stats of an Ethernet device. */
+
+typedef int (*eth_xstats_get_by_name_t)(struct rte_eth_dev *dev,
+		struct rte_eth_xstat_name *xstats_names,
+		struct rte_eth_xstat *xstat,
+		const char *name);
+/**< @internal Get xstat specified by name 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,
@@ -1456,8 +1482,13 @@ struct eth_dev_ops {
 	eth_stats_get_t            stats_get;     /**< Get generic device statistics. */
 	eth_stats_reset_t          stats_reset;   /**< Reset generic device statistics. */
 	eth_xstats_get_t           xstats_get;    /**< Get extended device statistics. */
+	eth_xstats_get_by_group_t  xstats_get_by_group;
+	/**< Get extended device statistics. */
 	eth_xstats_reset_t         xstats_reset;  /**< Reset extended device statistics. */
-	eth_xstats_get_names_t     xstats_get_names;
+	eth_xstats_get_names_t	   xstats_get_names;
+	eth_xstats_get_names_by_group_t xstats_get_names_by_group;
+	eth_xstats_get_by_name_t	xstats_get_by_name;
+
 	/**< Get names of extended statistics. */
 	eth_queue_stats_mapping_set_t queue_stats_mapping_set;
 	/**< Configure per queue stat counter mapping. */
@@ -2307,6 +2338,51 @@ int rte_eth_xstats_get_names(uint8_t port_id,
 		unsigned size);
 
 /**
+ * Get extended statistics of an Ethernet device matching specified name.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param name
+ *   Phrase used to search extended statistics
+ * @param name *xstat
+ *   Pointer to allocated memory for rte_eth_xstat structure
+ * @return
+ *   - 0 when xstat was successfully found and value and id were returned
+ *   using pointer to rte_eth_xstat,
+ *   - A negative value when xstat wasn't found.
+ */
+int
+rte_eth_xstats_get_by_name(uint8_t port_id, struct rte_eth_xstat *xstat,
+		const char *name);
+
+
+/**
+ * Retrieve names of extended grouped statistics of an Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. If set to NULL, the function returns the required number
+ *   of elements.
+ * @param size
+ *   The size of the xstats_names array (number of elements).
+ * @param group_id
+ *   Group identificator
+ * @return
+ *   - A positive value lower or equal to size: success. The return value
+ *     is the number of entries filled in the stats table.
+ *   - A 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.
+ */
+int
+rte_eth_xstats_get_names_by_group(uint8_t port_id,
+	struct rte_eth_xstat_name *xstats_names,
+	unsigned size, uint64_t group_mask);
+
+/**
  * Retrieve extended statistics of an Ethernet device.
  *
  * @param port_id
@@ -2332,6 +2408,33 @@ int rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstat *xstats,
 		unsigned n);
 
 /**
+ * Retrieve extended grouped statistics of an Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param xstats
+ *   A pointer to a table of structure of type *rte_eth_xstat*
+ *   to be filled with device statistics ids and values: id is the
+ *   index of the name string in xstats_names (see rte_eth_xstats_get_names()),
+ *   and value is the statistic counter.
+ *   This parameter can be set to NULL if n is 0.
+ * @param n
+ *   The size of the xstats array (number of elements).
+ * @param group_id
+ *   Group identificator
+ * @return
+ *   - A positive value lower or equal to n: success. The return value
+ *     is the number of entries filled in the stats table.
+ *   - A positive value higher than n: 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.
+ *   - A negative value on error (invalid port id).
+ */
+int rte_eth_xstats_get_by_group(uint8_t port_id, struct rte_eth_xstat *xstats,
+		unsigned n, uint64_t group_mask);
+
+/**
  * Reset extended statistics of an Ethernet device.
  *
  * @param port_id
-- 
1.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-03-06 10:17 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-03 12:54 [dpdk-dev] [PATCH 0/4] extend API to retriving xstats by group and xstats by name Kuba Kozak
2017-03-03 12:54 ` [dpdk-dev] [PATCH 1/4] ethdev: add retrieving " Kuba Kozak
2017-03-06 10:17   ` Thomas Monjalon
2017-03-03 12:54 ` [dpdk-dev] [PATCH 2/4] net/e1000: add grouping of xstats for e1000 driver Kuba Kozak
2017-03-06  2:05   ` Lu, Wenzhuo
2017-03-03 12:54 ` [dpdk-dev] [PATCH 3/4] net/ixgbe: add grouping of xstats for ixgbe driver Kuba Kozak
2017-03-03 12:54 ` [dpdk-dev] [PATCH 4/4] app/proc_info: add support for xstats-name and xstats-group Kuba Kozak
  -- strict thread matches above, loose matches on Subject: below --
2017-03-02 16:07 [dpdk-dev] [PATCH 0/4] extend API to retriving xstats by group and xstats by name Kuba Kozak
2017-03-02 16:07 ` [dpdk-dev] [PATCH 1/4] ethdev: add retrieving " Kuba Kozak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).