summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/run_cycle.sh
blob: 53ebf525a0b97822e1e8ead38c34c4739f6a4909 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2026 Open-IOV contributors
# run_cycle.sh - one instrumented CUDA bring-up cycle with full capture.
#
# Recipe (PART 70 + PART 71): restart VM/module, push tools, install kprobes
# (uvmt ON, uvsv/uvsvr OFF, 16 MB ring), start pin_gr_stream + semfix, launch
# cdt (strace -f -e ioctl) holding on failure, snapshot host+guest dmesg.
#
# Usage: tools/guest-diag/run_cycle.sh [hold-seconds] [strace|nostrace]
set -uo pipefail

HERE="$(cd "$(dirname "$0")" && pwd)"
REPO="$HERE/../.."
VMEXEC="$REPO/scripts/vgpu_vm.py"
OUT=/tmp/opencode
HOLD="${1:-900}"
TRACE="${2:-strace}"

mkdir -p "$OUT"
echo "[*] vmrestart"
timeout 180 "$HERE/vmrestart.sh" || { echo "vmrestart failed"; exit 1; }

echo "[*] waiting for guest"
for i in $(seq 1 24); do
    if timeout 10 "$VMEXEC" exec "echo UP" 2>/dev/null | grep -q UP; then
        echo "    guest up"
        break
    fi
    sleep 5
done

echo "[*] setting module params (SKIP_OPS=${SKIP_OPS:-Y}, OPS_LOG=${OPS_LOG:-8}, COPY_WATCH=${COPY_WATCH:-0}, COPY_PAT=${COPY_PAT:-0}, COPY_DST=${COPY_DST:-0}, COPY_DST2=${COPY_DST2:-0}, CE_GRACE=${CE_GRACE:-8000})"
SKIP_OPS="${SKIP_OPS:-Y}"
OPS_LOG="${OPS_LOG:-8}"
COPY_WATCH="${COPY_WATCH:-0}"
COPY_PAT="${COPY_PAT:-0}"
COPY_DST="${COPY_DST:-0}"
COPY_DST2="${COPY_DST2:-0}"
CE_GRACE="${CE_GRACE:-8000}"
# The per-push/per-op tracing is behind the master sema_dbg switch (default
# off, so a normal boot stays quiet). Instrumenting implies enabling it.
DBG="${DBG:-N}"
if [ "$DBG" != "Y" ] && { [ "$COPY_WATCH" != "0" ] || [ "$COPY_PAT" != "0" ] || \
   [ "$COPY_DST" != "0" ] || [ "$COPY_DST2" != "0" ] || [ "$OPS_LOG" -gt 8 ] 2>/dev/null; }; then
    DBG=Y
fi
echo "    sema_dbg=$DBG"
sudo sh -c "echo $DBG > /sys/module/vgsp/parameters/sema_dbg; echo Y > /sys/module/vgsp/parameters/sema_fake_rel; echo $SKIP_OPS > /sys/module/vgsp/parameters/sema_skip_ops; echo $OPS_LOG > /sys/module/vgsp/parameters/sema_ops_log; echo $COPY_WATCH > /sys/module/vgsp/parameters/sema_copy_watch; echo $COPY_PAT > /sys/module/vgsp/parameters/sema_copy_pat; echo $COPY_DST > /sys/module/vgsp/parameters/sema_copy_dst; echo $COPY_DST2 > /sys/module/vgsp/parameters/sema_copy_dst2; echo $CE_GRACE > /sys/module/vgsp/parameters/sema_ce_grace_ms"

echo "[*] pushing guest tools"
timeout 300 "$HERE/push_guest_tools.sh" >/dev/null 2>&1 || { echo "push failed"; exit 1; }

echo "[*] loading nvidia modules in guest (kprobe symbols need them)"
timeout 90 "$VMEXEC" exec "nvidia-smi -L >/dev/null 2>&1; lsmod | grep -q nvidia_uvm && echo UVM_LOADED" 2>/dev/null | grep -q UVM_LOADED || echo "    WARN: nvidia_uvm not loaded"

