Skip to content

GTEST/UCT: Add outstanding purge test base - #11891

Merged
roiedanino merged 10 commits into
openucx:masterfrom
roiedanino:uct-purge-test-base
Sep 8, 2026
Merged

roiedanino merged 10 commits into
openucx:masterfrom
roiedanino:uct-purge-test-base

Conversation

@roiedanino

@roiedanino roiedanino commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

What?

Add a reusable UCT endpoint outstanding-purge test fixture.

The fixture centralizes connected endpoint setup, capability checks, deterministic posting around endpoint invalidation, token exchange, purge callback dispatch, operation descriptor validation, and completion handling. This PR intentionally does not instantiate an operation-specific test.

Why?

AM short, AM bcopy, and PUT zcopy purge tests need the same fault-tolerance flow. Sharing the common UCT-level mechanics keeps the operation-specific PRs small and avoids duplicated test logic between #11857 and #11874.

How?

The fixture uses only public UCT APIs and skips transports that do not advertise peer-failure handling and token-query support. It first completes one operation, then posts an operation and an endpoint flush before endpoint invalidation, fills the remaining send resources without progress, and purges using the receiver token. Common validation covers operation identity, completion ownership, flush metadata, purge counts, and flush cancellation. Follow-up PRs add an operation case to validate_op() and a test that supplies its send function.

Co-authored-by: Zihao Zhao <zizhao@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

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

Comment thread test/gtest/uct/ib/test_rc.cc Outdated

_UCT_INSTANTIATE_TEST_CASE(test_rc_mlx5_token_query, rc_mlx5)

class test_rc_purge_outstanding : public test_rc {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

blocker: this class has no UCS_TEST* bodies and no _UCT_INSTANTIATE_TEST_CASE, so nothing here runs. The added test_rc_purge_outstanding class defines only helper methods (init, purge_outstanding, send_op, err_handler, purge_cb, query_tx_token, query_rx_token, ensure_undelivered, check_caps_v2) but there are no UCS_TEST*/UCS_TEST_SKIP_COND_P bodies that use it. Looks like the actual purge test is missing — pls add the test case(s) and instantiation, or drop this scaffolding.

Comment thread test/gtest/uct/ib/test_rc.cc Outdated
return ucs_test_all_flags(attr.cap.flags, required_flags);
}

void send_op(const uct_ep_op_info_t *info, purge_ctx *ctx)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

send_op: the switch (info->operation) has only a default branch that aborts, so ++ctx->num_replayed is currently unreachable for any real operation; the intended replay/case handling seems unfinished.

Comment thread test/gtest/uct/ib/test_rc.cc Outdated

_UCT_INSTANTIATE_TEST_CASE(test_rc_mlx5_token_query, rc_mlx5)

