#!/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