diff --git a/experiments/pro6000/kimi3_pro6000_pd_rdma/adaptive_config.env b/experiments/pro6000/kimi3_pro6000_pd_rdma/adaptive_config.env new file mode 100644 index 0000000..0443a32 --- /dev/null +++ b/experiments/pro6000/kimi3_pro6000_pd_rdma/adaptive_config.env @@ -0,0 +1,49 @@ +# PD 分离(MoonCake RDMA)长上下文 adaptive concurrency 配置。 +# +# 并发搜索:从 C=16 起 +16 递增(SEARCH_ADDEND=16),上限 64。 +# SEARCH_MULTIPLIER 为占位(库日志无条件引用它),实际走 SEARCH_ADDEND 加法递增。 +# 若初始并发就违反 TTFT SLO,回退 C=8 → C=1(SEARCH_INITIAL_BACKOFF)。 +# 若 C=1 仍严重超 SLO 或 OOM,停止该 shape。 +# SLO 方案 A:TTFT P95 随 ISL 分层递增(见 config.env 的 get_ttft_slo_ms)。 + +SEARCH_MULTIPLIER="${SEARCH_MULTIPLIER:-2}" +SEARCH_START_CONCURRENCY="${SEARCH_START_CONCURRENCY:-16}" +SEARCH_ADDEND=16 +SEARCH_MAX_CONCURRENCY="${SEARCH_MAX_CONCURRENCY:-64}" +# add16 初始探测违反 SLO 时回退:16 -> 8 -> 1。 +SEARCH_INITIAL_BACKOFF_CONCURRENCIES="8 1" + +# 长上下文场景不用整组跳过(64k 单并发 TTFT 可能就较高)。 +# TTFT_GROUP_SKIP_MS 留空禁用。 + +# TTFT_SLO_MS 是 flat fallback;config.env 定义了 get_ttft_slo_ms() 时以函数为准。 +TTFT_SLO_MS="${TTFT_SLO_MS:-4000}" +ENABLE_TTFT_SLO_STOP="${ENABLE_TTFT_SLO_STOP:-1}" + +# 吞吐饱和判定(沿用仓库默认)。 +TPS_MIN_GAIN_PCT="${TPS_MIN_GAIN_PCT:-2.0}" +PLATEAU_PATIENCE="${PLATEAU_PATIENCE:-2}" + +# Warmup 请求数上限(0=不限,按并发自适应)。长上下文大并发 warmup 昂贵,可设小上限。 +BENCH_WARMUP_MAX_REQUESTS="${BENCH_WARMUP_MAX_REQUESTS:-0}" + +# 每并发点的请求数 = concurrency * NUM_PROMPTS_MULTIPLIER。 +NUM_PROMPTS_MULTIPLIER="${NUM_PROMPTS_MULTIPLIER:-5}" + +# random 数据(ShareGPT 抽样)或 random-ids(整数 token)。长上下文建议 random-ids +# 避免 ShareGPT 前缀干扰测量;BENCH_DATASET_NAME 见 config.env。 +RANDOM_RANGE_RATIO="${RANDOM_RANGE_RATIO:-1.0}" + +# 长度容差与重试。 +INPUT_LENGTH_TOLERANCE_PCT="${INPUT_LENGTH_TOLERANCE_PCT:-5.0}" +OUTPUT_LENGTH_TOLERANCE_PCT="${OUTPUT_LENGTH_TOLERANCE_PCT:-10.0}" +MAX_POINT_RETRIES="${MAX_POINT_RETRIES:-1}" +SCENARIO_TIMEOUT_S="${SCENARIO_TIMEOUT_S:-3600}" +GPU_MEM_SAMPLE_INTERVAL_S="${GPU_MEM_SAMPLE_INTERVAL_S:-1}" + +# 过滤与限制(smoke 用)。 +TP_LIST="${TP_LIST:-}" +ISL_LIST="${ISL_LIST:-}" +OSL_LIST="${OSL_LIST:-}" +GRID_LIMIT="${GRID_LIMIT:-0}" +DRY_RUN="${DRY_RUN:-0}" \ No newline at end of file diff --git a/experiments/pro6000/kimi3_pro6000_pd_rdma/config.env b/experiments/pro6000/kimi3_pro6000_pd_rdma/config.env index 4f07f55..53173b0 100755 --- a/experiments/pro6000/kimi3_pro6000_pd_rdma/config.env +++ b/experiments/pro6000/kimi3_pro6000_pd_rdma/config.env @@ -30,5 +30,30 @@ DOCKER_CLIENT_IMAGE="${DOCKER_CLIENT_IMAGE:-lmsysorg/sglang:kimi-k3}" P_DEPLOY_PROFILE="${P_DEPLOY_PROFILE:-pro6000/kimi3_pro6000_pd_prefill}" D_DEPLOY_PROFILE="${D_DEPLOY_PROFILE:-pro6000/kimi3_pro6000_pd_decode}" +# ---- Bench client 配置(供 run_adaptive_concurrency_pd.sh 使用)---- +# 长上下文用 random-ids(整数 token),避免 ShareGPT 前缀干扰测量。 +BENCH_DATASET_NAME="${BENCH_DATASET_NAME:-random-ids}" +DATASET_PATH="${DATASET_PATH:-}" +SGLANG_BENCH_MODULE="${SGLANG_BENCH_MODULE:-sglang.bench_serving}" +GPU_MEM_SAMPLE_INTERVAL_S="${GPU_MEM_SAMPLE_INTERVAL_S:-1}" + # Per-scenario timeout to avoid hangs (seconds). -SCENARIO_TIMEOUT_S="${SCENARIO_TIMEOUT_S:-3600}" \ No newline at end of file +SCENARIO_TIMEOUT_S="${SCENARIO_TIMEOUT_S:-3600}" + +# --------------------------------------------------------------------------- +# Tiered TTFT SLO by input sequence length (方案 A). +# 长上下文场景 SLO 随 ISL 递增:prefill 有固有计算成本,TTFT 必须随输入放宽。 +# Kimi-K3 混合线性注意力在 RTX 6000D 上 prefill 较慢,阈值比 glm52 略宽。 +# 对应三个 shape: 1k->4s, 16k->15s, 64k->30s。 +# 由 adaptive_bench_lib.sh 的并发扫描调用:ttft_p95 超阈值即停止该 shape。 +# --------------------------------------------------------------------------- +get_ttft_slo_ms() { + local isl="$1" + if (( isl <= 2048 )); then echo 4000 + elif (( isl <= 8192 )); then echo 8000 + elif (( isl <= 32768 )); then echo 15000 + elif (( isl <= 131072 )); then echo 30000 + else echo 50000 + fi +} +TTFT_SLO_TIERS_DESC="≤2k:4s, ≤8k:8s, ≤32k:15s, ≤128k:30s, >128k:50s" diff --git a/experiments/pro6000/kimi3_pro6000_pd_rdma/matrix.json b/experiments/pro6000/kimi3_pro6000_pd_rdma/matrix.json new file mode 100644 index 0000000..8cadb6d --- /dev/null +++ b/experiments/pro6000/kimi3_pro6000_pd_rdma/matrix.json @@ -0,0 +1,9 @@ +{ + "comment": "PD 分离(MoonCake RDMA)长上下文 bench:并发 +16 递增搜索直到 TTFT SLO 或 OOM。ISL=64k/16k/1k。", + "mode": "Y", + "matrix": { + "65536": { "128": "Y" }, + "16384": { "1024": "Y" }, + "1024": { "4096": "Y" } + } +} \ No newline at end of file diff --git a/experiments/pro6000/kimi3_pro6000_pd_rdma/run_adaptive_concurrency_pd.sh b/experiments/pro6000/kimi3_pro6000_pd_rdma/run_adaptive_concurrency_pd.sh new file mode 100755 index 0000000..e715d6f --- /dev/null +++ b/experiments/pro6000/kimi3_pro6000_pd_rdma/run_adaptive_concurrency_pd.sh @@ -0,0 +1,133 @@ +#!/usr/bin/env bash +# PD 分离(MoonCake RDMA)长上下文 adaptive concurrency 搜索。 +# 并发 +16 递增(SEARCH_ADDEND=16),上限 64;TTFT P95 超 SLO 或 OOM 即停止。 +# PD 服务常驻(deploy_pd.sh 管理),本脚本只发请求,不启停服务器。 +# +# 用法: +# DRY_RUN=1 bash run_adaptive_concurrency_pd.sh # 预览 shape + 并发序列 +# bash run_adaptive_concurrency_pd.sh # 正式跑 +# ISL_LIST="1024" OSL_LIST="4096" bash ... # 只跑某 shape +# +# 产物: adaptive_results// (points/shapes/summary JSONL + CSV),与单组一致。 +set -Eeuo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +EXPERIMENT_NAME="$(basename "$SCRIPT_DIR")" + +# shellcheck source=/dev/null +source "${SCRIPT_DIR}/../../../scripts/common/lib.sh" +# shellcheck source=/dev/null +source "${SCRIPT_DIR}/../../../scripts/common/platform.sh" +# shellcheck source=/dev/null +source "${SCRIPT_DIR}/config.env" +# shellcheck source=/dev/null +source "${SCRIPT_DIR}/adaptive_config.env" +# shellcheck source=/dev/null +source "${SCRIPT_DIR}/../../../scripts/common/adaptive_bench_lib.sh" +# shellcheck source=/dev/null +source "${SCRIPT_DIR}/../../../scripts/common/deploy_cli.sh" + +# PD 服务由 deploy_pd.sh 常驻管理,本脚本不指定 TP/DP(固定 TP32×EP32)。 +TP="${TP:-32}" +DP="${DP:-1}" +ENGINE="sglang" +ENGINE_PORT="$SGLANG_PORT" # router 入口 31000 +RESULT_BASE="${RESULT_BASE:-${SCRIPT_DIR}/adaptive_results}" +ACTIVE_ENGINE_SERVER_LOG="" +DOCKER_IMAGE="${DOCKER_IMAGE:-${DOCKER_CLIENT_IMAGE:-lmsysorg/sglang:kimi-k3}}" + +if [[ -x "${VENV_CLIENT}/bin/python" ]]; then + PYTHON="${VENV_CLIENT}/bin/python" +else + PYTHON="$(command -v python3)" +fi + +# --------------------------------------------------------------------------- +# PD 常驻服务:server 生命周期函数全部 no-op(只探活,不启停)。 +# adaptive_bench_lib.sh 的 engine_* 调用会被安全绕过,搜索/产物逻辑保留。 +# --------------------------------------------------------------------------- +engine_is_healthy() { + curl --fail --silent --show-error --max-time 5 \ + "http://127.0.0.1:${ENGINE_PORT}/health" >/dev/null 2>&1 +} + +engine_start_server() { return 0; } +engine_stop_server() { return 0; } +engine_build_server_args() { echo "PD server managed by deploy_pd.sh"; } +engine_restart_server() { return 0; } + +engine_detect_oom() { + local detail_log="$1" + local pattern='CUDA out of memory|torch\.OutOfMemoryError|OutOfMemory|out of memory|OOM|RESOURCE_EXHAUSTED|Failed to allocate memory|error: [0-9]+: ERR_RESOURCE_STATE' + grep -Eiq "$pattern" "$detail_log" 2>/dev/null +} + +engine_run_bench() { + local isl="$1" + local osl="$2" + local concurrency="$3" + local num_prompts="$4" + local output_file="$5" + local warmup_requests + warmup_requests="$(adaptive_warmup_request_count "$concurrency")" + local -a bench_args=( + --backend sglang + --host 127.0.0.1 + --port "$ENGINE_PORT" + --tokenizer "$MODEL_PATH" + --dataset-name "$BENCH_DATASET_NAME" + --random-input-len "$isl" + --random-output-len "$osl" + --random-range-ratio "$RANDOM_RANGE_RATIO" + --num-prompts "$num_prompts" + --max-concurrency "$concurrency" + --request-rate 10000 + --warmup-requests "$warmup_requests" + --output-file "$output_file" + --output-details + --disable-tqdm + --flush-cache + ) + if [[ "$BENCH_DATASET_NAME" == "random" ]]; then + bench_args+=(--dataset-path "$DATASET_PATH") + elif [[ "$BENCH_DATASET_NAME" == "random-ids" ]]; then + : # random-ids 不需要 --tokenize-prompt + else + bench_args+=(--tokenize-prompt) + fi + + if [[ "$USE_DOCKER_CLIENT" == "1" ]]; then + local -a volume_args=(-v "${MODEL_PATH}:${MODEL_PATH}:ro" -v "${RESULT_BASE}:${RESULT_BASE}") + if [[ "$BENCH_DATASET_NAME" == "random" ]]; then + volume_args+=(-v "${DATASET_PATH}:${DATASET_PATH}:ro") + fi + docker run --rm \ + --network host \ + "${volume_args[@]}" \ + -e PYTHONUNBUFFERED=1 \ + -e HF_HUB_OFFLINE=1 \ + -e TRANSFORMERS_OFFLINE=1 \ + -e HF_DATASETS_OFFLINE=1 \ + --entrypoint python3 \ + "$DOCKER_IMAGE" \ + -m "$SGLANG_BENCH_MODULE" "${bench_args[@]}" + else + "$PYTHON" -m "$SGLANG_BENCH_MODULE" "${bench_args[@]}" + fi +} +export -f engine_run_bench + +export ENGINE_PORT MODEL_PATH RESULT_BASE DOCKER_IMAGE USE_DOCKER_CLIENT +export BENCH_DATASET_NAME DATASET_PATH RANDOM_RANGE_RATIO BENCH_WARMUP_MAX_REQUESTS PYTHON SGLANG_BENCH_MODULE +PARALLEL_CONFIGS=("${TP} ${DP}") + +export TP DP ENGINE PARALLEL_CONFIGS + +# PD 长上下文:C=16 起 +16 递增,上限 64;超 SLO 回退 C=8 -> 1。 +export SEARCH_START_CONCURRENCY=16 +export SEARCH_ADDEND=16 +export SEARCH_INITIAL_BACKOFF_CONCURRENCIES="8 1" +# 长上下文不用整组跳过(64k 单并发 TTFT 可能就较高)。 +export TTFT_GROUP_SKIP_MS="${TTFT_GROUP_SKIP_MS:-0}" + +adaptive_main "$@" \ No newline at end of file