Skip to content

Refactoring: derive nixlUcxThreadPoolEngine from nixlUcxThreadEngine - #1906

Merged
iyastreb merged 17 commits into
ai-dynamo:mainfrom
iyastreb:iyastreb/ucx-thread-refactoring
Jul 17, 2026
Merged

iyastreb merged 17 commits into
ai-dynamo:mainfrom
iyastreb:iyastreb/ucx-thread-refactoring

Conversation

@iyastreb

@iyastreb iyastreb commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

What?

To unify the code and reuse the same functions
It's pre-requisite for completions API PR

Summary by CodeRabbit

  • Bug Fixes

    • Improved UCX backend thread lifecycle so the shared progress thread is created and joined only when enabled and shared workers are available.
    • Notification retrieval now properly runs progress when the shared progress thread is not active.
  • Refactor

    • Updated the UCX thread-pool engine to inherit from the shared thread-engine, centralizing shared-worker sizing and notification behavior and removing pool-specific notification overrides.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

👋 Hi iyastreb! Thank you for contributing to ai-dynamo/nixl.

Your PR reviewers will review your contribution then trigger the CI to test your changes.

🚀

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

UCX thread handling now creates shared progress threads only when enabled and workers exist, and thread-pool instances inherit the thread-engine’s notification and progress behavior instead of maintaining separate shared-thread state.

Changes

UCX Thread Engine Refactor

Layer / File(s) Summary
Shared progress thread creation and getNotifs logic
src/plugins/ucx/ucx_backend.cpp, src/plugins/ucx/ucx_backend.h
nixlUcxThreadEngine documentation, constructor, destructor, and getNotifs now describe and implement conditional shared-thread creation and synchronous progress when no thread exists.
ThreadPoolEngine base class change and member cleanup
src/plugins/ucx/ucx_backend.h
nixlUcxThreadPoolEngine now derives from nixlUcxThreadEngine, removes its own notification overrides, and drops the shared-thread and mutex members from its state.
ThreadPoolEngine construction and notification delegation
src/plugins/ucx/ucx_backend.cpp
nixlUcxThreadPoolEngine construction delegates to the base class, validates shared-worker sizing through the inherited interface, stops joining a shared progress thread in destruction, and removes the local notification overrides.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is specific and accurately summarizes the main refactor in this PR.
Description check ✅ Passed The description covers the What and Why at a basic level, and the optional How section is the only major omission.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@iyastreb
iyastreb requested review from ColinNV and rakhmets July 8, 2026 08:50
@iyastreb

iyastreb commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

/build

Comment thread src/plugins/ucx/ucx_backend.cpp Outdated
Comment thread src/plugins/ucx/ucx_backend.h

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/plugins/ucx/ucx_backend.h (1)

328-328: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Override getNotifs() in the thread-pool engine. nixlUcxThreadPoolEngine can still be created with enableProgTh == false && num_threads > 0, so inheriting nixlUcxThreadEngine::getNotifs() makes the null-thread_ fallback call progressLoop() while dedicated workers are already active. That can progress the same UCX workers concurrently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/ucx/ucx_backend.h` at line 328, The thread-pool engine inherits
getNotifs() from nixlUcxThreadEngine, which can incorrectly fall back to
progressLoop() even when nixlUcxThreadPoolEngine has dedicated worker threads
running. Override getNotifs() in nixlUcxThreadPoolEngine so notification
handling uses the thread-pool path only and never starts the null-thread
fallback that can progress UCX workers concurrently; update the override near
nixlUcxThreadPoolEngine and align it with the existing thread-pool/progress
logic in nixlUcxThreadEngine.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/plugins/ucx/ucx_backend.h`:
- Line 328: The thread-pool engine inherits getNotifs() from
nixlUcxThreadEngine, which can incorrectly fall back to progressLoop() even when
nixlUcxThreadPoolEngine has dedicated worker threads running. Override
getNotifs() in nixlUcxThreadPoolEngine so notification handling uses the
thread-pool path only and never starts the null-thread fallback that can
progress UCX workers concurrently; update the override near
nixlUcxThreadPoolEngine and align it with the existing thread-pool/progress
logic in nixlUcxThreadEngine.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 76f8d202-60e9-4b8d-808d-05c26446014e

