基准测试和性能分析#

基准测试#

  • 在不使用服务器的情况下,运行单个静态批次的延迟基准测试。参数与 launch_server.py 相同。 请注意,这是一个没有动态批处理服务器的简化测试脚本,因此对于真实服务器可以处理的批次大小,它可能会耗尽内存。真实服务器会将预填充分批处理,而此简化脚本则不会。

    • 不使用服务器(无需启动服务器)

      python -m sglang.bench_one_batch --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --batch 32 --input-len 256 --output-len 32
      
    • 使用服务器(请先使用 sglang.launch_server 启动服务器,然后运行以下命令)

      python -m sglang.bench_one_batch_server --base-url http://127.0.0.1:30000 --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --batch-size 32 --input-len 256 --output-len 32
      
  • 基准测试离线处理。此脚本将启动一个离线引擎并运行基准测试。

    python3 -m sglang.bench_offline_throughput --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --num-prompts 10
    
  • 基准测试在线服务。请使用 sglang.launch_server 启动服务器,然后运行以下命令。

    python3 -m sglang.bench_serving --backend sglang --num-prompt 10
    

使用 PyTorch Profiler 进行性能分析#

Pytorch Profiler 是一个方便的基础工具,用于检查内核执行时间、调用堆栈以及内核重叠和占用情况。

使用 sglang.bench_serving 对服务器进行性能分析#

# 设置追踪路径
export SGLANG_TORCH_PROFILER_DIR=/root/sglang/profile_log

# 启动服务器
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct

# 从客户端发送性能分析请求
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --sharegpt-output-len 100 --profile

请确保在服务器和客户端都设置了 SGLANG_TORCH_PROFILER_DIR,否则无法正确生成追踪文件。一种安全的方法是在 shell 的 .*rc 文件(如 bash 的 ~/.bashrc)中设置 SGLANG_TORCH_PROFILER_DIR

有关更多详细信息,请参阅 Bench Serving Guide

在 PD 分离模式下进行性能分析#

在 PD 分离模式下进行性能分析时,由于 torch profiler 的限制,预填充和解码工作进程必须单独进行性能分析。bench_serving 命令为此提供了专门的选项:

对预填充工作进程进行性能分析#

# 设置追踪路径
export SGLANG_TORCH_PROFILER_DIR=/root/sglang/profile_log

# 启动预填充和解码服务器(设置方法参见 PD 分离文档)
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --disaggregation-mode prefill
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --disaggregation-mode decode --port 30001 --base-gpu-id 1

# 启动路由器
python -m sglang_router.launch_router --pd-disaggregation --prefill http://127.0.0.1:30000 --decode http://127.0.0.1:30001 --host 0.0.0.0 --port 8000

# 发送针对预填充工作进程的性能分析请求
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --sharegpt-output-len 100 --profile --pd-separated --profile-prefill-url http://127.0.0.1:30000

对解码工作进程进行性能分析#

# 发送针对解码工作进程的性能分析请求
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --sharegpt-output-len 100 --profile --pd-separated --profile-decode-url http://127.0.0.1:30001

重要说明#

  • --profile-prefill-url--profile-decode-url互斥的 - 您不能同时分析两者

  • 这两个选项都支持多实例设置下的多个工作进程 URL:

    # 分析多个预填充工作进程
    python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --profile --pd-separated --profile-prefill-url http://127.0.0.1:30000 http://127.0.0.1:30002
    
    # 分析多个解码工作进程
    python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --profile --pd-separated --profile-decode-url http://127.0.0.1:30001 http://127.0.0.1:30003
    
  • 在启动服务器之前,确保在所有工作节点上设置了 SGLANG_TORCH_PROFILER_DIR

  • 有关设置 PD 分离的更多详细信息,请参阅 PD Disaggregation Guide

使用 sglang.bench_offline_throughput 对服务器进行性能分析#

export SGLANG_TORCH_PROFILER_DIR=/root/sglang/profile_log

# 使用 bench_one_batch.py 分析单个批次
# 批次大小可以通过 --batch 参数控制
python3 -m sglang.bench_one_batch --model-path meta-llama/Llama-3.1-8B-Instruct --batch 32 --input-len 1024 --output-len 10 --profile

# 使用 bench_offline_throughput.py 分析多个批次
python -m sglang.bench_offline_throughput --model-path meta-llama/Llama-3.1-8B-Instruct --dataset-name random --num-prompts 10 --profile --mem-frac=0.8

使用 sglang.profiler 对服务器进行性能分析#

当服务器正在运行时(例如,正在处理解码请求),您可以通过向服务器发送性能分析请求立即开始实时性能分析。

您可以通过运行 python3 -m sglang.profiler 来实现。例如:

# 终端 1: 发送生成请求
python3 -m sglang.test.send_one