echo "[*] installing guest kprobes (uvmt ON; uvsv/uvsvr OFF; 16 MB ring)"
timeout 60 "$VMEXEC" exec "sh /tmp/kprobes.sh" 2>/dev/null | grep -E "ok|FAIL" | head -8
timeout 30 "$VMEXEC" exec "TR=/sys/kernel/tracing; [ -d \$TR ] || TR=/sys/kernel/debug/tracing; echo 16384 > \$TR/buffer_size_kb; echo 0 > \$TR/events/kprobes/uvsv/enable; echo 0 > \$TR/events/kprobes/uvsvr/enable; echo 1 > \$TR/events/kprobes/uvmt/enable; echo 1 > \$TR/events/kprobes/uvtw/enable; echo 1 > \$TR/events/kprobes/uvbp/enable; echo 1 > \$TR/events/kprobes/uvch/enable" >/dev/null 2>&1

echo "[*] starting host dmesg capture"
sudo dmesg -w > "$OUT/hostdmesg.log" 2>&1 &
DMESG_PID=$!

echo "[*] starting pin_gr_stream + semfix"
( setsid nohup env SEMFIX_COUNTER_RETRY=10 \
    python3 "$HERE/pin_gr_stream.py" > "$OUT/pin_gr_stream.log" 2>&1 & )
sleep 1
( setsid nohup env SEMFIX_SKIP_PB="${SEMFIX_SKIP_PB:-0}" SEMFIX_COUNTER_RETRY=10 \
    python3 "$HERE/semfix_uvmt.py" 0.5 > "$OUT/semfix.log" 2>&1 & )
sleep 2

echo "[*] launching cdt (HOLD=$HOLD, $TRACE)"
if [ "$TRACE" = "strace" ]; then
    timeout 30 "$VMEXEC" exec \
        "rm -f /tmp/cdt.out /tmp/strace.log; echo '=== CDT RUN START (strace) ===' > /dev/ttyS0; CDT_HOLD=$HOLD CDT_WAIT=${CDT_WAIT:-0} nohup sh -c 'strace -f -tt -e trace=ioctl -o /tmp/strace.log /tmp/cdt 2>&1 | tee /tmp/cdt.out | stdbuf -oL tee /dev/ttyS0 >/dev/null' >/dev/null 2>&1 & echo STARTED" \
        >/dev/null 2>&1
elif [ "$TRACE" = "gdb" ]; then
    timeout 30 "$VMEXEC" exec "rm -f /tmp/cdt.out /tmp/bpwait.out; sync; echo CLEARED" >/dev/null 2>&1
    timeout 30 "$VMEXEC" exec \
        "rm -f /tmp/cdt.out /tmp/bpwait.out; CDT_PAUSE=60 CDT_HOLD=$HOLD nohup /tmp/cdt >/tmp/cdt.out 2>&1 & echo STARTED" \
        >/dev/null 2>&1
    PID=""
    for i in $(seq 1 12); do
        PID=$(timeout 20 "$VMEXEC" exec "pgrep -x cdt" 2>/dev/null | grep -E '^[0-9]+$' | head -1)
        [ -n "$PID" ] && break
        sleep 2
    done
    echo "    cdt pid=$PID; arming ${GDBSCRIPT:-bp999v2.py} (999/719 exit, serial+file)"
    ARMED=0
    for a in 1 2 3; do
        if timeout 40 "$VMEXEC" exec \
            "test -f /tmp/${GDBSCRIPT:-bp999v2.py} && nohup sh -c \"gdb -p '$PID' -batch -x /tmp/${GDBSCRIPT:-bp999v2.py} < /dev/null 2>&1 | tee /tmp/bpwait.out >/dev/ttyS0\" >/dev/null 2>&1 & echo ARMED" \
            2>/dev/null | grep -q ARMED; then
            ARMED=1
            break
        fi
        # The launch exec can time out even though nohup gdb started; verify
        # from the guest side before declaring the arm failed.
        if timeout 20 "$VMEXEC" exec "pgrep -f 'gdb -p' >/dev/null && echo GDBOK" 2>/dev/null | grep -q GDBOK; then
            echo "    arm attempt $a: exec timed out but gdb is running; continuing"
            ARMED=1
            break
        fi
        echo "    arm attempt $a failed; retrying"
        sleep 8
    done
    [ "$ARMED" = 1 ] || echo "    WARN: gdb arm failed 3x"
