mlx5: add software counters
authorAdrien Mazarguil <adrien.mazarguil@6wind.com>
Fri, 30 Oct 2015 18:52:36 +0000 (19:52 +0100)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Fri, 30 Oct 2015 21:24:08 +0000 (22:24 +0100)
Hardware counters are not supported yet.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
drivers/net/mlx5/Makefile
drivers/net/mlx5/mlx5.c
drivers/net/mlx5/mlx5.h
drivers/net/mlx5/mlx5_defs.h
drivers/net/mlx5/mlx5_rxq.c
drivers/net/mlx5/mlx5_rxtx.c
drivers/net/mlx5/mlx5_rxtx.h
drivers/net/mlx5/mlx5_stats.c [new file with mode: 0644]
drivers/net/mlx5/mlx5_txq.c

index 028c22c..88b361c 100644 (file)
@@ -48,6 +48,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_trigger.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mac.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_stats.c
 
 # Dependencies.
 DEPDIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += lib/librte_ether
index ddd74d0..38f5199 100644 (file)
@@ -133,6 +133,8 @@ static const struct eth_dev_ops mlx5_dev_ops = {
        .dev_start = mlx5_dev_start,
        .dev_stop = mlx5_dev_stop,
        .dev_close = mlx5_dev_close,
+       .stats_get = mlx5_stats_get,
+       .stats_reset = mlx5_stats_reset,
        .dev_infos_get = mlx5_dev_infos_get,
        .rx_queue_setup = mlx5_rx_queue_setup,
        .tx_queue_setup = mlx5_tx_queue_setup,
index 0e2457a..79559bc 100644 (file)
@@ -177,6 +177,11 @@ int priv_mac_addr_add(struct priv *, unsigned int,
 void mlx5_mac_addr_add(struct rte_eth_dev *, struct ether_addr *, uint32_t,
                       uint32_t);
 
+/* mlx5_stats.c */
+
+void mlx5_stats_get(struct rte_eth_dev *, struct rte_eth_stats *);
+void mlx5_stats_reset(struct rte_eth_dev *);
+
 /* mlx5_trigger.c */
 
 int mlx5_dev_start(struct rte_eth_dev *);
index c85be9c..d3a0d0e 100644 (file)
 #define MLX5_PMD_TX_MP_CACHE 8
 #endif
 
+/*
+ * If defined, only use software counters. The PMD will never ask the hardware
+ * for these, and many of them won't be available.
+ */
+#ifndef MLX5_PMD_SOFT_COUNTERS
+#define MLX5_PMD_SOFT_COUNTERS 1
+#endif
+
 #endif /* RTE_PMD_MLX5_DEFS_H_ */
index 71d4470..620ec70 100644 (file)
@@ -993,6 +993,7 @@ mlx5_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
        if (ret)
                rte_free(rxq);
        else {
+               rxq->stats.idx = idx;
                DEBUG("%p: adding RX queue %p to list",
                      (void *)dev, (void *)rxq);
                (*priv->rxqs)[idx] = rxq;
index ed6faa1..eccbbb9 100644 (file)
@@ -367,6 +367,9 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
                struct txq_elt *elt_next = &(*txq->elts)[elts_head_next];
                struct txq_elt *elt = &(*txq->elts)[elts_head];
                unsigned int segs = NB_SEGS(buf);
+#ifdef MLX5_PMD_SOFT_COUNTERS
+               unsigned int sent_size = 0;
+#endif
                uint32_t send_flags = 0;
 
                /* Clean up old buffer. */
@@ -429,6 +432,9 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
                                         send_flags);
                        if (unlikely(err))
                                goto stop;
+#ifdef MLX5_PMD_SOFT_COUNTERS
+                       sent_size += length;
+#endif
                } else {
 #if MLX5_PMD_SGE_WR_N > 1
                        struct ibv_sge sges[MLX5_PMD_SGE_WR_N];
@@ -447,6 +453,9 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
                                 send_flags);
                        if (unlikely(err))
                                goto stop;
+#ifdef MLX5_PMD_SOFT_COUNTERS
+                       sent_size += ret.length;
+#endif
 #else /* MLX5_PMD_SGE_WR_N > 1 */
                        DEBUG("%p: TX scattered buffers support not"
                              " compiled in", (void *)txq);
@@ -454,11 +463,19 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
 #endif /* MLX5_PMD_SGE_WR_N > 1 */
                }
                elts_head = elts_head_next;
+#ifdef MLX5_PMD_SOFT_COUNTERS
+               /* Increment sent bytes counter. */
+               txq->stats.obytes += sent_size;
+#endif
        }
 stop:
        /* Take a shortcut if nothing must be sent. */
        if (unlikely(i == 0))
                return 0;
