Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
65b8b97
UCT/IB/MLX5: Purge outstanding AM short operations
roiedanino Aug 30, 2026
2e3e70d
UCT/IB/MLX5: Refine AM short outstanding purge
roiedanino Sep 1, 2026
1a39e5f
UCT/IB/MLX5: Localize purge PSN helper
roiedanino Sep 1, 2026
337510a
UCT/IB/MLX5: Complete AM short purge cleanup
roiedanino Sep 2, 2026
369e583
UCT/IB/MLX5: Fix AM short purge validation and test
roiedanino Sep 2, 2026
751da50
UCT/IB/MLX5: Remove redundant DEVX test check
roiedanino Sep 3, 2026
30c4fa2
UCT/IB/MLX5: Refine outstanding purge packet tracking
roiedanino Sep 3, 2026
485eb51
GTEST/UCT/IB: Defer AM short purge test
roiedanino Sep 7, 2026
f9a2484
UCT/IB/MLX5: Explain circular PSN comparison
roiedanino Sep 8, 2026
e9f208d
GTEST/UCT: Test outstanding AM short purge
roiedanino Sep 9, 2026
81c63d1
UCT/IB/MLX5: Report outstanding flush operations during purge
roiedanino Sep 9, 2026
981d6ad
UCT/IB/MLX5: Keep purge invariant checks always enabled
roiedanino Sep 9, 2026
23e6ddc
GTEST/UCT: Pass operation data through purge context
roiedanino Sep 9, 2026
c72dbd0
UCT/IB/MLX5: Simplify AM short outstanding purge
roiedanino Sep 9, 2026
3f6c0a5
GTEST/UCT: Simplify outstanding purge test posting
roiedanino Sep 10, 2026
b76e1d6
UCT/IB/MLX5: Advertise native token query support
roiedanino Sep 10, 2026
a44bce3
UCT/IB/MLX5: Simplify purge validation and diagnostics
roiedanino Sep 10, 2026
26af207
UCT/IB/MLX5: Reject non-inline AM purge layouts
roiedanino Sep 10, 2026
aec2bcb
UCT/IB/MLX5: Advance outstanding purge boundary
roiedanino Sep 10, 2026
c5ed002
UCT/IB/MLX5: Reuse WQE dump for unsupported purge operations
roiedanino Sep 14, 2026
bd56d22
UCT/IB/MLX5: Fix WQE dump alignment and DS byte order
roiedanino Sep 14, 2026
10bd703
UCT/IB/MLX5: Declare initialized WQE dump variables first
roiedanino Sep 15, 2026
c2942cd
UCT/IB/MLX5: Share inline segment decoding in purge
roiedanino Sep 15, 2026
75fc3a4
UCT/IB/MLX5: Complete flushes in WQE purge order
roiedanino Sep 15, 2026
d54595f
UCT/IB/MLX5: Invoke only flush completions during purge
roiedanino Sep 15, 2026
1f518a0
UCT/IB/MLX5: Simplify outstanding purge loop
roiedanino Sep 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/uct/ib/mlx5/ib_mlx5.c
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,23 @@ void *uct_ib_mlx5_txwq_get_wqe(const uct_ib_mlx5_txwq_t *txwq, uint16_t pi)
return UCS_PTR_BYTE_OFFSET(txwq->qstart, (pi % num_bb) * MLX5_SEND_WQE_BB);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Asymmetric endianness handling between the two new helpers is worth a one-line note. uct_ib_mlx5_wqe_size() correctly reads ds via ntohl(ctrl->qpn_ds) & UINT8_MAX (fixing the big-endian bug in the old >> 24), but uct_ib_mlx5_wqe_opcode() deliberately keeps ctrl->opmod_idx_opcode >> 24. This is correct because opmod_idx_opcode is built with host-order shifts rather than a plain htonl, so the opcode is only in the top byte on little-endian. The asymmetry looks like an oversight but is intentional — worth a short comment noting the opcode field is written in host order (unlike qpn_ds), so the raw shift is intended and not a missed BE fix. Optional.

}

size_t uct_ib_mlx5_wqe_size(const struct mlx5_wqe_ctrl_seg *ctrl)
{
uint8_t ds = ntohl(ctrl->qpn_ds) & UINT8_MAX;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old num_posted_wqes used (ctrl->qpn_ds >> 24), which extracts ds only on little-endian; the new ntohl(ctrl->qpn_ds) & UINT8_MAX is correct on both endiannesses. This is effectively a big-endian bug fix and should be called out.


ucs_assertv_always(
(ds > 0) &&
((ds * UCT_IB_MLX5_WQE_SEG_SIZE) <=
UCT_IB_MLX5_MAX_SEND_WQE_SIZE),
"ds=%u", ds);
return ds * UCT_IB_MLX5_WQE_SEG_SIZE;
}

