From 3b025c0ca425a634b7eead08420fa5a5cfaa1445 Mon Sep 17 00:00:00 2001 From: Viacheslav Ovsiienko Date: Thu, 16 Jul 2020 08:23:18 +0000 Subject: [PATCH] net/mlx5: provide send scheduling error statistics 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 15e35e8ac2..6e4f0552c6 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 a9b33ee77e..e30542e984 100644 --- a/drivers/net/mlx5/mlx5_stats.c +++ b/drivers/net/mlx5/mlx5_stats.c @@ -75,6 +75,7 @@ mlx5_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats, } } } + mlx5_stats_n = mlx5_txpp_xstats_get(dev, stats, n, mlx5_stats_n); return mlx5_stats_n; } @@ -237,7 +238,7 @@ mlx5_xstats_reset(struct rte_eth_dev *dev) xstats_ctrl->base[i] = counters[i]; xstats_ctrl->hw_stats[i] = 0; } - + mlx5_txpp_xstats_reset(dev); return 0; } @@ -255,7 +256,7 @@ mlx5_xstats_reset(struct rte_eth_dev *dev) * 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 @@ mlx5_xstats_get_names(struct rte_eth_dev *dev __rte_unused, 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 ee19071bfb..cdb00792d0 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 @@ mlx5_txpp_read_clock(struct rte_eth_dev *dev, uint64_t *timestamp) 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; +} -- 2.20.1