+#ifdef MLX5_PMD_SOFT_COUNTERS
+       /* Increment sent packets counter. */
+       txq->stats.opackets += i;
+#endif
        /* Ring QP doorbell. */
        err = txq->if_qp->send_flush(txq->qp);
        if (unlikely(err)) {
@@ -549,6 +566,10 @@ mlx5_rx_burst_sp(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
                                      " completion status (%d): %s",
                                      (void *)rxq, wc.wr_id, wc.status,
                                      ibv_wc_status_str(wc.status));
+#ifdef MLX5_PMD_SOFT_COUNTERS
+                               /* Increment dropped packets counter. */
+                               ++rxq->stats.idropped;
+#endif
                                /* Link completed WRs together for repost. */
                                *next = wr;
                                next = &wr->next;
@@ -592,6 +613,7 @@ mlx5_rx_burst_sp(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
                                        rte_pktmbuf_free(pkt_buf);
                                }
                                /* Increment out of memory counters. */
+                               ++rxq->stats.rx_nombuf;
                                ++rxq->priv->dev->data->rx_mbuf_alloc_failed;
                                goto repost;
                        }
@@ -651,6 +673,10 @@ mlx5_rx_burst_sp(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
                /* Return packet. */
                *(pkts++) = pkt_buf;
                ++pkts_ret;
+#ifdef MLX5_PMD_SOFT_COUNTERS
+               /* Increment bytes counter. */
+               rxq->stats.ibytes += pkt_buf_len;
+#endif
 repost:
                if (++elts_head >= elts_n)
                        elts_head = 0;
@@ -673,6 +699,10 @@ repost:
                abort();
        }
        rxq->elts_head = elts_head;
+#ifdef MLX5_PMD_SOFT_COUNTERS
+       /* Increment packets counter. */
+       rxq->stats.ipackets += pkts_ret;
+#endif
        return pkts_ret;
 }
 
@@ -753,6 +783,10 @@ mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
                                      " completion status (%d): %s",
                                      (void *)rxq, wc.wr_id, wc.status,
                                      ibv_wc_status_str(wc.status));
+#ifdef MLX5_PMD_SOFT_COUNTERS
+                               /* Increment dropped packets counter. */
+                               ++rxq->stats.idropped;
+#endif
                                /* Add SGE to array for repost. */
                                sges[i] = elt->sge;
                                goto repost;
@@ -772,6 +806,7 @@ mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
                              " can't allocate a new mbuf",
                              (void *)rxq, WR_ID(wr_id).id);
                        /* Increment out of memory counters. */
+                       ++rxq->stats.rx_nombuf;
                        ++rxq->priv->dev->data->rx_mbuf_alloc_failed;
                        goto repost;
                }
@@ -798,6 +833,10 @@ mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
                /* Return packet. */
                *(pkts++) = seg;
                ++pkts_ret;
+#ifdef MLX5_PMD_SOFT_COUNTERS
+               /* Increment bytes counter. */
+               rxq->stats.ibytes += len;
+#endif
 repost:
                if (++elts_head >= elts_n)
                        elts_head = 0;
@@ -818,6 +857,10 @@ repost:
                abort();
        }
        rxq->elts_head = elts_head;
+#ifdef MLX5_PMD_SOFT_COUNTERS
+       /* Increment packets counter. */
+       rxq->stats.ipackets += pkts_ret;
+#endif
        return pkts_ret;
 }
 
index b6f2128..4183820 100644 (file)
 #include "mlx5.h"
 #include "mlx5_defs.h"
 
+struct mlx5_rxq_stats {
+       unsigned int idx; /**< Mapping index. */
+#ifdef MLX5_PMD_SOFT_COUNTERS
+       uint64_t ipackets; /**< Total of successfully received packets. */
+       uint64_t ibytes; /**< Total of successfully received bytes. */
+#endif
+       uint64_t idropped; /**< Total of packets dropped when RX ring full. */
+       uint64_t rx_nombuf; /**< Total of RX mbuf allocation failures. */
+};
+
+struct mlx5_txq_stats {
+       unsigned int idx; /**< Mapping index. */
+#ifdef MLX5_PMD_SOFT_COUNTERS
+       uint64_t opackets; /**< Total of successfully sent packets. */
+       uint64_t obytes; /**< Total of successfully sent bytes. */
+#endif
+       uint64_t odropped; /**< Total of packets not sent when TX ring full. */
+};
+
 /* RX element (scattered packets). */
 struct rxq_elt_sp {
        struct ibv_recv_wr wr; /* Work Request. */
@@ -96,6 +115,7 @@ struct rxq {
        } elts;
        unsigned int sp:1; /* Use scattered RX elements. */
        uint32_t mb_len; /* Length of a mp-issued mbuf. */
+       struct mlx5_rxq_stats stats; /* RX queue counters. */
        unsigned int socket; /* CPU socket ID for allocations. */
        struct ibv_exp_res_domain *rd; /* Resource Domain. */
 };