# 终端 2: 在上述请求完成之前,在另一个终端中快速运行以下命令。
# 它将对上述请求的几个解码批次生成性能分析。
python3 -m sglang.profiler

您还可以将上述操作组合为单个命令

python3 -m sglang.test.send_one --profile

使用 HTTP API 端点对服务器进行性能分析#

SGLang 提供 HTTP API 端点来控制运行中服务器的性能分析。这允许您以编程方式启动和停止性能分析,这对于捕获特定工作负载模式很有用。

使用 /start_profile 端点#

/start_profile 端点在服务器上启动性能分析。您可以使用以下参数控制何时开始性能分析以及运行多长时间:

基本用法:

# 立即开始性能分析,进行 10 个步骤
curl -X POST http://127.0.0.1:30000/start_profile \
  -H "Content-Type: application/json" \
  -d '{
    "num_steps": 10
  }'

参数:

  • output_dir (可选):性能分析追踪文件将保存的目录。如果未指定,则使用 SGLANG_TORCH_PROFILER_DIR 环境变量,或默认使用 /tmp

  • num_steps (可选):要性能分析的步骤数。如果未指定,性能分析将持续进行,直到使用 /end_profile 手动停止

  • start_step (可选):开始性能分析的步骤编号(包含)。用于跳过预热迭代

  • activities (可选):要性能分析的活动列表,例如 ["CPU", "GPU"]。默认为 ["CPU", "GPU"]

  • merge_profiles (可选):是否合并分布式追踪。默认为 false

关于步骤范围的说明: 性能分析从 start_step(包含)开始,持续 num_steps 次迭代。例如,使用 start_step=3num_steps=10,性能分析将捕获步骤 3、4、5、6、7、8、9、10、11 和 12(总共 10 个步骤,从步骤 3 开始)。

使用 start_step 的高级用法:

# 等待 5 步(预热),然后进行 10 步性能分析
curl -X POST http://127.0.0.1:30000/start_profile \
  -H "Content-Type: application/json" \
  -d '{
    "output_dir": "/tmp/profiles",
    "start_step": 5,
    "num_steps": 10,
    "activities": ["CPU", "GPU"]
  }'

连续性能分析(手动停止):

# 启动性能分析时不使用 num_steps - 必须使用 /end_profile 手动停止
curl -X POST http://127.0.0.1:30000/start_profile

使用 /end_profile 端点#

/end_profile 端点停止正在进行的性能分析会话并保存追踪文件。

# 停止性能分析并保存追踪
curl -X POST http://127.0.0.1:30000/end_profile

这仅在您启动性能分析时未指定 num_steps 才需要。如果指定了 num_steps,性能分析将在该步骤数后自动停止。

示例工作流#

# 终端 1: 启动服务器
export SGLANG_TORCH_PROFILER_DIR=/tmp/profiles
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct

# 终端 2: 启动连续性能分析
curl -X POST http://127.0.0.1:30000/start_profile \
  -H "Content-Type: application/json" \
  -d '{
    "start_step": 3
  }'

# 终端 3: 发送请求以生成负载
python -m sglang.bench_serving --backend sglang --num-prompts 100

# 终端 2: 完成后停止性能分析
curl -X POST http://127.0.0.1:30000/end_profile

用于分布式追踪的性能分析追踪合并器#

SGLang 现在支持自动合并来自具有多种并行类型(TP、DP、PP、EP)的分布式设置的性能分析追踪。此功能对于分析分布式运行中的性能特别有用。

多节点性能分析和共享存储注意事项#

单节点性能分析输出合并完全受支持。在跨多个节点的分布式环境中进行性能分析时,所有节点都应该能够访问输出目录的共享存储(例如 NFS、Lustre),以实现追踪文件的合并。

如果节点之间没有可访问的共享存储,目前不支持在性能分析期间自动合并追踪文件。

HTTP API 用法#

# 启用自动追踪合并的性能分析
curl -X POST <BASE_URL>/start_profile \
  -H "Content-Type: application/json" \
  -d '{
    "output_dir": "/tmp/profiles", # 存储性能分析追踪的位置
    "num_steps": 10,
    "activities": ["CPU", "GPU"],
    "merge_profiles": true # 可选参数,用于合并性能分析追踪(默认=False)
  }'

命令行用法#

# 启用合并的性能分析
python -m sglang.profiler \
  --num-steps 10 \
  --cpu \
  --gpu \
  --output-dir /tmp/profiles \
  --merge-profiles # 可选参数,用于合并性能分析追踪(默认=False)

输出文件#

性能分析合并器生成:

  • 单个等级追踪文件:{profile_id}-TP-{tp}-DP-{dp}-PP-{pp}-EP-{ep}.trace.json.gz

  • 合并的追踪文件:merged-{profile_id}.trace.json.gz

