#!/usr/bin/env bash # Start 2 vLLM instances with Mooncake kv_connector (kv_both) for MB2. # # Default config: both on local GPU 0 and 1 (intra-node A/B test). # Override via GPU_A / GPU_B / HOST_A / HOST_B env vars. # # This uses the FRESH venv at /home/admin/cpfs/wjh/agentic-kv-fresh/.venv # (vanilla vllm 0.18.1 + vanilla mooncake-transfer-engine 0.3.11), NOT # the dash0 patched build. # # Usage: # GPU_A=0 GPU_B=1 bash microbench/fresh_setup/start_vllm_pair.sh # bash microbench/fresh_setup/start_vllm_pair.sh status # bash microbench/fresh_setup/start_vllm_pair.sh stop set -eo pipefail FRESH_ROOT="/home/admin/cpfs/wjh/agentic-kv-fresh" VENV="${FRESH_ROOT}/.venv" MODEL="${MODEL:-/home/admin/cpfs/wjh/models/Qwen/Qwen3-Coder-30B-A3B-Instruct}" LOGS_DIR="${LOGS_DIR:-${FRESH_ROOT}/mb2_logs}" mkdir -p "${LOGS_DIR}" GPU_A="${GPU_A:-0}" GPU_B="${GPU_B:-1}" PORT_A=8000 PORT_B=8001 BP_A=8998 BP_B=8999 MASTER_A=29500 MASTER_B=29501 ROLE_A="${ROLE_A:-kv_both}" # kv_both (works) or kv_producer (hits vllm 0.18.1 bootstrap_server bug on D-side counterpart) ROLE_B="${ROLE_B:-kv_both}" # kv_both / kv_consumer MB2_LOG_ROOT="${FRESH_ROOT}/mb2_transfer_logs" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" INSTRUMENT="${SCRIPT_DIR}/instrument_mooncake.py" stop_all() { pkill -9 -f "vllm serve" 2>/dev/null || true pkill -9 -f "EngineCore" 2>/dev/null || true sleep 2 if [[ -f "${INSTRUMENT}" ]]; then python "${INSTRUMENT}" --revert --venv "${VENV}" 2>/dev/null || true fi } case "${1:-start}" in stop) stop_all exit 0 ;; status) for p in "${PORT_A}" "${PORT_B}"; do if curl -sf "http://127.0.0.1:${p}/health" >/dev/null 2>&1; then echo "port ${p}: UP" else echo "port ${p}: DOWN" fi done exit 0 ;; start) ;; *) echo "Unknown command: $1"; exit 1;; esac stop_all source "${VENV}/bin/activate" if [[ -f "${INSTRUMENT}" ]]; then echo "[mb2] applying instrumentation patch" python "${INSTRUMENT}" --apply --venv "${VENV}" else echo "[mb2] WARN instrument_mooncake.py not found at ${INSTRUMENT}; transfer logs will be absent" fi mkdir -p "${MB2_LOG_ROOT}/A" "${MB2_LOG_ROOT}/B" launch() { local idx="$1" gpu="$2" port="$3" bp="$4" master="$5" role="$6" local cfg="{\"kv_connector\":\"MooncakeConnector\",\"kv_role\":\"${role}\"}" echo "[mb2] launching ${idx}: gpu=${gpu} port=${port} bp=${bp} role=${role}" PYTHONHASHSEED=42 \ VLLM_MOONCAKE_BOOTSTRAP_PORT="${bp}" \ CUDA_VISIBLE_DEVICES="${gpu}" \ MASTER_PORT="${master}" \ MB2_LOG_DIR="${MB2_LOG_ROOT}/${idx}" \ nohup vllm serve "${MODEL}" \ --host 0.0.0.0 --port "${port}" \ --tensor-parallel-size 1 \ --trust-remote-code --enable-prefix-caching \ --dtype auto --gpu-memory-utilization 0.9 \ --max-model-len 200000 \ --kv-transfer-config "${cfg}" \ --enable-prompt-tokens-details \ > "${LOGS_DIR}/vllm_${idx}_gpu${gpu}.log" 2>&1 & disown } launch A "${GPU_A}" "${PORT_A}" "${BP_A}" "${MASTER_A}" "${ROLE_A}" sleep 3 launch B "${GPU_B}" "${PORT_B}" "${BP_B}" "${MASTER_B}" "${ROLE_B}" echo "[mb2] waiting for both /health endpoints..." for port in "${PORT_A}" "${PORT_B}"; do tries=0 while ! curl -sf "http://127.0.0.1:${port}/health" >/dev/null 2>&1; do tries=$((tries+1)) if [ ${tries} -gt 180 ]; then echo "[mb2] FATAL port ${port} did not come up in 6 min" tail -40 "${LOGS_DIR}/vllm_"*"_gpu"*".log" || true exit 1 fi sleep 2 done echo " port=${port} ready" done echo "[mb2] both instances UP" echo " A: 127.0.0.1:${PORT_A} (GPU ${GPU_A}, bp ${BP_A}, log_dir ${MB2_LOG_ROOT}/A)" echo " B: 127.0.0.1:${PORT_B} (GPU ${GPU_B}, bp ${BP_B}, log_dir ${MB2_LOG_ROOT}/B)" echo " vllm stdout: ${LOGS_DIR}"