#!/usr/bin/env bash # Cache-DiT + Larry LoRA over 8 Feishu Ref2VA cases, TP4 x 2 replicas. # Resumable per case. set -Eeuo pipefail MODEL=${MODEL:-/data/hf_models/MiniMax-H3} REPO_ROOT=/data/wxy/sskj-h3 INPUT_ROOT=$REPO_ROOT/throughput/sglang-base/inputs/ref2va-feishu-20260831 RECORDS=${RECORDS:-$REPO_ROOT/throughput/sglang-lora/records_rewritten.json} ASSETS_ROOT=$INPUT_ROOT/assets PYTHON=/root/.miniconda3/envs/sglang-lora/bin/python SGLANG_BIN=/root/.miniconda3/envs/sglang-lora/bin/sglang CACHE_PATCH=/data/ymrl/h3_cache_patch CLIENT_SCRIPT=$REPO_ROOT/throughput/sglang-base/scripts/ref2va_feishu_bench.py MEDIA_BIN_DIR=/root/.miniconda3/envs/deploy/bin LORA_PATH=/data/hf_models/MiniMax-H3-Turbo-Lora LORA_WEIGHT_NAME=minimax_h3_turbo_v4_step600_ema.safetensors LORA_NICKNAME=h3-turbo-v4-600 LORA_SCALE=1.0 LORA_MERGE_MODE=merge BASE_PORT=34010; PORT_STRIDE=10 MASTER_PORT_BASE=35000; SCHEDULER_PORT_BASE=36000 HOST=127.0.0.1 TP_SIZE=4; REPLICAS=2 NUM_INFERENCE_STEPS=9 SHORT_EDGE=768; ASPECT_RATIO=9:16; DURATION_SECONDS=15 FLOW_SHIFT=12.0; AUDIO_FLOW_SHIFT=3.0 CLIENT_WARMUP_STEPS=5 CACHE_FN=2; CACHE_BN=0; CACHE_WARMUP=2 MAX_ATTEMPTS=3; SERVER_START_TIMEOUT=1800 RUN_ID=${RUN_ID:-ref2va-feishu-cache-lora-tp4x2-3tier-$(date +%Y%m%d-%H%M%S)} RESULT_ROOT=${RESULT_ROOT:-$REPO_ROOT/throughput/sglang-lora/results/$RUN_ID} PROFILES=( "quality_rdt003_mc2 0.03 2 quality" "balanced_rdt005_mc3 0.05 3 balanced" "throughput_rdt010_mc4 0.10 4 throughput" ) declare -a SERVER_PIDS=() declare -a CLIENT_PIDS=() CURRENT_PROFILE_DIR="" mkdir -p "$RESULT_ROOT" MASTER_LOG="$RESULT_ROOT/matrix.log" exec > >(tee -a "$MASTER_LOG") 2>&1 log() { printf "[%s] %s\n" "$(date +%F_%T)" "$*"; } die() { log "ERROR: $*" >&2; exit 1; } [[ -x "$PYTHON" ]] || die "python missing" [[ -x "$SGLANG_BIN" ]] || die "sglang missing" [[ -f "$MEDIA_BIN_DIR/ffprobe" ]] || die "ffprobe missing" [[ -f "$CLIENT_SCRIPT" ]] || die "client missing" [[ -f "$CACHE_PATCH/sitecustomize.py" ]] || die "patch missing" [[ -f "$LORA_PATH/$LORA_WEIGHT_NAME" ]] || die "lora missing" [[ -f "$RECORDS" ]] || die "records missing" port_is_open() { "$PYTHON" - "$HOST" "$1" <<"PY" import socket, sys s = socket.socket(); s.settimeout(0.5) try: s.connect((sys.argv[1], int(sys.argv[2]))) except OSError: raise SystemExit(1) else: raise SystemExit(0) finally: s.close() PY } stop_servers() { local pid deadline ((${#SERVER_PIDS[@]})) || return 0 log "stopping ${#SERVER_PIDS[@]} server(s)" for pid in "${SERVER_PIDS[@]}"; do kill -INT -- "-$pid" 2>/dev/null || kill -INT "$pid" 2>/dev/null || true; done deadline=$((SECONDS + 180)) while ((SECONDS < deadline)); do local alive=0 for pid in "${SERVER_PIDS[@]}"; do kill -0 "$pid" 2>/dev/null && alive=1; done ((alive == 0)) && break sleep 2 done for pid in "${SERVER_PIDS[@]}"; do if kill -0 "$pid" 2>/dev/null; then kill -TERM -- "-$pid" 2>/dev/null || kill -TERM "$pid" 2>/dev/null || true sleep 5; kill -KILL -- "-$pid" 2>/dev/null || kill -KILL "$pid" 2>/dev/null || true fi wait "$pid" 2>/dev/null || true done SERVER_PIDS=() } cleanup() { local rc=$? pid trap - EXIT INT TERM for pid in "${CLIENT_PIDS[@]}"; do kill -TERM "$pid" 2>/dev/null || true; done stop_servers exit "$rc" } trap cleanup EXIT INT TERM wait_healthy() { local port=$1 pid=$2 log_file=$3 deadline=$((SECONDS + SERVER_START_TIMEOUT)) while ((SECONDS < deadline)); do curl -fsS --max-time 5 "http://${HOST}:${port}/health" >/dev/null 2>&1 && return 0 if ! kill -0 "$pid" 2>/dev/null; then tail -160 "$log_file" >&2 || true; return 1; fi sleep 5 done tail -160 "$log_file" >&2 || true return 1 } start_servers() { local tag=$1 rdt=$2 mc=$3 attempt=$4 local replica port master_port scheduler_port first_gpu gpu_csv offset gpu server_dir server_log candidate SERVER_PIDS=() for ((replica=0; replica"$server_dir/cuda_visible_devices.txt" log "starting cache+lora TP$TP_SIZE profile=$tag attempt=$attempt replica=$replica GPUs=$gpu_csv port=$port RDT=$rdt MC=$mc" CUDA_VISIBLE_DEVICES="$gpu_csv" \ PATH="$MEDIA_BIN_DIR:$PATH" \ PYTHONPATH="$CACHE_PATCH${PYTHONPATH:+:$PYTHONPATH}" \ PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \ PYTHONUNBUFFERED=1 TOKENIZERS_PARALLELISM=false SGLANG_USE_RUNAI_MODEL_STREAMER=false \ SGLANG_CACHE_DIT_ENABLED=true SGLANG_CACHE_DIT_FN="$CACHE_FN" SGLANG_CACHE_DIT_BN="$CACHE_BN" \ SGLANG_CACHE_DIT_RDT="$rdt" SGLANG_CACHE_DIT_MC="$mc" SGLANG_CACHE_DIT_WARMUP="$CACHE_WARMUP" \ SGLANG_CACHE_DIT_TAYLORSEER=false SGLANG_CACHE_DIT_SCM_PRESET=none SGLANG_CACHE_DIT_SCM_POLICY=dynamic \ lora_path="" setsid "$PYTHON" "$CACHE_PATCH/../scripts-nonexistent" 2>/dev/null; true CUDA_VISIBLE_DEVICES="$gpu_csv" \ PATH="$MEDIA_BIN_DIR:$PATH" \ PYTHONPATH="$CACHE_PATCH${PYTHONPATH:+:$PYTHONPATH}" \ PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \ PYTHONUNBUFFERED=1 TOKENIZERS_PARALLELISM=false SGLANG_USE_RUNAI_MODEL_STREAMER=false \ SGLANG_CACHE_DIT_ENABLED=true SGLANG_CACHE_DIT_FN="$CACHE_FN" SGLANG_CACHE_DIT_BN="$CACHE_BN" \ SGLANG_CACHE_DIT_RDT="$rdt" SGLANG_CACHE_DIT_MC="$mc" SGLANG_CACHE_DIT_WARMUP="$CACHE_WARMUP" \ SGLANG_CACHE_DIT_TAYLORSEER=false SGLANG_CACHE_DIT_SCM_PRESET=none SGLANG_CACHE_DIT_SCM_POLICY=dynamic \ setsid "$SGLANG_BIN" serve --model-path "$MODEL" --model-variant Ref2VA --backend sglang \ --performance-mode speed --num-gpus "$TP_SIZE" --tp-size "$TP_SIZE" --ulysses-degree 1 \ --use-fsdp-inference false --enable-torch-compile false --batching-max-size 1 --batching-delay-ms 0 \ --lora-path "$LORA_PATH" --lora-weight-name "$LORA_WEIGHT_NAME" --lora-nickname "$LORA_NICKNAME" \ --lora-scale "$LORA_SCALE" --lora-merge-mode "$LORA_MERGE_MODE" \ --host 0.0.0.0 --port "$port" --master-port "$master_port" --scheduler-port "$scheduler_port" \ --output-path "$server_dir/outputs" >"$server_log" 2>&1 & SERVER_PIDS+=("$!") done for ((replica=0; replica 0 except Exception: ok = False raise SystemExit(0 if ok else 1) PY } run_batch_pending() { local tag=$1 batch=$2 first_case=$3 warmup_steps=$4 local replica port case_number client_dir pid launched=0 failed=0 CLIENT_PIDS=() for ((replica=0; replica"$client_dir/client.log" 2>&1 & pid=$! CLIENT_PIDS+=("$pid") launched=$((launched + 1)) log "profile=$tag batch=$batch started case=$case_number replica=$replica port=$port" done ((launched > 0)) || return 0 for pid in "${CLIENT_PIDS[@]}"; do wait "$pid" || failed=1; done CLIENT_PIDS=() ((failed == 0)) || { log "profile=$tag batch=$batch had failed requests"; return 1; } } completed_count() { local case_number count=0 for case_number in {1..8}; do case_successful "$case_number" && count=$((count + 1)); done printf "%s\n" "$count" } run_profile() { local tag=$1 rdt=$2 mc=$3 objective=$4 attempt done_count pass_failed CURRENT_PROFILE_DIR="$RESULT_ROOT/$tag" mkdir -p "$CURRENT_PROFILE_DIR" [[ -f "$CURRENT_PROFILE_DIR/PROFILE_COMPLETED" ]] && { log "profile=$tag already done"; return 0; } { printf "profile=%s\nobjective=%s\n" "$tag" "$objective" printf "rdt=%s\nmc=%s\nfn=%s\nbn=%s\ncache_warmup=%s\nlora_merge_mode=%s\ntp_size=%s\nreplicas=%s\n" \ "$rdt" "$mc" "$CACHE_FN" "$CACHE_BN" "$CACHE_WARMUP" "$LORA_MERGE_MODE" "$TP_SIZE" "$REPLICAS" printf "num_inference_steps=%s\nshort_edge=%s\naspect_ratio=%s\nduration_seconds=%s\n" \ "$NUM_INFERENCE_STEPS" "$SHORT_EDGE" "$ASPECT_RATIO" "$DURATION_SECONDS" } >"$CURRENT_PROFILE_DIR/run_config.env" done_count=$(completed_count) log "===== profile=$tag RDT=$rdt MC=$mc existing_success=$done_count/8 =====" for ((attempt=1; attempt<=MAX_ATTEMPTS && done_count<8; attempt++)); do start_servers "$tag" "$rdt" "$mc" "$attempt" || { stop_servers; sleep 10; continue; } pass_failed=0 launched=0 # REPLICAS covers subset of the 8 cases per server pass; loop 4 chunks. for ((slice=0; slice<8; slice+=REPLICAS)); do for ((r=0; r"$client_dir/client.log" 2>&1 & pid=$! CLIENT_PIDS+=("$pid") launched=$((launched + 1)) log "profile=$tag started case=$case_number replica=$r port=$port" done for pid in "${CLIENT_PIDS[@]}"; do wait "$pid" || pass_failed=1; done CLIENT_PIDS=() done stop_servers done_count=$(completed_count) log "profile=$tag attempt=$attempt success=$done_count/8 pass_failed=$pass_failed" done ((done_count == 8)) || die "profile=$tag incomplete: $done_count/8" "${CLIENT_SCRIPT%%bench.py}custom_summary" 2>/dev/null || true printf "%s\n" "$(date -Is)" >"$CURRENT_PROFILE_DIR/PROFILE_COMPLETED" log "profile=$tag complete 8/8" } "$PYTHON" "$CLIENT_SCRIPT" summarize --help >/dev/null 2>&1 || true for profile in "${PROFILES[@]}"; do read -r tag rdt mc objective <<< "$profile" run_profile "$tag" "$rdt" "$mc" "$objective" done trap - EXIT INT TERM log "CACHE+LORA TP4x2 ALL PROFILES COMPLETE: $RESULT_ROOT"