summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/track_waits.sh
blob: 6ae9154e16d8cf35ea07a1cc08cfeed954577a1d (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
#!/bin/bash
# track_waits.sh - guest-side wait sampler: while a CUDA client (cdt) runs,
# repeatedly dump the per-channel completion counters (values), the tracker
# wait entries (trkinfo.py, every 2nd pass) and the push pages the host could
# not resolve (read_va.py), so the last signal before a failure is recorded.
#
# Written for the guest (no host paths). Run as root in the guest:
#   sudo /tmp/track_waits.sh <pid> [samples] [sleep]
# Logs: /tmp/trk.log, /tmp/cnt.log, /tmp/push.log
set -u

PID="${1:?usage: track_waits.sh <pid> [samples] [sleep]}"
N="${2:-600}"
SLEEP="${3:-1}"
PAGE_VA="${PAGE_VA:-0x20400f000}"
COUNT="${COUNT:-20}"
STRIDE="${STRIDE:-16}"
OFFSET="${OFFSET:-0xec0}"
PUSH="${PUSH:-1}"

: > /tmp/trk.log
: > /tmp/cnt.log
: > /tmp/push.log

python3 - "$PID" "$PAGE_VA" "$COUNT" "$STRIDE" "$OFFSET" <<'PY' >> /tmp/cnt.log 2>&1 &
import os, sys, time
pid = int(sys.argv[1]); page = int(sys.argv[2], 16)
count = int(sys.argv[3]); stride = int(sys.argv[4], 16); off = int(sys.argv[5], 16)
pm = os.open('/proc/%d/pagemap' % pid, os.O_RDONLY)
mem = os.open('/proc/%d/mem' % pid, os.O_RDONLY)
while True:
    ts = time.strftime('%T')
    vals = []
    for i in range(count):
        va = page + off + i * stride
        try:
            os.lseek(pm, (va // 4096) * 8, 0)
            e = int.from_bytes(os.read(pm, 8), 'little')
            present = (e >> 63) & 1
            if present:
                v = int.from_bytes(os.pread(mem, 4, va), 'little')
                vals.append('%d:0x%x' % (i, v))
            else:
                vals.append('%d:-' % i)
        except OSError:
            vals.append('%d:ERR' % i)
    print('%s %s' % (ts, ' '.join(vals)), flush=True)
    time.sleep(0.5)
PY
CNTPID=$!

for i in $(seq 1 "$N"); do
    TS=$(date +%T.%3N)
    kill -0 "$PID" 2>/dev/null || { echo "PROCESS GONE at $TS (sample $i)" >> /tmp/trk.log; break; }

    if [ $((i % 2)) -eq 1 ] && [ "${GDB:-1}" = "1" ]; then
        echo "=== $TS sample $i ===" >> /tmp/trk.log
        timeout 8 gdb -p "$PID" -batch -x /tmp/trkinfo.py 2>&1 \
            | grep -vE "^\[|Reading symbols|^0x[0-9a-f]+ in |warning:" >> /tmp/trk.log
    fi

    if [ "$PUSH" = "1" ]; then
        {
            echo "=== $TS push pages ==="
            python3 /tmp/guest_pmap.py "$PID" 0x201000000 0x203400000 0x203400020 2>&1
            for va in 0x201000000 0x203400000 0x203400020; do
                echo "--- $va"
                timeout 5 python3 /tmp/read_va.py "$PID" "$va" 64 --u32 2>&1
            done
        } >> /tmp/push.log
    fi

    sleep "$SLEEP"
done
kill "$CNTPID" 2>/dev/null
echo "sampler done" >> /tmp/trk.log