Skip to content

bugfix: mlx5 ci hung - #622

Open
QizhouZhang97 wants to merge 9 commits into
mainfrom
bugfix/mlx5
Open

bugfix: mlx5 ci hung#622
QizhouZhang97 wants to merge 9 commits into
mainfrom
bugfix/mlx5

Conversation

@QizhouZhang97

@QizhouZhang97 QizhouZhang97 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor
  • migrate mlx ci to 19-05 & 19-14

  • fix mlx poll cq bug: clamp doneIdx against dbTouchIdx, not postIdx — the old
    window exceeded 65536, so a stale wqe_counter wrapped into a bogus advance and
    the recycle gate overwrote live SQ slots.

Qizhou Zhang and others added 8 commits August 31, 2026 09:30
Remove leftover mori* containers and GPU/RDMA processes on both nodes
before starting internode CI to avoid EP stress hangs on dirty runners.

Co-authored-by: Cursor <cursoragent@cursor.com>
Run remote host cleanup via bash -s heredoc so pkill patterns are not
embedded in the ssh command line, which was killing the session.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bench can leave torchrun/mlx5 state that makes the first stress case
hit timeout 600 (exit 124). Reset both nodes before stress and retry
the sweep once after killing lingering GPU workers.

Co-authored-by: Cursor <cursoragent@cursor.com>
Test 2 launched its kernel straight after the local memset, so PE 0's put-imm
could land before PE 1 had memset its own buffer. PE 1 then overwrote the
delivered 42s with 1 and its kernel spun on the clobbered values forever,
hanging hipDeviceSynchronize until CI's timeout killed the job (exit 124).

Test 1 and every other cross-PE kernel launch in the shmem examples already
barrier at this point; only this one was missing it. Reproduced deterministically
by delaying PE 1's memset: 6/6 hangs without the barrier, 6/6 passes with it.

Co-authored-by: Cursor <cursoragent@cursor.com>
The self-hosted runner moved off banff-ccs-aus-p19-29, so node1 (the runner
itself) and node2 (its ssh peer) now resolve to p19-05 and p19-14.

Both boxes have the same NIC layout as the old pair -- mlx5_0..7 on InfiniBand
plus mlx5_8 behind ens14np0 -- so rdma_devices and the ifnames are unchanged.
The runner label still reads 300_mlx_p19_29 because the agent registration was
moved rather than recreated; renaming it needs a fresh registration token.

Co-authored-by: Cursor <cursoragent@cursor.com>
The CI container mounts the workspace and runs as root, so every internode
job leaves root-owned build output behind on node2. node1 recovers from this
via "Fix workspace permissions" before checkout, but node2 has no checkout and
no equivalent step, so the next job's rsync hit EPERM on those files and failed
"Start container on node2" within seconds, before anything was built.

Co-authored-by: Cursor <cursoragent@cursor.com>
The collapsed-CQ drain bounded its reconstruction by postIdx when called from
the live quiet. postIdx is the reservation counter, bumped before a warp passes
the recycle gate, so it runs tens of thousands of entries ahead of what is
actually in the send queue. That slack let a wqe_counter from outside the live
window pass the sanity check -- the 16-bit value wraps into a plausible delta --
and pushed doneIdx past WQEs the NIC had not fetched yet. The recycle gate then
handed those still-live SQ slots out for reuse and the overwritten writes were
lost, which hangs any peer spinning on the data.

Reproduced with concurrent_put_thread under MORI_DISABLE_P2P=ON: test 3 pushes
262144 single-dword puts through one QP against a 4096-entry SQ, so the gate
recycles constantly. It hung in roughly 21% of runs (15/70), always in test 3,
with the receiver missing scattered wave-sized clusters of writes -- up to
131072 of them. Bounding by dbTouchIdx instead drops that to 2/165.

Co-authored-by: Cursor <cursoragent@cursor.com>

@jhchouuu jhchouuu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