@@ -135,6 +155,7 @@ struct txq {
        unsigned int elts_comp; /* Number of completion requests. */
        unsigned int elts_comp_cd; /* Countdown for next completion request. */
        unsigned int elts_comp_cd_init; /* Initial value for countdown. */
+       struct mlx5_txq_stats stats; /* TX queue counters. */
        linear_t (*elts_linear)[]; /* Linearized buffers. */
        struct ibv_mr *mr_linear; /* Memory Region for linearized buffers. */
        unsigned int socket; /* CPU socket ID for allocations. */
diff --git a/drivers/net/mlx5/mlx5_stats.c b/drivers/net/mlx5/mlx5_stats.c
new file mode 100644 (file)
index 0000000..a51e945
--- /dev/null
@@ -0,0 +1,144 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 6WIND S.A.
+ *   Copyright 2015 Mellanox.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of 6WIND S.A. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* DPDK headers don't like -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-pedantic"
+#endif
+#include <rte_ethdev.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-pedantic"
+#endif
+
+#include "mlx5.h"
+#include "mlx5_rxtx.h"
+#include "mlx5_defs.h"
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ */
+void
+mlx5_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+       struct priv *priv = dev->data->dev_private;
+       struct rte_eth_stats tmp = {0};
+       unsigned int i;
+       unsigned int idx;
+
+       priv_lock(priv);
+       /* Add software counters. */
+       for (i = 0; (i != priv->rxqs_n); ++i) {
+               struct rxq *rxq = (*priv->rxqs)[i];
+
+               if (rxq == NULL)
+                       continue;
+               idx = rxq->stats.idx;
+               if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+#ifdef MLX5_PMD_SOFT_COUNTERS
+                       tmp.q_ipackets[idx] += rxq->stats.ipackets;
+                       tmp.q_ibytes[idx] += rxq->stats.ibytes;
+#endif
+                       tmp.q_errors[idx] += (rxq->stats.idropped +
+                                             rxq->stats.rx_nombuf);
+               }
+#ifdef MLX5_PMD_SOFT_COUNTERS
+               tmp.ipackets += rxq->stats.ipackets;
+               tmp.ibytes += rxq->stats.ibytes;
+#endif
+               tmp.ierrors += rxq->stats.idropped;
+               tmp.rx_nombuf += rxq->stats.rx_nombuf;
+       }
+       for (i = 0; (i != priv->txqs_n); ++i) {
+               struct txq *txq = (*priv->txqs)[i];
+
+               if (txq == NULL)
+                       continue;
+               idx = txq->stats.idx;
+               if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+#ifdef MLX5_PMD_SOFT_COUNTERS
+                       tmp.q_opackets[idx] += txq->stats.opackets;
+                       tmp.q_obytes[idx] += txq->stats.obytes;
+#endif
+                       tmp.q_errors[idx] += txq->stats.odropped;
+               }
+#ifdef MLX5_PMD_SOFT_COUNTERS
+               tmp.opackets += txq->stats.opackets;
+               tmp.obytes += txq->stats.obytes;
+#endif
+               tmp.oerrors += txq->stats.odropped;
+       }
+#ifndef MLX5_PMD_SOFT_COUNTERS
+       /* FIXME: retrieve and add hardware counters. */
+#endif
+       *stats = tmp;
+       priv_unlock(priv);
+}
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+mlx5_stats_reset(struct rte_eth_dev *dev)
+{
+       struct priv *priv = dev->data->dev_private;
+       unsigned int i;
+       unsigned int idx;
+
+       priv_lock(priv);
+       for (i = 0; (i != priv->rxqs_n); ++i) {
+               if ((*priv->rxqs)[i] == NULL)
+                       continue;
+               idx = (*priv->rxqs)[i]->stats.idx;
+               (*priv->rxqs)[i]->stats =
+                       (struct mlx5_rxq_stats){ .idx = idx };
+       }
+       for (i = 0; (i != priv->txqs_n); ++i) {
+               if ((*priv->txqs)[i] == NULL)
+                       continue;
+               idx = (*priv->rxqs)[i]->stats.idx;
+               (*priv->txqs)[i]->stats =
+                       (struct mlx5_txq_stats){ .idx = idx };
+       }
+#ifndef MLX5_PMD_SOFT_COUNTERS
+       /* FIXME: reset hardware counters. */
+#endif
+       priv_unlock(priv);
+}
index 2bae61f..a53b128 100644 (file)
@@ -472,6 +472,7 @@ mlx5_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
        if (ret)
                rte_free(txq);
        else {
+               txq->stats.idx = idx;
                DEBUG("%p: adding TX queue %p to list",
                      (void *)dev, (void *)txq);
                (*priv->txqs)[idx] = txq;