Skip to content

[DNM] UCT/IB/MLX5: wqe parser for uct put - #11836

Open
jeynmann wants to merge 11 commits into
openucx:masterfrom
jeynmann:failover_uct_rcx_put
Open

[DNM] UCT/IB/MLX5: wqe parser for uct put#11836
jeynmann wants to merge 11 commits into
openucx:masterfrom
jeynmann:failover_uct_rcx_put

Conversation

@jeynmann

Copy link
Copy Markdown
Contributor

What?

Add wqe parse support for uct put.

Why?

FT need extract info from wqe before replay uct put.

How?

Add parser for uct put short/bcopy/zcopy.

@svc-ucx

svc-ucx commented Aug 26, 2026

Copy link
Copy Markdown

🤖 CI Triage AgentUCX PR · commit 026c3c2a

TL;DR: The Basic compile stage failed with -Werror=incompatible-pointer-types / "too many arguments" because the cleanup commit 026c3c2a changed uct_rc_mlx5_op_info_fill_put_short() to take a uct_rc_mlx5_op_callback_data_t* but left the call site passing the old (callback_data->data, sizeof(callback_data->data)) pair; fix the call site to pass callback_data.

Full analysis

Summary: Build of src/uct/ib/mlx5/rc/rc_mlx5_common.c failed (make[5]: *** [Makefile:939: rc/libuct_ib_mlx5_la-rc_mlx5_common.lo] Error 1) during the "Basic compile" stage.

Root cause: Incomplete refactor in the PR branch. The helper was refactored to a 5-parameter form:

110: static void uct_rc_mlx5_op_info_fill_put_short(
111:         uct_ep_op_info_t *info, const uct_ib_mlx5_txwq_t *txwq,
112:         const struct mlx5_wqe_inl_data_seg *inl,
113:         const struct mlx5_wqe_raddr_seg *raddr,
114:         uct_rc_mlx5_op_callback_data_t *callback_data)

but the only caller inside uct_rc_mlx5_op_info_fill_put() still uses the pre-refactor 6-argument buffer+size convention:

193:         uct_rc_mlx5_op_info_fill_put_short(info, txwq, inl, raddr,
194:                                            callback_data->data,
195:                                            sizeof(callback_data->data));

GCC reports two errors on this: argument 5 is uint8_t * where uct_rc_mlx5_op_callback_data_t * is expected, and "too many arguments to function". Since UCX builds with -Wall -Werror, this aborts the build. This is a pure compile-time inconsistency, not an environment or flaky-test issue.

Implicated commit: [REDACTED:Hex High Entropy String] — "UCT/IB/MLX5: cleanup", Zihao Zhao (follow-up to 95f69187 "UCT/IB/MLX5: Parse PUT WQEs for outstanding purge", same author)

File: src/uct/ib/mlx5/rc/rc_mlx5_common.c:193-195 (declaration at src/uct/ib/mlx5/rc/rc_mlx5_common.c:110-114)

Suggested fix: Update the call site to match the new signature — pass the struct pointer and drop the redundant size argument, since the callee already derives the bound via sizeof(callback_data->data) at line 118:

    if (inl->byte_count & htonl(MLX5_INLINE_SEG)) {
        uct_rc_mlx5_op_info_fill_put_short(info, txwq, inl, raddr,
                                           callback_data);
        return UCS_OK;
    }

Then rebuild locally with the same flags the CI uses (-Wall -Werror, -O0 -g) before re-pushing, and grep for any other callers of uct_rc_mlx5_op_info_fill_put_short that may still use the old convention. Consider squashing the "cleanup" commit into 95f69187 so no intermediate commit in the branch is non-compiling.

Related: PR #11836 (branch failover_uct_rcx_put) — this is the PR under test; no pre-existing issue matches this signature.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 6aff8dff-8b7c-4106-99ee-ed8206422540 in the triage console for the audit trail.

