From patchwork Thu Jul 16 08:23:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Slava Ovsiienko X-Patchwork-Id: 74204 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id B3CE4A0549; Thu, 16 Jul 2020 10:26:38 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 7AD601BFBC; Thu, 16 Jul 2020 10:23:53 +0200 (CEST) Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by dpdk.org (Postfix) with ESMTP id 9CA8E1BF74 for ; Thu, 16 Jul 2020 10:23:35 +0200 (CEST) Received: from Internal Mail-Server by MTLPINE1 (envelope-from viacheslavo@mellanox.com) with SMTP; 16 Jul 2020 11:23:34 +0300 Received: from pegasus12.mtr.labs.mlnx (pegasus12.mtr.labs.mlnx [10.210.17.40]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 06G8NYhL029033; Thu, 16 Jul 2020 11:23:34 +0300 Received: from pegasus12.mtr.labs.mlnx (localhost [127.0.0.1]) by pegasus12.mtr.labs.mlnx (8.14.7/8.14.7) with ESMTP id 06G8NYKj006763; Thu, 16 Jul 2020 08:23:34 GMT Received: (from viacheslavo@localhost) by pegasus12.mtr.labs.mlnx (8.14.7/8.14.7/Submit) id 06G8NYp4006762; Thu, 16 Jul 2020 08:23:34 GMT X-Authentication-Warning: pegasus12.mtr.labs.mlnx: viacheslavo set sender to viacheslavo@mellanox.com using -f From: Viacheslav Ovsiienko To: dev@dpdk.org Cc: matan@mellanox.com, rasland@mellanox.com, olivier.matz@6wind.com, thomas@monjalon.net, ferruh.yigit@intel.com Date: Thu, 16 Jul 2020 08:23:18 +0000 Message-Id: <1594887800-6563-16-git-send-email-viacheslavo@mellanox.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1594887800-6563-1-git-send-email-viacheslavo@mellanox.com> References: <1591771085-24959-1-git-send-email-viacheslavo@mellanox.com> <1594887800-6563-1-git-send-email-viacheslavo@mellanox.com> Subject: [dpdk-dev] [PATCH v3 15/17] net/mlx5: provide the send scheduling error statistics X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" The mlx5 PMD exposes the following new introduced extended statistics counter to report the errors of packet send scheduling on timestamps: - txpp_err_miss_int - rearm queue interrupt was not handled was not handled in time and service routine might miss the completions - txpp_err_rearm_queue - reports errors in rearm queue - txpp_err_clock_queue - reports errors in clock queue - txpp_err_ts_past - timestamps in the packet being sent were found in the past, timestamps were ignored - txpp_err_ts_future - timestamps in the packet being sent were found in the too distant future (beyond HW/clock queue capabilities to schedule, typically it is about 16M of tx_pp devarg periods) - txpp_jitter - estimated jitter in device clocks between 8K completions of Clock Queue. - txpp_wander - estimated wander in device clocks between 16M completions of Clock Queue. - txpp_sync_lost - error flag, the Clock Queue completions synchronization is lost, accurate packet scheduling can not be handled, timestamps are being ignored, the restart of all ports using scheduling must be performed. Signed-off-by: Viacheslav Ovsiienko Acked-by: Matan Azrad --- drivers/net/mlx5/mlx5.h | 7 ++ drivers/net/mlx5/mlx5_stats.c | 7 +- drivers/net/mlx5/mlx5_txpp.c | 220 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+), 2 deletions(-) diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 15e35e8..6e4f055 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -1011,6 +1011,13 @@ void mlx5_os_set_reg_mr_cb(mlx5_reg_mr_t *reg_mr_cb, int mlx5_txpp_start(struct rte_eth_dev *dev); void mlx5_txpp_stop(struct rte_eth_dev *dev); int mlx5_txpp_read_clock(struct rte_eth_dev *dev, uint64_t *timestamp); +int mlx5_txpp_xstats_get(struct rte_eth_dev *dev, + struct rte_eth_xstat *stats, + unsigned int n, unsigned int n_used); +int mlx5_txpp_xstats_reset(struct rte_eth_dev *dev); +int mlx5_txpp_xstats_get_names(struct rte_eth_dev *dev, + struct rte_eth_xstat_name *xstats_names, + unsigned int n, unsigned int n_used); void mlx5_txpp_interrupt_handler(void *cb_arg); #endif /* RTE_PMD_MLX5_H_ */ diff --git a/drivers/net/mlx5/mlx5_stats.c b/drivers/net/mlx5/mlx5_stats.c index a9b33ee..e30542e 100644 --- a/drivers/net/mlx5/mlx5_stats.c +++ b/drivers/net/mlx5/mlx5_stats.c @@ -75,6 +75,7 @@ } } } + mlx5_stats_n = mlx5_txpp_xstats_get(dev, stats, n, mlx5_stats_n); return mlx5_stats_n; } @@ -237,7 +238,7 @@ xstats_ctrl->base[i] = counters[i]; xstats_ctrl->hw_stats[i] = 0; } - + mlx5_txpp_xstats_reset(dev); return 0; } @@ -255,7 +256,7 @@ * Number of xstats names. */ int -mlx5_xstats_get_names(struct rte_eth_dev *dev __rte_unused, +mlx5_xstats_get_names(struct rte_eth_dev *dev, struct rte_eth_xstat_name *xstats_names, unsigned int n) { unsigned int i; @@ -271,5 +272,7 @@ xstats_names[i].name[RTE_ETH_XSTATS_NAME_SIZE - 1] = 0; } } + mlx5_xstats_n = mlx5_txpp_xstats_get_names(dev, xstats_names, + n, mlx5_xstats_n); return mlx5_xstats_n; } diff --git a/drivers/net/mlx5/mlx5_txpp.c b/drivers/net/mlx5/mlx5_txpp.c index 3a592d9..15c9a8e 100644 --- a/drivers/net/mlx5/mlx5_txpp.c +++ b/drivers/net/mlx5/mlx5_txpp.c @@ -15,6 +15,17 @@ #include "mlx5_rxtx.h" #include "mlx5_common_os.h" +static const char * const mlx5_txpp_stat_names[] = { + "txpp_err_miss_int", /* Missed service interrupt. */ + "txpp_err_rearm_queue", /* Rearm Queue errors. */ + "txpp_err_clock_queue", /* Clock Queue errors. */ + "txpp_err_ts_past", /* Timestamp in the past. */ + "txpp_err_ts_future", /* Timestamp in the distant future. */ + "txpp_jitter", /* Timestamp jitter (one Clock Queue completion). */ + "txpp_wander", /* Timestamp jitter (half of Clock Queue completions). */ + "txpp_sync_lost", /* Scheduling synchronization lost. */ +}; + /* Destroy Event Queue Notification Channel. */ static void mlx5_txpp_destroy_eqn(struct mlx5_dev_ctx_shared *sh) @@ -1113,3 +1124,212 @@ ret = mlx5_read_clock(dev, timestamp); return ret; } + +/** + * DPDK callback to clear device extended statistics. + * + * @param dev + * Pointer to Ethernet device structure. + * + * @return + * 0 on success and stats is reset, negative errno value otherwise and + * rte_errno is set. + */ +int mlx5_txpp_xstats_reset(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_dev_ctx_shared *sh = priv->sh; + + rte_atomic32_set(&sh->txpp.err_miss_int, 0); + rte_atomic32_set(&sh->txpp.err_rearm_queue, 0); + rte_atomic32_set(&sh->txpp.err_clock_queue, 0); + rte_atomic32_set(&sh->txpp.err_ts_past, 0); + rte_atomic32_set(&sh->txpp.err_ts_future, 0); + return 0; +} + +/** + * Routine to retrieve names of extended device statistics + * for packet send scheduling. It appends the specific stats names + * after the parts filled by preceding modules (eth stats, etc.) + * + * @param dev + * Pointer to Ethernet device structure. + * @param[out] xstats_names + * Buffer to insert names into. + * @param n + * Number of names. + * @param n_used + * Number of names filled by preceding statistics modules. + * + * @return + * Number of xstats names. + */ +int mlx5_txpp_xstats_get_names(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_xstat_name *xstats_names, + unsigned int n, unsigned int n_used) +{ + unsigned int n_txpp = RTE_DIM(mlx5_txpp_stat_names); + unsigned int i; + + if (n >= n_used + n_txpp && xstats_names) { + for (i = 0; i < n_txpp; ++i) { + strncpy(xstats_names[i + n_used].name, + mlx5_txpp_stat_names[i], + RTE_ETH_XSTATS_NAME_SIZE); + xstats_names[i + n_used].name + [RTE_ETH_XSTATS_NAME_SIZE - 1] = 0; + } + } + return n_used + n_txpp; +} + +static inline void +mlx5_txpp_read_tsa(struct mlx5_dev_txpp *txpp, + struct mlx5_txpp_ts *tsa, uint16_t idx) +{ + do { + int64_t ts, ci; + + ts = rte_atomic64_read(&txpp->tsa[idx].ts); + ci = rte_atomic64_read(&txpp->tsa[idx].ci_ts); + rte_compiler_barrier(); + if ((ci ^ ts) << MLX5_CQ_INDEX_WIDTH != 0) + continue; + if (rte_atomic64_read(&txpp->tsa[idx].ts) != ts) + continue; + if (rte_atomic64_read(&txpp->tsa[idx].ci_ts) != ci) + continue; + rte_atomic64_set(&tsa->ts, ts); + rte_atomic64_set(&tsa->ci_ts, ci); + return; + } while (true); +} + +/* + * Jitter reflects the clock change between + * neighbours Clock Queue completions. + */ +static uint64_t +mlx5_txpp_xstats_jitter(struct mlx5_dev_txpp *txpp) +{ + struct mlx5_txpp_ts tsa0, tsa1; + int64_t dts, dci; + uint16_t ts_p; + + if (txpp->ts_n < 2) { + /* No gathered enough reports yet. */ + return 0; + } + do { + int ts_0, ts_1; + + ts_p = txpp->ts_p; + rte_compiler_barrier(); + ts_0 = ts_p - 2; + if (ts_0 < 0) + ts_0 += MLX5_TXPP_REARM_SQ_SIZE; + ts_1 = ts_p - 1; + if (ts_1 < 0) + ts_1 += MLX5_TXPP_REARM_SQ_SIZE; + mlx5_txpp_read_tsa(txpp, &tsa0, ts_0); + mlx5_txpp_read_tsa(txpp, &tsa1, ts_1); + rte_compiler_barrier(); + } while (ts_p != txpp->ts_p); + /* We have two neighbor reports, calculate the jitter. */ + dts = rte_atomic64_read(&tsa1.ts) - rte_atomic64_read(&tsa0.ts); + dci = (rte_atomic64_read(&tsa1.ci_ts) >> (64 - MLX5_CQ_INDEX_WIDTH)) - + (rte_atomic64_read(&tsa0.ci_ts) >> (64 - MLX5_CQ_INDEX_WIDTH)); + if (dci < 0) + dci += 1 << MLX5_CQ_INDEX_WIDTH; + dci *= txpp->tick; + return (dts > dci) ? dts - dci : dci - dts; +} + +/* + * Wander reflects the long-term clock change + * over the entire length of all Clock Queue completions. + */ +static uint64_t +mlx5_txpp_xstats_wander(struct mlx5_dev_txpp *txpp) +{ + struct mlx5_txpp_ts tsa0, tsa1; + int64_t dts, dci; + uint16_t ts_p; + + if (txpp->ts_n < MLX5_TXPP_REARM_SQ_SIZE) { + /* No gathered enough reports yet. */ + return 0; + } + do { + int ts_0, ts_1; + + ts_p = txpp->ts_p; + rte_compiler_barrier(); + ts_0 = ts_p - MLX5_TXPP_REARM_SQ_SIZE / 2 - 1; + if (ts_0 < 0) + ts_0 += MLX5_TXPP_REARM_SQ_SIZE; + ts_1 = ts_p - 1; + if (ts_1 < 0) + ts_1 += MLX5_TXPP_REARM_SQ_SIZE; + mlx5_txpp_read_tsa(txpp, &tsa0, ts_0); + mlx5_txpp_read_tsa(txpp, &tsa1, ts_1); + rte_compiler_barrier(); + } while (ts_p != txpp->ts_p); + /* We have two neighbor reports, calculate the jitter. */ + dts = rte_atomic64_read(&tsa1.ts) - rte_atomic64_read(&tsa0.ts); + dci = (rte_atomic64_read(&tsa1.ci_ts) >> (64 - MLX5_CQ_INDEX_WIDTH)) - + (rte_atomic64_read(&tsa0.ci_ts) >> (64 - MLX5_CQ_INDEX_WIDTH)); + dci += 1 << MLX5_CQ_INDEX_WIDTH; + dci *= txpp->tick; + return (dts > dci) ? dts - dci : dci - dts; +} + +/** + * Routine to retrieve extended device statistics + * for packet send scheduling. It appends the specific statistics + * after the parts filled by preceding modules (eth stats, etc.) + * + * @param dev + * Pointer to Ethernet device. + * @param[out] stats + * Pointer to rte extended stats table. + * @param n + * The size of the stats table. + * @param n_used + * Number of stats filled by preceding statistics modules. + * + * @return + * Number of extended stats on success and stats is filled, + * negative on error and rte_errno is set. + */ +int +mlx5_txpp_xstats_get(struct rte_eth_dev *dev, + struct rte_eth_xstat *stats, + unsigned int n, unsigned int n_used) +{ + unsigned int n_txpp = RTE_DIM(mlx5_txpp_stat_names); + + if (n >= n_used + n_txpp && stats) { + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_dev_ctx_shared *sh = priv->sh; + unsigned int i; + + for (i = 0; i < n_txpp; ++i) + stats[n_used + i].id = n_used + i; + stats[n_used + 0].value = + rte_atomic32_read(&sh->txpp.err_miss_int); + stats[n_used + 1].value = + rte_atomic32_read(&sh->txpp.err_rearm_queue); + stats[n_used + 2].value = + rte_atomic32_read(&sh->txpp.err_clock_queue); + stats[n_used + 3].value = + rte_atomic32_read(&sh->txpp.err_ts_past); + stats[n_used + 4].value = + rte_atomic32_read(&sh->txpp.err_ts_future); + stats[n_used + 5].value = mlx5_txpp_xstats_jitter(&sh->txpp); + stats[n_used + 6].value = mlx5_txpp_xstats_wander(&sh->txpp); + stats[n_used + 7].value = sh->txpp.sync_lost; + } + return n_used + n_txpp; +}