class test_rc_purge_outstanding : public test_rc {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

check_caps_v2, purge_ctx::comp, and num_replayed are never referenced by any caller.

@svc-nvidia-pr-review

Copy link
Copy Markdown

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

Comment thread test/gtest/uct/ib/test_rc.cc Outdated
{
ASSERT_TRUE(info->field_mask & UCT_EP_OP_INFO_FIELD_OPERATION);

switch (info->operation) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

blocker: the switch only has default: abort, so ++ctx->num_replayed is unreachable and EXPECT_GT(ctx.num_replayed, 0u) (L1721) can never pass — any purge callback invocation aborts the test. Please add the real operation case(s) that replay the op so num_replayed is reachable, or clarify the intended flow.

Comment thread test/gtest/uct/ib/test_rc.cc Outdated

_UCT_INSTANTIATE_TEST_CASE(test_rc_mlx5_token_query, rc_mlx5)

class test_rc_purge_outstanding : public test_rc {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Class defined but not instantiated in this hunk: where is test_purge_outstanding invoked? I don't see a UCS_TEST_P / _UCT_INSTANTIATE_TEST_CASE for test_rc_purge_outstanding — without it the static helpers are unused (build warnings / dead code) and no test actually runs.

Comment thread test/gtest/uct/ib/test_rc.cc Outdated

if (receiver_next_psn ==
uct_ib_mlx5_txwq_get_next_wqe_psn(&rc_ep->tx.wq)) {
*rx_token = htobe32((receiver_next_psn - 1) & UCS_MASK(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.

minor: PSN wrap in ensure_undelivered — when receiver_next_psn == 0, (receiver_next_psn - 1) & UCS_MASK(24) wraps to 0xFFFFFF. This may be intended (24-bit PSN wraparound); please add a brief comment confirming the wrap is deliberate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There's an intentional 24-bit PSN wraparound

Comment thread test/gtest/uct/ib/test_rc.cc Resolved
Comment thread test/gtest/uct/ib/test_rc.cc Outdated
uct_rc_mlx5_tx_token_t tx_token = {};
uct_rc_mlx5_rx_token_t rx_token = {};

ASSERT_UCS_OK(uct_ep_invalidate(m_e1->ep(0), &invalidate_params));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we need to inject ep_invalidate in the tight loop of posts to have both - delivered and undelivered ops

@jeynmann jeynmann Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, it’s associated with the previous comments for progress. Please note that once error CQE is progressed, we won’t be able to post anything.

Comment thread test/gtest/uct/ib/test_rc.cc Resolved
@svc-ucx

svc-ucx commented Sep 3, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX PR (Coverity coverity devel on coverity_rh7) · commit 51c3f534

TL;DR: The Coverity devel job failed with one new defect — UNREACHABLE (structurally dead code) at test/gtest/uct/ib/test_rc.cc:1614, because send_op()'s switch (info->operation) contains only a default: label that calls UCS_TEST_ABORT, so the following ++ctx->num_replayed; can never execute. Add the real per-operation case branches (or restructure the abort into an else) so the increment is reachable.

Full analysis

Summary: Azure job "Coverity coverity devel on coverity_rh7" (build 134183) failed at the cov-analyze/cov-format-errors gate: ##[error]Coverity found 1 issues: /__w/1/s/test/gtest/uct/ib/test_rc.cc:1614 Type: Structurally dead code (UNREACHABLE). The build and all 739 compilation units succeeded; only the static-analysis defect count (nerrors=1 > 0) failed the job.

Root cause: In the new test_rc_purge_outstanding helper added by this PR, send_op() is written as:

switch (info->operation) {
default:
    UCS_TEST_ABORT("unsupported operation " << info->operation);
}

++ctx->num_replayed;      // line 1614

The switch has no non-default cases, and UCS_TEST_ABORT never returns normally, so control can never reach line 1614. Coverity correctly reports it as structurally dead code. This is a placeholder/scaffold switch — the actual operation handlers (e.g. AM short/bcopy/zcopy, PUT/GET) that would make the increment reachable are not present in the committed code yet.

Implicated commit: 1f15cc40 "GTEST/UCT/IB: Add outstanding purge replay test base" (Roie Danino), extended by 51c3f534 "GTEST/UCT/IB: Add outstanding purge test runner" (the head commit of this PR) — both on branch uct-purge-test-base.

File: test/gtest/uct/ib/test_rc.cc:1609-1614 (defect reported at line 1614)

Suggested fix: Make the replay path reachable. Preferred: land the concrete operation cases in the same commit, e.g.

switch (info->operation) {
case UCT_EP_OP_AM_SHORT:
    /* re-post the AM ... */
    break;
/* other supported ops ... */
default:
    UCS_TEST_ABORT("unsupported operation " << info->operation);
}

++ctx->num_replayed;

If the handler must stay a stub for now, avoid the dead-code pattern instead of relying on a default-only switch — for example:

if (info->operation != <supported_op>) {
    UCS_TEST_ABORT("unsupported operation " << info->operation);
}
/* replay ... */
++ctx->num_replayed;

Do not suppress this with a Coverity annotation; the report is a genuine sign that the incremental commit split left an unfinished code path. Note this build is only failing on this single new defect, so fixing it should make the Coverity stage green (baseline count returns to 0).

Related: PR #11891 (branch uct-purge-test-base); prerequisite commit 1f15cc4 in the same series.

Comment thread test/gtest/uct/ib/test_rc.cc Outdated
} while (status == UCS_ERR_NO_RESOURCE);
}

void send_op(const uct_ep_op_info_t *info, purge_ctx *ctx)

This comment was marked as resolved.

Comment thread test/gtest/uct/ib/test_rc.cc Outdated
EXPECT_EQ(UCS_INPROGRESS,
uct_ep_flush(m_e1->ep(0), 0, flush_comp));

wait_for_flag(&m_err_count);

This comment was marked as resolved.

@svc-nvidia-pr-review

Copy link
Copy Markdown

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

Comment thread test/gtest/uct/ib/test_rc.cc Outdated

_UCT_INSTANTIATE_TEST_CASE(test_rc_mlx5_token_query, rc_mlx5)

class test_rc_purge_outstanding : public test_rc {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

blocker: this whole class (test_rc_purge_outstanding) and all its helpers (init, post_ops, purge_outstanding, test_purge_outstanding, check_caps_v2, etc.) is never instantiated — there's no UCS_TEST_P/UCS_TEST_SKIP_COND_P calling test_purge_outstanding() and no _UCT_INSTANTIATE_TEST_CASE. A tree-wide search finds no other references. As-is it adds no coverage and the unused static/private helpers may fail to compile with -Werror. Are the test bodies / instantiation missing from this PR?

Comment thread test/gtest/uct/ib/test_rc.cc Outdated
}
}

void replay_op(const uct_ep_op_info_t *info, purge_ctx *ctx)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

replay_op always aborts in the default: arm, so ++ctx->num_replayed is unreachable (marked /* coverity[unreachable] */), yet test_purge_outstanding asserts EXPECT_GT(ctx.num_replayed, 0u) — that can never pass. If purge_cb is invoked for any operation the test aborts, and if it's never invoked num_replayed stays 0. This looks like the base is meant to be subclassed with a real replay_op; the derived test and instantiation appear to be missing.

@svc-ucx

svc-ucx commented Sep 6, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX PR (EFA_Tests EFA on rhel90_ib) · commit f7ee0c1e

TL;DR: The EFA/valgrind gtest run failed on a single UD test, ud_verbs/test_ud.stale_private_ep_reuse/0, where find_private_ep(m_e2, ep(m_e1)->ep_id) returned NULL (test/gtest/uct/ib/test_ud.cc:963) — a timing‑sensitive assertion in the recently added "stale private UD connection" test, not something PR #11891 (a gtest purge test base) touches. Make the test poll for the private EP with a scaled timeout (or skip under valgrind) instead of asserting after a fixed progress loop.

Full analysis

Summary: make test_valgrind returned Error 1 because 1 of 1404 gtests failed: ud_verbs/test_ud.stale_private_ep_reuse/0 (param ud_verbs/rdmap0:1); everything else passed and valgrind reported 0 errors / 0 definite leaks.

Root cause: In the failing instance the test expected a private UD endpoint on the passive side to exist for the (reused) ep_id of m_e1's endpoint:

/__w/2/s/contrib/../test/gtest/uct/ib/test_ud.cc:963: Failure
Value of: find_private_ep(m_e2, ep(m_e1)->ep_id) != NULL
  Actual: false
Expected: true

Evidence that this is a timing/flakiness issue in the test rather than a regression from this PR:

  • Only device instance /0 (rdmap0) failed; the identical /1 (rdmap1) instance passed (4049 ms), and the neighbouring private_ep_keepalive/0,1, stale_crep_on_reused_ep_id/0,1 and stale_dest_ep_id_update/0,1 tests all passed.
  • The run is under valgrind on EFA (rdmap* devices) where CREQ/CREP round trips and the UD linger/keepalive timers are heavily slowed (individual UD tests take 4–15 s here, e.g. cep_insert_4_paths 14.4 s). The assertion depends on the passive-side private EP having been created by the delivered CREQ and not yet reclaimed by the stale-private-connection cleanup — a narrow window that a fixed short_progress_loop()/linger timeout does not guarantee under valgrind.
  • PR GTEST/UCT: Add outstanding purge test base #11891 ("GTEST/UCT/IB: Add outstanding purge replay test base") is gtest infrastructure only; it does not modify src/uct/ib/ud/* connection or private-EP logic, so it cannot change whether a private EP is registered.
  • find_private_ep and the stale_private_ep_reuse / private_ep_keepalive tests come from the UD private-connection work (UCT/UD: Remove stale private UD connections #11822, backported as UCT/UD: Remove stale private UD connections - v1.23.x #11899), which is the code under test here.

Implicated commit: Not this PR's commit (f7ee0c1). The test and helper originate from PR #11822 "UCT/UD: Remove stale private UD connections" (exact sha not visible in the history snapshot available to me; nearest related commit on these files is 0ee470a8 — Ilia Yastrebov, "UCT/UD: Add generation ID to dest_id to make it unique" (#11800)).

File: test/gtest/uct/ib/test_ud.cc:963 (assertion find_private_ep(m_e2, ep(m_e1)->ep_id) != NULL); supporting logic in src/uct/ib/ud/base/ud_ep.c / ud_iface.c

Suggested fix:

  1. Make the check deterministic instead of relying on a fixed progress loop: replace the direct EXPECT/ASSERT with a wait-for-condition, e.g. ucs::wait_for_value-style loop / wait_for_flag polling find_private_ep(m_e2, ep(m_e1)->ep_id) != NULL with a timeout multiplied by ucs::test_time_multiplier().
  2. Scale any UD_LINGER_TIMEOUT / keepalive interval used by stale_private_ep_reuse by ucs::test_time_multiplier() (as done in other UD tests) so the private EP is not reclaimed before the assertion under valgrind, or add UCS_TEST_SKIP_COND_P(..., RUNNING_ON_VALGRIND) if the window cannot be made robust.
  3. Re-run this EFA job to confirm the failure is intermittent; since it is unrelated to the changes in GTEST/UCT: Add outstanding purge test base #11891, it should not block this PR once the test is hardened (open a separate issue against UCT/UD: Remove stale private UD connections #11822's test).

Related: PR #11891 (this PR), PR #11822 (UCT/UD: Remove stale private UD connections — added the failing test), PR #11899 (v1.23.x backport), PR #11800 / commit 0ee470a (UD dest_id generation ID)

@svc-nvidia-pr-review

Copy link
Copy Markdown

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

Comment thread test/gtest/uct/ib/test_rc.cc Outdated

_UCT_INSTANTIATE_TEST_CASE(test_rc_mlx5_token_query, rc_mlx5)

class test_rc_purge_outstanding : public test_rc {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This whole class has no UCS_TEST_* cases and no _UCT_INSTANTIATE_TEST_CASE, so test_purge_outstanding() and its helpers are never compiled into any running test. Was the intent to also add the test cases and instantiation? As-is the new purge coverage does not run.

Comment thread test/gtest/uct/ib/test_rc.cc Outdated
{
ASSERT_TRUE(info->field_mask & UCT_EP_OP_INFO_FIELD_OPERATION);

switch (info->operation) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

As written the switch (info->operation) only has a default that aborts, so any purged op makes the test fail. Since the test expects ctx.num_purged > 0, the first purge_cb → validate_op() invocation would abort the test. Please handle the operations the test actually posts with explicit case branches (e.g. UCT_EP_OP_AM_SHORT, UCT_EP_OP_AM_BCOPY, UCT_EP_OP_AM_ZCOPY, UCT_EP_OP_PUT_SHORT, UCT_EP_OP_PUT_BCOPY, UCT_EP_OP_PUT_ZCOPY).

@svc-nvidia-pr-review

Copy link
Copy Markdown

send_func_t/post_op accept a generic send_func, but no test wires up a concrete send function since there are no test cases.

@svc-ucx

svc-ucx commented Sep 6, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX PR (Tests gpu on worker 3) · commit 4b565923

TL;DR: The gtest binary aborted on a debug assertion in the DC send path — dcx/test_ucp_fault_tolerance.initiator_failure/5 <dc_x/GET|FLUSH> posted a GET zcopy WQE on a DCI whose txwq is still flagged UCT_IB_MLX5_TXWQ_FLAG_FAILED, i.e. UCP declared the failed lane "recovered" and issued a real send before the DCI was reset/cleared. This is a DC failover/recovery bug, not caused by PR #11891 (which is gtest-only).

Full analysis

Summary: make test aborted (core dumped) with rc_mlx5.inl:498 Assertion '!(txwq->flags & UCT_IB_MLX5_TXWQ_FLAG_FAILED)' failed during dcx/test_ucp_fault_tolerance.initiator_failure/5 <dc_x/GET|FLUSH>, right after the test printed "Checking recovery status...".

Root cause: From the log, the sequence is: the test injects a local failure with uct_ep_invalidate() on a DC lane (→ uct_dc_mlx5_ep_qp_to_err(), which moves the DCI QP to ERR and posts a NOP so the error CQE triggers a DCI reset), waits until ucp_ep_get_failed_lanes() == 0 and no wireup EPs remain, then issues a large ucp_get_nbx(). The backtrace (ucp_get_nbx → uct_dc_mlx5_ep_get_zcopy → uct_rc_mlx5_common_post_send → fatal) shows the recovered UCP lane sent a non-NOP WQE on a DCI whose txwq is still marked FAILED — i.e. the DCI had not yet been reset (uct_dc_mlx5_iface_reset_dci(), which is what clears the flag, only runs once the EP detaches the DCI in uct_dc_mlx5_ep_handle_failure(), dc_mlx5_ep.c:1969-1994). UCP's recovery completion condition (failed-lane bitmap cleared) is therefore not synchronized with the UCT DC DCI reset, so a real send races into a still-failed DCI. txwq->flags exists only under UCS_ENABLE_ASSERT (ib_mlx5.h:702-704), so this only aborts in debug/assert CI builds, which matches this being an intermittent debug-only crash.

Implicated commit: Not this PR. Most likely candidates, all landed days before this run and all touching exactly this path: [REDACTED:Hex High Entropy String] "UCT/IB/MLX5: support in progress error handler (#11829)", Zihao Zhao, 2026-09-01 (touches rc_mlx5.inl); 84548e4f "UCP/RMA: Support failover for offloaded GET bcopy protocol (#11840)", Evgeny Leksikov, 2026-08-31; recovery foundation db208ee4/9db2e488 (UCP/FT). PR #11891 (uct-purge-test-base, "GTEST/UCT/IB: Add outstanding purge replay test base") only adds gtest code and does not touch test_ucp_fault_tolerance or DC/UCP sources.

File: src/uct/ib/mlx5/rc/rc_mlx5.inl:498 (assertion), triggered via src/uct/ib/mlx5/dc/dc_mlx5_ep.c:955-965 (uct_dc_mlx5_ep_invalidate/qp_to_err) and src/uct/ib/mlx5/dc/dc_mlx5_ep.c:1969-1994 (DCI put/reset in uct_dc_mlx5_ep_handle_failure); test at test/gtest/ucp/test_ucp_fault_tolerance.cc:565-620 (test_recovery, GET after recovery).

Suggested fix:

  1. Close the race in UCT: make DC refuse to hand out / send on a DCI whose txwq still has UCT_IB_MLX5_TXWQ_FLAG_FAILED — e.g. treat such a DCI as having no TX resources (return UCS_ERR_NO_RESOURCE in UCT_DC_MLX5_CHECK_RES/uct_dc_mlx5_iface_dci_has_tx_resources()) until uct_dc_mlx5_iface_reset_dci() has cleared the flag, so the operation goes to pending instead of asserting.
  2. Alternatively/additionally, make UCP's recovery-complete condition depend on the underlying UCT EP being flushed/reset (the lane should stay in "failed/recovering" state until the DC error handler finished the DCI reset), not just on failed_lanes == 0.
  3. Re-run the PR CI to confirm it is unrelated; if it reproduces on master, open a separate issue against the FT/DC recovery path and, meanwhile, consider gating this variant so PRs aren't blocked (as was already done for the UD purge case at test_ucp_fault_tolerance.cc:443-450).

Related: PR #11891 (the build under test, gtest-only); #11829, #11840, #11563, #11562 (recent DC error-handling / GET-failover / FT recovery work); #11397 previously disabled a flaky fault-tolerance test; #7711 / #7071 are earlier instances of "don't send on a failed DCI" fixes.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id eafd17ce-193d-4da3-bfe2-0767e7a48bd5 in the triage console for the audit trail.

Comment thread test/gtest/uct/ib/test_rc.cc Resolved
Comment thread test/gtest/uct/ib/test_rc.cc Resolved
@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

test/gtest/uct/test_peer_failure.cc

Residual coverage note: even once test cases are added, uct_ep_outstanding_purge currently returns UCS_UNSUPPORTED for every in-tree transport except the mlx5 ext-plugin path (all ep_outstanding_purge slots are ucs_empty_function_return_unsupported). The check_caps_v2(UCT_IFACE_FLAG_V2_QUERY_TOKEN) guard will likely skip on all standard CI transports, so confirm which transport/plugin will actually run these cases in CI before relying on them for regression coverage.

@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.

@roiedanino roiedanino changed the title GTEST/UCT/IB: Add outstanding purge replay test base GTEST/UCT: Add outstanding purge base test Sep 7, 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.

@roiedanino roiedanino changed the title GTEST/UCT: Add outstanding purge base test GTEST/UCT: Add outstanding purge test base Sep 7, 2026
@svc-ucx

svc-ucx commented Sep 7, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX PR (AddressSanitizer roce on worker 0) · commit 8ba4a6a1

TL;DR: dc_mlx5/uct_p2p_am_tx_bufs.am_tx_max_bufs/2 failed (am_bcopy stuck at UCS_ERR_NO_RESOURCE, test_p2p_am.cc:745), and the subsequent unbounded flush() in uct_p2p_test::cleanup() hung for the full 900 s gtest watchdog, aborting the whole ASAN shard; the test should be skipped for DC (not just RC) and the cleanup flush needs a deadline.

Full analysis

Summary: ASAN roce gtest shard 1/4 aborted: dc_mlx5/uct_p2p_am_tx_bufs.am_tx_max_bufs/2 <dc_mlx5/mlx5_1:1> failed, then hung 15 minutes until the test watchdog sent SIGABRT (make: *** [Makefile:4713: test] Aborted (core dumped)).

Root cause: Two-stage failure, both visible in the log:

  1. 2026-09-07T15:46:11.2 — test/gtest/uct/test_p2p_am.cc:745: EXPECT_EQ(UCS_OK, status) with status = -2 (UCS_ERR_NO_RESOURCE). The fixture (uct_p2p_am_tx_bufs ctor, test_p2p_am.cc:699-702) forces UCX_IB_TX_MAX_BUFS=32 / TX_BUFS_GROW=32, then expects that 1 s of progress() frees a TX buffer. With only 32 TX descriptors, fewer than the RC/DC TX CQ moderation period, no signalled CQE is generated, so descriptors are never returned to the mpool and the ep stays permanently out of TX resources. This is exactly the condition the test already guards against for RC (else if (has_rc()) UCS_TEST_SKIP_R("Test does not work with IB RC transports"), test_p2p_am.cc:726) — but uct_test::has_rc() (uct_test.cc:616) covers only rc_verbs/rc_mlx5, so dc_mlx5, which uses the same RC TX/FC machinery, is not skipped.
  2. The 900 s of dead silence from 15:46:11 → 16:01:11 (exactly watchdog_timeout = 900. in test_helpers.cc:31, failure reported at test_helpers.cc:57 "Connection timed out - abort testing") is a hang, not slowness: after the failed expectation, uct_p2p_test::cleanup() (uct_p2p_test.cc:93) calls flush() with the default deadline ULONG_MAX, and uct_test::flush() (uct_test.cc:766-783) loops while (!flushed && ucs_get_time() < deadline) — with the ep wedged at UCS_ERR_NO_RESOURCE it never exits, so one test failure kills the entire shard with SIGABRT instead of failing just that test.

This looks like a latent/environment-sensitive test bug (aggravated by ASAN timing on the RoCE worker), not something introduced by the purge-test-base change in PR #11891.

Implicated commit: unknown — the has_rc()-only skip predates this PR (nearest related test changes: d09569b and 25dbbc8, Yossi Itigin, RX-queue-length tuning of the neighbouring no-buffers test)

File: test/gtest/uct/test_p2p_am.cc:726 (skip condition) and test/gtest/uct/uct_p2p_test.cc:93 / test/gtest/uct/uct_test.cc:766 (unbounded cleanup flush)

Suggested fix:

  1. Skip the test for DC as well: change } else if (has_rc()) { to } else if (has_rc_or_dc()) { at test_p2p_am.cc:726 (message: "Test does not work with IB RC/DC transports"). has_rc_or_dc() already exists (uct_test.cc:620). Alternatively also force UCX_RC_TX_CQ_MODERATION=1 in the fixture constructor so 32 TX buffers can actually be reclaimed.
  2. Bound the cleanup flush so a wedged ep fails the single test instead of hanging the shard: in uct_p2p_test::cleanup() pass a deadline, e.g. flush(ucs::get_deadline()), so EXPECT_TRUE(flushed) << "Timed out" fires quickly rather than spinning until the 900 s watchdog SIGABRT.
  3. Re-run the ASAN roce job after the skip fix to confirm the shard completes.

Related: PR #11891 (this build); adjacent purge work in #11857 — no existing issue found for am_tx_max_bufs on dc_mlx5, worth opening one.

Comment thread test/gtest/uct/test_peer_failure.cc Resolved
Comment thread test/gtest/uct/test_peer_failure.cc Outdated
Comment on lines +575 to +576
{completion_cb, 0, UCS_OK},
{completion_cb, 0, UCS_OK},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why need to initialize both with the same value?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not addressed

Comment thread test/gtest/uct/test_peer_failure.cc Resolved
Comment thread test/gtest/uct/test_peer_failure.cc Resolved
Comment thread test/gtest/uct/test_peer_failure.cc Resolved
Comment thread test/gtest/uct/test_peer_failure.cc Resolved
Comment thread test/gtest/uct/test_peer_failure.cc Resolved
Comment thread test/gtest/uct/test_peer_failure.cc Resolved
Comment thread test/gtest/uct/test_peer_failure.cc Resolved
Comment thread test/gtest/uct/test_peer_failure.cc Resolved
@svc-nvidia-pr-review

Copy link
Copy Markdown

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


UCT_INSTANTIATE_TEST_CASE(test_uct_peer_failure)

class test_uct_purge_outstanding : public uct_test {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This adds the whole test_uct_purge_outstanding fixture and its helpers, but there are no UCS_TEST_*P cases and no UCT_INSTANTIATE_TEST_CASE(test_uct_purge_outstanding), so none of it runs. pls add the actual test case(s) and instantiation, or drop the dead fixture.

@svc-nvidia-pr-review

Copy link
Copy Markdown

test/gtest/uct/test_peer_failure.cc

Even with test cases added, uct_ep_outstanding_purge is ucs_empty_function_return_unsupported for every in-tree transport except the mlx5 ext-plugin path, and the check_caps_v2(UCT_IFACE_FLAG_V2_QUERY_TOKEN) guard would skip on all standard CI transports. This was already raised in an earlier review thread. Note the current PR head appears to have moved this coverage into test/gtest/uct/ib/test_ib_mlx5_ext.cc (which exercises purge through a registered stub plugin), so if this diff was superseded by that approach, the test_peer_failure.cc fixture should be removed entirely rather than left as an un-instantiated skeleton.

Comment thread test/gtest/uct/test_peer_failure.cc Resolved
Comment thread test/gtest/uct/test_peer_failure.cc Resolved
@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.

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.

5 participants