@jeynmann
jeynmann force-pushed the failover_uct_rcx_put branch from 026c3c2 to 535cec7 Compare August 27, 2026 08:02
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5_common.c Outdated
int *skip_p,
uct_rc_mlx5_op_callback_data_t *callback_data)
{
*skip_p = 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

uct_rc_mlx5_op_info_fill: *skip_p = 0 is written unconditionally and never set to 1 anywhere in the function or its callees. The skip_p output parameter has no effect in-tree. Why do we need skip_p? It is always set to 0 and never to 1 in this PR.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5_common.c Outdated
#include <uct/ib/rc/base/rc_iface.h>
#include <ucs/arch/bitops.h>
#include <ucs/profile/profile.h>
#include <endian.h>

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: <endian.h> and <string.h> are already pulled in transitively via ib_mlx5.h (through rc_mlx5.inl). The explicit includes are redundant.

Comment thread src/uct/ib/mlx5/ib_mlx5.c

inl = uct_ib_mlx5_txwq_wrap_any((uct_ib_mlx5_txwq_t*)txwq,
(void*)(raddr + 1));
if (inl->byte_count & htonl(MLX5_INLINE_SEG)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

uct_rc_mlx5_op_info_fill_put: A keepalive/flush-check posts MLX5_OPCODE_RDMA_WRITE with a 0-length inline seg and remote_addr=0 (uct_rc_mlx5_base_ep_post_check); it will be reported to the purge callback as UCT_EP_OP_PUT_SHORT with remote_addr=0. This is an edge case a purge consumer could observe though it is not a real user PUT; worth confirming the purge consumer tolerates this synthetic PUT.

@svc-nvidia-pr-review

Copy link
Copy Markdown

Test coverage: the gtest exercises PUT_SHORT / PUT_BCOPY / PUT_ZCOPY reconstruction only when an ext plugin is registered that returns success — otherwise it skips. In upstream CI (no plugin) these three cases are effectively no-ops, so the parsing helpers are not exercised by CI. Worth noting to the author, though may be acceptable given the consumer is out-of-tree.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5_common.c Outdated
uct_rc_mlx5_op_info_fill(uct_ep_op_info_t *info, const uct_ib_mlx5_txwq_t *txwq,
uct_rc_iface_send_op_t *op,
const struct mlx5_wqe_ctrl_seg *ctrl, size_t wqe_size,
int *skip_p,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

skip_p is passed here but never written by this function or its callees. Is the skip path unfinished? If it's meant as an out-param the caller will read uninitialized data; if unused, pls drop it.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5_common.c Outdated
{
size_t iovcnt;

ucs_assert(seg_size >= 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ucs_assert(seg_size >= 0) is always true because seg_size is size_t (unsigned). The assert checks nothing; if the intent is to guard the == 0 path this can just be removed.

Comment thread src/uct/ib/mlx5/ib_mlx5.c
void uct_ib_mlx5_txwq_copy_segs(const uct_ib_mlx5_txwq_t *txwq, const void *src,
void *dst, size_t length)
{
size_t copy_len = ucs_min(length, UCS_PTR_BYTE_DIFF(src, txwq->qend));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mixed-sign ucs_min in uct_rc_mlx5_txwq_copy_segs: ucs_min(length /* size_t */, UCS_PTR_BYTE_DIFF(src, txwq->qend) /* ptrdiff_t */) mixes unsigned and signed. Callers pass src inside [qstart, qend) via txwq_wrap_any, so the diff is positive today, but the mixed-sign comparison is fragile. Consider casting the diff to size_t after the wrap invariant, or adding an assert that src < qend. Following the uct_ib_mlx5_inline_copy pattern (consistent ptrdiff_t n) would be more consistent.

@svc-nvidia-pr-review

Copy link
Copy Markdown

The three test_rc_purge_outstanding cases only exercise the new reconstruction paths when an out-of-tree ext plugin returns success; otherwise they GTEST_SKIP. In upstream CI (no plugin) uct_rc_mlx5_op_info_fill and its helpers are not covered. This is inherent to the out-of-tree consumer design and is acceptable, but the parsing helpers carry non-trivial pointer/wrap logic that will remain untested in-tree.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5_common.c Outdated
{
size_t iovcnt;

ucs_assert(seg_size >= 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Tautological assertion: ucs_assert(seg_size >= 0);seg_size is size_t (unsigned), so this comparison is always true and will likely produce compiler/linter warnings. Drop the assert; the seg_size == 0 case is already handled right below.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5_common.c Outdated
uct_rc_mlx5_op_info_fill(uct_ep_op_info_t *info, const uct_ib_mlx5_txwq_t *txwq,
uct_rc_iface_send_op_t *op,
const struct mlx5_wqe_ctrl_seg *ctrl, size_t wqe_size,
int *skip_p,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

skip_p output parameter is never written. uct_rc_mlx5_op_info_fill() takes int *skip_p but no path ever assigns *skip_p. The caller (and the gtest, which pre-sets skip = 0 then EXPECT_EQ(0, skip)) can't learn whether an op should be skipped. Either set *skip_p on the paths that need to skip (e.g. NOP/zero-length or unsupported cases), or remove the parameter. As-is it's a dead output that gives out-of-tree callers a false contract.

@jeynmann
jeynmann force-pushed the failover_uct_rcx_put branch from 6654193 to ab25169 Compare August 27, 2026 10:20
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5_common.c
Comment thread src/uct/ib/mlx5/rc/rc_mlx5_common.c Outdated

uct_rc_mlx5_op_info_fill_rma_raddr(info, raddr);

info->operation = is_dm ? UCT_EP_OP_PUT_SHORT : UCT_EP_OP_PUT_BCOPY;

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: DM put_bcopy reports UCT_EP_OP_PUT_SHORT with a device-memory buffer. In uct_rc_mlx5_op_info_fill_put_bcopy, when is_dm is true, info->rma.payload.data.buffer is set to op->buffer, which for a DM descriptor points into device memory (start_va + offset). A consumer doing a host-side read of payload.data.buffer inside the callback (as the gtest's non-zcopy path does with memcmp) would read device memory. Is a host-side read of payload.data.buffer by the consumer expected to work here?

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Review complete — no issues found.

@svc-ucx

svc-ucx commented Aug 27, 2026

Copy link
Copy Markdown

🤖 CI Triage AgentUCX PR (AddressSanitizer roce on worker 2) · commit 7827e4b6

TL;DR: The ASAN/RoCE gtest job failed on a single test out of 8616 — rc_mlx5/uct_atomic_key_reg_rdma_mem_type.fadd64/1 (device-memory/MEMIC atomic fetch-add on the RoCE port mlx5_1:1) — a test with a long history of MEMIC-allocation flakiness and no relation to this PR's put/purge WQE changes; re-run the job and, if it reproduces, extend the existing MEMIC retry/skip logic in that test.

Full analysis

Summary: make test in build-test/test/gtest exited with code 1 because exactly one test failed: rc_mlx5/uct_atomic_key_reg_rdma_mem_type.fadd64/1 (GetParam() = rc_mlx5/mlx5_1:1); the other 8615 tests passed.

Root cause: Evidence from the log tail: [ PASSED ] 8615 tests. / [ FAILED ] 1 test ... rc_mlx5/uct_atomic_key_reg_rdma_mem_type.fadd64/1make: *** [Makefile:4713: test] Error 1. The process ran to completion and printed the normal gtest summary and TOP-20 timing table, so this is a plain gtest failure — not an AddressSanitizer report (an ASAN abort would have terminated the run) and not a timeout (no gaps; continuous per-test timestamps through tear-down).

The failing test is the only test that allocates UCS_MEMORY_TYPE_RDMA (IB device memory / MEMIC) and runs 4 concurrent worker threads doing uct_ep_atomic64_fetch(ADD) against it (test/gtest/uct/test_atomic_key_reg_rdma_mem_type.cc:29-41, buffer created with num_retries = 10). That test is a well-known flaky spot: its entire git history consists of flakiness mitigations — 69718f6d "Add retries and rand sleep when it cannot allocate MEMIC memory", [REDACTED:Hex High Entropy String] "Retry when it cannot allocate MEMIC memory", d7d57e17 "Limit MEMIC allocation to prevent out-of-memory test failures". MEMIC is a small, per-HCA shared resource, so parallel jobs on the same CI worker ("roce on worker 2") can exhaust it even with 10 retries.

Nothing in this PR plausibly reaches this path: the PR commits are 31ae0aa2 (TX WQE opcode + wrap-around copy helpers), 535cec75/[REDACTED:Hex High Entropy String] (purge gtest + purge stub) and 7827e4b6 (cleanup) — read-only WQE parsing helpers and the outstanding-purge path, whereas the failing test exercises only atomic fetch-add and device-memory key registration and never calls purge.

Caveat: the exact assertion text is not recoverable — the log fetch returns only the final ~30 s of a ~44-minute run, and the failure occurred much earlier. The above is inferred from the summary line plus the test's source and history.

Implicated commit: none in this PR — most likely environmental/flaky. Historical context: 69718f6d (Michal Shalev), [REDACTED:Hex High Entropy String] (Michal Shalev), d7d57e17 (Leonid Genkin), original test 6c7715d0 (Roie Danino).

File: test/gtest/uct/test_atomic_key_reg_rdma_mem_type.cc:29-41 (buffer alloc at line 33-34; retry count plumbed via entity::mem_alloc(..., unsigned num_retries) in test/gtest/uct/uct_test.h:143-146)

Suggested fix:

  1. Re-trigger the "roce on worker 2" job; a single-test failure in an unrelated MEMIC atomic test on a 8616-test run is almost certainly infrastructure noise for this PR.
  2. To confirm before dismissing it, grab the full step log (not the tail) and search for rc_mlx5/uct_atomic_key_reg_rdma_mem_type.fadd64 to see whether it was (a) Failed to allocate memory / UCS_ERR_NO_MEMORY from MEMIC, or (b) Reply ... appeared N times; expected: M from uct_amo_test::validate_replies. Case (a) = flaky resource exhaustion; case (b) would be a real data-correctness bug and worth bisecting against 31ae0aa2.
  3. If (a) recurs: in test_atomic_key_reg_rdma_mem_type.cc, turn a post-retry MEMIC allocation failure into UCS_TEST_SKIP_R("cannot allocate device memory (MEMIC)") instead of a hard failure (extending the intent of 69718f6d), and/or raise the retry count above 10 with backoff.
  4. Reproduce locally with GTEST_FILTER='rc_mlx5/uct_atomic_key_reg_rdma_mem_type.*' make -C build-test/test/gtest test on a RoCE-capable HCA to verify the PR is not implicated.

Related: PR #11836 (this PR, [WIP][DNM] UCT/IB/MLX5: wqe parser for uct put); prior flakiness fixes for the same test: #10475 ("Increase retries and add random sleep when MEMIC allocation fails"); PR #11668 (outstanding purge implementation, the feature this PR builds on).

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 5587cd1c-d6c0-4736-a371-a07907c9318b in the triage console for the audit trail.

@jeynmann jeynmann changed the title [WIP][DNM] UCT/IB/MLX5: wqe parser for uct put [DNM] UCT/IB/MLX5: wqe parser for uct put Aug 28, 2026
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Review complete — no issues found.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Review complete — no issues found.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5_common.c Outdated

uct_rc_mlx5_op_info_fill_rma_raddr(info, raddr);

info->operation = is_dm ? UCT_EP_OP_PUT_SHORT : UCT_EP_OP_PUT_BCOPY;

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: In uct_rc_mlx5_op_info_fill_put_bcopy, the function returns UCS_ERR_UNSUPPORTED at lines 138-140 when is_dm is true, so is_dm is always false when reaching line 148. The ternary is_dm ? UCT_EP_OP_PUT_SHORT : UCT_EP_OP_PUT_BCOPY is dead — the operation is always UCT_EP_OP_PUT_BCOPY.

Suggested change
info->operation = is_dm ? UCT_EP_OP_PUT_SHORT : UCT_EP_OP_PUT_BCOPY;
info->operation = UCT_EP_OP_PUT_BCOPY;

is_dm is always false here since the function already returned UCS_ERR_UNSUPPORTED above when is_dm is set. Similarly, uct_rc_mlx5_get_dptr_buffer computes op->buffer only to discard it in the is_dm case.

@svc-ucx

svc-ucx commented Aug 31, 2026

Copy link
Copy Markdown

🤖 CI Triage AgentUCX PR (Coverity coverity release on coverity_rh7) · commit b254a03b

TL;DR: The Coverity release gate failed with one DEADCODE defect at src/uct/ib/mlx5/rc/rc_mlx5_common.c:148 — commit b254a03b added an early return UCS_ERR_UNSUPPORTED for is_dm but left a now-unreachable is_dm ? ... ternary below it; replace the ternary with the constant UCT_EP_OP_PUT_BCOPY.

Full analysis

Summary: coverity release on coverity_rh7 failed at the cov-analyze/cov-format-errors gate: build and analysis succeeded (549 units, 94 defect occurrences), but 1 newly-introduced defect tripped the nerrors > 0 check → ##[error]Coverity found 1 issues.

Root cause: In uct_rc_mlx5_op_info_fill_put_bcopy(), the head commit of this PR added an early bail-out:

137: uct_rc_mlx5_get_dptr_buffer(op, dptr, &buffer, &length, &is_dm);
138: if (is_dm) {
139:     return UCS_ERR_UNSUPPORTED;
140: }

Any code after line 140 is only reachable when is_dm == 0, so the pre-existing ternary on line 148 (info->operation = is_dm ? UCT_EP_OP_PUT_SHORT : UCT_EP_OP_PUT_BCOPY;) has a provably dead true-branch. Coverity reports exactly this chain: cond_const at line 138 (false branch → is_dm == 0), then dead_error_condition / dead_error_line at line 148 — "Execution cannot reach the expression UCT_EP_OP_PUT_SHORT". This is a genuine leftover from the refactor, not a false positive or infrastructure flake: the DM case now returns early instead of being encoded as PUT_SHORT.

Implicated commit: [REDACTED:Hex High Entropy String] — Zihao Zhao, "UCT/IB/MLX5: return unsupport for DM PUT" (2026-08-31)

File: src/uct/ib/mlx5/rc/rc_mlx5_common.c:148 (dead branch introduced by the guard at :138-140)

Suggested fix: Drop the now-redundant ternary so the operation is set unconditionally:

    info->operation   = UCT_EP_OP_PUT_BCOPY;
    info->field_mask |= UCT_EP_OP_INFO_FIELD_OPERATION;

While there, consider whether is_dm still needs to be a separate local — it is only used for the guard at line 138, so the variable can stay but the UCT_EP_OP_PUT_SHORT reference in this function should go away entirely (PUT_SHORT is still legitimately set in uct_rc_mlx5_op_info_fill_put_short() at line 123, so no other change is needed). Re-run the Coverity job after the fix; the remaining 93 occurrences are pre-existing baseline noise and should not re-trigger the gate.

Related: PR #11836 (branch failover_uct_rcx_put); same-series commits 7827e4b6, f75fbbfa, 1a563800 touch the same file and functions.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 74b4ccf9-96e8-405c-8e6a-e3a43b5778c1 in the triage console for the audit trail.

@jeynmann
jeynmann force-pushed the failover_uct_rcx_put branch from b254a03 to 9355f4c Compare August 31, 2026 08:11
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Review complete — no issues found.

@gleon99
gleon99 requested a review from roiedanino August 31, 2026 10:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants