Add vLLM v0.18.1 source tree with KV transfer abort fix
third_party/vllm/ now tracked in git for direct patch management.
Based on vLLM v0.18.1 release with one patch applied:
vllm/v1/core/sched/scheduler.py:
Replace fatal assert with graceful skip when KV transfer callback
arrives for an already-aborted request during PD disaggregated serving.
Future vLLM modifications should be made directly in third_party/vllm/
and committed normally. The patches/ directory is kept as documentation
of what changed from upstream.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
376
third_party/vllm/tests/config/base_model_arch_groundtruth.json
vendored
Normal file
376
third_party/vllm/tests/config/base_model_arch_groundtruth.json
vendored
Normal file
@@ -0,0 +1,376 @@
|
||||
{
|
||||
"state-spaces/mamba-130m-hf": {
|
||||
"architectures": [
|
||||
"MambaForCausalLM"
|
||||
],
|
||||
"model_type": "mamba",
|
||||
"text_model_type": "mamba",
|
||||
"hidden_size": 768,
|
||||
"total_num_hidden_layers": 24,
|
||||
"total_num_attention_heads": 0,
|
||||
"head_size": 0,
|
||||
"vocab_size": 50280,
|
||||
"total_num_kv_heads": 0,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.float32"
|
||||
},
|
||||
"mistralai/Mamba-Codestral-7B-v0.1": {
|
||||
"architectures": [
|
||||
"Mamba2ForCausalLM"
|
||||
],
|
||||
"model_type": "mamba",
|
||||
"text_model_type": "mamba",
|
||||
"hidden_size": 4096,
|
||||
"total_num_hidden_layers": 64,
|
||||
"total_num_attention_heads": 0,
|
||||
"head_size": 0,
|
||||
"vocab_size": 32768,
|
||||
"total_num_kv_heads": 0,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"ibm-nasa-geospatial/Prithvi-EO-2.0-300M-TL-Sen1Floods11": {
|
||||
"architectures": [
|
||||
"Terratorch"
|
||||
],
|
||||
"model_type": "timm_wrapper",
|
||||
"text_model_type": "timm_wrapper",
|
||||
"hidden_size": 0,
|
||||
"total_num_hidden_layers": 0,
|
||||
"total_num_attention_heads": 0,
|
||||
"head_size": 0,
|
||||
"vocab_size": 0,
|
||||
"total_num_kv_heads": 0,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": true,
|
||||
"dtype": "torch.float32"
|
||||
},
|
||||
"tiiuae/falcon-mamba-7b-instruct": {
|
||||
"architectures": [
|
||||
"FalconMambaForCausalLM"
|
||||
],
|
||||
"model_type": "falcon_mamba",
|
||||
"text_model_type": "falcon_mamba",
|
||||
"hidden_size": 4096,
|
||||
"total_num_hidden_layers": 64,
|
||||
"total_num_attention_heads": 0,
|
||||
"head_size": 0,
|
||||
"vocab_size": 65024,
|
||||
"total_num_kv_heads": 0,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"Zyphra/Zamba2-7B-instruct": {
|
||||
"architectures": [
|
||||
"Zamba2ForCausalLM"
|
||||
],
|
||||
"model_type": "zamba2",
|
||||
"text_model_type": "zamba2",
|
||||
"hidden_size": 3584,
|
||||
"total_num_hidden_layers": 81,
|
||||
"total_num_attention_heads": 32,
|
||||
"head_size": 224,
|
||||
"vocab_size": 32000,
|
||||
"total_num_kv_heads": 32,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"mosaicml/mpt-7b": {
|
||||
"architectures": [
|
||||
"MPTForCausalLM"
|
||||
],
|
||||
"model_type": "mpt",
|
||||
"text_model_type": "mpt",
|
||||
"hidden_size": 4096,
|
||||
"total_num_hidden_layers": 32,
|
||||
"total_num_attention_heads": 32,
|
||||
"head_size": 128,
|
||||
"vocab_size": 50432,
|
||||
"total_num_kv_heads": 32,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"databricks/dbrx-instruct": {
|
||||
"architectures": [
|
||||
"DbrxForCausalLM"
|
||||
],
|
||||
"model_type": "dbrx",
|
||||
"text_model_type": "dbrx",
|
||||
"hidden_size": 6144,
|
||||
"total_num_hidden_layers": 40,
|
||||
"total_num_attention_heads": 48,
|
||||
"head_size": 128,
|
||||
"vocab_size": 100352,
|
||||
"total_num_kv_heads": 8,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"tiiuae/falcon-7b": {
|
||||
"architectures": [
|
||||
"FalconForCausalLM"
|
||||
],
|
||||
"model_type": "falcon",
|
||||
"text_model_type": "falcon",
|
||||
"hidden_size": 4544,
|
||||
"total_num_hidden_layers": 32,
|
||||
"total_num_attention_heads": 71,
|
||||
"head_size": 64,
|
||||
"vocab_size": 65024,
|
||||
"total_num_kv_heads": 1,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"tiiuae/falcon-40b": {
|
||||
"architectures": [
|
||||
"FalconForCausalLM"
|
||||
],
|
||||
"model_type": "falcon",
|
||||
"text_model_type": "falcon",
|
||||
"hidden_size": 8192,
|
||||
"total_num_hidden_layers": 60,
|
||||
"total_num_attention_heads": 128,
|
||||
"head_size": 64,
|
||||
"vocab_size": 65024,
|
||||
"total_num_kv_heads": 8,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"luccafong/deepseek_mtp_main_random": {
|
||||
"architectures": [
|
||||
"DeepseekV3ForCausalLM"
|
||||
],
|
||||
"model_type": "deepseek_v3",
|
||||
"text_model_type": "deepseek_v3",
|
||||
"hidden_size": 2560,
|
||||
"total_num_hidden_layers": 5,
|
||||
"total_num_attention_heads": 32,
|
||||
"head_size": 576,
|
||||
"vocab_size": 129280,
|
||||
"total_num_kv_heads": 32,
|
||||
"num_experts": 72,
|
||||
"is_deepseek_mla": true,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"luccafong/deepseek_mtp_draft_random": {
|
||||
"architectures": [
|
||||
"DeepseekV3ForCausalLM"
|
||||
],
|
||||
"model_type": "deepseek_v3",
|
||||
"text_model_type": "deepseek_v3",
|
||||
"hidden_size": 2560,
|
||||
"total_num_hidden_layers": 10,
|
||||
"total_num_attention_heads": 32,
|
||||
"head_size": 576,
|
||||
"vocab_size": 129280,
|
||||
"total_num_kv_heads": 32,
|
||||
"num_experts": 72,
|
||||
"is_deepseek_mla": true,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"Qwen/Qwen3-Next-80B-A3B-Instruct": {
|
||||
"architectures": [
|
||||
"Qwen3NextForCausalLM"
|
||||
],
|
||||
"model_type": "qwen3_next",
|
||||
"text_model_type": "qwen3_next",
|
||||
"hidden_size": 2048,
|
||||
"total_num_hidden_layers": 48,
|
||||
"total_num_attention_heads": 16,
|
||||
"head_size": 256,
|
||||
"vocab_size": 151936,
|
||||
"total_num_kv_heads": 2,
|
||||
"num_experts": 512,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"tiny-random/qwen3-next-moe": {
|
||||
"architectures": [
|
||||
"Qwen3NextForCausalLM"
|
||||
],
|
||||
"model_type": "qwen3_next",
|
||||
"text_model_type": "qwen3_next",
|
||||
"hidden_size": 8,
|
||||
"total_num_hidden_layers": 4,
|
||||
"total_num_attention_heads": 16,
|
||||
"head_size": 32,
|
||||
"vocab_size": 151936,
|
||||
"total_num_kv_heads": 8,
|
||||
"num_experts": 32,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"zai-org/GLM-4.5": {
|
||||
"architectures": [
|
||||
"Glm4MoeForCausalLM"
|
||||
],
|
||||
"model_type": "glm4_moe",
|
||||
"text_model_type": "glm4_moe",
|
||||
"hidden_size": 5120,
|
||||
"total_num_hidden_layers": 92,
|
||||
"total_num_attention_heads": 96,
|
||||
"head_size": 128,
|
||||
"vocab_size": 151552,
|
||||
"total_num_kv_heads": 8,
|
||||
"num_experts": 160,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"baidu/ERNIE-4.5-21B-A3B-PT": {
|
||||
"architectures": [
|
||||
"Ernie4_5_MoeForCausalLM"
|
||||
],
|
||||
"model_type": "ernie4_5_moe",
|
||||
"text_model_type": "ernie4_5_moe",
|
||||
"hidden_size": 2560,
|
||||
"total_num_hidden_layers": 28,
|
||||
"total_num_attention_heads": 20,
|
||||
"head_size": 128,
|
||||
"vocab_size": 103424,
|
||||
"total_num_kv_heads": 4,
|
||||
"num_experts": 64,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"lmsys/gpt-oss-20b-bf16": {
|
||||
"architectures": [
|
||||
"GptOssForCausalLM"
|
||||
],
|
||||
"model_type": "gpt_oss",
|
||||
"text_model_type": "gpt_oss",
|
||||
"hidden_size": 2880,
|
||||
"total_num_hidden_layers": 24,
|
||||
"total_num_attention_heads": 64,
|
||||
"head_size": 64,
|
||||
"vocab_size": 201088,
|
||||
"total_num_kv_heads": 8,
|
||||
"num_experts": 32,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"deepseek-ai/DeepSeek-V3.2-Exp": {
|
||||
"architectures": [
|
||||
"DeepseekV32ForCausalLM"
|
||||
],
|
||||
"model_type": "deepseek_v32",
|
||||
"text_model_type": "deepseek_v32",
|
||||
"hidden_size": 7168,
|
||||
"total_num_hidden_layers": 61,
|
||||
"total_num_attention_heads": 128,
|
||||
"head_size": 576,
|
||||
"vocab_size": 129280,
|
||||
"total_num_kv_heads": 128,
|
||||
"num_experts": 256,
|
||||
"is_deepseek_mla": true,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"meta-llama/Llama-4-Scout-17B-16E-Instruct": {
|
||||
"architectures": [
|
||||
"Llama4ForConditionalGeneration"
|
||||
],
|
||||
"model_type": "llama4",
|
||||
"text_model_type": "llama4_text",
|
||||
"hidden_size": 5120,
|
||||
"total_num_hidden_layers": 48,
|
||||
"total_num_attention_heads": 40,
|
||||
"head_size": 128,
|
||||
"vocab_size": 202048,
|
||||
"total_num_kv_heads": 8,
|
||||
"num_experts": 16,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": true,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"nvidia/Llama-3_3-Nemotron-Super-49B-v1": {
|
||||
"architectures": [
|
||||
"DeciLMForCausalLM"
|
||||
],
|
||||
"model_type": "nemotron-nas",
|
||||
"text_model_type": "nemotron-nas",
|
||||
"hidden_size": 8192,
|
||||
"total_num_hidden_layers": 80,
|
||||
"total_num_attention_heads": 64,
|
||||
"head_size": 128,
|
||||
"vocab_size": 128256,
|
||||
"total_num_kv_heads": 8,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"XiaomiMiMo/MiMo-7B-RL": {
|
||||
"architectures": [
|
||||
"MiMoForCausalLM"
|
||||
],
|
||||
"model_type": "mimo",
|
||||
"text_model_type": "mimo",
|
||||
"hidden_size": 4096,
|
||||
"total_num_hidden_layers": 36,
|
||||
"total_num_attention_heads": 32,
|
||||
"head_size": 128,
|
||||
"vocab_size": 151680,
|
||||
"total_num_kv_heads": 8,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"meituan-longcat/LongCat-Flash-Chat": {
|
||||
"architectures": [
|
||||
"LongcatFlashForCausalLM"
|
||||
],
|
||||
"model_type": "longcat_flash",
|
||||
"text_model_type": "longcat_flash",
|
||||
"hidden_size": 6144,
|
||||
"total_num_hidden_layers": 28,
|
||||
"total_num_attention_heads": 64,
|
||||
"head_size": 576,
|
||||
"vocab_size": 131072,
|
||||
"total_num_kv_heads": 64,
|
||||
"num_experts": 512,
|
||||
"is_deepseek_mla": true,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.float32"
|
||||
},
|
||||
"nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16": {
|
||||
"architectures": [
|
||||
"NemotronHForCausalLM"
|
||||
],
|
||||
"model_type": "nemotron_h",
|
||||
"text_model_type": "nemotron_h",
|
||||
"hidden_size": 2688,
|
||||
"total_num_hidden_layers": 52,
|
||||
"total_num_attention_heads": 32,
|
||||
"head_size": 128,
|
||||
"vocab_size": 131072,
|
||||
"total_num_kv_heads": 2,
|
||||
"num_experts": 128,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
}
|
||||
}
|
||||
87
third_party/vllm/tests/config/draft_model_arch_groundtruth.json
vendored
Normal file
87
third_party/vllm/tests/config/draft_model_arch_groundtruth.json
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"abhigoyal/vllm-medusa-llama-68m-random": {
|
||||
"architectures": [
|
||||
"MedusaModel"
|
||||
],
|
||||
"model_type": "medusa",
|
||||
"text_model_type": "medusa",
|
||||
"hidden_size": 768,
|
||||
"total_num_hidden_layers": 1,
|
||||
"total_num_attention_heads": 0,
|
||||
"head_size": "Error: integer division or modulo by zero",
|
||||
"vocab_size": 32000,
|
||||
"total_num_kv_heads": 0,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.float32"
|
||||
},
|
||||
"luccafong/deepseek_mtp_draft_random": {
|
||||
"architectures": [
|
||||
"DeepSeekMTPModel"
|
||||
],
|
||||
"model_type": "deepseek_mtp",
|
||||
"text_model_type": "deepseek_mtp",
|
||||
"hidden_size": 2560,
|
||||
"total_num_hidden_layers": 1,
|
||||
"total_num_attention_heads": 32,
|
||||
"head_size": 576,
|
||||
"vocab_size": 129280,
|
||||
"total_num_kv_heads": 32,
|
||||
"num_experts": 72,
|
||||
"is_deepseek_mla": true,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "torch.bfloat16"
|
||||
},
|
||||
"eagle618/eagle-deepseek-v3-random": {
|
||||
"architectures": [
|
||||
"EagleDeepSeekMTPModel"
|
||||
],
|
||||
"model_type": "eagle",
|
||||
"text_model_type": "eagle",
|
||||
"hidden_size": 2560,
|
||||
"total_num_hidden_layers": 1,
|
||||
"total_num_attention_heads": 32,
|
||||
"head_size": 576,
|
||||
"vocab_size": 129280,
|
||||
"total_num_kv_heads": 32,
|
||||
"num_experts": 72,
|
||||
"is_deepseek_mla": true,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "bfloat16"
|
||||
},
|
||||
"yuhuili/EAGLE-LLaMA3-Instruct-8B": {
|
||||
"architectures": [
|
||||
"EagleLlamaForCausalLM"
|
||||
],
|
||||
"model_type": "eagle",
|
||||
"text_model_type": "eagle",
|
||||
"hidden_size": 4096,
|
||||
"total_num_hidden_layers": 1,
|
||||
"total_num_attention_heads": 32,
|
||||
"head_size": 128,
|
||||
"vocab_size": 128256,
|
||||
"total_num_kv_heads": 8,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "float16"
|
||||
},
|
||||
"yuhuili/EAGLE3-LLaMA3.1-Instruct-8B": {
|
||||
"architectures": [
|
||||
"Eagle3LlamaForCausalLM"
|
||||
],
|
||||
"model_type": "eagle",
|
||||
"text_model_type": "eagle",
|
||||
"hidden_size": 4096,
|
||||
"total_num_hidden_layers": 1,
|
||||
"total_num_attention_heads": 32,
|
||||
"head_size": 128,
|
||||
"vocab_size": 128256,
|
||||
"total_num_kv_heads": 8,
|
||||
"num_experts": 0,
|
||||
"is_deepseek_mla": false,
|
||||
"is_multimodal_model": false,
|
||||
"dtype": "float16"
|
||||
}
|
||||
}
|
||||
4
third_party/vllm/tests/config/test_config.yaml
vendored
Normal file
4
third_party/vllm/tests/config/test_config.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
port: 12312
|
||||
served_model_name: mymodel
|
||||
tensor_parallel_size: 2
|
||||
trust_remote_code: true
|
||||
111
third_party/vllm/tests/config/test_config_generation.py
vendored
Normal file
111
third_party/vllm/tests/config/test_config_generation.py
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
import pytest
|
||||
|
||||
from vllm.engine.arg_utils import EngineArgs
|
||||
from vllm.model_executor.layers.quantization.quark.utils import deep_compare
|
||||
|
||||
|
||||
def test_cuda_empty_vs_unset_configs(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Test that configs created with normal (untouched) CUDA_VISIBLE_DEVICES
|
||||
and CUDA_VISIBLE_DEVICES="" are equivalent. This ensures consistent
|
||||
behavior regardless of whether GPU visibility is disabled via empty string
|
||||
or left in its normal state.
|
||||
"""
|
||||
|
||||
def create_config():
|
||||
engine_args = EngineArgs(
|
||||
model="deepseek-ai/DeepSeek-V2-Lite", trust_remote_code=True
|
||||
)
|
||||
return engine_args.create_engine_config()
|
||||
|
||||
# Create config with CUDA_VISIBLE_DEVICES set normally
|
||||
normal_config = create_config()
|
||||
|
||||
# Create config with CUDA_VISIBLE_DEVICES=""
|
||||
with monkeypatch.context() as m:
|
||||
m.setenv("CUDA_VISIBLE_DEVICES", "")
|
||||
empty_config = create_config()
|
||||
|
||||
normal_config_dict = vars(normal_config)
|
||||
empty_config_dict = vars(empty_config)
|
||||
|
||||
# Remove instance_id before comparison as it's expected to be different
|
||||
normal_config_dict.pop("instance_id", None)
|
||||
empty_config_dict.pop("instance_id", None)
|
||||
|
||||
assert deep_compare(normal_config_dict, empty_config_dict), (
|
||||
'Configs with normal CUDA_VISIBLE_DEVICES and CUDA_VISIBLE_DEVICES=""'
|
||||
" should be equivalent"
|
||||
)
|
||||
|
||||
|
||||
def test_ray_runtime_env(monkeypatch: pytest.MonkeyPatch):
|
||||
# In testing, this method needs to be nested inside as ray does not
|
||||
# see the test module.
|
||||
def create_config():
|
||||
engine_args = EngineArgs(
|
||||
model="deepseek-ai/DeepSeek-V2-Lite", trust_remote_code=True
|
||||
)
|
||||
return engine_args.create_engine_config()
|
||||
|
||||
config = create_config()
|
||||
parallel_config = config.parallel_config
|
||||
assert parallel_config.ray_runtime_env is None
|
||||
|
||||
import ray
|
||||
|
||||
ray.init()
|
||||
|
||||
runtime_env = {
|
||||
"env_vars": {
|
||||
"TEST_ENV_VAR": "test_value",
|
||||
# In future ray versions, this will be default, so when setting a
|
||||
# task or actor with num_gpus=None/0, the visible devices env var
|
||||
# won't be overridden resulting in no GPUs being visible on a gpu
|
||||
# machine.
|
||||
"RAY_ACCEL_ENV_VAR_OVERRIDE_ON_ZERO": "0",
|
||||
},
|
||||
}
|
||||
|
||||
config_ref = ray.remote(create_config).options(runtime_env=runtime_env).remote()
|
||||
|
||||
config = ray.get(config_ref)
|
||||
parallel_config = config.parallel_config
|
||||
assert parallel_config.ray_runtime_env is not None
|
||||
assert (
|
||||
parallel_config.ray_runtime_env.env_vars().get("TEST_ENV_VAR") == "test_value"
|
||||
)
|
||||
|
||||
ray.shutdown()
|
||||
|
||||
|
||||
def test_unrecognized_env(monkeypatch):
|
||||
import os
|
||||
|
||||
from vllm.envs import environment_variables
|
||||
|
||||
# Remove any existing unrecognized VLLM env vars that might interfere
|
||||
for env in list(os.environ):
|
||||
if env.startswith("VLLM_") and env not in environment_variables:
|
||||
monkeypatch.delenv(env, raising=False)
|
||||
|
||||
# Test that if fail_on_environ_validation is True, then an error
|
||||
# is raised when an unrecognized vLLM environment variable is set
|
||||
monkeypatch.setenv("VLLM_UNRECOGNIZED_ENV_VAR", "some_value")
|
||||
engine_args = EngineArgs(
|
||||
fail_on_environ_validation=True,
|
||||
)
|
||||
with pytest.raises(ValueError, match="Unknown vLLM environment variable detected"):
|
||||
engine_args.create_engine_config()
|
||||
|
||||
# Test that if fail_on_environ_validation is False, then no error is raised
|
||||
engine_args = EngineArgs()
|
||||
engine_args.create_engine_config()
|
||||
|
||||
# Test that when the unrecognized env var is removed, no error is raised
|
||||
monkeypatch.delenv("VLLM_UNRECOGNIZED_ENV_VAR")
|
||||
engine_args = EngineArgs(
|
||||
fail_on_environ_validation=True,
|
||||
)
|
||||
engine_args.create_engine_config()
|
||||
203
third_party/vllm/tests/config/test_config_utils.py
vendored
Normal file
203
third_party/vllm/tests/config/test_config_utils.py
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
|
||||
import pytest
|
||||
|
||||
from vllm.config.utils import get_hash_factors, hash_factors, normalize_value
|
||||
|
||||
# Helpers
|
||||
|
||||
|
||||
def endswith_fqname(obj, suffix: str) -> bool:
|
||||
# normalize_value(type) returns fully-qualified name
|
||||
# Compare suffix to avoid brittle import paths.
|
||||
out = normalize_value(obj)
|
||||
return isinstance(out, str) and out.endswith(suffix)
|
||||
|
||||
|
||||
def expected_path(p_str: str = ".") -> str:
|
||||
import pathlib
|
||||
|
||||
p = pathlib.Path(p_str)
|
||||
return p.expanduser().resolve().as_posix()
|
||||
|
||||
|
||||
# Minimal dataclass to test get_hash_factors.
|
||||
# Avoid importing heavy vLLM configs.
|
||||
@dataclass
|
||||
class SimpleConfig:
|
||||
a: object
|
||||
b: object | None = None
|
||||
|
||||
|
||||
class DummyLogprobsMode(Enum):
|
||||
RAW_LOGITS = "raw_logits"
|
||||
|
||||
|
||||
def test_hash_factors_deterministic():
|
||||
"""Test that hash_factors produces consistent SHA-256 hashes"""
|
||||
factors = {"a": 1, "b": "test"}
|
||||
hash1 = hash_factors(factors)
|
||||
hash2 = hash_factors(factors)
|
||||
|
||||
assert hash1 == hash2
|
||||
# Dict key insertion order should not affect the hash.
|
||||
factors_reordered = {"b": "test", "a": 1}
|
||||
assert hash_factors(factors_reordered) == hash1
|
||||
assert len(hash1) == 64
|
||||
assert all(c in "0123456789abcdef" for c in hash1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"inp, expected",
|
||||
[
|
||||
(None, None),
|
||||
(True, True),
|
||||
(1, 1),
|
||||
(1.0, 1.0),
|
||||
("x", "x"),
|
||||
(b"ab", "6162"),
|
||||
(bytearray(b"ab"), "6162"),
|
||||
([1, 2], (1, 2)),
|
||||
({"b": 2, "a": 1}, (("a", 1), ("b", 2))),
|
||||
],
|
||||
)
|
||||
def test_normalize_value_matrix(inp, expected):
|
||||
"""Parametric input→expected normalization table."""
|
||||
assert normalize_value(inp) == expected
|
||||
|
||||
|
||||
def test_normalize_value_enum():
|
||||
# Enums normalize to (module.QualName, value).
|
||||
# DummyLogprobsMode uses a string payload.
|
||||
out = normalize_value(DummyLogprobsMode.RAW_LOGITS)
|
||||
assert isinstance(out, tuple)
|
||||
assert out[0].endswith("DummyLogprobsMode")
|
||||
# Expect string payload 'raw_logits'.
|
||||
assert out[1] == "raw_logits"
|
||||
|
||||
|
||||
def test_normalize_value_set_order_insensitive():
|
||||
# Sets are unordered; normalize_value sorts elements for determinism.
|
||||
assert normalize_value({3, 1, 2}) == normalize_value({1, 2, 3})
|
||||
|
||||
|
||||
def test_normalize_value_path_normalization():
|
||||
from pathlib import Path # local import to avoid global dependency
|
||||
|
||||
# Paths expand/resolve to absolute strings.
|
||||
# Stabilizes hashing across working dirs.
|
||||
assert normalize_value(Path(".")) == expected_path(".")
|
||||
|
||||
|
||||
def test_normalize_value_uuid_and_to_json():
|
||||
# Objects may normalize via uuid() or to_json_string().
|
||||
class HasUUID:
|
||||
def uuid(self):
|
||||
return "test-uuid"
|
||||
|
||||
class ToJson:
|
||||
def to_json_string(self):
|
||||
return '{"x":1}'
|
||||
|
||||
assert normalize_value(HasUUID()) == "test-uuid"
|
||||
assert normalize_value(ToJson()) == '{"x":1}'
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"bad",
|
||||
[
|
||||
(lambda x: x),
|
||||
(type("CallableInstance", (), {"__call__": lambda self: 0}))(),
|
||||
(lambda: (lambda: 0))(), # nested function instance
|
||||
],
|
||||
)
|
||||
def test_error_cases(bad):
|
||||
"""Inputs expected to raise TypeError."""
|
||||
# Reject functions/lambdas/callable instances
|
||||
# to avoid under-hashing.
|
||||
with pytest.raises(TypeError):
|
||||
normalize_value(bad)
|
||||
|
||||
|
||||
def test_enum_vs_int_disambiguation():
|
||||
# int stays primitive
|
||||
nf_int = normalize_value(1)
|
||||
assert nf_int == 1
|
||||
|
||||
# enum becomes ("module.QualName", value)
|
||||
nf_enum = normalize_value(DummyLogprobsMode.RAW_LOGITS)
|
||||
assert isinstance(nf_enum, tuple) and len(nf_enum) == 2
|
||||
enum_type, enum_val = nf_enum
|
||||
assert enum_type.endswith(".DummyLogprobsMode")
|
||||
assert enum_val == "raw_logits"
|
||||
|
||||
# Build factor dicts from configs with int vs enum
|
||||
f_int = get_hash_factors(SimpleConfig(1), set())
|
||||
f_enum = get_hash_factors(SimpleConfig(DummyLogprobsMode.RAW_LOGITS), set())
|
||||
# The int case remains a primitive value
|
||||
assert f_int["a"] == 1
|
||||
# The enum case becomes a tagged tuple ("module.QualName", "raw_logits")
|
||||
assert isinstance(f_enum["a"], tuple) and f_enum["a"][1] == "raw_logits"
|
||||
# Factor dicts must differ so we don't collide primitives with Enums.
|
||||
assert f_int != f_enum
|
||||
# Hash digests must differ correspondingly
|
||||
assert hash_factors(f_int) != hash_factors(f_enum)
|
||||
|
||||
# Hash functions produce stable hex strings
|
||||
h_int = hash_factors(f_int)
|
||||
h_enum = hash_factors(f_enum)
|
||||
assert isinstance(h_int, str) and len(h_int) == 64
|
||||
assert isinstance(h_enum, str) and len(h_enum) == 64
|
||||
|
||||
|
||||
def test_classes_are_types():
|
||||
"""Types normalize to FQNs; include real vLLM types."""
|
||||
# Only classes allowed; functions/lambdas are rejected.
|
||||
# Canonical form is the fully-qualified name.
|
||||
assert isinstance(normalize_value(str), str)
|
||||
|
||||
class LocalDummy:
|
||||
pass
|
||||
|
||||
assert endswith_fqname(LocalDummy, ".LocalDummy")
|
||||
|
||||
|
||||
def test_envs_compile_factors_stable():
|
||||
"""Test that envs.compile_factors() hash is stable across fresh initializations.
|
||||
|
||||
Uses subprocesses to ensure env vars with dynamic defaults (like UUIDs)
|
||||
are freshly generated each time, verifying they're properly ignored.
|
||||
"""
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
code = """
|
||||
import sys
|
||||
import logging
|
||||
logging.disable(logging.CRITICAL)
|
||||
from vllm import envs
|
||||
from vllm.config.utils import hash_factors
|
||||
print(hash_factors(envs.compile_factors()))
|
||||
"""
|
||||
|
||||
def get_hash_in_subprocess():
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-c", code],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
env={**dict(__import__("os").environ), "VLLM_LOGGING_LEVEL": "ERROR"},
|
||||
)
|
||||
return result.stdout.strip()
|
||||
|
||||
hash1 = get_hash_in_subprocess()
|
||||
hash2 = get_hash_in_subprocess()
|
||||
|
||||
assert hash1 == hash2, (
|
||||
"compile_factors hash differs between fresh initializations - "
|
||||
"dynamic env vars may not be properly ignored"
|
||||
)
|
||||
6
third_party/vllm/tests/config/test_config_with_model.yaml
vendored
Normal file
6
third_party/vllm/tests/config/test_config_with_model.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Same as test_config.yaml but with model specified
|
||||
model: config-model
|
||||
port: 12312
|
||||
served_model_name: mymodel
|
||||
tensor_parallel_size: 2
|
||||
trust_remote_code: true
|
||||
156
third_party/vllm/tests/config/test_model_arch_config.py
vendored
Normal file
156
third_party/vllm/tests/config/test_model_arch_config.py
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
"""Tests for ModelArchitectureConfig and its integration with ModelConfig."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from vllm.config import ModelConfig, ParallelConfig, SpeculativeConfig
|
||||
from vllm.transformers_utils.model_arch_config_convertor import (
|
||||
ModelArchConfigConvertorBase,
|
||||
)
|
||||
|
||||
BASE_TRUST_REMOTE_CODE_MODELS = {
|
||||
"nvidia/Llama-3_3-Nemotron-Super-49B-v1",
|
||||
"nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16",
|
||||
"XiaomiMiMo/MiMo-7B-RL",
|
||||
# Excluded: Not available online right now
|
||||
# "FreedomIntelligence/openPangu-Ultra-MoE-718B-V1.1",
|
||||
"meituan-longcat/LongCat-Flash-Chat",
|
||||
}
|
||||
|
||||
BASE_MODELS_TO_TEST = [
|
||||
"state-spaces/mamba-130m-hf",
|
||||
"mistralai/Mamba-Codestral-7B-v0.1",
|
||||
# Excluded: terratorch/torchgeo version mismatch in CPU CI environment
|
||||
# (NonGeoDataset import error). Tested in model initialization tests.
|
||||
# "ibm-nasa-geospatial/Prithvi-EO-2.0-300M-TL-Sen1Floods11",
|
||||
"Zyphra/Zamba2-7B-instruct",
|
||||
# FIXME: mosaicml/mpt-7b has been deleted
|
||||
# "mosaicml/mpt-7b",
|
||||
# FIXME: databricks/dbrx-instruct has been deleted
|
||||
# "databricks/dbrx-instruct",
|
||||
"tiiuae/falcon-7b",
|
||||
"tiiuae/falcon-40b",
|
||||
"luccafong/deepseek_mtp_main_random",
|
||||
"Qwen/Qwen3-Next-80B-A3B-Instruct",
|
||||
"tiny-random/qwen3-next-moe",
|
||||
"zai-org/GLM-4.5",
|
||||
"baidu/ERNIE-4.5-21B-A3B-PT",
|
||||
# Models using base convertor
|
||||
"lmsys/gpt-oss-20b-bf16",
|
||||
"deepseek-ai/DeepSeek-V3.2-Exp",
|
||||
"meta-llama/Llama-4-Scout-17B-16E-Instruct",
|
||||
] + list(BASE_TRUST_REMOTE_CODE_MODELS)
|
||||
|
||||
# (target_model, draft_model, trust_remote_code)
|
||||
SPECULATIVE_MODELS = [
|
||||
("JackFram/llama-68m", "abhigoyal/vllm-medusa-llama-68m-random", False),
|
||||
("luccafong/deepseek_mtp_main_random", "luccafong/deepseek_mtp_draft_random", True),
|
||||
("eagle618/deepseek-v3-random", "eagle618/eagle-deepseek-v3-random", True),
|
||||
("meta-llama/Meta-Llama-3-8B-Instruct", "yuhuili/EAGLE-LLaMA3-Instruct-8B", True),
|
||||
("meta-llama/Llama-3.1-8B-Instruct", "yuhuili/EAGLE3-LLaMA3.1-Instruct-8B", True),
|
||||
]
|
||||
|
||||
|
||||
def _load_groundtruth(filename: str) -> dict:
|
||||
"""Load groundtruth JSON from the test directory."""
|
||||
groundtruth_path = Path(__file__).parent / filename
|
||||
with open(groundtruth_path) as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def _assert_model_arch_config(
|
||||
model_config, expected: dict, check_head_size: bool = True
|
||||
):
|
||||
"""Assert model_arch_config matches expected values."""
|
||||
model_arch_config = model_config.model_arch_config
|
||||
assert model_arch_config.architectures == expected["architectures"]
|
||||
assert model_arch_config.model_type == expected["model_type"]
|
||||
assert model_arch_config.text_model_type == expected["text_model_type"]
|
||||
assert model_arch_config.hidden_size == expected["hidden_size"]
|
||||
assert (
|
||||
model_arch_config.total_num_hidden_layers == expected["total_num_hidden_layers"]
|
||||
)
|
||||
assert (
|
||||
model_arch_config.total_num_attention_heads
|
||||
== expected["total_num_attention_heads"]
|
||||
)
|
||||
assert model_arch_config.vocab_size == expected["vocab_size"]
|
||||
assert model_arch_config.total_num_kv_heads == expected["total_num_kv_heads"]
|
||||
assert model_arch_config.num_experts == expected["num_experts"]
|
||||
assert model_arch_config.is_deepseek_mla == expected["is_deepseek_mla"]
|
||||
|
||||
torch_dtype = ModelArchConfigConvertorBase.get_torch_dtype(
|
||||
model_config.hf_config,
|
||||
model_config.model,
|
||||
revision=model_config.revision,
|
||||
config_format="hf",
|
||||
)
|
||||
assert str(torch_dtype) == expected["dtype"]
|
||||
|
||||
if check_head_size:
|
||||
assert model_arch_config.head_size == expected["head_size"]
|
||||
|
||||
|
||||
def _assert_model_config_methods(
|
||||
model_config, expected: dict, check_head_size: bool = True
|
||||
):
|
||||
"""Assert model_config methods return expected values."""
|
||||
assert model_config.architectures == expected["architectures"]
|
||||
assert model_config.get_vocab_size() == expected["vocab_size"]
|
||||
assert model_config.get_hidden_size() == expected["hidden_size"]
|
||||
assert model_config.get_total_num_kv_heads() == expected["total_num_kv_heads"]
|
||||
assert model_config.get_num_experts() == expected["num_experts"]
|
||||
assert (
|
||||
model_config.get_total_num_hidden_layers()
|
||||
== expected["total_num_hidden_layers"]
|
||||
)
|
||||
|
||||
if check_head_size:
|
||||
assert model_config.get_head_size() == expected["head_size"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("model", BASE_MODELS_TO_TEST)
|
||||
def test_base_model_arch_config(model: str):
|
||||
"""Test model architecture config for base models."""
|
||||
groundtruth = _load_groundtruth("base_model_arch_groundtruth.json")
|
||||
expected = groundtruth[model]
|
||||
|
||||
model_config = ModelConfig(
|
||||
model, trust_remote_code=model in BASE_TRUST_REMOTE_CODE_MODELS
|
||||
)
|
||||
|
||||
_assert_model_arch_config(model_config, expected)
|
||||
_assert_model_config_methods(model_config, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"target_model,draft_model,trust_remote_code", SPECULATIVE_MODELS
|
||||
)
|
||||
def test_draft_model_arch_config(
|
||||
target_model: str, draft_model: str, trust_remote_code: bool
|
||||
):
|
||||
"""Test model architecture config for draft/speculative models."""
|
||||
groundtruth = _load_groundtruth("draft_model_arch_groundtruth.json")
|
||||
expected = groundtruth[draft_model]
|
||||
|
||||
target_model_config = ModelConfig(target_model, trust_remote_code=trust_remote_code)
|
||||
speculative_config = SpeculativeConfig(
|
||||
model=draft_model,
|
||||
num_speculative_tokens=1,
|
||||
target_model_config=target_model_config,
|
||||
target_parallel_config=ParallelConfig(),
|
||||
)
|
||||
model_config = speculative_config.draft_model_config
|
||||
|
||||
# For medusa models, head_size may cause division by zero before
|
||||
# model_arch_config was introduced, so we conditionally check it
|
||||
check_head_size = isinstance(expected["head_size"], int)
|
||||
|
||||
_assert_model_arch_config(model_config, expected, check_head_size=check_head_size)
|
||||
_assert_model_config_methods(
|
||||
model_config, expected, check_head_size=check_head_size
|
||||
)
|
||||
53
third_party/vllm/tests/config/test_mp_reducer.py
vendored
Normal file
53
third_party/vllm/tests/config/test_mp_reducer.py
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
from vllm.config import VllmConfig
|
||||
from vllm.engine.arg_utils import AsyncEngineArgs
|
||||
from vllm.v1.engine.async_llm import AsyncLLM
|
||||
|
||||
|
||||
def test_mp_reducer():
|
||||
"""
|
||||
Test that _reduce_config reducer is registered when AsyncLLM is instantiated
|
||||
without transformers_modules. This is a regression test for
|
||||
https://github.com/vllm-project/vllm/pull/18640.
|
||||
"""
|
||||
|
||||
# Ensure transformers_modules is not in sys.modules
|
||||
if "transformers_modules" in sys.modules:
|
||||
del sys.modules["transformers_modules"]
|
||||
|
||||
with patch("multiprocessing.reducer.register") as mock_register:
|
||||
engine_args = AsyncEngineArgs(
|
||||
model="facebook/opt-125m",
|
||||
max_model_len=32,
|
||||
gpu_memory_utilization=0.1,
|
||||
disable_log_stats=True,
|
||||
)
|
||||
|
||||
async_llm = AsyncLLM.from_engine_args(
|
||||
engine_args,
|
||||
start_engine_loop=False,
|
||||
)
|
||||
|
||||
assert mock_register.called, (
|
||||
"multiprocessing.reducer.register should have been called"
|
||||
)
|
||||
|
||||
vllm_config_registered = False
|
||||
for call_args in mock_register.call_args_list:
|
||||
# Verify that a reducer for VllmConfig was registered
|
||||
if len(call_args[0]) >= 2 and call_args[0][0] == VllmConfig:
|
||||
vllm_config_registered = True
|
||||
|
||||
reducer_func = call_args[0][1]
|
||||
assert callable(reducer_func), "Reducer function should be callable"
|
||||
break
|
||||
|
||||
assert vllm_config_registered, (
|
||||
"VllmConfig should have been registered to multiprocessing.reducer"
|
||||
)
|
||||
|
||||
async_llm.shutdown()
|
||||
43
third_party/vllm/tests/config/test_multimodal_config.py
vendored
Normal file
43
third_party/vllm/tests/config/test_multimodal_config.py
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
|
||||
import pytest
|
||||
|
||||
from vllm.config.model import ModelConfig
|
||||
from vllm.config.multimodal import MultiModalConfig
|
||||
from vllm.v1.attention.backends.registry import AttentionBackendEnum
|
||||
|
||||
|
||||
def test_mm_encoder_attn_backend_str_conversion():
|
||||
config = MultiModalConfig(mm_encoder_attn_backend="FLASH_ATTN")
|
||||
assert config.mm_encoder_attn_backend == AttentionBackendEnum.FLASH_ATTN
|
||||
|
||||
|
||||
def test_mm_encoder_attn_backend_invalid():
|
||||
with pytest.raises(ValueError):
|
||||
MultiModalConfig(mm_encoder_attn_backend="not_a_backend")
|
||||
|
||||
|
||||
def test_mm_encoder_attn_backend_hash_updates():
|
||||
base_hash = MultiModalConfig().compute_hash()
|
||||
overridden_hash = MultiModalConfig(
|
||||
mm_encoder_attn_backend=AttentionBackendEnum.FLASH_ATTN
|
||||
).compute_hash()
|
||||
assert base_hash != overridden_hash
|
||||
|
||||
|
||||
def test_language_model_only_does_not_affect_mm_hash():
|
||||
"""language_model_only does not affect the ViT computation graph,
|
||||
so it should not change the multimodal config hash."""
|
||||
base_hash = MultiModalConfig().compute_hash()
|
||||
lm_only_hash = MultiModalConfig(language_model_only=True).compute_hash()
|
||||
assert base_hash == lm_only_hash
|
||||
|
||||
|
||||
def test_language_model_only_affects_model_hash():
|
||||
"""language_model_only affects the LM computation graph,
|
||||
so it should change the model config hash."""
|
||||
model = "llava-hf/llava-1.5-7b-hf"
|
||||
base_hash = ModelConfig(model).compute_hash()
|
||||
lm_only_hash = ModelConfig(model, language_model_only=True).compute_hash()
|
||||
assert base_hash != lm_only_hash
|
||||
Reference in New Issue
Block a user