[dpdk-dev,v2,6/8] net/mrvl: add extended statistics

Message ID 1520844132-29969-7-git-send-email-tdu@semihalf.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/Intel-compilation success Compilation OK

Commit Message

Tomasz Duszynski March 12, 2018, 8:42 a.m. UTC
  Add extended statistics implementation.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |   1 +
 doc/guides/nics/mrvl.rst          |   1 +
 drivers/net/mrvl/mrvl_ethdev.c    | 205 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 206 insertions(+), 1 deletion(-)
  

Comments

Ferruh Yigit March 14, 2018, 5:21 p.m. UTC | #1
On 3/12/2018 8:42 AM, Tomasz Duszynski wrote:
> Add extended statistics implementation.
> 
> Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>

<...>

> @@ -1674,6 +1784,94 @@ mrvl_eth_filter_ctrl(struct rte_eth_dev *dev __rte_unused,
>  	}
>  }
>  
> +/**
> + * DPDK callback to get xstats by id.
> + *
> + * @param dev
> + *   Pointer to the device structure.
> + * @param ids
> + *   Pointer to the ids table.
> + * @param values
> + *   Pointer to the values table.
> + * @param n
> + *   Values table size.
> + * @returns
> + *   Number of read values, negative value otherwise.
> + */
> +static int
> +mrvl_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
> +		      uint64_t *values, unsigned int n)
> +{
> +	unsigned int i, num = RTE_DIM(mrvl_xstats_tbl);
> +	uint64_t vals[n];
> +	int ret;
> +
> +	if (!ids) {

You will not get NULL ids, this case covered by ethdev layer, for both by_id()
functions.

> +		struct rte_eth_xstat xstats[num];
> +		int j;
> +
> +		ret = mrvl_xstats_get(dev, xstats, num);
> +		for (j = 0; j < ret; i++)
> +			values[j] = xstats[j].value;
> +
> +		return ret;
> +	}
> +
> +	ret = mrvl_xstats_get_by_id(dev, NULL, vals, n);
> +	if (ret < 0)
> +		return ret;
> +
> +	for (i = 0; i < n; i++) {
> +		if (ids[i] >= num) {
> +			RTE_LOG(ERR, PMD, "id value is not valid\n");
> +			return -1;
> +		}
> +
> +		values[i] = vals[ids[i]];
> +	}
> +
> +	return n;
> +}
> +
> +/**
> + * DPDK callback to get xstats names by ids.
> + *
> + * @param dev
> + *   Pointer to the device structure.
> + * @param xstats_names
> + *   Pointer to table with xstats names.
> + * @param ids
> + *   Pointer to table with ids.
> + * @param size
> + *   Xstats names table size.
> + * @returns
> + *   Number of names read, negative value otherwise.
> + */
> +static int
> +mrvl_xstats_get_names_by_id(struct rte_eth_dev *dev,
> +			    struct rte_eth_xstat_name *xstats_names,
> +			    const uint64_t *ids, unsigned int size)
> +{
> +	unsigned int i, num = RTE_DIM(mrvl_xstats_tbl);
> +	struct rte_eth_xstat_name names[num];
> +
> +	if (!ids)
> +		return mrvl_xstats_get_names(dev, xstats_names, size);
> +
> +	mrvl_xstats_get_names(dev, names, size);
> +	for (i = 0; i < size; i++) {
> +		if (ids[i] >= num) {
> +			RTE_LOG(ERR, PMD, "id value is not valid");
> +			return -1;
> +		}
> +
> +		snprintf(xstats_names[i].name, RTE_ETH_XSTATS_NAME_SIZE,
> +			 "%s", names[ids[i]].name);
> +	}
> +
> +	return size;
> +}

Specific to *_by_id() implementations, please check ethdev layer APIs for these
devops, they already do same thing as you did here.

These devops are to access specific ids efficiently with support of PMD, if you
don't have a quick way to access to an extended stat by id, you may just left
these unimplemented and abstraction layer will do the work for you, it is up to you.


Thanks,
ferruh
  