elif [ "$TRACE" = "gdb-launch" ]; then
    # Launch cdt INSIDE gdb so device-init code that runs before the
    # CDT_PAUSE (cuInit/cuDeviceGet) is visible to the breakpoints.
    timeout 30 "$VMEXEC" exec "rm -f /tmp/cdt.out /tmp/cdtgdb.out; sync; echo CLEARED" >/dev/null 2>&1
    timeout 30 "$VMEXEC" exec \
        "rm -f /tmp/cdt.out /tmp/cdtgdb.out; nohup sh -c 'gdb -batch -x /tmp/${GDBSCRIPT:-bp999v2.py} --args /tmp/cdt > /tmp/cdtgdb.out 2>&1' & echo STARTED" \
        >/dev/null 2>&1
    sleep 3
    PID=$(timeout 20 "$VMEXEC" exec "pgrep -x cdt" 2>/dev/null | grep -E '^[0-9]+$' | head -1)
    echo "    launched under gdb; cdt pid=${PID:-?} script=${GDBSCRIPT:-bp999v2.py}"
else
    timeout 30 "$VMEXEC" exec \
        "rm -f /tmp/cdt.out; echo '=== CDT RUN START (plain) ===' > /dev/ttyS0; CDT_HOLD=$HOLD nohup sh -c '/tmp/cdt 2>&1 | tee /tmp/cdt.out | stdbuf -oL tee /dev/ttyS0 >/dev/null' >/dev/null 2>&1 & echo STARTED" \
        >/dev/null 2>&1
fi

echo "[*] waiting for the run to finish (watch cdt.out)"
POLL_FILE=/tmp/cdt.out
[ "$TRACE" = "gdb-launch" ] && POLL_FILE=/tmp/cdtgdb.out
for i in $(seq 1 90); do
    sleep 2
    OUT_TXT=$(timeout 20 "$VMEXEC" exec "cat $POLL_FILE 2>/dev/null" 2>/dev/null | tail -6)
    if echo "$OUT_TXT" | grep -q "FAILED rc="; then
        echo "    failure observed after ~$((i*2))s"
        break
    fi
done

echo "[*] snapshotting guest dmesg"
timeout 60 "$VMEXEC" exec "dmesg > /tmp/guestdmesg.log; cp /tmp/cdt.out /tmp/cdt.out.snap; [ -f /tmp/strace.log ] && cp /tmp/strace.log /tmp/strace.log.snap; [ -f /tmp/bpwait.out ] && cp /tmp/bpwait.out /tmp/bpwait.out.snap; [ -f /tmp/cdtgdb.out ] && cp /tmp/cdtgdb.out /tmp/bpwait.out.snap; echo DONE" >/dev/null 2>&1
sleep 1
sudo kill "$DMESG_PID" 2>/dev/null

echo "[*] collecting artifacts to $OUT"
for f in cdt.out.snap strace.log.snap bpwait.out.snap guestdmesg.log; do
    timeout 60 "$VMEXEC" exec "cat /tmp/$f" > "$OUT/$f" 2>/dev/null
done
echo "[*] done: $OUT/cdt.out.snap $OUT/strace.log.snap $OUT/guestdmesg.log $OUT/hostdmesg.log"
tail -5 "$OUT/cdt.out.snap" 2>/dev/null