uint16_t uct_ib_mlx5_txwq_next_wqe_index(uint16_t index, size_t wqe_size)
{
return index + ucs_div_round_up(wqe_size, MLX5_SEND_WQE_BB);
}

uint16_t uct_ib_mlx5_txwq_num_posted_wqes(const uct_ib_mlx5_txwq_t *txwq,
uint16_t outstanding)
{
Expand All @@ -873,8 +890,8 @@ uint16_t uct_ib_mlx5_txwq_num_posted_wqes(const uct_ib_mlx5_txwq_t *txwq,
ucs_assert(pi == txwq->hw_ci);
do {
ctrl = uct_ib_mlx5_txwq_get_wqe(txwq, pi);
wqe_size = (ctrl->qpn_ds >> 24) * UCT_IB_MLX5_WQE_SEG_SIZE;
pi += (wqe_size + MLX5_SEND_WQE_BB - 1) / MLX5_SEND_WQE_BB;
wqe_size = uct_ib_mlx5_wqe_size(ctrl);
pi = uct_ib_mlx5_txwq_next_wqe_index(pi, wqe_size);
++count;
} while (pi != txwq->sw_pi);

Expand Down
10 changes: 9 additions & 1 deletion src/uct/ib/mlx5/ib_mlx5.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
#define UCT_IB_MLX5_CQ_SET_CI 0
#define UCT_IB_MLX5_CQ_ARM_DB 1
#define UCT_IB_MLX5_LOG_MAX_MSG_SIZE 30
#define UCT_IB_MLX5_PSN_BITS 24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO UCT_IB_MLX5_PSN_ORDER fits better here — UCT_IB_QPN_ORDER is the existing name for "how many bits" in ib_device.h.

#define UCT_IB_MLX5_PSN_MASK UCS_MASK(UCT_IB_MLX5_PSN_BITS)
#define UCT_IB_MLX5_ATOMIC_MODE_COMP 1
#define UCT_IB_MLX5_ATOMIC_MODE_EXT 3
#define UCT_IB_MLX5_CQE_FLAG_L3_IN_DATA UCS_BIT(28) /* GRH/IP in the receive buffer */
Expand Down Expand Up @@ -709,7 +711,7 @@ typedef struct uct_ib_mlx5_txwq {
static UCS_F_ALWAYS_INLINE uint32_t
uct_ib_mlx5_txwq_get_next_wqe_psn(const uct_ib_mlx5_txwq_t *txwq)
{
return txwq->next_wqe_psn & UCS_MASK(24);
return txwq->next_wqe_psn & UCT_IB_MLX5_PSN_MASK;
}


Expand Down Expand Up @@ -917,6 +919,12 @@ ucs_status_t uct_ib_mlx5_txwq_init(uct_priv_worker_t *worker,
/* Get pointer to a WQE by producer index */
void *uct_ib_mlx5_txwq_get_wqe(const uct_ib_mlx5_txwq_t *txwq, uint16_t pi);

/* Get the WQE size in bytes from its control segment */
size_t uct_ib_mlx5_wqe_size(const struct mlx5_wqe_ctrl_seg *ctrl);
Comment thread
roiedanino marked this conversation as resolved.
Resolved

/* Get the index of the WQE that follows a WQE of the given size */
uint16_t uct_ib_mlx5_txwq_next_wqe_index(uint16_t index, size_t wqe_size);

/* Count how many WQEs are currently posted */
uint16_t uct_ib_mlx5_txwq_num_posted_wqes(const uct_ib_mlx5_txwq_t *txwq,
uint16_t outstanding);
Expand Down
55 changes: 1 addition & 54 deletions src/uct/ib/mlx5/ib_mlx5_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,55 +111,6 @@ uct_ib_mlx5_ext_ep_put_sgl_zcopy(uct_ep_h ep, void * const *buffers,
return UCS_ERR_UNSUPPORTED;
}

static ucs_status_t uct_ib_mlx5_ext_ep_outstanding_purge_check_param(
const uct_ep_outstanding_purge_params_t *params)
{
if (params == NULL) {
ucs_error("ib mlx5 ext: outstanding purge parameters are NULL");
return UCS_ERR_INVALID_PARAM;
}

if (!(params->field_mask & UCT_EP_OUTSTANDING_FIELD_RX_TOKEN) ||
!(params->field_mask & UCT_EP_OUTSTANDING_FIELD_CB) ||
(params->rx_token == NULL) || (params->cb == NULL)) {
ucs_error("ib mlx5 ext: rx token or callback is not set or is NULL");
return UCS_ERR_INVALID_PARAM;
}

return UCS_OK;
}

ucs_status_t uct_ib_mlx5_ext_ep_outstanding_purge(
uct_ep_h ep, const uct_ep_outstanding_purge_params_t *params)
{
ucs_status_t status;
uct_ib_mlx5_ext_plugin_t *plugin;

status = uct_ib_mlx5_ext_ep_outstanding_purge_check_param(params);
if (status != UCS_OK) {
return status;
}

ucs_list_for_each(plugin, &uct_ib_mlx5_ext_plugins, list) {
if (ucs_unlikely(uct_ib_mlx5_ext_is_unsupported_op(
(const void*)plugin->ops.ep_outstanding_purge))) {
continue;
}

/* The provider validates parameters and token signatures itself, and
* returns an error if it should not handle this request. */
status = plugin->ops.ep_outstanding_purge(ep, params);
if (status != UCS_OK) {
continue;
}

return UCS_OK;
}

ucs_error("ib mlx5 ext: ep outstanding purge is not supported");
return UCS_ERR_UNSUPPORTED;
}

void uct_ib_mlx5_ext_cleanup(void)
{
uct_ib_mlx5_ext_plugin_t *plugin, *tmp;
Expand Down Expand Up @@ -211,7 +162,7 @@ ucs_status_t uct_ib_mlx5_ext_register(const uct_ib_mlx5_ext_ops_t *ops)
num_plugins = ucs_list_length(&uct_ib_mlx5_ext_plugins);

ucs_debug("ib mlx5 ext: registered plugin name=%s iface_query=%s "
"put_sgl_zcopy=%s outstanding_purge=%s (total=%u)",
"put_sgl_zcopy=%s (total=%u)",
plugin->ops.name,
uct_ib_mlx5_ext_is_unsupported_op(
(const void*)plugin->ops.iface_query) ?
Expand All @@ -221,10 +172,6 @@ ucs_status_t uct_ib_mlx5_ext_register(const uct_ib_mlx5_ext_ops_t *ops)
(const void*)plugin->ops.ep_put_sgl_zcopy) ?
"unsupported" :
"supported",
uct_ib_mlx5_ext_is_unsupported_op(
(const void*)plugin->ops.ep_outstanding_purge) ?
"unsupported" :
"supported",
num_plugins);
return UCS_OK;
}
4 changes: 0 additions & 4 deletions src/uct/ib/mlx5/ib_mlx5_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ typedef struct uct_ib_mlx5_ext_ops {
uct_ib_mlx5_ext_iface_query_func_t iface_query; /**< Iface query callback */
uct_ib_mlx5_ext_max_put_sgl_zcopy_count_func_t max_put_sgl_zcopy_count; /**< Maximum PUT SGL zero-copy entry count callback */
uct_ep_put_sgl_zcopy_func_t ep_put_sgl_zcopy; /**< PUT SGL zero-copy callback */
uct_ep_outstanding_purge_func_t ep_outstanding_purge; /**< Outstanding operation purge callback */
} uct_ib_mlx5_ext_ops_t;

/**
Expand Down Expand Up @@ -118,9 +117,6 @@ ucs_status_t uct_ib_mlx5_ext_ep_put_sgl_zcopy(uct_ep_h ep,
size_t count,
uct_completion_t *comp);

ucs_status_t uct_ib_mlx5_ext_ep_outstanding_purge(
uct_ep_h ep, const uct_ep_outstanding_purge_params_t *params);

END_C_DECLS

#endif /* UCT_IB_MLX5_EXT_H_ */
31 changes: 17 additions & 14 deletions src/uct/ib/mlx5/ib_mlx5_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
#include <string.h>


static void uct_ib_mlx5_wqe_dump(uct_ib_iface_t *iface, void *wqe, void *qstart,
void *qend, int max_sge, int dump_qp,
uct_log_data_dump_func_t packet_dump_cb,
char *buffer, size_t max, uct_ib_log_sge_t *log_sge);

static void uct_ib_mlx5_resp_error_dump(const uct_ib_mlx5_srq_seg_t *seg,
unsigned max_strides, char *buffer,
size_t max);
Expand Down Expand Up @@ -281,10 +276,10 @@ static size_t uct_ib_mlx5_dump_dgram(char *buf, size_t max, void *seg, int is_et
UCT_IB_MLX5_AV_FULL_SIZE : UCT_IB_MLX5_AV_BASE_SIZE;
}

static void uct_ib_mlx5_wqe_dump(uct_ib_iface_t *iface, void *wqe, void *qstart,
void *qend, int max_sge, int dump_qp,
uct_log_data_dump_func_t packet_dump_cb,
char *buffer, size_t max, uct_ib_log_sge_t *log_sge)
void uct_ib_mlx5_wqe_dump(uct_ib_iface_t *iface, void *wqe, void *qstart,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: pls re-align the argument list after dropping static; docs/CodeStyle.md requires function arguments indented on column.

Suggested change
void uct_ib_mlx5_wqe_dump(uct_ib_iface_t *iface, void *wqe, void *qstart,
void uct_ib_mlx5_wqe_dump(uct_ib_iface_t *iface, void *wqe, void *qstart,
void *qend, int max_sge, int dump_qp,
uct_log_data_dump_func_t packet_dump_cb,
char *buffer, size_t max, uct_ib_log_sge_t *log_sge)

void *qend, int max_sge, int dump_qp,
uct_log_data_dump_func_t packet_dump_cb,
char *buffer, size_t max, uct_ib_log_sge_t *log_sge)
{
static uct_ib_opcode_t opcodes[] = {
[MLX5_OPCODE_NOP] = { "NOP", 0 },
Expand All @@ -308,18 +303,26 @@ static void uct_ib_mlx5_wqe_dump(uct_ib_iface_t *iface, void *wqe, void *qstart,
uint8_t opcode = ctrl->opmod_idx_opcode >> 24;
uint8_t opmod = ctrl->opmod_idx_opcode & 0xff;
uint32_t qp_num = ntohl(ctrl->qpn_ds) >> 8;
int ds = ctrl->qpn_ds >> 24;
uct_ib_opcode_t *op = &opcodes[opcode];
int ds = ntohl(ctrl->qpn_ds) & UINT8_MAX;
char *s = buffer;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still present (belongs on the existing thread): this still uses the LE-only ctrl->qpn_ds >> 24 rather than the new uct_ib_mlx5_wqe_size() helper.

char *ends = buffer + max;
const char* sg_prefix_arr = (op->flags & UCT_IB_OPCODE_FLAG_HAS_DMA) ?
"GS" : NULL;
uct_ib_opcode_t *op;
const char *sg_prefix_arr;
struct ibv_sge sg_list[16];
uint64_t inline_bitmap;
int i, is_inline, is_eth;
size_t dg_size;
void *seg;

if ((opcode >= ucs_static_array_size(opcodes)) ||
(opcodes[opcode].name == NULL)) {
snprintf(buffer, max, "unknown opcode 0x%x", opcode);
return;
}

op = &opcodes[opcode];
sg_prefix_arr = (op->flags & UCT_IB_OPCODE_FLAG_HAS_DMA) ? "GS" : NULL;

/* QP and WQE index */
if (dump_qp) {
snprintf(s, ends - s, "QP 0x%x [%03ld] ", qp_num,
Expand Down Expand Up @@ -387,8 +390,8 @@ static void uct_ib_mlx5_wqe_dump(uct_ib_iface_t *iface, void *wqe, void *qstart,

/* Extended atomic segment */
if (op->flags & UCT_IB_OPCODE_FLAG_HAS_EXT_ATOMIC) {
uint64_t add, boundary, compare, swap, compare_mask, swap_mask;
int size = 1 << ((opmod & 7) + 2);
uint64_t add, boundary, compare, swap, compare_mask, swap_mask;

if (opcode == MLX5_OPCODE_ATOMIC_MASKED_FA) {
add = network_to_host(seg, size);
Expand Down
6 changes: 6 additions & 0 deletions src/uct/ib/mlx5/ib_mlx5_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ ucs_status_t uct_ib_mlx5_completion_with_err(uct_ib_iface_t *iface,
ucs_log_level_t log_level);


void uct_ib_mlx5_wqe_dump(uct_ib_iface_t *iface, void *wqe, void *qstart,
void *qend, int max_sge, int dump_qp,
uct_log_data_dump_func_t packet_dump_cb,
char *buffer, size_t max, uct_ib_log_sge_t *log_sge);


void __uct_ib_mlx5_log_tx(const char *file, int line, const char *function,
uct_ib_iface_t *iface, void *wqe, void *qstart,
void *qend, int max_sge, uct_ib_log_sge_t *log_sge,
Expand Down
3 changes: 3 additions & 0 deletions src/uct/ib/mlx5/rc/rc_mlx5.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ ucs_status_t
uct_rc_mlx5_base_ep_invalidate(uct_ep_h tl_ep,
const uct_ep_invalidate_params_t *params);

ucs_status_t uct_rc_mlx5_ep_outstanding_purge(
uct_ep_h tl_ep, const uct_ep_outstanding_purge_params_t *params);

ucs_status_t uct_rc_mlx5_base_ep_fc_ctrl(uct_ep_t *tl_ep, unsigned op,
uct_rc_pending_req_t *req);

Expand Down
Loading