Tomasz Duszynski March 15, 2018, 7:09 a.m. UTC | #2
On Wed, Mar 14, 2018 at 05:21:07PM +0000, Ferruh Yigit wrote:
> On 3/12/2018 8:42 AM, Tomasz Duszynski wrote:
> > Add extended statistics implementation.
> >
> > Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
> > Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>
> <...>
>
> > @@ -1674,6 +1784,94 @@ mrvl_eth_filter_ctrl(struct rte_eth_dev *dev __rte_unused,
> >  	}
> >  }
> >
> > +/**
> > + * DPDK callback to get xstats by id.
> > + *
> > + * @param dev
> > + *   Pointer to the device structure.
> > + * @param ids
> > + *   Pointer to the ids table.
> > + * @param values
> > + *   Pointer to the values table.
> > + * @param n
> > + *   Values table size.
> > + * @returns
> > + *   Number of read values, negative value otherwise.
> > + */
> > +static int
> > +mrvl_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
> > +		      uint64_t *values, unsigned int n)
> > +{
> > +	unsigned int i, num = RTE_DIM(mrvl_xstats_tbl);
> > +	uint64_t vals[n];
> > +	int ret;
> > +
> > +	if (!ids) {
>
> You will not get NULL ids, this case covered by ethdev layer, for both by_id()
> functions.
>
> > +		struct rte_eth_xstat xstats[num];
> > +		int j;
> > +
> > +		ret = mrvl_xstats_get(dev, xstats, num);
> > +		for (j = 0; j < ret; i++)
> > +			values[j] = xstats[j].value;
> > +
> > +		return ret;
> > +	}
> > +
> > +	ret = mrvl_xstats_get_by_id(dev, NULL, vals, n);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		if (ids[i] >= num) {
> > +			RTE_LOG(ERR, PMD, "id value is not valid\n");
> > +			return -1;
> > +		}
> > +
> > +		values[i] = vals[ids[i]];
> > +	}
> > +
> > +	return n;
> > +}
> > +
> > +/**
> > + * DPDK callback to get xstats names by ids.
> > + *
> > + * @param dev
> > + *   Pointer to the device structure.
> > + * @param xstats_names
> > + *   Pointer to table with xstats names.
> > + * @param ids
> > + *   Pointer to table with ids.
> > + * @param size
> > + *   Xstats names table size.
> > + * @returns
> > + *   Number of names read, negative value otherwise.
> > + */
> > +static int
> > +mrvl_xstats_get_names_by_id(struct rte_eth_dev *dev,
> > +			    struct rte_eth_xstat_name *xstats_names,
> > +			    const uint64_t *ids, unsigned int size)
> > +{
> > +	unsigned int i, num = RTE_DIM(mrvl_xstats_tbl);
> > +	struct rte_eth_xstat_name names[num];
> > +
> > +	if (!ids)
> > +		return mrvl_xstats_get_names(dev, xstats_names, size);
> > +
> > +	mrvl_xstats_get_names(dev, names, size);
> > +	for (i = 0; i < size; i++) {
> > +		if (ids[i] >= num) {
> > +			RTE_LOG(ERR, PMD, "id value is not valid");
> > +			return -1;
> > +		}
> > +
> > +		snprintf(xstats_names[i].name, RTE_ETH_XSTATS_NAME_SIZE,
> > +			 "%s", names[ids[i]].name);
> > +	}
> > +
> > +	return size;
> > +}
>
> Specific to *_by_id() implementations, please check ethdev layer APIs for these
> devops, they already do same thing as you did here.
>
> These devops are to access specific ids efficiently with support of PMD, if you
> don't have a quick way to access to an extended stat by id, you may just left
> these unimplemented and abstraction layer will do the work for you, it is up to you.

Good point. Since *_by_id() are using xstats_get_names()/xstats_get()
anyway they do not provide a real speedup. I'll drop that in v3.

>
>
> Thanks,
> ferruh

--
- Tomasz Duszyński
  

Patch

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index 00d9621..120fd4d 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -19,5 +19,6 @@  L3 checksum offload  = Y
 L4 checksum offload  = Y
 Packet type parsing  = Y
 Basic stats          = Y
+Extended stats       = Y
 ARMv8                = Y
 Usage doc            = Y
diff --git a/doc/guides/nics/mrvl.rst b/doc/guides/nics/mrvl.rst
index 9230d5e..7678265 100644
--- a/doc/guides/nics/mrvl.rst
+++ b/doc/guides/nics/mrvl.rst
@@ -70,6 +70,7 @@  Features of the MRVL PMD are:
 - L4 checksum offload
 - Packet type parsing
 - Basic stats