📥 Commits

Reviewing files that changed from the base of the PR and between eef947f and 062d2f3.

📒 Files selected for processing (1)
  • src/plugins/ucx/ucx_backend.h

@brminich

brminich commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

/build

Comment thread src/plugins/ucx/ucx_backend.h
Comment thread src/plugins/ucx/ucx_backend.h Outdated
@iyastreb

iyastreb commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

/build

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/plugins/ucx/ucx_backend.cpp`:
- Around line 366-368: Validate `num_threads` in `UcxBackend` before computing
`numSharedWorkers_` so it cannot exceed `getWorkers().size()`, and fail fast
with a runtime error if the requested thread count is invalid. Update the logic
around `shared_count` and the worker-indexing path in `UcxBackend::...` so it no
longer relies on `NIXL_ASSERT` for production safety, and ensure the derived
worker range used later when indexing workers is always bounds-checked.

In `@src/plugins/ucx/ucx_backend.h`:
- Around line 315-322: Move getSharedWorkersSize() back under the protected
section alongside appendNotif() in ucx_backend.h so it remains an internal
helper instead of a public API. Keep the UCX backend member grouping consistent
by preserving the intended public/protected/private layout, and make sure any
existing access by the pool still works through the protected override rather
than exposing it through the public interface.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 469a4e81-8e2e-47a6-b6f0-3394bff8ec44

📥 Commits

Reviewing files that changed from the base of the PR and between 062d2f3 and ed2fe96.

📒 Files selected for processing (2)
  • src/plugins/ucx/ucx_backend.cpp
  • src/plugins/ucx/ucx_backend.h

Comment thread src/plugins/ucx/ucx_backend.cpp Outdated
Comment thread src/plugins/ucx/ucx_backend.h Outdated
@iyastreb

iyastreb commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

/build

@iyastreb

Copy link
Copy Markdown
Contributor Author

/build

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-gpu · commit adac02f4

TL;DR: The "Run CPP tests" stage exited 42 because the gtest CI harness treats the benign environmental warning 8 NVIDIA GPU(s) were detected, but UCX CUDA support was not found! as a fatal error, flagging 67 otherwise-passing tests; plus two genuine failures (HardwareWarningTest.NoWarningWhenIbAndCudaSupported throwing "Failed to create UCX context: No such device", and MetadataExchangeTestFixture.EtcdSendLocalAndFetchRemote where sendLocalMD() returned -2). The test container's UCX build lacks CUDA/IB transport support, so those tests cannot pass in this environment.

Full analysis

Summary: Stages 203 and 242 ("Run CPP tests") failed with exit code 42; 69/154 tests reported failed, almost all due to a UCX build lacking CUDA/IB support in the test container.

Root cause: The UCX in the test image was built/loaded without CUDA and accelerated-IB transports (UCX WARN transports 'ib','cuda' are not available; ERROR no usable transports/devices (asked ib,cuda...)). The gtest harness raises "ATTENTION: Unexpected NIXL warning or error detected!" and returns exit code 42 for every test that emits the ucx_utils.cpp:639/:646 GPU/IB-not-supported warning — that accounts for ~67 of the 69 "failures" (they still print [ OK ]/[ PASSED ]). Two are real failures: HardwareWarningTest.NoWarningWhenIbAndCudaSupported (exit 1) forces a UCX context requiring ib,cuda and throws Failed to create UCX context: No such device because neither transport exists in this image; and MetadataExchangeTestFixture.EtcdSendLocalAndFetchRemote where sendLocalMD() returned -2 (NIXL_ERR_BACKEND, an etcd backend issue). Note the build_helper ucx-master/ucx-v1.22.x parallel stages (124/125) also failed first, consistent with a UCX build/setup problem feeding a bad UCX into the test image.

Implicated commit: unknown (recent history on test/gtest is all telemetry/tracing work by e-eygin, none touching UCX transport detection; the transport-less UCX build in the container is the environmental trigger).

File: src/utils/ucx/ucx_utils.cpp:639 and :646 (warning source); test HardwareWarningTest.NoWarningWhenIbAndCudaSupported and MetadataExchangeTestFixture.EtcdSendLocalAndFetchRemote in test/gtest.

Suggested fix: Fix the test container's UCX so it is built with CUDA and IB/RDMA transport support (investigate the failing build_helper/ucx-master and ucx-v1.22.x stages 124/125 — the UCX build there is what the image consumes). Until UCX has CUDA/IB, HardwareWarningTest.NoWarningWhenIbAndCudaSupported cannot pass and every UCX test trips the "unexpected warning" check. Separately, the harness should not convert the informational ucx_utils.cpp:639/:646 GPU/IB-capability warnings into exit code 42 on hosts where UCX legitimately lacks CUDA/IB. Also confirm the etcd server is reachable for sendLocalMD (the -2/NIXL_ERR_BACKEND suggests an etcd connectivity/backend problem).

Related: none found.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-gpu · commit adac02f4

TL;DR: The "Run Nixlbench tests" stage was killed by Jenkins (exit 143) after an ~18-minute hang, not a slow test; the first UCCL+ETCD benchmark hung during engine teardown (one nixlbench worker never exited after "Engine destroyed"/epoll_client HUP), so parallel blocked until the wall-clock kill. Investigate the UCX engine shutdown/progress-thread lifecycle changed in PR #1906.

Full analysis

Summary: Nixlbench stage (node 356) hung during teardown of the first UCCL+ETCD benchmark and was SIGTERM-killed after ~18 min of no output.

Root cause: Engine/worker shutdown deadlock. At 06:47:45–48 both workers reached "Destroying Engine…"; one printed "Engine destroyed" but the peer hit event_loop rdma/epoll_client.h:207 Error/HUP on connection: 1.1.101.4:44479 and never completed teardown/exit. Because the two workers run under parallel --halt now,fail=1, the surviving hung process prevented parallel from returning, producing 18 minutes of silence until Jenkins killed the build (exit 143 is the symptom, not the cause). This is a hang, so raising the time limit is NOT the fix.

Implicated commit: PR #1906 (adac02f, "Refactoring: derive nixlUcxThreadPoolEngine from nixlUcxThreadEngine") — the change under test; closely related prior fix is 0225cd5 (#1880, "ucx: fix infinite loop dropping pending requests on dedicated-thread exit") by Eylon Eliyahu Krause, same shutdown code path.

File: UCX engine shutdown path exercised via src/plugins/ucx (thread/thread-pool engine destructor + pending-request drain); the visible hang site is rdma/epoll_client.h:207 (UCCL provider) during engine destroy.

Suggested fix: Reproduce the UCCL+ETCD READ VRAM→VRAM case and capture a stack trace (gdb/py-spy) of the stuck nixlbench at teardown. Audit PR #1906's changes to the nixlUcxThreadEngine/nixlUcxThreadPoolEngine destructor and progress-thread join/pending-request-drain logic — a base-class destructor that no longer stops/joins the progress thread (or double-drains) in the derived type would leave a worker blocked on a HUP'd connection. Ensure the shutdown ordering from #1880 (drain pending requests, then join thread, then destroy endpoints) is preserved in the refactored hierarchy. Do not simply increase the Jenkins timeout.

Related: PR #1906 (#1906); PR #1880 (#1880); PR #1846 (#1846, forcibly close UCP endpoints).

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-gpu · commit adac02f4

TL;DR: The "Run CPP tests" stage crashed (SIGABRT, exit 134) in ucx_backend_multi because UCX failed to open the TCP interface over IB device ibp84s0f1 ("No such device") on node mizu02; this is an environment mismatch, not a hang or a code bug.

Full analysis

Summary: Jenkins nixl-ci-gpu #2783 stage 203 ("Run CPP tests") failed when ./bin/ucx_backend_multi aborted with a std::runtime_error: Failed to create UCX worker: No such device.

Root cause: UCX on test node mizu02 tried to open a TCP transport bound to IB device ibp84s0f1 (uct_iface_open(tcp/ibp84s0f1) failed: No such device) and the test threw an unhandled std::runtime_error from the failed worker creation, terminating the process (exit 134). The preceding warnings — "8 NVIDIA GPU(s) were detected, but UCX CUDA support was not found" and "4 IB device(s) were detected, but accelerated IB support was not found" — show the UCX in this container image lacks CUDA/IB-accelerated transports, so UCX falls back to a device/interface name that isn't valid on this host. This is an environment/build-config problem, not a source regression: the log shows continuous activity up to the abort (no multi-minute gaps), so it is a crash, not a timeout/hang. (Note the second failure, stage 124 build_helper/x86_64/ucx-master, is a separate short build_helper failure that the pipeline recovered from via retry — stage 142 succeeded.)

Implicated commit: unknown — no code change in the failing test path is implicated; the failure originates from the UCX runtime/device configuration on node mizu02. Recent CI-image change PR #1869 ("Switch CI base image to pytorch + CUDA 13.3") is a plausible contributor to the UCX-without-CUDA/IB-accel build and is worth checking.

File: test/test_cpp.sh:100 (invocation of ./bin/ucx_backend_multi); crash surfaces from UCX worker creation in the UCX backend (see ucx_utils.cpp:639/646 warnings and ucp_worker.c:1492).

Suggested fix:

  1. Investigate node mizu02 / the CI image: the UCX build reports missing CUDA and accelerated-IB support and is selecting IB device ibp84s0f1 which is absent. Rebuild/install UCX with CUDA + IB (rdma-core/verbs) support in the CUDA 13.3 pytorch base image, or pin UCX_NET_DEVICES/UCX_TLS in the test environment so ucx_backend_multi doesn't attempt tcp/ibp84s0f1 on a host without it.
  2. Harden the test: ucx_backend_multi should catch the worker-creation std::runtime_error and skip/xfail with a clear message instead of aborting, so an environment issue doesn't crash the whole CPP stage.
  3. Re-run on a node whose IB devices match the expected names to confirm it's host-specific.

Related: PR #1869 (CI base image switch to pytorch + CUDA 13.3); PR #1743 (run gtest in single process). No existing issue matches the "No such device" UCX worker failure.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-gpu · commit adac02f4

TL;DR: The NIXL build compiled and installed cleanly; the pipeline failed in the "Allocate Environment" stage when the Slurm salloc job (65366) was queued waiting for resources and the container command stream dropped (websocket close 1006). This is a CI infrastructure failure, not a code/PR defect — re-run the build.

Full analysis

Summary: Build #2789 failed in the "Allocate Environment" stage (node 200/183) while allocating a GPU node via Slurm; the container exec stream disconnected before the job started.

Root cause: Infrastructure, not code. The salloc request (salloc -N 1 -p mizu ... --gres=gpu:4 --mincpus=24 --mem=128G, job 65366) went into "queued and waiting for resources" at 10:11:28, and the Jenkins-to-container streaming session then died with Error: error streaming command in container: error reading from error stream: next reader: websocket: close 1006 (abnormal closure): unexpected EOF, causing script returned exit code 1. The whole NIXL/UCX/nixlbench compile-and-install (stage 168 "Compiling NIXL Docker Image") completed successfully and the image was pushed to artifactory, so this is a Slurm-allocation/network dropout, not a compilation or test failure. The earlier build_helper FAILUREs (nodes 124/125) were automatically retried and succeeded (nodes 160/142), so they did not block the pipeline.

Note on timing: there is an ~8-minute quiet span between 10:03:06 (allocation call start) and 10:11:28 (salloc login/queue), but that gap is the Slurm scheduler queueing for a free GPU node, not a hung application process — and the stage then died on an explicit websocket disconnect error rather than a wall-clock kill, so this is a transient connection failure, not a timeout to be raised.

Implicated commit: unknown — not code-related (commit adac02f / PR #1906 is not implicated; the build and image push succeeded).

File: Jenkins pipeline Slurm allocation step (slurm.allocation / scctl salloc, swx-jenkins-lib) — no NIXL source file involved.

Suggested fix: Re-run build #2789 (retry the "Allocate Environment" stage); the failure is a transient Slurm/websocket dropout. If it recurs: (1) check the mizu partition/scctl for GPU node availability and queue backlog around the allocation time, and (2) make the allocation step resilient to scctl/exec-stream disconnects — add a retry/reconnect around the salloc streaming call and/or use --immediate handling so a queued-then-dropped session is retried rather than failing the pipeline. No source-code change to PR #1906 is warranted.

Related: none (issue search returned no matching reports).

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-gpu · commit adac02f4

TL;DR: The "Run CPP tests" stage failed because one gtest, HardwareWarningTest.NoWarningWhenIbAndCudaSupported, aborted with Failed to create UCX context: No such device — the CI node's UCX build lacks CUDA/IB transport support, so a test that forces an ib,cuda UCX context cannot run there. Guard that test to skip when UCX lacks usable ib/cuda transports (or fix the image to include UCX CUDA/RDMA support).

Full analysis

Summary: Run CPP tests (Jenkins stages 203/242) exited 42; the only real failure among the 69 listed is HardwareWarningTest.NoWarningWhenIbAndCudaSupported (exit code 1), which threw a C++ exception creating a UCX context.

Root cause: The test unconditionally creates a UCX context requesting ib,cuda transports. On the mizu02 runner the UCX in the container was built/loaded without CUDA and accelerated-IB support (log shows repeated UCX CUDA support was not found, accelerated IB support was not found, and ibp75s0f0/f1: No such device), so UCX reports no usable transports/devices (asked ib,cuda ...) and throws Failed to create UCX context: No such device. The other 68 "failures" are false positives: they PASSED but the harness returns exit code 42 whenever the "8 NVIDIA GPU(s) detected but UCX CUDA support not found" warning is emitted — an environment/harness artifact, not a code bug. (Note: the timestamps show continuous progress, so this is not a hang/timeout despite the 23-minute stage duration.)

Implicated commit: unknown — the failing test file wasn't retrievable via the tools and no matching commit was found in the searched history; the failure is environment-driven (UCX build lacking CUDA/IB) rather than a specific code change.

File: test gtest HardwareWarningTest.NoWarningWhenIbAndCudaSupported (UCX plugin hardware-warning test; exact path not resolvable via available tools). UCX warnings originate at src/.../ucx_utils.cpp:639 and :646.

Suggested fix: Make NoWarningWhenIbAndCudaSupported skip (GTEST_SKIP) when UCX has no usable ib/cuda transports instead of hard-failing — mirror the guarding the sibling WarnWhen* tests already tolerate. Longer term, provision the CI image on mizu02 with a UCX built with CUDA and RDMA/IB support so ib,cuda contexts can be created; and consider suppressing the "GPU detected but UCX CUDA not found" warning on CI nodes so it stops turning passing tests into exit-code-42 noise.

Related: #1909 ("TEST/GTEST: Fail on unexpectedly skipped tests and fix device tests"), #1953 (UCX version logging) — possibly relevant to the UCX/device-test handling; no exact matching issue found.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-gpu · commit adac02f4

TL;DR: The "Run Nixlbench tests" stages didn't time-out from being slow — they hung for ~12–16 minutes during UCX/UCCL engine teardown after the last completed benchmark (UCCL WRITE, VRAM→VRAM, ETCD), then Jenkins killed them (exit 143). The hang is in the UCX progress-thread shutdown path that PR #1906 refactors, so that PR is the implicated change.

Full analysis

Summary: Jenkins nixl-ci-gpu #2794 stages 356 (mizu04) and 327 (mizu01) "Run Nixlbench tests" were ABORTED with exit code 143 after a long silence, not a genuine slowdown.

Root cause: Log-timestamp analysis shows a hang, not overrun. Stage 356's last application line is 13:21:04.599 Engine destroyed / Error/HUP on connection: 1.1.101.4:37199, then nothing until 13:37:29.500 Sending interrupt signal to process — a ~16.5-minute gap. Stage 327's last line is 13:19:24.688 Engine destroyed / Error/HUP on connection: 1.1.101.1:33487, then silence until the 13:31:21 channel-closed and 13:35:48 kill — a ~12-minute gap. In both runs the final benchmark that produced output was run_nixlbench_two_workers_etcd --backend UCCL --op_type WRITE --initiator_seg_type VRAM --target_seg_type VRAM; the process printed Destroying Engine... and then hung — the next iteration (UCCL WRITE VRAM→DRAM) never even printed its command line. The hang is inside the UCX/UCCL engine destructor (progress-thread join / draining pending requests), which is exactly the code PR #1906 ("derive nixlUcxThreadPoolEngine from nixlUcxThreadEngine") reorganizes. parallel --halt now,fail=1 waits on the stuck worker forever until Jenkins SIGTERMs the build.

Implicated commit: PR #1906 (commit [REDACTED:Hex High Entropy String], "Refactoring: derive nixlUcxThreadPoolEngine from nixlUcxThreadEngine"). Related prior fix in the same area: 0225cd5 (Eylon Eliyahu Krause, #1880, "ucx: fix infinite loop dropping pending requests on dedicated-thread exit").

File: src/plugins/ucx/ucx_backend.h:105-160 (the nixlUcxThreadEngine/nixlUcxThreadPoolEngine destructors and their nixlUcxThread progress-thread teardown) — inspect the corresponding ~nixlUcxThreadEngine() / ~nixlUcxThreadPoolEngine() and thread-stop logic in ucx_backend.cpp.

Suggested fix: Audit the refactored destructor/thread-shutdown path introduced by #1906. After deriving the shared base, the progress thread's stop-flag / join() (and request-draining loop touched by #1880) is very likely no longer signalled correctly for one engine variant, so the destructor blocks on join() forever. Ensure the base class fully stops and joins the nixlUcxThread (and drains pending reqs) before member teardown, add a bounded timeout/assert on thread join, and re-run the UCCL WRITE VRAM→VRAM ETCD case locally to reproduce the teardown hang. Do not raise the Jenkins time limit — that would only mask a real deadlock.

Related: PR #1906 (the change under test); PR #1880 (recent fix to UCX dedicated-thread exit infinite loop, same shutdown path).

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 63a43565-c68a-47a2-8a18-0dd74a02d3b7 in the triage console for the audit trail.

@iyastreb

Copy link
Copy Markdown
Contributor Author

/build

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-gpu · commit adac02f4

TL;DR: The "Run CPP tests" stage failed because CUDA could not initialize on the test node mizu04 (cuDeviceGetCount ... failed: initialization error), so UCX came up without CUDA support; the test harness flags the resulting "GPU detected but no UCX CUDA support" warning as exit code 42, failing 69/154 tests. Fix the node's CUDA/driver environment (or the container's GPU access) — this is an infrastructure issue, not a code bug.

Full analysis

Summary: Jenkins nixl-ci-gpu #2798 stage "Run CPP tests" (node 203/242) exited with code 42; 68 tests "passed" their assertions but were failed by the harness on an unexpected NIXL warning, and 1 test (HardwareWarningTest.NoWarningWhenIbAndCudaSupported) genuinely failed.

Root cause: CUDA failed to initialize inside the test container on mizu04. Every test logs cuda_ctx.c:52 UCX ERROR cuDeviceGetCount(&num_devices) failed: initialization error, so UCX reports no UCS_MEMORY_TYPE_CUDA support. nixlUcxContext::warnAboutHardwareSupportMismatch() then emits "8 NVIDIA GPU(s) were detected, but UCX CUDA support was not found! GPU memory is not supported." because the hardware probe still sees 8 GPUs. The CI harness treats any unexpected NIXL warning as failure (exit 42). The single hard failure, HardwareWarningTest.NoWarningWhenIbAndCudaSupported, throws Failed to create UCX context: No such device for the same reason — it requests ib,cuda transports that are unavailable when CUDA can't init. GPUs are physically present but the CUDA driver/runtime is not usable in the container (e.g., missing/mismatched driver, nvidia device not mapped into the enroot/pyxis container, or MPS/driver state on the node).

Implicated commit: unknown — no code regression identified; evidence points to node/container CUDA environment on mizu04. (Prior CUDA-context change [REDACTED:Hex High Entropy String] "PLUGINS/UCX: Removed CUDA context management" is worth ruling out but is not supported as the cause by these logs.)

File: src/plugins/ucx/ucx_utils.cpp:639 (warning emitter); genuine failure originates from HardwareWarningTest.NoWarningWhenIbAndCudaSupported requesting ib,cuda transports.

Suggested fix: Repair GPU access on the test node/container so cuDeviceGetCount succeeds — verify the NVIDIA driver on mizu04, confirm GPUs are exposed into the enroot/pyxis container (device mounts / NVIDIA_VISIBLE_DEVICES), and confirm driver/CUDA-toolkit versions are compatible with the cuda13.3 base image. Re-run the build once CUDA initializes; if the node genuinely lacks CUDA, the test suite should be run on a properly provisioned GPU node rather than raising any timeout. Do not treat the exit-42 warnings as a code defect until the same tests are shown to fail on a node with working CUDA.

Related: none found.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 37228b01-a4dc-4623-94d9-29f5e73a313f in the triage console for the audit trail.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-gpu · commit a59b072e

TL;DR: The GPU node mizu02 was in a degraded state: ucx_backend_test aborted with a UCX-fatal failed to arm iface: Input/output error (an RDMA async-event I/O fault) mid-VRAM-test, and the sibling v1.22.x stage couldn't even start its container due to nvidia-container-cli ... nvml error: unknown error. This is a node/environment failure, not a code regression — retry on a healthy node and quarantine mizu02.

Full analysis

Summary: "Run CPP tests" stages failed on GPU node mizu02ucx_backend_test core-dumped (exit 134) and the v1.22.x container failed to start (NVML unknown error).

Root cause: Node-level GPU/RDMA fault on mizu02. Stage 203 crashed at ucp_worker.c:669 Fatal: failed to arm iface 0x555555c2f010: Input/output error during the intra-agent VRAM READ test — a UCX-internal I/O error arming the InfiniBand interface's async-event fd, not a test-logic error. Stage 262 on the same node failed even earlier at container init with nvidia-container-cli: detection error: nvml error: unknown error / 98-nvidia.sh exited with return code 1. Both symptoms (RDMA arm I/O error + NVML unknown error) indicate the driver/GPU/HCA stack on mizu02 was unhealthy. Log timestamps show continuous ~1s-per-iteration progress right up to the abort (no multi-minute gaps), so this is a crash, not a hang or a timeout.

Implicated commit: None. The failing test test/unit/plugins/ucx/ucx_backend_test.cpp is unchanged since Feb 2026; the only recent UCX-plugin change (#1846 ucx_ep_close_force) is gated behind a param defaulting to false and is unrelated to arming an iface mid-transfer. This is an infrastructure failure on mizu02, not PR #1906.

File: Environmental — src/plugins/ucx/ucx_backend.cpp runs fine; failure is in UCX runtime ucp_worker.c:669 on node mizu02 (.gitlab/test_cpp.sh:87 invoking ./bin/ucx_backend_test).

Suggested fix: Retry the build on a healthy GPU node and drain/reboot mizu02 (its NVIDIA driver/NVML and mlx5 HCA async-event path are faulted). If the crash reproduces on healthy hardware, collect the core dump per docs/DebugCoreDumps.md and re-triage; do not raise timeouts (this is a crash, not slowness).

Related: none found (issue/PR search returned no matches for the UCX arm-iface error).

@iyastreb
iyastreb merged commit 209abbe into ai-dynamo:main Jul 17, 2026
18 checks passed
@iyastreb
iyastreb deleted the iyastreb/ucx-thread-refactoring branch July 17, 2026 03:43
nv-nmailhot pushed a commit that referenced this pull request Aug 3, 2026
…- v1.4.0 (#2012)

## What?
Backport #1906 to v1.4.0

To unify the code and reuse the same functions
It's pre-requisite for completions API PR


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Added configurable UCX shared and dedicated worker threading.
* Added optional CUDA, Torch, Infinia DDN, and UCX plugin build
configuration.
  * Added pre-built wheel-base image support for faster wheel builds.
  * Added container build verification coverage for multiple platforms.
  * Updated project and package version to 1.4.0.

* **Documentation**
* Updated CI workflow, wheel-building, caching, and image-tag
documentation.
  * Added NVIDIA proprietary licensing attribution.

* **Chores**
* Added NVIDIA license information and updated third-party component
notices.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants