94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
270 lines
9.3 KiB
Python
270 lines
9.3 KiB
Python
"""
|
|
Run one test prompt.
|
|
|
|
Usage:
|
|
python3 -m sglang.test.send_one
|
|
python3 -m sglang.test.send_one --profile --profile-steps 5
|
|
python3 -m sglang.test.send_one --profile --profile-by-stage
|
|
python3 -m sglang.test.send_one --stop "<|separator|>" "<|eos|>" --max-new-tokens 2048
|
|
"""
|
|
|
|
import argparse
|
|
import dataclasses
|
|
import json
|
|
import random
|
|
from typing import Optional
|
|
|
|
import requests
|
|
import tabulate
|
|
|
|
from sglang.profiler import run_profile
|
|
from sglang.srt.utils.network import resolve_base_url
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class BenchArgs:
|
|
host: str = "localhost"
|
|
port: int = 30000
|
|
base_url: str = ""
|
|
batch_size: int = 1
|
|
different_prompts: bool = False
|
|
random_input_len: Optional[int] = None
|
|
random_input_vocab_size: int = 32768
|
|
seed: Optional[int] = None
|
|
temperature: float = 0.0
|
|
max_new_tokens: int = 512
|
|
frequency_penalty: float = 0.0
|
|
presence_penalty: float = 0.0
|
|
json: bool = False
|
|
return_logprob: bool = False
|
|
prompt: str = (
|
|
"Human: Give me a fully functional FastAPI server. Show the python code.\n\nAssistant:"
|
|
)
|
|
image: bool = False
|
|
many_images: bool = False
|
|
stop: Optional[list] = None
|
|
stream: bool = False
|
|
profile: bool = False
|
|
profile_steps: int = 5
|
|
profile_by_stage: bool = False
|
|
profile_prefix: Optional[str] = None
|
|
|
|
@staticmethod
|
|
def add_cli_args(parser: argparse.ArgumentParser):
|
|
parser.add_argument("--host", type=str, default=BenchArgs.host)
|
|
parser.add_argument("--port", type=int, default=BenchArgs.port)
|
|
parser.add_argument(
|
|
"--base-url",
|
|
type=str,
|
|
default=BenchArgs.base_url,
|
|
help="Server base url. Overrides --host/--port when set.",
|
|
)
|
|
parser.add_argument("--batch-size", type=int, default=BenchArgs.batch_size)
|
|
parser.add_argument(
|
|
"--different-prompts",
|
|
action="store_true",
|
|
default=BenchArgs.different_prompts,
|
|
)
|
|
parser.add_argument(
|
|
"--random-input-len",
|
|
type=int,
|
|
default=BenchArgs.random_input_len,
|
|
help="Generate a random prompt of exactly this many tokens (random token IDs). "
|
|
"Each request in the batch gets unique random IDs, avoiding radix cache hits. "
|
|
"Useful for profiling to ensure the full prefill is captured.",
|
|
)
|
|
parser.add_argument(
|
|
"--random-input-vocab-size",
|
|
type=int,
|
|
default=BenchArgs.random_input_vocab_size,
|
|
help="Vocab size for --random-input-len. Token IDs are sampled from "
|
|
"[0, vocab_size). Default: 32768.",
|
|
)
|
|
parser.add_argument("--seed", type=int, default=BenchArgs.seed)
|
|
parser.add_argument("--temperature", type=float, default=BenchArgs.temperature)
|
|
parser.add_argument(
|
|
"--max-new-tokens", type=int, default=BenchArgs.max_new_tokens
|
|
)
|
|
parser.add_argument(
|
|
"--frequency-penalty", type=float, default=BenchArgs.frequency_penalty
|
|
)
|
|
parser.add_argument(
|
|
"--presence-penalty", type=float, default=BenchArgs.presence_penalty
|
|
)
|
|
parser.add_argument("--json", action="store_true")
|
|
parser.add_argument("--return-logprob", action="store_true")
|
|
parser.add_argument("--prompt", type=str, default=BenchArgs.prompt)
|
|
parser.add_argument("--stop", type=str, nargs="*", default=None)
|
|
parser.add_argument("--image", action="store_true")
|
|
parser.add_argument("--many-images", action="store_true")
|
|
parser.add_argument("--stream", action="store_true")
|
|
parser.add_argument("--profile", action="store_true")
|
|
parser.add_argument(
|
|
"--profile-steps", type=int, default=BenchArgs.profile_steps
|
|
)
|
|
parser.add_argument("--profile-by-stage", action="store_true")
|
|
parser.add_argument(
|
|
"--profile-prefix", type=str, default=BenchArgs.profile_prefix
|
|
)
|
|
|
|
@classmethod
|
|
def from_cli_args(cls, args: argparse.Namespace):
|
|
attrs = [attr.name for attr in dataclasses.fields(cls)]
|
|
return cls(**{attr: getattr(args, attr) for attr in attrs})
|
|
|
|
|
|
def send_one_prompt(
|
|
args: BenchArgs,
|
|
label: Optional[str] = None,
|
|
print_output: bool = True,
|
|
):
|
|
base_url = resolve_base_url(args.base_url, args.host, args.port)
|
|
|
|
# Construct the input
|
|
if args.random_input_len is not None:
|
|
# Generate random input ids within the vocab size
|
|
n = args.random_input_len
|
|
v = args.random_input_vocab_size
|
|
if args.batch_size == 1:
|
|
input_ids = random.choices(range(v), k=n)
|
|
else:
|
|
if args.different_prompts:
|
|
input_ids = [
|
|
random.choices(range(v), k=n) for _ in range(args.batch_size)
|
|
]
|
|
else:
|
|
input_ids = [random.choices(range(v), k=n)] * args.batch_size
|
|
else:
|
|
# Use the user inputs
|
|
input_ids = None
|
|
if args.batch_size == 1:
|
|
prompt = args.prompt
|
|
else:
|
|
if args.different_prompts:
|
|
prompt = [
|
|
f"Test case {i+1}: " + args.prompt for i in range(args.batch_size)
|
|
]
|
|
else:
|
|
prompt = [args.prompt] * args.batch_size
|
|
|
|
# If need image
|
|
if args.image:
|
|
assert args.batch_size == 1 and not args.random_input_len
|
|
args.prompt = (
|
|
"Human: Describe this image in a very short sentence.\n\nAssistant:"
|
|
)
|
|
image_data = "https://raw.githubusercontent.com/sgl-project/sglang/main/examples/assets/example_image.png"
|
|
elif args.many_images:
|
|
args.prompt = (
|
|
"Human: I have one reference image and many images."
|
|
"Describe their relationship in a very short sentence.\n\nAssistant:"
|
|
)
|
|
image_data = [
|
|
"https://raw.githubusercontent.com/sgl-project/sglang/main/examples/assets/example_image.png",
|
|
"https://raw.githubusercontent.com/sgl-project/sglang/main/examples/assets/example_image.png",
|
|
"https://raw.githubusercontent.com/sgl-project/sglang/main/examples/assets/example_image.png",
|
|
"https://raw.githubusercontent.com/sgl-project/sglang/main/examples/assets/example_image.png",
|
|
]
|
|
else:
|
|
image_data = None
|
|
|
|
# If need json output
|
|
if args.json:
|
|
assert args.batch_size == 1 and not args.random_input_len
|
|
prompt = (
|
|
"Human: What is the capital of France and how is that city like. "
|
|
"Give me 3 trivial information about that city. "
|
|
"Write in a format of json.\nAssistant:"
|
|
)
|
|
json_schema = "$$ANY$$"
|
|
else:
|
|
json_schema = None
|
|
|
|
json_data = {
|
|
**({"input_ids": input_ids} if input_ids is not None else {"text": prompt}),
|
|
"image_data": image_data,
|
|
"sampling_params": {
|
|
"sampling_seed": args.seed,
|
|
"temperature": args.temperature,
|
|
"max_new_tokens": args.max_new_tokens,
|
|
"frequency_penalty": args.frequency_penalty,
|
|
"presence_penalty": args.presence_penalty,
|
|
"json_schema": json_schema,
|
|
"stop": args.stop,
|
|
},
|
|
"return_logprob": args.return_logprob,
|
|
"stream": args.stream,
|
|
}
|
|
|
|
# Run profiler if requested
|
|
if args.profile:
|
|
print(f"Running profiler with {args.profile_steps} steps...")
|
|
run_profile(
|
|
url=base_url,
|
|
num_steps=args.profile_steps,
|
|
activities=["CPU", "GPU"],
|
|
profile_by_stage=args.profile_by_stage,
|
|
profile_prefix=args.profile_prefix,
|
|
)
|
|
|
|
# Send the request
|
|
response = requests.post(
|
|
f"{base_url}/generate",
|
|
json=json_data,
|
|
stream=args.stream,
|
|
)
|
|
|
|
if args.stream:
|
|
last_len = 0
|
|
for chunk in response.iter_lines(decode_unicode=False):
|
|
chunk = chunk.decode("utf-8")
|
|
if chunk and chunk.startswith("data:"):
|
|
if chunk == "data: [DONE]":
|
|
break
|
|
ret = json.loads(chunk[5:].strip("\n"))
|
|
chunk_str = ret["text"][last_len:]
|
|
last_len = len(ret["text"])
|
|
print(chunk_str, end="", flush=True)
|
|
else:
|
|
ret = response.json()
|
|
|
|
if args.batch_size > 1:
|
|
ret = ret[0]
|
|
|
|
if response.status_code != 200:
|
|
print(ret)
|
|
return 0, 0
|
|
|
|
# Print results
|
|
if "spec_verify_ct" in ret["meta_info"] and ret["meta_info"]["spec_verify_ct"] > 0:
|
|
acc_length = (
|
|
ret["meta_info"]["completion_tokens"] / ret["meta_info"]["spec_verify_ct"]
|
|
)
|
|
else:
|
|
acc_length = 1.0
|
|
|
|
latency = ret["meta_info"]["e2e_latency"]
|
|
speed = ret["meta_info"]["completion_tokens"] / latency
|
|
tokens = ret["meta_info"]["completion_tokens"]
|
|
|
|
if not args.stream and print_output:
|
|
print(ret["text"])
|
|
|
|
print()
|
|
if label is not None:
|
|
print(label)
|
|
headers = ["Latency (s)", "Tokens", "Acc Length", "Speed (token/s)"]
|
|
rows = [[f"{latency:.3f}", f"{tokens}", f"{acc_length:.3f}", f"{speed:.2f}"]]
|
|
msg = tabulate.tabulate(rows, headers=headers, tablefmt="pretty")
|
|
print(msg)
|
|
|
|
return acc_length, speed
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
BenchArgs.add_cli_args(parser)
|
|
args = BenchArgs.from_cli_args(parser.parse_args())
|
|
|
|
send_one_prompt(args)
|