Comment thread .github/workflows/ci.yml Outdated
Comment on lines +900 to +941
- name: Reset GPU processes before EP internode stress
run: |
# Bench runs 20 torchrun sessions; lingering workers or mlx5 UAR mappings can
# leave the first stress case hung until timeout 600 (exit 124).
$CT exec $CONTAINER bash -c 'pkill -9 -f "[t]orchrun" 2>/dev/null || true; pkill -9 -f "[t]est_dispatch_combine_internode" 2>/dev/null || true; pkill -9 -f "[t]ests\.python\.io\.benchmark" 2>/dev/null || true; sleep 3'
ssh $SSH_OPTS -p $NODE2_PORT $(whoami)@$NODE2_HOST \
"$CT exec $CONTAINER bash -c 'pkill -9 -f \"[t]orchrun\" 2>/dev/null || true; pkill -9 -f \"[t]est_dispatch_combine_internode\" 2>/dev/null || true; pkill -9 -f \"[t]ests\\.python\\.io\\.benchmark\" 2>/dev/null || true; sleep 3'"

- name: MORI-EP internode normal kernel stress
run: |
SCRIPT="$GITHUB_WORKSPACE/tools/run_internode_test.sh"
PORT=29160
for KERNEL in v1 v1_ll; do
for TOKENS in 64 128 1024 2048 4096; do
echo "=== stress kernel=$KERNEL max-tokens=$TOKENS port=$PORT ==="
NODE2_CMD=(
$CT exec -e MORI_INTERNODE_TIMEOUT=600 $CONTAINER bash $SCRIPT
--rank 1 --master-addr $NODE1_HOST --master-port $PORT
--ifname $NODE2_IFNAME
--cmd stress --kernel-type $KERNEL --max-tokens $TOKENS
)
ssh $SSH_OPTS -p $NODE2_PORT $(whoami)@$NODE2_HOST "${NODE2_CMD[*]}" &
$CT exec -e MORI_INTERNODE_TIMEOUT=600 $CONTAINER bash $SCRIPT \
--rank 0 --master-addr $NODE1_HOST --master-port $PORT \
--ifname $NODE1_IFNAME \
--cmd stress --kernel-type $KERNEL --max-tokens $TOKENS
wait
sleep 1
PORT=$((PORT + 1))
reset_ep_gpu() {
$CT exec $CONTAINER bash -c 'pkill -9 -f "[t]orchrun" 2>/dev/null || true; pkill -9 -f "[t]est_dispatch_combine_internode" 2>/dev/null || true; pkill -9 -f "[t]ests\.python\.io\.benchmark" 2>/dev/null || true; sleep 3'
ssh $SSH_OPTS -p $NODE2_PORT $(whoami)@$NODE2_HOST \
"$CT exec $CONTAINER bash -c 'pkill -9 -f \"[t]orchrun\" 2>/dev/null || true; pkill -9 -f \"[t]est_dispatch_combine_internode\" 2>/dev/null || true; pkill -9 -f \"[t]ests\\.python\\.io\\.benchmark\" 2>/dev/null || true; sleep 3'"
}
run_stress_sweep() {
local rc=0
SCRIPT="$GITHUB_WORKSPACE/tools/run_internode_test.sh"
PORT=29160
for KERNEL in v1 v1_ll; do
for TOKENS in 64 128 1024 2048 4096; do
echo "=== stress kernel=$KERNEL max-tokens=$TOKENS port=$PORT ==="
NODE2_CMD=(
$CT exec -e MORI_INTERNODE_TIMEOUT=600 $CONTAINER bash $SCRIPT
--rank 1 --master-addr $NODE1_HOST --master-port $PORT
--ifname $NODE2_IFNAME
--cmd stress --kernel-type $KERNEL --max-tokens $TOKENS
)
ssh $SSH_OPTS -p $NODE2_PORT $(whoami)@$NODE2_HOST "${NODE2_CMD[*]}" &
$CT exec -e MORI_INTERNODE_TIMEOUT=600 $CONTAINER bash $SCRIPT \
--rank 0 --master-addr $NODE1_HOST --master-port $PORT \
--ifname $NODE1_IFNAME \
--cmd stress --kernel-type $KERNEL --max-tokens $TOKENS
wait
case_rc=$?
if [ $case_rc -ne 0 ]; then
rc=$case_rc
break 2
fi
sleep 1
PORT=$((PORT + 1))
done

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

remove reset gpu if not necessary

The container/process sweep and the stress retry were workarounds for
zombie IBGDA repros left on p19-29 / p20-29. The pair now runs on
p19-05 / p19-14, so let a hang fail the job instead of hiding it.

Co-authored-by: Cursor <cursoragent@cursor.com>
@QizhouZhang97 QizhouZhang97 changed the title ci: cleanup stale mori containers before internode tests bugfix: mlx5 ci hung Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants