Files
vLLM/vllm/entrypoints/cli/snapshot.py
T
Nils MattesonTaneem IbrahimelehayymAndreas Karatzasmergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
13058faa49 [Frontend] Add reusable TP1 initialized-engine snapshots (#51360)
Signed-off-by: Nils Matteson <nilsmatteson@icloud.com>
Signed-off-by: Taneem Ibrahim <taneem.ibrahim@gmail.com>
Signed-off-by: Andreas Karatzas <Andreas.Karatzas@amd.com>
Co-authored-by: Taneem Ibrahim <taneem.ibrahim@gmail.com>
Co-authored-by: elehayym <52448798+Yuzu23@users.noreply.github.com>
Co-authored-by: Andreas Karatzas <akaratza@amd.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2026-09-21 23:18:49 +00:00

144 lines
4.8 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import argparse
import json
import os
import platform
import typing
from pathlib import Path
from vllm.entrypoints.cli.types import CLISubcommand
if typing.TYPE_CHECKING:
from vllm.utils.argparse_utils import FlexibleArgumentParser
else:
FlexibleArgumentParser = argparse.ArgumentParser
def validate_create_args(args: argparse.Namespace) -> None:
model = str(getattr(args, "model_tag", None) or args.model)
revision = str(getattr(args, "revision", None) or "")
if (
Path(model).exists()
or len(revision) != 40
or any(character not in "0123456789abcdefABCDEF" for character in revision)
):
raise ValueError(
"snapshot create requires an immutable remote model and "
"40-character --revision"
)
parallel_sizes = (
("tensor parallel", args.tensor_parallel_size),
("pipeline parallel", args.pipeline_parallel_size),
("data parallel", args.data_parallel_size),
("prefill context parallel", args.prefill_context_parallel_size),
)
for name, size in parallel_sizes:
if size != 1:
raise ValueError(f"snapshot create currently requires {name} size 1")
unsupported_frontend = (
args.api_server_count not in (None, 1)
or args.grpc
or args.headless
or args.api_key
or os.environ.get("VLLM_API_KEY")
or args.uds
or args.middleware
)
if unsupported_frontend or any(
(
args.ssl_keyfile,
args.ssl_certfile,
args.ssl_ca_certs,
args.enable_ssl_refresh,
args.ssl_ciphers,
)
):
raise ValueError(
"snapshot create requires one unauthenticated plaintext HTTP server"
)
if args.logprobs_mode in {"raw_logits", "processed_logits"}:
raise ValueError("snapshot canary requires a log-probability mode")
if any(
getattr(args, name, None) is not None
for name in ("speculative_config", "spec_method", "spec_model", "spec_tokens")
):
raise ValueError("snapshot create does not support speculative decoding")
if platform.system() != "Linux" or platform.machine() != "x86_64":
raise ValueError("snapshot create requires Linux x86_64")
def run_create(args: argparse.Namespace) -> None:
validate_create_args(args)
from vllm.snapshot.controller import create_snapshot
create_snapshot(args)
def run_inspect(args: argparse.Namespace) -> None:
from vllm.snapshot.manifest import inspect_snapshot
print(json.dumps(inspect_snapshot(Path(args.snapshot_dir)), indent=2))
def run_restore(args: argparse.Namespace) -> None:
from vllm.snapshot.controller import restore_snapshot
restore_snapshot(args)
class SnapshotSubcommand(CLISubcommand):
"""The `snapshot` subcommand for the vLLM CLI."""
name = "snapshot"
def __init__(self, *, create_requested: bool = False) -> None:
self.create_requested = create_requested
@staticmethod
def cmd(args: argparse.Namespace) -> None:
args.snapshot_dispatch(args)
def subparser_init(
self, subparsers: argparse._SubParsersAction
) -> FlexibleArgumentParser:
parser = subparsers.add_parser(
self.name,
help="Create, inspect, or restore an initialized vLLM snapshot.",
usage="vllm snapshot <create|inspect|restore> [options]",
)
actions = parser.add_subparsers(required=True, dest="snapshot_action")
create_parser = actions.add_parser(
"create", help="Create a snapshot from an initialized TP1 engine."
)
if self.create_requested:
from vllm.entrypoints.launchers.cli_args import make_arg_parser
create_parser = make_arg_parser(create_parser)
else:
create_parser.add_argument("model_tag", nargs="?")
create_parser.add_argument("--snapshot-dir", required=True)
create_parser.set_defaults(snapshot_dispatch=run_create)
inspect_parser = actions.add_parser(
"inspect", help="Inspect a snapshot without restoring it."
)
inspect_parser.add_argument("snapshot_dir")
inspect_parser.set_defaults(snapshot_dispatch=run_inspect)
restore_parser = actions.add_parser(
"restore", help="Restore a same-host TP1 snapshot."
)
restore_parser.add_argument("snapshot_dir")
restore_parser.add_argument("--host", default=None)
restore_parser.add_argument("--port", type=int, default=8000)
restore_parser.set_defaults(snapshot_dispatch=run_restore)
return parser
def cmd_init(*, create_requested: bool = False) -> list[CLISubcommand]:
return [SnapshotSubcommand(create_requested=create_requested)]