<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">Hi Ferruh,<div><br></div><div>Opps, I was not aware of that rejection.</div><div>Thanks for notification.</div><div><font color="#000000"><span style="caret-color: rgb(0, 0, 0);"> </span></font></div><div>Let me supersede this patch.</div><div>And create a new one. </div><div><br></div><div>Best,</div><div>Levend</div><div><div><br><blockquote type="cite"><div>On 19 Feb 2023, at 23:09, Ferruh Yigit <ferruh.yigit@amd.com> wrote:</div><br class="Apple-interchange-newline"><div><div>On 2/19/2023 12:26 AM, Levend Sayar wrote:<br><blockquote type="cite">Ferruh,<br><br>Thanks for this detailed review.<br>I am setting superseded this patch and create a new one.<br>You’re right at all points.<br>For rx.no_mbufs counting, I probably overlooked while rebasing my patch<br>and it is mixed with newly came patch.<br><br>When I check ethdev layer again, I noticed that when dev_flags<br>has RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS<br>Rx/tx queue stats are already added. I am pushing a fresh patch for<br>adding rx/tx queue stats.<br><br></blockquote><br>Hi Levend,<br><br>You are right BUT, 'RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS' is a temporary<br>solution and plan is to remove it [1].<br><br>Background is, queue stats in "struct rte_eth_stats" has fixed size and<br>as number of queues supported by devices increase these fields getting<br>bigger and bigger, the solution we came was to completely remove these<br>fields from stats struct and get queue statistics via xstats.<br><br>During transition 'RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS' is introduced<br>until all drivers implement queue stats in xstats. We are not pushing<br>hard for existing drivers to update but at least requiring new drivers<br>to implement xstats method.<br><br>That is why for net/gve updating queue stats in 'gve_dev_stats_get()'<br>rejected before, and xstats implementation is requested.<br><br><br>[1]<br>https://elixir.bootlin.com/dpdk/v22.11.1/source/doc/guides/rel_notes/deprecation.rst#L88<br><br><br><blockquote type="cite">And also noticed a missing part at rx no_mbufs counting.<br><br>Best,<br>Levend<br> <br><br><blockquote type="cite">On 17 Feb 2023, at 15:34, Ferruh Yigit <ferruh.yigit@amd.com> wrote:<br><br>On 2/16/2023 6:58 PM, Levend Sayar wrote:<br><blockquote type="cite">Google Virtual NIC PMD is enriched with extended statistics info.<br></blockquote><br>Only queue stats added to xstats, can you please highlight this in the<br>commit log?<br><br><blockquote type="cite">eth_dev_ops callback names are also synched with eth_dev_ops field names<br><br></blockquote><br>Renaming eth_dev_ops is not related to xstats, and I am not sure if the<br>change is necessary, can you please drop it from this patch?<br><br><blockquote type="cite">Signed-off-by: Levend Sayar <levendsayar@gmail.com><br>---<br>drivers/net/gve/gve_ethdev.c | 152 ++++++++++++++++++++++++++++++-----<br>drivers/net/gve/gve_rx.c | 8 +-<br>2 files changed, 138 insertions(+), 22 deletions(-)<br><br>diff --git a/drivers/net/gve/gve_ethdev.c b/drivers/net/gve/gve_ethdev.c<br>index fef2458a16..e31fdce960 100644<br>--- a/drivers/net/gve/gve_ethdev.c<br>+++ b/drivers/net/gve/gve_ethdev.c<br>@@ -266,7 +266,7 @@ gve_dev_close(struct rte_eth_dev *dev)<br>}<br><br>static int<br>-gve_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info<br>*dev_info)<br>+gve_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info<br>*dev_info)<br>{<br>struct gve_priv *priv = dev->data->dev_private;<br><br>@@ -319,15 +319,12 @@ gve_dev_info_get(struct rte_eth_dev *dev,<br>struct rte_eth_dev_info *dev_info)<br>}<br><br>static int<br>-gve_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)<br>+gve_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)<br>{<br>uint16_t i;<br><br>for (i = 0; i < dev->data->nb_tx_queues; i++) {<br>struct gve_tx_queue *txq = dev->data->tx_queues[i];<br>-if (txq == NULL)<br>-continue;<br>-<br></blockquote><br>I assume check is removed because it is unnecessary, but again not<br>directly related with the patch, can you also drop these from the patch<br>to reduce the noise.<br><br><blockquote type="cite">stats->opackets += txq->packets;<br>stats->obytes += txq->bytes;<br>stats->oerrors += txq->errors;<br>@@ -335,9 +332,6 @@ gve_dev_stats_get(struct rte_eth_dev *dev, struct<br>rte_eth_stats *stats)<br><br>for (i = 0; i < dev->data->nb_rx_queues; i++) {<br>struct gve_rx_queue *rxq = dev->data->rx_queues[i];<br>-if (rxq == NULL)<br>-continue;<br>-<br>stats->ipackets += rxq->packets;<br>stats->ibytes += rxq->bytes;<br>stats->ierrors += rxq->errors;<br>@@ -348,15 +342,12 @@ gve_dev_stats_get(struct rte_eth_dev *dev,<br>struct rte_eth_stats *stats)<br>}<br><br>static int<br>-gve_dev_stats_reset(struct rte_eth_dev *dev)<br>+gve_stats_reset(struct rte_eth_dev *dev)<br>{<br>uint16_t i;<br><br>for (i = 0; i < dev->data->nb_tx_queues; i++) {<br>struct gve_tx_queue *txq = dev->data->tx_queues[i];<br>-if (txq == NULL)<br>-continue;<br>-<br>txq->packets = 0;<br>txq->bytes = 0;<br>txq->errors = 0;<br>@@ -364,9 +355,6 @@ gve_dev_stats_reset(struct rte_eth_dev *dev)<br><br>for (i = 0; i < dev->data->nb_rx_queues; i++) {<br>struct gve_rx_queue *rxq = dev->data->rx_queues[i];<br>-if (rxq == NULL)<br>-continue;<br>-<br>rxq->packets = 0;<br>rxq->bytes = 0;<br>rxq->errors = 0;<br>@@ -377,7 +365,7 @@ gve_dev_stats_reset(struct rte_eth_dev *dev)<br>}<br><br>static int<br>-gve_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)<br>+gve_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)<br>{<br>struct gve_priv *priv = dev->data->dev_private;<br>int err;<br>@@ -403,20 +391,144 @@ gve_dev_mtu_set(struct rte_eth_dev *dev,<br>uint16_t mtu)<br>return 0;<br>}<br><br>+static int<br>+gve_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat<br>*xstats, unsigned int n)<br>+{<br>+if (xstats) {<br></blockquote><br>To reduce indentation (and increase readability) you can prefer:<br>``<br>if !xstats<br>return count;<br><br><put rest of logic here><br>``<br><br><blockquote type="cite">+uint requested = n;<br></blockquote><br>uint? C#? Please prefer standard "unsigned int" type.<br><br><blockquote type="cite">+uint64_t indx = 0;<br>+struct rte_eth_xstat *xstat = xstats;<br>+uint16_t i;<br>+<br>+for (i = 0; i < dev->data->nb_rx_queues; i++) {<br>+struct gve_rx_queue *rxq = dev->data->rx_queues[i];<br>+xstat->id = indx++;<br>+xstat->value = rxq->packets;<br>+if (--requested == 0)<br>+return n;<br></blockquote><br>And in this case, ethdev layer does the checks and return accordingly,<br>so need to try to fill the stats as much as possible, can you please<br>double check the ethdev API?<br><br><blockquote type="cite">+xstat++;<br>+<br>+xstat->id = indx++;<br>+xstat->value = rxq->bytes;<br>+if (--requested == 0)<br>+return n;<br>+xstat++;<br>+<br>+xstat->id = indx++;<br>+xstat->value = rxq->errors;<br>+if (--requested == 0)<br>+return n;<br>+xstat++;<br>+<br>+xstat->id = indx++;<br>+xstat->value = rxq->no_mbufs;<br>+if (--requested == 0)<br>+return n;<br>+xstat++;<br>+}<br>+<br>+for (i = 0; i < dev->data->nb_tx_queues; i++) {<br>+struct gve_tx_queue *txq = dev->data->tx_queues[i];<br>+xstat->id = indx++;<br>+xstat->value = txq->packets;<br>+if (--requested == 0)<br>+return n;<br>+xstat++;<br>+<br>+xstat->id = indx++;<br>+xstat->value = txq->bytes;<br>+if (--requested == 0)<br>+return n;<br>+xstat++;<br>+<br>+xstat->id = indx++;<br>+xstat->value = txq->errors;<br>+if (--requested == 0)<br>+return n;<br>+xstat++;<br>+}<br></blockquote><br><br>This approach is error to prone and close to extension,<br>many inplementations prefer to have an itnernal struct to link between<br>names and values, something like:<br>struct name_offset {<br>char name[RTE_ETH_XSTATS_NAME_SIZE];<br>uint32_t offset;<br>};<br><br>'name' holds the xstat name, for this patch it will be only repeating<br>part of name like 'packets', 'bytes', etc.. and you need to construct<br>the full name on the fly, that is why it you may prefer to add type to<br>above struct to diffrenciate Rx and Tx and use it for name creation, up<br>to you.<br><br><br>'offset' holds the offset of corresponding value in a struct, for you it<br>is "struct gve_rx_queue" & "struct gve_tx_queue", since there are two<br>different structs it helps to create helper macro that gets offset from<br>correct struct.<br><br>struct name_offset rx_name_offset[] = {<br>{ "packets", offsetof(struct gve_rx_queue, packets) },<br> ....<br>}<br><br><br>for (i = 0; i < dev->data->nb_rx_queues; i++) {<br>struct gve_rx_queue *rxq = dev->data->rx_queues[i];<br>addr = (char *)rxq + rx_name_offset[i].offset;<br>xstats[index++].value = *addr;<br>}<br>for (i = 0; i < dev->data->nb_tx_queues; i++) {<br>struct gve_tx_queue *txq = dev->data->tx_queues[i];<br>addr = (char *)txq + tx_name_offset[i].offset;<br>xstats[index++].value = *addr;<br>}<br><br>There are many sample of this in other drivers.<br><br>And since for this case instead of having fixed numbe of names, there<br>are dynamiccaly changing queue names,<br><br><br><blockquote type="cite">+}<br>+<br>+return (dev->data->nb_rx_queues * 4) + (dev->data->nb_tx_queues * 3);<br></blockquote><br>When above suggested 'name_offset' struct used, you can use size of it<br>instead of hardcoded 4 & 3 values.<br><br>With above sample, it becomes:<br><br>return (dev->data->nb_rx_queues * RTE_DIM(rx_name_offset)) +<br>(dev->data->nb_tx_queues * RTE_DIM(tx_name_offset));<br><br><br><blockquote type="cite">+}<br>+<br>+static int<br>+gve_xstats_reset(struct rte_eth_dev *dev)<br>+{<br>+return gve_stats_reset(dev);<br>+}<br>+<br>+static int<br>+gve_xstats_get_names(struct rte_eth_dev *dev, struct<br>rte_eth_xstat_name *xstats_names,<br>+unsigned int n)<br>+{<br>+if (xstats_names) {<br>+uint requested = n;<br>+struct rte_eth_xstat_name *xstats_name = xstats_names;<br>+uint16_t i;<br>+<br>+for (i = 0; i < dev->data->nb_rx_queues; i++) {<br>+snprintf(xstats_name->name, sizeof(xstats_name->name),<br>+"rx_q%d_packets", i);<br>+if (--requested == 0)<br>+return n;<br>+xstats_name++;<br>+snprintf(xstats_name->name, sizeof(xstats_name->name),<br>+"rx_q%d_bytes", i);<br>+if (--requested == 0)<br>+return n;<br>+xstats_name++;<br>+snprintf(xstats_name->name, sizeof(xstats_name->name),<br>+"rx_q%d_errors", i);<br>+if (--requested == 0)<br>+return n;<br>+xstats_name++;<br>+snprintf(xstats_name->name, sizeof(xstats_name->name),<br>+"rx_q%d_no_mbufs", i);<br>+if (--requested == 0)<br>+return n;<br>+xstats_name++;<br>+}<br>+<br></blockquote><br>And again according above samples this becomes:<br><br>for (i = 0; i < dev->data->nb_rx_queues; i++) {<br> for (j = 0; j < RTE_DIM(rx_name_offset); j++) {<br>snprintf(xstats_names[index++].name, sizeof(), "rx_q%d_%s",<br>i, rx_name_offset[j].name);<br>}<br><br><br><blockquote type="cite">+for (i = 0; i < dev->data->nb_tx_queues; i++) {<br>+snprintf(xstats_name->name, sizeof(xstats_name->name),<br>+"tx_q%d_packets", i);<br>+if (--requested == 0)<br>+return n;<br>+xstats_name++;<br>+snprintf(xstats_name->name, sizeof(xstats_name->name),<br>+"tx_q%d_bytes", i);<br>+if (--requested == 0)<br>+return n;<br>+xstats_name++;<br>+snprintf(xstats_name->name, sizeof(xstats_name->name),<br>+"tx_q%d_errors", i);<br>+if (--requested == 0)<br>+return n;<br>+xstats_name++;<br>+}<br>+}<br>+<br>+return (dev->data->nb_rx_queues * 4) + (dev->data->nb_tx_queues * 3);<br>+}<br>+<br>static const struct eth_dev_ops gve_eth_dev_ops = {<br>.dev_configure = gve_dev_configure,<br>.dev_start = gve_dev_start,<br>.dev_stop = gve_dev_stop,<br>.dev_close = gve_dev_close,<br>-.dev_infos_get = gve_dev_info_get,<br>+.dev_infos_get = gve_dev_infos_get,<br>.rx_queue_setup = gve_rx_queue_setup,<br>.tx_queue_setup = gve_tx_queue_setup,<br>.rx_queue_release = gve_rx_queue_release,<br>.tx_queue_release = gve_tx_queue_release,<br>.link_update = gve_link_update,<br>-.stats_get = gve_dev_stats_get,<br>-.stats_reset = gve_dev_stats_reset,<br>-.mtu_set = gve_dev_mtu_set,<br>+.stats_get = gve_stats_get,<br>+.stats_reset = gve_stats_reset,<br>+.mtu_set = gve_mtu_set,<br>+.xstats_get = gve_xstats_get,<br>+.xstats_reset = gve_xstats_reset,<br>+.xstats_get_names = gve_xstats_get_names,<br>};<br><br>static void<br>diff --git a/drivers/net/gve/gve_rx.c b/drivers/net/gve/gve_rx.c<br>index 66fbcf3930..7687977003 100644<br>--- a/drivers/net/gve/gve_rx.c<br>+++ b/drivers/net/gve/gve_rx.c<br>@@ -22,8 +22,10 @@ gve_rx_refill(struct gve_rx_queue *rxq)<br>if (diag < 0) {<br>for (i = 0; i < nb_alloc; i++) {<br>nmb = rte_pktmbuf_alloc(rxq->mpool);<br>-if (!nmb)<br>+if (!nmb) {<br>+rxq->no_mbufs++;<br></blockquote><br>Why this is needed, original code is as following:<br><br>``<br>for (i = 0; i < nb_alloc; i++) {<br>nmb = rte_pktmbuf_alloc(rxq->mpool);<br>if (!nmb)<br>break;<br>rxq->sw_ring[idx + i] = nmb;<br>}<br>if (i != nb_alloc) {<br>rxq->no_mbufs += nb_alloc - i;<br>nb_alloc = i;<br>}<br>``<br><br>"if (i != nb_alloc)" block already takes care of 'rxq->no_mbufs' value,<br>is an additional increment required in the for loop?<br><br><br>And change is unrelated with the patch anyway.<br><br><blockquote type="cite">break;<br>+}<br>rxq->sw_ring[idx + i] = nmb;<br>}<br>if (i != nb_alloc) {<br>@@ -57,8 +59,10 @@ gve_rx_refill(struct gve_rx_queue *rxq)<br>if (diag < 0) {<br>for (i = 0; i < nb_alloc; i++) {<br>nmb = rte_pktmbuf_alloc(rxq->mpool);<br>-if (!nmb)<br>+if (!nmb) {<br>+rxq->no_mbufs++;<br>break;<br>+}<br>rxq->sw_ring[idx + i] = nmb;<br>}<br>nb_alloc = i;<br></blockquote></blockquote><br></blockquote><br></div></div></blockquote></div><br></div></body></html>