可能的 PyTorch 错误#

如果在任何情况下遇到以下错误(例如,使用 qwen 2.5 VL):

RuntimeError: !stack.empty() INTERNAL ASSERT FAILED at "/pytorch/torch/csrc/autograd/profiler_python.cpp":983, please report a bug to PyTorch. Python replay stack is empty.

这可能是 PyTorch 错误,已在 Bug: vLLM ProfilerBug: torch.profiler.profile 中报告。作为一种解决方案,您可以使用环境变量禁用 with_stack,如下所示:

export SGLANG_PROFILE_WITH_STACK=False
python -m sglang.bench_offline_throughput --model-path meta-llama/Llama-3.1-8B-Instruct --dataset-name random --num-prompts 10 --profile --mem-frac=0.8

查看追踪#

追踪文件可以从以下位置加载和可视化:

  1. https://ui.perfetto.dev/(任何浏览器)

  2. chrome://tracing(仅限 Chrome 浏览器)

如果浏览器由于追踪文件太大而无法打开, 客户端可以通过控制提示数量和提示输出长度生成小追踪文件(<100MB)。 例如,在性能分析服务器时,

python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 2 --sharegpt-output-len 100 --profile

此命令使用 --num-prompts 参数将提示数量设置为 2,并使用 --sharegpt-output-len 参数将输出序列长度限制为 100,这样可以生成小追踪文件,浏览器可以流畅打开。

此外,如果您想通过 Trace 中的 CUDA 定位 SGLang Python 源代码,您需要在启动服务时禁用 CUDA Graph。这可以通过在启动服务的命令中使用 --disable-cuda-graph 参数来实现。

使用 Nsight 进行性能分析#

Nsight systems 是一个高级工具,它可以暴露更多性能分析细节,如寄存器和共享内存使用情况、带注释的代码区域以及低级 CUDA API 和事件。

  1. 先决条件:

    使用 apt 安装,或在 NVIDIA Docker 容器SGLang Docker 容器 中运行。

    # 安装 nsys
    # https://docs.nvidia.com/nsight-systems/InstallationGuide/index.html
    apt update
    apt install -y --no-install-recommends gnupg
    echo "deb http://developer.download.nvidia.com/devtools/repos/ubuntu$(source /etc/lsb-release; echo "$DISTRIB_RELEASE" | tr -d .)/$(dpkg --print-architecture) /" | tee /etc/apt/sources.list.d/nvidia-devtools.list
    apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
    apt update
    apt install nsight-systems-cli
    
  2. 要对单个批次进行性能分析,请使用

    nsys profile --trace-fork-before-exec=true --cuda-graph-trace=node python3 -m sglang.bench_one_batch --model meta-llama/Meta-Llama-3-8B --batch-size 64 --input-len 512
    
  3. 要对服务器进行性能分析,例如

    # 启动服务器,根据需要设置延迟和持续时间时间
    # 当持续时间用完后,服务器将被 nsys 杀死
    
    nsys profile --trace-fork-before-exec=true --cuda-graph-trace=node -o sglang.out --delay 60 --duration 70 python3 -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --disable-radix-cache
    
    # 客户端
    python3 -m sglang.bench_serving --backend sglang --num-prompts 1000 --dataset-name random --random-input 1024 --random-output 512
    

    实际上,我们建议用户将 --duration 参数设置为一个较大的值。当用户想要服务器停止性能分析时,首先运行:

    nsys sessions list
    

    以获取 profile-XXXXX 形式的会话 ID,然后运行:

    nsys stop --session=profile-XXXXX
    

    以手动杀死性能分析器并立即生成 nsys-rep 文件。

  4. 使用 NVTX 对代码区域进行注释,例如查看它们的执行时间。

    # 安装 nvtx
    pip install nvtx
    
    # 代码片段
    import nvtx
    with nvtx.annotate("description", color="color"):
        # 一些关键代码
    

使用 Nsight Systems 进行逐层 NVTX 性能分析#

SGLang 提供内置的逐层 NVTX 注释,可与 CUDA Profiler 结合使用,在 Nsight Systems 中进行详细的逐层性能分析。这对于识别层的性能瓶颈特别有用。

--enable-layerwise-nvtx-marker 与 Nsight Systems 和 /start_profile 一起使用#

--enable-layerwise-nvtx-marker 标志会自动向模型中的每一层添加 NVTX 标记。当与 Nsight Systems 性能分析结合使用时,这可以查看详细的逐层性能,特别强大。

方法 1:使用 /start_profile 和 CUDA_PROFILER(用于编程控制)

