File size: 7,307 Bytes
8d0b310 | 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 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | #!/usr/bin/env bash
# CLI option smoke tests. Run from the repo root via `make test`.
# These do not exercise CUDA or tensor-parallel hardware.
set -uo pipefail
cd "$(dirname "$0")/.."
PASS=0
FAIL=0
LOG=$(mktemp)
ok() { PASS=$((PASS+1)); echo "ok $1"; }
fail() { FAIL=$((FAIL+1)); echo "FAIL $1"; }
assert_grep() {
# $1 = name, $2 = pattern, $3 = file
if grep -q -- "$2" "$3" 2>/dev/null; then ok "$1"; else
fail "$1 (pattern not in $3)"
echo " --- content of $3 ---"
head -20 "$3" | sed 's/^/ /'
fi
}
assert_not_grep() {
# $1 = name, $2 = pattern, $3 = file
if grep -q -- "$2" "$3" 2>/dev/null; then
fail "$1 (obsolete pattern found in $3)"
else
ok "$1"
fi
}
# Binaries to check
BINS=(./ds4 ./ds4-server ./ds4-bench ./ds4-agent)
NAMES=(ds4 ds4-server ds4-bench ds4-agent)
# 1: each binary's --help mentions both flags.
for i in "${!BINS[@]}"; do
name=${NAMES[$i]}; bin=${BINS[$i]}
if [ ! -x "$bin" ]; then
fail "$name not built — skipping help check"
continue
fi
"$bin" --help > "$LOG" 2>&1 || true
assert_grep "$name --help mentions --gpu-vram" "gpu-vram" "$LOG"
assert_grep "$name --help mentions --gpu-devices" "gpu-devices" "$LOG"
assert_grep "$name --help mentions --cuda-tensor-parallel" "cuda-tensor-parallel" "$LOG"
if [ "$name" = "ds4" ]; then
"$bin" --help distributed > "$LOG" 2>&1 || true
assert_grep "$name --help distributed mentions --tensor-parallel-token-prefill" \
"tensor-parallel-token-prefill" "$LOG"
assert_not_grep "$name --help distributed omits old --tp spellings" "--tp-" "$LOG"
fi
done
# 2: parser error on syntactically invalid value. For ds4-bench, we
# also pass --prompt-file /dev/null so it doesn't exit on the
# "specify exactly one of --prompt-file or --chat-prompt-file" check
# before the gpu-vram parser is reached.
for i in "${!BINS[@]}"; do
name=${NAMES[$i]}; bin=${BINS[$i]}
[ -x "$bin" ] || continue
if [ "$name" = "ds4-bench" ]; then
"$bin" --gpu-vram abc -m /dev/null --prompt-file /dev/null > "$LOG" 2>&1
else
"$bin" --gpu-vram abc -m /dev/null > "$LOG" 2>&1
fi
rc=$?
if [ $rc -eq 0 ]; then
fail "$name --gpu-vram abc should exit non-zero (got 0)"
else
ok "$name --gpu-vram abc exits non-zero ($rc)"
fi
# Confirm the shared value parser was reached, not merely the binary's
# unknown-option fallback.
if grep -q -- "--gpu-vram: not a number" "$LOG" 2>/dev/null &&
! grep -q "unknown option" "$LOG" 2>/dev/null; then
ok "$name --gpu-vram abc reaches shared parser"
else
fail "$name --gpu-vram abc did not reach shared parser"
head -10 "$LOG" | sed 's/^/ /'
fi
done
# 3: count mismatch.
for i in "${!BINS[@]}"; do
name=${NAMES[$i]}; bin=${BINS[$i]}
[ -x "$bin" ] || continue
if [ "$name" = "ds4-bench" ]; then
"$bin" --gpu-vram 40,12 --gpu-devices 0 -m /dev/null \
--prompt-file /dev/null > "$LOG" 2>&1
else
"$bin" --gpu-vram 40,12 --gpu-devices 0 -m /dev/null > "$LOG" 2>&1
fi
rc=$?
if [ $rc -ne 0 ] &&
grep -q -- "--gpu-devices count (1) does not match --gpu-vram count (2)" "$LOG" &&
! grep -q "unknown option" "$LOG"; then
ok "$name count-mismatch reaches shared parser ($rc)"
else
fail "$name count-mismatch did not reach shared parser"
head -10 "$LOG" | sed 's/^/ /'
fi
done
# 4: --cuda --help still works (the flag alone shouldn't break parsing).
for i in "${!BINS[@]}"; do
name=${NAMES[$i]}; bin=${BINS[$i]}
[ -x "$bin" ] || continue
"$bin" --cuda --help > "$LOG" 2>&1 || true
# Servers may print a usage banner; check help still surfaced.
if grep -qE "Usage:|usage:|--help" "$LOG"; then
ok "$name --cuda --help still prints help"
else
fail "$name --cuda --help did not print help text"
fi
done
# 5: --gpu-vram 0 short-circuit. We use ds4 (CLI) specifically because
# it produces predictable stdout/stderr.
if [ -x ./ds4 ]; then
./ds4 --gpu-vram 0 -m /dev/null > "$LOG" 2>&1
rc=$?
if [ $rc -ne 0 ]; then
ok "ds4 --gpu-vram 0 exits non-zero (expected: model-load fail)"
else
fail "ds4 --gpu-vram 0 returned 0 — unexpected"
fi
# The layout line must NOT appear (short-circuit happens before).
if grep -q "GPU config:" "$LOG"; then
fail "ds4 --gpu-vram 0 should NOT print GPU layout line"
head -10 "$LOG" | sed 's/^/ /'
else
ok "ds4 --gpu-vram 0 does not print GPU layout (short-circuit reached)"
fi
fi
# 6: tensor parallelism reuses the distributed role and address options, but
# owns the split and therefore rejects --layers.
if [ -x ./ds4 ]; then
./ds4 --metal --tensor-parallel --role coordinator --listen 127.0.0.1 9911 \
--layers 0:1 -m /dev/null > "$LOG" 2>&1
rc=$?
if [ $rc -ne 0 ] && grep -q "always uses one 50/50 worker" "$LOG"; then
ok "tensor parallel rejects explicit layer slices"
else
fail "tensor parallel accepted --layers or returned the wrong error"
fi
./ds4 --tensor-parallel --role worker -m /dev/null > "$LOG" 2>&1
rc=$?
if [ $rc -ne 0 ] && grep -q "requires --coordinator HOST PORT" "$LOG"; then
ok "tensor-parallel worker requires coordinator address"
else
fail "tensor-parallel worker returned the wrong missing-address error"
fi
./ds4 --metal --tensor-parallel --role coordinator --listen 127.0.0.1 9911 \
--transport tcp --tensor-parallel-token-prefill --debug-hash 2 \
--rdma-device rdma-test --rdma-gid-index 0 \
--inspect -m /dev/null > "$LOG" 2>&1
rc=$?
if [ $rc -ne 0 ] &&
grep -qE "model file is too small|another ds4 process is already running" "$LOG" &&
! grep -q "requires --layers" "$LOG"; then
ok "tensor-parallel common options reach model loading"
else
fail "tensor-parallel common options did not reach model loading"
fi
for old_arg in \
"--tp-coordinator 9911" \
"--tp-lead 9911" \
"--tp-coordinator-host 127.0.0.1" \
"--tp-lead-host 127.0.0.1" \
"--tp-worker 127.0.0.1 9911" \
"--tp-transport tcp" \
"--tp-debug-hash 2" \
"--tp-token-prefill"
do
# Word splitting is intentional: each item contains one old option
# and its former arguments.
./ds4 $old_arg -m /dev/null > "$LOG" 2>&1
rc=$?
if [ $rc -ne 0 ] && grep -q "unknown option" "$LOG"; then
ok "obsolete ${old_arg%% *} is rejected"
else
fail "obsolete ${old_arg%% *} was not rejected"
fi
done
fi
# 7: --gpu-vram 40,12 layout line.
if [ -x ./ds4 ]; then
./ds4 --gpu-vram 40,12 -m /dev/null > "$LOG" 2>&1
rc=$?
if grep -q "GPU config: 2 devices \[0,1\] requested, budgets 40,12 GB" "$LOG"; then
ok "ds4 --gpu-vram 40,12 prints expected layout line"
else
fail "ds4 --gpu-vram 40,12 missing or malformed layout line"
head -10 "$LOG" | sed 's/^/ /'
fi
fi
rm -f "$LOG"
echo ""
echo "test_gpu_args_cli: PASS=$PASS FAIL=$FAIL"
if [ $FAIL -gt 0 ]; then
exit 1
fi
exit 0
|