From: Huisong Li lihuisong@huawei.com
One of the hot discussions in community recently was moving queue stats to xstats. In this solution, a temporary 'RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS' device flag is created to implement the smooth switch. And the first half of this work has been completed in the ethdev framework. Now driver needs to remove the flag from the driver initialization process and does the rest of work.
For better readability and reasonablity, per-queue stats also should be cleared when rte_eth_stats is cleared. Otherwise, the sum of one item in per-queue stats may be greater than corresponding item in rte_eth_stats.
Signed-off-by: Huisong Li lihuisong@huawei.com Signed-off-by: Lijun Ou oulijun@huawei.com --- drivers/net/hns3/hns3_ethdev.c | 2 - drivers/net/hns3/hns3_ethdev_vf.c | 2 - drivers/net/hns3/hns3_rxtx.c | 2 + drivers/net/hns3/hns3_rxtx.h | 13 ++ drivers/net/hns3/hns3_stats.c | 241 +++++++++++++++++++++++++++++++------- drivers/net/hns3/hns3_stats.h | 6 + 6 files changed, 221 insertions(+), 45 deletions(-)
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c index 449d967..7c51e83 100644 --- a/drivers/net/hns3/hns3_ethdev.c +++ b/drivers/net/hns3/hns3_ethdev.c @@ -6148,8 +6148,6 @@ hns3_dev_init(struct rte_eth_dev *eth_dev) return 0; }
- eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS; - ret = hns3_mp_init_primary(); if (ret) { PMD_INIT_LOG(ERR, diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c index bb4ec6b..37135d7 100644 --- a/drivers/net/hns3/hns3_ethdev_vf.c +++ b/drivers/net/hns3/hns3_ethdev_vf.c @@ -2746,8 +2746,6 @@ hns3vf_dev_init(struct rte_eth_dev *eth_dev) return 0; }
- eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS; - ret = hns3_mp_init_primary(); if (ret) { PMD_INIT_LOG(ERR, diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c index 3d5f74f..30f1e06 100644 --- a/drivers/net/hns3/hns3_rxtx.c +++ b/drivers/net/hns3/hns3_rxtx.c @@ -1792,6 +1792,7 @@ hns3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t nb_desc, rxq->io_head_reg = (volatile void *)((char *)rxq->io_base + HNS3_RING_RX_HEAD_REG); rxq->rx_buf_len = rx_buf_size; + memset(&rxq->basic_stats, 0, sizeof(struct hns3_rx_basic_stats)); memset(&rxq->err_stats, 0, sizeof(struct hns3_rx_bd_errors_stats)); memset(&rxq->dfx_stats, 0, sizeof(struct hns3_rx_dfx_stats));
@@ -2618,6 +2619,7 @@ hns3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t nb_desc, HNS3_RING_TX_TAIL_REG); txq->min_tx_pkt_len = hw->min_tx_pkt_len; txq->tso_mode = hw->tso_mode; + memset(&txq->basic_stats, 0, sizeof(struct hns3_tx_basic_stats)); memset(&txq->dfx_stats, 0, sizeof(struct hns3_tx_dfx_stats));
rte_spinlock_lock(&hw->lock); diff --git a/drivers/net/hns3/hns3_rxtx.h b/drivers/net/hns3/hns3_rxtx.h index 8a0c981..331b507 100644 --- a/drivers/net/hns3/hns3_rxtx.h +++ b/drivers/net/hns3/hns3_rxtx.h @@ -266,6 +266,12 @@ struct hns3_entry { struct rte_mbuf *mbuf; };
+struct hns3_rx_basic_stats { + uint64_t packets; + uint64_t bytes; + uint64_t errors; +}; + struct hns3_rx_dfx_stats { uint64_t l3_csum_errors; uint64_t l4_csum_errors; @@ -324,6 +330,7 @@ struct hns3_rx_queue { bool pvid_sw_discard_en; bool enabled; /* indicate if Rx queue has been enabled */
+ struct hns3_rx_basic_stats basic_stats; /* DFX statistics that driver does not need to discard packets */ struct hns3_rx_dfx_stats dfx_stats; /* Error statistics that driver needs to discard packets */ @@ -338,6 +345,11 @@ struct hns3_rx_queue { struct rte_mbuf fake_mbuf; /* fake mbuf used with vector rx */ };
+struct hns3_tx_basic_stats { + uint64_t packets; + uint64_t bytes; +}; + /* * The following items are used for the abnormal errors statistics in * the Tx datapath. When upper level application calls the @@ -472,6 +484,7 @@ struct hns3_tx_queue { bool pvid_sw_shift_en; bool enabled; /* indicate if Tx queue has been enabled */
+ struct hns3_tx_basic_stats basic_stats; struct hns3_tx_dfx_stats dfx_stats; };
diff --git a/drivers/net/hns3/hns3_stats.c b/drivers/net/hns3/hns3_stats.c index 419d7e2..3ba09e2 100644 --- a/drivers/net/hns3/hns3_stats.c +++ b/drivers/net/hns3/hns3_stats.c @@ -11,6 +11,24 @@ #include "hns3_logs.h" #include "hns3_regs.h"
+/* The statistics of the per-rxq basic stats */ +static const struct hns3_xstats_name_offset hns3_rxq_basic_stats_strings[] = { + {"packets", + HNS3_RXQ_BASIC_STATS_FIELD_OFFSET(packets)}, + {"bytes", + HNS3_RXQ_BASIC_STATS_FIELD_OFFSET(bytes)}, + {"errors", + HNS3_RXQ_BASIC_STATS_FIELD_OFFSET(errors)} +}; + +/* The statistics of the per-txq basic stats */ +static const struct hns3_xstats_name_offset hns3_txq_basic_stats_strings[] = { + {"packets", + HNS3_TXQ_BASIC_STATS_FIELD_OFFSET(packets)}, + {"bytes", + HNS3_TXQ_BASIC_STATS_FIELD_OFFSET(bytes)} +}; + /* MAC statistics */ static const struct hns3_xstats_name_offset hns3_mac_strings[] = { {"mac_tx_mac_pause_num", @@ -330,6 +348,12 @@ static const struct hns3_xstats_name_offset hns3_tx_queue_strings[] = { #define HNS3_NUM_TX_QUEUE_STATS (sizeof(hns3_tx_queue_strings) / \ sizeof(hns3_tx_queue_strings[0]))
+#define HNS3_NUM_RXQ_BASIC_STATS (sizeof(hns3_rxq_basic_stats_strings) / \ + sizeof(hns3_rxq_basic_stats_strings[0])) + +#define HNS3_NUM_TXQ_BASIC_STATS (sizeof(hns3_txq_basic_stats_strings) / \ + sizeof(hns3_txq_basic_stats_strings[0])) + #define HNS3_FIX_NUM_STATS (HNS3_NUM_MAC_STATS + HNS3_NUM_ERROR_INT_XSTATS + \ HNS3_NUM_RESET_XSTATS)
@@ -508,9 +532,7 @@ hns3_stats_get(struct rte_eth_dev *eth_dev, struct rte_eth_stats *rte_stats) struct hns3_hw *hw = &hns->hw; struct hns3_tqp_stats *stats = &hw->tqp_stats; struct hns3_rx_queue *rxq; - struct hns3_tx_queue *txq; uint64_t cnt; - uint64_t num; uint16_t i; int ret;
@@ -522,25 +544,14 @@ hns3_stats_get(struct rte_eth_dev *eth_dev, struct rte_eth_stats *rte_stats) }
/* Get the error stats of received packets */ - num = RTE_MIN(RTE_ETHDEV_QUEUE_STAT_CNTRS, eth_dev->data->nb_rx_queues); - for (i = 0; i != num; ++i) { + for (i = 0; i < eth_dev->data->nb_rx_queues; i++) { rxq = eth_dev->data->rx_queues[i]; if (rxq) { cnt = rxq->err_stats.l2_errors + rxq->err_stats.pkt_len_errors; - rte_stats->q_errors[i] = cnt; - rte_stats->q_ipackets[i] = - stats->rcb_rx_ring_pktnum[i] - cnt; rte_stats->ierrors += cnt; } } - /* Get the error stats of transmitted packets */ - num = RTE_MIN(RTE_ETHDEV_QUEUE_STAT_CNTRS, eth_dev->data->nb_tx_queues); - for (i = 0; i < num; i++) { - txq = eth_dev->data->tx_queues[i]; - if (txq) - rte_stats->q_opackets[i] = stats->rcb_tx_ring_pktnum[i]; - }
rte_stats->oerrors = 0; rte_stats->ipackets = stats->rcb_rx_ring_pktnum_rcd - @@ -600,6 +611,11 @@ hns3_stats_reset(struct rte_eth_dev *eth_dev) } }
+ /* + * 'packets' in hns3_tx_basic_stats and hns3_rx_basic_stats come + * from hw->tqp_stats. And clearing tqp stats is like clearing + * their source. + */ hns3_tqp_stats_clear(hw);
return 0; @@ -628,21 +644,26 @@ hns3_mac_stats_reset(__rte_unused struct rte_eth_dev *dev) static int hns3_xstats_calc_num(struct rte_eth_dev *dev) { +#define HNS3_PF_VF_RX_COMM_STATS_NUM (HNS3_NUM_RX_BD_ERROR_XSTATS + \ + HNS3_NUM_RXQ_DFX_XSTATS + \ + HNS3_NUM_RX_QUEUE_STATS + \ + HNS3_NUM_RXQ_BASIC_STATS) +#define HNS3_PF_VF_TX_COMM_STATS_NUM (HNS3_NUM_TXQ_DFX_XSTATS + \ + HNS3_NUM_TX_QUEUE_STATS + \ + HNS3_NUM_TXQ_BASIC_STATS) + struct hns3_adapter *hns = dev->data->dev_private; uint16_t nb_rx_q = dev->data->nb_rx_queues; uint16_t nb_tx_q = dev->data->nb_tx_queues; - int bderr_stats = nb_rx_q * HNS3_NUM_RX_BD_ERROR_XSTATS; - int rx_dfx_stats = nb_rx_q * HNS3_NUM_RXQ_DFX_XSTATS; - int tx_dfx_stats = nb_tx_q * HNS3_NUM_TXQ_DFX_XSTATS; - int rx_queue_stats = nb_rx_q * HNS3_NUM_RX_QUEUE_STATS; - int tx_queue_stats = nb_tx_q * HNS3_NUM_TX_QUEUE_STATS; + int rx_comm_stats_num = nb_rx_q * HNS3_PF_VF_RX_COMM_STATS_NUM; + int tx_comm_stats_num = nb_tx_q * HNS3_PF_VF_TX_COMM_STATS_NUM;
if (hns->is_vf) - return bderr_stats + rx_dfx_stats + tx_dfx_stats + - rx_queue_stats + tx_queue_stats + HNS3_NUM_RESET_XSTATS; + return rx_comm_stats_num + tx_comm_stats_num + + HNS3_NUM_RESET_XSTATS; else - return bderr_stats + rx_dfx_stats + tx_dfx_stats + - rx_queue_stats + tx_queue_stats + HNS3_FIX_NUM_STATS; + return rx_comm_stats_num + tx_comm_stats_num + + HNS3_FIX_NUM_STATS; }
static void @@ -751,6 +772,118 @@ hns3_tqp_dfx_stats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats, hns3_rxq_dfx_stats_get(dev, xstats, count); hns3_txq_dfx_stats_get(dev, xstats, count); } + +static void +hns3_rxq_basic_stats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats, + int *count) +{ + struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct hns3_tqp_stats *stats = &hw->tqp_stats; + struct hns3_rx_basic_stats *rxq_stats; + struct hns3_rx_queue *rxq; + uint16_t i, j; + char *val; + + for (i = 0; i < dev->data->nb_rx_queues; i++) { + rxq = dev->data->rx_queues[i]; + if (rxq == NULL) + continue; + + rxq_stats = &rxq->basic_stats; + rxq_stats->errors = rxq->err_stats.l2_errors + + rxq->err_stats.pkt_len_errors; + rxq_stats->packets = stats->rcb_rx_ring_pktnum[i] - + rxq_stats->errors; + rxq_stats->bytes = 0; + for (j = 0; j < HNS3_NUM_RXQ_BASIC_STATS; j++) { + val = (char *)rxq_stats + + hns3_rxq_basic_stats_strings[j].offset; + xstats[*count].value = *(uint64_t *)val; + xstats[*count].id = *count; + (*count)++; + } + } +} + +static void +hns3_txq_basic_stats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats, + int *count) +{ + struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct hns3_tqp_stats *stats = &hw->tqp_stats; + struct hns3_tx_basic_stats *txq_stats; + struct hns3_tx_queue *txq; + uint16_t i, j; + char *val; + + for (i = 0; i < dev->data->nb_tx_queues; i++) { + txq = dev->data->tx_queues[i]; + if (txq == NULL) + continue; + + txq_stats = &txq->basic_stats; + txq_stats->packets = stats->rcb_tx_ring_pktnum[i]; + txq_stats->bytes = 0; + for (j = 0; j < HNS3_NUM_TXQ_BASIC_STATS; j++) { + val = (char *)txq_stats + + hns3_txq_basic_stats_strings[j].offset; + xstats[*count].value = *(uint64_t *)val; + xstats[*count].id = *count; + (*count)++; + } + } +} + +static int +hns3_tqp_basic_stats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats, + int *count) +{ + struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int ret; + + /* Update tqp stats by read register */ + ret = hns3_update_tqp_stats(hw); + if (ret) { + hns3_err(hw, "Update tqp stats fail, ret = %d.", ret); + return ret; + } + + hns3_rxq_basic_stats_get(dev, xstats, count); + hns3_txq_basic_stats_get(dev, xstats, count); + + return 0; +} + +/* + * The function is only called by hns3_dev_xstats_reset to clear + * basic stats of per-queue. TQP stats are all cleared in hns3_stats_reset + * which is called before this function. + * + * @param dev + * Pointer to Ethernet device. + */ +static void +hns3_tqp_basic_stats_clear(struct rte_eth_dev *dev) +{ + struct hns3_tx_queue *txq; + struct hns3_rx_queue *rxq; + uint16_t i; + + for (i = 0; i < dev->data->nb_rx_queues; i++) { + rxq = dev->data->rx_queues[i]; + if (rxq) + memset(&rxq->basic_stats, 0, + sizeof(struct hns3_rx_basic_stats)); + } + + for (i = 0; i < dev->data->nb_tx_queues; i++) { + txq = dev->data->tx_queues[i]; + if (txq) + memset(&txq->basic_stats, 0, + sizeof(struct hns3_tx_basic_stats)); + } +} + /* * Retrieve extended(tqp | Mac) statistics of an Ethernet device. * @param dev @@ -789,6 +922,10 @@ hns3_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
count = 0;
+ ret = hns3_tqp_basic_stats_get(dev, xstats, &count); + if (ret < 0) + return ret; + if (!hns->is_vf) { /* Update Mac stats */ ret = hns3_query_update_mac_stats(dev); @@ -844,28 +981,55 @@ hns3_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats, }
static void +hns3_tqp_basic_stats_name_get(struct rte_eth_dev *dev, + struct rte_eth_xstat_name *xstats_names, + uint32_t *count) +{ + uint16_t i, j; + + for (i = 0; i < dev->data->nb_rx_queues; i++) { + for (j = 0; j < HNS3_NUM_RXQ_BASIC_STATS; j++) { + snprintf(xstats_names[*count].name, + sizeof(xstats_names[*count].name), + "rx_q%u_%s", i, + hns3_rxq_basic_stats_strings[j].name); + (*count)++; + } + } + for (i = 0; i < dev->data->nb_tx_queues; i++) { + for (j = 0; j < HNS3_NUM_TXQ_BASIC_STATS; j++) { + snprintf(xstats_names[*count].name, + sizeof(xstats_names[*count].name), + "tx_q%u_%s", i, + hns3_txq_basic_stats_strings[j].name); + (*count)++; + } + } +} + +static void hns3_tqp_dfx_stats_name_get(struct rte_eth_dev *dev, struct rte_eth_xstat_name *xstats_names, uint32_t *count) { uint16_t i, j;
- for (j = 0; j < dev->data->nb_rx_queues; j++) { - for (i = 0; i < HNS3_NUM_RXQ_DFX_XSTATS; i++) { + for (i = 0; i < dev->data->nb_rx_queues; i++) { + for (j = 0; j < HNS3_NUM_RXQ_DFX_XSTATS; j++) { snprintf(xstats_names[*count].name, sizeof(xstats_names[*count].name), - "rx_q%u_%s", j, - hns3_rxq_dfx_stats_strings[i].name); + "rx_q%u_%s", i, + hns3_rxq_dfx_stats_strings[j].name); (*count)++; } }
- for (j = 0; j < dev->data->nb_tx_queues; j++) { - for (i = 0; i < HNS3_NUM_TXQ_DFX_XSTATS; i++) { + for (i = 0; i < dev->data->nb_tx_queues; i++) { + for (j = 0; j < HNS3_NUM_TXQ_DFX_XSTATS; j++) { snprintf(xstats_names[*count].name, sizeof(xstats_names[*count].name), - "tx_q%u_%s", j, - hns3_txq_dfx_stats_strings[i].name); + "tx_q%u_%s", i, + hns3_txq_dfx_stats_strings[j].name); (*count)++; } } @@ -908,6 +1072,8 @@ hns3_dev_xstats_get_names(struct rte_eth_dev *dev, if (xstats_names == NULL) return cnt_stats;
+ hns3_tqp_basic_stats_name_get(dev, xstats_names, &count); + /* Note: size limited checked in rte_eth_xstats_get_names() */ if (!hns->is_vf) { /* Get MAC name from hw->hw_xstats.mac_stats struct */ @@ -999,7 +1165,6 @@ hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids, uint32_t count_value; uint64_t len; uint32_t i; - int ret;
if (ids == NULL && values == NULL) return cnt_stats; @@ -1008,13 +1173,6 @@ hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids, if (size < cnt_stats) return cnt_stats;
- /* Update tqp stats by read register */ - ret = hns3_update_tqp_stats(hw); - if (ret) { - hns3_err(hw, "Update tqp stats fail : %d", ret); - return ret; - } - len = cnt_stats * sizeof(struct rte_eth_xstat); values_copy = rte_zmalloc("hns3_xstats_values", len, 0); if (values_copy == NULL) { @@ -1157,11 +1315,12 @@ hns3_dev_xstats_reset(struct rte_eth_dev *dev) if (ret) return ret;
+ hns3_tqp_basic_stats_clear(dev); + hns3_tqp_dfx_stats_clear(dev); + /* Clear reset stats */ memset(&hns->hw.reset.stats, 0, sizeof(struct hns3_reset_stats));
- hns3_tqp_dfx_stats_clear(dev); - if (hns->is_vf) return 0;
diff --git a/drivers/net/hns3/hns3_stats.h b/drivers/net/hns3/hns3_stats.h index 12842cd..d213be5 100644 --- a/drivers/net/hns3/hns3_stats.h +++ b/drivers/net/hns3/hns3_stats.h @@ -135,6 +135,12 @@ struct hns3_reset_stats; #define HNS3_TXQ_DFX_STATS_FIELD_OFFSET(f) \ (offsetof(struct hns3_tx_dfx_stats, f))
+#define HNS3_RXQ_BASIC_STATS_FIELD_OFFSET(f) \ + (offsetof(struct hns3_rx_basic_stats, f)) + +#define HNS3_TXQ_BASIC_STATS_FIELD_OFFSET(f) \ + (offsetof(struct hns3_tx_basic_stats, f)) + int hns3_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats); int hns3_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats, unsigned int n);