此方法允许您通过 HTTP API 精确控制何时启动/停止性能分析,而 Nsight Systems 正在运行。

  1. 在 Nsight Systems 下使用逐层 NVTX 启动服务器:

    # 终端 1: 使用 nsys 和 capture-range 选项启动服务器
    nsys profile --trace-fork-before-exec=true \
      --cuda-graph-trace=node \
      --capture-range=cudaProfilerApi \
      --capture-range-end=stop \
      -o layerwise_profile \
      python -m sglang.launch_server \
        --model-path meta-llama/Llama-3.1-8B-Instruct \
        --enable-layerwise-nvtx-marker \
        --disable-cuda-graph
    

    注意:对于 CUDA 图捕获的内核启动,不会发出 NVTX 标记。使用 --disable-cuda-graph 确保所有逐层 NVTX 标记在追踪中发出。

  2. 在另一个终端中,通过 /start_profile 控制使用 CUDA_PROFILER 活性的性能分析:

    # 终端 2: 等待服务器准备就绪,然后启动 CUDA 性能分析
    # 等待 3 步进行预热,然后进行 10 步性能分析
    curl -X POST http://127.0.0.1:30000/start_profile \
      -H "Content-Type: application/json" \
      -d '{
        "start_step": 3,
        "num_steps": 10,
        "activities": ["CUDA_PROFILER"]
      }'
    
  3. 发送请求以生成负载:

    # 终端 3: 生成工作负载
    python -m sglang.bench_serving --backend sglang --num-prompts 100
    
  4. 性能分析将在 10 步后自动停止(由于 num_steps: 10)。如果您没有指定 num_steps,则需要手动停止:

    # 终端 2: 仅在不指定 num_steps 时才需要
    curl -X POST http://127.0.0.1:30000/end_profile
    

    --capture-range=cudaProfilerApi 选项告诉 Nsight Systems 仅在 cudaProfilerStart()cudaProfilerStop() 调用之间(由 /start_profile/end_profile 触发)捕获数据,从而减少开销和文件大小。start_step 参数跳过前 3 步以避免捕获预热开销。

方法 2:更简单的不使用 /start_profile API 的方法

对于不需要精细控制性能分析启动/停止的更简单用例,您可以使用 Nsight Systems 捕获整个工作负载进行性能分析:

# 终端 1: 使用逐层 NVTX 启动服务器
# 注意:--disable-cuda-graph 确保发出所有 NVTX 标记
python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.1-8B-Instruct \
  --enable-layerwise-nvtx-marker \
  --disable-cuda-graph

# 终端 2: 对基准测试客户端进行性能分析
nsys profile --trace-fork-before-exec=true \
  --cuda-graph-trace=node \
  -o layerwise_profile \
  python -m sglang.bench_serving --backend sglang --num-prompts 10

此方法对整个客户端执行进行性能分析,包括所有服务器交互。逐层 NVTX 标记将在 Nsight Systems 时间线中可见。

查看性能分析结果:

使用 Nsight Systems 打开生成的 .qdrep 文件:

nsys-ui layerwise_profile.qdrep

在 Nsight Systems GUI 中,您将看到:

  • NVTX 范围:每个层显示为时间线中的标记范围,标记元数据中有详细信息

  • CUDA 内核:所有 GPU 内核与层注释一起显示

  • 层层次结构:完整的模块路径(例如 meta-llama/Meta-Llama-3.1-8B-Instruct.model.layers.0.self_attn.qkv_proj)有助于识别特定层。前缀使用来自 --model-path 的完整模型路径。

  • 张量形状:输入/输出维度和参数形状包含在 NVTX 标记数据中

逐层 NVTX 性能分析的好处:

  • 细粒度可见性:准确查看哪些层花费最多时间

  • 内存跟踪:识别具有大内存分配的层

  • 瓶颈识别:快速定位低效操作

  • 通信开销:在多 GPU 设置中,查看每层通信成本

  • 开发调试:验证模型架构更改具有预期的性能影响

其他提示#

  1. 您可以通过仅提供 config.json 文件,使用虚拟权重对模型进行基准测试。这允许快速测试模型变体而无需训练。为此,请向上述命令添加 --load-format dummy,然后您只需要检查点文件夹中有正确的 config.json

  2. 您可以使用 --json-model-override-args 对具有修改配置的模型进行基准测试(例如,更少的层数)。例如,您可以使用以下命令对只有 2 层和 2 个 kv 头的模型进行基准测试:

    python -m sglang.bench_one_batch --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --batch 32 --input-len 256 --output-len 32 --load-format dummy --json-model-override-args '{"num_hidden_layers": 1, "num_key_value_heads": 1}'
    
  3. 您可以使用 --python-backtrace=cuda 查看 CUDA 内核的 Python 调用堆栈,如 PyTorch Profiler 所示。(注意:这可能导致基于 CUDA 事件计时的不准确的长时间内核运行)

  4. 有关更多参数,请参阅 Nsight Systems User Guide