Skip to content

CI: Jenkins integration testing (do not merge) - #12094

Draft
Alexey-Rivkin wants to merge 155 commits into
openucx:masterfrom
Alexey-Rivkin:ci-jenkins-integration
Draft

Alexey-Rivkin wants to merge 155 commits into
openucx:masterfrom
Alexey-Rivkin:ci-jenkins-integration

Conversation

@Alexey-Rivkin

Copy link
Copy Markdown
Contributor

What?

Test-only branch that combines the open Jenkins CI drafts (#11173, #11471, #11469, #11491) on top of master.

Why?

Validate all Jenkins (Blossom) jobs together as part of the Azure to Jenkins migration. Jenkins only fetches openucx refs, so the branch needs a PR. Not for merge: each draft lands on its own.

How?

  • Changes go back to the owning draft PR.
  • Close this PR once all drafts are merged.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
Gtest failures when running in k8s env, as unlimites
max_threads cause resource exhaustion. Setting the CPU
affinity will limit max_threads to 2 dynamically.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
Run RoCE first, then IB.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
RoCE on Blossom hits a crash in rdma_get_cm_event during
test_ucp_sockaddr.ep_query that doesn't reproduce on Azure RoCE.
Land IB (CX8) coverage first; RoCE will return in a separate PR
after the rdmacm path is triaged.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
Run RoCE first, then IB.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
PR openucx#11161 introduced an adaptive NPROC cap in common.sh to avoid
OOM on k8s nodes where `nproc` reports the full host. Two
Jenkins-invoked spots still called `nproc` directly; switch them
to ${NPROC} so they honor the cap.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
The OSS dispatcher already aborts the prior dispatcher build for the same
PR, but the 8 leaf jobs it spawned via `build job: ..., wait: true` keep
running until they finish naturally. That ties up build executors every
time someone pushes a new commit to a PR.

Port the pattern NIXL uses: scrape each stale dispatcher's console log
for `Starting building: <name> #<num>` lines to find its children, kill
the leaves first so the dispatcher's wait unblocks, then kill the
dispatcher. Use `doKill()` instead of `doStop()` for a hard stop, and
retry up to 3 times with a 5s gap so builds caught mid-startup still get
torn down.

Failures inside the abort block are still swallowed and logged - we
never want stale cleanup to break a fresh build.
Lets the stale-build cleanup in Jenkinsfile.dispatcher be tested on the live dispatcher before it merges. Revert to master once validated.
@svc-nvidia-pr-review

Copy link
Copy Markdown

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

@svc-ucx

svc-ucx commented Oct 15, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX-OSS/ucx-test-oss · commit be0fa8b5

TL;DR: Build #48 was manually cancelled by a user ~24 s into the "Checkout source code" stage — there is no product or test failure to fix; just re-run the build.

Full analysis

Summary: The only stage in the pipeline, "Checkout source code", ended in state aborted after 24.2 s; the checkout step's git fetch was interrupted by a human cancellation.

Root cause: Not a code defect. The whole-build log shows the explicit marker Aborted by Alexey Rivkin immediately after the second git fetch --tags --force --progress --depth=100 ... +refs/pull/*:refs/remotes/origin/pr/* line, followed by org.jenkinsci.plugins.workflow.steps.FlowInterruptedException: Aborted by arivkin@nvidia.com and Calling Pipeline was cancelled / Finished: ABORTED. The java.lang.InterruptedException in GitSCM.fetchFrom is the consequence of that abort (Jenkins interrupting the remoting call), not a git or network error — note the stage even printed Retrying after 10 seconds, meaning the SCM retry logic was still healthy when the pipeline was torn down. The upstream dispatcher (UCX-OSS/ucx-dispatcher-oss #13, also started manually by the same user) was cancelled, which cascaded the cancellation to this child job. Timeline supports this: 24 s total with no multi-minute gap, so this was neither a hang nor a timeout.

Implicated commit: unknown — commit [REDACTED:Hex High Entropy String] (merged as [REDACTED:Hex High Entropy String]) was never built; the job died before any source was checked out, so no UCX code was compiled or executed.

File: unknown — no UCX source file was reached (failure occurred in .ci/jenkins/Jenkinsfile.github at the checkout scm step of the "Checkout source code" stage).

Suggested fix: No code change required. Re-trigger UCX-OSS/ucx-dispatcher-oss for PR #12094 and let it run to completion, then triage the real result. Two optional CI hygiene improvements, both unrelated to this abort: (1) the checkout fetches +refs/pull/*:refs/remotes/origin/pr/* for the entire openucx/ucx repo on every build — restricting the refspec to the single PR ref being tested would cut clone time substantially and reduce the window in which an abort looks like a checkout error; (2) since the job is marked No credentials specified for an https clone of a public repo, nothing is broken, but treat the aborted state as distinct from failed in any CI alerting/polling so user cancellations don't page as build breakages.

Related: PR #12094 (branch ci-jenkins-integration); upstream trigger UCX-OSS/ucx-dispatcher-oss build #13.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 0d3090c5-a9e8-4190-b548-1f3ad99289f4 in the triage console for the audit trail.

@svc-ucx

svc-ucx commented Oct 15, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX-OSS/ucx-coverity-oss · commit be0fa8b5

TL;DR: The build didn't fail on a code or test problem — it was manually aborted by the user (arivkin@nvidia.com) ~14 seconds into configure, so both Coverity matrix branches got SIGINT and the pipeline ended as ABORTED. No fix is needed in UCX; just re-run the job.

Full analysis

Summary: UCX-OSS/ucx-coverity-oss #16 ended as ABORTED — both parallel branches (x86_64/cov/release and x86_64/cov/devel) were interrupted during contrib/configure-{release,devel}, before cov-build ever ran.

Root cause: Human cancellation, not a product or CI-script defect. The whole-build log contains, at 09:25:02:

  • Aborted by Alexey Rivkin
  • Calling Pipeline was cancelled
  • ERROR: parallel task failed with msg: hudson.AbortException: Coverity failed with msg: Step Coverity failed with exit code=null exception=org.jenkinsci.plugins.workflow.steps.FlowInterruptedException: Aborted by arivkin@nvidia.com
  • Finished: ABORTED

Timestamp analysis rules out a hang or timeout: the stage started at 09:24:49/09:24:58 and the interrupt arrived at 09:25:02 — ~4–14 s of execution with continuous, gap-free output (module loads → autogen.sh → configure progressing normally, last line checking whether make sets $(MAKE)... / checking build system type...). The stage timeout was set to 30 min and had barely started, so neither the 30-min stage timeout nor an outer build timeout was involved. The exit code=null and "Sending interrupt signal to process / Killing processes" lines are the Jenkins abort mechanism, downstream symptoms of the cancellation.

The Coverity and Coverity end stages are reported as failure only because the parallel branch rethrows the FlowInterruptedException as an AbortException; there is no Coverity defect report (cov_error_log.txt was never produced, since cov-build/cov-analyze in buildlib/tools/coverity.sh:101-107 were never reached).

Implicated commit: none — [REDACTED:Hex High Entropy String] (branch ci-jenkins-integration, PR #12094 "CI: Jenkins integration testing (do not merge)") was not exercised far enough to be implicated.

File: no source file at fault; abort surfaced at buildlib/tools/coverity.sh:88 (configure_coverity → contrib/configure-devel)

Suggested fix:

  1. Simply re-trigger the job (/build on PR CI: Jenkins integration testing (do not merge) #12094) — there is nothing to fix in UCX or the CI scripts for this run. Treat this build as non-signal when evaluating the Jenkins migration.
  2. Optional CI-ergonomics improvement: in the pipeline's parallel/Coverity wrapper, distinguish FlowInterruptedException from real step failures and mark the branch ABORTED/NOT_BUILT instead of failure, so user cancellations don't look like Coverity defects in the stage view and don't page triage.
  3. Security, unrelated to the failure but urgent: the env dump printed by prepare_build (buildlib/tools/coverity.sh:131 → common.sh) emits the full githubData blob into the public console log, including an artifactory_token basic-auth credential and the Artifactory server URL. Rotate that Artifactory credential and stop dumping githubData (unset/scrub it before env, or mask it via Jenkins credentials binding) — set -x plus env in prepare_build makes every build leak it.

Related: PR #12094 (openucx/ucx, the "do not merge" Jenkins integration branch under test); umbrella drafts referenced by it: #11173, #11471, #11469, #11491. Last functional changes to the Coverity matrix: [REDACTED:Hex High Entropy String] "CI: reduce CPU requests in all CI pipelines (#11494)" (NirWolfer) and a346463 "CI: Jenkins/Gitlab integration - phase 1 (#11113)" (Alexey Rivkin) — neither is implicated here.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 2f220544-9708-4250-8da9-95688f0f3829 in the triage console for the audit trail.

@svc-ucx

svc-ucx commented Oct 15, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX-OSS/ucx-build-static-oss · commit be0fa8b5

TL;DR: This build wasn't a real test/code failure — it was manually aborted by a human ("Aborted by Alexey Rivkin") ~13 s into the configure step, which killed both parallel matrix branches. No fix is needed for the build itself; just re-run it (but there are two genuine latent issues found in the log worth fixing separately).

Full analysis

Summary: UCX-OSS/ucx-build-static-oss #15 ended in ABORTED: both parallel branches (x86_64/centos7-ib and x86_64/ubuntu2004-mofed5.0) were interrupted mid-configure by a user-initiated cancellation.

Root cause: Manual pipeline cancellation, not a product or test defect. Evidence from the whole-build log:

  • 09:24:57 — contrib/configure-devel --prefix=/root/15/build/install starts on both agents.
  • 09:25:01.750 — Aborted by Alexey Rivkin
  • 09:25:01.751 — Sending interrupt signal to process / Killing processes
  • 09:25:02.432 — checking compiler flag -Wno-unused-parameter... Terminated
  • Calling Pipeline was cancelled → FlowInterruptedException
  • Final: ERROR: parallel task failed with msg: ... Step Build Static failed with exit code=null exception=...FlowInterruptedException: Calling Pipeline was cancelled / Finished: ABORTED

This is not a timeout or hang. Stage durations were 16 s and 25 s, log lines are continuous with sub-second gaps (largest gap < 1 s) right up to the kill, and the kill message names a human actor rather than a time limit. The Build Static stages are reported as failure only because the Jenkins parallel/error wrapper converts the interrupt into a stage failure — a reporting artifact of the abort.

Two real (but non-fatal, pre-existing) defects are visible in the same log and are worth separate fixes:

  1. Shell error in configure: configure: line 27021: test: : integer expression expected. This is config/m4/rocm.m4:112, AS_IF([test "$hip_version" -ge 70000000], ...). hip_version is only ever assigned inside the AS_IF([test "x$rocm_happy" = "xyes"], ...) block at lines 101–110, but the comparison at line 112 sits outside that guard. On any node without ROCm (both nodes here logged configure: WARNING: ROCm not found), $hip_version is empty and the test errors out. Harmless today, but it masks real errors and would break under set -e.

  2. Credential exposure: the githubData= environment dump at the top of the Build Static stage log prints the full webhook payload including an artifactory_token value (a base64 basic-auth credential for the internal artifact log store). This is written to a Jenkins console that is readable by anyone with job access. That token should be rotated and the payload dump should be scrubbed or the token injected via Jenkins credentials binding (which masks it) instead of being echoed with env.

Implicated commit: None for the abort (operator action, not a commit). For the configure shell error: 27acabdb — "UCT/ROCM: adjust hsa memory type check for new rocm releases (#11236)", Manu Shantharam, 2026-03-07.

File: Abort: no source file — Build Static stage, build #15 console. Latent bug: config/m4/rocm.m4:112 (guard missing; hip_version set only at config/m4/rocm.m4:101-110).

Suggested fix:

  1. For this failure: no code change — re-trigger the build (re-comment /build on PR CI: Jenkins integration testing (do not merge) #12094). Treat fix distcheck #15 as a non-signal run.
  2. Harden the abort reporting so operator cancellations surface as ABORTED rather than a failure stage, e.g. catch FlowInterruptedException in the parallel branch wrapper and re-throw it unchanged instead of wrapping it in hudson.AbortException. This avoids triaging human cancels as build breakage.
  3. Fix the configure error by initializing the variable before use or moving the check inside the ROCm guard:
    rocm_happy=no
    hip_happy=no
    hip_version=0        # add this
    or fold lines 112–114 into the existing AS_IF([test "x$rocm_happy" = "xyes"], ...) block that ends at line 110.
  4. Rotate the Artifactory token that is printed in the stage log and stop dumping the raw webhook payload to the console; pass it through Jenkins credentials so it is automatically masked.

Related: PR #12094 ("CI: Jenkins integration testing (do not merge)") — the test-only branch under validation; rocm.m4 change PR #11236.

Comment thread .ci/jenkins/proj_jjb_oss.yaml Outdated
- git:
url: "https://github.com/openucx/ucx.git"
branches: [ 'master' ]
branches: [ 'origin/pr/12094/head' ]

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 dispatcher job's pipeline SCM branch is pinned to this PR's head instead of master. This file is "applied by DevOps to Jenkins", so merging it would make the production dispatcher permanently load Jenkinsfile.dispatcher from PR 12094.

Suggested change
branches: [ 'origin/pr/12094/head' ]
branches: [ 'master' ]

Leftover from testing — the dispatcher must load the Jenkinsfile from master.

Comment thread .ci/pipeline/test_matrix.yaml Outdated
run: |
./contrib/test_jenkins.sh
# Limit tests to 2 CPUs to prevent max_threads exhaustion in k8s (similar to Azure CPU affinity)
allowed_cpus=$(awk '/^Cpus_allowed_list:/ {print $2}' /proc/self/status)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pinning derives CPUs from a host-wide mask: unless the kubelet runs the static CPU manager policy, Cpus_allowed_list in a pod is the full host range (e.g. 0-127), so first_chunk is the whole range and every one of the 8 worker pods (2 images × 4 workers) pins itself to the same CPUs 0-1 and contends for them. Can we offset the slice by ${worker}, or rely on the cgroup CPU quota instead?

Comment thread .ci/pipeline/test_matrix.yaml Outdated
arch: x86_64,
tolerations: "[{key: 'node.kubernetes.io/unschedulable', operator: 'Exists', effect: 'NoSchedule'}]",
annotations: [{ key: "k8s.v1.cni.cncf.io/networks", value: "sriov-cx7-p2" }],
limits: "{memory: 16Gi, cpu: 10000m, nvidia.com/sriov_cx7_p2: 1}",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Requests 10 CPUs but uses 2: limits/requests ask for cpu: 10000m per pod while the step pins all work (including make -j) to at most 2 CPUs, over-reserving the node by 8 CPUs per pod. Can we lower the request so the nodes are not over-reserved?

RUN_TESTS: "yes"
TEST_PERF: "0"
ASAN_CHECK: "no"
VALGRIND_CHECK: "no"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ASAN_CHECK removed without explanation. contrib/test_jenkins.sh documents ASAN_CHECK as a job input and branches on it; it still works because the script does not use set -u, but every other matrix (test_gpu_matrix.yaml, test_dl_matrix.yaml) sets it explicitly. Why remove it?

Comment thread .ci/jenkins/Jenkinsfile.dispatcher Outdated
if (!alive) break
alive.each { target ->
echo "${attempt > 1 ? 'Retry ' + attempt + ': ' : ''}Killing ${target.fullDisplayName}"
target.doKill()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

doKill() skips the leaf job's finally: Jenkinsfile.github updates the GitHub commit status and uploads logs in a finally block. A hard doKill() bypasses it, so the killed leaf jobs leave their per-job status stuck at "CI started". Please call doStop() first and use doKill() only if the build is still alive.

// Collect leaf builds from each stale dispatcher's console log
def leafBuilds = []
staleBuilds.each { b ->
b.getLog(1000).each { line ->

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Leaf builds found by scraping console text: Run.getLog(1000) returns only the tail of the log, while the Starting building: lines are printed at the very beginning of the dispatcher run, so a verbose run silently finds no leaf builds. Why not find leaf builds by their githubData/VARIABLE_FROM_POST parameter, like the dispatcher matching above, instead of parsing the console log?

Comment thread contrib/test_jenkins.sh
# Each thread requires 5MB. Cap threads number by total available shared memory.
max_threads=$(df /dev/shm | awk '/shm/ {printf "%d", $4 / 5000}')
num_threads=$(($max_threads < $(nproc) ? $max_threads : $(nproc)))
num_threads=$(($max_threads < ${NPROC} ? $max_threads : ${NPROC}))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

NPROC is larger than the pinned CPU count: with the new taskset, nproc returns 2 inside the step, while NPROC from buildlib/tools/common.sh is memory-derived (16 for the 16Gi limit). So for this job the change raises num_threads from 2 to 16, which works against the stated goal of bounding max_threads. Is raising the thread count intended?

Comment thread .ci/pipeline/test_matrix.yaml Outdated
timeout: "${STEP_TIMEOUT_MINUTES}"
run: |
./contrib/test_jenkins.sh
# Limit tests to 2 CPUs to prevent max_threads exhaustion in k8s (similar to Azure CPU affinity)

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: This comment and the one on line 62 state the same thing; one is enough.

@svc-nvidia-pr-review

Copy link
Copy Markdown

Per REVIEW.md the CI-change rule asks for evidence that the stated CI behavior changed as intended. Please link a dispatcher run showing stale leaf jobs actually aborted, and a hca-ib/hca-roce run showing the new pods get their SR-IOV devices — the new tolerations, annotations, caps_add, and resource keys cannot be validated from the repository alone.

@svc-ucx

svc-ucx commented Oct 15, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX-OSS/ucx-codestyle-oss · commit be0fa8b5

TL;DR: Build #15 was not a real codestyle failure — the Ctags stage was killed by SIGTERM ("Aborted by Alexey Rivkin") 27 s into the job while vim was resolving the second tag, because a newer dispatcher run for PR #12094 executed the new stale-build kill logic in .ci/jenkins/Jenkinsfile.dispatcher; the fix is to make the dispatcher/leaf jobs distinguish an abort from a failure instead of reporting FAILURE.

Full analysis

Summary: UCX-OSS/ucx-codestyle-oss #15 ended ABORTED with the Ctags stage marked failure after the running vim tag-lookup process received an interrupt/TERM signal.

Root cause: The stage log shows normal, expected progress: ctags generated tags, tag_not_found failed as intended (E426: tag not found → failures='|tag_not_found'), and ucp_tag_send_nbx resolved correctly to src/ucp/tag/tag_send.c. Immediately after, the whole-build log shows Aborted by Alexey Rivkin → Sending interrupt signal to process → Killing processes, and vim: Caught deadly signal TERM. The loop in test_ctags.sh runs with set +e, so the TERM-killed vim just left the stage with a non-zero exit, which Jenkins rendered as Ctags: failure and Parallel: aborted, ending in Finished: ABORTED / "parallel task failed with msg: ... Calling Pipeline was cancelled". There are no large timestamp gaps (whole run is ~27 s, lines continuous), so this is not a hang or a timeout — it is an external abort. The abort source is the newly added stale-dispatcher cleanup block (Jenkins.instance...doKill() on leaf builds collected via the Starting building: (\S+) #(\d+) regex), which a newer dispatcher run for the same PR used to kill this leaf build. The dispatcher then unconditionally posts GitHubCommitState.FAILURE in its catch(Exception ex) block, so a deliberately-killed stale run is reported to GitHub as a CI failure rather than as aborted.

Secondary (cosmetic, not the failure): ctags: Warning: cannot open source file "src/uct/ib/mlx5/gdaki/gpunetio" — the gpunetio headers listed in src/uct/ib/mlx5/gdaki/Makefile.am:33-37 are absent because the codestyle job intentionally does not fetch submodules; ctags still exits 0 and the tags file was produced.

Implicated commit: bfc4886 "CI: Kill leaf jobs when aborting stale PR dispatchers" (Alexey Rivkin), on top of feec90b "CI: Extract dispatcher pipeline into Jenkinsfile" (Noam Tsemah)

File: .ci/jenkins/Jenkinsfile.dispatcher:47-55 (leaf doKill() loop) and .ci/jenkins/Jenkinsfile.dispatcher:91-94 (unconditional FAILURE status); symptom surfaces at buildlib/tools/test_ctags.sh:30

Suggested fix:

  1. In .ci/jenkins/Jenkinsfile.dispatcher, don't report FAILURE for aborts — catch the interruption separately:
    } catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException fie) {
      echo "Dispatcher aborted (superseded or user abort); not updating commit status"
      currentBuild.result = 'ABORTED'
      throw fie
    } catch (Exception ex) { ... existing FAILURE path ... }
    Also check currentBuild.rawBuild.getAction(InterruptedBuildAction) / result before the updateCommitStatus(..., FAILURE) call so a killed stale run leaves the pending status alone (or sets it back to PENDING for the new run).
  2. Make the kill path explicit so these builds show as ABORTED, not FAILURE: set currentBuild.result = 'ABORTED' in the leaf matrix wrapper when the stage is terminated by a signal, and/or have test_ctags.sh detect signal exits (rc -ge 128) and exit $rc instead of recording them in failures:
    rc=$?
    if [[ $rc -ge 128 ]]; then echo "vim killed by signal $((rc-128)); aborting"; exit $rc; fi
    if [[ $rc -ne 0 ]]; then failures="$failures|$tag"; fi
  3. Optional cleanup: silence the misleading gpunetio ctags warning by excluding the un-fetched submodule path in contrib/ctags.sh (--exclude=src/uct/ib/mlx5/gdaki/gpunetio).
  4. Re-run build fix distcheck #15 for commit be0fa8b to get a clean verdict — nothing in the log indicates an actual codestyle violation.

Related: #11491 (CI: kill leaf jobs when aborting stale PR dispatchers), #11796 (CI: Replace Blue Ocean with pipeline-overview URL), PR #12094 (this build's PR)

@svc-ucx

svc-ucx commented Oct 15, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX-OSS/ucx-test-gpu-oss · commit be0fa8b5

TL;DR: Build #20 wasn't a product/test failure — it was externally aborted ("Aborted by Alexey Rivkin") ~7 s into the Parallel stage while its four build_helper_ucx workers were still waiting for Kubernetes pods that couldn't be created because the nbu-swx-ucx namespace CPU quota was fully consumed (399.4 of 400 cores). Re-run the job once the namespace drains, and reduce the per-worker CPU request / fanout width so 8 fanned-out leaf jobs don't oversubscribe a 400-core quota.

Full analysis

Summary: UCX-OSS/ucx-test-gpu-oss #20 finished ABORTED — all four parallel branches x86_64/build_helper_ucx/w0..w3 failed with FlowInterruptedException: Calling Pipeline was cancelled after an external abort, against a backdrop of exhausted k8s resource quota.

Root cause: Two interacting infrastructure issues, no UCX code defect:

  1. External abort (direct cause of ABORTED). Stage 82 Parallel ran only 7072 ms before the console shows Aborted by Alexey Rivkin, immediately followed by Failed in branch x86_64/build_helper_ucx/w0..w3 and Calling Pipeline was cancelled. The four branches had only reached [Pipeline] node — they never started any build or test work, so nothing in the product was exercised. This is consistent with the dispatcher's stale-build reaper (target.doKill() at .ci/jenkins/Jenkinsfile.dispatcher:52), which kills leaf builds of earlier dispatcher runs for the same PR; PR CI: Jenkins integration testing (do not merge) #12094 is an active integration-testing PR being repeatedly pushed, and HEAD commit be0fa8b5 makes the dispatcher load from that PR.

  2. Kubernetes CPU quota exhaustion (why the workers had no agents to run on). Pod creation repeatedly failed: pods "ucx-test-gpu-buildhelperucx-20-fwk27-*" is forbidden: exceeded quota: resourcequota-nbu-swx-ucx, requested: cpu=4500m, used: cpu=399400m, limited: cpu=400, plus Still waiting to schedule task / All nodes of label 'UCX-OSS_ucx-test-gpu-oss_20-8122v' are offline. The namespace was at 399.4/400 cores. The dispatcher fans out 8 leaf jobs in parallel (.ci/jenkins/Jenkinsfile.dispatcher:67-89), and this job alone requests 4 workers × 4500m ≈ 18 cores, so concurrent dispatcher runs trivially saturate the quota. Note the quota showed ~399 cores used even as this build's pods were being rejected — strongly suggesting agent pods from aborted/stale builds are not being reclaimed, i.e. the kill logic terminates Jenkins builds but leaks their pods.

Secondary, non-fatal noise worth cleaning up: docker manifest inspect fails under podman with Treating single images as manifest lists is not implemented (stage 47 falls back to podman search --list-tags, so it recovers), podman system reset -f errors with unlinkat /var/lib/containers/storage: device or resource busy, and Jenkins warns Did you forget the 'def' keyword? Matrix seems to be setting a field named image ... could lead to memory leaks — an unscoped image variable in the matrix job script.

Implicated commit: [REDACTED:Hex High Entropy String] — Alexey Rivkin, "CI: Load the dispatcher from the integration PR (temporary)"; the kill behavior itself comes from bfc4886a — Alexey Rivkin, "CI: Kill leaf jobs when aborting stale PR dispatchers"

File: .ci/jenkins/Jenkinsfile.dispatcher:46-55 (leaf-kill loop) and .ci/jenkins/Jenkinsfile.dispatcher:67-89 (8-way fanout)

Suggested fix:

  1. Don't treat this as a code regression — re-trigger the build. No test ever ran; there is nothing to bisect in UCX source.
  2. Make the kill logic reclaim pods. After target.doKill(), the Kubernetes agent pods survive and keep holding quota. Add explicit cleanup of pods labelled with the killed build (the pod template already stamps jenkins/label and the buildUrl annotation), or set podRetention: never() plus a short idleMinutes/activeDeadlineSeconds on the pod template so orphans self-expire.
  3. Stop oversubscribing the quota. 8 parallel leaf jobs × multi-worker fanout × 4500m exceeds the 400-core namespace limit. Either throttle the dispatcher fanout (Jenkins lock/throttle or batch the parallel map), lower the 4000m request/limit in the GPU pod template, or reduce the w0..w3 worker count.
  4. Fail fast and legibly on quota exhaustion instead of retrying into a timeout — the retry around node currently burns the build on 403s. Detect exceeded quota and surface it as an infra error.
  5. Low-priority cleanups: drop the docker manifest inspect probe (or use skopeo inspect / go straight to podman search --list-tags) since it always errors under podman; ignore the benign podman system reset unmount error; and add def to the image variable in the matrix job script to silence the memory-leak warning.

Related: PR #12094 (CI: Jenkins integration testing — do not merge), PR #11491 (CI: kill leaf jobs when aborting stale PR dispatchers), PR #11796 (CI: Replace Blue Ocean with pipeline-overview URL)

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 50ecc9b0-588f-4f7b-bda4-7942a29b9934 in the triage console for the audit trail.

Holding Run objects or a JsonSlurper across the retry sleep breaks the pipeline state checkpoint, so targets are kept as job name and build number pairs, as in NIXL. Leaf jobs live in the UCX-OSS folder and are logged as 'UCX-OSS » <job>', which the NIXL regex does not match, so the display path is mapped back to the full job name.
@svc-nvidia-pr-review

Copy link
Copy Markdown

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

Comment thread .ci/jenkins/proj_jjb_oss.yaml Outdated
- git:
url: "https://github.com/openucx/ucx.git"
branches: [ 'master' ]
branches: [ 'origin/pr/12094/head' ]

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 — dispatcher SCM pinned to this PR's branch. This is a debug pin that must be reverted before merge; the file is applied by DevOps to Jenkins, so the dispatcher would permanently load Jenkinsfile.dispatcher from PR #12094 instead of master. Suggested: branches: [ 'master' ]

if (!alive) break
alive.each { t ->
echo "${attempt > 1 ? 'Retry ' + attempt + ': ' : ''}Killing ${t[0]} #${t[1]}"
Jenkins.instance.getItemByFullName(t[0])?.getBuildByNumber(t[1])?.doKill()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

doKill() skips pipeline cleanup. doKill() is Jenkins' hard kill and does not run post/finally sections. Two concrete consequences:

  • pipeline_stop in test_gpu_matrix.yaml and test_dl_matrix.yaml releases the Slurm allocations (SLURM_JOB_TIMEOUT: '02:45:00' / '03:20:00'); hard-killing the leaf leaks the allocation and the /mnt/pvc/job_id_* file until the Slurm timeout expires, holding funk/gb200nvl72_ci nodes.
  • Hard-killing the stale dispatcher skips its catch block, so updateCommitStatus(... FAILURE) never runs and the PR keeps a stale "Blossom CI started" pending status.

Can we doStop() on the first attempts and only doKill() on the last one?

// path is mapped back to the "UCX-OSS/<job>" full name.
def targets = []
staleBuilds.each { b ->
b.getLog(1000).each { line ->

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Leaf discovery via console-log scraping is fragile. Run.getLog(1000) returns only the tail of the log, so the Starting building: lines (emitted at the very beginning of the parallel fanout) can fall out of the window and the leaves will silently survive. The match also depends on the " » " display-name format. Instead of parsing the console log, can we locate the leaf builds via their UpstreamCause (upstream project + build number)?

Comment thread contrib/test_jenkins.sh
# Each thread requires 5MB. Cap threads number by total available shared memory.
max_threads=$(df /dev/shm | awk '/shm/ {printf "%d", $4 / 5000}')
num_threads=$(($max_threads < $(nproc) ? $max_threads : $(nproc)))
num_threads=$(($max_threads < ${NPROC} ? $max_threads : ${NPROC}))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

NPROC ignores the CPU affinity mask. NPROC from buildlib/tools/common.sh is derived from the cgroup memory limit (16Gi → 16), not from the affinity mask. With the new taskset -c 0-1 wrapper, /dev/shm in a pod is typically 64MB → max_threads ≈ 13, so test_init_mt now runs ~13 threads on 2 CPUs, whereas plain nproc (affinity-aware) returned 2. This works against the stated goal of the pinning in test_matrix.yaml. Pls cap by the number of allowed CPUs.

Comment thread .ci/pipeline/test_matrix.yaml Outdated
fi

echo "Running test_jenkins.sh with CPU affinity: ${cpu_set} (allowed: ${allowed_cpus})"
taskset -c "${cpu_set}" ./contrib/test_jenkins.sh

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Whole script pinned to 2 CPUs while the pod requests 10. taskset wraps all of test_jenkins.sh, including build devel, $MAKEP, and the MPI/release builds, so every build in the job is confined to 2 cores even though requests/limits ask for cpu: 10000m. This is the likely reason timeout_minutes had to go 90 → 240. Why not bound the thread counts in the tests instead and let the build use the requested CPUs?

Comment thread .ci/pipeline/test_matrix.yaml Outdated
./contrib/test_jenkins.sh
# Limit tests to 2 CPUs to prevent max_threads exhaustion in k8s (similar to Azure CPU affinity)
allowed_cpus=$(awk '/^Cpus_allowed_list:/ {print $2}' /proc/self/status)
first_chunk=${allowed_cpus%%,*}

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 — only the first CPU chunk is considered. With the k8s static CPU manager, Cpus_allowed_list is commonly a non-contiguous sibling pair (e.g. 3,67). first_chunk is then 3 with no -, so cpu_set becomes a single CPU, and slice_affinity 0/slice_affinity 1 in test_jenkins.sh return the same core for both client and server. Maybe count CPUs across all chunks instead of only the first one.

Every row ran build_mode=short, so long-mode checks (clang, gcc, no_devx, installed headers, soname) never ran, and without /hpc/local the CUDA, fuse and doxygen steps were skipped. Set the Azure build mode per image, mount /hpc/local, and add the rows Azure has and Jenkins lacked: centos7 with IB, rhel8.2 with GCC 15.2, the ZE null-driver build and ICC/PGI.
With the 64M container /dev/shm, mm iface chunk allocation fails (uct_mem.c:482 assertion). A RAM-backed /dev/shm fixes that but counts against the pod limit, and 16Gi pods get SIGKILLed mid-run, so pods get 32Gi. test_uct_peer_failure_multiple needs more contexts than a VF BAR allows and is excluded until the VF BAR is raised. /hpc/local provides the MPI modules for the MPI tests.
@svc-nvidia-pr-review

Copy link
Copy Markdown

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

Checks whether Blossom pods can pull UCX builder images through the Artifactory Harbor remote.
@svc-ucx

svc-ucx commented Oct 15, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX-OSS/ucx-build-static-oss · commit f7042d3f

TL;DR: Build #18 never got to compile — its Checkout source code stage couldn't resolve the SHA it was told to build (bb82a7ea, a GitHub PR merge commit) because the PR head advanced to f7042d3f while the build sat in the queue waiting for Kubernetes CPU quota, so GitHub recreated refs/pull/12094/merge and the old merge commit became unfetchable. Fix: dispatch the PR head SHA (or fetch refs/pull/<n>/merge explicitly and merge locally) and make the dispatcher's stale-build cleanup also cancel queued leaf builds.

Full analysis

Summary: UCX-OSS/ucx-build-static-oss #18 failed in the only stage, Checkout source code, with ERROR: Couldn't find any revision to build after 6 retries (189 s), aborting the pipeline before any build work.

Root cause: Evidence chain from the logs:

  1. The dispatcher (ucx-dispatcher-oss ../source/configure: line 15969: PKG_PROG_PKG_CONFIG: command not found #16) passed sha1 = [REDACTED:Hex High Entropy String], whose commit message is Merge [REDACTED:Hex High Entropy String]... into 8749d9219... — i.e. the ephemeral GitHub-generated merge commit for PR CI: Jenkins integration testing (do not merge) #12094, produced by githubHelper.getMergedSHA() (.ci/jenkins/Jenkinsfile.dispatcher:68).
  2. The lightweight @script checkout on the controller succeeded and resolved bb82a7ea — so the ref existed at dispatch time.
  3. The agent pod could not start for several minutes: repeated WARNING: Unable to create pod ... is forbidden: exceeded quota: resourcequota-nbu-swx-ucx, requested: cpu=100m, used: cpu=400, limited: cpu=400 (4 failed launches before Created Pod: ...-zp45h).
  4. By the time the workspace checkout ran, the PR head had moved on — git history shows 2d470cd3 (the merged parent in UCS/UCT: Fix issues found by coverity. #18) was superseded by 25bb37d4 and f7042d3f ("CI: Match Azure build modes…", "CI: Size gtest pods…", both 2026-10-15T09:53:50Z, Alexey Rivkin), the commit in this trigger's context. GitHub regenerated refs/pull/12094/merge, orphaning bb82a7ea.
  5. The job's refspec only fetches live refs (+refs/heads/*:... +refs/pull/*:refs/remotes/origin/pr/*) with --depth=100, so an unreferenced merge commit can never be retrieved — hence git rev-parse bb82a7ea^{commit} fails on every one of the 6 retries. Retrying is useless here; the object is gone.

Secondarily, the dispatcher's stale-build killer should have removed this zombie leaf: .ci/jenkins/Jenkinsfile.dispatcher:52-62 only acts on targets where getBuildByNumber(...)?.isBuilding() is true, and it harvests leaf build numbers by grepping Starting building: ... from the stale dispatcher log. Build #18 was queued/waiting for a pod, so it was skipped and left to fail.

This is a CI-infrastructure/race failure, not a UCX code defect.

Implicated commit: be0fa8b5 / 2d470cd3 (Alexey Rivkin, 2026-10-15, PR #12094) introduced the merge-SHA dispatch + stale-cleanup mechanism; the proximate trigger is f7042d3f (Alexey Rivkin) pushed while #18 was still queued.

File: .ci/jenkins/Jenkinsfile.dispatcher:68 (merge-SHA dispatch) and .ci/jenkins/Jenkinsfile.dispatcher:52-62 (stale-build kill loop)

Suggested fix:

  1. Stop dispatching the transient merge SHA. Either pass the PR head SHA (githubHelper.getPRHeadSHA() / issue.pull_request.head.sha) and let the leaf job merge against the target branch locally, or have leaf jobs check out the named ref refs/pull/12094/merge instead of a bare SHA so a regenerated merge ref resolves instead of 404-ing.
  2. If the merge SHA must be used, make the leaf checkout fetch it explicitly and unshallow-tolerantly, e.g. git fetch origin +refs/pull/<n>/merge:refs/remotes/origin/pr/<n>/merge with no --depth, and treat an unresolvable SHA as NOT_BUILT/aborted rather than FAILURE so superseded runs don't post red statuses.
  3. Extend the stale cleanup to cancel queued items, not just running ones — scan Jenkins.instance.queue.items for leaf jobs carrying the same githubData/PR number and queue.cancel(item), in addition to the isBuilding() + doKill() path.
  4. Independently, raise or review resourcequota-nbu-swx-ucx (CPU pinned at the 400 limit) — the multi-minute queue wait is what widened the race window.

Related: PR #12094 — "CI: Jenkins integration testing (do not merge)" (#12094)

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 0246995a-94bf-4388-970c-2679f83552b5 in the triage console for the audit trail.

TEST_PERF: "0"
ASAN_CHECK: "no"
# MPI test_memhooks loops on a debug.c assert with the lab HPC-X (Open MPI 5).
RUN_MPI_TESTS: "no"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

all four gtest matrices (test, gpu, dl, bf) set RUN_MPI_TESTS=no, so run_mpi_tests - and the make installcheck inside it - never runs in the new CI. can we keep it enabled on at least one row? the /hpc/local mount above is commented as being there for the MPI tests.

refspec: "+refs/heads/*:refs/remotes/origin/* +refs/pull/*:refs/remotes/origin/pr/*"
browser: githubweb
browser-url: "https://github.com/openucx/ucx"
wipe-workspace: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

wipe-workspace: false (leaf template): JJB defaults wipe-workspace to true, so this keeps the previous build's tree in the workspace. steps that create fresh dirs then fail: mkdir build in test_bindings_matrix.yaml and git_clone_with_retry into ${WORKSPACE}/ucx_<tag> in test_wirecompat_matrix.yaml. why is it needed?

Comment thread .ci/scripts/cap_output.sh
if IFS= read -r -n 1 _; then
echo "ERROR: step output passed ${ci_output_cap} bytes" >&${ci_stdout}
fi) 2>&1
ci_output_pid=$!

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: bash sets $! for a process substitution only since 5.1, so ci_output_pid is empty on the centos7 / ubuntu18.04 images used by test_cuda_matrix.yaml and test_wirecompat_gpu_matrix.yaml; the EXIT loop breaks on the first kill -0, so the last lines it is meant to save are still lost there.

run: run
args:
jobIdFile: "${JOB_ID_FILE_ROOT}/job_id_gpuwc_${BUILD_NUMBER}.txt"
testScript: >-

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 is the same legacy-tag loop as test_wirecompat_matrix.yaml, rewritten as one line (and the non-GPU copy still carries dead != v1.14.0 checks). can we move the loop into a buildlib/tools/ script and call it from both? root AGENTS.md asks not to duplicate implementation patterns.

args:
jobIdFile: "${JOB_ID_FILE_ROOT}/job_id_jucx_${BUILD_NUMBER}.txt"
# Skip testMmapFile: it assumes 4K pages, GB200 uses 64K
testScript: &jucx_test 'set -xeE; source .ci/scripts/cap_output.sh; export JAVA_HOME=/usr/lib/jvm/$jucx_jdk; export PATH=/usr/lib/jvm/$jucx_jdk/bin:$(printenv PATH); ulimit -l unlimited; unset UCX_NET_DEVICES; source buildlib/az-helpers.sh; ifaces=$(get_rdma_interfaces); if [ -z "$ifaces" ]; then echo ERROR: No active RDMA interfaces on machine; exit 1; fi; jport=$((20000 + RANDOM % 10000)); export JUCX_TEST_PORT=$jport; export UCX_HANDLE_ERRORS=bt; jtests=$(cd bindings/java/src/test/java/org/openucx/jucx; ls Ucp*Test.java | grep -v UcpMemoryTest | sed s/.java// | paste -sd,); make -C bindings/java/src/main/native test MVN="mvn -Dtest=$jtests"; make -C bindings/java/src/main/native test MVN="mvn -Dtest=UcpMemoryTest#testGetRkey+testRemoteKeyUnpack+testExportedMkey"; make -C bindings/java/src/main/native package; ipv4_found=0; for iface in $ifaces; do sip=$(get_ip $iface); if [ -z "$sip" ]; then continue; fi; echo Running standalone benchmark on $iface:$jport; java -XX:ErrorFile=hs_err_%p.log -XX:OnError="cat hs_err_%p.log" -cp "bindings/java/resources/:bindings/java/src/main/native/build-java/*" org.openucx.jucx.examples.UcxReadBWBenchmarkReceiver s=$sip p=$jport t=1000000 & sleep 10; java -XX:ErrorFile=hs_err_%p.log -XX:OnError="cat hs_err_%p.log" -cp "bindings/java/resources/:bindings/java/src/main/native/build-java/*" org.openucx.jucx.examples.UcxReadBWBenchmarkSender s=$sip p=$jport t=1000000; wait; ipv4_found=1; done; if [ $ipv4_found -eq 0 ]; then echo ERROR: No IPv4 address on any of $ifaces; exit 1; fi'

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 JUCX build+test body now exists in three slightly different copies (here, test_bindings_matrix.yaml, test_bindings_gpu_matrix.yaml) on top of buildlib/jucx/jucx-test.yml. can we extract one script under buildlib/jucx/ that all rows call?

@svc-nvidia-pr-review

Copy link
Copy Markdown

Existing threads supported with +1 (not re-opened): the proj_jjb_oss.yaml branch pin to origin/pr/12094/head (blocker — confirmed against the base file, which uses master); PR size over the 500-added-line limit; ucx-test-namespace-gpu-oss registered in proj_jjb_oss.yaml but missing from the dispatcher leafJobs; build_matrix.yaml dropping build_mode: "short" from env:; timeout_minutes vs step timeouts and step timeouts vs SLURM_JOB_TIMEOUT; hostPID/hostIPC injected through the raw tolerations string; and build_sanity → build_gcc silently skipping when dev/gcc-15.2.0 cannot be loaded (confirmed: build_gcc returns 0 on Ubuntu and when the module is missing).

Residual coverage gaps (unverifiable from the repo, need CI run links): Per-docker key propagation as step env (build_mode, TEST_PERF, ASAN_CHECK, GCC_MODULE, require_ze, CONTAINER, EXTRA_MODULES/EXTRA_TLS/RUN_TLS, JAVA_VERSION, SLOT_BASE, DOCKER_IMAGE, per-docker privileged/hostNetwork); regex containerSelector support (jucx.*, [0-9].*, soname.*, build_helper_ucx.*, cuda: '13.*'); the uri:-only asan row in test_gpu_matrix.yaml; SR-IOV pod specs and aggregate VF/funk-node demand; mknod without CAP_MKNOD and sudo in test_efa/test_namespace (test_efa.sh install_rdma_core runs sudo cp); /dev/infiniband/umad* permissions for test_mad — Azure's test_mad.sh relies on sudo chmod 777 /dev/infiniband/umad*, which the new matrix does not do; ibstat in the doca-2.9.0 builder; mvn in dl-base; add_network_host from the PGI module in the unprivileged rocky89-icc-pgi row; and CPS-safety of the rewritten dispatcher abort loop.

Review mode: REQUEST_CHANGES, carried by the still-open branch-pin blocker; findings 1–5 above are non-blocking.

The GB200 filter hid five product failures (cuda-async and
cuda-managed rendezvous, the new GPU-NIC RMA test and a tag fallback
timeout), so the job could pass while UCX is broken on GB200. Run the
full gtest set so these failures stay visible until UCX fixes them.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

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

Comment thread .ci/scripts/cap_output.sh
if IFS= read -r -n 1 _; then
echo "ERROR: step output passed ${ci_output_cap} bytes" >&${ci_stdout}
fi) 2>&1
ci_output_pid=$!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

$! is only set for process substitutions in bash >= 5.1, so ci_output_pid is empty on the centos7/centos8 images that source this (test_wirecompat_gpu, test_cuda, test_gpu asan) and the drain loop below breaks immediately. Can we have the reader publish its own $BASHPID instead, so the tail of a step log is not lost?

args:
jobIdFile: "${JOB_ID_FILE_ROOT}/job_id_jucx_${BUILD_NUMBER}.txt"
# Skip testMmapFile: it assumes 4K pages, GB200 uses 64K
testScript: &jucx_test 'set -xeE; source .ci/scripts/cap_output.sh; export JAVA_HOME=/usr/lib/jvm/$jucx_jdk; export PATH=/usr/lib/jvm/$jucx_jdk/bin:$(printenv PATH); ulimit -l unlimited; unset UCX_NET_DEVICES; source buildlib/az-helpers.sh; ifaces=$(get_rdma_interfaces); if [ -z "$ifaces" ]; then echo ERROR: No active RDMA interfaces on machine; exit 1; fi; jport=$((20000 + RANDOM % 10000)); export JUCX_TEST_PORT=$jport; export UCX_HANDLE_ERRORS=bt; jtests=$(cd bindings/java/src/test/java/org/openucx/jucx; ls Ucp*Test.java | grep -v UcpMemoryTest | sed s/.java// | paste -sd,); make -C bindings/java/src/main/native test MVN="mvn -Dtest=$jtests"; make -C bindings/java/src/main/native test MVN="mvn -Dtest=UcpMemoryTest#testGetRkey+testRemoteKeyUnpack+testExportedMkey"; make -C bindings/java/src/main/native package; ipv4_found=0; for iface in $ifaces; do sip=$(get_ip $iface); if [ -z "$sip" ]; then continue; fi; echo Running standalone benchmark on $iface:$jport; java -XX:ErrorFile=hs_err_%p.log -XX:OnError="cat hs_err_%p.log" -cp "bindings/java/resources/:bindings/java/src/main/native/build-java/*" org.openucx.jucx.examples.UcxReadBWBenchmarkReceiver s=$sip p=$jport t=1000000 & sleep 10; java -XX:ErrorFile=hs_err_%p.log -XX:OnError="cat hs_err_%p.log" -cp "bindings/java/resources/:bindings/java/src/main/native/build-java/*" org.openucx.jucx.examples.UcxReadBWBenchmarkSender s=$sip p=$jport t=1000000; wait; ipv4_found=1; done; if [ $ipv4_found -eq 0 ]; then echo ERROR: No IPv4 address on any of $ifaces; exit 1; fi'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bare wait can block on the output reader: pls capture the receiver pid and use wait $java_pid here, as test_bindings_matrix.yaml does (see test_bindings_matrix.yaml:205-209) — with cap_output.sh sourced, a bare wait can also wait for its process substitution, which only exits at script end (dl-base is Ubuntu 24.04 / bash 5.2).

Comment thread contrib/test_jenkins.sh

# all are running mpi tests
run_mpi_tests
if [ "${RUN_MPI_TESTS:-yes}" == "yes" ]

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: new env var is undocumented — pls add RUN_MPI_TESTS to the env var list in the header comment, next to RUN_TESTS/TEST_PERF.

Comment thread .ci/jenkins/proj_jjb_oss.yaml Outdated
branches: [ 'master' ]
shallow-clone: true
depth: 100
branches: [ 'origin/pr/12094/head' ]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Already reported (support the existing thread rather than re-opening) — blocker, still open: the dispatcher SCM is still pinned to branches: [ 'origin/pr/12094/head' ] and drops shallow-clone/depth while adding wipe-workspace: false. The base file uses master with shallow-clone: true, depth: 100. This is debug scaffolding that must be reverted before merge.

@svc-nvidia-pr-review

Copy link
Copy Markdown

.ci/pipeline/test_matrix.yaml

Step timeout was cut 360 → 210 but this matrix sets neither parallel_jobs nor BUILD_JOBS, so common.sh still builds with make -j4 (parallel_jobs=${parallel_jobs:-4}). Pods now request cpu: 10000m and two of four rows are ASan, so a full devel + gtest build at -j4 must fit in the reduced 210-minute budget. Suggest adding to the env: block next to nworkers: "4":

  nworkers: "4"
  # common.sh builds with make -j4 unless parallel_jobs is passed.
  parallel_jobs: "10"

test_gpu and test_dl pass this in the same PR.

Already reported (existing thread): PR size (~750 added lines) exceeds the 500-added-line hard limit in REVIEW.md.

Already reported (existing thread): ucx-test-namespace-gpu-oss is defined in proj_jjb_oss.yaml but absent from the dispatcher leafJobs map, so it is a dead job.

Already reported (existing thread): build_matrix.yaml drops build_mode: "short" from env: in favour of per-docker keys.

Already reported (existing thread): timeout_minutes vs the sum of step timeouts, and step timeouts vs SLURM_JOB_TIMEOUT (test_bindings_gpu 02:45:00 vs ~295 min of steps; test_gpu 05:30:00 vs 600 min; test_cuda 300 min for 33 rows at batchSize: 6).

Already reported (existing thread): hostPID/hostIPC are injected through the raw tolerations string (test_namespace_matrix.yaml:29, test_wirecompat_matrix.yaml:28).

Already reported (existing thread): build_sanity → build_gcc silently returns 0 when dev/gcc-15.2.0 cannot be loaded (confirmed in builds.sh:400-423), so a green rhel82-mofed5.0-gcc15.2 row does not prove the GCC 15.2 build ran.

Already reported (existing thread): aggregate SR-IOV VF demand and concurrent funk-node demand.

Residual coverage gaps (need CI run links; all previously raised): per-docker key propagation as step env (build_mode, TEST_PERF, ASAN_CHECK, GCC_MODULE, require_ze, CONTAINER, EXTRA_MODULES/EXTRA_TLS/RUN_TLS, JAVA_VERSION, SLOT_BASE, DOCKER_IMAGE, per-docker privileged/hostNetwork); regex containerSelector support (jucx.*, [0-9].*, soname.*, build_helper_ucx.*, cuda: '13.*') and the uri:-only asan row in test_gpu_matrix.yaml; the SR-IOV pod specs and the duplicated cx8-ib-network annotation for the 2-VF MAD row; /dev/infiniband/umad* permissions for test_mad (Azure's test_mad.sh:68 relies on sudo chmod 777 /dev/infiniband/umad*, which the new matrix does not do) and ibstat in the doca-2.9.0 builder; mknod without CAP_MKNOD in test_efa_matrix.yaml:31 and sudo for test_efa.sh install_rdma_core's sudo cp; add_network_host from the PGI module in the unprivileged rocky89-icc-pgi row; mvn in dl-base; and CPS-safety of the rewritten dispatcher abort loop (Jenkins.instance lookups across sleep).

Coverity 2019.12 misses the security checkers needed for current CWE
coverage. Move the Jenkins Coverity job to the lab's tools/cov-2026.03
module at high aggressiveness, in the rhel9.0 builder image because
the new analyzer needs glibc 2.18+, and generate a compiler
configuration per job because the new installation ships none.
coverity.sh takes the module, aggressiveness and configure step from
the environment, so Azure keeps running 2019.12 unchanged.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

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

# Install scctl for slurm client management (x86_64 only, not available for ARM64)
RUN if [ "$(uname -m)" = "x86_64" ]; then \
curl -s https://urm.nvidia.com/artifactory/sw-swx-lab-infra-generic/scctl/get-app.sh | bash -s -- --output-dir /usr/local/bin || echo "INFO: scctl installation failed, continuing..."; \
curl -fsS https://artifactory.nvidia.com/artifactory/sw-swx-lab-infra-generic-local/scctl/get-app.sh | bash -s -- --output-dir /usr/local/bin; \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Dropping the || echo ... continuing was meant to make this fail loud, but a pipeline's exit status is bash's, and the default RUN shell has no pipefail — so a 404/401 from curl still leaves the image without scctl and the RUN succeeds.

Suggested change:

        curl -fsS https://artifactory.nvidia.com/artifactory/sw-swx-lab-infra-generic-local/scctl/get-app.sh -o /tmp/get-app.sh && \
        bash /tmp/get-app.sh --output-dir /usr/local/bin && rm /tmp/get-app.sh; \

refspec: "+refs/heads/*:refs/remotes/origin/* +refs/pull/*:refs/remotes/origin/pr/*"
browser: githubweb
browser-url: "https://github.com/openucx/ucx"
wipe-workspace: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

why wipe-workspace: false? (same at line 105) JJB defaults it to true, and steps added here fail on a reused workspace: mkdir build in test_bindings_matrix.yaml:97 and git_clone_with_retry into ${WORKSPACE}/ucx_${ucx_tag} in test_wirecompat_matrix.yaml:78 (plain git clone into an existing non-empty dir). Removing shallow-clone looks justified — test_bindings_matrix.yaml:162 needs git describe --tags — but this one looks like debug leftover.

def leafBranches = { jobs ->
jobs.collectEntries { branchName, jobName ->
[(branchName): {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', catchInterruptions: false) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

catchError here also swallows a dispatch failure, e.g. a leaf name not yet registered in JJB: the branch turns red but the dispatcher still reports SUCCESS and the leaf posts no GitHub status at all (Jenkinsfile.github:24), so the PR looks green with a check silently missing. The basic-compile branch guards exactly this with the gate?.result re-check — can we do the same for the leaves?

Comment thread .ci/scripts/cap_output.sh
if IFS= read -r -n 1 _; then
echo "ERROR: step output passed ${ci_output_cap} bytes" >&${ci_stdout}
fi) 2>&1
ci_output_pid=$!

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: $! is only set for a process substitution by recent bash, so on the older images (the centos7 nvidia/cuda rows in test_cuda, centos7-mofed5.4-cuda11 in test_wirecompat_gpu, centos8-...-cuda11_asan in test_gpu) ci_output_pid stays empty, kill -0 '' fails and the drain loop breaks immediately — dropping the last lines exactly when a step fails. can we have the subshell write its $$ to a temp file instead?

run: |
source .ci/scripts/cap_output.sh
set -eEx -o pipefail
hcas=($(ibv_devinfo | awk '/hca_id:/ {h=$2} /port:/ {p=$2} /state:/ {s=$2}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

buildlib/tools/test_mad.sh already has detect_active_ib_hca/set_vars doing this ibv_devinfo | awk and the ibstat LID/GUID parsing, and the Build step above already sources that file. can we add the two-port variant there and keep the YAML to a one-line call? 20 lines of test logic in YAML is hard to reproduce by hand when it breaks.

args:
jobIdFile: "${JOB_ID_FILE_ROOT}/job_id_jucx_${BUILD_NUMBER}.txt"
# Skip testMmapFile: it assumes 4K pages, GB200 uses 64K
testScript: &jucx_test 'set -xeE; source .ci/scripts/cap_output.sh; export JAVA_HOME=/usr/lib/jvm/$jucx_jdk; export PATH=/usr/lib/jvm/$jucx_jdk/bin:$(printenv PATH); ulimit -l unlimited; unset UCX_NET_DEVICES; source buildlib/az-helpers.sh; ifaces=$(get_rdma_interfaces); if [ -z "$ifaces" ]; then echo ERROR: No active RDMA interfaces on machine; exit 1; fi; jport=$((20000 + RANDOM % 10000)); export JUCX_TEST_PORT=$jport; export UCX_HANDLE_ERRORS=bt; jtests=$(cd bindings/java/src/test/java/org/openucx/jucx; ls Ucp*Test.java | grep -v UcpMemoryTest | sed s/.java// | paste -sd,); make -C bindings/java/src/main/native test MVN="mvn -Dtest=$jtests"; make -C bindings/java/src/main/native test MVN="mvn -Dtest=UcpMemoryTest#testGetRkey+testRemoteKeyUnpack+testExportedMkey"; make -C bindings/java/src/main/native package; ipv4_found=0; for iface in $ifaces; do sip=$(get_ip $iface); if [ -z "$sip" ]; then continue; fi; echo Running standalone benchmark on $iface:$jport; java -XX:ErrorFile=hs_err_%p.log -XX:OnError="cat hs_err_%p.log" -cp "bindings/java/resources/:bindings/java/src/main/native/build-java/*" org.openucx.jucx.examples.UcxReadBWBenchmarkReceiver s=$sip p=$jport t=1000000 & sleep 10; java -XX:ErrorFile=hs_err_%p.log -XX:OnError="cat hs_err_%p.log" -cp "bindings/java/resources/:bindings/java/src/main/native/build-java/*" org.openucx.jucx.examples.UcxReadBWBenchmarkSender s=$sip p=$jport t=1000000; wait; ipv4_found=1; done; if [ $ipv4_found -eq 0 ]; then echo ERROR: No IPv4 address on any of $ifaces; exit 1; fi'

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 is the third copy of the JUCX flow in this PR (test_bindings_matrix.yaml, test_bindings_gpu_matrix.yaml, here), each written differently, on top of buildlib/jucx/jucx-test.yml. can we extract it into a buildlib/tools/test_jucx.sh that all three call? a single-line rendering of that whole flow is not maintainable.

BUILD_ID: "${BUILD_NUMBER}"
# Module name of the lab modulefiles tree.
COV_MODULE: "tools/cov-2026.03"
COV_AGGRESSIVENESS: "high"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

why high? run_coverity fails on any reported defect (coverity.sh:115-117), so raising aggressiveness together with the 2019.12 → 2026.03 bump is likely to keep the coverity leaf red until all the new findings are triaged.

jobs:
- "{jjb_proj}"

- project:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Existing thread (+1, still true): ucx-test-namespace-gpu-oss is registered here (lines 242-248) but absent from the dispatcher leafJobs.

@svc-nvidia-pr-review

Copy link
Copy Markdown

Existing thread (+1, still true): the branches: [ 'origin/pr/12094/head' ] pin is a blocker — base uses master.

Existing thread (+1, still true): PR size is over the 500-added-line limit.

.ci/pipeline/build_matrix.yaml

Existing thread (+1, still true): build_matrix.yaml drops build_mode: "short" from env:.

Existing thread (+1, still true): step timeouts exceed SLURM_JOB_TIMEOUT — test_bindings_gpu 165 min vs ~295; test_gpu 330 vs 600; zero slack in test_wirecompat_gpu 135/135 and test_namespace_gpu 60/60.

.ci/pipeline/test_cuda_matrix.yaml

Existing thread (+1, still true): timeout_minutes: 300 for 33 rows at batchSize: 6.

Existing thread (+1, still true): hostPID/hostIPC are injected through the raw tolerations string.

Existing thread (+1, still true): build_sanity → build_gcc returns 0 silently when dev/gcc-15.2.0 cannot be loaded (confirmed at builds.sh:400-423).

Existing thread (+1, still true): aggregate SR-IOV VF / funk-node demand.

Residual coverage gaps — unverifiable from the repository, still needing CI run links: per-docker key propagation as step env (build_mode, TEST_PERF, ASAN_CHECK, GCC_MODULE, require_ze, CONTAINER, EXTRA_MODULES/EXTRA_TLS/RUN_TLS, JAVA_VERSION, SLOT_BASE, DOCKER_IMAGE, per-docker privileged/hostNetwork); regex containerSelector support (jucx.*, [0-9].*, soname.*, build_helper_ucx.*, cuda: '13.*'); the uri:-only asan row in test_gpu_matrix.yaml; the SR-IOV pod specs and the duplicated cx8-ib-network annotation for the 2-VF MAD row; /dev/infiniband/umad* access for test_mad (Azure's test_mad.sh:40,74 relies on sudo chmod 777 /dev/infiniband/umad*, which the new matrix does not do, and it mounts no /dev/infiniband unlike test_bf_matrix.yaml); ibstat in the doca-2.9.0 builder; mknod without CAP_MKNOD in test_efa_matrix.yaml:31 plus sudo for test_efa.sh install_rdma_core; sudo in the non-GPU test_namespace pod (test_namespace.sh:33 runs sudo unshare ... sudo -u $USER); mvn in dl-base; add_network_host in the unprivileged rocky89-icc-pgi row; and CPS-safety of the rewritten dispatcher abort loop (staleBuilds holds Run objects live across the echo step at line 31).

With Coverity 2026 the devel capture alone took 21 minutes with 4 jobs,
so cov-analyze was killed at the 30 minute step timeout. Build and
analyze with all 6 pod CPUs and raise the step timeout to 75 minutes,
within the 90 minute job timeout.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

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

# Install scctl for slurm client management (x86_64 only, not available for ARM64)
RUN if [ "$(uname -m)" = "x86_64" ]; then \
curl -s https://urm.nvidia.com/artifactory/sw-swx-lab-infra-generic/scctl/get-app.sh | bash -s -- --output-dir /usr/local/bin || echo "INFO: scctl installation failed, continuing..."; \
curl -fsS https://artifactory.nvidia.com/artifactory/sw-swx-lab-infra-generic-local/scctl/get-app.sh | bash -s -- --output-dir /usr/local/bin; \

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 || echo "...continuing..." was dropped to make a failed scctl install fatal, but the pipe still hides it: RUN uses /bin/sh (dash, no pipefail), so the exit status is bash's, not curl's. On a 404/auth error curl -fsS writes nothing to stdout, bash -s -- reads an empty script and exits 0, and the image builds without scctl — surfacing much later as scctl: command not found in the allocation step of test_gpu/test_cuda/test_bindings_gpu/test_ucxx_gpu.

Suggestion:

        curl -fsS https://artifactory.nvidia.com/artifactory/sw-swx-lab-infra-generic-local/scctl/get-app.sh -o /tmp/get-app.sh && bash /tmp/get-app.sh --output-dir /usr/local/bin; \


az_init_modules
modules_for_coverity
cov-analyze --ident

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: cov-analyze --ident is unconditional, and COV_MODULE still defaults to tools/cov-2019.12, so this diagnostic also runs on the Azure job (buildlib/pr/coverity.yml:23). The script is #!/bin/bash -eEl, so a version that rejects the flag would abort Coverity on Azure for a line with no functional purpose.

Suggestion:

cov-analyze --ident || true


parallel(leafBranches(leafJobs))

githubHelper.updateCommitStatus(pipelineOverviewUrl, "UCX CI ended", GitHubCommitState.SUCCESS)

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: Both the success and failure paths now post the same description, "UCX CI ended", so the text next to the GitHub check no longer says whether CI passed (only the state icon differs). Can we keep distinct wording, e.g. "UCX CI passed" / "UCX CI failed"? (also applies at line 158)

Comment thread .ci/jenkins/proj_jjb_oss.yaml Outdated
branches: [ 'master' ]
shallow-clone: true
depth: 100
branches: [ 'origin/pr/12094/head' ]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Already reported (+1 on existing thread): branch pin to origin/pr/12094/head — base uses branches: [ 'master' ]; also drops shallow-clone/depth: 100. Still the blocker carrying REQUEST_CHANGES.

arch: x86_64,
# posix without proc link needs the host (default) PID namespace;
# ci-demo has no hostPID option, so it rides on the raw tolerations.
tolerations: "[]\n hostPID: true"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Already reported (+1 on existing thread): hostPID/hostIPC injected through the raw tolerations string (also test_wirecompat_matrix.yaml:28).

@svc-nvidia-pr-review

Copy link
Copy Markdown

Already reported (+1 on existing thread): PR size is ~750 added lines vs the 500 hard limit in REVIEW.md.

Already reported (+1 on existing thread): ucx-test-namespace-gpu-oss is the one project defined in proj_jjb_oss.yaml (22 leaf projects) but absent from the dispatcher's gateStageJobs/leafJobs (21 dispatched) — a dead job.

.ci/pipeline/build_matrix.yaml

Already reported (+1 on existing thread): build_matrix.yaml drops build_mode: "short" from env: — builds.sh:24 defaults to long, so a propagation failure silently switches all 42 images to the long test list.

Already reported (+1 on existing thread): timeout_minutes vs step sums, and step sums vs SLURM_JOB_TIMEOUT — test_bindings_gpu 165 min allocation vs ~295 min of steps (go row) and timeout_minutes: 240; test_gpu 330 vs 600; zero slack in test_wirecompat_gpu (135/135) and test_namespace_gpu (60/60); test_cuda 300 min for 33 rows at batchSize: 6.

Already reported (+1 on existing thread): build_sanity → build_gcc silently returns 0 when dev/gcc-15.2.0 cannot be loaded (builds.sh:400-423: early return 0 on Ubuntu, and the az_module_load failure path falls through), so a green rhel82-mofed5.0-gcc15.2 row does not prove the GCC 15.2 build ran.

.ci/pipeline/test_matrix.yaml

Already reported (+1 on existing thread): test_matrix.yaml sets neither parallel_jobs nor BUILD_JOBS — common.sh:52 leaves make -j4 while the step timeout was cut 360 → 210.

Already reported (+1 on existing thread): aggregate SR-IOV VF demand and concurrent funk-node demand.

Already reported (+1 on existing thread): scope of the ucxx sed -i patching of eight upstream rapidsai/ucxx CI scripts.

Residual coverage gaps (need CI run links; all previously raised): per-docker key propagation as step env (build_mode, TEST_PERF, ASAN_CHECK, GCC_MODULE, require_ze, CONTAINER, EXTRA_MODULES/EXTRA_TLS/RUN_TLS, JAVA_VERSION, SLOT_BASE, DOCKER_IMAGE, per-docker privileged/hostNetwork); regex containerSelector support (jucx.*, [0-9].*, soname.*, build_helper_ucx.*, cuda: '13.*') — note pipeline_start/pipeline_stop in test_gpu_matrix.yaml use the unanchored {name: 'build_helper_ucx'} and would run twice if matching is unanchored; the uri:-only asan row in test_gpu_matrix.yaml; the SR-IOV pod specs and the duplicated cx8-ib-network annotation for the 2-VF MAD row; /dev/infiniband/umad* permissions for test_mad — Azure's test_mad.sh:40,74 relies on sudo chmod 777 /dev/infiniband/umad*, which the new matrix does not do, and it mounts no /dev/infiniband unlike test_bf_matrix.yaml; ibstat in the doca-2.9.0 builder; sudo for test_efa.sh install_rdma_core's sudo cp and for test_namespace.sh:33's sudo unshare; mvn in dl-base (Dockerfile.dl-base installs only python3-setuptools, iproute2, and gdrcopy, while every JUCX target in bindings/java/src/main/native/Makefile.am runs $(MVN)); add_network_host from the PGI module in the unprivileged rocky89-icc-pgi row; and CPS-safety of the rewritten dispatcher abort loop (staleBuilds still holds WorkflowRun objects live across the echo at line 31, and the catch would mask a NotSerializableException as "Could not abort previous builds").

.ci/pipeline/coverity_matrix.yaml

Same class as the timeout findings, so folding it in rather than opening a thread: coverity_matrix.yaml raises the step timeout 30 → 75 but leaves timeout_minutes: 90, giving only 15 minutes of slack for pod scheduling, the large Coverity image pull, and checkout across the two parallel release/devel rows.

The PGI compiler (nvc 21.2) fails the devel build when a type is
typedef'd twice ("typedef name has already been declared"), which breaks
the EFA transport build. ROCm IPC and ZE IPC headers repeat the same
typedefs, so keep a single one for each type.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
(cherry picked from commit 7066531)
rocm_ipc_md.h forward-declares uct_rocm_ipc_cache_t but never uses it, and
every user of the type includes rocm_ipc_cache.h. Removing the forward
declaration leaves a single typedef on the struct definition, same as the
ZE IPC change, instead of splitting the type across two headers.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
(cherry picked from commit 1cc5bc9)
@svc-nvidia-pr-review

Copy link
Copy Markdown

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

kubernetes:
cloud: il-ipp-blossom-prod-nbu-swx-ucx
namespace: nbu-swx-ucx
limits: "{memory: 10Gi, cpu: 6000m}"

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 pod requests cpu: 6000m, but the step pins the entire run (build included) to 2 CPUs with taskset -c "$((slot * 2))-$((slot * 2 + 1))". Four of the six reserved cores stay idle, and a 16-core BF3 then fits only 2 pods while batchSize: 4 expects 4 at once. Can we make the request match the pinned set, or widen the taskset to 3 CPUs?

source .ci/scripts/cap_output.sh
# Host network and CPUs are shared, so each pod gets its own ports and 2 CPUs.
slot=$((SLOT_BASE + worker))
export EXECUTOR_NUMBER=${slot}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

slot comes only from SLOT_BASE + worker, so two concurrent builds of this job (the job template sets concurrent: true) pick the same slots. With hostNetwork: true their EXECUTOR_NUMBER-derived port ranges (UCX_TCP_PORT_RANGE, server_port_min in common.sh) collide whenever the pods land on the same BF3 node. Azure avoided this with AZP_AGENT_ID, which buildlib/pr/tests.yml:94 documents as "uniq for one host". How is cross-build slot uniqueness handled here?

refspec: "+refs/heads/*:refs/remotes/origin/* +refs/pull/*:refs/remotes/origin/pr/*"
browser: githubweb
browser-url: "https://github.com/openucx/ucx"
wipe-workspace: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Are wipe-workspace: false and dropping shallow-clone/depth: 100 intended, or part of the same debug change as the origin/pr/12094/head pin above? Without the wipe, untracked leftovers from a previous build persist in the leaf-job workspace.

Comment thread contrib/test_jenkins.sh
# Each thread requires 5MB. Cap threads number by total available shared memory.
max_threads=$(df /dev/shm | awk '/shm/ {printf "%d", $4 / 5000}')
num_threads=$(($max_threads < $(nproc) ? $max_threads : $(nproc)))
num_threads=$(($max_threads < ${NPROC} ? $max_threads : ${NPROC}))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
num_threads=$(($max_threads < ${NPROC} ? $max_threads : ${NPROC}))
num_threads=$(($max_threads < $(nproc) ? $max_threads : $(nproc)))

NPROC from common.sh:38 is nproc --all outside containers, which ignores CPU affinity, whereas $(nproc) respected it. Enroot/pyxis sets neither /.dockerenv nor KUBERNETES_SERVICE_HOST, so on the DL cluster this reports 144 instead of the ~24 CPUs the Slurm cpuset grants, and the new BF3 rows run under taskset -c with 2 CPUs.

@svc-nvidia-pr-review

Copy link
Copy Markdown

Already reported — still true in this revision (support the existing threads, do not re-open): the branches: [ 'origin/pr/12094/head' ] pin (blocker; base uses master); PR size over the 500-added-line hard limit; ucx-test-namespace-gpu-oss defined in proj_jjb_oss.yaml (22 leaf projects) but absent from the dispatcher's gateStageJobs/leafJobs (21 dispatched) — re-counted and confirmed as the single dead job; build_matrix.yaml dropping build_mode: "short" from env: (builds.sh:24 defaults to long); step sums exceeding SLURM_JOB_TIMEOUT (test_bindings_gpu 165 min vs ~295, test_gpu 330 vs 600, zero slack in test_wirecompat_gpu 135/135 and test_namespace_gpu 60/60); test_cuda timeout_minutes: 300 for 33 rows at batchSize: 6; coverity 90 vs a 75-minute step; test_matrix.yaml setting neither parallel_jobs nor BUILD_JOBS while cutting the step timeout 360 → 210; hostPID/hostIPC injected through the raw tolerations string; build_sanity → build_gcc silently returning 0 when dev/gcc-15.2.0 cannot be loaded (confirmed at builds.sh:400-423); aggregate SR-IOV VF and funk-node demand; and the scope of the sed -i patching of upstream rapidsai/ucxx CI scripts.

Residual coverage gaps (need CI run links): per-docker key propagation as step env (build_mode, TEST_PERF, ASAN_CHECK, GCC_MODULE, require_ze, CONTAINER, EXTRA_*, JAVA_VERSION, SLOT_BASE, DOCKER_IMAGE, per-docker privileged/hostNetwork); regex containerSelector support (jucx.*, [0-9].*, soname.*, build_helper_ucx.*, cuda: '13.*') plus the unanchored pipeline_start/pipeline_stop selectors in test_gpu_matrix.yaml; the uri:-only ASan row; duplicate name: 'rapidsai-ci-conda' entries in test_ucxx_matrix.yaml; mknod without CAP_MKNOD and sudo for test_efa.sh install_rdma_core / test_namespace.sh:33; /dev/infiniband/umad* permissions for test_mad (Azure's test_mad.sh:40,74 relies on sudo chmod 777 /dev/infiniband/umad*, which the new matrix omits, and it mounts no /dev/infiniband) and the duplicated cx8-ib-network annotation; ibstat in the doca-2.9.0 builder; mvn in dl-base; add_network_host in the unprivileged rocky89-icc-pgi row; and CPS-safety of the rewritten dispatcher abort loop (staleBuilds still holds WorkflowRun objects across the echo at line 31).

The dispatcher job loaded its pipeline from the integration PR branch, so every /build ran that branch's basic compile gate and its full job list. PRs that do not carry those matrix files failed on missing conf_file. Loading from master runs the job list each PR is expected to pass.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

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

BUILD_ID: "${BUILD_NUMBER}"
# Module name of the lab modulefiles tree.
COV_MODULE: "tools/cov-2026.03"
COV_AGGRESSIVENESS: "high"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

why high here? run_coverity fails the job on any non-zero defect count, so raising the aggressiveness level on top of the Coverity 2019→2026 jump will likely surface pre-existing findings unrelated to the PR. can we land the version bump first with the default level?


az_init_modules
modules_for_coverity
cov-analyze --ident

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: this looks like a leftover probe (cov-analyze --ident) — pls drop it or guard it; the script runs with -e and Azure still loads tools/cov-2019.12 here, so an unsupported option would fail the Coverity stage there too.

Comment thread .ci/scripts/cap_output.sh
if IFS= read -r -n 1 _; then
echo "ERROR: step output passed ${ci_output_cap} bytes" >&${ci_stdout}
fi) 2>&1
ci_output_pid=$!

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: $! is only set by a process substitution from bash 5.1 on, so on the CentOS 7 / UBI 8 images (bash 4.x) ci_output_pid stays empty, kill -0 fails and the drain loop breaks immediately — the last lines of the step can still be lost.

def leafBranches = { jobs ->
jobs.collectEntries { branchName, jobName ->
[(branchName): {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', catchInterruptions: false) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

with buildResult: 'SUCCESS' on every leaf branch the dispatcher build stays SUCCESS, so this sets the commit status to SUCCESS even when e.g. ucx-test-oss failed. is a green aggregate status intended, given the per-leaf statuses are then the only real signal?

A busy GPU partition makes salloc give up after the 1h --immediate
window and fail the PR with "Unable to allocate resources: Connection
timed out", although the job would have run once a node freed up.
Queue for up to 4h instead and raise each job timeout by the same 3h,
since the allocation step has no step timeout and only the job timeout
bounds the wait. The CUDA memory hooks rows also pull their CUDA image
in a step of its own, so a slow image import no longer eats the test
step's timeout.

Signed-off-by: Alexey Rivkin <arivkin@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

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

RUNNING_IN_AZURE: "no"
BUILD_REPOSITORY_URI: "https://github.com/openucx/ucx.git"
# v1.14.0 off: its server cannot reconfigure the ep the PR client answers.
UCX_LEGACY_TAGS: "v1.15.x v1.16.x v1.17.x v1.18.x"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

UCX_LEGACY_TAGS drops v1.14.0, but the two != "v1.14.0" guards below were kept, so they are now dead. On Azure (wire_compat.yml) only stages 1 and 3 are skipped for v1.14.0 while ucp_hello_world (stages 2 and 4) still runs against it — can we add v1.14.0 back to the list so that coverage is kept? The GPU variant (test_wirecompat_gpu_matrix.yaml) dropped it too, and has no guards at all.

BUILD_ID: "${BUILD_NUMBER}"
# Module name of the lab modulefiles tree.
COV_MODULE: "tools/cov-2026.03"
COV_AGGRESSIVENESS: "high"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

why high aggressiveness? coverity.sh fails the job whenever nerrors > 0 and has no suppression path, so together with the 2019.12 -> 2026.03 upgrade this gate now has to be clean at the most false-positive-prone level.

Comment thread .ci/scripts/cap_output.sh
if IFS= read -r -n 1 _; then
echo "ERROR: step output passed ${ci_output_cap} bytes" >&${ci_stdout}
fi) 2>&1
ci_output_pid=$!

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: $! is not set by process substitution on bash 4.x, which the centos7 CUDA, centos8 asan and rockylinux8 wheel images that source this still run — ci_output_pid stays empty there, kill -0 ${ci_output_pid} fails and the drain loop breaks immediately, losing exactly the trailing lines the trap was added to preserve. Can we use a short fixed sleep instead, so the tail of the log is not lost on those images?

jobs:
- "{jjb_proj}"

- project:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

+1 (existing thread, still true): ucx-test-namespace-gpu-oss is registered here but absent from the dispatcher's leafJobs — 22 leaf projects defined, 21 dispatched; namespace-gpu is the only dead one, making test_namespace_gpu_matrix.yaml's 154 lines unreachable.


# Loads swx-jenkins-lib once before the parallel rows; /tmp has no job id files.
pipeline_start:
containerSelector: "{name: 'build_helper_ucx'}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Residual coverage gap (needs CI run links): unanchored pipeline_start/pipeline_stop container selectors here and at line 181.

}

if (staleBuilds) {
echo "PR #${currentPrNumber}: found ${staleBuilds.size()} stale dispatcher(s) to abort"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Residual coverage gap (needs CI run links): CPS-safety of the rewritten dispatcher abort loop — staleBuilds still holds WorkflowRun objects live across this echo.

@svc-nvidia-pr-review

Copy link
Copy Markdown

+1 (existing thread, still true): PR size is over the 500-added-line hard limit.

.ci/pipeline/build_matrix.yaml

+1 (existing thread, still true): build_matrix.yaml drops build_mode: "short" from env:, and builds.sh:24 defaults to long.

+1 (existing thread, still true): step timeout sums exceed SLURM_JOB_TIMEOUT and timeout_minutes.

+1 (existing thread, still true): hostPID/hostIPC are injected through the raw tolerations string.

.ci/pipeline/test_matrix.yaml

+1 (existing thread, still true): test_matrix.yaml sets neither parallel_jobs nor BUILD_JOBS while cutting the step timeout from 360 to 210.

.ci/pipeline/coverity_matrix.yaml

+1 (existing thread, still true): coverity timeout of 90 vs a 75-minute step.

+1 (existing thread, still true): build_sanity → build_gcc returns 0 silently when dev/gcc-15.2.0 cannot be loaded.

+1 (existing thread, still true): aggregate SR-IOV VF and funk-node demand.

+1 (existing thread, still true): scope of the sed -i patching of upstream rapidsai/ucxx CI scripts.

Residual coverage gap (needs CI run links): per-docker key propagation as step env — build_mode, TEST_PERF, ASAN_CHECK, GCC_MODULE, require_ze, CONTAINER, EXTRA_MODULES/EXTRA_TLS/RUN_TLS, JAVA_VERSION, SLOT_BASE, DOCKER_IMAGE, and per-docker privileged/hostNetwork.

Residual coverage gap (needs CI run links): regex containerSelector support (jucx.*, [0-9].*, soname.*, build_helper_ucx.*, cuda: '13.*').

Residual coverage gap (needs CI run links): the uri:-only ASan row.

.ci/pipeline/test_ucxx_matrix.yaml

Residual coverage gap (needs CI run links): duplicate name: 'rapidsai-ci-conda' rows.

.ci/pipeline/test_mad_matrix.yaml

Residual coverage gap (needs CI run links): /dev/infiniband/umad* permissions for test_mad — Azure's test_mad.sh:40,74 relies on sudo chmod 777 /dev/infiniband/umad*, which this matrix omits, and it mounts no /dev/infiniband; also the duplicated cx8-ib-network annotation for 2 VFs.

Residual coverage gap (needs CI run links): availability of ibstat in the doca-2.9.0 builder.

Residual coverage gap (needs CI run links): sudo availability for test_efa.sh install_rdma_core and test_namespace.sh.

.ci/dockerfiles/Dockerfile.dl-base

Residual coverage gap (needs CI run links): mvn availability in dl-base.

Residual coverage gap (needs CI run links): add_network_host in the unprivileged rocky89-icc-pgi row.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WIP-DNM Work in progress / Do not review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants