175 lines
6.3 KiB
Bash
Executable File
175 lines
6.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
TP="${TP:?TP is required}"
|
|
PROFILE_BATCH="${PROFILE_BATCH:?PROFILE_BATCH is required}"
|
|
OUTPUT_ROOT="${OUTPUT_ROOT:?OUTPUT_ROOT is required}"
|
|
SERVER_PORT="${SERVER_PORT:?SERVER_PORT is required}"
|
|
VENV_ROOT="${VENV_ROOT:-/home/admin/cpfs/wjh/venvs/vllm-0.20.0-cu129-workload-regime-v2}"
|
|
MODEL_ROOT="${MODEL_ROOT:-/home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B}"
|
|
GPU_MEMORY_UTILIZATION="${GPU_MEMORY_UTILIZATION:-0.92}"
|
|
SERVER_READY_ATTEMPTS="${SERVER_READY_ATTEMPTS:-900}"
|
|
ACTIVE_ITERATIONS="${ACTIVE_ITERATIONS:-16}"
|
|
SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)"
|
|
MATERIALIZER="${SCRIPT_ROOT}/materialize_decode_batch.py"
|
|
CLIENT="${PROJECT_ROOT}/runs/frontier-fidelity-envelope-v1/qwen30_exact_trace_client.py"
|
|
SERVER_PID=""
|
|
|
|
if [[ ! "${PROFILE_BATCH}" =~ ^(2|4|6|8)$ ]]; then
|
|
echo "ERROR: PROFILE_BATCH must be 2, 4, 6, or 8" >&2
|
|
exit 1
|
|
fi
|
|
IFS=',' read -r -a GPU_IDS <<< "${CUDA_VISIBLE_DEVICES:?GPU allocation is required}"
|
|
if [[ "${#GPU_IDS[@]}" -ne "${TP}" ]]; then
|
|
echo "ERROR: TP=${TP}, but CUDA_VISIBLE_DEVICES=${CUDA_VISIBLE_DEVICES}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "${OUTPUT_ROOT}"
|
|
OUTPUT_ROOT="$(cd "${OUTPUT_ROOT}" && pwd)"
|
|
mkdir -p "${OUTPUT_ROOT}/logs" "${OUTPUT_ROOT}/provenance" \
|
|
"${OUTPUT_ROOT}/requests" "${OUTPUT_ROOT}/results" \
|
|
"${OUTPUT_ROOT}/trace-staging" "${OUTPUT_ROOT}/traces/profile"
|
|
exec > >(tee -a "${OUTPUT_ROOT}/logs/controller.log") 2>&1
|
|
|
|
cleanup() {
|
|
if [[ -n "${SERVER_PID}" ]] && kill -0 "${SERVER_PID}" 2>/dev/null; then
|
|
kill -TERM -- "-${SERVER_PID}" 2>/dev/null || true
|
|
for _ in $(seq 1 30); do
|
|
kill -0 "${SERVER_PID}" 2>/dev/null || break
|
|
sleep 1
|
|
done
|
|
kill -KILL -- "-${SERVER_PID}" 2>/dev/null || true
|
|
fi
|
|
SERVER_PID=""
|
|
}
|
|
trap cleanup EXIT INT TERM
|
|
|
|
sha256sum "${BASH_SOURCE[0]}" "${MATERIALIZER}" "${CLIENT}" \
|
|
"${MODEL_ROOT}/config.json" > "${OUTPUT_ROOT}/provenance/inputs.sha256"
|
|
"${VENV_ROOT}/bin/python" -c \
|
|
'import torch, transformers, vllm; print(f"torch={torch.__version__}"); print(f"transformers={transformers.__version__}"); print(f"vllm={vllm.__version__}")' \
|
|
> "${OUTPUT_ROOT}/provenance/runtime.versions"
|
|
nvidia-smi --query-gpu=index,name,uuid,driver_version,memory.total \
|
|
--format=csv,noheader > "${OUTPUT_ROOT}/provenance/gpus.before.csv"
|
|
ps -eo user,pid,ppid,etimes,pcpu,pmem,args --sort=pid \
|
|
> "${OUTPUT_ROOT}/provenance/processes.before.txt"
|
|
uptime > "${OUTPUT_ROOT}/provenance/uptime.before.txt"
|
|
env | sort > "${OUTPUT_ROOT}/provenance/environment.txt"
|
|
|
|
PROFILE_CONFIG="$("${VENV_ROOT}/bin/python" - "${OUTPUT_ROOT}/trace-staging" \
|
|
"${ACTIVE_ITERATIONS}" <<'PY'
|
|
import json
|
|
import sys
|
|
|
|
print(json.dumps({
|
|
"profiler": "torch",
|
|
"torch_profiler_dir": sys.argv[1],
|
|
"torch_profiler_with_stack": False,
|
|
"torch_profiler_record_shapes": True,
|
|
"torch_profiler_use_gzip": True,
|
|
"ignore_frontend": True,
|
|
"wait_iterations": 0,
|
|
"warmup_iterations": 2,
|
|
"active_iterations": int(sys.argv[2]),
|
|
}, separators=(",", ":")))
|
|
PY
|
|
)"
|
|
printf '%s\n' "${PROFILE_CONFIG}" \
|
|
> "${OUTPUT_ROOT}/provenance/profiler-config.json"
|
|
|
|
export TOKENIZERS_PARALLELISM=false
|
|
export VLLM_USE_V1=1
|
|
export HF_HUB_OFFLINE=1
|
|
export TRANSFORMERS_OFFLINE=1
|
|
export FLASHINFER_WORKSPACE_BASE="${FLASHINFER_WORKSPACE_BASE:-${OUTPUT_ROOT}/flashinfer-workspace}"
|
|
mkdir -p "${FLASHINFER_WORKSPACE_BASE}"
|
|
ulimit -n 65536
|
|
|
|
"${VENV_ROOT}/bin/python" "${MATERIALIZER}" --model "${MODEL_ROOT}" \
|
|
--batch "${PROFILE_BATCH}" --input-tokens 2048 --output-tokens 128 \
|
|
--output "${OUTPUT_ROOT}/requests/b${PROFILE_BATCH}.jsonl"
|
|
|
|
printf 'LAUNCH host=%s tp=%s batch=%s gpus=%s output=%s\n' \
|
|
"$(hostname)" "${TP}" "${PROFILE_BATCH}" "${CUDA_VISIBLE_DEVICES}" \
|
|
"${OUTPUT_ROOT}"
|
|
setsid "${VENV_ROOT}/bin/vllm" serve "${MODEL_ROOT}" \
|
|
--host 127.0.0.1 --port "${SERVER_PORT}" \
|
|
--served-model-name qwen30-decode-batch-profile \
|
|
--tensor-parallel-size "${TP}" \
|
|
--gpu-memory-utilization "${GPU_MEMORY_UTILIZATION}" \
|
|
--max-model-len 40960 --max-num-batched-tokens 8192 --max-num-seqs 16 \
|
|
--no-enable-prefix-caching --enable-chunked-prefill --no-enable-log-requests \
|
|
--enable-logging-iteration-details --profiler-config "${PROFILE_CONFIG}" \
|
|
> "${OUTPUT_ROOT}/logs/server.log" 2>&1 &
|
|
SERVER_PID=$!
|
|
|
|
READY=0
|
|
for _ in $(seq 1 "${SERVER_READY_ATTEMPTS}"); do
|
|
if curl -fsS --max-time 2 \
|
|
"http://127.0.0.1:${SERVER_PORT}/v1/models" \
|
|
> "${OUTPUT_ROOT}/results/models.json" 2>/dev/null; then
|
|
READY=1
|
|
break
|
|
fi
|
|
if ! kill -0 "${SERVER_PID}" 2>/dev/null; then
|
|
tail -200 "${OUTPUT_ROOT}/logs/server.log"
|
|
exit 1
|
|
fi
|
|
sleep 3
|
|
done
|
|
if [[ "${READY}" -ne 1 ]]; then
|
|
echo "ERROR: server readiness timeout" >&2
|
|
tail -200 "${OUTPUT_ROOT}/logs/server.log"
|
|
exit 1
|
|
fi
|
|
|
|
run_client() {
|
|
local label="$1"
|
|
"${VENV_ROOT}/bin/python" "${CLIENT}" \
|
|
--port "${SERVER_PORT}" \
|
|
--requests-file "${OUTPUT_ROOT}/requests/b${PROFILE_BATCH}.jsonl" \
|
|
--served-model qwen30-decode-batch-profile \
|
|
--output "${OUTPUT_ROOT}/results/${label}.json" \
|
|
--tpot-slo-ms 150 --timeout-seconds 1800
|
|
}
|
|
|
|
# Exercise the same graph and scheduler path twice before profiling.
|
|
run_client warmup-1
|
|
run_client warmup-2
|
|
|
|
curl -fsS -X POST "http://127.0.0.1:${SERVER_PORT}/start_profile" \
|
|
> "${OUTPUT_ROOT}/logs/start-profile.txt"
|
|
run_client profile
|
|
|
|
deadline=$((SECONDS + 120))
|
|
while (( SECONDS < deadline )); do
|
|
trace_count="$(find "${OUTPUT_ROOT}/trace-staging" -maxdepth 1 -type f \
|
|
-name '*.pt.trace.json*' | wc -l)"
|
|
if (( trace_count >= TP )); then
|
|
break
|
|
fi
|
|
sleep 2
|
|
done
|
|
trace_count="$(find "${OUTPUT_ROOT}/trace-staging" -maxdepth 1 -type f \
|
|
-name '*.pt.trace.json*' | wc -l)"
|
|
if (( trace_count < TP )); then
|
|
echo "ERROR: expected ${TP} rank traces, found ${trace_count}" >&2
|
|
exit 1
|
|
fi
|
|
find "${OUTPUT_ROOT}/trace-staging" -maxdepth 1 -type f \
|
|
-name '*.pt.trace.json*' -exec mv -t "${OUTPUT_ROOT}/traces/profile" {} +
|
|
curl -fsS -X POST "http://127.0.0.1:${SERVER_PORT}/stop_profile" \
|
|
> "${OUTPUT_ROOT}/logs/stop-profile.txt"
|
|
|
|
cleanup
|
|
nvidia-smi --query-gpu=index,name,uuid,driver_version,memory.total \
|
|
--format=csv,noheader > "${OUTPUT_ROOT}/provenance/gpus.after.csv"
|
|
find "${OUTPUT_ROOT}" -type f \
|
|
! -path '*/provenance/artifacts.sha256' -print0 \
|
|
| sort -z | xargs -0 sha256sum \
|
|
> "${OUTPUT_ROOT}/provenance/artifacts.sha256"
|
|
echo DECODE_BATCH_PROFILE_COMPLETE
|