mirror of
https://git.datalinker.icu/vllm-project/vllm.git
synced 2025-12-19 04:05:03 +08:00
[Benchmark] Convenience script for multiple parameter combinations
Signed-off-by: DarkLight1337 <tlleungac@connect.ust.hk>
This commit is contained in:
parent
5550ff9c25
commit
d06788477b
226
vllm/benchmarks/serve_multi.py
Normal file
226
vllm/benchmarks/serve_multi.py
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||||
|
import argparse
|
||||||
|
import contextlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shlex
|
||||||
|
import signal
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
_BAD_PARAMS_TYPE_MSG = (
|
||||||
|
"The parameters to vary should be expressed as a JSON list of dictionaries."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_combs(params: list[dict[str, object]]):
|
||||||
|
if not isinstance(params, list):
|
||||||
|
raise TypeError(f"{_BAD_PARAMS_TYPE_MSG} Found JSON type {type(params)}")
|
||||||
|
|
||||||
|
for comb in params:
|
||||||
|
if not isinstance(comb, dict):
|
||||||
|
raise TypeError(f"{_BAD_PARAMS_TYPE_MSG} Found item type {type(comb)}")
|
||||||
|
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
def _iter_cmd_key_candidates(param_key: str):
|
||||||
|
# We prefer "-" instead of "_", but the user-inputted command may contain "_"
|
||||||
|
yield "--" + param_key.replace("_", "-")
|
||||||
|
yield "--" + param_key.replace("-", "_")
|
||||||
|
yield "--" + param_key
|
||||||
|
|
||||||
|
|
||||||
|
def _override_args(cmd: list[str], params: dict[str, object]):
|
||||||
|
cmd = list(cmd)
|
||||||
|
|
||||||
|
for k, v in params.items():
|
||||||
|
for k_candidate in _iter_cmd_key_candidates(k):
|
||||||
|
try:
|
||||||
|
k_idx = cmd.index(k_candidate)
|
||||||
|
cmd[k_idx + 1] = str(v)
|
||||||
|
|
||||||
|
break
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
cmd.extend([next(_iter_cmd_key_candidates(k)), str(v)])
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
|
def _get_result_dir(output_dir: str, params: dict[str, object]):
|
||||||
|
return os.path.join(
|
||||||
|
output_dir,
|
||||||
|
"_".join(f"{k}={v}" for k, v in params.items()) + ".json",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_result_path(result_dir: str, run_number: int):
|
||||||
|
return os.path.join(result_dir, f"run={run_number}.json")
|
||||||
|
|
||||||
|
|
||||||
|
def benchmark_one_run(
|
||||||
|
serve_cmd: list[str],
|
||||||
|
bench_cmd: list[str],
|
||||||
|
serve_comb: dict[str, object],
|
||||||
|
run_number: int,
|
||||||
|
result_dir: str,
|
||||||
|
dry_run: bool,
|
||||||
|
):
|
||||||
|
result_path = _get_result_path(result_dir, run_number)
|
||||||
|
|
||||||
|
server_cmd = _override_args(serve_cmd, serve_comb)
|
||||||
|
benchmark_cmd = [
|
||||||
|
*bench_cmd,
|
||||||
|
"--save-result",
|
||||||
|
"--result-dir",
|
||||||
|
result_dir,
|
||||||
|
"--result-filename",
|
||||||
|
os.path.basename(result_path),
|
||||||
|
]
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(f"Parameter Combination: {serve_comb}")
|
||||||
|
print(f"Run Number: {run_number}")
|
||||||
|
print(f"Server command: {server_cmd}")
|
||||||
|
print(f"Benchmark command: {benchmark_cmd}")
|
||||||
|
print(f"Output file: {result_path}")
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
|
# Create new process group for clean termination
|
||||||
|
server_process = subprocess.Popen(server_cmd, start_new_session=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(benchmark_cmd, check=True)
|
||||||
|
finally:
|
||||||
|
if server_process.poll() is None:
|
||||||
|
# Process might already be terminated
|
||||||
|
with contextlib.suppress(ProcessLookupError):
|
||||||
|
# Kill entire process group
|
||||||
|
os.killpg(os.getpgid(server_process.pid), signal.SIGKILL)
|
||||||
|
|
||||||
|
return result_path
|
||||||
|
|
||||||
|
|
||||||
|
def benchmark_one_comb(
|
||||||
|
serve_cmd: list[str],
|
||||||
|
bench_cmd: list[str],
|
||||||
|
serve_comb: dict[str, object],
|
||||||
|
output_dir: str,
|
||||||
|
num_runs: int,
|
||||||
|
dry_run: bool,
|
||||||
|
):
|
||||||
|
result_dir = _get_result_dir(output_dir, serve_comb)
|
||||||
|
if not dry_run:
|
||||||
|
os.makedirs(result_dir, exist_ok=True)
|
||||||
|
|
||||||
|
result_data = list[dict[str, object]]()
|
||||||
|
for run_number in range(num_runs):
|
||||||
|
result_path = benchmark_one_run(
|
||||||
|
serve_cmd=serve_cmd,
|
||||||
|
bench_cmd=bench_cmd,
|
||||||
|
serve_comb=serve_comb,
|
||||||
|
run_number=run_number,
|
||||||
|
result_dir=result_dir,
|
||||||
|
dry_run=dry_run,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
|
with open(result_path, "rb") as f:
|
||||||
|
run_data = json.load(f)
|
||||||
|
|
||||||
|
run_data.update(serve_comb)
|
||||||
|
run_data["run_number"] = run_number
|
||||||
|
|
||||||
|
result_data.append(run_data)
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
|
with open(os.path.join(result_dir, "summary.json"), "w") as f:
|
||||||
|
json.dump(result_data, f)
|
||||||
|
|
||||||
|
|
||||||
|
def benchmark_all(
|
||||||
|
serve_cmd: list[str],
|
||||||
|
bench_cmd: list[str],
|
||||||
|
serve_params: list[dict[str, object]],
|
||||||
|
output_dir: str,
|
||||||
|
num_runs: int,
|
||||||
|
dry_run: bool,
|
||||||
|
):
|
||||||
|
for serve_comb in _validate_combs(serve_params):
|
||||||
|
benchmark_one_comb(
|
||||||
|
serve_cmd=serve_cmd,
|
||||||
|
bench_cmd=bench_cmd,
|
||||||
|
serve_comb=serve_comb,
|
||||||
|
output_dir=output_dir,
|
||||||
|
num_runs=num_runs,
|
||||||
|
dry_run=dry_run,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Run vLLM server benchmark on a parameter grid of settings."
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--serve-cmd",
|
||||||
|
type=str,
|
||||||
|
required=True,
|
||||||
|
help="The command used to run the server: `vllm serve ...`",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--bench-cmd",
|
||||||
|
type=str,
|
||||||
|
required=True,
|
||||||
|
help="The command used to run the benchmark: `vllm bench serve...`",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--serve-params",
|
||||||
|
type=str,
|
||||||
|
default=None,
|
||||||
|
help="Path to JSON file containing parameter combinations for the "
|
||||||
|
"`vllm serve` command.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-o",
|
||||||
|
"--output-dir",
|
||||||
|
type=str,
|
||||||
|
default="results",
|
||||||
|
help="The directory to which results are written.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--num-runs",
|
||||||
|
type=int,
|
||||||
|
default=3,
|
||||||
|
help="Number of runs per parameter combination",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--dry-run",
|
||||||
|
action="store_true",
|
||||||
|
help="If set, only prints the commands to run.",
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
serve_cmd = shlex.split(args.serve_cmd)
|
||||||
|
bench_cmd = shlex.split(args.bench_cmd)
|
||||||
|
|
||||||
|
if args.serve_params:
|
||||||
|
with open(args.serve_params, "rb") as f:
|
||||||
|
serve_params = json.load(f)
|
||||||
|
else:
|
||||||
|
serve_params = [{}]
|
||||||
|
|
||||||
|
benchmark_all(
|
||||||
|
serve_cmd=serve_cmd,
|
||||||
|
bench_cmd=bench_cmd,
|
||||||
|
serve_params=serve_params,
|
||||||
|
output_dir=args.output_dir,
|
||||||
|
num_runs=args.num_runs,
|
||||||
|
dry_run=args.dry_run,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
x
Reference in New Issue
Block a user