+- Extended stats
 - QoS
 
 
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index 34b9ef7..cbe3f4d 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -145,6 +145,32 @@  static inline void mrvl_free_sent_buffers(struct pp2_ppio *ppio,
 			struct pp2_hif *hif, unsigned int core_id,
 			struct mrvl_shadow_txq *sq, int qid, int force);
 
+#define MRVL_XSTATS_TBL_ENTRY(name) { \
+	#name, offsetof(struct pp2_ppio_statistics, name),	\
+	sizeof(((struct pp2_ppio_statistics *)0)->name)		\
+}
+
+/* Table with xstats data */
+static struct {
+	const char *name;
+	unsigned int offset;
+	unsigned int size;
+} mrvl_xstats_tbl[] = {
+	MRVL_XSTATS_TBL_ENTRY(rx_bytes),
+	MRVL_XSTATS_TBL_ENTRY(rx_packets),
+	MRVL_XSTATS_TBL_ENTRY(rx_unicast_packets),
+	MRVL_XSTATS_TBL_ENTRY(rx_errors),
+	MRVL_XSTATS_TBL_ENTRY(rx_fullq_dropped),
+	MRVL_XSTATS_TBL_ENTRY(rx_bm_dropped),
+	MRVL_XSTATS_TBL_ENTRY(rx_early_dropped),
+	MRVL_XSTATS_TBL_ENTRY(rx_fifo_dropped),
+	MRVL_XSTATS_TBL_ENTRY(rx_cls_dropped),
+	MRVL_XSTATS_TBL_ENTRY(tx_bytes),
+	MRVL_XSTATS_TBL_ENTRY(tx_packets),
+	MRVL_XSTATS_TBL_ENTRY(tx_unicast_packets),
+	MRVL_XSTATS_TBL_ENTRY(tx_errors)
+};
+
 static inline int
 mrvl_get_bpool_size(int pp2_id, int pool_id)
 {
@@ -1110,6 +1136,90 @@  mrvl_stats_reset(struct rte_eth_dev *dev)
 }
 
 /**
+ * DPDK callback to get extended statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param stats
+ *   Pointer to xstats table.
+ * @param n
+ *   Number of entries in xstats table.
+ * @return
+ *   Negative value on error, number of read xstats otherwise.
+ */
+static int
+mrvl_xstats_get(struct rte_eth_dev *dev,
+		struct rte_eth_xstat *stats, unsigned int n)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct pp2_ppio_statistics ppio_stats;
+	unsigned int i;
+
+	if (!stats)
+		return 0;
+
+	pp2_ppio_get_statistics(priv->ppio, &ppio_stats, 0);
+	for (i = 0; i < n && i < RTE_DIM(mrvl_xstats_tbl); i++) {
+		uint64_t val;
+
+		if (mrvl_xstats_tbl[i].size == sizeof(uint32_t))
+			val = *(uint32_t *)((uint8_t *)&ppio_stats +
+					    mrvl_xstats_tbl[i].offset);
+		else if (mrvl_xstats_tbl[i].size == sizeof(uint64_t))
+			val = *(uint64_t *)((uint8_t *)&ppio_stats +
+					    mrvl_xstats_tbl[i].offset);
+		else
+			return -EINVAL;
+
+		stats[i].id = i;
+		stats[i].value = val;
+	}
+
+	return n;
+}
+
+/**
+ * DPDK callback to reset extended statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_xstats_reset(struct rte_eth_dev *dev)
+{
+	mrvl_stats_reset(dev);
+}
+
+/**
+ * DPDK callback to get extended statistics names.
+ *
+ * @param dev (unused)
+ *   Pointer to Ethernet device structure.
+ * @param xstats_names
+ *   Pointer to xstats names table.
+ * @param size
+ *   Size of the xstats names table.
+ * @return
+ *   Number of read names.
+ */
+static int
+mrvl_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+		      struct rte_eth_xstat_name *xstats_names,
+		      unsigned int size)
+{
+	unsigned int i;
+
+	if (!xstats_names)
+		return RTE_DIM(mrvl_xstats_tbl);
+
+	for (i = 0; i < size && i < RTE_DIM(mrvl_xstats_tbl); i++)
+		snprintf(xstats_names[i].name, RTE_ETH_XSTATS_NAME_SIZE, "%s",
+			 mrvl_xstats_tbl[i].name);
+
+	return size;
+}
+
+/**
  * DPDK callback to get information about the device.
  *
  * @param dev
@@ -1674,6 +1784,94 @@  mrvl_eth_filter_ctrl(struct rte_eth_dev *dev __rte_unused,
 	}
 }
 
+/**
+ * DPDK callback to get xstats by id.
+ *
+ * @param dev
+ *   Pointer to the device structure.
+ * @param ids
+ *   Pointer to the ids table.
+ * @param values
+ *   Pointer to the values table.
+ * @param n
+ *   Values table size.
+ * @returns
+ *   Number of read values, negative value otherwise.
+ */
+static int
+mrvl_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
+		      uint64_t *values, unsigned int n)
+{
+	unsigned int i, num = RTE_DIM(mrvl_xstats_tbl);
+	uint64_t vals[n];
+	int ret;
+
+	if (!ids) {
+		struct rte_eth_xstat xstats[num];
+		int j;
+
+		ret = mrvl_xstats_get(dev, xstats, num);
+		for (j = 0; j < ret; i++)
+			values[j] = xstats[j].value;
+
+		return ret;
+	}
+
+	ret = mrvl_xstats_get_by_id(dev, NULL, vals, n);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < n; i++) {
+		if (ids[i] >= num) {
+			RTE_LOG(ERR, PMD, "id value is not valid\n");
+			return -1;
+		}
+
+		values[i] = vals[ids[i]];
+	}
+
+	return n;
+}
+
+/**
+ * DPDK callback to get xstats names by ids.
+ *
+ * @param dev
+ *   Pointer to the device structure.
+ * @param xstats_names
+ *   Pointer to table with xstats names.
+ * @param ids
+ *   Pointer to table with ids.
+ * @param size
+ *   Xstats names table size.
+ * @returns
+ *   Number of names read, negative value otherwise.
+ */
+static int
+mrvl_xstats_get_names_by_id(struct rte_eth_dev *dev,
+			    struct rte_eth_xstat_name *xstats_names,
+			    const uint64_t *ids, unsigned int size)
+{
+	unsigned int i, num = RTE_DIM(mrvl_xstats_tbl);
+	struct rte_eth_xstat_name names[num];
+
+	if (!ids)
+		return mrvl_xstats_get_names(dev, xstats_names, size);
+
+	mrvl_xstats_get_names(dev, names, size);
+	for (i = 0; i < size; i++) {
+		if (ids[i] >= num) {
+			RTE_LOG(ERR, PMD, "id value is not valid");
+			return -1;
+		}
+
+		snprintf(xstats_names[i].name, RTE_ETH_XSTATS_NAME_SIZE,
+			 "%s", names[ids[i]].name);
+	}
+
+	return size;
+}
+
 static const struct eth_dev_ops mrvl_ops = {
 	.dev_configure = mrvl_dev_configure,
 	.dev_start = mrvl_dev_start,
@@ -1692,6 +1890,9 @@  static const struct eth_dev_ops mrvl_ops = {
 	.mtu_set = mrvl_mtu_set,
 	.stats_get = mrvl_stats_get,
 	.stats_reset = mrvl_stats_reset,
+	.xstats_get = mrvl_xstats_get,
+	.xstats_reset = mrvl_xstats_reset,
+	.xstats_get_names = mrvl_xstats_get_names,
 	.dev_infos_get = mrvl_dev_infos_get,
 	.dev_supported_ptypes_get = mrvl_dev_supported_ptypes_get,
 	.rxq_info_get = mrvl_rxq_info_get,
@@ -1703,7 +1904,9 @@  static const struct eth_dev_ops mrvl_ops = {
 	.tx_queue_release = mrvl_tx_queue_release,
 	.rss_hash_update = mrvl_rss_hash_update,
 	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
-	.filter_ctrl = mrvl_eth_filter_ctrl
+	.filter_ctrl = mrvl_eth_filter_ctrl,
+	.xstats_get_by_id = mrvl_xstats_get_by_id,
+	.xstats_get_names_by_id = mrvl_xstats_get_names_by_id
 };
 
 /**