forked from Karylab-cklius/vllm
Compare commits
245
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c846ccbda | ||
|
|
f2069b005b | ||
|
|
ccd49f6821 | ||
|
|
1c7bc18318 | ||
|
|
9a938df64e | ||
|
|
3da4a1b124 | ||
|
|
6871738777 | ||
|
|
aa4990a9a2 | ||
|
|
a4610da0c6 | ||
|
|
09cdcf34aa | ||
|
|
d2c671c29b | ||
|
|
b5a2adec4b | ||
|
|
78739e3bda | ||
|
|
89accad2cc | ||
|
|
3c8e49596c | ||
|
|
cec2ec1176 | ||
|
|
435f82d61a | ||
|
|
1c4b51b990 | ||
|
|
2e2c47928b | ||
|
|
80abe0de7d | ||
|
|
a9f7b2d41c | ||
|
|
d14e551a53 | ||
|
|
68567ef2df | ||
|
|
6bc6f2d86d | ||
|
|
1eb2cc961e | ||
|
|
31124749d1 | ||
|
|
9037498c22 | ||
|
|
db32b53e30 | ||
|
|
b529bfd6c5 | ||
|
|
f3df7a7231 | ||
|
|
485bbe1c6f | ||
|
|
a19ff2218a | ||
|
|
4f0d0049a0 | ||
|
|
13b83d77ad | ||
|
|
50241602fd | ||
|
|
12fe2a9aac | ||
|
|
89bd2c14d3 | ||
|
|
9c450b1027 | ||
|
|
635c38338a | ||
|
|
c441ad1c07 | ||
|
|
745bba5ea8 | ||
|
|
2cac89f9da | ||
|
|
3e6e33526d | ||
|
|
b91b7726e0 | ||
|
|
d3ad8e8bcd | ||
|
|
b80ce9dd2f | ||
|
|
b5495cc5f9 | ||
|
|
183a430c13 | ||
|
|
a346d589f5 | ||
|
|
7df3d7dada | ||
|
|
8dd1b702f2 | ||
|
|
f57ac274b2 | ||
|
|
6e919960af | ||
|
|
c88d3d4775 | ||
|
|
ab7fcbdd5d | ||
|
|
3b4a76b63f | ||
|
|
cc22621b51 | ||
|
|
77148992cf | ||
|
|
891cc4b9c5 | ||
|
|
1bdf9810aa | ||
|
|
ebfbcfe46a | ||
|
|
e9de72fe6c | ||
|
|
d272418f45 | ||
|
|
7ff7f5c8eb | ||
|
|
dced290769 | ||
|
|
93bad11912 | ||
|
|
0fbf42af84 | ||
|
|
e6cd8913dd | ||
|
|
859e4d436b | ||
|
|
4a083cc858 | ||
|
|
ca7e1f2c43 | ||
|
|
dec860fb19 | ||
|
|
0a49fb2b13 | ||
|
|
4a8abf37c7 | ||
|
|
01192139bf | ||
|
|
b9a7cd464c | ||
|
|
69bdd34542 | ||
|
|
ec67d7ae61 | ||
|
|
ecf9d83520 | ||
|
|
c9135db27c | ||
|
|
2a6c6b9429 | ||
|
|
ab66606993 | ||
|
|
9ea3a4015b | ||
|
|
560fb8b867 | ||
|
|
675cd5d228 | ||
|
|
7f616c327d | ||
|
|
c3c6d723fd | ||
|
|
41dcf49ca5 | ||
|
|
35e4dd4a69 | ||
|
|
4ce2d01453 | ||
|
|
16908e132e | ||
|
|
225936a1dd | ||
|
|
f6ba720963 | ||
|
|
b53b1c7ffe | ||
|
|
79ca54d221 | ||
|
|
09f3cd5c10 | ||
|
|
ea6078fe6a | ||
|
|
a0df04e477 | ||
|
|
e2352c2974 | ||
|
|
25faa1f4cc | ||
|
|
4583630b56 | ||
|
|
21da47dabe | ||
|
|
6c379b9e54 | ||
|
|
5099474633 | ||
|
|
058cc0a8b6 | ||
|
|
837db7605e | ||
|
|
bf2a393034 | ||
|
|
d682968aa9 | ||
|
|
021cdf72bc | ||
|
|
4cb5e746b6 | ||
|
|
22cc891108 | ||
|
|
afdcbd5d39 | ||
|
|
8d4f54966c | ||
|
|
351c72d6e5 | ||
|
|
7299e6509e | ||
|
|
08985351f3 | ||
|
|
5fd3b276f8 | ||
|
|
1e9f04da14 | ||
|
|
702214146c | ||
|
|
a331589394 | ||
|
|
e945169207 | ||
|
|
554352a311 | ||
|
|
421c1ec448 | ||
|
|
b4c80ec0fd | ||
|
|
f428718ffe | ||
|
|
4403af8fb5 | ||
|
|
d57888efa4 | ||
|
|
ed938ad7db | ||
|
|
731fb3323d | ||
|
|
8dd8b6ed78 | ||
|
|
e1a5fc406b | ||
|
|
b4092176b9 | ||
|
|
ebbb2d55ac | ||
|
|
2959a9273a | ||
|
|
1797576237 | ||
|
|
0d339cf135 | ||
|
|
5fd21eb0b2 | ||
|
|
9d4b87f4f0 | ||
|
|
58b2e89642 | ||
|
|
2659f60a1a | ||
|
|
091386a99b | ||
|
|
d112eb1ac7 | ||
|
|
2a47a9ff0f | ||
|
|
9c7c74bf10 | ||
|
|
5e27b2baf4 | ||
|
|
eb0fdeb1e8 | ||
|
|
46f74e144b | ||
|
|
0a7bacdcac | ||
|
|
8b2b566ea7 | ||
|
|
0b131b16c9 | ||
|
|
bcb518ad7a | ||
|
|
06e1e0885c | ||
|
|
1a59078c87 | ||
|
|
fa85ead2f3 | ||
|
|
e28e8c8782 | ||
|
|
ee0fd6984a | ||
|
|
d537122398 | ||
|
|
3d20275bb4 | ||
|
|
f694d43b33 | ||
|
|
3c6084bb0d | ||
|
|
68ff30d40e | ||
|
|
6d8fff5698 | ||
|
|
e2c58570ea | ||
|
|
43fa24e832 | ||
|
|
93bbe94d3a | ||
|
|
17bc144556 | ||
|
|
295232a26a | ||
|
|
56e4345226 | ||
|
|
e9993a52aa | ||
|
|
a46abb7ae6 | ||
|
|
4c62663315 | ||
|
|
d78650cf97 | ||
|
|
5bdc01bcc3 | ||
|
|
20a5f8b43b | ||
|
|
7b5d60cc37 | ||
|
|
14b438a98b | ||
|
|
2785a5e0e6 | ||
|
|
efd15e192a | ||
|
|
556b063e45 | ||
|
|
aa0ac8a661 | ||
|
|
b831374cf1 | ||
|
|
71bc19dbdd | ||
|
|
ef2c40dc00 | ||
|
|
4bf699d310 | ||
|
|
520828789c | ||
|
|
9d4dc4ca2f | ||
|
|
b9684d99e9 | ||
|
|
4fadf9c92c | ||
|
|
d8d95998dc | ||
|
|
475a6ad18a | ||
|
|
f2beaa80c8 | ||
|
|
8e27a9c215 | ||
|
|
7d567172fc | ||
|
|
f00e163f35 | ||
|
|
44b2512767 | ||
|
|
188c68798e | ||
|
|
c45f681932 | ||
|
|
89e8645a9e | ||
|
|
88a9cdd439 | ||
|
|
6f612fbedf | ||
|
|
506ec6d656 | ||
|
|
a52205bccf | ||
|
|
3d34f8cbdc | ||
|
|
eb04c769d3 | ||
|
|
ce3ef17bec | ||
|
|
bf5149b516 | ||
|
|
cca3365b73 | ||
|
|
040df8f2ea | ||
|
|
ced32bb474 | ||
|
|
c5e5c33fcd | ||
|
|
a8c86eeb16 | ||
|
|
7e179e4bc0 | ||
|
|
405c7cf283 | ||
|
|
3f53e2138f | ||
|
|
d53f4593ce | ||
|
|
ad32608e24 | ||
|
|
b2cfae777d | ||
|
|
3f1ff1ff14 | ||
|
|
c69c73418a | ||
|
|
ebf3a6d705 | ||
|
|
c4fd9794e9 | ||
|
|
7ad894c86a | ||
|
|
a7fdfeef72 | ||
|
|
8bf374955f | ||
|
|
9096659edb | ||
|
|
81d8f4ebac | ||
|
|
a9a8a32dcd | ||
|
|
9d808e2309 | ||
|
|
f3858d5422 | ||
|
|
259ff891be | ||
|
|
6607a80dab | ||
|
|
b8bd773fe4 | ||
|
|
2addbb9cc9 | ||
|
|
e3cfea2e1b | ||
|
|
f99260d2aa | ||
|
|
3f65e21e32 | ||
|
|
b00e76ff72 | ||
|
|
f4359a70f9 | ||
|
|
3afe659b6b | ||
|
|
16e91176cf | ||
|
|
ab8b0fe338 | ||
|
|
d467a2a7f2 | ||
|
|
76a373eff4 | ||
|
|
25ee659db0 | ||
|
|
eacff17c8d |
@@ -0,0 +1,80 @@
|
|||||||
|
group: Intel
|
||||||
|
steps:
|
||||||
|
- label: ":docker: Build XPU image"
|
||||||
|
soft_fail: true
|
||||||
|
optional: true
|
||||||
|
depends_on: []
|
||||||
|
key: image-build-xpu
|
||||||
|
commands:
|
||||||
|
- bash -lc '.buildkite/image_build/image_build_xpu.sh "public.ecr.aws/q9t5s3a7" "vllm-ci-test-repo" "$BUILDKITE_COMMIT"'
|
||||||
|
env:
|
||||||
|
DOCKER_BUILDKIT: "1"
|
||||||
|
retry:
|
||||||
|
automatic:
|
||||||
|
- exit_status: -1 # Agent was lost
|
||||||
|
limit: 2
|
||||||
|
- exit_status: -10 # Agent was lost
|
||||||
|
limit: 2
|
||||||
|
- label: "XPU example Test"
|
||||||
|
depends_on:
|
||||||
|
- image-build-xpu
|
||||||
|
timeout_in_minutes: 30
|
||||||
|
optional: true
|
||||||
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 2+
|
||||||
|
mem: 24+
|
||||||
|
no_plugin: true
|
||||||
|
env:
|
||||||
|
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
||||||
|
REPO: "vllm-ci-test-repo"
|
||||||
|
source_file_dependencies:
|
||||||
|
- .buildkite/hardware_tests/intel_xpu_ci/test-intel.yaml
|
||||||
|
- .buildkite/scripts/hardware_ci/run-intel-ci-test.sh
|
||||||
|
commands:
|
||||||
|
- >-
|
||||||
|
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
|
||||||
|
'bash .buildkite/scripts/hardware_ci/run-intel-ci-test.sh example'
|
||||||
|
- label: "XPU V1 test"
|
||||||
|
depends_on:
|
||||||
|
- image-build-xpu
|
||||||
|
timeout_in_minutes: 30
|
||||||
|
optional: true
|
||||||
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
|
no_plugin: true
|
||||||
|
env:
|
||||||
|
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
||||||
|
REPO: "vllm-ci-test-repo"
|
||||||
|
source_file_dependencies:
|
||||||
|
- .buildkite/hardware_tests/intel_xpu_ci/test-intel.yaml
|
||||||
|
- .buildkite/scripts/hardware_ci/run-intel-ci-test.sh
|
||||||
|
commands:
|
||||||
|
- >-
|
||||||
|
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
|
||||||
|
'bash .buildkite/scripts/hardware_ci/run-intel-ci-test.sh v1'
|
||||||
|
- label: "XPU server test"
|
||||||
|
depends_on:
|
||||||
|
- image-build-xpu
|
||||||
|
timeout_in_minutes: 30
|
||||||
|
optional: true
|
||||||
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
|
no_plugin: true
|
||||||
|
env:
|
||||||
|
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
||||||
|
REPO: "vllm-ci-test-repo"
|
||||||
|
source_file_dependencies:
|
||||||
|
- .buildkite/hardware_tests/intel_xpu_ci/test-intel.yaml
|
||||||
|
- .buildkite/scripts/hardware_ci/run-intel-ci-test.sh
|
||||||
|
commands:
|
||||||
|
- >-
|
||||||
|
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
|
||||||
|
'bash .buildkite/scripts/hardware_ci/run-intel-ci-test.sh server'
|
||||||
@@ -5,6 +5,10 @@ steps:
|
|||||||
- label: XPU Sleep Mode
|
- label: XPU Sleep Mode
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ steps:
|
|||||||
- label: Engine (1 GPU)
|
- label: Engine (1 GPU)
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ steps:
|
|||||||
key: eplb-algorithm
|
key: eplb-algorithm
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ steps:
|
|||||||
- label: vLLM IR Tests
|
- label: vLLM IR Tests
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ steps:
|
|||||||
- label: LoRA Runtime + Utils
|
- label: LoRA Runtime + Utils
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 24+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -34,6 +38,10 @@ steps:
|
|||||||
- label: LoRA Fused/MoE Kernels
|
- label: LoRA Fused/MoE Kernels
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -54,6 +62,10 @@ steps:
|
|||||||
- label: LoRA Punica Kernels
|
- label: LoRA Punica Kernels
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -74,6 +86,10 @@ steps:
|
|||||||
- label: LoRA Punica FP8/XPU Ops
|
- label: LoRA Punica FP8/XPU Ops
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -94,6 +110,10 @@ steps:
|
|||||||
- label: LoRA Models
|
- label: LoRA Models
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 2+
|
||||||
|
mem: 24+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -117,6 +137,10 @@ steps:
|
|||||||
- label: LoRA Multimodal
|
- label: LoRA Multimodal
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ steps:
|
|||||||
- label: V1 Core + KV + Metrics
|
- label: V1 Core + KV + Metrics
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -31,6 +35,10 @@ steps:
|
|||||||
- label: V1 Sample + Logits
|
- label: V1 Sample + Logits
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -57,17 +65,24 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- >-
|
- >-
|
||||||
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
|
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
|
||||||
'export VLLM_WORKER_MULTIPROC_METHOD=spawn &&
|
'pip install lm_eval[api]>=0.4.12 &&
|
||||||
|
export VLLM_WORKER_MULTIPROC_METHOD=spawn &&
|
||||||
cd tests &&
|
cd tests &&
|
||||||
pytest -v -s v1/logits_processors --ignore=v1/logits_processors/test_custom_online.py --ignore=v1/logits_processors/test_custom_offline.py &&
|
pytest -v -s v1/logits_processors --ignore=v1/logits_processors/test_custom_online.py --ignore=v1/logits_processors/test_custom_offline.py &&
|
||||||
pytest -v -s v1/test_oracle.py &&
|
pytest -v -s v1/test_oracle.py &&
|
||||||
pytest -v -s v1/test_request.py &&
|
pytest -v -s v1/test_request.py &&
|
||||||
pytest -v -s v1/test_outputs.py &&
|
pytest -v -s v1/test_outputs.py &&
|
||||||
pytest -v -s v1/sample/test_topk_topp_sampler.py'
|
pytest -v -s v1/sample/test_topk_topp_sampler.py &&
|
||||||
|
pytest -v -s v1/sample/test_logprobs.py &&
|
||||||
|
pytest -v -s v1/sample/test_logprobs_e2e.py'
|
||||||
|
|
||||||
- label: XPU CPU Offload
|
- label: XPU CPU Offload
|
||||||
timeout_in_minutes: 60
|
timeout_in_minutes: 60
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -92,6 +107,10 @@ steps:
|
|||||||
key: regression
|
key: regression
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -123,6 +142,10 @@ steps:
|
|||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
num_devices: 2
|
num_devices: 2
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 2+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -154,6 +177,10 @@ steps:
|
|||||||
key: async-engine-inputs-utils-worker
|
key: async-engine-inputs-utils-worker
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 24+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
group: Model Runner V2 Intel
|
||||||
|
depends_on:
|
||||||
|
- image-build-xpu
|
||||||
|
steps:
|
||||||
|
- label: Model Runner V2 Core Tests (Intel)
|
||||||
|
timeout_in_minutes: 45
|
||||||
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 2+
|
||||||
|
mem: 16+
|
||||||
|
no_plugin: true
|
||||||
|
working_dir: "."
|
||||||
|
env:
|
||||||
|
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
||||||
|
REPO: "vllm-ci-test-repo"
|
||||||
|
VLLM_TEST_DEVICE: "xpu"
|
||||||
|
source_file_dependencies:
|
||||||
|
- vllm/v1/worker/gpu/
|
||||||
|
- vllm/v1/worker/gpu_worker.py
|
||||||
|
- vllm/v1/core/sched/
|
||||||
|
- vllm/v1/attention/
|
||||||
|
- tests/v1/engine/test_llm_engine.py
|
||||||
|
- tests/v1/e2e/
|
||||||
|
commands:
|
||||||
|
- >-
|
||||||
|
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
|
||||||
|
'export VLLM_USE_V2_MODEL_RUNNER=1 &&
|
||||||
|
cd tests &&
|
||||||
|
pytest -v -s v1/engine/test_llm_engine.py -k "not test_engine_metrics" &&
|
||||||
|
ENFORCE_EAGER=1 pytest -v -s v1/e2e/general/test_async_scheduling.py -k "not ngram" &&
|
||||||
|
pytest -v -s v1/e2e/general/test_min_tokens.py'
|
||||||
|
|
||||||
|
- label: Model Runner V2 Examples (Intel)
|
||||||
|
timeout_in_minutes: 45
|
||||||
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 24+
|
||||||
|
no_plugin: true
|
||||||
|
working_dir: "."
|
||||||
|
env:
|
||||||
|
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
||||||
|
REPO: "vllm-ci-test-repo"
|
||||||
|
VLLM_TEST_DEVICE: "xpu"
|
||||||
|
source_file_dependencies:
|
||||||
|
- vllm/v1/worker/gpu/
|
||||||
|
- vllm/v1/core/sched/
|
||||||
|
- vllm/v1/worker/gpu_worker.py
|
||||||
|
- examples/basic/offline_inference/
|
||||||
|
- examples/generate/multimodal/
|
||||||
|
- examples/features/
|
||||||
|
commands:
|
||||||
|
- >-
|
||||||
|
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
|
||||||
|
'export VLLM_USE_V2_MODEL_RUNNER=1 &&
|
||||||
|
cd examples &&
|
||||||
|
python3 basic/offline_inference/chat.py &&
|
||||||
|
python3 basic/offline_inference/generate.py --model facebook/opt-125m &&
|
||||||
|
python3 generate/multimodal/vision_language_offline.py --seed 0 &&
|
||||||
|
python3 features/automatic_prefix_caching/prefix_caching_offline.py'
|
||||||
@@ -6,6 +6,10 @@ steps:
|
|||||||
key: multi-modal-models-standard-1-qwen2
|
key: multi-modal-models-standard-1-qwen2
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -27,6 +31,10 @@ steps:
|
|||||||
key: multi-modal-models-standard-2-qwen3-gemma
|
key: multi-modal-models-standard-2-qwen3-gemma
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -47,6 +55,10 @@ steps:
|
|||||||
key: multi-modal-models-standard-3-llava-qwen2-vl
|
key: multi-modal-models-standard-3-llava-qwen2-vl
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 24+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -68,6 +80,10 @@ steps:
|
|||||||
key: multi-modal-models-standard-4-other-whisper
|
key: multi-modal-models-standard-4-other-whisper
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
@@ -88,6 +104,10 @@ steps:
|
|||||||
key: multi-modal-processor
|
key: multi-modal-processor
|
||||||
timeout_in_minutes: 45
|
timeout_in_minutes: 45
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
working_dir: "."
|
working_dir: "."
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ steps:
|
|||||||
- image-build-xpu
|
- image-build-xpu
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 2+
|
||||||
|
mem: 24+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
env:
|
env:
|
||||||
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
||||||
@@ -49,6 +53,10 @@ steps:
|
|||||||
- image-build-xpu
|
- image-build-xpu
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
env:
|
env:
|
||||||
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
||||||
@@ -60,19 +68,24 @@ steps:
|
|||||||
- >-
|
- >-
|
||||||
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
|
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
|
||||||
'cd tests &&
|
'cd tests &&
|
||||||
|
bash v1/kv_connector/nixl_integration/run_xpu_disagg_accuracy_test.sh &&
|
||||||
pytest -v -s v1/core --ignore=v1/core/test_reset_prefix_cache_e2e.py --ignore=v1/core/test_scheduler_e2e.py &&
|
pytest -v -s v1/core --ignore=v1/core/test_reset_prefix_cache_e2e.py --ignore=v1/core/test_scheduler_e2e.py &&
|
||||||
pytest -v -s v1/engine --ignore=v1/engine/test_output_processor.py &&
|
pytest -v -s v1/engine --ignore=v1/engine/test_output_processor.py &&
|
||||||
pytest -v -s v1/sample --ignore=v1/sample/test_logprobs.py --ignore=v1/sample/test_logprobs_e2e.py -k "not test_topk_only and not test_topp_only and not test_topk_and_topp" &&
|
pytest -v -s v1/sample --ignore=v1/sample/test_logprobs.py --ignore=v1/sample/test_logprobs_e2e.py -k "not test_topk_only and not test_topp_only and not test_topk_and_topp" &&
|
||||||
pytest -v -s v1/worker --ignore=v1/worker/test_gpu_model_runner.py --ignore=v1/worker/test_worker_memory_snapshot.py &&
|
pytest -v -s v1/worker --ignore=v1/worker/test_gpu_model_runner.py --ignore=v1/worker/test_worker_memory_snapshot.py &&
|
||||||
pytest -v -s v1/structured_output &&
|
pytest -v -s v1/structured_output &&
|
||||||
pytest -v -s v1/test_serial_utils.py &&
|
pytest -v -s v1/test_serial_utils.py &&
|
||||||
pytest -v -s v1/spec_decode --ignore=v1/spec_decode/test_max_len.py --ignore=v1/spec_decode/test_speculators_eagle3.py --ignore=v1/spec_decode/test_acceptance_length.py &&
|
pytest -v -s v1/spec_decode --ignore=v1/spec_decode/test_max_len.py --ignore=v1/spec_decode/test_speculators_eagle3.py --ignore=v1/spec_decode/test_acceptance_length.py --ignore=v1/spec_decode/test_speculators_correctness.py &&
|
||||||
pytest -v -s v1/kv_connector/unit --ignore=v1/kv_connector/unit/test_multi_connector.py --ignore=v1/kv_connector/unit/test_example_connector.py --ignore=v1/kv_connector/unit/test_lmcache_integration.py --ignore=v1/kv_connector/unit/test_hf3fs_client.py --ignore=v1/kv_connector/unit/test_hf3fs_connector.py --ignore=v1/kv_connector/unit/test_hf3fs_metadata_server.py --ignore=v1/kv_connector/unit/test_offloading_connector.py'
|
pytest -v -s v1/kv_connector/unit --ignore=v1/kv_connector/unit/test_multi_connector.py --ignore=v1/kv_connector/unit/test_example_connector.py --ignore=v1/kv_connector/unit/test_lmcache_integration.py --ignore=v1/kv_connector/unit/test_hf3fs_client.py --ignore=v1/kv_connector/unit/test_hf3fs_connector.py --ignore=v1/kv_connector/unit/test_hf3fs_metadata_server.py --ignore=v1/kv_connector/unit/test_offloading_connector.py'
|
||||||
- label: "XPU server test"
|
- label: "XPU server test"
|
||||||
depends_on:
|
depends_on:
|
||||||
- image-build-xpu
|
- image-build-xpu
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
device: intel_gpu
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
no_plugin: true
|
no_plugin: true
|
||||||
env:
|
env:
|
||||||
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
||||||
@@ -87,3 +100,24 @@ steps:
|
|||||||
cd tests &&
|
cd tests &&
|
||||||
pytest -v -s entrypoints/multimodal/openai/chat_completion/test_audio_in_video.py &&
|
pytest -v -s entrypoints/multimodal/openai/chat_completion/test_audio_in_video.py &&
|
||||||
pytest -v -s benchmarks/test_serve_cli.py'
|
pytest -v -s benchmarks/test_serve_cli.py'
|
||||||
|
- label: "XPU quantization test"
|
||||||
|
depends_on:
|
||||||
|
- image-build-xpu
|
||||||
|
timeout_in_minutes: 30
|
||||||
|
device: intel_gpu
|
||||||
|
agent_tags:
|
||||||
|
label: production
|
||||||
|
gpu: 1+
|
||||||
|
mem: 16+
|
||||||
|
no_plugin: true
|
||||||
|
env:
|
||||||
|
REGISTRY: "public.ecr.aws/q9t5s3a7"
|
||||||
|
REPO: "vllm-ci-test-repo"
|
||||||
|
source_file_dependencies:
|
||||||
|
- vllm/
|
||||||
|
- .buildkite/intel_jobs/test-intel.yaml
|
||||||
|
commands:
|
||||||
|
- >-
|
||||||
|
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
|
||||||
|
'cd tests &&
|
||||||
|
pytest -v -s quantization/test_auto_round.py'
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
test_suite="${1:-}"
|
||||||
|
|
||||||
|
if [[ -z "${test_suite}" ]]; then
|
||||||
|
echo "Usage: $0 <example|v1|server>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${test_suite}" in
|
||||||
|
example)
|
||||||
|
pip install tblib==3.1.0
|
||||||
|
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model facebook/opt-125m --block-size 64 --enforce-eager
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model facebook/opt-125m --block-size 64 -O3 -cc.cudagraph_mode=NONE
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model facebook/opt-125m --block-size 64 --enforce-eager -tp 2 --distributed-executor-backend mp
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model facebook/opt-125m --block-size 64 --enforce-eager --attention-backend=TRITON_ATTN
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model facebook/opt-125m --block-size 64 --enforce-eager --quantization fp8
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model facebook/opt-125m --block-size 64 --enforce-eager --kv-cache-dtype fp8
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model nvidia/Llama-3.1-8B-Instruct-FP8 --block-size 64 --enforce-eager --quantization modelopt --kv-cache-dtype fp8 --attention-backend TRITON_ATTN --max-model-len 4096
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model superjob/Qwen3-4B-Instruct-2507-GPTQ-Int4 --block-size 64 --enforce-eager --max-model-len 8192
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model ibm-research/PowerMoE-3b --block-size 64 --enforce-eager -tp 2
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model ibm-research/PowerMoE-3b --block-size 64 --enforce-eager -tp 2 --enable-expert-parallel
|
||||||
|
python3 examples/basic/offline_inference/generate.py --model superjob/Qwen3-4B-Instruct-2507-GPTQ-Int4 --max-model-len 8192
|
||||||
|
;;
|
||||||
|
v1)
|
||||||
|
cd tests
|
||||||
|
|
||||||
|
pytest -v -s v1/core --ignore=v1/core/test_reset_prefix_cache_e2e.py --ignore=v1/core/test_scheduler_e2e.py
|
||||||
|
pytest -v -s v1/engine --ignore=v1/engine/test_output_processor.py
|
||||||
|
pytest -v -s v1/sample --ignore=v1/sample/test_logprobs.py --ignore=v1/sample/test_logprobs_e2e.py -k "not test_topk_only and not test_topp_only and not test_topk_and_topp"
|
||||||
|
pytest -v -s v1/worker --ignore=v1/worker/test_gpu_model_runner.py --ignore=v1/worker/test_worker_memory_snapshot.py
|
||||||
|
pytest -v -s v1/structured_output
|
||||||
|
pytest -v -s v1/test_serial_utils.py
|
||||||
|
pytest -v -s v1/spec_decode --ignore=v1/spec_decode/test_max_len.py --ignore=v1/spec_decode/test_speculators_eagle3.py --ignore=v1/spec_decode/test_acceptance_length.py --ignore=v1/spec_decode/test_speculators_correctness.py
|
||||||
|
pytest -v -s v1/kv_connector/unit --ignore=v1/kv_connector/unit/test_multi_connector.py --ignore=v1/kv_connector/unit/test_example_connector.py --ignore=v1/kv_connector/unit/test_lmcache_integration.py --ignore=v1/kv_connector/unit/test_hf3fs_client.py --ignore=v1/kv_connector/unit/test_hf3fs_connector.py --ignore=v1/kv_connector/unit/test_hf3fs_metadata_server.py --ignore=v1/kv_connector/unit/test_offloading_connector.py
|
||||||
|
;;
|
||||||
|
server)
|
||||||
|
pip install av
|
||||||
|
cd tests
|
||||||
|
|
||||||
|
pytest -v -s entrypoints/multimodal/openai/chat_completion/test_audio_in_video.py
|
||||||
|
pytest -v -s benchmarks/test_serve_cli.py
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown Intel test suite: ${test_suite}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -243,8 +243,10 @@ container_name="xpu_${BUILDKITE_COMMIT}_$(tr -dc A-Za-z0-9 < /dev/urandom | head
|
|||||||
|
|
||||||
# ---- Command source selection ----
|
# ---- Command source selection ----
|
||||||
commands=""
|
commands=""
|
||||||
|
commands_source=""
|
||||||
if [[ -n "${VLLM_TEST_COMMANDS:-}" ]]; then
|
if [[ -n "${VLLM_TEST_COMMANDS:-}" ]]; then
|
||||||
commands="${VLLM_TEST_COMMANDS}"
|
commands="${VLLM_TEST_COMMANDS}"
|
||||||
|
commands_source="env"
|
||||||
echo "Commands sourced from VLLM_TEST_COMMANDS (quoting preserved)"
|
echo "Commands sourced from VLLM_TEST_COMMANDS (quoting preserved)"
|
||||||
elif [[ $# -gt 0 ]]; then
|
elif [[ $# -gt 0 ]]; then
|
||||||
all_yaml=true
|
all_yaml=true
|
||||||
@@ -303,8 +305,12 @@ if [[ -z "$commands" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Raw commands: $commands"
|
echo "Raw commands: $commands"
|
||||||
commands=$(re_quote_pytest_markers "$commands")
|
if [[ "$commands_source" != "env" ]]; then
|
||||||
echo "After re-quoting: $commands"
|
commands=$(re_quote_pytest_markers "$commands")
|
||||||
|
echo "After re-quoting: $commands"
|
||||||
|
else
|
||||||
|
echo "Skipping re-quoting for VLLM_TEST_COMMANDS input"
|
||||||
|
fi
|
||||||
commands=$(apply_intel_test_overrides "$commands")
|
commands=$(apply_intel_test_overrides "$commands")
|
||||||
echo "Final commands: $commands"
|
echo "Final commands: $commands"
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,11 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
if python3 -c "import torch; raise SystemExit(0 if torch.version.hip is not None else 1)"; then
|
||||||
|
uv pip install --system -r /vllm-workspace/requirements/kv_connectors_rocm.txt
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
REQUIREMENTS_FILE="${KV_CONNECTORS_REQUIREMENTS:-/vllm-workspace/requirements/kv_connectors.txt}"
|
REQUIREMENTS_FILE="${KV_CONNECTORS_REQUIREMENTS:-/vllm-workspace/requirements/kv_connectors.txt}"
|
||||||
|
|
||||||
uv pip install --system -r "${REQUIREMENTS_FILE}"
|
uv pip install --system -r "${REQUIREMENTS_FILE}"
|
||||||
|
|||||||
+37
-47
@@ -415,22 +415,6 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- pytest -v -s kernels/mamba
|
- pytest -v -s kernels/mamba
|
||||||
|
|
||||||
#----------------------------------------------------------- mi250 · lora ------------------------------------------------------------#
|
|
||||||
|
|
||||||
- label: LoRA %N # TBD
|
|
||||||
timeout_in_minutes: 180
|
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx90anightly, amdmi250]
|
|
||||||
agent_pool: mi250_1
|
|
||||||
parallelism: 4
|
|
||||||
optional: true
|
|
||||||
working_dir: "/vllm-workspace/tests"
|
|
||||||
source_file_dependencies:
|
|
||||||
- vllm/lora
|
|
||||||
- tests/lora
|
|
||||||
- vllm/platforms/rocm.py
|
|
||||||
commands:
|
|
||||||
- pytest -v -s lora --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --ignore=lora/test_chatglm3_tp.py --ignore=lora/test_llama_tp.py --ignore=lora/test_qwen3_with_multi_loras.py --ignore=lora/test_olmoe_tp.py --ignore=lora/test_deepseekv2_tp.py --ignore=lora/test_gptoss_tp.py --ignore=lora/test_qwen3moe_tp.py --ignore=lora/test_qwen35_densemodel_lora.py
|
|
||||||
|
|
||||||
#------------------------------------------------------ mi250 · models / basic -------------------------------------------------------#
|
#------------------------------------------------------ mi250 · models / basic -------------------------------------------------------#
|
||||||
|
|
||||||
- label: Basic Models Test (Other CPU) # TBD
|
- label: Basic Models Test (Other CPU) # TBD
|
||||||
@@ -608,6 +592,11 @@ steps:
|
|||||||
- pytest -v -s plugins_tests/test_bge_m3_sparse_io_processor_plugins.py
|
- pytest -v -s plugins_tests/test_bge_m3_sparse_io_processor_plugins.py
|
||||||
- pip uninstall bge_m3_sparse_plugin -y
|
- pip uninstall bge_m3_sparse_plugin -y
|
||||||
# END: `bge_m3_sparse io_processor` test
|
# END: `bge_m3_sparse io_processor` test
|
||||||
|
# BEGIN: `colbert_query io_processor` test
|
||||||
|
- pip install -e ./plugins/colbert_query_plugin
|
||||||
|
- pytest -v -s plugins_tests/test_colbert_query_io_processor_plugins.py
|
||||||
|
- pip uninstall colbert_query_plugin -y
|
||||||
|
# END: `colbert_query io_processor` test
|
||||||
# BEGIN: `stat_logger` plugins test
|
# BEGIN: `stat_logger` plugins test
|
||||||
- pip install -e ./plugins/vllm_add_dummy_stat_logger
|
- pip install -e ./plugins/vllm_add_dummy_stat_logger
|
||||||
- pytest -v -s plugins_tests/test_stats_logger_plugins.py
|
- pytest -v -s plugins_tests/test_stats_logger_plugins.py
|
||||||
@@ -658,7 +647,7 @@ steps:
|
|||||||
- pytest -v -s v1/cudagraph/test_cudagraph_mode.py
|
- pytest -v -s v1/cudagraph/test_cudagraph_mode.py
|
||||||
|
|
||||||
- label: e2e Core (1 GPU) # TBD
|
- label: e2e Core (1 GPU) # TBD
|
||||||
timeout_in_minutes: 180
|
timeout_in_minutes: 35
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx90anightly, amdmi250]
|
mirror_hardwares: [amdexperimental, amdproduction, amdgfx90anightly, amdmi250]
|
||||||
agent_pool: mi250_1
|
agent_pool: mi250_1
|
||||||
optional: true
|
optional: true
|
||||||
@@ -1605,9 +1594,10 @@ steps:
|
|||||||
#---------------------------------------------------------- mi300 · kernels ----------------------------------------------------------#
|
#---------------------------------------------------------- mi300 · kernels ----------------------------------------------------------#
|
||||||
|
|
||||||
- label: Kernels Attention Test %N # TBD
|
- label: Kernels Attention Test %N # TBD
|
||||||
timeout_in_minutes: 180
|
timeout_in_minutes: 55
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
||||||
agent_pool: mi300_1
|
agent_pool: mi300_1
|
||||||
|
optional: true
|
||||||
parallelism: 2
|
parallelism: 2
|
||||||
working_dir: "/vllm-workspace/tests"
|
working_dir: "/vllm-workspace/tests"
|
||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
@@ -1638,10 +1628,11 @@ steps:
|
|||||||
- pytest -v -s kernels/core --ignore=kernels/core/test_minimax_reduce_rms.py kernels/test_concat_mla_q.py kernels/test_top_k_per_row.py
|
- pytest -v -s kernels/core --ignore=kernels/core/test_minimax_reduce_rms.py kernels/test_concat_mla_q.py kernels/test_top_k_per_row.py
|
||||||
|
|
||||||
- label: Kernels MoE Test %N # TBD
|
- label: Kernels MoE Test %N # TBD
|
||||||
timeout_in_minutes: 180
|
timeout_in_minutes: 50
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
||||||
agent_pool: mi300_1
|
agent_pool: mi300_1
|
||||||
parallelism: 4
|
optional: true
|
||||||
|
parallelism: 5
|
||||||
working_dir: "/vllm-workspace/tests"
|
working_dir: "/vllm-workspace/tests"
|
||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
- csrc/quantization/cutlass_w8a8/moe/
|
- csrc/quantization/cutlass_w8a8/moe/
|
||||||
@@ -1694,6 +1685,20 @@ steps:
|
|||||||
|
|
||||||
#----------------------------------------------------------- mi300 · lora ------------------------------------------------------------#
|
#----------------------------------------------------------- mi300 · lora ------------------------------------------------------------#
|
||||||
|
|
||||||
|
- label: LoRA %N # TBD
|
||||||
|
timeout_in_minutes: 180
|
||||||
|
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
||||||
|
agent_pool: mi300_1
|
||||||
|
parallelism: 4
|
||||||
|
optional: true
|
||||||
|
working_dir: "/vllm-workspace/tests"
|
||||||
|
source_file_dependencies:
|
||||||
|
- vllm/lora
|
||||||
|
- tests/lora
|
||||||
|
- vllm/platforms/rocm.py
|
||||||
|
commands:
|
||||||
|
- pytest -v -s lora --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --ignore=lora/test_chatglm3_tp.py --ignore=lora/test_llama_tp.py --ignore=lora/test_qwen3_with_multi_loras.py --ignore=lora/test_olmoe_tp.py --ignore=lora/test_deepseekv2_tp.py --ignore=lora/test_gptoss_tp.py --ignore=lora/test_qwen3moe_tp.py --ignore=lora/test_qwen35_densemodel_lora.py
|
||||||
|
|
||||||
- label: LoRA TP (Distributed) # TBD
|
- label: LoRA TP (Distributed) # TBD
|
||||||
timeout_in_minutes: 180
|
timeout_in_minutes: 180
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
||||||
@@ -1778,10 +1783,9 @@ steps:
|
|||||||
- tests/models/multimodal/generation
|
- tests/models/multimodal/generation
|
||||||
- tests/models/multimodal/test_mapping.py
|
- tests/models/multimodal/test_mapping.py
|
||||||
commands:
|
commands:
|
||||||
- uv pip install --system --no-build-isolation 'git+https://github.com/AndreasKaratzas/mamba@rocm-7.0-v2.3.0'
|
- pip install git+https://github.com/TIGER-AI-Lab/Mantis.git
|
||||||
- uv pip install --system --no-build-isolation 'git+https://github.com/Dao-AILab/causal-conv1d@v1.6.0'
|
- pytest -v -s models/multimodal/generation -m 'not core_model' --ignore models/multimodal/generation/test_common.py
|
||||||
- pytest -v -s models/language/generation -m hybrid_model --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB
|
- pytest -v -s models/multimodal/test_mapping.py
|
||||||
|
|
||||||
|
|
||||||
- label: Multi-Modal Models (Extended Generation 2) # TBD
|
- label: Multi-Modal Models (Extended Generation 2) # TBD
|
||||||
timeout_in_minutes: 180
|
timeout_in_minutes: 180
|
||||||
@@ -1793,9 +1797,8 @@ steps:
|
|||||||
- vllm/
|
- vllm/
|
||||||
- tests/models/multimodal/generation
|
- tests/models/multimodal/generation
|
||||||
commands:
|
commands:
|
||||||
- uv pip install --system --no-build-isolation 'git+https://github.com/AndreasKaratzas/mamba@rocm-7.0-v2.3.0'
|
- pip install git+https://github.com/TIGER-AI-Lab/Mantis.git
|
||||||
- uv pip install --system --no-build-isolation 'git+https://github.com/Dao-AILab/causal-conv1d@v1.6.0'
|
- pytest -v -s models/multimodal/generation/test_common.py -m 'split(group=0) and not core_model'
|
||||||
- pytest -v -s models/language/generation -m '(not core_model) and (not hybrid_model)'
|
|
||||||
|
|
||||||
|
|
||||||
- label: Multi-Modal Models (Extended Generation 3) # TBD
|
- label: Multi-Modal Models (Extended Generation 3) # TBD
|
||||||
@@ -2074,19 +2077,6 @@ steps:
|
|||||||
- export VLLM_ALLOW_INSECURE_SERIALIZATION=1
|
- export VLLM_ALLOW_INSECURE_SERIALIZATION=1
|
||||||
- pytest -v -s v1/spec_decode/test_acceptance_length.py -m slow_test
|
- pytest -v -s v1/spec_decode/test_acceptance_length.py -m slow_test
|
||||||
|
|
||||||
- label: e2e Core (1 GPU) # TBD
|
|
||||||
timeout_in_minutes: 180
|
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
|
||||||
agent_pool: mi300_1
|
|
||||||
optional: true
|
|
||||||
working_dir: "/vllm-workspace/tests"
|
|
||||||
source_file_dependencies:
|
|
||||||
- vllm/v1/
|
|
||||||
- tests/v1/e2e/
|
|
||||||
- vllm/platforms/rocm.py
|
|
||||||
commands:
|
|
||||||
- pytest -v -s v1/e2e/general --ignore v1/e2e/general/test_async_scheduling.py
|
|
||||||
|
|
||||||
- label: e2e Scheduling (1 GPU) # TBD
|
- label: e2e Scheduling (1 GPU) # TBD
|
||||||
timeout_in_minutes: 180
|
timeout_in_minutes: 180
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
||||||
@@ -2132,9 +2122,10 @@ steps:
|
|||||||
- pytest -v -s v1/e2e/spec_decode -k "draft_model or no_sync or batch_inference"
|
- pytest -v -s v1/e2e/spec_decode -k "draft_model or no_sync or batch_inference"
|
||||||
|
|
||||||
- label: Spec Decode Eagle # TBD
|
- label: Spec Decode Eagle # TBD
|
||||||
timeout_in_minutes: 180
|
timeout_in_minutes: 45
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
mirror_hardwares: [amdexperimental, amdproduction, amdgfx942nightly, amdmi300]
|
||||||
agent_pool: mi300_1
|
agent_pool: mi300_1
|
||||||
|
optional: true
|
||||||
working_dir: "/vllm-workspace/tests"
|
working_dir: "/vllm-workspace/tests"
|
||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
- vllm/v1/spec_decode/
|
- vllm/v1/spec_decode/
|
||||||
@@ -2754,7 +2745,7 @@ steps:
|
|||||||
- vllm/_aiter_ops.py
|
- vllm/_aiter_ops.py
|
||||||
- vllm/platforms/rocm.py
|
- vllm/platforms/rocm.py
|
||||||
commands:
|
commands:
|
||||||
- python3 benchmarks/attention_benchmarks/benchmark.py --backends ROCM_ATTN ROCM_AITER_FA ROCM_AITER_UNIFIED_ATTN --batch-specs "8q1s1k" --repeats 1 --warmup-iters 1
|
- python3 benchmarks/attention_benchmarks/benchmark.py --backends ROCM_ATTN ROCM_AITER_FA ROCM_AITER_UNIFIED_ATTN --batch-specs "8q1s1k"
|
||||||
|
|
||||||
#-------------------------------------------------------- mi355 · distributed --------------------------------------------------------#
|
#-------------------------------------------------------- mi355 · distributed --------------------------------------------------------#
|
||||||
|
|
||||||
@@ -3052,7 +3043,7 @@ steps:
|
|||||||
#---------------------------------------------------------- mi355 · kernels ----------------------------------------------------------#
|
#---------------------------------------------------------- mi355 · kernels ----------------------------------------------------------#
|
||||||
|
|
||||||
- label: Kernels (B200-MI355) # TBD
|
- label: Kernels (B200-MI355) # TBD
|
||||||
timeout_in_minutes: 180
|
timeout_in_minutes: 15
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx950nightly, amdmi355]
|
mirror_hardwares: [amdexperimental, amdproduction, amdgfx950nightly, amdmi355]
|
||||||
agent_pool: mi355_1
|
agent_pool: mi355_1
|
||||||
working_dir: "/vllm-workspace/"
|
working_dir: "/vllm-workspace/"
|
||||||
@@ -3076,11 +3067,10 @@ steps:
|
|||||||
- pytest -v -s tests/kernels/attention/test_attention_selector.py
|
- pytest -v -s tests/kernels/attention/test_attention_selector.py
|
||||||
|
|
||||||
- label: Kernels Attention Test %N # TBD
|
- label: Kernels Attention Test %N # TBD
|
||||||
timeout_in_minutes: 180
|
timeout_in_minutes: 60
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx950nightly, amdmi355]
|
mirror_hardwares: [amdexperimental, amdproduction, amdgfx950nightly, amdmi355]
|
||||||
agent_pool: mi355_1
|
agent_pool: mi355_1
|
||||||
parallelism: 2
|
parallelism: 2
|
||||||
optional: true
|
|
||||||
working_dir: "/vllm-workspace/tests"
|
working_dir: "/vllm-workspace/tests"
|
||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
- csrc/attention/
|
- csrc/attention/
|
||||||
@@ -3094,10 +3084,10 @@ steps:
|
|||||||
- pytest -v -s kernels/attention --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT
|
- pytest -v -s kernels/attention --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT
|
||||||
|
|
||||||
- label: Kernels MoE Test %N # TBD
|
- label: Kernels MoE Test %N # TBD
|
||||||
timeout_in_minutes: 180
|
timeout_in_minutes: 50
|
||||||
mirror_hardwares: [amdexperimental, amdproduction, amdgfx950nightly, amdmi355]
|
mirror_hardwares: [amdexperimental, amdproduction, amdgfx950nightly, amdmi355]
|
||||||
agent_pool: mi355_1
|
agent_pool: mi355_1
|
||||||
parallelism: 4
|
parallelism: 5
|
||||||
working_dir: "/vllm-workspace/tests"
|
working_dir: "/vllm-workspace/tests"
|
||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
- csrc/quantization/cutlass_w8a8/moe/
|
- csrc/quantization/cutlass_w8a8/moe/
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ steps:
|
|||||||
- tests/basic_correctness/test_cpu_offload
|
- tests/basic_correctness/test_cpu_offload
|
||||||
- tests/basic_correctness/test_mem.py
|
- tests/basic_correctness/test_mem.py
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s basic_correctness/test_mem.py
|
||||||
- pytest -v -s basic_correctness/test_mem.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s basic_correctness/test_basic_correctness.py
|
||||||
- pytest -v -s basic_correctness/test_basic_correctness.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s basic_correctness/test_cpu_offload.py
|
||||||
- pytest -v -s basic_correctness/test_cpu_offload.py
|
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ steps:
|
|||||||
- benchmarks/attention_benchmarks/
|
- benchmarks/attention_benchmarks/
|
||||||
- vllm/v1/attention/
|
- vllm/v1/attention/
|
||||||
commands:
|
commands:
|
||||||
- python3 benchmarks/attention_benchmarks/benchmark.py --backends flash flashinfer --batch-specs "8q1s1k" --repeats 1 --warmup-iters 1
|
- python3 benchmarks/attention_benchmarks/benchmark.py --backends flash flashinfer --batch-specs "8q1s1k"
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ steps:
|
|||||||
- vllm/v1/cudagraph_dispatcher.py
|
- vllm/v1/cudagraph_dispatcher.py
|
||||||
- tests/compile/correctness_e2e/test_sequence_parallel.py
|
- tests/compile/correctness_e2e/test_sequence_parallel.py
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_TEST_CLEAN_GPU_MEMORY=1
|
- VLLM_TEST_CLEAN_GPU_MEMORY=1 pytest -v -s tests/compile/correctness_e2e/test_sequence_parallel.py
|
||||||
- pytest -v -s tests/compile/correctness_e2e/test_sequence_parallel.py
|
|
||||||
|
|
||||||
- label: Sequence Parallel Correctness Tests (2xH100)
|
- label: Sequence Parallel Correctness Tests (2xH100)
|
||||||
key: sequence-parallel-correctness-tests-2xh100
|
key: sequence-parallel-correctness-tests-2xh100
|
||||||
@@ -25,8 +24,7 @@ steps:
|
|||||||
optional: true
|
optional: true
|
||||||
num_devices: 2
|
num_devices: 2
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_TEST_CLEAN_GPU_MEMORY=1
|
- VLLM_TEST_CLEAN_GPU_MEMORY=1 pytest -v -s tests/compile/correctness_e2e/test_sequence_parallel.py
|
||||||
- pytest -v -s tests/compile/correctness_e2e/test_sequence_parallel.py
|
|
||||||
|
|
||||||
- label: AsyncTP Correctness Tests (2xH100)
|
- label: AsyncTP Correctness Tests (2xH100)
|
||||||
key: asynctp-correctness-tests-2xh100
|
key: asynctp-correctness-tests-2xh100
|
||||||
@@ -36,8 +34,7 @@ steps:
|
|||||||
optional: true
|
optional: true
|
||||||
num_devices: 2
|
num_devices: 2
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_TEST_CLEAN_GPU_MEMORY=1
|
- VLLM_TEST_CLEAN_GPU_MEMORY=1 pytest -v -s tests/compile/correctness_e2e/test_async_tp.py
|
||||||
- pytest -v -s tests/compile/correctness_e2e/test_async_tp.py
|
|
||||||
|
|
||||||
- label: AsyncTP Correctness Tests (B200)
|
- label: AsyncTP Correctness Tests (B200)
|
||||||
key: asynctp-correctness-tests-b200
|
key: asynctp-correctness-tests-b200
|
||||||
@@ -47,8 +44,7 @@ steps:
|
|||||||
optional: true
|
optional: true
|
||||||
num_devices: 2
|
num_devices: 2
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_TEST_CLEAN_GPU_MEMORY=1
|
- VLLM_TEST_CLEAN_GPU_MEMORY=1 pytest -v -s tests/compile/correctness_e2e/test_async_tp.py
|
||||||
- pytest -v -s tests/compile/correctness_e2e/test_async_tp.py
|
|
||||||
|
|
||||||
- label: Distributed Compile Unit Tests (2xH100)
|
- label: Distributed Compile Unit Tests (2xH100)
|
||||||
key: distributed-compile-unit-tests-2xh100
|
key: distributed-compile-unit-tests-2xh100
|
||||||
@@ -61,8 +57,7 @@ steps:
|
|||||||
- vllm/model_executor/layers
|
- vllm/model_executor/layers
|
||||||
- tests/compile/passes/distributed/
|
- tests/compile/passes/distributed/
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_TEST_CLEAN_GPU_MEMORY=1
|
- VLLM_TEST_CLEAN_GPU_MEMORY=1 pytest -s -v tests/compile/passes/distributed
|
||||||
- pytest -s -v tests/compile/passes/distributed
|
|
||||||
|
|
||||||
- label: Fusion and Compile Unit Tests (2xB200)
|
- label: Fusion and Compile Unit Tests (2xB200)
|
||||||
key: fusion-and-compile-unit-tests-2xb200
|
key: fusion-and-compile-unit-tests-2xb200
|
||||||
|
|||||||
@@ -32,11 +32,10 @@ steps:
|
|||||||
- tests/entrypoints/openai/test_multi_api_servers.py
|
- tests/entrypoints/openai/test_multi_api_servers.py
|
||||||
commands:
|
commands:
|
||||||
# https://github.com/NVIDIA/nccl/issues/1838
|
# https://github.com/NVIDIA/nccl/issues/1838
|
||||||
- export NCCL_CUMEM_HOST_ENABLE=0
|
- NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_async_llm_dp.py
|
||||||
- TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_async_llm_dp.py
|
- NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_eagle_dp.py
|
||||||
- TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_eagle_dp.py
|
- NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_external_lb_dp.py
|
||||||
- TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_external_lb_dp.py
|
- NCCL_CUMEM_HOST_ENABLE=0 DP_SIZE=2 pytest -v -s entrypoints/openai/test_multi_api_servers.py
|
||||||
- DP_SIZE=2 pytest -v -s entrypoints/openai/test_multi_api_servers.py
|
|
||||||
|
|
||||||
- label: Distributed Compile + RPC Tests (2 GPUs)
|
- label: Distributed Compile + RPC Tests (2 GPUs)
|
||||||
key: distributed-compile-rpc-tests-2-gpus
|
key: distributed-compile-rpc-tests-2-gpus
|
||||||
@@ -56,10 +55,9 @@ steps:
|
|||||||
- tests/entrypoints/llm/test_collective_rpc.py
|
- tests/entrypoints/llm/test_collective_rpc.py
|
||||||
commands:
|
commands:
|
||||||
# https://github.com/NVIDIA/nccl/issues/1838
|
# https://github.com/NVIDIA/nccl/issues/1838
|
||||||
- export NCCL_CUMEM_HOST_ENABLE=0
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s entrypoints/llm/test_collective_rpc.py
|
||||||
- pytest -v -s entrypoints/llm/test_collective_rpc.py
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s ./compile/fullgraph/test_basic_correctness.py
|
||||||
- pytest -v -s ./compile/fullgraph/test_basic_correctness.py
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s ./compile/test_wrapper.py
|
||||||
- pytest -v -s ./compile/test_wrapper.py
|
|
||||||
|
|
||||||
- label: Distributed Torchrun + Shutdown Tests (2 GPUs)
|
- label: Distributed Torchrun + Shutdown Tests (2 GPUs)
|
||||||
key: distributed-torchrun-shutdown-tests-2-gpus
|
key: distributed-torchrun-shutdown-tests-2-gpus
|
||||||
@@ -78,11 +76,10 @@ steps:
|
|||||||
- tests/v1/worker/test_worker_memory_snapshot.py
|
- tests/v1/worker/test_worker_memory_snapshot.py
|
||||||
commands:
|
commands:
|
||||||
# https://github.com/NVIDIA/nccl/issues/1838
|
# https://github.com/NVIDIA/nccl/issues/1838
|
||||||
- export NCCL_CUMEM_HOST_ENABLE=0
|
- NCCL_CUMEM_HOST_ENABLE=0 VLLM_TEST_SAME_HOST=1 torchrun --nproc-per-node=4 distributed/test_same_node.py | grep 'Same node test passed'
|
||||||
- VLLM_TEST_SAME_HOST=1 torchrun --nproc-per-node=4 distributed/test_same_node.py | grep 'Same node test passed'
|
- NCCL_CUMEM_HOST_ENABLE=0 VLLM_TEST_SAME_HOST=1 VLLM_TEST_WITH_DEFAULT_DEVICE_SET=1 torchrun --nproc-per-node=4 distributed/test_same_node.py | grep 'Same node test passed'
|
||||||
- VLLM_TEST_SAME_HOST=1 VLLM_TEST_WITH_DEFAULT_DEVICE_SET=1 torchrun --nproc-per-node=4 distributed/test_same_node.py | grep 'Same node test passed'
|
- NCCL_CUMEM_HOST_ENABLE=0 CUDA_VISIBLE_DEVICES=0,1 pytest -v -s v1/shutdown
|
||||||
- CUDA_VISIBLE_DEVICES=0,1 pytest -v -s v1/shutdown
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s v1/worker/test_worker_memory_snapshot.py
|
||||||
- pytest -v -s v1/worker/test_worker_memory_snapshot.py
|
|
||||||
|
|
||||||
- label: Distributed Torchrun + Examples (4 GPUs)
|
- label: Distributed Torchrun + Examples (4 GPUs)
|
||||||
key: distributed-torchrun-examples-4-gpus
|
key: distributed-torchrun-examples-4-gpus
|
||||||
@@ -97,24 +94,23 @@ steps:
|
|||||||
- tests/examples/features/data_parallel/data_parallel_offline.py
|
- tests/examples/features/data_parallel/data_parallel_offline.py
|
||||||
commands:
|
commands:
|
||||||
# https://github.com/NVIDIA/nccl/issues/1838
|
# https://github.com/NVIDIA/nccl/issues/1838
|
||||||
- export NCCL_CUMEM_HOST_ENABLE=0
|
|
||||||
# test with torchrun tp=2 and external_dp=2
|
# test with torchrun tp=2 and external_dp=2
|
||||||
- torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example.py
|
- NCCL_CUMEM_HOST_ENABLE=0 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example.py
|
||||||
# test with torchrun tp=2 and pp=2
|
# test with torchrun tp=2 and pp=2
|
||||||
- PP_SIZE=2 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example.py
|
- NCCL_CUMEM_HOST_ENABLE=0 PP_SIZE=2 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example.py
|
||||||
# test with torchrun tp=4 and dp=1
|
# test with torchrun tp=4 and dp=1
|
||||||
- TP_SIZE=4 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example_moe.py
|
- NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=4 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example_moe.py
|
||||||
# test with torchrun tp=2, pp=2 and dp=1
|
# test with torchrun tp=2, pp=2 and dp=1
|
||||||
- PP_SIZE=2 TP_SIZE=2 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example_moe.py
|
- NCCL_CUMEM_HOST_ENABLE=0 PP_SIZE=2 TP_SIZE=2 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example_moe.py
|
||||||
# test with torchrun tp=1 and dp=4 with ep
|
# test with torchrun tp=1 and dp=4 with ep
|
||||||
- DP_SIZE=4 ENABLE_EP=1 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example_moe.py
|
- NCCL_CUMEM_HOST_ENABLE=0 DP_SIZE=4 ENABLE_EP=1 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example_moe.py
|
||||||
# test with torchrun tp=2 and dp=2 with ep
|
# test with torchrun tp=2 and dp=2 with ep
|
||||||
- TP_SIZE=2 DP_SIZE=2 ENABLE_EP=1 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example_moe.py
|
- NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=2 DP_SIZE=2 ENABLE_EP=1 torchrun --nproc-per-node=4 tests/distributed/test_torchrun_example_moe.py
|
||||||
# test with internal dp
|
# test with internal dp
|
||||||
- python3 examples/features/data_parallel/data_parallel_offline.py --enforce-eager
|
- NCCL_CUMEM_HOST_ENABLE=0 python3 examples/features/data_parallel/data_parallel_offline.py --enforce-eager
|
||||||
# rlhf examples
|
# rlhf examples
|
||||||
- VLLM_ALLOW_INSECURE_SERIALIZATION=1 python3 examples/rl/rlhf_nccl.py
|
- NCCL_CUMEM_HOST_ENABLE=0 VLLM_ALLOW_INSECURE_SERIALIZATION=1 python3 examples/rl/rlhf_nccl.py
|
||||||
- VLLM_ALLOW_INSECURE_SERIALIZATION=1 python3 examples/rl/rlhf_ipc.py
|
- NCCL_CUMEM_HOST_ENABLE=0 VLLM_ALLOW_INSECURE_SERIALIZATION=1 python3 examples/rl/rlhf_ipc.py
|
||||||
|
|
||||||
- label: Distributed DP Tests (4 GPUs)
|
- label: Distributed DP Tests (4 GPUs)
|
||||||
key: distributed-dp-tests-4-gpus
|
key: distributed-dp-tests-4-gpus
|
||||||
@@ -128,14 +124,13 @@ steps:
|
|||||||
- tests/distributed/test_utils
|
- tests/distributed/test_utils
|
||||||
commands:
|
commands:
|
||||||
# https://github.com/NVIDIA/nccl/issues/1838
|
# https://github.com/NVIDIA/nccl/issues/1838
|
||||||
- export NCCL_CUMEM_HOST_ENABLE=0
|
- NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=2 DP_SIZE=2 pytest -v -s v1/distributed/test_async_llm_dp.py
|
||||||
- TP_SIZE=2 DP_SIZE=2 pytest -v -s v1/distributed/test_async_llm_dp.py
|
- NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=2 DP_SIZE=2 pytest -v -s v1/distributed/test_eagle_dp.py
|
||||||
- TP_SIZE=2 DP_SIZE=2 pytest -v -s v1/distributed/test_eagle_dp.py
|
- NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=2 DP_SIZE=2 pytest -v -s v1/distributed/test_external_lb_dp.py
|
||||||
- TP_SIZE=2 DP_SIZE=2 pytest -v -s v1/distributed/test_external_lb_dp.py
|
- NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=1 DP_SIZE=4 pytest -v -s v1/distributed/test_internal_lb_dp.py
|
||||||
- TP_SIZE=1 DP_SIZE=4 pytest -v -s v1/distributed/test_internal_lb_dp.py
|
- NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=1 DP_SIZE=4 pytest -v -s v1/distributed/test_hybrid_lb_dp.py
|
||||||
- TP_SIZE=1 DP_SIZE=4 pytest -v -s v1/distributed/test_hybrid_lb_dp.py
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s v1/engine/test_engine_core_client.py::test_kv_cache_events_dp
|
||||||
- pytest -v -s v1/engine/test_engine_core_client.py::test_kv_cache_events_dp
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s distributed/test_utils.py
|
||||||
- pytest -v -s distributed/test_utils.py
|
|
||||||
|
|
||||||
- label: Distributed Compile + Comm (4 GPUs)
|
- label: Distributed Compile + Comm (4 GPUs)
|
||||||
key: distributed-compile-comm-4-gpus
|
key: distributed-compile-comm-4-gpus
|
||||||
@@ -151,13 +146,12 @@ steps:
|
|||||||
- tests/distributed/test_multiproc_executor.py
|
- tests/distributed/test_multiproc_executor.py
|
||||||
commands:
|
commands:
|
||||||
# https://github.com/NVIDIA/nccl/issues/1838
|
# https://github.com/NVIDIA/nccl/issues/1838
|
||||||
- export NCCL_CUMEM_HOST_ENABLE=0
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s compile/fullgraph/test_basic_correctness.py
|
||||||
- pytest -v -s compile/fullgraph/test_basic_correctness.py
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s distributed/test_pynccl.py
|
||||||
- pytest -v -s distributed/test_pynccl.py
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s distributed/test_events.py
|
||||||
- pytest -v -s distributed/test_events.py
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s distributed/test_symm_mem_allreduce.py
|
||||||
- pytest -v -s distributed/test_symm_mem_allreduce.py
|
|
||||||
# test multi-node TP with multiproc executor (simulated on single node)
|
# test multi-node TP with multiproc executor (simulated on single node)
|
||||||
- pytest -v -s distributed/test_multiproc_executor.py::test_multiproc_executor_multi_node
|
- NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s distributed/test_multiproc_executor.py::test_multiproc_executor_multi_node
|
||||||
|
|
||||||
- label: Distributed Tests (8 GPUs)(H100)
|
- label: Distributed Tests (8 GPUs)(H100)
|
||||||
key: distributed-tests-8-gpus-h100
|
key: distributed-tests-8-gpus-h100
|
||||||
@@ -176,9 +170,8 @@ steps:
|
|||||||
|
|
||||||
commands:
|
commands:
|
||||||
# https://github.com/NVIDIA/nccl/issues/1838
|
# https://github.com/NVIDIA/nccl/issues/1838
|
||||||
- export NCCL_CUMEM_HOST_ENABLE=0
|
|
||||||
# test with torchrun tp=2 and dp=4 with ep
|
# test with torchrun tp=2 and dp=4 with ep
|
||||||
- torchrun --nproc-per-node=8 ../examples/features/torchrun/torchrun_dp_example_offline.py --tp-size=2 --pp-size=1 --dp-size=4 --enable-ep
|
- NCCL_CUMEM_HOST_ENABLE=0 torchrun --nproc-per-node=8 ../examples/features/torchrun/torchrun_dp_example_offline.py --tp-size=2 --pp-size=1 --dp-size=4 --enable-ep
|
||||||
|
|
||||||
- label: Distributed Tests (4 GPUs)(A100)
|
- label: Distributed Tests (4 GPUs)(A100)
|
||||||
key: distributed-tests-4-gpus-a100
|
key: distributed-tests-4-gpus-a100
|
||||||
@@ -271,9 +264,7 @@ steps:
|
|||||||
- tests/distributed/test_pipeline_parallel.py
|
- tests/distributed/test_pipeline_parallel.py
|
||||||
- tests/basic_correctness/test_basic_correctness.py
|
- tests/basic_correctness/test_basic_correctness.py
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_USE_RAY_V2_EXECUTOR_BACKEND=1
|
- VLLM_USE_RAY_V2_EXECUTOR_BACKEND=1 NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s distributed/test_ray_v2_executor.py
|
||||||
- export NCCL_CUMEM_HOST_ENABLE=0
|
- VLLM_USE_RAY_V2_EXECUTOR_BACKEND=1 NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s distributed/test_ray_v2_executor_e2e.py
|
||||||
- pytest -v -s distributed/test_ray_v2_executor.py
|
- VLLM_USE_RAY_V2_EXECUTOR_BACKEND=1 NCCL_CUMEM_HOST_ENABLE=0 pytest -v -s distributed/test_pipeline_parallel.py -k "ray"
|
||||||
- pytest -v -s distributed/test_ray_v2_executor_e2e.py
|
- VLLM_USE_RAY_V2_EXECUTOR_BACKEND=1 NCCL_CUMEM_HOST_ENABLE=0 TARGET_TEST_SUITE=L4 pytest -v -s basic_correctness/test_basic_correctness.py -k "ray"
|
||||||
- pytest -v -s distributed/test_pipeline_parallel.py -k "ray"
|
|
||||||
- TARGET_TEST_SUITE=L4 pytest -v -s basic_correctness/test_basic_correctness.py -k "ray"
|
|
||||||
|
|||||||
@@ -74,6 +74,16 @@ steps:
|
|||||||
- tests/v1/e2e/general/
|
- tests/v1/e2e/general/
|
||||||
commands:
|
commands:
|
||||||
- pytest -v -s v1/e2e/general --ignore v1/e2e/general/test_async_scheduling.py
|
- pytest -v -s v1/e2e/general --ignore v1/e2e/general/test_async_scheduling.py
|
||||||
|
mirror:
|
||||||
|
amd:
|
||||||
|
device: mi250_1
|
||||||
|
timeout_in_minutes: 35
|
||||||
|
depends_on:
|
||||||
|
- image-build-amd
|
||||||
|
source_file_dependencies:
|
||||||
|
- vllm/v1/
|
||||||
|
- tests/v1/e2e/general/
|
||||||
|
- vllm/platforms/rocm.py
|
||||||
|
|
||||||
- label: V1 e2e (2 GPUs)
|
- label: V1 e2e (2 GPUs)
|
||||||
key: v1-e2e-2-gpus
|
key: v1-e2e-2-gpus
|
||||||
|
|||||||
@@ -22,10 +22,9 @@ steps:
|
|||||||
- vllm/
|
- vllm/
|
||||||
- tests/entrypoints/llm
|
- tests/entrypoints/llm
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/llm --ignore=entrypoints/llm/test_generate.py --ignore=entrypoints/llm/test_collective_rpc.py --ignore=entrypoints/llm/offline_mode
|
||||||
- pytest -v -s entrypoints/llm --ignore=entrypoints/llm/test_generate.py --ignore=entrypoints/llm/test_collective_rpc.py --ignore=entrypoints/llm/offline_mode
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/llm/test_generate.py # it needs a clean process
|
||||||
- pytest -v -s entrypoints/llm/test_generate.py # it needs a clean process
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/llm/offline_mode # Needs to avoid interference with other tests
|
||||||
- pytest -v -s entrypoints/llm/offline_mode # Needs to avoid interference with other tests
|
|
||||||
mirror:
|
mirror:
|
||||||
amd:
|
amd:
|
||||||
device: mi325_1
|
device: mi325_1
|
||||||
@@ -41,9 +40,8 @@ steps:
|
|||||||
- vllm/
|
- vllm/
|
||||||
- tests/entrypoints/serve
|
- tests/entrypoints/serve
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/serve --ignore=entrypoints/serve/dev/rpc
|
||||||
- pytest -v -s entrypoints/serve --ignore=entrypoints/serve/dev/rpc
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn PYTHONPATH=/vllm-workspace pytest -v -s entrypoints/serve/dev/rpc
|
||||||
- PYTHONPATH=/vllm-workspace pytest -v -s entrypoints/serve/dev/rpc
|
|
||||||
mirror:
|
mirror:
|
||||||
amd:
|
amd:
|
||||||
device: mi325_1
|
device: mi325_1
|
||||||
@@ -59,8 +57,7 @@ steps:
|
|||||||
- tests/entrypoints/openai
|
- tests/entrypoints/openai
|
||||||
- tests/entrypoints/test_chat_utils
|
- tests/entrypoints/test_chat_utils
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/openai --ignore=entrypoints/openai/completion --ignore=entrypoints/openai/chat_completion --ignore=entrypoints/openai/responses --ignore=entrypoints/openai/correctness
|
||||||
- pytest -v -s entrypoints/openai --ignore=entrypoints/openai/completion --ignore=entrypoints/openai/chat_completion --ignore=entrypoints/openai/responses --ignore=entrypoints/openai/correctness
|
|
||||||
mirror:
|
mirror:
|
||||||
amd:
|
amd:
|
||||||
device: mi325_1
|
device: mi325_1
|
||||||
@@ -77,9 +74,8 @@ steps:
|
|||||||
- tests/entrypoints/openai
|
- tests/entrypoints/openai
|
||||||
- tests/entrypoints/test_chat_utils
|
- tests/entrypoints/test_chat_utils
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/openai/chat_completion
|
||||||
- pytest -v -s entrypoints/openai/chat_completion
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/openai/completion --ignore=entrypoints/openai/completion/test_tensorizer_entrypoint.py
|
||||||
- pytest -v -s entrypoints/openai/completion --ignore=entrypoints/openai/completion/test_tensorizer_entrypoint.py
|
|
||||||
mirror:
|
mirror:
|
||||||
amd:
|
amd:
|
||||||
device: mi325_1
|
device: mi325_1
|
||||||
@@ -128,8 +124,7 @@ steps:
|
|||||||
- vllm/
|
- vllm/
|
||||||
- tests/entrypoints/speech_to_text
|
- tests/entrypoints/speech_to_text
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/speech_to_text
|
||||||
- pytest -v -s entrypoints/speech_to_text
|
|
||||||
|
|
||||||
- label: Entrypoints Integration (Multimodal)
|
- label: Entrypoints Integration (Multimodal)
|
||||||
device: h200_35gb
|
device: h200_35gb
|
||||||
@@ -140,8 +135,7 @@ steps:
|
|||||||
- vllm/
|
- vllm/
|
||||||
- tests/entrypoints/multimodal
|
- tests/entrypoints/multimodal
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/multimodal
|
||||||
- pytest -v -s entrypoints/multimodal
|
|
||||||
|
|
||||||
- label: Entrypoints Integration (Pooling)
|
- label: Entrypoints Integration (Pooling)
|
||||||
key: entrypoints-integration-pooling
|
key: entrypoints-integration-pooling
|
||||||
@@ -151,8 +145,7 @@ steps:
|
|||||||
- vllm/
|
- vllm/
|
||||||
- tests/entrypoints/pooling
|
- tests/entrypoints/pooling
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/pooling
|
||||||
- pytest -v -s entrypoints/pooling
|
|
||||||
|
|
||||||
- label: OpenAI API Correctness
|
- label: OpenAI API Correctness
|
||||||
key: openai-api-correctness
|
key: openai-api-correctness
|
||||||
|
|||||||
@@ -74,6 +74,20 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- pytest -v -s kernels/attention --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT
|
- pytest -v -s kernels/attention --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT
|
||||||
parallelism: 2
|
parallelism: 2
|
||||||
|
mirror:
|
||||||
|
amd:
|
||||||
|
device: mi325_1
|
||||||
|
timeout_in_minutes: 55
|
||||||
|
depends_on:
|
||||||
|
- image-build-amd
|
||||||
|
source_file_dependencies:
|
||||||
|
- csrc/attention/
|
||||||
|
- vllm/v1/attention
|
||||||
|
- vllm/model_executor/layers/attention
|
||||||
|
- tests/kernels/attention
|
||||||
|
- vllm/_aiter_ops.py
|
||||||
|
- vllm/envs.py
|
||||||
|
- vllm/platforms/rocm.py
|
||||||
|
|
||||||
- label: Kernels Attention DiffKV Test (H100)
|
- label: Kernels Attention DiffKV Test (H100)
|
||||||
key: kernels-attention-diffkv-test-h100
|
key: kernels-attention-diffkv-test-h100
|
||||||
@@ -104,6 +118,7 @@ steps:
|
|||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
- csrc/quantization/
|
- csrc/quantization/
|
||||||
- vllm/model_executor/layers/quantization
|
- vllm/model_executor/layers/quantization
|
||||||
|
- vllm/config/
|
||||||
- tests/kernels/quantization
|
- tests/kernels/quantization
|
||||||
- tests/kernels/quantization/test_rocm_skinny_gemms.py
|
- tests/kernels/quantization/test_rocm_skinny_gemms.py
|
||||||
- vllm/_aiter_ops.py
|
- vllm/_aiter_ops.py
|
||||||
@@ -127,6 +142,22 @@ steps:
|
|||||||
- pytest -v -s kernels/moe --ignore=kernels/moe/test_modular_oai_triton_moe.py --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT
|
- pytest -v -s kernels/moe --ignore=kernels/moe/test_modular_oai_triton_moe.py --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT
|
||||||
- pytest -v -s kernels/moe/test_modular_oai_triton_moe.py --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT
|
- pytest -v -s kernels/moe/test_modular_oai_triton_moe.py --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT
|
||||||
parallelism: 5
|
parallelism: 5
|
||||||
|
mirror:
|
||||||
|
amd:
|
||||||
|
device: mi325_1
|
||||||
|
timeout_in_minutes: 50
|
||||||
|
source_file_dependencies:
|
||||||
|
- csrc/quantization/cutlass_w8a8/moe/
|
||||||
|
- csrc/moe/
|
||||||
|
- tests/kernels/moe
|
||||||
|
- vllm/model_executor/layers/fused_moe/
|
||||||
|
- vllm/distributed/device_communicators/
|
||||||
|
- vllm/envs.py
|
||||||
|
- vllm/config
|
||||||
|
- vllm/_aiter_ops.py
|
||||||
|
- vllm/platforms/rocm.py
|
||||||
|
depends_on:
|
||||||
|
- image-build-amd
|
||||||
|
|
||||||
- label: Kernels Mamba Test
|
- label: Kernels Mamba Test
|
||||||
key: kernels-mamba-test
|
key: kernels-mamba-test
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ steps:
|
|||||||
- csrc/
|
- csrc/
|
||||||
- vllm/model_executor/layers/quantization
|
- vllm/model_executor/layers/quantization
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_USE_DEEP_GEMM=0 # We found Triton is faster than DeepGEMM for H100
|
- VLLM_USE_DEEP_GEMM=0 pytest -s -v test_lm_eval_correctness.py --config-list-file=configs/models-large-hopper.txt --tp-size=4 # Triton is faster than DeepGEMM for H100
|
||||||
- pytest -s -v test_lm_eval_correctness.py --config-list-file=configs/models-large-hopper.txt --tp-size=4
|
|
||||||
|
|
||||||
- label: LM Eval Small Models (B200)
|
- label: LM Eval Small Models (B200)
|
||||||
key: lm-eval-small-models-b200
|
key: lm-eval-small-models-b200
|
||||||
@@ -101,6 +100,14 @@ steps:
|
|||||||
num_devices: 8
|
num_devices: 8
|
||||||
commands:
|
commands:
|
||||||
- pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=configs/models-h200.txt
|
- pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=configs/models-h200.txt
|
||||||
|
mirror:
|
||||||
|
amd:
|
||||||
|
device: mi300_8
|
||||||
|
timeout_in_minutes: 180
|
||||||
|
depends_on:
|
||||||
|
- image-build-amd
|
||||||
|
commands:
|
||||||
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn PYTORCH_ROCM_ARCH=gfx942 pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=configs/models-mi3xx.txt # Limit Quark compilation to save time
|
||||||
|
|
||||||
- label: MoE Refactor Integration Test (H100 - TEMPORARY)
|
- label: MoE Refactor Integration Test (H100 - TEMPORARY)
|
||||||
key: moe-refactor-integration-test-h100-temporary
|
key: moe-refactor-integration-test-h100-temporary
|
||||||
|
|||||||
@@ -12,6 +12,17 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- pytest -v -s lora --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --ignore=lora/test_chatglm3_tp.py --ignore=lora/test_llama_tp.py --ignore=lora/test_qwen3_with_multi_loras.py --ignore=lora/test_olmoe_tp.py --ignore=lora/test_deepseekv2_tp.py --ignore=lora/test_gptoss_tp.py --ignore=lora/test_qwen3moe_tp.py --ignore=lora/test_qwen35_densemodel_lora.py
|
- pytest -v -s lora --shard-id=$$BUILDKITE_PARALLEL_JOB --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --ignore=lora/test_chatglm3_tp.py --ignore=lora/test_llama_tp.py --ignore=lora/test_qwen3_with_multi_loras.py --ignore=lora/test_olmoe_tp.py --ignore=lora/test_deepseekv2_tp.py --ignore=lora/test_gptoss_tp.py --ignore=lora/test_qwen3moe_tp.py --ignore=lora/test_qwen35_densemodel_lora.py
|
||||||
parallelism: 4
|
parallelism: 4
|
||||||
|
mirror:
|
||||||
|
amd:
|
||||||
|
device: mi325_1
|
||||||
|
working_dir: "/vllm-workspace/tests"
|
||||||
|
timeout_in_minutes: 60
|
||||||
|
source_file_dependencies:
|
||||||
|
- vllm/lora
|
||||||
|
- tests/lora
|
||||||
|
- vllm/platforms/rocm.py
|
||||||
|
depends_on:
|
||||||
|
- image-build-amd
|
||||||
|
|
||||||
|
|
||||||
- label: LoRA TP (Distributed)
|
- label: LoRA TP (Distributed)
|
||||||
@@ -25,14 +36,14 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
# FIXIT: find out which code initialize cuda before running the test
|
# FIXIT: find out which code initialize cuda before running the test
|
||||||
# before the fix, we need to use spawn to test it
|
# before the fix, we need to use spawn to test it
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
#
|
||||||
# Alot of these tests are on the edge of OOMing
|
# Alot of these tests are on the edge of OOMing
|
||||||
- export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
|
#
|
||||||
# There is some Tensor Parallelism related processing logic in LoRA that
|
# There is some Tensor Parallelism related processing logic in LoRA that
|
||||||
# requires multi-GPU testing for validation.
|
# requires multi-GPU testing for validation.
|
||||||
- pytest -v -s -x lora/test_chatglm3_tp.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True pytest -v -s -x lora/test_chatglm3_tp.py
|
||||||
- pytest -v -s -x lora/test_llama_tp.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True pytest -v -s -x lora/test_llama_tp.py
|
||||||
- pytest -v -s -x lora/test_qwen3_with_multi_loras.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True pytest -v -s -x lora/test_qwen3_with_multi_loras.py
|
||||||
- pytest -v -s -x lora/test_olmoe_tp.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True pytest -v -s -x lora/test_olmoe_tp.py
|
||||||
- pytest -v -s -x lora/test_gptoss_tp.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True pytest -v -s -x lora/test_gptoss_tp.py
|
||||||
- pytest -v -s -x lora/test_qwen35_densemodel_lora.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True pytest -v -s -x lora/test_qwen35_densemodel_lora.py
|
||||||
@@ -18,9 +18,14 @@ steps:
|
|||||||
- vllm/v1/
|
- vllm/v1/
|
||||||
- tests/v1/spec_decode
|
- tests/v1/spec_decode
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
|
||||||
# TODO: create another `optional` test group for slow tests
|
# TODO: create another `optional` test group for slow tests
|
||||||
- pytest -v -s -m 'not slow_test' v1/spec_decode
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s -m 'not slow_test' v1/spec_decode
|
||||||
|
mirror:
|
||||||
|
amd:
|
||||||
|
device: mi300_1
|
||||||
|
timeout_in_minutes: 65
|
||||||
|
depends_on:
|
||||||
|
- image-build-amd
|
||||||
|
|
||||||
- label: V1 Sample + Logits
|
- label: V1 Sample + Logits
|
||||||
key: v1-sample-logits
|
key: v1-sample-logits
|
||||||
@@ -44,12 +49,11 @@ steps:
|
|||||||
- tests/v1/test_request.py
|
- tests/v1/test_request.py
|
||||||
- tests/v1/test_outputs.py
|
- tests/v1/test_outputs.py
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/sample
|
||||||
- pytest -v -s v1/sample
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/logits_processors
|
||||||
- pytest -v -s v1/logits_processors
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/test_oracle.py
|
||||||
- pytest -v -s v1/test_oracle.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/test_request.py
|
||||||
- pytest -v -s v1/test_request.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/test_outputs.py
|
||||||
- pytest -v -s v1/test_outputs.py
|
|
||||||
mirror:
|
mirror:
|
||||||
amd:
|
amd:
|
||||||
device: mi325_1
|
device: mi325_1
|
||||||
@@ -87,18 +91,23 @@ steps:
|
|||||||
- tests/entrypoints/openai/correctness/test_lmeval.py
|
- tests/entrypoints/openai/correctness/test_lmeval.py
|
||||||
commands:
|
commands:
|
||||||
- bash /vllm-workspace/.buildkite/scripts/install-kv-connectors.sh
|
- bash /vllm-workspace/.buildkite/scripts/install-kv-connectors.sh
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
|
||||||
# split the test to avoid interference
|
# split the test to avoid interference
|
||||||
- pytest -v -s -m 'not cpu_test' v1/core
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s -m 'not cpu_test' v1/core
|
||||||
- pytest -v -s v1/executor
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/executor
|
||||||
- pytest -v -s v1/kv_offload
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/kv_offload
|
||||||
- pytest -v -s v1/simple_kv_offload
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/simple_kv_offload
|
||||||
- pytest -v -s v1/worker
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/worker
|
||||||
- pytest -v -s -m 'not cpu_test' v1/kv_connector/unit
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s -m 'not cpu_test' v1/kv_connector/unit
|
||||||
- pytest -v -s -m 'not cpu_test' v1/metrics
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s -m 'not cpu_test' v1/metrics
|
||||||
# Integration test for streaming correctness (requires special branch).
|
# Integration test for streaming correctness (requires special branch).
|
||||||
- pip install -U git+https://github.com/robertgshaw2-redhat/lm-evaluation-harness.git@streaming-api
|
- pip install -U git+https://github.com/robertgshaw2-redhat/lm-evaluation-harness.git@streaming-api
|
||||||
- pytest -v -s entrypoints/openai/correctness/test_lmeval.py::test_lm_eval_accuracy_v1_engine
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/openai/correctness/test_lmeval.py::test_lm_eval_accuracy_v1_engine
|
||||||
|
mirror:
|
||||||
|
amd:
|
||||||
|
device: mi325_1
|
||||||
|
timeout_in_minutes: 60
|
||||||
|
depends_on:
|
||||||
|
- image-build-amd
|
||||||
|
|
||||||
- label: V1 Others (CPU)
|
- label: V1 Others (CPU)
|
||||||
key: v1-others-cpu
|
key: v1-others-cpu
|
||||||
@@ -141,8 +150,7 @@ steps:
|
|||||||
- vllm/distributed/kv_transfer/kv_connector/v1/example_hidden_states_connector.py
|
- vllm/distributed/kv_transfer/kv_connector/v1/example_hidden_states_connector.py
|
||||||
- tests/v1/kv_connector/extract_hidden_states_integration
|
- tests/v1/kv_connector/extract_hidden_states_integration
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/kv_connector/extract_hidden_states_integration
|
||||||
- pytest -v -s v1/kv_connector/extract_hidden_states_integration
|
|
||||||
|
|
||||||
- label: Extract Hidden States Integration (2 GPUs)
|
- label: Extract Hidden States Integration (2 GPUs)
|
||||||
key: extract-hidden-states-integration-2-gpus
|
key: extract-hidden-states-integration-2-gpus
|
||||||
@@ -155,8 +163,7 @@ steps:
|
|||||||
- vllm/distributed/kv_transfer/kv_connector/v1/example_hidden_states_connector.py
|
- vllm/distributed/kv_transfer/kv_connector/v1/example_hidden_states_connector.py
|
||||||
- tests/v1/kv_connector/extract_hidden_states_integration
|
- tests/v1/kv_connector/extract_hidden_states_integration
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s -m 'distributed' v1/kv_connector/extract_hidden_states_integration
|
||||||
- pytest -v -s -m 'distributed' v1/kv_connector/extract_hidden_states_integration
|
|
||||||
|
|
||||||
- label: Regression
|
- label: Regression
|
||||||
key: regression
|
key: regression
|
||||||
@@ -348,10 +355,9 @@ steps:
|
|||||||
- vllm/model_executor/layers
|
- vllm/model_executor/layers
|
||||||
- tests/v1/determinism/
|
- tests/v1/determinism/
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
|
||||||
- pip install pytest-timeout pytest-forked
|
- pip install pytest-timeout pytest-forked
|
||||||
- pytest -v -s v1/determinism/test_batch_invariance.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/determinism/test_batch_invariance.py
|
||||||
- VLLM_TEST_MODEL=deepseek-ai/DeepSeek-V2-Lite-Chat pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[TRITON_MLA]
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn VLLM_TEST_MODEL=deepseek-ai/DeepSeek-V2-Lite-Chat pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[TRITON_MLA]
|
||||||
|
|
||||||
- label: Batch Invariance (H100)
|
- label: Batch Invariance (H100)
|
||||||
key: batch-invariance-h100
|
key: batch-invariance-h100
|
||||||
@@ -362,12 +368,11 @@ steps:
|
|||||||
- vllm/model_executor/layers
|
- vllm/model_executor/layers
|
||||||
- tests/v1/determinism/
|
- tests/v1/determinism/
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
|
||||||
- pip install pytest-timeout pytest-forked
|
- pip install pytest-timeout pytest-forked
|
||||||
- pytest -v -s v1/determinism/test_batch_invariance.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/determinism/test_batch_invariance.py
|
||||||
- pytest -v -s v1/determinism/test_rms_norm_batch_invariant.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/determinism/test_rms_norm_batch_invariant.py
|
||||||
- VLLM_TEST_MODEL=deepseek-ai/DeepSeek-V2-Lite-Chat pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[TRITON_MLA]
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn VLLM_TEST_MODEL=deepseek-ai/DeepSeek-V2-Lite-Chat pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[TRITON_MLA]
|
||||||
- VLLM_TEST_MODEL=Qwen/Qwen3-30B-A3B-Thinking-2507-FP8 pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[FLASH_ATTN]
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn VLLM_TEST_MODEL=Qwen/Qwen3-30B-A3B-Thinking-2507-FP8 pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[FLASH_ATTN]
|
||||||
|
|
||||||
- label: Batch Invariance (B200)
|
- label: Batch Invariance (B200)
|
||||||
key: batch-invariance-b200
|
key: batch-invariance-b200
|
||||||
@@ -378,14 +383,13 @@ steps:
|
|||||||
- vllm/model_executor/layers
|
- vllm/model_executor/layers
|
||||||
- tests/v1/determinism/
|
- tests/v1/determinism/
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
|
||||||
- pip install pytest-timeout pytest-forked
|
- pip install pytest-timeout pytest-forked
|
||||||
- pytest -v -s v1/determinism/test_batch_invariance.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/determinism/test_batch_invariance.py
|
||||||
- pytest -v -s v1/determinism/test_rms_norm_batch_invariant.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/determinism/test_rms_norm_batch_invariant.py
|
||||||
- VLLM_TEST_MODEL=deepseek-ai/DeepSeek-V2-Lite-Chat pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[TRITON_MLA]
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn VLLM_TEST_MODEL=deepseek-ai/DeepSeek-V2-Lite-Chat pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[TRITON_MLA]
|
||||||
- VLLM_TEST_MODEL=Qwen/Qwen3-30B-A3B-Thinking-2507-FP8 pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[FLASH_ATTN]
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn VLLM_TEST_MODEL=Qwen/Qwen3-30B-A3B-Thinking-2507-FP8 pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[FLASH_ATTN]
|
||||||
- pytest -v -s v1/determinism/test_nvfp4_batch_invariant.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/determinism/test_nvfp4_batch_invariant.py
|
||||||
- pytest -v -s v1/determinism/test_nvfp4_batch_invariant_scaled_mm.py
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/determinism/test_nvfp4_batch_invariant_scaled_mm.py
|
||||||
|
|
||||||
- label: Acceptance Length Test (Large Models) # optional
|
- label: Acceptance Length Test (Large Models) # optional
|
||||||
device: h200_35gb
|
device: h200_35gb
|
||||||
@@ -400,5 +404,4 @@ steps:
|
|||||||
- vllm/model_executor/models/mlp_speculator.py
|
- vllm/model_executor/models/mlp_speculator.py
|
||||||
- tests/v1/spec_decode/test_acceptance_length.py
|
- tests/v1/spec_decode/test_acceptance_length.py
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_ALLOW_INSECURE_SERIALIZATION=1
|
- VLLM_ALLOW_INSECURE_SERIALIZATION=1 pytest -v -s v1/spec_decode/test_acceptance_length.py -m slow_test
|
||||||
- pytest -v -s v1/spec_decode/test_acceptance_length.py -m slow_test
|
|
||||||
|
|||||||
@@ -13,13 +13,12 @@ steps:
|
|||||||
- tests/entrypoints/openai/completion/test_tensorizer_entrypoint.py
|
- tests/entrypoints/openai/completion/test_tensorizer_entrypoint.py
|
||||||
commands:
|
commands:
|
||||||
- apt-get update && apt-get install -y curl libsodium23
|
- apt-get update && apt-get install -y curl libsodium23
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
|
||||||
# Dump tracebacks of all threads if a test hangs, so a wedged GPU/CUDA
|
|
||||||
# init surfaces a stack instead of silently stalling.
|
|
||||||
- export PYTHONFAULTHANDLER=1
|
|
||||||
# Per-test watchdog: a single hung test (e.g. stuck during engine/CUDA
|
# Per-test watchdog: a single hung test (e.g. stuck during engine/CUDA
|
||||||
# init) fails fast with a traceback instead of running until the global
|
# init) fails fast with a traceback instead of running until the global
|
||||||
# build timeout. The `thread` method also handles hangs inside C/CUDA
|
# build timeout. The `thread` method also handles hangs inside C/CUDA
|
||||||
# calls that the signal method cannot interrupt.
|
# calls that the signal method cannot interrupt.
|
||||||
- pytest -v -s model_executor -m '(not slow_test)' --timeout=900 --timeout-method=thread
|
#
|
||||||
- pytest -v -s entrypoints/openai/completion/test_tensorizer_entrypoint.py --timeout=900 --timeout-method=thread
|
# Env vars are inlined because CONTINUE_ON_FAILURE wraps each command
|
||||||
|
# in a subshell, so a standalone `export` would be lost.
|
||||||
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn PYTHONFAULTHANDLER=1 pytest -v -s model_executor -m '(not slow_test)' --timeout=900 --timeout-method=thread
|
||||||
|
- VLLM_WORKER_MULTIPROC_METHOD=spawn PYTHONFAULTHANDLER=1 pytest -v -s entrypoints/openai/completion/test_tensorizer_entrypoint.py --timeout=900 --timeout-method=thread
|
||||||
|
|||||||
@@ -16,15 +16,14 @@ steps:
|
|||||||
- tests/entrypoints/llm/test_struct_output_generate.py
|
- tests/entrypoints/llm/test_struct_output_generate.py
|
||||||
commands:
|
commands:
|
||||||
- set -x
|
- set -x
|
||||||
- export VLLM_USE_V2_MODEL_RUNNER=1
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s v1/engine/test_llm_engine.py -k "not test_engine_metrics"
|
||||||
- pytest -v -s v1/engine/test_llm_engine.py -k "not test_engine_metrics"
|
|
||||||
# This requires eager until we sort out CG correctness issues.
|
# This requires eager until we sort out CG correctness issues.
|
||||||
# TODO: remove ENFORCE_EAGER here after https://github.com/vllm-project/vllm/pull/32936 is merged.
|
# TODO: remove ENFORCE_EAGER here after https://github.com/vllm-project/vllm/pull/32936 is merged.
|
||||||
- ENFORCE_EAGER=1 pytest -v -s v1/e2e/general/test_async_scheduling.py -k "not ngram"
|
- VLLM_USE_V2_MODEL_RUNNER=1 ENFORCE_EAGER=1 pytest -v -s v1/e2e/general/test_async_scheduling.py -k "not ngram"
|
||||||
- pytest -v -s v1/e2e/general/test_context_length.py
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s v1/e2e/general/test_context_length.py
|
||||||
- pytest -v -s v1/e2e/general/test_min_tokens.py
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s v1/e2e/general/test_min_tokens.py
|
||||||
# Temporary hack filter to exclude ngram spec decoding based tests.
|
# Temporary hack filter to exclude ngram spec decoding based tests.
|
||||||
- pytest -v -s entrypoints/llm/test_struct_output_generate.py -k "xgrammar and not speculative_config6 and not speculative_config7 and not speculative_config8 and not speculative_config0"
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s entrypoints/llm/test_struct_output_generate.py -k "xgrammar and not speculative_config6 and not speculative_config7 and not speculative_config8 and not speculative_config0"
|
||||||
|
|
||||||
- label: Model Runner V2 Examples
|
- label: Model Runner V2 Examples
|
||||||
device: h200_35gb
|
device: h200_35gb
|
||||||
@@ -42,26 +41,25 @@ steps:
|
|||||||
- examples/features/tensorize_vllm_model.py
|
- examples/features/tensorize_vllm_model.py
|
||||||
commands:
|
commands:
|
||||||
- set -x
|
- set -x
|
||||||
- export VLLM_USE_V2_MODEL_RUNNER=1
|
|
||||||
- pip install tensorizer # for tensorizer test
|
- pip install tensorizer # for tensorizer test
|
||||||
- python3 basic/offline_inference/chat.py # for basic
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 basic/offline_inference/chat.py # for basic
|
||||||
- python3 basic/offline_inference/generate.py --model facebook/opt-125m
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 basic/offline_inference/generate.py --model facebook/opt-125m
|
||||||
#- python3 basic/offline_inference/generate.py --model meta-llama/Llama-2-13b-chat-hf --cpu-offload-gb 10 # TODO
|
#- VLLM_USE_V2_MODEL_RUNNER=1 python3 basic/offline_inference/generate.py --model meta-llama/Llama-2-13b-chat-hf --cpu-offload-gb 10 # TODO
|
||||||
#- python3 basic/offline_inference/embed.py # TODO
|
#- VLLM_USE_V2_MODEL_RUNNER=1 python3 basic/offline_inference/embed.py # TODO
|
||||||
# for multi-modal models
|
# for multi-modal models
|
||||||
- python3 generate/multimodal/audio_language_offline.py --seed 0
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 generate/multimodal/audio_language_offline.py --seed 0
|
||||||
- python3 generate/multimodal/vision_language_offline.py --seed 0
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 generate/multimodal/vision_language_offline.py --seed 0
|
||||||
- python3 generate/multimodal/vision_language_multi_image_offline.py --seed 0
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 generate/multimodal/vision_language_multi_image_offline.py --seed 0
|
||||||
- python3 generate/multimodal/encoder_decoder_multimodal_offline.py --model-type whisper --seed 0
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 generate/multimodal/encoder_decoder_multimodal_offline.py --model-type whisper --seed 0
|
||||||
# for pooling models
|
# for pooling models
|
||||||
- python3 pooling/embed/vision_embedding_offline.py --seed 0
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 pooling/embed/vision_embedding_offline.py --seed 0
|
||||||
# for features demo
|
# for features demo
|
||||||
- python3 features/automatic_prefix_caching/prefix_caching_offline.py
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 features/automatic_prefix_caching/prefix_caching_offline.py
|
||||||
- python3 deployment/llm_engine_example.py
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 deployment/llm_engine_example.py
|
||||||
- python3 features/tensorize_vllm_model.py --model facebook/opt-125m serialize --serialized-directory /tmp/ --suffix v1 && python3 features/tensorize_vllm_model.py --model facebook/opt-125m deserialize --path-to-tensors /tmp/vllm/facebook/opt-125m/v1/model.tensors
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 features/tensorize_vllm_model.py --model facebook/opt-125m serialize --serialized-directory /tmp/ --suffix v1 && VLLM_USE_V2_MODEL_RUNNER=1 python3 features/tensorize_vllm_model.py --model facebook/opt-125m deserialize --path-to-tensors /tmp/vllm/facebook/opt-125m/v1/model.tensors
|
||||||
- python3 features/speculative_decoding/spec_decode_offline.py --test --method eagle --num_spec_tokens 3 --dataset-name hf --dataset-path philschmid/mt-bench --num-prompts 80 --temp 0 --top-p 1.0 --top-k -1 --tp 1 --enable-chunked-prefill --max-model-len 2048
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 features/speculative_decoding/spec_decode_offline.py --test --method eagle --num_spec_tokens 3 --dataset-name hf --dataset-path philschmid/mt-bench --num-prompts 80 --temp 0 --top-p 1.0 --top-k -1 --tp 1 --enable-chunked-prefill --max-model-len 2048
|
||||||
# https://github.com/vllm-project/vllm/pull/26682 uses slightly more memory in PyTorch 2.9+ causing this test to OOM in 1xL4 GPU
|
# https://github.com/vllm-project/vllm/pull/26682 uses slightly more memory in PyTorch 2.9+ causing this test to OOM in 1xL4 GPU
|
||||||
- python3 features/speculative_decoding/spec_decode_offline.py --test --method eagle3 --num_spec_tokens 3 --dataset-name hf --dataset-path philschmid/mt-bench --num-prompts 80 --temp 0 --top-p 1.0 --top-k -1 --tp 1 --enable-chunked-prefill --max-model-len 1536
|
- VLLM_USE_V2_MODEL_RUNNER=1 python3 features/speculative_decoding/spec_decode_offline.py --test --method eagle3 --num_spec_tokens 3 --dataset-name hf --dataset-path philschmid/mt-bench --num-prompts 80 --temp 0 --top-p 1.0 --top-k -1 --tp 1 --enable-chunked-prefill --max-model-len 1536
|
||||||
|
|
||||||
- label: Model Runner V2 Distributed (2 GPUs)
|
- label: Model Runner V2 Distributed (2 GPUs)
|
||||||
key: model-runner-v2-distributed-2-gpus
|
key: model-runner-v2-distributed-2-gpus
|
||||||
@@ -76,13 +74,11 @@ steps:
|
|||||||
- tests/v1/distributed/test_eagle_dp.py
|
- tests/v1/distributed/test_eagle_dp.py
|
||||||
commands:
|
commands:
|
||||||
- set -x
|
- set -x
|
||||||
- export VLLM_USE_V2_MODEL_RUNNER=1
|
|
||||||
# The "and not True" here is a hacky way to exclude the prompt_embeds cases which aren't yet supported.
|
# The "and not True" here is a hacky way to exclude the prompt_embeds cases which aren't yet supported.
|
||||||
- TARGET_TEST_SUITE=L4 pytest -v -s basic_correctness/test_basic_correctness.py -m 'distributed(num_gpus=2)' -k "not ray and not True"
|
- VLLM_USE_V2_MODEL_RUNNER=1 TARGET_TEST_SUITE=L4 pytest -v -s basic_correctness/test_basic_correctness.py -m 'distributed(num_gpus=2)' -k "not ray and not True"
|
||||||
# https://github.com/NVIDIA/nccl/issues/1838
|
# https://github.com/NVIDIA/nccl/issues/1838
|
||||||
- export NCCL_CUMEM_HOST_ENABLE=0
|
- VLLM_USE_V2_MODEL_RUNNER=1 NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_async_llm_dp.py -k "not ray"
|
||||||
- TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_async_llm_dp.py -k "not ray"
|
- VLLM_USE_V2_MODEL_RUNNER=1 NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_eagle_dp.py
|
||||||
- TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_eagle_dp.py
|
|
||||||
|
|
||||||
- label: Model Runner V2 Pipeline Parallelism (4 GPUs)
|
- label: Model Runner V2 Pipeline Parallelism (4 GPUs)
|
||||||
key: model-runner-v2-pipeline-parallelism-4-gpus
|
key: model-runner-v2-pipeline-parallelism-4-gpus
|
||||||
@@ -97,10 +93,9 @@ steps:
|
|||||||
- tests/v1/distributed/test_pp_dp_v2.py
|
- tests/v1/distributed/test_pp_dp_v2.py
|
||||||
commands:
|
commands:
|
||||||
- set -x
|
- set -x
|
||||||
- export VLLM_USE_V2_MODEL_RUNNER=1
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s distributed/test_pipeline_parallel.py -k "not ray and not Jamba"
|
||||||
- pytest -v -s distributed/test_pipeline_parallel.py -k "not ray and not Jamba"
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s distributed/test_pp_cudagraph.py -k "not ray"
|
||||||
- pytest -v -s distributed/test_pp_cudagraph.py -k "not ray"
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s v1/distributed/test_pp_dp_v2.py
|
||||||
- pytest -v -s v1/distributed/test_pp_dp_v2.py
|
|
||||||
|
|
||||||
- label: Model Runner V2 Spec Decode
|
- label: Model Runner V2 Spec Decode
|
||||||
device: h200_35gb
|
device: h200_35gb
|
||||||
@@ -115,8 +110,7 @@ steps:
|
|||||||
- tests/v1/e2e/spec_decode/test_spec_decode.py
|
- tests/v1/e2e/spec_decode/test_spec_decode.py
|
||||||
commands:
|
commands:
|
||||||
- set -x
|
- set -x
|
||||||
- export VLLM_USE_V2_MODEL_RUNNER=1
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s v1/spec_decode/test_max_len.py -k "eagle or mtp"
|
||||||
- pytest -v -s v1/spec_decode/test_max_len.py -k "eagle or mtp"
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s v1/spec_decode/test_rejection_sampler_utils.py
|
||||||
- pytest -v -s v1/spec_decode/test_rejection_sampler_utils.py
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s v1/spec_decode/test_synthetic_rejection_sampler_utils.py
|
||||||
- pytest -v -s v1/spec_decode/test_synthetic_rejection_sampler_utils.py
|
- VLLM_USE_V2_MODEL_RUNNER=1 pytest -v -s v1/e2e/spec_decode/test_spec_decode.py -k "eagle or mtp"
|
||||||
- pytest -v -s v1/e2e/spec_decode/test_spec_decode.py -k "eagle or mtp"
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ steps:
|
|||||||
- pip install git+https://github.com/TIGER-AI-Lab/Mantis.git
|
- pip install git+https://github.com/TIGER-AI-Lab/Mantis.git
|
||||||
- pytest -v -s models/multimodal/generation/test_common.py -m core_model -k "qwen3 or gemma"
|
- pytest -v -s models/multimodal/generation/test_common.py -m core_model -k "qwen3 or gemma"
|
||||||
- pytest -v -s models/multimodal/generation/test_qwen2_5_vl.py -m core_model
|
- pytest -v -s models/multimodal/generation/test_qwen2_5_vl.py -m core_model
|
||||||
- pytest -v -s models/multimodal/generation/test_vit_cudagraph.py -m core_model
|
|
||||||
mirror:
|
mirror:
|
||||||
amd:
|
amd:
|
||||||
device: mi325_1
|
device: mi325_1
|
||||||
@@ -63,9 +62,15 @@ steps:
|
|||||||
- tests/models/multimodal
|
- tests/models/multimodal
|
||||||
commands:
|
commands:
|
||||||
- pip install git+https://github.com/TIGER-AI-Lab/Mantis.git
|
- pip install git+https://github.com/TIGER-AI-Lab/Mantis.git
|
||||||
- pytest -v -s models/multimodal -m core_model --ignore models/multimodal/generation/test_common.py --ignore models/multimodal/generation/test_ultravox.py --ignore models/multimodal/generation/test_qwen2_5_vl.py --ignore models/multimodal/generation/test_qwen2_vl.py --ignore models/multimodal/generation/test_whisper.py --ignore models/multimodal/generation/test_memory_leak.py --ignore models/multimodal/processing
|
- pytest -v -s models/multimodal -m core_model --ignore models/multimodal/generation/test_common.py --ignore models/multimodal/generation/test_ultravox.py --ignore models/multimodal/generation/test_qwen2_5_vl.py --ignore models/multimodal/generation/test_qwen2_vl.py --ignore models/multimodal/generation/test_whisper.py --ignore models/multimodal/generation/test_memory_leak.py --ignore models/multimodal/generation/test_vit_cudagraph.py --ignore models/multimodal/processing
|
||||||
|
- pytest -v -s models/multimodal/generation/test_vit_cudagraph.py -m core_model
|
||||||
- pytest models/multimodal/generation/test_memory_leak.py -m core_model
|
- pytest models/multimodal/generation/test_memory_leak.py -m core_model
|
||||||
- cd .. && VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s tests/models/multimodal/generation/test_whisper.py -m core_model # Otherwise, mp_method="spawn" doesn't work
|
- cd .. && VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s tests/models/multimodal/generation/test_whisper.py -m core_model # Otherwise, mp_method="spawn" doesn't work
|
||||||
|
mirror:
|
||||||
|
amd:
|
||||||
|
device: mi325_1
|
||||||
|
depends_on:
|
||||||
|
- image-build-amd
|
||||||
|
|
||||||
- label: Multi-Modal Processor (CPU)
|
- label: Multi-Modal Processor (CPU)
|
||||||
key: multi-modal-processor-cpu
|
key: multi-modal-processor-cpu
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ steps:
|
|||||||
- pip install -e ./plugins/bge_m3_sparse_plugin
|
- pip install -e ./plugins/bge_m3_sparse_plugin
|
||||||
- pytest -v -s plugins_tests/test_bge_m3_sparse_io_processor_plugins.py
|
- pytest -v -s plugins_tests/test_bge_m3_sparse_io_processor_plugins.py
|
||||||
- pip uninstall bge_m3_sparse_plugin -y
|
- pip uninstall bge_m3_sparse_plugin -y
|
||||||
|
# test colbert_query io_processor plugin
|
||||||
|
- pip install -e ./plugins/colbert_query_plugin
|
||||||
|
- pytest -v -s plugins_tests/test_colbert_query_io_processor_plugins.py
|
||||||
|
- pip uninstall colbert_query_plugin -y
|
||||||
# end io_processor plugins test
|
# end io_processor plugins test
|
||||||
# begin stat_logger plugins test
|
# begin stat_logger plugins test
|
||||||
- pip install -e ./plugins/vllm_add_dummy_stat_logger
|
- pip install -e ./plugins/vllm_add_dummy_stat_logger
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ steps:
|
|||||||
- tests/compile/passes
|
- tests/compile/passes
|
||||||
commands:
|
commands:
|
||||||
- pytest -s -v compile/passes --ignore compile/passes/distributed
|
- pytest -s -v compile/passes --ignore compile/passes/distributed
|
||||||
|
mirror:
|
||||||
|
amd:
|
||||||
|
device: mi300_1
|
||||||
|
timeout_in_minutes: 180
|
||||||
|
depends_on:
|
||||||
|
- image-build-amd
|
||||||
|
|
||||||
- label: PyTorch Fullgraph Smoke Test
|
- label: PyTorch Fullgraph Smoke Test
|
||||||
key: pytorch-fullgraph-smoke-test
|
key: pytorch-fullgraph-smoke-test
|
||||||
|
|||||||
@@ -23,17 +23,15 @@ steps:
|
|||||||
# - tests/entrypoints/openai/test_uds.py
|
# - tests/entrypoints/openai/test_uds.py
|
||||||
- tests/v1/sample/test_logprobs_e2e.py
|
- tests/v1/sample/test_logprobs_e2e.py
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_USE_RUST_FRONTEND=1
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s benchmarks/test_serve_cli.py -k "not insecure and not (test_bench_serve and not test_bench_serve_chat)"
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/openai/chat_completion/test_chat_completion.py
|
||||||
- pytest -v -s benchmarks/test_serve_cli.py -k "not insecure and not (test_bench_serve and not test_bench_serve_chat)"
|
# - VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/openai/chat_completion/test_chat_logit_bias_validation.py -k "not invalid"
|
||||||
- pytest -v -s entrypoints/openai/chat_completion/test_chat_completion.py
|
|
||||||
# - pytest -v -s entrypoints/openai/chat_completion/test_chat_logit_bias_validation.py -k "not invalid"
|
|
||||||
|
|
||||||
# - pytest -v -s entrypoints/openai/completion/test_prompt_validation.py -k "not prompt_embeds"
|
# - VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/openai/completion/test_prompt_validation.py -k "not prompt_embeds"
|
||||||
- pytest -v -s entrypoints/openai/completion/test_shutdown.py -k "not engine_failure and not test_abort_timeout_exits_quickly"
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/openai/completion/test_shutdown.py -k "not engine_failure and not test_abort_timeout_exits_quickly"
|
||||||
# - pytest -v -s entrypoints/openai/test_return_token_ids.py
|
# - VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/openai/test_return_token_ids.py
|
||||||
# - pytest -v -s entrypoints/openai/test_uds.py
|
# - VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/openai/test_uds.py
|
||||||
- pytest -v -s v1/sample/test_logprobs_e2e.py -k "test_prompt_logprobs_e2e_server"
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s v1/sample/test_logprobs_e2e.py -k "test_prompt_logprobs_e2e_server"
|
||||||
|
|
||||||
- label: Rust Frontend Serve/Admin Coverage
|
- label: Rust Frontend Serve/Admin Coverage
|
||||||
timeout_in_minutes: 60
|
timeout_in_minutes: 60
|
||||||
@@ -51,13 +49,11 @@ steps:
|
|||||||
- tests/entrypoints/serve/instrumentator/test_metrics.py
|
- tests/entrypoints/serve/instrumentator/test_metrics.py
|
||||||
# - tests/entrypoints/serve/dev/test_sleep.py
|
# - tests/entrypoints/serve/dev/test_sleep.py
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_USE_RUST_FRONTEND=1
|
# - VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/serve/dev/rpc/test_collective_rpc.py
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/serve/instrumentator/test_basic.py -k "not show_version and not server_load"
|
||||||
# - pytest -v -s entrypoints/serve/dev/rpc/test_collective_rpc.py
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/serve/disagg/test_serving_tokens.py -k "not stream and not lora and not test_generate_logprobs and not stop_string_workflow"
|
||||||
- pytest -v -s entrypoints/serve/instrumentator/test_basic.py -k "not show_version and not server_load"
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/serve/instrumentator/test_metrics.py -k "text and not show and not run_batch and not test_metrics_counts and not test_metrics_exist"
|
||||||
- pytest -v -s entrypoints/serve/disagg/test_serving_tokens.py -k "not stream and not lora and not test_generate_logprobs and not stop_string_workflow"
|
# - VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s entrypoints/serve/dev/test_sleep.py
|
||||||
- pytest -v -s entrypoints/serve/instrumentator/test_metrics.py -k "text and not show and not run_batch and not test_metrics_counts and not test_metrics_exist"
|
|
||||||
# - pytest -v -s entrypoints/serve/dev/test_sleep.py
|
|
||||||
|
|
||||||
- label: Rust Frontend Core Correctness
|
- label: Rust Frontend Core Correctness
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
@@ -69,9 +65,7 @@ steps:
|
|||||||
- tests/utils.py
|
- tests/utils.py
|
||||||
- tests/entrypoints/openai/correctness/test_lmeval.py
|
- tests/entrypoints/openai/correctness/test_lmeval.py
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_USE_RUST_FRONTEND=1
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -s entrypoints/openai/correctness/test_lmeval.py::test_lm_eval_accuracy_v1_engine
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
|
||||||
- pytest -s entrypoints/openai/correctness/test_lmeval.py::test_lm_eval_accuracy_v1_engine
|
|
||||||
|
|
||||||
- label: Rust Frontend Tool Use
|
- label: Rust Frontend Tool Use
|
||||||
timeout_in_minutes: 60
|
timeout_in_minutes: 60
|
||||||
@@ -83,9 +77,7 @@ steps:
|
|||||||
- tests/utils.py
|
- tests/utils.py
|
||||||
- tests/tool_use/
|
- tests/tool_use/
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_USE_RUST_FRONTEND=1
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s tool_use --ignore=tool_use/mistral --models llama3.2 -k "not test_response_format_with_tool_choice_required and not test_parallel_tool_calls_false and not test_tool_call_and_choice"
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
|
||||||
- pytest -v -s tool_use --ignore=tool_use/mistral --models llama3.2 -k "not test_response_format_with_tool_choice_required and not test_parallel_tool_calls_false and not test_tool_call_and_choice"
|
|
||||||
|
|
||||||
- label: Rust Frontend Distributed
|
- label: Rust Frontend Distributed
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
@@ -99,9 +91,10 @@ steps:
|
|||||||
- vllm/v1/engine/
|
- vllm/v1/engine/
|
||||||
- vllm/v1/worker/
|
- vllm/v1/worker/
|
||||||
- tests/utils.py
|
- tests/utils.py
|
||||||
|
- tests/v1/distributed/test_external_lb_dp.py
|
||||||
|
- tests/v1/distributed/test_hybrid_lb_dp.py
|
||||||
- tests/v1/distributed/test_internal_lb_dp.py
|
- tests/v1/distributed/test_internal_lb_dp.py
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_USE_RUST_FRONTEND=1
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=1 DP_SIZE=4 pytest -v -s v1/distributed/test_internal_lb_dp.py -k "not 4 and not server_info"
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=1 DP_SIZE=2 pytest -v -s v1/distributed/test_external_lb_dp.py -k "not 4 and not server_info"
|
||||||
- export NCCL_CUMEM_HOST_ENABLE=0
|
- VLLM_USE_RUST_FRONTEND=1 VLLM_WORKER_MULTIPROC_METHOD=spawn NCCL_CUMEM_HOST_ENABLE=0 TP_SIZE=1 DP_SIZE=4 pytest -v -s v1/distributed/test_hybrid_lb_dp.py -k "not 4 and not server_info"
|
||||||
- TP_SIZE=1 DP_SIZE=4 pytest -v -s v1/distributed/test_internal_lb_dp.py -k "not 4 and not server_info"
|
|
||||||
|
|||||||
@@ -12,6 +12,20 @@ steps:
|
|||||||
- tests/v1/e2e/spec_decode/
|
- tests/v1/e2e/spec_decode/
|
||||||
commands:
|
commands:
|
||||||
- pytest -v -s v1/e2e/spec_decode -k "eagle_correctness"
|
- pytest -v -s v1/e2e/spec_decode -k "eagle_correctness"
|
||||||
|
mirror:
|
||||||
|
amd:
|
||||||
|
device: mi325_1
|
||||||
|
timeout_in_minutes: 45
|
||||||
|
depends_on:
|
||||||
|
- image-build-amd
|
||||||
|
source_file_dependencies:
|
||||||
|
- vllm/v1/spec_decode/
|
||||||
|
- vllm/v1/worker/gpu/spec_decode/
|
||||||
|
- vllm/model_executor/model_loader/
|
||||||
|
- vllm/v1/sample/
|
||||||
|
- vllm/model_executor/layers/
|
||||||
|
- tests/v1/e2e/spec_decode/
|
||||||
|
- vllm/platforms/rocm.py
|
||||||
|
|
||||||
- label: Spec Decode Eagle Nightly B200
|
- label: Spec Decode Eagle Nightly B200
|
||||||
key: spec-decode-eagle-nightly-b200
|
key: spec-decode-eagle-nightly-b200
|
||||||
@@ -139,8 +153,7 @@ steps:
|
|||||||
- vllm/model_executor/models/qwen3_dflash.py
|
- vllm/model_executor/models/qwen3_dflash.py
|
||||||
- tests/v1/spec_decode/test_speculators_correctness.py
|
- tests/v1/spec_decode/test_speculators_correctness.py
|
||||||
commands:
|
commands:
|
||||||
- export VLLM_ALLOW_INSECURE_SERIALIZATION=1
|
- VLLM_ALLOW_INSECURE_SERIALIZATION=1 pytest -v -s v1/spec_decode/test_speculators_correctness.py -m slow_test
|
||||||
- pytest -v -s v1/spec_decode/test_speculators_correctness.py -m slow_test
|
|
||||||
|
|
||||||
- label: Spec Decode MTP hybrid (B200)
|
- label: Spec Decode MTP hybrid (B200)
|
||||||
timeout_in_minutes: 30
|
timeout_in_minutes: 30
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
name: ci-fails-buildkite
|
||||||
|
description: Fetch and diagnose vLLM Buildkite CI failure logs. Use when investigating failing CI jobs on a PR or build, when the user pastes a buildkite.com URL, or asks to fetch/diagnose CI logs.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Diagnosing vLLM Buildkite CI Failures
|
||||||
|
|
||||||
|
Buildkite logs are public; no login needed.
|
||||||
|
|
||||||
|
`.buildkite/scripts/ci-fetch-log.sh` saves each log as `ci-<build>-<job-name>.log`, stripped of timestamps and ANSI codes. Existing files are kept; set `CI_FETCH_LOG_FORCE=1` to refetch.
|
||||||
|
|
||||||
|
## Fetching logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# All failed jobs in a PR's latest build (current branch's PR if omitted):
|
||||||
|
.buildkite/scripts/ci-fetch-log.sh --pr <PR>
|
||||||
|
|
||||||
|
# All failed jobs in a build (--soft also includes soft-failed jobs;
|
||||||
|
# --all fetches every finished job):
|
||||||
|
.buildkite/scripts/ci-fetch-log.sh "https://buildkite.com/vllm/ci/builds/<N>"
|
||||||
|
|
||||||
|
# One job — `gh pr checks` URLs (#<job_uuid>) and web UI URLs (?sid=) both
|
||||||
|
# work; pass "-" as a second argument to stream to stdout:
|
||||||
|
.buildkite/scripts/ci-fetch-log.sh "https://buildkite.com/vllm/ci/builds/<N>#<job_uuid>"
|
||||||
|
```
|
||||||
|
|
||||||
|
To clean an already-downloaded log with `.buildkite/scripts/ci-clean-log.sh`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./ci-clean-log.sh ci.log
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
|
||||||
|
See [docs/contributing/ci/failures.md](../../../docs/contributing/ci/failures.md) for the full guide: filing CI failure issues, investigating/bisecting, reproducing flaky tests, and daily triage.
|
||||||
+2
-13
@@ -2,15 +2,14 @@
|
|||||||
# for more info about CODEOWNERS file
|
# for more info about CODEOWNERS file
|
||||||
|
|
||||||
# This lists cover the "core" components of vLLM that require careful review
|
# This lists cover the "core" components of vLLM that require careful review
|
||||||
/vllm/compilation @zou3519 @youkaichao @ProExpertProg @BoyuanFeng @vadiklyutiy
|
/vllm/compilation @zou3519 @youkaichao @ProExpertProg @BoyuanFeng
|
||||||
/vllm/distributed/kv_transfer @NickLucche @ApostaC @orozery @xuechendi
|
/vllm/distributed/kv_transfer @NickLucche @ApostaC @orozery @xuechendi
|
||||||
/vllm/lora @jeejeelee
|
/vllm/lora @jeejeelee
|
||||||
/vllm/model_executor/layers/attention @LucasWilkinson @MatthewBonanni
|
/vllm/model_executor/layers/attention @LucasWilkinson @MatthewBonanni
|
||||||
/vllm/model_executor/layers/fused_moe @mgoin @pavanimajety @zyongye
|
/vllm/model_executor/layers/fused_moe @mgoin @pavanimajety @zyongye
|
||||||
/vllm/model_executor/layers/quantization @mgoin @robertgshaw2-redhat @tlrmchlsmth @yewentao256 @pavanimajety @zyongye
|
/vllm/model_executor/layers/quantization @mgoin @robertgshaw2-redhat @tlrmchlsmth @yewentao256 @pavanimajety @zyongye
|
||||||
/vllm/model_executor/layers/mamba @tdoublep @tomeras91
|
/vllm/model_executor/layers/mamba @tdoublep @tomeras91
|
||||||
/vllm/model_executor/layers/mamba/gdn_linear_attn.py @tdoublep @ZJY0516 @vadiklyutiy
|
/vllm/model_executor/layers/mamba/gdn/qwen_gdn_linear_attn.py @tdoublep @ZJY0516 @vadiklyutiy
|
||||||
/vllm/model_executor/layers/rotary_embedding.py @vadiklyutiy
|
|
||||||
/vllm/model_executor/model_loader @22quinn
|
/vllm/model_executor/model_loader @22quinn
|
||||||
/vllm/model_executor/layers/batch_invariant.py @yewentao256
|
/vllm/model_executor/layers/batch_invariant.py @yewentao256
|
||||||
/vllm/ir @ProExpertProg
|
/vllm/ir @ProExpertProg
|
||||||
@@ -120,16 +119,6 @@
|
|||||||
/vllm/model_executor/models/transformers @hmellor
|
/vllm/model_executor/models/transformers @hmellor
|
||||||
/tests/models/test_transformers.py @hmellor
|
/tests/models/test_transformers.py @hmellor
|
||||||
|
|
||||||
# Observability
|
|
||||||
/vllm/config/observability.py @markmc
|
|
||||||
/vllm/v1/metrics @markmc
|
|
||||||
/tests/v1/metrics @markmc
|
|
||||||
/vllm/tracing.py @markmc
|
|
||||||
/tests/v1/tracing/test_tracing.py @markmc
|
|
||||||
/vllm/config/kv_events.py @markmc
|
|
||||||
/vllm/distributed/kv_events.py @markmc
|
|
||||||
/tests/distributed/test_events.py @markmc
|
|
||||||
|
|
||||||
# Docs
|
# Docs
|
||||||
/docs/mkdocs @hmellor
|
/docs/mkdocs @hmellor
|
||||||
/docs/**/*.yml @hmellor
|
/docs/**/*.yml @hmellor
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Custom self-hosted runner labels (e.g. the autoscaling vllm-runners pool) so
|
||||||
|
# actionlint doesn't flag them as unknown in `runs-on`.
|
||||||
|
self-hosted-runner:
|
||||||
|
labels:
|
||||||
|
- vllm-runners
|
||||||
@@ -388,9 +388,13 @@ pull_request_rules:
|
|||||||
- or:
|
- or:
|
||||||
- files~=^tests/tool_use/
|
- files~=^tests/tool_use/
|
||||||
- files~=^tests/tool_parsers/
|
- files~=^tests/tool_parsers/
|
||||||
|
- files~=^tests/parser/
|
||||||
|
- files~=^tests/reasoning/
|
||||||
- files~=^tests/entrypoints/openai/.*tool.*
|
- files~=^tests/entrypoints/openai/.*tool.*
|
||||||
- files~=^tests/entrypoints/anthropic/.*tool.*
|
- files~=^tests/entrypoints/anthropic/.*tool.*
|
||||||
- files~=^vllm/tool_parsers/
|
- files~=^vllm/tool_parsers/
|
||||||
|
- files~=^vllm/parser/
|
||||||
|
- files~=^vllm/reasoning/
|
||||||
- files=docs/features/tool_calling.md
|
- files=docs/features/tool_calling.md
|
||||||
- files~=^examples/tool_calling/
|
- files~=^examples/tool_calling/
|
||||||
actions:
|
actions:
|
||||||
|
|||||||
@@ -46,12 +46,16 @@ jobs:
|
|||||||
pre-commit:
|
pre-commit:
|
||||||
needs: pre-run-check
|
needs: pre-run-check
|
||||||
if: always() && (needs.pre-run-check.result == 'success' || needs.pre-run-check.result == 'skipped')
|
if: always() && (needs.pre-run-check.result == 'success' || needs.pre-run-check.result == 'skipped')
|
||||||
runs-on: ubuntu-latest
|
runs-on: [self-hosted, linux, x64, vllm-runners]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
# Provide shellcheck on PATH so tools/pre_commit/shellcheck.sh skips its
|
||||||
|
# wget + tar -xJ self-download, which the self-hosted runner image lacks
|
||||||
|
# (no wget/xz). Pinned to shellcheck 0.10.0 to match the script's "stable".
|
||||||
|
- run: python -m pip install shellcheck-py==0.10.0.1
|
||||||
- run: echo "::add-matcher::.github/workflows/matchers/actionlint.json"
|
- run: echo "::add-matcher::.github/workflows/matchers/actionlint.json"
|
||||||
- run: echo "::add-matcher::.github/workflows/matchers/markdownlint.json"
|
- run: echo "::add-matcher::.github/workflows/matchers/markdownlint.json"
|
||||||
- run: echo "::add-matcher::.github/workflows/matchers/mypy.json"
|
- run: echo "::add-matcher::.github/workflows/matchers/mypy.json"
|
||||||
|
|||||||
+3
-1
@@ -199,7 +199,9 @@ cython_debug/
|
|||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
# Claude
|
# Claude
|
||||||
.claude/
|
.claude/*
|
||||||
|
!.claude/skills/
|
||||||
|
!.claude/skills/**
|
||||||
|
|
||||||
# Codex
|
# Codex
|
||||||
.codex/
|
.codex/
|
||||||
|
|||||||
@@ -114,17 +114,6 @@ Follow these rules for all code changes in this repository:
|
|||||||
- Keep comments and docstrings minimal and concise.
|
- Keep comments and docstrings minimal and concise.
|
||||||
- Assume the reader is familiar with vLLM.
|
- Assume the reader is familiar with vLLM.
|
||||||
|
|
||||||
### Diagnosing CI failures
|
|
||||||
|
|
||||||
Buildkite logs are public; no login needed. Details: [docs/contributing/ci/failures.md](docs/contributing/ci/failures.md).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# All failed-job logs for a PR's latest build (current branch's PR if omitted):
|
|
||||||
.buildkite/scripts/ci-fetch-log.sh --pr <PR>
|
|
||||||
# Any Buildkite build or job URL also works:
|
|
||||||
.buildkite/scripts/ci-fetch-log.sh "<buildkite_url>"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Commit messages
|
### Commit messages
|
||||||
|
|
||||||
Add attribution using commit trailers such as `Co-authored-by:` (other projects use `Assisted-by:` or `Generated-by:`). For example:
|
Add attribution using commit trailers such as `Co-authored-by:` (other projects use `Assisted-by:` or `Generated-by:`). For example:
|
||||||
@@ -146,6 +135,12 @@ Do not modify code in these areas without first reading and following the
|
|||||||
linked guide. If the guide conflicts with the requested change, **refuse the
|
linked guide. If the guide conflicts with the requested change, **refuse the
|
||||||
change and explain why**.
|
change and explain why**.
|
||||||
|
|
||||||
|
Security reviewers should start with [`SECURITY.md`](SECURITY.md),
|
||||||
|
[`docs/usage/security.md`](docs/usage/security.md), and
|
||||||
|
[`docs/contributing/vulnerability_management.md`](docs/contributing/vulnerability_management.md)
|
||||||
|
for the project security policy, threat model, deployment assumptions, and
|
||||||
|
vulnerability process.
|
||||||
|
|
||||||
- **Editing these instructions**:
|
- **Editing these instructions**:
|
||||||
[`docs/contributing/editing-agent-instructions.md`](docs/contributing/editing-agent-instructions.md)
|
[`docs/contributing/editing-agent-instructions.md`](docs/contributing/editing-agent-instructions.md)
|
||||||
— Rules for modifying AGENTS.md or any domain-specific guide it references.
|
— Rules for modifying AGENTS.md or any domain-specific guide it references.
|
||||||
|
|||||||
+56
-101
@@ -319,111 +319,35 @@ if(VLLM_GPU_LANG STREQUAL "CUDA" OR VLLM_GPU_LANG STREQUAL "HIP")
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
# _C extension
|
# Legacy _C extension (ROCm only — CUDA ops migrated to _C_stable_libtorch)
|
||||||
#
|
#
|
||||||
|
|
||||||
set(VLLM_EXT_SRC
|
if(VLLM_GPU_LANG STREQUAL "HIP")
|
||||||
"csrc/quantization/activation_kernels.cu"
|
set(VLLM_EXT_SRC
|
||||||
"csrc/torch_bindings.cpp")
|
"csrc/torch_bindings.cpp"
|
||||||
|
|
||||||
if(VLLM_GPU_LANG STREQUAL "CUDA")
|
|
||||||
SET(CUTLASS_ENABLE_HEADERS_ONLY ON CACHE BOOL "Enable only the header library")
|
|
||||||
|
|
||||||
# Set CUTLASS_REVISION. Used for FetchContent. Also fixes some bogus messages when building.
|
|
||||||
set(CUTLASS_REVISION "v4.4.2")
|
|
||||||
|
|
||||||
# Use the specified CUTLASS source directory for compilation if VLLM_CUTLASS_SRC_DIR is provided
|
|
||||||
if (DEFINED ENV{VLLM_CUTLASS_SRC_DIR})
|
|
||||||
set(VLLM_CUTLASS_SRC_DIR $ENV{VLLM_CUTLASS_SRC_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(VLLM_CUTLASS_SRC_DIR)
|
|
||||||
if(NOT IS_ABSOLUTE VLLM_CUTLASS_SRC_DIR)
|
|
||||||
get_filename_component(VLLM_CUTLASS_SRC_DIR "${VLLM_CUTLASS_SRC_DIR}" ABSOLUTE)
|
|
||||||
endif()
|
|
||||||
message(STATUS "The VLLM_CUTLASS_SRC_DIR is set, using ${VLLM_CUTLASS_SRC_DIR} for compilation")
|
|
||||||
FetchContent_Declare(cutlass SOURCE_DIR ${VLLM_CUTLASS_SRC_DIR})
|
|
||||||
else()
|
|
||||||
FetchContent_Declare(
|
|
||||||
cutlass
|
|
||||||
GIT_REPOSITORY https://github.com/nvidia/cutlass.git
|
|
||||||
# Please keep this in sync with CUTLASS_REVISION line above.
|
|
||||||
GIT_TAG ${CUTLASS_REVISION}
|
|
||||||
GIT_PROGRESS TRUE
|
|
||||||
|
|
||||||
# Speed up CUTLASS download by retrieving only the specified GIT_TAG instead of the history.
|
|
||||||
# Important: If GIT_SHALLOW is enabled then GIT_TAG works only with branch names and tags.
|
|
||||||
# So if the GIT_TAG above is updated to a commit hash, GIT_SHALLOW must be set to FALSE
|
|
||||||
GIT_SHALLOW TRUE
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
FetchContent_MakeAvailable(cutlass)
|
|
||||||
|
|
||||||
set_gencode_flags_for_srcs(
|
|
||||||
SRCS "${VLLM_EXT_SRC}"
|
|
||||||
CUDA_ARCHS "${CUDA_ARCHS}")
|
|
||||||
|
|
||||||
# Expert-specialization MXFP8 blockscaled grouped kernels (SM100+).
|
|
||||||
if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 13.0)
|
|
||||||
cuda_archs_loose_intersection(ES_MXFP8_GROUPED_MM_ARCHS "10.0f;11.0f" "${CUDA_ARCHS}")
|
|
||||||
else()
|
|
||||||
cuda_archs_loose_intersection(ES_MXFP8_GROUPED_MM_ARCHS "10.0a;10.1a;10.3a" "${CUDA_ARCHS}")
|
|
||||||
endif()
|
|
||||||
if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 12.8 AND ES_MXFP8_GROUPED_MM_ARCHS)
|
|
||||||
set(ES_MXFP8_GROUPED_MM_SRCS
|
|
||||||
"csrc/libtorch_stable/moe/mxfp8_moe/cutlass_mxfp8_grouped_mm.cu"
|
|
||||||
"csrc/libtorch_stable/moe/mxfp8_moe/mxfp8_experts_quant.cu")
|
|
||||||
set_gencode_flags_for_srcs(
|
|
||||||
SRCS "${ES_MXFP8_GROUPED_MM_SRCS}"
|
|
||||||
CUDA_ARCHS "${ES_MXFP8_GROUPED_MM_ARCHS}")
|
|
||||||
list(APPEND VLLM_STABLE_EXT_SRC "${ES_MXFP8_GROUPED_MM_SRCS}")
|
|
||||||
list(APPEND VLLM_GPU_FLAGS "-DENABLE_ES_MXFP8_GROUPED_MM_SM100=1")
|
|
||||||
message(STATUS "Building ES MXFP8 grouped kernels for archs: ${ES_MXFP8_GROUPED_MM_ARCHS}")
|
|
||||||
else()
|
|
||||||
if (NOT ${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 12.8
|
|
||||||
AND ES_MXFP8_GROUPED_MM_ARCHS)
|
|
||||||
message(STATUS "Not building ES MXFP8 grouped kernels as CUDA Compiler version is "
|
|
||||||
"not >= 12.8.")
|
|
||||||
else()
|
|
||||||
message(STATUS "Not building ES MXFP8 grouped kernels as no compatible archs found "
|
|
||||||
"in CUDA target architectures.")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# if CUDA endif
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (VLLM_GPU_LANG STREQUAL "HIP")
|
|
||||||
# Add QuickReduce kernels (ROCm-only; not part of stable ABI migration).
|
|
||||||
# TODO: Remove the cuda_view when ROCm upgrade to torch 2.11.
|
|
||||||
list(APPEND VLLM_EXT_SRC
|
|
||||||
"csrc/custom_quickreduce.cu"
|
"csrc/custom_quickreduce.cu"
|
||||||
"csrc/cuda_view.cu"
|
"csrc/cuda_view.cu"
|
||||||
"csrc/libtorch_stable/cuda_utils_kernels.cu"
|
"csrc/libtorch_stable/cuda_utils_kernels.cu")
|
||||||
)
|
|
||||||
# if ROCM endif
|
|
||||||
endif()
|
|
||||||
|
|
||||||
message(STATUS "Enabling C extension.")
|
message(STATUS "Enabling C extension.")
|
||||||
define_extension_target(
|
define_extension_target(
|
||||||
_C
|
_C
|
||||||
DESTINATION vllm
|
DESTINATION vllm
|
||||||
LANGUAGE ${VLLM_GPU_LANG}
|
LANGUAGE ${VLLM_GPU_LANG}
|
||||||
SOURCES ${VLLM_EXT_SRC}
|
SOURCES ${VLLM_EXT_SRC}
|
||||||
COMPILE_FLAGS ${VLLM_GPU_FLAGS}
|
COMPILE_FLAGS ${VLLM_GPU_FLAGS}
|
||||||
ARCHITECTURES ${VLLM_GPU_ARCHES}
|
ARCHITECTURES ${VLLM_GPU_ARCHES}
|
||||||
INCLUDE_DIRECTORIES ${CUTLASS_INCLUDE_DIR}
|
INCLUDE_DIRECTORIES ${CUTLASS_INCLUDE_DIR}
|
||||||
INCLUDE_DIRECTORIES ${CUTLASS_TOOLS_UTIL_INCLUDE_DIR}
|
INCLUDE_DIRECTORIES ${CUTLASS_TOOLS_UTIL_INCLUDE_DIR}
|
||||||
USE_SABI 3
|
USE_SABI 3
|
||||||
WITH_SOABI)
|
WITH_SOABI)
|
||||||
|
|
||||||
# If CUTLASS is compiled on NVCC >= 12.5, it by default uses
|
# If CUTLASS is compiled on NVCC >= 12.5, it by default uses
|
||||||
# cudaGetDriverEntryPointByVersion as a wrapper to avoid directly calling the
|
# cudaGetDriverEntryPointByVersion as a wrapper to avoid directly calling the
|
||||||
# driver API. This causes problems when linking with earlier versions of CUDA.
|
# driver API. This causes problems when linking with earlier versions of CUDA.
|
||||||
# Setting this variable sidesteps the issue by calling the driver directly.
|
# Setting this variable sidesteps the issue by calling the driver directly.
|
||||||
target_compile_definitions(_C PRIVATE CUTLASS_ENABLE_DIRECT_CUDA_DRIVER_CALL=1)
|
target_compile_definitions(_C PRIVATE CUTLASS_ENABLE_DIRECT_CUDA_DRIVER_CALL=1)
|
||||||
|
endif() # _C HIP endif
|
||||||
|
|
||||||
if(VLLM_GPU_LANG STREQUAL "CUDA" OR VLLM_GPU_LANG STREQUAL "HIP")
|
if(VLLM_GPU_LANG STREQUAL "CUDA" OR VLLM_GPU_LANG STREQUAL "HIP")
|
||||||
#
|
#
|
||||||
@@ -432,6 +356,7 @@ if(VLLM_GPU_LANG STREQUAL "CUDA" OR VLLM_GPU_LANG STREQUAL "HIP")
|
|||||||
set(VLLM_STABLE_EXT_SRC
|
set(VLLM_STABLE_EXT_SRC
|
||||||
"csrc/libtorch_stable/torch_bindings.cpp"
|
"csrc/libtorch_stable/torch_bindings.cpp"
|
||||||
"csrc/libtorch_stable/activation_kernels.cu"
|
"csrc/libtorch_stable/activation_kernels.cu"
|
||||||
|
"csrc/libtorch_stable/quantization/activation_kernels.cu"
|
||||||
"csrc/libtorch_stable/quantization/w8a8/int8/scaled_quant.cu"
|
"csrc/libtorch_stable/quantization/w8a8/int8/scaled_quant.cu"
|
||||||
"csrc/libtorch_stable/quantization/w8a8/fp8/common.cu"
|
"csrc/libtorch_stable/quantization/w8a8/fp8/common.cu"
|
||||||
"csrc/libtorch_stable/quantization/w8a8/fp8/per_token_group_quant.cu"
|
"csrc/libtorch_stable/quantization/w8a8/fp8/per_token_group_quant.cu"
|
||||||
@@ -458,6 +383,38 @@ if(VLLM_GPU_LANG STREQUAL "CUDA" OR VLLM_GPU_LANG STREQUAL "HIP")
|
|||||||
"csrc/libtorch_stable/fused_deepseek_v4_qnorm_rope_kv_insert_kernel.cu")
|
"csrc/libtorch_stable/fused_deepseek_v4_qnorm_rope_kv_insert_kernel.cu")
|
||||||
|
|
||||||
if(VLLM_GPU_LANG STREQUAL "CUDA")
|
if(VLLM_GPU_LANG STREQUAL "CUDA")
|
||||||
|
SET(CUTLASS_ENABLE_HEADERS_ONLY ON CACHE BOOL "Enable only the header library")
|
||||||
|
|
||||||
|
# Set CUTLASS_REVISION. Used for FetchContent. Also fixes some bogus messages when building.
|
||||||
|
set(CUTLASS_REVISION "v4.4.2")
|
||||||
|
|
||||||
|
# Use the specified CUTLASS source directory for compilation if VLLM_CUTLASS_SRC_DIR is provided
|
||||||
|
if (DEFINED ENV{VLLM_CUTLASS_SRC_DIR})
|
||||||
|
set(VLLM_CUTLASS_SRC_DIR $ENV{VLLM_CUTLASS_SRC_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(VLLM_CUTLASS_SRC_DIR)
|
||||||
|
if(NOT IS_ABSOLUTE VLLM_CUTLASS_SRC_DIR)
|
||||||
|
get_filename_component(VLLM_CUTLASS_SRC_DIR "${VLLM_CUTLASS_SRC_DIR}" ABSOLUTE)
|
||||||
|
endif()
|
||||||
|
message(STATUS "The VLLM_CUTLASS_SRC_DIR is set, using ${VLLM_CUTLASS_SRC_DIR} for compilation")
|
||||||
|
FetchContent_Declare(cutlass SOURCE_DIR ${VLLM_CUTLASS_SRC_DIR})
|
||||||
|
else()
|
||||||
|
FetchContent_Declare(
|
||||||
|
cutlass
|
||||||
|
GIT_REPOSITORY https://github.com/nvidia/cutlass.git
|
||||||
|
# Please keep this in sync with CUTLASS_REVISION line above.
|
||||||
|
GIT_TAG ${CUTLASS_REVISION}
|
||||||
|
GIT_PROGRESS TRUE
|
||||||
|
|
||||||
|
# Speed up CUTLASS download by retrieving only the specified GIT_TAG instead of the history.
|
||||||
|
# Important: If GIT_SHALLOW is enabled then GIT_TAG works only with branch names and tags.
|
||||||
|
# So if the GIT_TAG above is updated to a commit hash, GIT_SHALLOW must be set to FALSE
|
||||||
|
GIT_SHALLOW TRUE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
FetchContent_MakeAvailable(cutlass)
|
||||||
|
|
||||||
list(APPEND VLLM_STABLE_EXT_SRC
|
list(APPEND VLLM_STABLE_EXT_SRC
|
||||||
"csrc/libtorch_stable/cuda_view.cu"
|
"csrc/libtorch_stable/cuda_view.cu"
|
||||||
"csrc/libtorch_stable/cuda_utils_kernels.cu"
|
"csrc/libtorch_stable/cuda_utils_kernels.cu"
|
||||||
@@ -958,7 +915,6 @@ if(VLLM_GPU_LANG STREQUAL "CUDA" OR VLLM_GPU_LANG STREQUAL "HIP")
|
|||||||
SRCS "${FP4_SM120_SRCS}"
|
SRCS "${FP4_SM120_SRCS}"
|
||||||
CUDA_ARCHS "${FP4_SM120_ARCHS}")
|
CUDA_ARCHS "${FP4_SM120_ARCHS}")
|
||||||
list(APPEND VLLM_STABLE_EXT_SRC "${FP4_SM120_SRCS}")
|
list(APPEND VLLM_STABLE_EXT_SRC "${FP4_SM120_SRCS}")
|
||||||
target_compile_definitions(_C PRIVATE ENABLE_NVFP4_SM120=1)
|
|
||||||
list(APPEND VLLM_GPU_FLAGS "-DENABLE_NVFP4_SM120=1")
|
list(APPEND VLLM_GPU_FLAGS "-DENABLE_NVFP4_SM120=1")
|
||||||
list(APPEND VLLM_GPU_FLAGS "-DENABLE_CUTLASS_MOE_SM120=1")
|
list(APPEND VLLM_GPU_FLAGS "-DENABLE_CUTLASS_MOE_SM120=1")
|
||||||
message(STATUS "Building SM12x NVFP4 for archs: ${FP4_SM120_ARCHS}")
|
message(STATUS "Building SM12x NVFP4 for archs: ${FP4_SM120_ARCHS}")
|
||||||
@@ -991,7 +947,6 @@ if(VLLM_GPU_LANG STREQUAL "CUDA" OR VLLM_GPU_LANG STREQUAL "HIP")
|
|||||||
SRCS "${FP4_SM100_SRCS}"
|
SRCS "${FP4_SM100_SRCS}"
|
||||||
CUDA_ARCHS "${FP4_SM100_ARCHS}")
|
CUDA_ARCHS "${FP4_SM100_ARCHS}")
|
||||||
list(APPEND VLLM_STABLE_EXT_SRC "${FP4_SM100_SRCS}")
|
list(APPEND VLLM_STABLE_EXT_SRC "${FP4_SM100_SRCS}")
|
||||||
target_compile_definitions(_C PRIVATE ENABLE_NVFP4_SM100=1)
|
|
||||||
list(APPEND VLLM_GPU_FLAGS "-DENABLE_NVFP4_SM100=1")
|
list(APPEND VLLM_GPU_FLAGS "-DENABLE_NVFP4_SM100=1")
|
||||||
list(APPEND VLLM_GPU_FLAGS "-DENABLE_CUTLASS_MOE_SM100=1")
|
list(APPEND VLLM_GPU_FLAGS "-DENABLE_CUTLASS_MOE_SM100=1")
|
||||||
message(STATUS "Building SM10x/11x NVFP4/MXFP4 for archs: ${FP4_SM100_ARCHS}")
|
message(STATUS "Building SM10x/11x NVFP4/MXFP4 for archs: ${FP4_SM100_ARCHS}")
|
||||||
|
|||||||
@@ -53,6 +53,16 @@ from common import (
|
|||||||
from vllm.v1.worker.workspace import init_workspace_manager
|
from vllm.v1.worker.workspace import init_workspace_manager
|
||||||
|
|
||||||
|
|
||||||
|
def _str2bool(v) -> bool:
|
||||||
|
if isinstance(v, bool):
|
||||||
|
return v
|
||||||
|
if v.lower() in ("true", "1", "yes", "t"):
|
||||||
|
return True
|
||||||
|
if v.lower() in ("false", "0", "no", "f"):
|
||||||
|
return False
|
||||||
|
raise argparse.ArgumentTypeError(f"expected a boolean, got {v!r}")
|
||||||
|
|
||||||
|
|
||||||
def run_standard_attention_benchmark(config: BenchmarkConfig) -> BenchmarkResult:
|
def run_standard_attention_benchmark(config: BenchmarkConfig) -> BenchmarkResult:
|
||||||
"""Run standard attention benchmark (Flash/Triton/FlashInfer)."""
|
"""Run standard attention benchmark (Flash/Triton/FlashInfer)."""
|
||||||
from runner import run_attention_benchmark
|
from runner import run_attention_benchmark
|
||||||
@@ -485,6 +495,20 @@ def main():
|
|||||||
help="Prefill backends to compare (fa2, fa3, fa4). "
|
help="Prefill backends to compare (fa2, fa3, fa4). "
|
||||||
"Uses the first decode backend for impl construction.",
|
"Uses the first decode backend for impl construction.",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--fp8-output-scale",
|
||||||
|
type=float,
|
||||||
|
help="Static per-tensor scale enabling the MLA prefill FP8-output "
|
||||||
|
"comparison on FA4 (fused write vs standalone post-quant).",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--fuse-quant-op",
|
||||||
|
nargs="+",
|
||||||
|
type=_str2bool,
|
||||||
|
help="FP8-output write path(s) to run: false = bf16 attention + "
|
||||||
|
"standalone static-FP8 quant, true = FA4 writes FP8 directly. "
|
||||||
|
"Default: both.",
|
||||||
|
)
|
||||||
|
|
||||||
# Batch specifications
|
# Batch specifications
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@@ -618,6 +642,12 @@ def main():
|
|||||||
# Prefill backends (e.g., ["fa3", "fa4"])
|
# Prefill backends (e.g., ["fa3", "fa4"])
|
||||||
args.prefill_backends = yaml_config.get("prefill_backends", None)
|
args.prefill_backends = yaml_config.get("prefill_backends", None)
|
||||||
|
|
||||||
|
# FP8 output benchmark knobs; CLI wins.
|
||||||
|
if args.fp8_output_scale is None:
|
||||||
|
args.fp8_output_scale = yaml_config.get("fp8_output_scale", None)
|
||||||
|
if args.fuse_quant_op is None:
|
||||||
|
args.fuse_quant_op = yaml_config.get("fuse_quant_op", None)
|
||||||
|
|
||||||
# Check for special modes
|
# Check for special modes
|
||||||
args.mode = yaml_config.get("mode", None)
|
args.mode = yaml_config.get("mode", None)
|
||||||
|
|
||||||
@@ -787,8 +817,59 @@ def main():
|
|||||||
"skipped (timings are placeholder zeros).[/]"
|
"skipped (timings are placeholder zeros).[/]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# FA4 fused FP8 output vs standalone post-quant, on the same fa4 kernel:
|
||||||
|
# the delta is the post-quant kernel the fused path removes.
|
||||||
|
fp8_output_scale = getattr(args, "fp8_output_scale", None)
|
||||||
|
if fp8_output_scale is not None:
|
||||||
|
decode_backend = backends[0]
|
||||||
|
fuse_variants = args.fuse_quant_op or [False, True]
|
||||||
|
label_of = {False: "post_quant", True: "fused"}
|
||||||
|
console.print(
|
||||||
|
f"[yellow]FP8 output comparison @ scale={fp8_output_scale} "
|
||||||
|
f"(prefill=fa4, decode impl={decode_backend})[/]"
|
||||||
|
)
|
||||||
|
fp8_results = []
|
||||||
|
total = len(fuse_variants) * len(args.batch_specs)
|
||||||
|
with tqdm(total=total, desc="FP8 output benchmarking") as pbar:
|
||||||
|
for spec in args.batch_specs:
|
||||||
|
for fuse in fuse_variants:
|
||||||
|
config = BenchmarkConfig(
|
||||||
|
backend=decode_backend,
|
||||||
|
batch_spec=spec,
|
||||||
|
num_layers=args.num_layers,
|
||||||
|
head_dim=args.head_dim,
|
||||||
|
num_q_heads=args.num_q_heads,
|
||||||
|
num_kv_heads=args.num_kv_heads,
|
||||||
|
block_size=args.block_size,
|
||||||
|
device=args.device,
|
||||||
|
repeats=args.repeats,
|
||||||
|
warmup_iters=args.warmup_iters,
|
||||||
|
profile_memory=args.profile_memory,
|
||||||
|
kv_cache_dtype=args.kv_cache_dtype,
|
||||||
|
use_cuda_graphs=args.cuda_graphs,
|
||||||
|
prefill_backend="fa4",
|
||||||
|
)
|
||||||
|
result = run_benchmark(
|
||||||
|
config, output_scale=fp8_output_scale, fuse_quant_op=fuse
|
||||||
|
)
|
||||||
|
label = label_of[fuse]
|
||||||
|
labeled_config = replace(result.config, backend=label)
|
||||||
|
result = replace(result, config=labeled_config)
|
||||||
|
fp8_results.append(result)
|
||||||
|
|
||||||
|
if not result.success:
|
||||||
|
console.print(f"[red]Error {label} {spec}: {result.error}[/]")
|
||||||
|
|
||||||
|
pbar.update(1)
|
||||||
|
|
||||||
|
console.print("\n[bold green]FP8 Output Results:[/]")
|
||||||
|
formatter = ResultsFormatter(console)
|
||||||
|
labels = [label_of[f] for f in fuse_variants]
|
||||||
|
formatter.print_table(fp8_results, labels, compare_to_fastest=True)
|
||||||
|
all_results = fp8_results
|
||||||
|
|
||||||
# Handle special mode: decode_vs_prefill comparison
|
# Handle special mode: decode_vs_prefill comparison
|
||||||
if hasattr(args, "mode") and args.mode == "decode_vs_prefill":
|
elif hasattr(args, "mode") and args.mode == "decode_vs_prefill":
|
||||||
console.print("[yellow]Mode: Decode vs Prefill pipeline comparison[/]")
|
console.print("[yellow]Mode: Decode vs Prefill pipeline comparison[/]")
|
||||||
console.print(
|
console.print(
|
||||||
"[dim]For each query length, testing both decode and prefill pipelines[/]"
|
"[dim]For each query length, testing both decode and prefill pipelines[/]"
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# MLA prefill FP8-output microbenchmark (FA4).
|
||||||
|
# Compares the fused FP8 write against bf16 attention + a standalone static-FP8
|
||||||
|
# quant; the delta is the post-quant kernel the fused path removes.
|
||||||
|
# DeepSeek-Coder-V2-Lite dims; FA4 needs SM100/110.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# python benchmark.py --config configs/mla_fa4_fp8_output.yaml
|
||||||
|
|
||||||
|
description: "MLA prefill FA4 fused-FP8 output vs post-quant"
|
||||||
|
|
||||||
|
model:
|
||||||
|
name: "deepseek-v2-lite"
|
||||||
|
num_layers: 27
|
||||||
|
num_q_heads: 16
|
||||||
|
num_kv_heads: 1
|
||||||
|
head_dim: 576
|
||||||
|
kv_lora_rank: 512
|
||||||
|
qk_nope_head_dim: 128
|
||||||
|
qk_rope_head_dim: 64
|
||||||
|
v_head_dim: 128
|
||||||
|
block_size: 128
|
||||||
|
|
||||||
|
# Pure prefill (q_len == kv_len) so every token goes through forward_mha.
|
||||||
|
batch_specs:
|
||||||
|
- "q512"
|
||||||
|
- "q1k"
|
||||||
|
- "q2k"
|
||||||
|
- "q4k"
|
||||||
|
- "q8k"
|
||||||
|
- "2q4k"
|
||||||
|
- "4q4k"
|
||||||
|
- "8q4k"
|
||||||
|
|
||||||
|
# Only used to construct the MLA impl; the pure-prefill specs skip decode.
|
||||||
|
decode_backends:
|
||||||
|
- CUTLASS_MLA
|
||||||
|
|
||||||
|
# Sweep the two FP8 write paths (prefill backend is fixed to fa4).
|
||||||
|
fp8_output_scale: 0.1
|
||||||
|
fuse_quant_op: [false, true]
|
||||||
|
|
||||||
|
device: "cuda:0"
|
||||||
|
repeats: 50
|
||||||
|
warmup_iters: 10
|
||||||
@@ -708,6 +708,8 @@ def _run_single_benchmark(
|
|||||||
device: torch.device,
|
device: torch.device,
|
||||||
indexer=None,
|
indexer=None,
|
||||||
kv_cache_dtype: str | None = None,
|
kv_cache_dtype: str | None = None,
|
||||||
|
output_scale: float | None = None,
|
||||||
|
fuse_quant_op: bool = False,
|
||||||
) -> BenchmarkResult:
|
) -> BenchmarkResult:
|
||||||
"""
|
"""
|
||||||
Run a single benchmark iteration.
|
Run a single benchmark iteration.
|
||||||
@@ -721,6 +723,11 @@ def _run_single_benchmark(
|
|||||||
mla_dims: MLA dimension configuration
|
mla_dims: MLA dimension configuration
|
||||||
device: Target device
|
device: Target device
|
||||||
indexer: Optional MockIndexer for sparse backends
|
indexer: Optional MockIndexer for sparse backends
|
||||||
|
output_scale: Static per-tensor FP8 scale for prefill output. None
|
||||||
|
keeps the plain bf16 output (no quantization).
|
||||||
|
fuse_quant_op: With output_scale set, True lets the prefill kernel write
|
||||||
|
FP8 directly; False runs bf16 attention then a standalone static-FP8
|
||||||
|
quant. The delta isolates the saved post-quant kernel.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BenchmarkResult with timing statistics
|
BenchmarkResult with timing statistics
|
||||||
@@ -824,23 +831,55 @@ def _run_single_benchmark(
|
|||||||
num_prefill, mla_dims, query_fmt, device, torch.bfloat16
|
num_prefill, mla_dims, query_fmt, device, torch.bfloat16
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Prefill FP8 output: fused (kernel writes e4m3) vs separate post-quant.
|
||||||
|
prefill_fp8_output = None
|
||||||
|
prefill_output_scale = None
|
||||||
|
prefill_quant_op = None
|
||||||
|
if has_prefill and output_scale is not None:
|
||||||
|
from vllm.platforms import current_platform
|
||||||
|
|
||||||
|
prefill_output_scale = torch.tensor(
|
||||||
|
[output_scale], device=device, dtype=torch.float32
|
||||||
|
)
|
||||||
|
if fuse_quant_op:
|
||||||
|
prefill_fp8_output = torch.empty_like(
|
||||||
|
prefill_inputs["output"], dtype=current_platform.fp8_dtype()
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
from vllm.model_executor.layers.quantization.input_quant_fp8 import (
|
||||||
|
QuantFP8,
|
||||||
|
)
|
||||||
|
from vllm.model_executor.layers.quantization.utils.quant_utils import (
|
||||||
|
GroupShape,
|
||||||
|
)
|
||||||
|
|
||||||
|
prefill_quant_op = QuantFP8(static=True, group_shape=GroupShape.PER_TENSOR)
|
||||||
|
|
||||||
|
fused_output = output_scale is not None and fuse_quant_op
|
||||||
|
|
||||||
# Build forward function (runs a single decode/prefill pass)
|
# Build forward function (runs a single decode/prefill pass)
|
||||||
def forward_fn():
|
def forward_fn():
|
||||||
results = []
|
results = []
|
||||||
if has_decode:
|
if has_decode:
|
||||||
results.append(impl.forward_mqa(decode_inputs, kv_cache, metadata, layer))
|
results.append(impl.forward_mqa(decode_inputs, kv_cache, metadata, layer))
|
||||||
if has_prefill:
|
if has_prefill:
|
||||||
results.append(
|
out = impl.forward_mha(
|
||||||
impl.forward_mha(
|
prefill_inputs["q"],
|
||||||
prefill_inputs["q"],
|
prefill_inputs["k_c_normed"],
|
||||||
prefill_inputs["k_c_normed"],
|
prefill_inputs["k_pe"],
|
||||||
prefill_inputs["k_pe"],
|
kv_cache,
|
||||||
kv_cache,
|
metadata,
|
||||||
metadata,
|
prefill_inputs["k_scale"],
|
||||||
prefill_inputs["k_scale"],
|
prefill_fp8_output if fused_output else prefill_inputs["output"],
|
||||||
prefill_inputs["output"],
|
prefill_output_scale if fused_output else None,
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
if fused_output:
|
||||||
|
out = prefill_fp8_output
|
||||||
|
elif prefill_quant_op is not None:
|
||||||
|
out, _ = prefill_quant_op(
|
||||||
|
prefill_inputs["output"], prefill_output_scale
|
||||||
|
)
|
||||||
|
results.append(out)
|
||||||
return results[0] if len(results) == 1 else tuple(results)
|
return results[0] if len(results) == 1 else tuple(results)
|
||||||
|
|
||||||
def benchmark_fn():
|
def benchmark_fn():
|
||||||
@@ -881,6 +920,8 @@ def _run_mla_benchmark_batched(
|
|||||||
configs_with_params: list[tuple], # [(config, threshold, num_splits), ...]
|
configs_with_params: list[tuple], # [(config, threshold, num_splits), ...]
|
||||||
index_topk: int = 2048,
|
index_topk: int = 2048,
|
||||||
prefill_backend: str | None = None,
|
prefill_backend: str | None = None,
|
||||||
|
output_scale: float | None = None,
|
||||||
|
fuse_quant_op: bool = False,
|
||||||
) -> list[BenchmarkResult]:
|
) -> list[BenchmarkResult]:
|
||||||
"""
|
"""
|
||||||
Unified batched MLA benchmark runner for all backends.
|
Unified batched MLA benchmark runner for all backends.
|
||||||
@@ -1020,6 +1061,8 @@ def _run_mla_benchmark_batched(
|
|||||||
device,
|
device,
|
||||||
indexer=indexer,
|
indexer=indexer,
|
||||||
kv_cache_dtype=kv_cache_dtype,
|
kv_cache_dtype=kv_cache_dtype,
|
||||||
|
output_scale=output_scale,
|
||||||
|
fuse_quant_op=fuse_quant_op,
|
||||||
)
|
)
|
||||||
results.append(result)
|
results.append(result)
|
||||||
|
|
||||||
@@ -1047,6 +1090,8 @@ def run_mla_benchmark(
|
|||||||
num_kv_splits: int | None = None,
|
num_kv_splits: int | None = None,
|
||||||
index_topk: int = 2048,
|
index_topk: int = 2048,
|
||||||
prefill_backend: str | None = None,
|
prefill_backend: str | None = None,
|
||||||
|
output_scale: float | None = None,
|
||||||
|
fuse_quant_op: bool = False,
|
||||||
) -> BenchmarkResult | list[BenchmarkResult]:
|
) -> BenchmarkResult | list[BenchmarkResult]:
|
||||||
"""
|
"""
|
||||||
Unified MLA benchmark runner for all backends.
|
Unified MLA benchmark runner for all backends.
|
||||||
@@ -1066,6 +1111,9 @@ def run_mla_benchmark(
|
|||||||
index_topk: Topk value for sparse MLA backends (default 2048)
|
index_topk: Topk value for sparse MLA backends (default 2048)
|
||||||
prefill_backend: Prefill backend name (e.g., "fa3", "fa4").
|
prefill_backend: Prefill backend name (e.g., "fa3", "fa4").
|
||||||
When set, forces the specified FlashAttention version for prefill.
|
When set, forces the specified FlashAttention version for prefill.
|
||||||
|
output_scale: Static per-tensor FP8 scale for prefill output (None = bf16).
|
||||||
|
fuse_quant_op: With output_scale set, fuse the FP8 write into the prefill
|
||||||
|
kernel vs a standalone post-quant kernel. See _run_single_benchmark.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BenchmarkResult (single mode) or list of BenchmarkResult (batched mode)
|
BenchmarkResult (single mode) or list of BenchmarkResult (batched mode)
|
||||||
@@ -1090,7 +1138,12 @@ def run_mla_benchmark(
|
|||||||
|
|
||||||
# Use unified batched execution
|
# Use unified batched execution
|
||||||
results = _run_mla_benchmark_batched(
|
results = _run_mla_benchmark_batched(
|
||||||
backend, configs_with_params, index_topk, prefill_backend=prefill_backend
|
backend,
|
||||||
|
configs_with_params,
|
||||||
|
index_topk,
|
||||||
|
prefill_backend=prefill_backend,
|
||||||
|
output_scale=output_scale,
|
||||||
|
fuse_quant_op=fuse_quant_op,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Return single result or list based on input
|
# Return single result or list based on input
|
||||||
|
|||||||
@@ -0,0 +1,358 @@
|
|||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||||
|
"""Benchmark and regression-test pinned (page-locked) CPU memory for vLLM.
|
||||||
|
|
||||||
|
Verifies that enabling pinned memory does not regress throughput or latency
|
||||||
|
compared to unpinned memory. Each condition runs in an isolated ``spawn``
|
||||||
|
subprocess so both start from a cold CUDA context, giving an unbiased
|
||||||
|
comparison.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
Run all tests with the default model::
|
||||||
|
|
||||||
|
python benchmarks/benchmark_pin_memory.py -v
|
||||||
|
|
||||||
|
Override the model and optional max-model-len::
|
||||||
|
|
||||||
|
python benchmarks/benchmark_pin_memory.py --model unsloth/Qwen3-1.7B -v
|
||||||
|
python benchmarks/benchmark_pin_memory.py --model unsloth/Qwen3-1.7B \
|
||||||
|
--max-model-len 8192 -v
|
||||||
|
|
||||||
|
Run only throughput or latency tests::
|
||||||
|
|
||||||
|
python benchmarks/benchmark_pin_memory.py -v -k test_throughput
|
||||||
|
python benchmarks/benchmark_pin_memory.py -v -k test_latency
|
||||||
|
|
||||||
|
Run only the v1 or v2 runner variant::
|
||||||
|
|
||||||
|
python benchmarks/benchmark_pin_memory.py -v -k v1
|
||||||
|
python benchmarks/benchmark_pin_memory.py -v -k v2
|
||||||
|
|
||||||
|
Note: on WSL2, v1 runner tests are skipped because pin memory is not available
|
||||||
|
for the v1 runner without cpu_offload_gb. Run on other platforms to exercise v1.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import multiprocessing
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
# Allow up to 2% degradation. Both benchmark runs start from an identical
|
||||||
|
# cold CUDA context (separate spawn subprocesses), so the measured difference
|
||||||
|
# reflects the genuine pin_memory overhead rather than cold/warm ordering bias.
|
||||||
|
_THROUGHPUT_TOLERANCE = 0.98
|
||||||
|
_THROUGHPUT_NUM_REQUESTS = 200
|
||||||
|
_THROUGHPUT_INPUT_LEN = 128
|
||||||
|
_THROUGHPUT_OUTPUT_LEN = 512
|
||||||
|
_THROUGHPUT_MAX_NUM_SEQS = 128
|
||||||
|
|
||||||
|
# Latency benchmark constants — match latency.py defaults.
|
||||||
|
_LATENCY_TOLERANCE = 1.02 # Allow up to 2% latency regression.
|
||||||
|
_LATENCY_BATCH_SIZE = 64
|
||||||
|
_LATENCY_INPUT_LEN = 32
|
||||||
|
_LATENCY_OUTPUT_LEN = 128
|
||||||
|
_LATENCY_WARMUP_ITERS = 5
|
||||||
|
_LATENCY_BENCH_ITERS = 15
|
||||||
|
|
||||||
|
_DEFAULT_MODEL = "unsloth/Qwen3-1.7B"
|
||||||
|
_DEFAULT_MAX_MODEL_LEN = 16384
|
||||||
|
|
||||||
|
|
||||||
|
def _benchmark_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(add_help=False)
|
||||||
|
parser.add_argument("--model", default=_DEFAULT_MODEL)
|
||||||
|
parser.add_argument("--max-model-len", type=int, default=_DEFAULT_MAX_MODEL_LEN)
|
||||||
|
args, _ = parser.parse_known_args()
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def model() -> str:
|
||||||
|
return _benchmark_args().model
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def max_model_len() -> int:
|
||||||
|
return _benchmark_args().max_model_len
|
||||||
|
|
||||||
|
|
||||||
|
def _skip_if_pin_memory_not_available(engine_args_kwargs: dict) -> None:
|
||||||
|
"""Skip the current pytest test if pin_memory is unavailable for this config."""
|
||||||
|
import vllm.utils.platform_utils as pu
|
||||||
|
from vllm.config import set_current_vllm_config
|
||||||
|
from vllm.engine.arg_utils import EngineArgs
|
||||||
|
|
||||||
|
vllm_config = EngineArgs(**engine_args_kwargs).create_engine_config()
|
||||||
|
with set_current_vllm_config(vllm_config):
|
||||||
|
pu.is_pin_memory_available.cache_clear()
|
||||||
|
if not pu.is_pin_memory_available():
|
||||||
|
import os
|
||||||
|
|
||||||
|
runner = "v2" if os.environ.get("VLLM_USE_V2_MODEL_RUNNER") == "1" else "v1"
|
||||||
|
model = engine_args_kwargs.get("model", "unknown")
|
||||||
|
print(
|
||||||
|
f"\033[33mSKIP: pin_memory not available for "
|
||||||
|
f"{runner} runner, model={model}\033[0m"
|
||||||
|
)
|
||||||
|
pytest.skip("pin_memory not available for this configuration")
|
||||||
|
|
||||||
|
|
||||||
|
def _throughput_worker(
|
||||||
|
pin: bool,
|
||||||
|
engine_args_kwargs: dict,
|
||||||
|
q: "multiprocessing.Queue[float]",
|
||||||
|
v2_mode: bool = False,
|
||||||
|
) -> None:
|
||||||
|
"""Run throughput benchmark in a fresh spawn subprocess.
|
||||||
|
|
||||||
|
Delegates to vllm/benchmarks/throughput.py main() using the random dataset,
|
||||||
|
so the methodology matches the official benchmark. Results are written to a
|
||||||
|
temp JSON file and forwarded through the queue as tokens/s.
|
||||||
|
|
||||||
|
v2_mode: when True, monkeypatches is_uva_available() to always return True
|
||||||
|
so the v2 model runner's UVA buffers remain functional even when pin=False.
|
||||||
|
This isolates the non-UVA pin_memory paths in v2.
|
||||||
|
"""
|
||||||
|
import vllm.utils.platform_utils as pu
|
||||||
|
from vllm.platforms import current_platform
|
||||||
|
|
||||||
|
pu.is_pin_memory_available.cache_clear()
|
||||||
|
pu.is_uva_available.cache_clear()
|
||||||
|
type(current_platform).is_pin_memory_available = classmethod(lambda cls: pin)
|
||||||
|
if v2_mode:
|
||||||
|
pu.is_uva_available = lambda: True
|
||||||
|
|
||||||
|
from vllm.benchmarks.throughput import add_cli_args
|
||||||
|
from vllm.benchmarks.throughput import main as throughput_main
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
add_cli_args(parser)
|
||||||
|
args = parser.parse_args([])
|
||||||
|
|
||||||
|
for key, val in engine_args_kwargs.items():
|
||||||
|
setattr(args, key, val)
|
||||||
|
args.max_num_seqs = _THROUGHPUT_MAX_NUM_SEQS
|
||||||
|
args.dataset_name = "random"
|
||||||
|
args.input_len = _THROUGHPUT_INPUT_LEN
|
||||||
|
args.output_len = _THROUGHPUT_OUTPUT_LEN
|
||||||
|
# Nullify defaults that conflict with explicit input/output_len.
|
||||||
|
args.random_input_len = None
|
||||||
|
args.random_output_len = None
|
||||||
|
args.random_prefix_len = None
|
||||||
|
args.num_prompts = _THROUGHPUT_NUM_REQUESTS
|
||||||
|
args.seed = 0
|
||||||
|
args.disable_detokenize = True
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
|
||||||
|
tmp_path = f.name
|
||||||
|
args.output_json = tmp_path
|
||||||
|
|
||||||
|
throughput_main(args)
|
||||||
|
|
||||||
|
with open(tmp_path) as f:
|
||||||
|
results = json.load(f)
|
||||||
|
q.put(results["tokens_per_second"])
|
||||||
|
|
||||||
|
|
||||||
|
def _run_throughput_benchmark(
|
||||||
|
pin: bool,
|
||||||
|
engine_args_kwargs: dict,
|
||||||
|
v2_mode: bool = False,
|
||||||
|
) -> float:
|
||||||
|
ctx = multiprocessing.get_context("spawn")
|
||||||
|
q = ctx.Queue()
|
||||||
|
p = ctx.Process(
|
||||||
|
target=_throughput_worker,
|
||||||
|
args=(pin, engine_args_kwargs, q, v2_mode),
|
||||||
|
)
|
||||||
|
p.start()
|
||||||
|
p.join()
|
||||||
|
if p.exitcode != 0:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Throughput benchmark subprocess (pin={pin}) exited with code {p.exitcode}"
|
||||||
|
)
|
||||||
|
return q.get()
|
||||||
|
|
||||||
|
|
||||||
|
def _latency_worker(
|
||||||
|
pin: bool,
|
||||||
|
engine_args_kwargs: dict,
|
||||||
|
q: "multiprocessing.Queue[dict]",
|
||||||
|
v2_mode: bool = False,
|
||||||
|
) -> None:
|
||||||
|
"""Run latency benchmark in a fresh spawn subprocess.
|
||||||
|
|
||||||
|
Follows latency.py methodology: fixed batch of dummy token IDs, warmup
|
||||||
|
iterations to reach steady state, then timed iterations reduced to avg
|
||||||
|
and percentiles. Results are written to a temp JSON file by latency_main
|
||||||
|
and forwarded through the queue.
|
||||||
|
"""
|
||||||
|
import vllm.utils.platform_utils as pu
|
||||||
|
from vllm.platforms import current_platform
|
||||||
|
|
||||||
|
pu.is_pin_memory_available.cache_clear()
|
||||||
|
pu.is_uva_available.cache_clear()
|
||||||
|
type(current_platform).is_pin_memory_available = classmethod(lambda cls: pin)
|
||||||
|
if v2_mode:
|
||||||
|
pu.is_uva_available = lambda: True
|
||||||
|
|
||||||
|
from vllm.benchmarks.latency import add_cli_args
|
||||||
|
from vllm.benchmarks.latency import main as latency_main
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
add_cli_args(parser)
|
||||||
|
args = parser.parse_args([])
|
||||||
|
|
||||||
|
for key, val in engine_args_kwargs.items():
|
||||||
|
setattr(args, key, val)
|
||||||
|
args.input_len = _LATENCY_INPUT_LEN
|
||||||
|
args.output_len = _LATENCY_OUTPUT_LEN
|
||||||
|
args.batch_size = _LATENCY_BATCH_SIZE
|
||||||
|
args.num_iters_warmup = _LATENCY_WARMUP_ITERS
|
||||||
|
args.num_iters = _LATENCY_BENCH_ITERS
|
||||||
|
args.profile = False
|
||||||
|
args.disable_detokenize = True
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
|
||||||
|
tmp_path = f.name
|
||||||
|
args.output_json = tmp_path
|
||||||
|
|
||||||
|
latency_main(args)
|
||||||
|
|
||||||
|
with open(tmp_path) as f:
|
||||||
|
results = json.load(f)
|
||||||
|
q.put(results)
|
||||||
|
|
||||||
|
|
||||||
|
def _run_latency_benchmark(
|
||||||
|
pin: bool,
|
||||||
|
engine_args_kwargs: dict,
|
||||||
|
v2_mode: bool = False,
|
||||||
|
) -> dict:
|
||||||
|
ctx = multiprocessing.get_context("spawn")
|
||||||
|
q = ctx.Queue()
|
||||||
|
p = ctx.Process(
|
||||||
|
target=_latency_worker,
|
||||||
|
args=(pin, engine_args_kwargs, q, v2_mode),
|
||||||
|
)
|
||||||
|
p.start()
|
||||||
|
p.join()
|
||||||
|
if p.exitcode != 0:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Latency benchmark subprocess (pin={pin}) exited with code {p.exitcode}"
|
||||||
|
)
|
||||||
|
return q.get()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"test_v2_runner",
|
||||||
|
[
|
||||||
|
pytest.param(False, id="v1"),
|
||||||
|
pytest.param(True, id="v2"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class TestPinnedMemory:
|
||||||
|
"""Verify pinned memory yields >= throughput vs unpinned via real vLLM inference."""
|
||||||
|
|
||||||
|
def test_throughput(self, monkeypatch, test_v2_runner, model, max_model_len):
|
||||||
|
"""Benchmark throughput with pin_memory forced on then off.
|
||||||
|
|
||||||
|
Delegates to vllm/benchmarks/throughput.py main() with the random
|
||||||
|
dataset. Each condition runs in an isolated spawn subprocess so both
|
||||||
|
start from a cold CUDA context, giving an unbiased comparison.
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv("VLLM_ENABLE_V1_MULTIPROCESSING", "0")
|
||||||
|
monkeypatch.setenv("VLLM_USE_V2_MODEL_RUNNER", "1" if test_v2_runner else "0")
|
||||||
|
|
||||||
|
engine_args_kwargs = dict(
|
||||||
|
model=model,
|
||||||
|
gpu_memory_utilization=0.88,
|
||||||
|
max_model_len=max_model_len,
|
||||||
|
enable_prefix_caching=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
_skip_if_pin_memory_not_available(engine_args_kwargs)
|
||||||
|
|
||||||
|
unpinned_tps = _run_throughput_benchmark(
|
||||||
|
False, engine_args_kwargs, v2_mode=test_v2_runner
|
||||||
|
)
|
||||||
|
pinned_tps = _run_throughput_benchmark(
|
||||||
|
True, engine_args_kwargs, v2_mode=test_v2_runner
|
||||||
|
)
|
||||||
|
|
||||||
|
pct_diff = (pinned_tps - unpinned_tps) / unpinned_tps * 100
|
||||||
|
runner = "v2" if test_v2_runner else "v1"
|
||||||
|
print(
|
||||||
|
f"\n=== Throughput results ({runner} runner, {model}) ==="
|
||||||
|
f"\npin_memory=True: {pinned_tps:.1f} tok/s"
|
||||||
|
f"\npin_memory=False: {unpinned_tps:.1f} tok/s"
|
||||||
|
f"\nDifference: {pct_diff:+.1f}% (pinned vs unpinned)"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert pinned_tps >= unpinned_tps * _THROUGHPUT_TOLERANCE, (
|
||||||
|
f"Pinned throughput ({pinned_tps:.1f} tok/s) fell more than "
|
||||||
|
f"{(1.0 - _THROUGHPUT_TOLERANCE) * 100:.1f}% below "
|
||||||
|
f"unpinned ({unpinned_tps:.1f} tok/s)."
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_latency(self, monkeypatch, test_v2_runner, model, max_model_len):
|
||||||
|
"""Benchmark per-batch latency with pin_memory forced on then off.
|
||||||
|
|
||||||
|
Follows vllm/benchmarks/latency.py: fixed dummy-token batch, warmup
|
||||||
|
iterations to reach steady state, then timed iterations reduced to avg
|
||||||
|
and percentiles. Subprocesses run serially so each gets a cold CUDA
|
||||||
|
context without GPU memory pressure from the other run.
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv("VLLM_ENABLE_V1_MULTIPROCESSING", "0")
|
||||||
|
monkeypatch.setenv("VLLM_USE_V2_MODEL_RUNNER", "1" if test_v2_runner else "0")
|
||||||
|
|
||||||
|
engine_args_kwargs = dict(
|
||||||
|
model=model,
|
||||||
|
gpu_memory_utilization=0.88,
|
||||||
|
max_model_len=max_model_len,
|
||||||
|
enable_prefix_caching=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
_skip_if_pin_memory_not_available(engine_args_kwargs)
|
||||||
|
|
||||||
|
unpinned = _run_latency_benchmark(
|
||||||
|
False, engine_args_kwargs, v2_mode=test_v2_runner
|
||||||
|
)
|
||||||
|
pinned = _run_latency_benchmark(
|
||||||
|
True, engine_args_kwargs, v2_mode=test_v2_runner
|
||||||
|
)
|
||||||
|
|
||||||
|
pct_diff = (
|
||||||
|
(pinned["avg_latency"] - unpinned["avg_latency"])
|
||||||
|
/ unpinned["avg_latency"]
|
||||||
|
* 100
|
||||||
|
)
|
||||||
|
runner = "v2" if test_v2_runner else "v1"
|
||||||
|
print(
|
||||||
|
f"\n=== Latency results ({runner} runner, {model}) ==="
|
||||||
|
f"\npin_memory=True: avg={pinned['avg_latency']:.3f}s"
|
||||||
|
f" p50={pinned['percentiles']['50']:.3f}s"
|
||||||
|
f" p99={pinned['percentiles']['99']:.3f}s"
|
||||||
|
f"\npin_memory=False: avg={unpinned['avg_latency']:.3f}s"
|
||||||
|
f" p50={unpinned['percentiles']['50']:.3f}s"
|
||||||
|
f" p99={unpinned['percentiles']['99']:.3f}s"
|
||||||
|
f"\nDifference: {pct_diff:+.1f}% (pinned vs unpinned)"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert pinned["avg_latency"] <= unpinned["avg_latency"] * _LATENCY_TOLERANCE, (
|
||||||
|
f"Pinned avg latency ({pinned['avg_latency']:.3f}s) exceeded "
|
||||||
|
f"unpinned ({unpinned['avg_latency']:.3f}s) by more than "
|
||||||
|
f"{(_LATENCY_TOLERANCE - 1.0) * 100:.1f}%."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
_parser = argparse.ArgumentParser(add_help=False)
|
||||||
|
_parser.add_argument("--model", default=_DEFAULT_MODEL)
|
||||||
|
_parser.add_argument("--max-model-len", type=int, default=_DEFAULT_MAX_MODEL_LEN)
|
||||||
|
_, _remaining = _parser.parse_known_args()
|
||||||
|
sys.exit(pytest.main([__file__] + _remaining))
|
||||||
@@ -32,19 +32,17 @@ message(STATUS "fmha_sm100 is available at ${fmha_sm100_SOURCE_DIR}")
|
|||||||
|
|
||||||
add_custom_target(fmha_sm100)
|
add_custom_target(fmha_sm100)
|
||||||
|
|
||||||
|
set(FMHA_SM100_PY_ROOT "${fmha_sm100_SOURCE_DIR}/python/fmha_sm100")
|
||||||
|
|
||||||
install(FILES
|
install(FILES
|
||||||
"${fmha_sm100_SOURCE_DIR}/python/fmha_sm100/__init__.py"
|
"${FMHA_SM100_PY_ROOT}/__init__.py"
|
||||||
"${fmha_sm100_SOURCE_DIR}/python/fmha_sm100/sparse.py"
|
"${FMHA_SM100_PY_ROOT}/sparse.py"
|
||||||
DESTINATION vllm/third_party/fmha_sm100
|
DESTINATION vllm/third_party/fmha_sm100
|
||||||
COMPONENT fmha_sm100)
|
COMPONENT fmha_sm100)
|
||||||
|
|
||||||
install(DIRECTORY "${fmha_sm100_SOURCE_DIR}/python/fmha_sm100/cute/"
|
install(DIRECTORY "${FMHA_SM100_PY_ROOT}/cute/"
|
||||||
DESTINATION vllm/third_party/fmha_sm100/cute
|
DESTINATION vllm/third_party/fmha_sm100/cute
|
||||||
COMPONENT fmha_sm100
|
COMPONENT fmha_sm100
|
||||||
FILES_MATCHING
|
PATTERN "__pycache__" EXCLUDE
|
||||||
REGEX "/__pycache__(/.*)?$" EXCLUDE
|
PATTERN "*.pyc" EXCLUDE
|
||||||
REGEX ".*\\.pyc$" EXCLUDE
|
PATTERN ".git*" EXCLUDE)
|
||||||
PATTERN "example.py" EXCLUDE
|
|
||||||
PATTERN "test_*.py" EXCLUDE
|
|
||||||
PATTERN "*.py"
|
|
||||||
PATTERN "build_k2q_csr.cu")
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ endif()
|
|||||||
|
|
||||||
if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 12.8 AND QUTLASS_ARCHS)
|
if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 12.8 AND QUTLASS_ARCHS)
|
||||||
set(QUTLASS_SOURCES
|
set(QUTLASS_SOURCES
|
||||||
|
csrc/qutlass_registration.cpp
|
||||||
${qutlass_SOURCE_DIR}/qutlass/csrc/bindings.cpp
|
${qutlass_SOURCE_DIR}/qutlass/csrc/bindings.cpp
|
||||||
${qutlass_SOURCE_DIR}/qutlass/csrc/gemm.cu
|
${qutlass_SOURCE_DIR}/qutlass/csrc/gemm.cu
|
||||||
${qutlass_SOURCE_DIR}/qutlass/csrc/gemm_ada.cu
|
${qutlass_SOURCE_DIR}/qutlass/csrc/gemm_ada.cu
|
||||||
@@ -78,8 +79,19 @@ if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 12.8 AND QUTLASS_ARCHS)
|
|||||||
|
|
||||||
if(CUTLASS_INCLUDE_DIR AND EXISTS "${CUTLASS_INCLUDE_DIR}/cutlass/cutlass.h")
|
if(CUTLASS_INCLUDE_DIR AND EXISTS "${CUTLASS_INCLUDE_DIR}/cutlass/cutlass.h")
|
||||||
list(APPEND QUTLASS_INCLUDES "${CUTLASS_INCLUDE_DIR}")
|
list(APPEND QUTLASS_INCLUDES "${CUTLASS_INCLUDE_DIR}")
|
||||||
|
if(CUTLASS_TOOLS_UTIL_INCLUDE_DIR AND
|
||||||
|
EXISTS "${CUTLASS_TOOLS_UTIL_INCLUDE_DIR}/cutlass/util/packed_stride.hpp")
|
||||||
|
list(APPEND QUTLASS_INCLUDES "${CUTLASS_TOOLS_UTIL_INCLUDE_DIR}")
|
||||||
|
else()
|
||||||
|
get_filename_component(_qutlass_cutlass_root "${CUTLASS_INCLUDE_DIR}" DIRECTORY)
|
||||||
|
if(EXISTS "${_qutlass_cutlass_root}/tools/util/include/cutlass/util/packed_stride.hpp")
|
||||||
|
list(APPEND QUTLASS_INCLUDES "${_qutlass_cutlass_root}/tools/util/include")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
elseif(EXISTS "${qutlass_SOURCE_DIR}/qutlass/third_party/cutlass/include/cutlass/cutlass.h")
|
elseif(EXISTS "${qutlass_SOURCE_DIR}/qutlass/third_party/cutlass/include/cutlass/cutlass.h")
|
||||||
list(APPEND QUTLASS_INCLUDES "${qutlass_SOURCE_DIR}/qutlass/third_party/cutlass/include")
|
list(APPEND QUTLASS_INCLUDES
|
||||||
|
"${qutlass_SOURCE_DIR}/qutlass/third_party/cutlass/include"
|
||||||
|
"${qutlass_SOURCE_DIR}/qutlass/third_party/cutlass/tools/util/include")
|
||||||
message(STATUS "[QUTLASS] Using QuTLASS vendored CUTLASS headers (no vLLM CUTLASS detected).")
|
message(STATUS "[QUTLASS] Using QuTLASS vendored CUTLASS headers (no vLLM CUTLASS detected).")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "[QUTLASS] CUTLASS headers not found. "
|
message(FATAL_ERROR "[QUTLASS] CUTLASS headers not found. "
|
||||||
@@ -91,12 +103,23 @@ if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 12.8 AND QUTLASS_ARCHS)
|
|||||||
CUDA_ARCHS "${QUTLASS_ARCHS}"
|
CUDA_ARCHS "${QUTLASS_ARCHS}"
|
||||||
)
|
)
|
||||||
|
|
||||||
target_sources(_C PRIVATE ${QUTLASS_SOURCES})
|
# QuTLASS uses legacy ATen headers and cannot be built with TORCH_TARGET_VERSION.
|
||||||
target_include_directories(_C PRIVATE ${QUTLASS_INCLUDES})
|
# Keep it as its own extension (registers torch.ops._qutlass_C).
|
||||||
target_compile_definitions(_C PRIVATE
|
define_extension_target(
|
||||||
|
_qutlass_C
|
||||||
|
DESTINATION vllm
|
||||||
|
LANGUAGE ${VLLM_GPU_LANG}
|
||||||
|
SOURCES ${QUTLASS_SOURCES}
|
||||||
|
COMPILE_FLAGS ${VLLM_GPU_FLAGS}
|
||||||
|
ARCHITECTURES ${VLLM_GPU_ARCHES}
|
||||||
|
INCLUDE_DIRECTORIES ${QUTLASS_INCLUDES}
|
||||||
|
USE_SABI 3
|
||||||
|
WITH_SOABI)
|
||||||
|
|
||||||
|
target_compile_definitions(_qutlass_C PRIVATE
|
||||||
QUTLASS_DISABLE_PYBIND=1
|
QUTLASS_DISABLE_PYBIND=1
|
||||||
TARGET_CUDA_ARCH=${QUTLASS_TARGET_CC}
|
TARGET_CUDA_ARCH=${QUTLASS_TARGET_CC}
|
||||||
)
|
CUTLASS_ENABLE_DIRECT_CUDA_DRIVER_CALL=1)
|
||||||
|
|
||||||
set_property(SOURCE ${QUTLASS_SOURCES} APPEND PROPERTY COMPILE_OPTIONS
|
set_property(SOURCE ${QUTLASS_SOURCES} APPEND PROPERTY COMPILE_OPTIONS
|
||||||
$<$<COMPILE_LANGUAGE:CUDA>:--expt-relaxed-constexpr --use_fast_math -O3>
|
$<$<COMPILE_LANGUAGE:CUDA>:--expt-relaxed-constexpr --use_fast_math -O3>
|
||||||
@@ -111,4 +134,5 @@ else()
|
|||||||
"[QUTLASS] Skipping build: no supported arch (12.0f / 10.0f) found in "
|
"[QUTLASS] Skipping build: no supported arch (12.0f / 10.0f) found in "
|
||||||
"CUDA_ARCHS='${CUDA_ARCHS}'.")
|
"CUDA_ARCHS='${CUDA_ARCHS}'.")
|
||||||
endif()
|
endif()
|
||||||
|
add_custom_target(_qutlass_C)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
+25
-25
@@ -11,13 +11,25 @@ static inline cpu_attention::Fp8KVCacheDataType parse_fp8_kv_dtype(
|
|||||||
return cpu_attention::Fp8KVCacheDataType::kAuto;
|
return cpu_attention::Fp8KVCacheDataType::kAuto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cpu_attn_has_isa(const std::string& isa) {
|
||||||
|
if (isa == "rvv") {
|
||||||
|
#if defined(__riscv) && defined(__riscv_v_min_vlen) && __riscv_v_min_vlen == 128
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
torch::Tensor get_scheduler_metadata(
|
torch::Tensor get_scheduler_metadata(
|
||||||
const int64_t num_req, const int64_t num_heads_q,
|
const int64_t num_req, const int64_t num_heads_q,
|
||||||
const int64_t num_heads_kv, const int64_t head_dim,
|
const int64_t num_heads_kv, const int64_t head_dim,
|
||||||
const torch::Tensor& seq_lens, at::ScalarType dtype,
|
const torch::Tensor& seq_lens, at::ScalarType dtype,
|
||||||
const torch::Tensor& query_start_loc, const bool casual,
|
const torch::Tensor& query_start_loc, const bool causal,
|
||||||
const int64_t window_size, const std::string& isa_hint,
|
const int64_t window_size, const std::string& isa_hint,
|
||||||
const bool enable_kv_split) {
|
const bool enable_kv_split,
|
||||||
|
const std::optional<torch::Tensor>& dynamic_causal) {
|
||||||
cpu_attention::ISA isa;
|
cpu_attention::ISA isa;
|
||||||
if (isa_hint == "amx") {
|
if (isa_hint == "amx") {
|
||||||
isa = cpu_attention::ISA::AMX;
|
isa = cpu_attention::ISA::AMX;
|
||||||
@@ -44,24 +56,13 @@ torch::Tensor get_scheduler_metadata(
|
|||||||
input.head_dim = head_dim;
|
input.head_dim = head_dim;
|
||||||
input.query_start_loc = query_start_loc.data_ptr<int32_t>();
|
input.query_start_loc = query_start_loc.data_ptr<int32_t>();
|
||||||
input.seq_lens = seq_lens.data_ptr<int32_t>();
|
input.seq_lens = seq_lens.data_ptr<int32_t>();
|
||||||
if (window_size != -1) {
|
|
||||||
input.left_sliding_window_size = window_size - 1;
|
input.sliding_window_size = window_size;
|
||||||
if (casual) {
|
input.causal = causal;
|
||||||
input.right_sliding_window_size = 0;
|
|
||||||
} else {
|
|
||||||
input.right_sliding_window_size = window_size - 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
input.left_sliding_window_size = -1;
|
|
||||||
if (casual) {
|
|
||||||
input.right_sliding_window_size = 0;
|
|
||||||
} else {
|
|
||||||
input.right_sliding_window_size = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
input.casual = casual;
|
|
||||||
input.isa = isa;
|
input.isa = isa;
|
||||||
input.enable_kv_split = enable_kv_split;
|
input.enable_kv_split = enable_kv_split;
|
||||||
|
input.dynamic_causal =
|
||||||
|
dynamic_causal.has_value() ? dynamic_causal->data_ptr<bool>() : nullptr;
|
||||||
|
|
||||||
VLLM_DISPATCH_FLOATING_TYPES(dtype, "get_scheduler_metadata", [&]() {
|
VLLM_DISPATCH_FLOATING_TYPES(dtype, "get_scheduler_metadata", [&]() {
|
||||||
CPU_ATTN_DISPATCH(head_dim, isa, 0, [&]() {
|
CPU_ATTN_DISPATCH(head_dim, isa, 0, [&]() {
|
||||||
@@ -175,10 +176,11 @@ void cpu_attention_with_kv_cache(
|
|||||||
const torch::Tensor& seq_lens, // [num_tokens]
|
const torch::Tensor& seq_lens, // [num_tokens]
|
||||||
const double scale, const bool causal,
|
const double scale, const bool causal,
|
||||||
const std::optional<torch::Tensor>& alibi_slopes, // [num_heads]
|
const std::optional<torch::Tensor>& alibi_slopes, // [num_heads]
|
||||||
const int64_t sliding_window_left, const int64_t sliding_window_right,
|
const int64_t sliding_window,
|
||||||
const torch::Tensor& block_table, // [num_tokens, max_block_num]
|
const torch::Tensor& block_table, // [num_tokens, max_block_num]
|
||||||
const double softcap, const torch::Tensor& scheduler_metadata,
|
const double softcap, const torch::Tensor& scheduler_metadata,
|
||||||
const std::optional<torch::Tensor>& s_aux, // [num_heads]
|
const std::optional<torch::Tensor>& s_aux, // [num_heads]
|
||||||
|
const std::optional<torch::Tensor>& dynamic_causal, // [num_reqs]
|
||||||
const double k_scale = 1.0, const double v_scale = 1.0,
|
const double k_scale = 1.0, const double v_scale = 1.0,
|
||||||
const std::string& kv_cache_dtype = "auto") {
|
const std::string& kv_cache_dtype = "auto") {
|
||||||
TORCH_CHECK_EQ(query.dim(), 3);
|
TORCH_CHECK_EQ(query.dim(), 3);
|
||||||
@@ -220,13 +222,11 @@ void cpu_attention_with_kv_cache(
|
|||||||
input.alibi_slopes =
|
input.alibi_slopes =
|
||||||
alibi_slopes.has_value() ? alibi_slopes->data_ptr<float>() : nullptr;
|
alibi_slopes.has_value() ? alibi_slopes->data_ptr<float>() : nullptr;
|
||||||
input.s_aux = s_aux.has_value() ? s_aux->data_ptr<c10::BFloat16>() : nullptr;
|
input.s_aux = s_aux.has_value() ? s_aux->data_ptr<c10::BFloat16>() : nullptr;
|
||||||
|
input.dynamic_causal =
|
||||||
|
dynamic_causal.has_value() ? dynamic_causal->data_ptr<bool>() : nullptr;
|
||||||
input.scale = scale;
|
input.scale = scale;
|
||||||
input.causal = causal;
|
input.causal = causal;
|
||||||
input.sliding_window_left = sliding_window_left;
|
input.sliding_window_size = sliding_window;
|
||||||
input.sliding_window_right = sliding_window_right;
|
|
||||||
if (input.causal) {
|
|
||||||
input.sliding_window_right = 0;
|
|
||||||
}
|
|
||||||
input.softcap = static_cast<float>(softcap);
|
input.softcap = static_cast<float>(softcap);
|
||||||
|
|
||||||
if (is_fp8) {
|
if (is_fp8) {
|
||||||
|
|||||||
+62
-27
@@ -388,13 +388,13 @@ class AttentionScheduler {
|
|||||||
int32_t head_dim;
|
int32_t head_dim;
|
||||||
int32_t* query_start_loc;
|
int32_t* query_start_loc;
|
||||||
int32_t* seq_lens;
|
int32_t* seq_lens;
|
||||||
int32_t left_sliding_window_size;
|
int32_t sliding_window_size;
|
||||||
int32_t right_sliding_window_size;
|
bool causal;
|
||||||
bool casual;
|
|
||||||
cpu_attention::ISA isa;
|
cpu_attention::ISA isa;
|
||||||
int32_t max_num_q_per_iter; // max Q head num can be hold in registers
|
int32_t max_num_q_per_iter; // max Q head num can be hold in registers
|
||||||
int32_t kv_block_alignment; // context length alignment requirement
|
int32_t kv_block_alignment; // context length alignment requirement
|
||||||
bool enable_kv_split;
|
bool enable_kv_split;
|
||||||
|
bool* dynamic_causal;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr int32_t MaxQTileIterNum = 128;
|
static constexpr int32_t MaxQTileIterNum = 128;
|
||||||
@@ -403,7 +403,8 @@ class AttentionScheduler {
|
|||||||
: available_cache_size_(cpu_utils::get_available_l2_size()) {}
|
: available_cache_size_(cpu_utils::get_available_l2_size()) {}
|
||||||
|
|
||||||
torch::Tensor schedule(const ScheduleInput& input) const {
|
torch::Tensor schedule(const ScheduleInput& input) const {
|
||||||
const bool casual = input.casual;
|
const bool causal = input.causal;
|
||||||
|
const bool is_dynamic_causal = input.dynamic_causal != nullptr;
|
||||||
const int32_t thread_num = omp_get_max_threads();
|
const int32_t thread_num = omp_get_max_threads();
|
||||||
const int64_t cache_size = cpu_utils::get_available_l2_size();
|
const int64_t cache_size = cpu_utils::get_available_l2_size();
|
||||||
const int32_t max_num_q_per_iter = input.max_num_q_per_iter;
|
const int32_t max_num_q_per_iter = input.max_num_q_per_iter;
|
||||||
@@ -434,8 +435,7 @@ class AttentionScheduler {
|
|||||||
const int32_t default_tile_token_num = default_tile_size / q_head_per_kv;
|
const int32_t default_tile_token_num = default_tile_size / q_head_per_kv;
|
||||||
const int32_t split_kv_q_token_num_threshold =
|
const int32_t split_kv_q_token_num_threshold =
|
||||||
input.enable_kv_split ? 1 : 0;
|
input.enable_kv_split ? 1 : 0;
|
||||||
const int32_t left_sliding_window_size = input.left_sliding_window_size;
|
const int32_t sliding_window_size = input.sliding_window_size;
|
||||||
const int32_t right_sliding_window_size = input.right_sliding_window_size;
|
|
||||||
TORCH_CHECK_LE(split_kv_q_token_num_threshold * q_head_per_kv, 16);
|
TORCH_CHECK_LE(split_kv_q_token_num_threshold * q_head_per_kv, 16);
|
||||||
|
|
||||||
// get total kv len
|
// get total kv len
|
||||||
@@ -444,7 +444,9 @@ class AttentionScheduler {
|
|||||||
const int32_t seq_len = input.seq_lens[req_id];
|
const int32_t seq_len = input.seq_lens[req_id];
|
||||||
const int32_t q_token_num =
|
const int32_t q_token_num =
|
||||||
input.query_start_loc[req_id + 1] - input.query_start_loc[req_id];
|
input.query_start_loc[req_id + 1] - input.query_start_loc[req_id];
|
||||||
const int32_t q_start_pos = (casual ? (seq_len - q_token_num) : 0);
|
const bool req_causal =
|
||||||
|
is_dynamic_causal ? input.dynamic_causal[req_id] : causal;
|
||||||
|
const int32_t q_start_pos = seq_len - q_token_num;
|
||||||
const int32_t kv_start_pos = 0;
|
const int32_t kv_start_pos = 0;
|
||||||
const int32_t kv_end_pos = seq_len;
|
const int32_t kv_end_pos = seq_len;
|
||||||
|
|
||||||
@@ -456,7 +458,7 @@ class AttentionScheduler {
|
|||||||
const int32_t q_tile_pos_right = q_tile_pos_left + q_tile_token_num;
|
const int32_t q_tile_pos_right = q_tile_pos_left + q_tile_token_num;
|
||||||
const auto [kv_tile_pos_left, kv_tile_pos_right] = calcu_kv_tile_pos(
|
const auto [kv_tile_pos_left, kv_tile_pos_right] = calcu_kv_tile_pos(
|
||||||
kv_start_pos, kv_end_pos, q_tile_pos_left, q_tile_pos_right,
|
kv_start_pos, kv_end_pos, q_tile_pos_left, q_tile_pos_right,
|
||||||
left_sliding_window_size, right_sliding_window_size);
|
sliding_window_size, req_causal);
|
||||||
const auto [aligned_kv_tile_pos_left, aligned_kv_tile_pos_right] =
|
const auto [aligned_kv_tile_pos_left, aligned_kv_tile_pos_right] =
|
||||||
align_kv_tile_pos(kv_tile_pos_left, kv_tile_pos_right,
|
align_kv_tile_pos(kv_tile_pos_left, kv_tile_pos_right,
|
||||||
kv_len_alignment);
|
kv_len_alignment);
|
||||||
@@ -484,7 +486,9 @@ class AttentionScheduler {
|
|||||||
const int32_t seq_len = input.seq_lens[req_id];
|
const int32_t seq_len = input.seq_lens[req_id];
|
||||||
const int32_t q_token_num =
|
const int32_t q_token_num =
|
||||||
input.query_start_loc[req_id + 1] - input.query_start_loc[req_id];
|
input.query_start_loc[req_id + 1] - input.query_start_loc[req_id];
|
||||||
const int32_t q_start_pos = (casual ? (seq_len - q_token_num) : 0);
|
const bool req_causal =
|
||||||
|
is_dynamic_causal ? input.dynamic_causal[req_id] : causal;
|
||||||
|
const int32_t q_start_pos = seq_len - q_token_num;
|
||||||
const int32_t kv_start_pos = 0;
|
const int32_t kv_start_pos = 0;
|
||||||
const int32_t kv_end_pos = seq_len;
|
const int32_t kv_end_pos = seq_len;
|
||||||
int32_t local_split_id = 0;
|
int32_t local_split_id = 0;
|
||||||
@@ -498,7 +502,7 @@ class AttentionScheduler {
|
|||||||
const int32_t q_tile_pos_right = q_tile_pos_left + q_tile_token_num;
|
const int32_t q_tile_pos_right = q_tile_pos_left + q_tile_token_num;
|
||||||
const auto [kv_tile_pos_left, kv_tile_pos_right] = calcu_kv_tile_pos(
|
const auto [kv_tile_pos_left, kv_tile_pos_right] = calcu_kv_tile_pos(
|
||||||
kv_start_pos, kv_end_pos, q_tile_pos_left, q_tile_pos_right,
|
kv_start_pos, kv_end_pos, q_tile_pos_left, q_tile_pos_right,
|
||||||
left_sliding_window_size, right_sliding_window_size);
|
sliding_window_size, req_causal);
|
||||||
const auto [aligned_kv_tile_pos_left, aligned_kv_tile_pos_right] =
|
const auto [aligned_kv_tile_pos_left, aligned_kv_tile_pos_right] =
|
||||||
align_kv_tile_pos(kv_tile_pos_left, kv_tile_pos_right,
|
align_kv_tile_pos(kv_tile_pos_left, kv_tile_pos_right,
|
||||||
kv_len_alignment);
|
kv_len_alignment);
|
||||||
@@ -708,15 +712,41 @@ class AttentionScheduler {
|
|||||||
return metadata_tensor;
|
return metadata_tensor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE static std::pair<int32_t, int32_t> calcu_sliding_window_size(
|
||||||
|
int32_t window_size, bool causal) {
|
||||||
|
int32_t left_sliding_window_size, right_sliding_window_size;
|
||||||
|
if (window_size != -1) {
|
||||||
|
left_sliding_window_size = window_size - 1;
|
||||||
|
if (causal) {
|
||||||
|
right_sliding_window_size = 0;
|
||||||
|
} else {
|
||||||
|
right_sliding_window_size = window_size - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
left_sliding_window_size = -1;
|
||||||
|
if (causal) {
|
||||||
|
right_sliding_window_size = 0;
|
||||||
|
} else {
|
||||||
|
right_sliding_window_size = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {left_sliding_window_size, right_sliding_window_size};
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE static std::pair<int32_t, int32_t> calcu_kv_tile_pos(
|
FORCE_INLINE static std::pair<int32_t, int32_t> calcu_kv_tile_pos(
|
||||||
int32_t kv_left_pos, int32_t kv_right_pos, int32_t q_left_pos,
|
int32_t kv_left_pos, int32_t kv_right_pos, int32_t q_left_pos,
|
||||||
int32_t q_right_pos, int32_t sliding_window_left,
|
int32_t q_right_pos, int32_t window_size, bool causal) {
|
||||||
int32_t sliding_window_right) {
|
auto [left_sliding_window_size, right_sliding_window_size] =
|
||||||
if (sliding_window_left != -1) {
|
calcu_sliding_window_size(window_size, causal);
|
||||||
kv_left_pos = std::max(kv_left_pos, q_left_pos - sliding_window_left);
|
|
||||||
|
if (left_sliding_window_size != -1) {
|
||||||
|
kv_left_pos =
|
||||||
|
std::max(kv_left_pos, q_left_pos - left_sliding_window_size);
|
||||||
}
|
}
|
||||||
if (sliding_window_right != -1) {
|
if (right_sliding_window_size != -1) {
|
||||||
kv_right_pos = std::min(kv_right_pos, q_right_pos + sliding_window_right);
|
kv_right_pos =
|
||||||
|
std::min(kv_right_pos, q_right_pos + right_sliding_window_size);
|
||||||
}
|
}
|
||||||
return {kv_left_pos, kv_right_pos};
|
return {kv_left_pos, kv_right_pos};
|
||||||
}
|
}
|
||||||
@@ -805,10 +835,10 @@ struct AttentionInput {
|
|||||||
int32_t* block_table;
|
int32_t* block_table;
|
||||||
float* alibi_slopes;
|
float* alibi_slopes;
|
||||||
c10::BFloat16* s_aux;
|
c10::BFloat16* s_aux;
|
||||||
|
bool* dynamic_causal;
|
||||||
float scale;
|
float scale;
|
||||||
bool causal;
|
bool causal;
|
||||||
int32_t sliding_window_left;
|
int32_t sliding_window_size;
|
||||||
int32_t sliding_window_right;
|
|
||||||
float softcap;
|
float softcap;
|
||||||
// FP8 KV cache scales (used by FP8 attention implementations)
|
// FP8 KV cache scales (used by FP8 attention implementations)
|
||||||
float k_scale_fp8 = 1.0f;
|
float k_scale_fp8 = 1.0f;
|
||||||
@@ -1442,15 +1472,16 @@ class AttentionMainLoop {
|
|||||||
const int64_t q_head_num_stride = input->query_num_heads_stride;
|
const int64_t q_head_num_stride = input->query_num_heads_stride;
|
||||||
const int64_t kv_cache_head_num_stride = input->cache_num_kv_heads_stride;
|
const int64_t kv_cache_head_num_stride = input->cache_num_kv_heads_stride;
|
||||||
const int64_t kv_cache_block_num_stride = input->cache_num_blocks_stride;
|
const int64_t kv_cache_block_num_stride = input->cache_num_blocks_stride;
|
||||||
const int32_t sliding_window_left = input->sliding_window_left;
|
const int32_t sliding_window_size = input->sliding_window_size;
|
||||||
const int32_t sliding_window_right = input->sliding_window_right;
|
|
||||||
const int32_t block_size = input->block_size;
|
const int32_t block_size = input->block_size;
|
||||||
const float scale = input->scale;
|
const float scale = input->scale;
|
||||||
const float softcap_scale = input->softcap;
|
const float softcap_scale = input->softcap;
|
||||||
const float* alibi_slopes = input->alibi_slopes;
|
const float* alibi_slopes = input->alibi_slopes;
|
||||||
const c10::BFloat16* s_aux = input->s_aux;
|
const c10::BFloat16* s_aux = input->s_aux;
|
||||||
|
const bool* dynamic_causal = input->dynamic_causal;
|
||||||
|
const bool is_dynamic_causal = dynamic_causal != nullptr;
|
||||||
|
|
||||||
const bool casual = input->causal;
|
const bool causal = input->causal;
|
||||||
int32_t* const block_table = input->block_table;
|
int32_t* const block_table = input->block_table;
|
||||||
const int64_t block_table_stride = input->blt_num_tokens_stride;
|
const int64_t block_table_stride = input->blt_num_tokens_stride;
|
||||||
|
|
||||||
@@ -1533,6 +1564,11 @@ class AttentionMainLoop {
|
|||||||
&curr_workitem_groups[workitem_group_idx];
|
&curr_workitem_groups[workitem_group_idx];
|
||||||
|
|
||||||
const int32_t current_group_idx = current_workitem_group->req_id;
|
const int32_t current_group_idx = current_workitem_group->req_id;
|
||||||
|
const int32_t current_group_causal =
|
||||||
|
is_dynamic_causal ? dynamic_causal[current_group_idx] : causal;
|
||||||
|
auto [sliding_window_left, sliding_window_right] =
|
||||||
|
AttentionScheduler::calcu_sliding_window_size(
|
||||||
|
sliding_window_size, current_group_causal);
|
||||||
const int32_t kv_start_pos =
|
const int32_t kv_start_pos =
|
||||||
current_workitem_group->kv_split_pos_start;
|
current_workitem_group->kv_split_pos_start;
|
||||||
const int32_t kv_end_pos = current_workitem_group->kv_split_pos_end;
|
const int32_t kv_end_pos = current_workitem_group->kv_split_pos_end;
|
||||||
@@ -1560,8 +1596,7 @@ class AttentionMainLoop {
|
|||||||
const int32_t q_end = input->query_start_loc[current_group_idx + 1];
|
const int32_t q_end = input->query_start_loc[current_group_idx + 1];
|
||||||
const int32_t q_start = input->query_start_loc[current_group_idx];
|
const int32_t q_start = input->query_start_loc[current_group_idx];
|
||||||
const int32_t seq_len = input->seq_lens[current_group_idx];
|
const int32_t seq_len = input->seq_lens[current_group_idx];
|
||||||
const int32_t q_start_pos =
|
const int32_t q_start_pos = seq_len - (q_end - q_start);
|
||||||
(casual ? seq_len - (q_end - q_start) : 0);
|
|
||||||
const int32_t block_num = (seq_len + block_size - 1) / block_size;
|
const int32_t block_num = (seq_len + block_size - 1) / block_size;
|
||||||
// Only apply sink for the first KV split
|
// Only apply sink for the first KV split
|
||||||
bool use_sink = (s_aux != nullptr &&
|
bool use_sink = (s_aux != nullptr &&
|
||||||
@@ -1611,8 +1646,8 @@ class AttentionMainLoop {
|
|||||||
const auto [kv_tile_start_pos, kv_tile_end_pos] =
|
const auto [kv_tile_start_pos, kv_tile_end_pos] =
|
||||||
AttentionScheduler::calcu_kv_tile_pos(
|
AttentionScheduler::calcu_kv_tile_pos(
|
||||||
kv_start_pos, kv_end_pos, q_tile_start_pos,
|
kv_start_pos, kv_end_pos, q_tile_start_pos,
|
||||||
q_tile_end_pos, sliding_window_left,
|
q_tile_end_pos, sliding_window_size,
|
||||||
sliding_window_right);
|
current_group_causal);
|
||||||
const auto [rounded_kv_tile_start_pos, rounded_kv_tile_end_pos] =
|
const auto [rounded_kv_tile_start_pos, rounded_kv_tile_end_pos] =
|
||||||
AttentionScheduler::align_kv_tile_pos(
|
AttentionScheduler::align_kv_tile_pos(
|
||||||
kv_tile_start_pos, kv_tile_end_pos, blocksize_alignment);
|
kv_tile_start_pos, kv_tile_end_pos, blocksize_alignment);
|
||||||
@@ -1725,8 +1760,8 @@ class AttentionMainLoop {
|
|||||||
actual_kv_tile_pos_right] =
|
actual_kv_tile_pos_right] =
|
||||||
AttentionScheduler::calcu_kv_tile_pos(
|
AttentionScheduler::calcu_kv_tile_pos(
|
||||||
kv_tile_pos_left, kv_tile_pos_right, q_tile_pos_left,
|
kv_tile_pos_left, kv_tile_pos_right, q_tile_pos_left,
|
||||||
q_tile_pos_right, sliding_window_left,
|
q_tile_pos_right, sliding_window_size,
|
||||||
sliding_window_right);
|
current_group_causal);
|
||||||
const int32_t q_iter_idx =
|
const int32_t q_iter_idx =
|
||||||
q_head_tile_token_offset / curr_max_q_token_num_per_iter;
|
q_head_tile_token_offset / curr_max_q_token_num_per_iter;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include <sleef.h>
|
||||||
|
|
||||||
#include "cpu/cpu_types.hpp"
|
#include "cpu/cpu_types.hpp"
|
||||||
#include "cpu/utils.hpp"
|
#include "cpu/utils.hpp"
|
||||||
#include "cpu/micro_gemm/cpu_micro_gemm_vec.hpp"
|
#include "cpu/micro_gemm/cpu_micro_gemm_vec.hpp"
|
||||||
@@ -163,7 +165,6 @@ void gelu_tanh_and_mul(float* __restrict__ input, scalar_t* __restrict__ output,
|
|||||||
vec_op::FP32Vec16 w1_vec(0.7978845608028654);
|
vec_op::FP32Vec16 w1_vec(0.7978845608028654);
|
||||||
vec_op::FP32Vec16 w2_vec(0.5);
|
vec_op::FP32Vec16 w2_vec(0.5);
|
||||||
vec_op::FP32Vec16 w3_vec(0.044715);
|
vec_op::FP32Vec16 w3_vec(0.044715);
|
||||||
alignas(64) float temp[16];
|
|
||||||
|
|
||||||
for (int32_t m = 0; m < m_size; ++m) {
|
for (int32_t m = 0; m < m_size; ++m) {
|
||||||
for (int32_t n = 0; n < dim; n += 16) {
|
for (int32_t n = 0; n < dim; n += 16) {
|
||||||
@@ -171,12 +172,9 @@ void gelu_tanh_and_mul(float* __restrict__ input, scalar_t* __restrict__ output,
|
|||||||
vec_op::FP32Vec16 up_vec(up + n);
|
vec_op::FP32Vec16 up_vec(up + n);
|
||||||
auto gate_pow3_vec = gate_vec * gate_vec * gate_vec;
|
auto gate_pow3_vec = gate_vec * gate_vec * gate_vec;
|
||||||
auto inner_vec = w1_vec * (gate_vec + w3_vec * gate_pow3_vec);
|
auto inner_vec = w1_vec * (gate_vec + w3_vec * gate_pow3_vec);
|
||||||
|
// Note: can't use fast_exp form because diffusiongemma will generate
|
||||||
inner_vec.save(temp);
|
// wrong results
|
||||||
for (int32_t i = 0; i < 16; ++i) {
|
vec_op::FP32Vec16 tanh_vec(Sleef_tanhf16_u10(inner_vec.reg));
|
||||||
temp[i] = std::tanh(temp[i]);
|
|
||||||
}
|
|
||||||
vec_op::FP32Vec16 tanh_vec(temp);
|
|
||||||
auto gelu_tanh = gate_vec * w2_vec * (one_vec + tanh_vec);
|
auto gelu_tanh = gate_vec * w2_vec * (one_vec + tanh_vec);
|
||||||
auto gated_output_fp32 = up_vec * gelu_tanh;
|
auto gated_output_fp32 = up_vec * gelu_tanh;
|
||||||
scalar_vec_t gated_output = scalar_vec_t(gated_output_fp32);
|
scalar_vec_t gated_output = scalar_vec_t(gated_output_fp32);
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
#ifdef CPU_CAPABILITY_AMXBF16
|
#ifdef CPU_CAPABILITY_AMXBF16
|
||||||
#include "cpu/micro_gemm/cpu_micro_gemm_amx.hpp"
|
#include "cpu/micro_gemm/cpu_micro_gemm_amx.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(__riscv_v)
|
||||||
|
#include "cpu/micro_gemm/cpu_micro_gemm_rvv.hpp"
|
||||||
|
#endif
|
||||||
#include "cpu/micro_gemm/cpu_micro_gemm_vec.hpp"
|
#include "cpu/micro_gemm/cpu_micro_gemm_vec.hpp"
|
||||||
|
|
||||||
#define VLLM_DISPATCH_CASE_16B_TYPES(...) \
|
#define VLLM_DISPATCH_CASE_16B_TYPES(...) \
|
||||||
@@ -319,6 +322,8 @@ void cpu_gemm_wna16(
|
|||||||
return ISA::AMX;
|
return ISA::AMX;
|
||||||
} else if (isa_hint == "vec") {
|
} else if (isa_hint == "vec") {
|
||||||
return ISA::VEC;
|
return ISA::VEC;
|
||||||
|
} else if (isa_hint == "rvv") {
|
||||||
|
return ISA::RVV;
|
||||||
} else {
|
} else {
|
||||||
TORCH_CHECK(false, "unsupported isa hint: " + isa_hint);
|
TORCH_CHECK(false, "unsupported isa hint: " + isa_hint);
|
||||||
}
|
}
|
||||||
@@ -397,6 +402,40 @@ void cpu_gemm_wna16(
|
|||||||
pack_factor);
|
pack_factor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (isa == ISA::RVV) {
|
||||||
|
using gemm_t = cpu_micro_gemm::MicroGemm<ISA::RVV, scalar_t>;
|
||||||
|
if (has_zp) {
|
||||||
|
using dequantizer_t = Dequantizer4b<scalar_t, ISA::RVV, true, false>;
|
||||||
|
cpu_gemm_wna16_impl<scalar_t, dequantizer_t, gemm_t>(
|
||||||
|
input.data_ptr<scalar_t>(), q_weight.data_ptr<int32_t>(),
|
||||||
|
output.data_ptr<scalar_t>(), scales.data_ptr<scalar_t>(), zeros_ptr,
|
||||||
|
g_idx_ptr, bias.has_value() ? bias->data_ptr<scalar_t>() : nullptr,
|
||||||
|
a_m_size, b_n_size, a_k_size, a_m_stride, output_m_stride,
|
||||||
|
scales_group_stride, zeros_group_stride, group_num, group_size,
|
||||||
|
pack_factor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (use_desc_act) {
|
||||||
|
using dequantizer_t = Dequantizer4b<scalar_t, ISA::RVV, false, true>;
|
||||||
|
cpu_gemm_wna16_impl<scalar_t, dequantizer_t, gemm_t>(
|
||||||
|
input.data_ptr<scalar_t>(), q_weight.data_ptr<int32_t>(),
|
||||||
|
output.data_ptr<scalar_t>(), scales.data_ptr<scalar_t>(), zeros_ptr,
|
||||||
|
g_idx_ptr, bias.has_value() ? bias->data_ptr<scalar_t>() : nullptr,
|
||||||
|
a_m_size, b_n_size, a_k_size, a_m_stride, output_m_stride,
|
||||||
|
scales_group_stride, zeros_group_stride, group_num, group_size,
|
||||||
|
pack_factor);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
using dequantizer_t = Dequantizer4b<scalar_t, ISA::RVV, false, false>;
|
||||||
|
cpu_gemm_wna16_impl<scalar_t, dequantizer_t, gemm_t>(
|
||||||
|
input.data_ptr<scalar_t>(), q_weight.data_ptr<int32_t>(),
|
||||||
|
output.data_ptr<scalar_t>(), scales.data_ptr<scalar_t>(), zeros_ptr,
|
||||||
|
g_idx_ptr, bias.has_value() ? bias->data_ptr<scalar_t>() : nullptr,
|
||||||
|
a_m_size, b_n_size, a_k_size, a_m_stride, output_m_stride,
|
||||||
|
scales_group_stride, zeros_group_stride, group_num, group_size,
|
||||||
|
pack_factor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-22
@@ -4,8 +4,9 @@ namespace {
|
|||||||
template <typename scalar_t>
|
template <typename scalar_t>
|
||||||
void rms_norm_impl(scalar_t* __restrict__ out,
|
void rms_norm_impl(scalar_t* __restrict__ out,
|
||||||
const scalar_t* __restrict__ input,
|
const scalar_t* __restrict__ input,
|
||||||
const scalar_t* __restrict__ weight, const float epsilon,
|
const scalar_t* __restrict__ weight, const bool has_weight,
|
||||||
const int num_tokens, const int hidden_size) {
|
const float epsilon, const int num_tokens,
|
||||||
|
const int hidden_size) {
|
||||||
using scalar_vec_t = vec_op::vec_t<scalar_t>;
|
using scalar_vec_t = vec_op::vec_t<scalar_t>;
|
||||||
constexpr int VEC_ELEM_NUM = scalar_vec_t::get_elem_num();
|
constexpr int VEC_ELEM_NUM = scalar_vec_t::get_elem_num();
|
||||||
TORCH_CHECK(hidden_size % VEC_ELEM_NUM == 0);
|
TORCH_CHECK(hidden_size % VEC_ELEM_NUM == 0);
|
||||||
@@ -27,12 +28,15 @@ void rms_norm_impl(scalar_t* __restrict__ out,
|
|||||||
|
|
||||||
for (int j = 0; j < hidden_size; j += VEC_ELEM_NUM) {
|
for (int j = 0; j < hidden_size; j += VEC_ELEM_NUM) {
|
||||||
scalar_vec_t x(input_p + j);
|
scalar_vec_t x(input_p + j);
|
||||||
scalar_vec_t w(weight + j);
|
|
||||||
|
|
||||||
vec_op::FP32Vec8 fp32_x(x);
|
vec_op::FP32Vec8 fp32_x(x);
|
||||||
vec_op::FP32Vec8 fp32_w(w);
|
vec_op::FP32Vec8 fp32_out;
|
||||||
|
if (has_weight) {
|
||||||
vec_op::FP32Vec8 fp32_out = fp32_x * fp32_s_variance * fp32_w;
|
scalar_vec_t w(weight + j);
|
||||||
|
vec_op::FP32Vec8 fp32_w(w);
|
||||||
|
fp32_out = fp32_x * fp32_s_variance * fp32_w;
|
||||||
|
} else {
|
||||||
|
fp32_out = fp32_x * fp32_s_variance;
|
||||||
|
}
|
||||||
|
|
||||||
scalar_vec_t out(fp32_out);
|
scalar_vec_t out(fp32_out);
|
||||||
out.save(output_p + j);
|
out.save(output_p + j);
|
||||||
@@ -44,8 +48,8 @@ template <typename scalar_t>
|
|||||||
void fused_add_rms_norm_impl(scalar_t* __restrict__ input,
|
void fused_add_rms_norm_impl(scalar_t* __restrict__ input,
|
||||||
scalar_t* __restrict__ residual,
|
scalar_t* __restrict__ residual,
|
||||||
const scalar_t* __restrict__ weight,
|
const scalar_t* __restrict__ weight,
|
||||||
const float epsilon, const int num_tokens,
|
const bool has_weight, const float epsilon,
|
||||||
const int hidden_size) {
|
const int num_tokens, const int hidden_size) {
|
||||||
using scalar_vec_t = vec_op::vec_t<scalar_t>;
|
using scalar_vec_t = vec_op::vec_t<scalar_t>;
|
||||||
constexpr int VEC_ELEM_NUM = scalar_vec_t::get_elem_num();
|
constexpr int VEC_ELEM_NUM = scalar_vec_t::get_elem_num();
|
||||||
TORCH_CHECK(hidden_size % VEC_ELEM_NUM == 0);
|
TORCH_CHECK(hidden_size % VEC_ELEM_NUM == 0);
|
||||||
@@ -72,13 +76,18 @@ void fused_add_rms_norm_impl(scalar_t* __restrict__ input,
|
|||||||
vec_op::FP32Vec8 fp32_s_variance(s_variance);
|
vec_op::FP32Vec8 fp32_s_variance(s_variance);
|
||||||
|
|
||||||
for (int j = 0; j < hidden_size; j += VEC_ELEM_NUM) {
|
for (int j = 0; j < hidden_size; j += VEC_ELEM_NUM) {
|
||||||
scalar_vec_t w(weight + j);
|
vec_op::FP32Vec8 fp32_out;
|
||||||
scalar_vec_t res(residual_p + j);
|
if (has_weight) {
|
||||||
|
scalar_vec_t w(weight + j);
|
||||||
vec_op::FP32Vec8 fp32_w(w);
|
scalar_vec_t res(residual_p + j);
|
||||||
vec_op::FP32Vec8 fp32_res(res);
|
vec_op::FP32Vec8 fp32_w(w);
|
||||||
|
vec_op::FP32Vec8 fp32_res(res);
|
||||||
vec_op::FP32Vec8 fp32_out = fp32_res * fp32_s_variance * fp32_w;
|
fp32_out = fp32_res * fp32_s_variance * fp32_w;
|
||||||
|
} else {
|
||||||
|
scalar_vec_t res(residual_p + j);
|
||||||
|
vec_op::FP32Vec8 fp32_res(res);
|
||||||
|
fp32_out = fp32_res * fp32_s_variance;
|
||||||
|
}
|
||||||
|
|
||||||
scalar_vec_t out(fp32_out);
|
scalar_vec_t out(fp32_out);
|
||||||
out.save(input_p + j);
|
out.save(input_p + j);
|
||||||
@@ -87,31 +96,41 @@ void fused_add_rms_norm_impl(scalar_t* __restrict__ input,
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void rms_norm(torch::Tensor& out, torch::Tensor& input, torch::Tensor& weight,
|
void rms_norm(torch::Tensor& out, torch::Tensor& input,
|
||||||
double epsilon) {
|
std::optional<torch::Tensor> weight, double epsilon) {
|
||||||
int hidden_size = input.size(-1);
|
int hidden_size = input.size(-1);
|
||||||
int num_tokens = input.numel() / hidden_size;
|
int num_tokens = input.numel() / hidden_size;
|
||||||
|
const bool has_weight = weight.has_value();
|
||||||
|
if (has_weight) {
|
||||||
|
TORCH_CHECK(weight->is_contiguous());
|
||||||
|
}
|
||||||
|
|
||||||
VLLM_DISPATCH_FLOATING_TYPES(input.scalar_type(), "rms_norm_impl", [&] {
|
VLLM_DISPATCH_FLOATING_TYPES(input.scalar_type(), "rms_norm_impl", [&] {
|
||||||
CPU_KERNEL_GUARD_IN(rms_norm_impl)
|
CPU_KERNEL_GUARD_IN(rms_norm_impl)
|
||||||
rms_norm_impl(out.data_ptr<scalar_t>(), input.data_ptr<scalar_t>(),
|
rms_norm_impl(out.data_ptr<scalar_t>(), input.data_ptr<scalar_t>(),
|
||||||
weight.data_ptr<scalar_t>(), epsilon, num_tokens,
|
has_weight ? weight->data_ptr<scalar_t>() : nullptr,
|
||||||
hidden_size);
|
has_weight, epsilon, num_tokens, hidden_size);
|
||||||
CPU_KERNEL_GUARD_OUT(rms_norm_impl)
|
CPU_KERNEL_GUARD_OUT(rms_norm_impl)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void fused_add_rms_norm(torch::Tensor& input, torch::Tensor& residual,
|
void fused_add_rms_norm(torch::Tensor& input, torch::Tensor& residual,
|
||||||
torch::Tensor& weight, double epsilon) {
|
std::optional<torch::Tensor> weight, double epsilon) {
|
||||||
int hidden_size = input.size(-1);
|
int hidden_size = input.size(-1);
|
||||||
int num_tokens = input.numel() / hidden_size;
|
int num_tokens = input.numel() / hidden_size;
|
||||||
|
const bool has_weight = weight.has_value();
|
||||||
|
if (has_weight) {
|
||||||
|
TORCH_CHECK(weight->scalar_type() == input.scalar_type());
|
||||||
|
TORCH_CHECK(weight->is_contiguous());
|
||||||
|
}
|
||||||
|
|
||||||
VLLM_DISPATCH_FLOATING_TYPES(
|
VLLM_DISPATCH_FLOATING_TYPES(
|
||||||
input.scalar_type(), "fused_add_rms_norm_impl", [&] {
|
input.scalar_type(), "fused_add_rms_norm_impl", [&] {
|
||||||
CPU_KERNEL_GUARD_IN(fused_add_rms_norm_impl)
|
CPU_KERNEL_GUARD_IN(fused_add_rms_norm_impl)
|
||||||
fused_add_rms_norm_impl(
|
fused_add_rms_norm_impl(
|
||||||
input.data_ptr<scalar_t>(), residual.data_ptr<scalar_t>(),
|
input.data_ptr<scalar_t>(), residual.data_ptr<scalar_t>(),
|
||||||
weight.data_ptr<scalar_t>(), epsilon, num_tokens, hidden_size);
|
has_weight ? weight->data_ptr<scalar_t>() : nullptr, has_weight,
|
||||||
|
epsilon, num_tokens, hidden_size);
|
||||||
CPU_KERNEL_GUARD_OUT(fused_add_rms_norm_impl)
|
CPU_KERNEL_GUARD_OUT(fused_add_rms_norm_impl)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,228 @@
|
|||||||
|
#ifndef CPU_MICRO_GEMM_RVV_HPP
|
||||||
|
#define CPU_MICRO_GEMM_RVV_HPP
|
||||||
|
|
||||||
|
#include "cpu/micro_gemm/cpu_micro_gemm_impl.hpp"
|
||||||
|
|
||||||
|
#if defined(__riscv_v)
|
||||||
|
|
||||||
|
namespace cpu_micro_gemm {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr int32_t RVV_MGEMM_N8 = 8;
|
||||||
|
constexpr int32_t RVV_MGEMM_B_GROUP_STRIDE = 16;
|
||||||
|
|
||||||
|
template <typename scalar_t>
|
||||||
|
FORCE_INLINE fixed_fp32x8_t load_row8_b_as_f32(const scalar_t* ptr);
|
||||||
|
|
||||||
|
template <>
|
||||||
|
FORCE_INLINE fixed_fp32x8_t load_row8_b_as_f32<float>(const float* ptr) {
|
||||||
|
return RVVI(__riscv_vle32_v_f32, LMUL_256)(ptr, RVV_MGEMM_N8);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
FORCE_INLINE fixed_fp32x8_t
|
||||||
|
load_row8_b_as_f32<c10::Half>(const c10::Half* ptr) {
|
||||||
|
#if defined(__riscv_zvfh)
|
||||||
|
fixed_fp16x8_t vec = RVVI(__riscv_vle16_v_f16, LMUL_128)(
|
||||||
|
reinterpret_cast<const _Float16*>(ptr), RVV_MGEMM_N8);
|
||||||
|
return RVVI(__riscv_vfwcvt_f_f_v_f32, LMUL_256)(vec, RVV_MGEMM_N8);
|
||||||
|
#else
|
||||||
|
alignas(32) float values[RVV_MGEMM_N8];
|
||||||
|
for (int32_t i = 0; i < RVV_MGEMM_N8; ++i) {
|
||||||
|
values[i] = static_cast<float>(ptr[i]);
|
||||||
|
}
|
||||||
|
return RVVI(__riscv_vle32_v_f32, LMUL_256)(values, RVV_MGEMM_N8);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
FORCE_INLINE fixed_fp32x8_t
|
||||||
|
load_row8_b_as_f32<c10::BFloat16>(const c10::BFloat16* ptr) {
|
||||||
|
#if defined(__riscv_zvfbfmin)
|
||||||
|
fixed_u16x8_t raw = RVVI(__riscv_vle16_v_u16, LMUL_128)(
|
||||||
|
reinterpret_cast<const uint16_t*>(ptr), RVV_MGEMM_N8);
|
||||||
|
fixed_bf16x8_t vec =
|
||||||
|
RVVI4(__riscv_vreinterpret_v_u16, LMUL_128, _bf16, LMUL_128)(raw);
|
||||||
|
return RVVI(__riscv_vfwcvtbf16_f_f_v_f32, LMUL_256)(vec, RVV_MGEMM_N8);
|
||||||
|
#else
|
||||||
|
fixed_u16x8_t raw = RVVI(__riscv_vle16_v_u16, LMUL_128)(
|
||||||
|
reinterpret_cast<const uint16_t*>(ptr), RVV_MGEMM_N8);
|
||||||
|
auto wide = RVVI(__riscv_vzext_vf2_u32, LMUL_256)(raw, RVV_MGEMM_N8);
|
||||||
|
auto shifted = RVVI(__riscv_vsll_vx_u32, LMUL_256)(wide, 16, RVV_MGEMM_N8);
|
||||||
|
return RVVI4(__riscv_vreinterpret_v_u32, LMUL_256, _f32, LMUL_256)(shifted);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mx8 RVV kernel. B points at one 8-channel half of a 16-channel packed group,
|
||||||
|
// with rows separated by RVV_MGEMM_B_GROUP_STRIDE scalar elements.
|
||||||
|
template <int32_t M, typename scalar_t>
|
||||||
|
FORCE_INLINE void gemm_micro_rvv_fma_mx8_ku4(const scalar_t* __restrict__ a_ptr,
|
||||||
|
const scalar_t* __restrict__ b_ptr,
|
||||||
|
float* __restrict__ c_ptr,
|
||||||
|
const int64_t lda,
|
||||||
|
const int64_t ldc, const int32_t k,
|
||||||
|
const bool accum_c) {
|
||||||
|
static_assert(0 < M && M <= 8);
|
||||||
|
|
||||||
|
#define RVV_ROWS_APPLY(OP) OP(0) OP(1) OP(2) OP(3) OP(4) OP(5) OP(6) OP(7)
|
||||||
|
#define RVV_IF_M(i) if constexpr (M > (i))
|
||||||
|
|
||||||
|
#define RVV_DECL_A(i) const scalar_t* __restrict__ a##i = a_ptr + (i) * lda;
|
||||||
|
RVV_ROWS_APPLY(RVV_DECL_A)
|
||||||
|
#undef RVV_DECL_A
|
||||||
|
|
||||||
|
#define RVV_DECL_ACC(i) fixed_fp32x8_t acc##i;
|
||||||
|
RVV_ROWS_APPLY(RVV_DECL_ACC)
|
||||||
|
#undef RVV_DECL_ACC
|
||||||
|
|
||||||
|
#define RVV_INIT_ACC(i) \
|
||||||
|
RVV_IF_M(i) { \
|
||||||
|
if (accum_c) { \
|
||||||
|
acc##i = RVVI(__riscv_vle32_v_f32, LMUL_256)(c_ptr + (i) * ldc, \
|
||||||
|
RVV_MGEMM_N8); \
|
||||||
|
} else { \
|
||||||
|
acc##i = RVVI(__riscv_vfmv_v_f_f32, LMUL_256)(0.0f, RVV_MGEMM_N8); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
RVV_ROWS_APPLY(RVV_INIT_ACC)
|
||||||
|
#undef RVV_INIT_ACC
|
||||||
|
|
||||||
|
int32_t k_idx = 0;
|
||||||
|
for (; k_idx + 3 < k; k_idx += 4) {
|
||||||
|
#define RVV_FMA_ROW(i, K_OFFSET) \
|
||||||
|
RVV_IF_M(i) { \
|
||||||
|
acc##i = RVVI(__riscv_vfmacc_vf_f32, LMUL_256)( \
|
||||||
|
acc##i, static_cast<float>(*(a##i + k_idx + (K_OFFSET))), b, \
|
||||||
|
RVV_MGEMM_N8); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RVV_STEP_K(K_OFFSET) \
|
||||||
|
{ \
|
||||||
|
fixed_fp32x8_t b = load_row8_b_as_f32<scalar_t>( \
|
||||||
|
b_ptr + (k_idx + (K_OFFSET)) * RVV_MGEMM_B_GROUP_STRIDE); \
|
||||||
|
RVV_FMA_ROW(0, K_OFFSET) \
|
||||||
|
RVV_FMA_ROW(1, K_OFFSET) \
|
||||||
|
RVV_FMA_ROW(2, K_OFFSET) \
|
||||||
|
RVV_FMA_ROW(3, K_OFFSET) \
|
||||||
|
RVV_FMA_ROW(4, K_OFFSET) \
|
||||||
|
RVV_FMA_ROW(5, K_OFFSET) \
|
||||||
|
RVV_FMA_ROW(6, K_OFFSET) \
|
||||||
|
RVV_FMA_ROW(7, K_OFFSET) \
|
||||||
|
}
|
||||||
|
|
||||||
|
RVV_STEP_K(0)
|
||||||
|
RVV_STEP_K(1)
|
||||||
|
RVV_STEP_K(2)
|
||||||
|
RVV_STEP_K(3)
|
||||||
|
#undef RVV_STEP_K
|
||||||
|
#undef RVV_FMA_ROW
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; k_idx < k; ++k_idx) {
|
||||||
|
fixed_fp32x8_t b =
|
||||||
|
load_row8_b_as_f32<scalar_t>(b_ptr + k_idx * RVV_MGEMM_B_GROUP_STRIDE);
|
||||||
|
#define RVV_TAIL_ROW(i) \
|
||||||
|
RVV_IF_M(i) { \
|
||||||
|
acc##i = RVVI(__riscv_vfmacc_vf_f32, LMUL_256)( \
|
||||||
|
acc##i, static_cast<float>(*(a##i + k_idx)), b, RVV_MGEMM_N8); \
|
||||||
|
}
|
||||||
|
RVV_ROWS_APPLY(RVV_TAIL_ROW)
|
||||||
|
#undef RVV_TAIL_ROW
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RVV_STORE_ROW(i) \
|
||||||
|
RVV_IF_M(i) { \
|
||||||
|
RVVI(__riscv_vse32_v_f32, LMUL_256)(c_ptr + (i) * ldc, acc##i, \
|
||||||
|
RVV_MGEMM_N8); \
|
||||||
|
}
|
||||||
|
RVV_ROWS_APPLY(RVV_STORE_ROW)
|
||||||
|
#undef RVV_STORE_ROW
|
||||||
|
|
||||||
|
#undef RVV_ROWS_APPLY
|
||||||
|
#undef RVV_IF_M
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int32_t M, typename scalar_t>
|
||||||
|
FORCE_INLINE void gemm_micro_rvv_mx32_ku4(DEFINE_CPU_MICRO_GEMM_PARAMS) {
|
||||||
|
static_assert(0 < M && M <= 8);
|
||||||
|
scalar_t* __restrict__ curr_b_0 = b_ptr;
|
||||||
|
scalar_t* __restrict__ curr_b_1 = b_ptr + b_n_group_stride;
|
||||||
|
|
||||||
|
gemm_micro_rvv_fma_mx8_ku4<M>(a_ptr, curr_b_0, c_ptr, lda, ldc, k, accum_c);
|
||||||
|
gemm_micro_rvv_fma_mx8_ku4<M>(a_ptr, curr_b_0 + RVV_MGEMM_N8,
|
||||||
|
c_ptr + RVV_MGEMM_N8, lda, ldc, k, accum_c);
|
||||||
|
gemm_micro_rvv_fma_mx8_ku4<M>(a_ptr, curr_b_1, c_ptr + 16, lda, ldc, k,
|
||||||
|
accum_c);
|
||||||
|
gemm_micro_rvv_fma_mx8_ku4<M>(a_ptr, curr_b_1 + RVV_MGEMM_N8, c_ptr + 24, lda,
|
||||||
|
ldc, k, accum_c);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TileGemmRVV {
|
||||||
|
public:
|
||||||
|
template <typename scalar_t>
|
||||||
|
FORCE_INLINE static void gemm(DEFINE_CPU_MICRO_GEMM_PARAMS) {
|
||||||
|
switch (m) {
|
||||||
|
case 1:
|
||||||
|
gemm_micro_rvv_mx32_ku4<1>(CPU_MICRO_GEMM_PARAMS);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
gemm_micro_rvv_mx32_ku4<2>(CPU_MICRO_GEMM_PARAMS);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
gemm_micro_rvv_mx32_ku4<3>(CPU_MICRO_GEMM_PARAMS);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
gemm_micro_rvv_mx32_ku4<4>(CPU_MICRO_GEMM_PARAMS);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
gemm_micro_rvv_mx32_ku4<5>(CPU_MICRO_GEMM_PARAMS);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
gemm_micro_rvv_mx32_ku4<6>(CPU_MICRO_GEMM_PARAMS);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
gemm_micro_rvv_mx32_ku4<7>(CPU_MICRO_GEMM_PARAMS);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
gemm_micro_rvv_mx32_ku4<8>(CPU_MICRO_GEMM_PARAMS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
template <typename scalar_t>
|
||||||
|
class MicroGemm<cpu_utils::ISA::RVV, scalar_t> {
|
||||||
|
public:
|
||||||
|
static constexpr int32_t MaxMSize = 8;
|
||||||
|
static constexpr int32_t NSize = 32;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void gemm(DEFINE_CPU_MICRO_GEMM_PARAMS) {
|
||||||
|
TileGemmRVV::gemm<scalar_t>(CPU_MICRO_GEMM_PARAMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pack_weight(const scalar_t* __restrict__ weight,
|
||||||
|
scalar_t* __restrict__ packed_weight,
|
||||||
|
const int32_t output_size, const int32_t input_size) {
|
||||||
|
TORCH_CHECK_EQ(output_size % 16, 0);
|
||||||
|
for (int32_t o_idx = 0; o_idx < output_size; ++o_idx) {
|
||||||
|
const scalar_t* __restrict__ curr_weight = weight + o_idx * input_size;
|
||||||
|
scalar_t* __restrict__ curr_packed_weight =
|
||||||
|
packed_weight + (o_idx / 16) * (16 * input_size) + o_idx % 16;
|
||||||
|
for (int32_t i_idx = 0; i_idx < input_size; ++i_idx) {
|
||||||
|
*curr_packed_weight = *curr_weight;
|
||||||
|
|
||||||
|
curr_packed_weight += 16;
|
||||||
|
++curr_weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cpu_micro_gemm
|
||||||
|
|
||||||
|
#endif // defined(__riscv_v)
|
||||||
|
|
||||||
|
#endif // CPU_MICRO_GEMM_RVV_HPP
|
||||||
+15
-10
@@ -146,13 +146,16 @@ at::Tensor causal_conv1d_update_cpu(
|
|||||||
void activation_lut_bf16(torch::Tensor& out, torch::Tensor& input,
|
void activation_lut_bf16(torch::Tensor& out, torch::Tensor& input,
|
||||||
const std::string& activation);
|
const std::string& activation);
|
||||||
|
|
||||||
|
bool cpu_attn_has_isa(const std::string& isa);
|
||||||
|
|
||||||
torch::Tensor get_scheduler_metadata(
|
torch::Tensor get_scheduler_metadata(
|
||||||
const int64_t num_req, const int64_t num_heads_q,
|
const int64_t num_req, const int64_t num_heads_q,
|
||||||
const int64_t num_heads_kv, const int64_t head_dim,
|
const int64_t num_heads_kv, const int64_t head_dim,
|
||||||
const torch::Tensor& seq_lens, at::ScalarType dtype,
|
const torch::Tensor& seq_lens, at::ScalarType dtype,
|
||||||
const torch::Tensor& query_start_loc, const bool casual,
|
const torch::Tensor& query_start_loc, const bool casual,
|
||||||
const int64_t window_size, const std::string& isa_hint,
|
const int64_t window_size, const std::string& isa_hint,
|
||||||
const bool enable_kv_split);
|
const bool enable_kv_split,
|
||||||
|
const std::optional<torch::Tensor>& dynamic_causal);
|
||||||
|
|
||||||
void cpu_attn_reshape_and_cache(const torch::Tensor& key,
|
void cpu_attn_reshape_and_cache(const torch::Tensor& key,
|
||||||
const torch::Tensor& value,
|
const torch::Tensor& value,
|
||||||
@@ -169,10 +172,10 @@ void cpu_attention_with_kv_cache(
|
|||||||
const torch::Tensor& query_start_loc, const torch::Tensor& seq_lens,
|
const torch::Tensor& query_start_loc, const torch::Tensor& seq_lens,
|
||||||
const double scale, const bool causal,
|
const double scale, const bool causal,
|
||||||
const std::optional<torch::Tensor>& alibi_slopes,
|
const std::optional<torch::Tensor>& alibi_slopes,
|
||||||
const int64_t sliding_window_left, const int64_t sliding_window_right,
|
const int64_t sliding_window_left, const torch::Tensor& block_table,
|
||||||
const torch::Tensor& block_table, const double softcap,
|
const double softcap, const torch::Tensor& scheduler_metadata,
|
||||||
const torch::Tensor& scheduler_metadata,
|
const std::optional<torch::Tensor>& s_aux,
|
||||||
const std::optional<torch::Tensor>& s_aux, const double k_scale,
|
const std::optional<torch::Tensor>& dynamic_causal, const double k_scale,
|
||||||
const double v_scale, const std::string& kv_cache_dtype);
|
const double v_scale, const std::string& kv_cache_dtype);
|
||||||
|
|
||||||
// Note: just for avoiding importing errors
|
// Note: just for avoiding importing errors
|
||||||
@@ -309,13 +312,13 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
|
|||||||
// Layernorm
|
// Layernorm
|
||||||
// Apply Root Mean Square (RMS) Normalization to the input tensor.
|
// Apply Root Mean Square (RMS) Normalization to the input tensor.
|
||||||
ops.def(
|
ops.def(
|
||||||
"rms_norm(Tensor! out, Tensor input, Tensor weight, float epsilon) -> "
|
"rms_norm(Tensor! out, Tensor input, Tensor? weight, float epsilon) -> "
|
||||||
"()");
|
"()");
|
||||||
ops.impl("rms_norm", torch::kCPU, &rms_norm);
|
ops.impl("rms_norm", torch::kCPU, &rms_norm);
|
||||||
|
|
||||||
// In-place fused Add and RMS Normalization.
|
// In-place fused Add and RMS Normalization.
|
||||||
ops.def(
|
ops.def(
|
||||||
"fused_add_rms_norm(Tensor! input, Tensor! residual, Tensor weight, "
|
"fused_add_rms_norm(Tensor! input, Tensor! residual, Tensor? weight, "
|
||||||
"float epsilon) -> ()");
|
"float epsilon) -> ()");
|
||||||
ops.impl("fused_add_rms_norm", torch::kCPU, &fused_add_rms_norm);
|
ops.impl("fused_add_rms_norm", torch::kCPU, &fused_add_rms_norm);
|
||||||
|
|
||||||
@@ -496,11 +499,12 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
|
|||||||
ops.impl("fused_gdn_gating_cpu", torch::kCPU, &fused_gdn_gating_cpu);
|
ops.impl("fused_gdn_gating_cpu", torch::kCPU, &fused_gdn_gating_cpu);
|
||||||
|
|
||||||
// CPU attention kernels
|
// CPU attention kernels
|
||||||
|
ops.def("cpu_attn_has_isa(str isa) -> bool", &cpu_attn_has_isa);
|
||||||
ops.def(
|
ops.def(
|
||||||
"get_scheduler_metadata(int num_req, int num_heads_q, int num_heads_kv, "
|
"get_scheduler_metadata(int num_req, int num_heads_q, int num_heads_kv, "
|
||||||
"int head_dim, Tensor seq_lens, ScalarType dtype, Tensor "
|
"int head_dim, Tensor seq_lens, ScalarType dtype, Tensor "
|
||||||
"query_start_loc, bool casual, int window_size, str isa_hint, bool "
|
"query_start_loc, bool casual, int window_size, str isa_hint, bool "
|
||||||
"enable_kv_split) -> Tensor",
|
"enable_kv_split, Tensor? dynamic_causal) -> Tensor",
|
||||||
&get_scheduler_metadata);
|
&get_scheduler_metadata);
|
||||||
ops.def(
|
ops.def(
|
||||||
"cpu_attn_reshape_and_cache(Tensor key, Tensor value, Tensor(a2!) "
|
"cpu_attn_reshape_and_cache(Tensor key, Tensor value, Tensor(a2!) "
|
||||||
@@ -512,8 +516,9 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
|
|||||||
"cpu_attention_with_kv_cache(Tensor query, Tensor key_cache, Tensor "
|
"cpu_attention_with_kv_cache(Tensor query, Tensor key_cache, Tensor "
|
||||||
"value_cache, Tensor(a3!) output, Tensor query_start_loc, Tensor "
|
"value_cache, Tensor(a3!) output, Tensor query_start_loc, Tensor "
|
||||||
"seq_lens, float scale, bool causal, Tensor? alibi_slopes, SymInt "
|
"seq_lens, float scale, bool causal, Tensor? alibi_slopes, SymInt "
|
||||||
"sliding_window_left, SymInt sliding_window_right, Tensor block_table, "
|
"sliding_window_size, Tensor block_table, "
|
||||||
"float softcap, Tensor scheduler_metadata, Tensor? s_aux, "
|
"float softcap, Tensor scheduler_metadata, Tensor? s_aux, Tensor? "
|
||||||
|
"dynamic_causal, "
|
||||||
"float k_scale=1.0, float v_scale=1.0, str kv_cache_dtype=\"auto\") -> "
|
"float k_scale=1.0, float v_scale=1.0, str kv_cache_dtype=\"auto\") -> "
|
||||||
"()",
|
"()",
|
||||||
&cpu_attention_with_kv_cache);
|
&cpu_attention_with_kv_cache);
|
||||||
|
|||||||
+3
-1
@@ -8,13 +8,15 @@
|
|||||||
#include "cpu/cpu_types.hpp"
|
#include "cpu/cpu_types.hpp"
|
||||||
|
|
||||||
namespace cpu_utils {
|
namespace cpu_utils {
|
||||||
enum class ISA { AMX, VEC };
|
enum class ISA { AMX, VEC, RVV };
|
||||||
|
|
||||||
inline ISA get_isa(const std::string& isa) {
|
inline ISA get_isa(const std::string& isa) {
|
||||||
if (isa == "amx") {
|
if (isa == "amx") {
|
||||||
return ISA::AMX;
|
return ISA::AMX;
|
||||||
} else if (isa == "vec") {
|
} else if (isa == "vec") {
|
||||||
return ISA::VEC;
|
return ISA::VEC;
|
||||||
|
} else if (isa == "rvv") {
|
||||||
|
return ISA::RVV;
|
||||||
} else {
|
} else {
|
||||||
TORCH_CHECK(false, "Invalid isa type: " + isa);
|
TORCH_CHECK(false, "Invalid isa type: " + isa);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,8 +136,12 @@ typename T::Fmha::Arguments args_from_options(
|
|||||||
StrideQ stride_Q_pe = cute::make_tuple(
|
StrideQ stride_Q_pe = cute::make_tuple(
|
||||||
static_cast<int64_t>(q_pe.stride(1)), _1{}, static_cast<int64_t>(q_pe.stride(0)));
|
static_cast<int64_t>(q_pe.stride(1)), _1{}, static_cast<int64_t>(q_pe.stride(0)));
|
||||||
|
|
||||||
|
// Read the token and page strides from the cache tensor instead of assuming
|
||||||
|
// packed pages, so strided views (e.g. per-layer views into a cross-layer
|
||||||
|
// block-major cache) are addressed correctly.
|
||||||
StrideK stride_C = cute::make_tuple(
|
StrideK stride_C = cute::make_tuple(
|
||||||
static_cast<int64_t>(0 + D_latent + D_rope), _1{}, static_cast<int64_t>(page_size * (D_latent + D_rope)));
|
static_cast<int64_t>(kv_c_and_k_pe_cache.stride(1)), _1{},
|
||||||
|
static_cast<int64_t>(kv_c_and_k_pe_cache.stride(0)));
|
||||||
StrideLSE stride_PT = cute::make_stride(_1{}, page_count_per_seq);
|
StrideLSE stride_PT = cute::make_stride(_1{}, page_count_per_seq);
|
||||||
StrideLSE stride_LSE = cute::make_tuple(_1{}, 0 + H);
|
StrideLSE stride_LSE = cute::make_tuple(_1{}, 0 + H);
|
||||||
StrideO stride_O = cute::make_tuple(static_cast<int64_t>(0 + D_latent), _1{}, static_cast<int64_t>(0 + H * D_latent));
|
StrideO stride_O = cute::make_tuple(static_cast<int64_t>(0 + D_latent), _1{}, static_cast<int64_t>(0 + H * D_latent));
|
||||||
@@ -268,9 +272,14 @@ int64_t sm100_cutlass_mla_get_workspace_size(int64_t max_seq_len, int64_t num_ba
|
|||||||
using TileShapeD = typename MlaSm100Type::TileShapeD;
|
using TileShapeD = typename MlaSm100Type::TileShapeD;
|
||||||
arguments.problem_shape =
|
arguments.problem_shape =
|
||||||
cute::make_tuple(TileShapeH{}, static_cast<int>(max_seq_len), TileShapeD{}, static_cast<int>(num_batches));
|
cute::make_tuple(TileShapeH{}, static_cast<int>(max_seq_len), TileShapeD{}, static_cast<int>(num_batches));
|
||||||
// Assumes device 0 when getting sm_count.
|
if (sm_count <= 0) {
|
||||||
arguments.hw_info.sm_count =
|
int current_device = 0;
|
||||||
sm_count <= 0 ? cutlass::KernelHardwareInfo::query_device_multiprocessor_count(/*device_id=*/0) : sm_count;
|
cudaGetDevice(¤t_device);
|
||||||
|
arguments.hw_info.sm_count =
|
||||||
|
cutlass::KernelHardwareInfo::query_device_multiprocessor_count(current_device);
|
||||||
|
} else {
|
||||||
|
arguments.hw_info.sm_count = sm_count;
|
||||||
|
}
|
||||||
arguments.split_kv = static_cast<int>(num_kv_splits);
|
arguments.split_kv = static_cast<int>(num_kv_splits);
|
||||||
MlaSm100Type::Fmha::set_split_kv(arguments);
|
MlaSm100Type::Fmha::set_split_kv(arguments);
|
||||||
|
|
||||||
|
|||||||
@@ -549,7 +549,7 @@ __global__ void indexer_k_quant_and_cache_kernel(
|
|||||||
const int head_dim, // dimension of each head
|
const int head_dim, // dimension of each head
|
||||||
const int quant_block_size, // quantization block size
|
const int quant_block_size, // quantization block size
|
||||||
const int cache_block_size, // cache block size
|
const int cache_block_size, // cache block size
|
||||||
const int cache_stride, // stride for each token in kv_cache
|
const int64_t cache_block_stride, // stride for each block in kv_cache
|
||||||
|
|
||||||
const bool use_ue8m0 // use ue8m0 scale format
|
const bool use_ue8m0 // use ue8m0 scale format
|
||||||
) {
|
) {
|
||||||
@@ -590,16 +590,15 @@ __global__ void indexer_k_quant_and_cache_kernel(
|
|||||||
scale = exp2f(ceilf(log2f(scale)));
|
scale = exp2f(ceilf(log2f(scale)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const int64_t dst_offset = block_idx * cache_block_size * cache_stride +
|
const int64_t dst_offset =
|
||||||
block_offset * head_dim + head_dim_idx;
|
block_idx * cache_block_stride + block_offset * head_dim + head_dim_idx;
|
||||||
for (int i = 0; i < VEC_SIZE; i++) {
|
for (int i = 0; i < VEC_SIZE; i++) {
|
||||||
kv_cache[dst_offset + i] =
|
kv_cache[dst_offset + i] =
|
||||||
fp8::scaled_convert<cache_t, scalar_t, kv_dt>(k_val_ptr[i], scale);
|
fp8::scaled_convert<cache_t, scalar_t, kv_dt>(k_val_ptr[i], scale);
|
||||||
}
|
}
|
||||||
if (threadIdx.x == 0) {
|
if (threadIdx.x == 0) {
|
||||||
const int64_t dst_scale_idx =
|
const int64_t dst_scale_idx =
|
||||||
block_idx * cache_block_size * cache_stride +
|
block_idx * cache_block_stride + cache_block_size * head_dim +
|
||||||
cache_block_size * head_dim +
|
|
||||||
(block_offset * head_dim + head_dim_idx) * 4 / quant_block_size;
|
(block_offset * head_dim + head_dim_idx) * 4 / quant_block_size;
|
||||||
reinterpret_cast<float*>(kv_cache)[dst_scale_idx / 4] = scale;
|
reinterpret_cast<float*>(kv_cache)[dst_scale_idx / 4] = scale;
|
||||||
}
|
}
|
||||||
@@ -1452,7 +1451,7 @@ void cp_gather_and_upconvert_fp8_kv_cache(
|
|||||||
reinterpret_cast<KV_T*>(k.data_ptr()), \
|
reinterpret_cast<KV_T*>(k.data_ptr()), \
|
||||||
reinterpret_cast<CACHE_T*>(kv_cache.data_ptr()), \
|
reinterpret_cast<CACHE_T*>(kv_cache.data_ptr()), \
|
||||||
slot_mapping.const_data_ptr<int64_t>(), head_dim, quant_block_size, \
|
slot_mapping.const_data_ptr<int64_t>(), head_dim, quant_block_size, \
|
||||||
cache_block_size, cache_stride, use_ue8m0);
|
cache_block_size, cache_block_stride, use_ue8m0);
|
||||||
|
|
||||||
void indexer_k_quant_and_cache(
|
void indexer_k_quant_and_cache(
|
||||||
torch::stable::Tensor& k, // [num_tokens, head_dim]
|
torch::stable::Tensor& k, // [num_tokens, head_dim]
|
||||||
@@ -1463,7 +1462,7 @@ void indexer_k_quant_and_cache(
|
|||||||
int num_tokens = k.size(0);
|
int num_tokens = k.size(0);
|
||||||
int head_dim = k.size(1);
|
int head_dim = k.size(1);
|
||||||
int cache_block_size = kv_cache.size(1);
|
int cache_block_size = kv_cache.size(1);
|
||||||
int cache_stride = kv_cache.size(2);
|
int64_t cache_block_stride = kv_cache.stride(0);
|
||||||
bool use_ue8m0 = scale_fmt == "ue8m0";
|
bool use_ue8m0 = scale_fmt == "ue8m0";
|
||||||
|
|
||||||
STD_TORCH_CHECK(k.device() == kv_cache.device(),
|
STD_TORCH_CHECK(k.device() == kv_cache.device(),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
* ROPE_DIM = 64 (RoPE applied to dims [NOPE_DIM, HEAD_DIM))
|
* ROPE_DIM = 64 (RoPE applied to dims [NOPE_DIM, HEAD_DIM))
|
||||||
* NOPE_DIM = 448
|
* NOPE_DIM = 448
|
||||||
* QUANT_BLOCK = 64 (UE8M0 FP8 quant block)
|
* QUANT_BLOCK = 64 (UE8M0 FP8 quant block)
|
||||||
* FP8_MAX = 448.0f
|
* FP8_MAX = 224.0f on ROCm FNUZ / 448.0f on OCP
|
||||||
* is_neox=false (GPT-J interleaved pairs)
|
* is_neox=false (GPT-J interleaved pairs)
|
||||||
* cos_sin_cache layout [max_pos, rope_dim] = cos || sin (cos first, sin
|
* cos_sin_cache layout [max_pos, rope_dim] = cos || sin (cos first, sin
|
||||||
* second along last dim; each half is rope_dim/2 = 32 values)
|
* second along last dim; each half is rope_dim/2 = 32 values)
|
||||||
@@ -61,10 +61,11 @@
|
|||||||
#ifdef USE_ROCM
|
#ifdef USE_ROCM
|
||||||
// ROCm-compatible FP8 conversion helpers
|
// ROCm-compatible FP8 conversion helpers
|
||||||
__device__ __forceinline__ uint8_t rocm_cvt_float_to_fp8_e4m3(float val) {
|
__device__ __forceinline__ uint8_t rocm_cvt_float_to_fp8_e4m3(float val) {
|
||||||
#if defined(HIP_FP8_TYPE_OCP)
|
// gfx942 uses FNUZ FP8; other ROCm targets use OCP E4M3.
|
||||||
__hip_fp8_e4m3 fp8_val(val);
|
#if defined(__gfx942__)
|
||||||
#else
|
|
||||||
__hip_fp8_e4m3_fnuz fp8_val(val);
|
__hip_fp8_e4m3_fnuz fp8_val(val);
|
||||||
|
#else
|
||||||
|
__hip_fp8_e4m3 fp8_val(val);
|
||||||
#endif
|
#endif
|
||||||
return reinterpret_cast<uint8_t&>(fp8_val);
|
return reinterpret_cast<uint8_t&>(fp8_val);
|
||||||
}
|
}
|
||||||
@@ -90,7 +91,13 @@ constexpr int kQuantBlock = 64;
|
|||||||
constexpr int kNumQuantBlocks = kNopeDim / kQuantBlock; // 7
|
constexpr int kNumQuantBlocks = kNopeDim / kQuantBlock; // 7
|
||||||
constexpr int kScaleBytesPerToken = kNumQuantBlocks + 1; // 8 (7 real + 1 pad)
|
constexpr int kScaleBytesPerToken = kNumQuantBlocks + 1; // 8 (7 real + 1 pad)
|
||||||
constexpr int kTokenDataBytes = kNopeDim + kRopeDim * 2; // 448 + 128 = 576
|
constexpr int kTokenDataBytes = kNopeDim + kRopeDim * 2; // 448 + 128 = 576
|
||||||
|
// FNUZ on gfx942 / OCP elsewhere. FNUZ uses 224.0 (not the dtype's raw
|
||||||
|
// 240.0) to match the rest of vLLM's FNUZ pipeline.
|
||||||
|
#if defined(USE_ROCM) && defined(__gfx942__)
|
||||||
|
constexpr float kFp8Max = 224.0f;
|
||||||
|
#else
|
||||||
constexpr float kFp8Max = 448.0f;
|
constexpr float kFp8Max = 448.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef USE_ROCM
|
#ifndef USE_ROCM
|
||||||
// When num_tokens is less than this threshold,
|
// When num_tokens is less than this threshold,
|
||||||
|
|||||||
@@ -58,8 +58,15 @@
|
|||||||
|
|
||||||
#include "../cuda_compat.h"
|
#include "../cuda_compat.h"
|
||||||
#include "../type_convert.cuh"
|
#include "../type_convert.cuh"
|
||||||
|
#include "../attention/dtype_fp8.cuh"
|
||||||
#include "dispatch_utils.h"
|
#include "dispatch_utils.h"
|
||||||
|
|
||||||
|
#ifdef USE_ROCM
|
||||||
|
#include "../quantization/w8a8/fp8/amd/quant_utils.cuh"
|
||||||
|
#else
|
||||||
|
#include "../quantization/w8a8/fp8/nvidia/quant_utils.cuh"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FINAL_MASK
|
#ifndef FINAL_MASK
|
||||||
#ifdef USE_ROCM
|
#ifdef USE_ROCM
|
||||||
#define FINAL_MASK 0xffffffffffffffffULL
|
#define FINAL_MASK 0xffffffffffffffffULL
|
||||||
@@ -186,6 +193,21 @@ __device__ __forceinline__ void storeElems(
|
|||||||
*reinterpret_cast<uint2*>(dst) = v;
|
*reinterpret_cast<uint2*>(dst) = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename scalar_t, typename cache_t, Fp8KVCacheDataType kv_dt>
|
||||||
|
__device__ __forceinline__ void storeCacheElems(
|
||||||
|
cache_t* __restrict__ dst, float const (&elems)[kElemsPerLane]) {
|
||||||
|
if constexpr (kv_dt == Fp8KVCacheDataType::kAuto) {
|
||||||
|
// kAuto means unquantized KV cache here: cache_t == scalar_t, so store the
|
||||||
|
// model dtype directly. FP8 cache dtypes use the conversion path below.
|
||||||
|
storeElems<scalar_t>(reinterpret_cast<scalar_t*>(dst), elems);
|
||||||
|
} else {
|
||||||
|
#pragma unroll
|
||||||
|
for (int i = 0; i < kElemsPerLane; i++) {
|
||||||
|
dst[i] = fp8::scaled_convert<cache_t, float, kv_dt>(elems[i], 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
// Kernel
|
// Kernel
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
@@ -202,7 +224,8 @@ __device__ __forceinline__ void storeElems(
|
|||||||
// V : nkv only if kInsertKV (V-cache insert; no warps in dense)
|
// V : nkv only if kInsertKV (V-cache insert; no warps in dense)
|
||||||
// IQ: niq only if kIsSparse (norm+RoPE)
|
// IQ: niq only if kIsSparse (norm+RoPE)
|
||||||
// IK: 1 only if kIsSparse (norm+RoPE; +index-cache insert)
|
// IK: 1 only if kIsSparse (norm+RoPE; +index-cache insert)
|
||||||
template <typename scalar_t, bool kIsSparse, bool kInsertKV>
|
template <typename scalar_t, typename cache_t, Fp8KVCacheDataType kv_dt,
|
||||||
|
bool kIsSparse, bool kInsertKV>
|
||||||
__global__ void fusedMiniMaxM3QNormRopeKVInsertKernel(
|
__global__ void fusedMiniMaxM3QNormRopeKVInsertKernel(
|
||||||
scalar_t* __restrict__ qkv, // [N, qkv_row] in/out (packs index if sparse)
|
scalar_t* __restrict__ qkv, // [N, qkv_row] in/out (packs index if sparse)
|
||||||
scalar_t* __restrict__ q_out, // [N, nq*128] contiguous, or nullptr
|
scalar_t* __restrict__ q_out, // [N, nq*128] contiguous, or nullptr
|
||||||
@@ -215,7 +238,7 @@ __global__ void fusedMiniMaxM3QNormRopeKVInsertKernel(
|
|||||||
int64_t const* __restrict__ positions, // [N] i64
|
int64_t const* __restrict__ positions, // [N] i64
|
||||||
int64_t const* __restrict__ slot_mapping, // main K/V slots or nullptr
|
int64_t const* __restrict__ slot_mapping, // main K/V slots or nullptr
|
||||||
int64_t const* __restrict__ index_slot_mapping, // index K slots/nullptr
|
int64_t const* __restrict__ index_slot_mapping, // index K slots/nullptr
|
||||||
scalar_t* __restrict__ kv_cache, // [nb,2,bs,nkv,128] or nullptr
|
cache_t* __restrict__ kv_cache, // [nb,2,bs,nkv,128] or nullptr
|
||||||
scalar_t* __restrict__ index_cache, // [nb*bs, 128] or nullptr
|
scalar_t* __restrict__ index_cache, // [nb*bs, 128] or nullptr
|
||||||
float const eps, int const rotary_dim, int const num_tokens, int const nq,
|
float const eps, int const rotary_dim, int const num_tokens, int const nq,
|
||||||
int const nkv, int const niq, int const block_size,
|
int const nkv, int const niq, int const block_size,
|
||||||
@@ -355,7 +378,8 @@ __global__ void fusedMiniMaxM3QNormRopeKVInsertKernel(
|
|||||||
int const kv = isK ? 0 : 1;
|
int const kv = isK ? 0 : 1;
|
||||||
int64_t const off =
|
int64_t const off =
|
||||||
b * kv_s_block + kv * kv_s_kv + t * kv_s_token + head * kv_s_head;
|
b * kv_s_block + kv * kv_s_kv + t * kv_s_token + head * kv_s_head;
|
||||||
storeElems<scalar_t>(kv_cache + off + dim_base, elems);
|
storeCacheElems<scalar_t, cache_t, kv_dt>(kv_cache + off + dim_base,
|
||||||
|
elems);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,13 +397,13 @@ __global__ void fusedMiniMaxM3QNormRopeKVInsertKernel(
|
|||||||
// ────────────────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
// Launch wrapper
|
// Launch wrapper
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
template <typename scalar_t>
|
template <typename scalar_t, typename cache_t, Fp8KVCacheDataType kv_dt>
|
||||||
void launchFusedMiniMaxM3(scalar_t* qkv, scalar_t* q_out, scalar_t* index_q_out,
|
void launchFusedMiniMaxM3(scalar_t* qkv, scalar_t* q_out, scalar_t* index_q_out,
|
||||||
scalar_t const* q_norm_w, scalar_t const* k_norm_w,
|
scalar_t const* q_norm_w, scalar_t const* k_norm_w,
|
||||||
scalar_t const* iq_norm_w, scalar_t const* ik_norm_w,
|
scalar_t const* iq_norm_w, scalar_t const* ik_norm_w,
|
||||||
scalar_t const* cos_sin_cache,
|
scalar_t const* cos_sin_cache,
|
||||||
int64_t const* positions, int64_t const* slot_mapping,
|
int64_t const* positions, int64_t const* slot_mapping,
|
||||||
int64_t const* index_slot_mapping, scalar_t* kv_cache,
|
int64_t const* index_slot_mapping, cache_t* kv_cache,
|
||||||
scalar_t* index_cache, float const eps,
|
scalar_t* index_cache, float const eps,
|
||||||
int const rotary_dim, int const num_tokens,
|
int const rotary_dim, int const num_tokens,
|
||||||
int const nq, int const nkv, int const niq,
|
int const nq, int const nkv, int const niq,
|
||||||
@@ -419,7 +443,8 @@ void launchFusedMiniMaxM3(scalar_t* qkv, scalar_t* q_out, scalar_t* index_q_out,
|
|||||||
#define LAUNCH(IS_SPARSE, INSERT) \
|
#define LAUNCH(IS_SPARSE, INSERT) \
|
||||||
cudaLaunchKernelEx( \
|
cudaLaunchKernelEx( \
|
||||||
&config, \
|
&config, \
|
||||||
fusedMiniMaxM3QNormRopeKVInsertKernel<scalar_t, IS_SPARSE, INSERT>, \
|
fusedMiniMaxM3QNormRopeKVInsertKernel<scalar_t, cache_t, kv_dt, \
|
||||||
|
IS_SPARSE, INSERT>, \
|
||||||
qkv, q_out, index_q_out, q_norm_w, k_norm_w, iq_norm_w, ik_norm_w, \
|
qkv, q_out, index_q_out, q_norm_w, k_norm_w, iq_norm_w, ik_norm_w, \
|
||||||
cos_sin_cache, positions, slot_mapping, index_slot_mapping, kv_cache, \
|
cos_sin_cache, positions, slot_mapping, index_slot_mapping, kv_cache, \
|
||||||
index_cache, eps, rotary_dim, num_tokens, nq, nkv, niq, block_size, \
|
index_cache, eps, rotary_dim, num_tokens, nq, nkv, niq, block_size, \
|
||||||
@@ -428,7 +453,8 @@ void launchFusedMiniMaxM3(scalar_t* qkv, scalar_t* q_out, scalar_t* index_q_out,
|
|||||||
// ROCm: standard kernel launch syntax (no PDL/stream serialization).
|
// ROCm: standard kernel launch syntax (no PDL/stream serialization).
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#define LAUNCH(IS_SPARSE, INSERT) \
|
#define LAUNCH(IS_SPARSE, INSERT) \
|
||||||
fusedMiniMaxM3QNormRopeKVInsertKernel<scalar_t, IS_SPARSE, INSERT> \
|
fusedMiniMaxM3QNormRopeKVInsertKernel<scalar_t, cache_t, kv_dt, \
|
||||||
|
IS_SPARSE, INSERT> \
|
||||||
<<<grid, kBlockSize, 0, stream>>>( \
|
<<<grid, kBlockSize, 0, stream>>>( \
|
||||||
qkv, q_out, index_q_out, q_norm_w, k_norm_w, iq_norm_w, \
|
qkv, q_out, index_q_out, q_norm_w, k_norm_w, iq_norm_w, \
|
||||||
ik_norm_w, cos_sin_cache, positions, slot_mapping, \
|
ik_norm_w, cos_sin_cache, positions, slot_mapping, \
|
||||||
@@ -455,6 +481,33 @@ void launchFusedMiniMaxM3(scalar_t* qkv, scalar_t* q_out, scalar_t* index_q_out,
|
|||||||
} // namespace minimax_m3_fused_ops
|
} // namespace minimax_m3_fused_ops
|
||||||
} // namespace vllm
|
} // namespace vllm
|
||||||
|
|
||||||
|
#define CALL_FUSED_MINIMAX_M3(_RAW_T, CACHE_T, KV_DTYPE) \
|
||||||
|
vllm::minimax_m3_fused_ops::launchFusedMiniMaxM3<st, CACHE_T, KV_DTYPE>( \
|
||||||
|
reinterpret_cast<st*>(qkv.data_ptr()), \
|
||||||
|
q_out.has_value() ? reinterpret_cast<st*>(q_out->data_ptr()) : nullptr, \
|
||||||
|
index_q_out.has_value() ? reinterpret_cast<st*>(index_q_out->data_ptr()) \
|
||||||
|
: nullptr, \
|
||||||
|
reinterpret_cast<st const*>(q_norm_weight.data_ptr()), \
|
||||||
|
reinterpret_cast<st const*>(k_norm_weight.data_ptr()), \
|
||||||
|
has_index ? reinterpret_cast<st const*>(index_q_norm_weight->data_ptr()) \
|
||||||
|
: nullptr, \
|
||||||
|
has_index ? reinterpret_cast<st const*>(index_k_norm_weight->data_ptr()) \
|
||||||
|
: nullptr, \
|
||||||
|
reinterpret_cast<st const*>(cos_sin_cache.data_ptr()), \
|
||||||
|
reinterpret_cast<int64_t const*>(positions.data_ptr()), \
|
||||||
|
insert_kv ? reinterpret_cast<int64_t const*>(slot_mapping->data_ptr()) \
|
||||||
|
: nullptr, \
|
||||||
|
insert_kv ? reinterpret_cast<int64_t const*>( \
|
||||||
|
effective_index_slot_mapping->data_ptr()) \
|
||||||
|
: nullptr, \
|
||||||
|
insert_kv ? reinterpret_cast<CACHE_T*>(kv_cache->data_ptr()) : nullptr, \
|
||||||
|
(insert_kv && has_index) \
|
||||||
|
? reinterpret_cast<st*>(index_cache->data_ptr()) \
|
||||||
|
: nullptr, \
|
||||||
|
static_cast<float>(eps), static_cast<int>(rotary_dim), num_tokens, nq, \
|
||||||
|
nkv, niq, static_cast<int>(block_size), kv_s_block, kv_s_kv, kv_s_token, \
|
||||||
|
kv_s_head, has_index, insert_kv, stream)
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
// Torch op wrapper
|
// Torch op wrapper
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
@@ -475,9 +528,14 @@ void fused_minimax_m3_qknorm_rope_kv_insert(
|
|||||||
int64_t block_size,
|
int64_t block_size,
|
||||||
std::optional<torch::stable::Tensor> q_out, // [N, nq*128] contiguous
|
std::optional<torch::stable::Tensor> q_out, // [N, nq*128] contiguous
|
||||||
std::optional<torch::stable::Tensor>
|
std::optional<torch::stable::Tensor>
|
||||||
index_q_out) { // [N, niq*128] contiguous
|
index_q_out, // [N, niq*128] contiguous
|
||||||
|
const std::string& kv_cache_dtype) {
|
||||||
STD_TORCH_CHECK(qkv.is_cuda() && qkv.is_contiguous(),
|
STD_TORCH_CHECK(qkv.is_cuda() && qkv.is_contiguous(),
|
||||||
"qkv must be contiguous CUDA");
|
"qkv must be contiguous CUDA");
|
||||||
|
STD_TORCH_CHECK(
|
||||||
|
qkv.scalar_type() == torch::headeronly::ScalarType::Half ||
|
||||||
|
qkv.scalar_type() == torch::headeronly::ScalarType::BFloat16,
|
||||||
|
"qkv must be float16 or bfloat16");
|
||||||
STD_TORCH_CHECK(
|
STD_TORCH_CHECK(
|
||||||
positions.is_cuda() &&
|
positions.is_cuda() &&
|
||||||
positions.scalar_type() == torch::headeronly::ScalarType::Long,
|
positions.scalar_type() == torch::headeronly::ScalarType::Long,
|
||||||
@@ -510,6 +568,8 @@ void fused_minimax_m3_qknorm_rope_kv_insert(
|
|||||||
// (1 head)]) right after [q|k|v] in the same row; the dense layer does not.
|
// (1 head)]) right after [q|k|v] in the same row; the dense layer does not.
|
||||||
bool const has_index = niq > 0;
|
bool const has_index = niq > 0;
|
||||||
bool const insert_kv = kv_cache.has_value();
|
bool const insert_kv = kv_cache.has_value();
|
||||||
|
vllm::Fp8KVCacheDataType const kv_dt =
|
||||||
|
vllm::get_fp8_kv_cache_data_type(kv_cache_dtype);
|
||||||
int const kHeadDim = vllm::minimax_m3_fused_ops::kHeadDim;
|
int const kHeadDim = vllm::minimax_m3_fused_ops::kHeadDim;
|
||||||
int const expected_row =
|
int const expected_row =
|
||||||
(nq + 2 * nkv + (has_index ? niq + 1 : 0)) * kHeadDim;
|
(nq + 2 * nkv + (has_index ? niq + 1 : 0)) * kHeadDim;
|
||||||
@@ -552,8 +612,14 @@ void fused_minimax_m3_qknorm_rope_kv_insert(
|
|||||||
torch::headeronly::ScalarType::Long &&
|
torch::headeronly::ScalarType::Long &&
|
||||||
index_slot_mapping->numel() == slot_mapping->numel()),
|
index_slot_mapping->numel() == slot_mapping->numel()),
|
||||||
"index_slot_mapping must be int64 CUDA with slot_mapping length");
|
"index_slot_mapping must be int64 CUDA with slot_mapping length");
|
||||||
STD_TORCH_CHECK(kv_cache->scalar_type() == qkv.scalar_type(),
|
if (kv_dt == vllm::Fp8KVCacheDataType::kAuto) {
|
||||||
"kv_cache dtype must match qkv (bf16 cache only)");
|
STD_TORCH_CHECK(kv_cache->scalar_type() == qkv.scalar_type(),
|
||||||
|
"auto kv_cache dtype must match qkv");
|
||||||
|
} else {
|
||||||
|
STD_TORCH_CHECK(
|
||||||
|
kv_cache->scalar_type() == torch::headeronly::ScalarType::Byte,
|
||||||
|
"fp8 kv_cache must use uint8 storage");
|
||||||
|
}
|
||||||
STD_TORCH_CHECK(index_cache.has_value() &&
|
STD_TORCH_CHECK(index_cache.has_value() &&
|
||||||
index_cache->scalar_type() == qkv.scalar_type(),
|
index_cache->scalar_type() == qkv.scalar_type(),
|
||||||
"insert mode requires matching index_cache");
|
"insert mode requires matching index_cache");
|
||||||
@@ -601,35 +667,9 @@ void fused_minimax_m3_qknorm_rope_kv_insert(
|
|||||||
VLLM_STABLE_DISPATCH_HALF_TYPES(
|
VLLM_STABLE_DISPATCH_HALF_TYPES(
|
||||||
qkv.scalar_type(), "fused_minimax_m3_qknorm_rope_kv_insert", [&] {
|
qkv.scalar_type(), "fused_minimax_m3_qknorm_rope_kv_insert", [&] {
|
||||||
using st = scalar_t;
|
using st = scalar_t;
|
||||||
vllm::minimax_m3_fused_ops::launchFusedMiniMaxM3<st>(
|
DISPATCH_BY_KV_CACHE_DTYPE(qkv.scalar_type(), kv_cache_dtype,
|
||||||
reinterpret_cast<st*>(qkv.data_ptr()),
|
CALL_FUSED_MINIMAX_M3);
|
||||||
q_out.has_value() ? reinterpret_cast<st*>(q_out->data_ptr())
|
|
||||||
: nullptr,
|
|
||||||
index_q_out.has_value()
|
|
||||||
? reinterpret_cast<st*>(index_q_out->data_ptr())
|
|
||||||
: nullptr,
|
|
||||||
reinterpret_cast<st const*>(q_norm_weight.data_ptr()),
|
|
||||||
reinterpret_cast<st const*>(k_norm_weight.data_ptr()),
|
|
||||||
has_index
|
|
||||||
? reinterpret_cast<st const*>(index_q_norm_weight->data_ptr())
|
|
||||||
: nullptr,
|
|
||||||
has_index
|
|
||||||
? reinterpret_cast<st const*>(index_k_norm_weight->data_ptr())
|
|
||||||
: nullptr,
|
|
||||||
reinterpret_cast<st const*>(cos_sin_cache.data_ptr()),
|
|
||||||
reinterpret_cast<int64_t const*>(positions.data_ptr()),
|
|
||||||
insert_kv
|
|
||||||
? reinterpret_cast<int64_t const*>(slot_mapping->data_ptr())
|
|
||||||
: nullptr,
|
|
||||||
insert_kv ? reinterpret_cast<int64_t const*>(
|
|
||||||
effective_index_slot_mapping->data_ptr())
|
|
||||||
: nullptr,
|
|
||||||
insert_kv ? reinterpret_cast<st*>(kv_cache->data_ptr()) : nullptr,
|
|
||||||
(insert_kv && has_index)
|
|
||||||
? reinterpret_cast<st*>(index_cache->data_ptr())
|
|
||||||
: nullptr,
|
|
||||||
static_cast<float>(eps), static_cast<int>(rotary_dim), num_tokens,
|
|
||||||
nq, nkv, niq, static_cast<int>(block_size), kv_s_block, kv_s_kv,
|
|
||||||
kv_s_token, kv_s_head, has_index, insert_kv, stream);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef CALL_FUSED_MINIMAX_M3
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
namespace vllm {
|
namespace vllm {
|
||||||
|
|
||||||
// TODO(woosuk): Further optimize this kernel.
|
// TODO(woosuk): Further optimize this kernel.
|
||||||
template <typename scalar_t, int VEC_SIZE, int NUM_DIMS>
|
template <typename scalar_t, int VEC_SIZE, int NUM_DIMS, bool HasWeight>
|
||||||
__global__ void rms_norm_kernel(
|
__global__ void rms_norm_kernel(
|
||||||
scalar_t* __restrict__ out, // [..., hidden_size]
|
scalar_t* __restrict__ out, // [..., hidden_size]
|
||||||
const scalar_t* __restrict__ input, // [..., hidden_size]
|
const scalar_t* __restrict__ input, // [..., hidden_size]
|
||||||
@@ -20,7 +20,7 @@ __global__ void rms_norm_kernel(
|
|||||||
const int64_t input_stride_d4, // input.stride(-4)
|
const int64_t input_stride_d4, // input.stride(-4)
|
||||||
const int64_t input_shape_d2, // input.size(-2)
|
const int64_t input_shape_d2, // input.size(-2)
|
||||||
const int64_t input_shape_d3, // input.size(-3)
|
const int64_t input_shape_d3, // input.size(-3)
|
||||||
const scalar_t* __restrict__ weight, // [hidden_size]
|
const scalar_t* __restrict__ weight, // [hidden_size], null if !HasWeight
|
||||||
const float epsilon, const int num_tokens, const int hidden_size) {
|
const float epsilon, const int num_tokens, const int hidden_size) {
|
||||||
__shared__ float s_variance;
|
__shared__ float s_variance;
|
||||||
float variance = 0.0f;
|
float variance = 0.0f;
|
||||||
@@ -74,11 +74,19 @@ __global__ void rms_norm_kernel(
|
|||||||
for (int i = threadIdx.x; i < hidden_size / VEC_SIZE; i += blockDim.x) {
|
for (int i = threadIdx.x; i < hidden_size / VEC_SIZE; i += blockDim.x) {
|
||||||
vec_n_t<scalar_t, VEC_SIZE> dst;
|
vec_n_t<scalar_t, VEC_SIZE> dst;
|
||||||
vec_n_t<scalar_t, VEC_SIZE> src1 = v_in[i];
|
vec_n_t<scalar_t, VEC_SIZE> src1 = v_in[i];
|
||||||
vec_n_t<scalar_t, VEC_SIZE> src2 = v_w[i];
|
vec_n_t<scalar_t, VEC_SIZE> src2;
|
||||||
|
if constexpr (HasWeight) {
|
||||||
|
src2 = v_w[i];
|
||||||
|
}
|
||||||
#pragma unroll
|
#pragma unroll
|
||||||
for (int j = 0; j < VEC_SIZE; j++) {
|
for (int j = 0; j < VEC_SIZE; j++) {
|
||||||
float x = static_cast<float>(src1.val[j]);
|
float x = static_cast<float>(src1.val[j]);
|
||||||
dst.val[j] = static_cast<scalar_t>(x * s_variance) * src2.val[j];
|
if constexpr (HasWeight) {
|
||||||
|
float w = static_cast<float>(src2.val[j]);
|
||||||
|
dst.val[j] = static_cast<scalar_t>(x * s_variance * w);
|
||||||
|
} else {
|
||||||
|
dst.val[j] = static_cast<scalar_t>(x * s_variance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
v_out[i] = dst;
|
v_out[i] = dst;
|
||||||
}
|
}
|
||||||
@@ -88,13 +96,13 @@ __global__ void rms_norm_kernel(
|
|||||||
Additional optimizations we can make in this case are
|
Additional optimizations we can make in this case are
|
||||||
packed and vectorized operations, which help with the
|
packed and vectorized operations, which help with the
|
||||||
memory latency bottleneck. */
|
memory latency bottleneck. */
|
||||||
template <typename scalar_t, int width>
|
template <typename scalar_t, int width, bool HasWeight>
|
||||||
__global__ std::enable_if_t<(width > 0) && _typeConvert<scalar_t>::exists>
|
__global__ std::enable_if_t<(width > 0) && _typeConvert<scalar_t>::exists>
|
||||||
fused_add_rms_norm_kernel(
|
fused_add_rms_norm_kernel(
|
||||||
scalar_t* __restrict__ input, // [..., hidden_size]
|
scalar_t* __restrict__ input, // [..., hidden_size]
|
||||||
const int64_t input_stride,
|
const int64_t input_stride,
|
||||||
scalar_t* __restrict__ residual, // [..., hidden_size]
|
scalar_t* __restrict__ residual, // [..., hidden_size]
|
||||||
const scalar_t* __restrict__ weight, // [hidden_size]
|
const scalar_t* __restrict__ weight, // [hidden_size], null if !HasWeight
|
||||||
const float epsilon, const int num_tokens, const int hidden_size) {
|
const float epsilon, const int num_tokens, const int hidden_size) {
|
||||||
// Sanity checks on our vector struct and type-punned pointer arithmetic
|
// Sanity checks on our vector struct and type-punned pointer arithmetic
|
||||||
static_assert(std::is_pod_v<_f16Vec<scalar_t, width>>);
|
static_assert(std::is_pod_v<_f16Vec<scalar_t, width>>);
|
||||||
@@ -136,13 +144,22 @@ fused_add_rms_norm_kernel(
|
|||||||
int id = blockIdx.x * vec_hidden_size + idx;
|
int id = blockIdx.x * vec_hidden_size + idx;
|
||||||
int64_t strided_id = blockIdx.x * vec_input_stride + idx;
|
int64_t strided_id = blockIdx.x * vec_input_stride + idx;
|
||||||
_f16Vec<scalar_t, width> res = residual_v[id];
|
_f16Vec<scalar_t, width> res = residual_v[id];
|
||||||
_f16Vec<scalar_t, width> w = weight_v[idx];
|
|
||||||
_f16Vec<scalar_t, width> out;
|
_f16Vec<scalar_t, width> out;
|
||||||
using Converter = _typeConvert<scalar_t>;
|
using Converter = _typeConvert<scalar_t>;
|
||||||
|
if constexpr (HasWeight) {
|
||||||
|
_f16Vec<scalar_t, width> w = weight_v[idx];
|
||||||
#pragma unroll
|
#pragma unroll
|
||||||
for (int j = 0; j < width; ++j) {
|
for (int j = 0; j < width; ++j) {
|
||||||
float x = Converter::convert(res.data[j]);
|
float x = Converter::convert(res.data[j]);
|
||||||
out.data[j] = Converter::convert(x * s_variance) * w.data[j];
|
float wf = Converter::convert(w.data[j]);
|
||||||
|
out.data[j] = Converter::convert(x * s_variance * wf);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#pragma unroll
|
||||||
|
for (int j = 0; j < width; ++j) {
|
||||||
|
float x = Converter::convert(res.data[j]);
|
||||||
|
out.data[j] = Converter::convert(x * s_variance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
input_v[strided_id] = out;
|
input_v[strided_id] = out;
|
||||||
}
|
}
|
||||||
@@ -151,13 +168,13 @@ fused_add_rms_norm_kernel(
|
|||||||
/* Generic fused_add_rms_norm_kernel
|
/* Generic fused_add_rms_norm_kernel
|
||||||
The width field is not used here but necessary for other specializations.
|
The width field is not used here but necessary for other specializations.
|
||||||
*/
|
*/
|
||||||
template <typename scalar_t, int width>
|
template <typename scalar_t, int width, bool HasWeight>
|
||||||
__global__ std::enable_if_t<(width == 0) || !_typeConvert<scalar_t>::exists>
|
__global__ std::enable_if_t<(width == 0) || !_typeConvert<scalar_t>::exists>
|
||||||
fused_add_rms_norm_kernel(
|
fused_add_rms_norm_kernel(
|
||||||
scalar_t* __restrict__ input, // [..., hidden_size]
|
scalar_t* __restrict__ input, // [..., hidden_size]
|
||||||
const int64_t input_stride,
|
const int64_t input_stride,
|
||||||
scalar_t* __restrict__ residual, // [..., hidden_size]
|
scalar_t* __restrict__ residual, // [..., hidden_size]
|
||||||
const scalar_t* __restrict__ weight, // [hidden_size]
|
const scalar_t* __restrict__ weight, // [hidden_size], null if !HasWeight
|
||||||
const float epsilon, const int num_tokens, const int hidden_size) {
|
const float epsilon, const int num_tokens, const int hidden_size) {
|
||||||
__shared__ float s_variance;
|
__shared__ float s_variance;
|
||||||
float variance = 0.0f;
|
float variance = 0.0f;
|
||||||
@@ -181,23 +198,29 @@ fused_add_rms_norm_kernel(
|
|||||||
|
|
||||||
for (int idx = threadIdx.x; idx < hidden_size; idx += blockDim.x) {
|
for (int idx = threadIdx.x; idx < hidden_size; idx += blockDim.x) {
|
||||||
float x = (float)residual[blockIdx.x * hidden_size + idx];
|
float x = (float)residual[blockIdx.x * hidden_size + idx];
|
||||||
input[blockIdx.x * input_stride + idx] =
|
if constexpr (HasWeight) {
|
||||||
(scalar_t)(x * s_variance) * weight[idx];
|
float w = (float)weight[idx];
|
||||||
|
input[blockIdx.x * input_stride + idx] = (scalar_t)(x * s_variance * w);
|
||||||
|
} else {
|
||||||
|
input[blockIdx.x * input_stride + idx] = (scalar_t)(x * s_variance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vllm
|
} // namespace vllm
|
||||||
|
|
||||||
void rms_norm(torch::stable::Tensor& out, // [..., hidden_size]
|
void rms_norm(torch::stable::Tensor& out, // [..., hidden_size]
|
||||||
torch::stable::Tensor& input, // [..., hidden_size]
|
torch::stable::Tensor& input, // [..., hidden_size]
|
||||||
torch::stable::Tensor& weight, // [hidden_size]
|
std::optional<torch::stable::Tensor> weight, // [hidden_size]
|
||||||
double epsilon) {
|
double epsilon) {
|
||||||
STD_TORCH_CHECK(out.is_contiguous());
|
STD_TORCH_CHECK(out.is_contiguous());
|
||||||
if (input.stride(-1) != 1) {
|
if (input.stride(-1) != 1) {
|
||||||
input = torch::stable::contiguous(input);
|
input = torch::stable::contiguous(input);
|
||||||
}
|
}
|
||||||
STD_TORCH_CHECK(input.stride(-1) == 1);
|
STD_TORCH_CHECK(input.stride(-1) == 1);
|
||||||
STD_TORCH_CHECK(weight.is_contiguous());
|
if (weight.has_value()) {
|
||||||
|
STD_TORCH_CHECK(weight->is_contiguous());
|
||||||
|
}
|
||||||
|
|
||||||
int hidden_size = input.size(-1);
|
int hidden_size = input.size(-1);
|
||||||
|
|
||||||
@@ -215,46 +238,69 @@ void rms_norm(torch::stable::Tensor& out, // [..., hidden_size]
|
|||||||
const torch::stable::accelerator::DeviceGuard device_guard(
|
const torch::stable::accelerator::DeviceGuard device_guard(
|
||||||
input.get_device_index());
|
input.get_device_index());
|
||||||
const cudaStream_t stream = get_current_cuda_stream();
|
const cudaStream_t stream = get_current_cuda_stream();
|
||||||
|
const bool has_weight = weight.has_value();
|
||||||
VLLM_STABLE_DISPATCH_RANK234(num_dims, [&] {
|
VLLM_STABLE_DISPATCH_RANK234(num_dims, [&] {
|
||||||
VLLM_STABLE_DISPATCH_FLOATING_TYPES(
|
VLLM_STABLE_DISPATCH_FLOATING_TYPES(
|
||||||
input.scalar_type(), "rms_norm_kernel", [&] {
|
input.scalar_type(), "rms_norm_kernel", [&] {
|
||||||
|
const scalar_t* weight_ptr =
|
||||||
|
has_weight ? weight->const_data_ptr<scalar_t>() : nullptr;
|
||||||
const int calculated_vec_size =
|
const int calculated_vec_size =
|
||||||
std::gcd(16 / sizeof(scalar_t), hidden_size);
|
std::gcd(16 / sizeof(scalar_t), hidden_size);
|
||||||
const int block_size =
|
const int block_size =
|
||||||
std::min(hidden_size / calculated_vec_size, max_block_size);
|
std::min(hidden_size / calculated_vec_size, max_block_size);
|
||||||
dim3 block(block_size);
|
dim3 block(block_size);
|
||||||
VLLM_STABLE_DISPATCH_VEC_SIZE(calculated_vec_size, [&] {
|
VLLM_STABLE_DISPATCH_VEC_SIZE(calculated_vec_size, [&] {
|
||||||
vllm::rms_norm_kernel<scalar_t, vec_size, tensor_rank>
|
if (has_weight) {
|
||||||
<<<grid, block, 0, stream>>>(
|
vllm::rms_norm_kernel<scalar_t, vec_size, tensor_rank, true>
|
||||||
out.mutable_data_ptr<scalar_t>(),
|
<<<grid, block, 0, stream>>>(
|
||||||
input.const_data_ptr<scalar_t>(), input_stride_d2,
|
out.mutable_data_ptr<scalar_t>(),
|
||||||
input_stride_d3, input_stride_d4, input_shape_d2,
|
input.const_data_ptr<scalar_t>(), input_stride_d2,
|
||||||
input_shape_d3, weight.const_data_ptr<scalar_t>(), epsilon,
|
input_stride_d3, input_stride_d4, input_shape_d2,
|
||||||
num_tokens, hidden_size);
|
input_shape_d3, weight_ptr, epsilon, num_tokens,
|
||||||
|
hidden_size);
|
||||||
|
} else {
|
||||||
|
vllm::rms_norm_kernel<scalar_t, vec_size, tensor_rank, false>
|
||||||
|
<<<grid, block, 0, stream>>>(
|
||||||
|
out.mutable_data_ptr<scalar_t>(),
|
||||||
|
input.const_data_ptr<scalar_t>(), input_stride_d2,
|
||||||
|
input_stride_d3, input_stride_d4, input_shape_d2,
|
||||||
|
input_shape_d3, weight_ptr, epsilon, num_tokens,
|
||||||
|
hidden_size);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LAUNCH_FUSED_ADD_RMS_NORM(width) \
|
#define LAUNCH_FUSED_ADD_RMS_NORM(width, has_weight) \
|
||||||
VLLM_STABLE_DISPATCH_FLOATING_TYPES( \
|
VLLM_STABLE_DISPATCH_FLOATING_TYPES( \
|
||||||
input.scalar_type(), "fused_add_rms_norm_kernel", [&] { \
|
input.scalar_type(), "fused_add_rms_norm_kernel", [&] { \
|
||||||
vllm::fused_add_rms_norm_kernel<scalar_t, width> \
|
if (has_weight) { \
|
||||||
<<<grid, block, 0, stream>>>( \
|
vllm::fused_add_rms_norm_kernel<scalar_t, width, true> \
|
||||||
input.mutable_data_ptr<scalar_t>(), input_stride, \
|
<<<grid, block, 0, stream>>>( \
|
||||||
residual.mutable_data_ptr<scalar_t>(), \
|
input.mutable_data_ptr<scalar_t>(), input_stride, \
|
||||||
weight.const_data_ptr<scalar_t>(), epsilon, num_tokens, \
|
residual.mutable_data_ptr<scalar_t>(), \
|
||||||
hidden_size); \
|
weight->const_data_ptr<scalar_t>(), epsilon, num_tokens, \
|
||||||
|
hidden_size); \
|
||||||
|
} else { \
|
||||||
|
vllm::fused_add_rms_norm_kernel<scalar_t, width, false> \
|
||||||
|
<<<grid, block, 0, stream>>>( \
|
||||||
|
input.mutable_data_ptr<scalar_t>(), input_stride, \
|
||||||
|
residual.mutable_data_ptr<scalar_t>(), nullptr, epsilon, \
|
||||||
|
num_tokens, hidden_size); \
|
||||||
|
} \
|
||||||
});
|
});
|
||||||
|
|
||||||
void fused_add_rms_norm(torch::stable::Tensor& input, // [..., hidden_size]
|
void fused_add_rms_norm(torch::stable::Tensor& input, // [..., hidden_size]
|
||||||
torch::stable::Tensor& residual, // [..., hidden_size]
|
torch::stable::Tensor& residual, // [..., hidden_size]
|
||||||
torch::stable::Tensor& weight, // [hidden_size]
|
std::optional<torch::stable::Tensor> weight,
|
||||||
double epsilon) {
|
double epsilon) {
|
||||||
STD_TORCH_CHECK(weight.scalar_type() == input.scalar_type());
|
|
||||||
STD_TORCH_CHECK(input.scalar_type() == residual.scalar_type());
|
STD_TORCH_CHECK(input.scalar_type() == residual.scalar_type());
|
||||||
STD_TORCH_CHECK(residual.is_contiguous());
|
STD_TORCH_CHECK(residual.is_contiguous());
|
||||||
STD_TORCH_CHECK(weight.is_contiguous());
|
if (weight.has_value()) {
|
||||||
|
STD_TORCH_CHECK(weight->scalar_type() == input.scalar_type());
|
||||||
|
STD_TORCH_CHECK(weight->is_contiguous());
|
||||||
|
}
|
||||||
int hidden_size = input.size(-1);
|
int hidden_size = input.size(-1);
|
||||||
int64_t input_stride = input.stride(-2);
|
int64_t input_stride = input.stride(-2);
|
||||||
int num_tokens = input.numel() / hidden_size;
|
int num_tokens = input.numel() / hidden_size;
|
||||||
@@ -269,30 +315,33 @@ void fused_add_rms_norm(torch::stable::Tensor& input, // [..., hidden_size]
|
|||||||
const torch::stable::accelerator::DeviceGuard device_guard(
|
const torch::stable::accelerator::DeviceGuard device_guard(
|
||||||
input.get_device_index());
|
input.get_device_index());
|
||||||
const cudaStream_t stream = get_current_cuda_stream();
|
const cudaStream_t stream = get_current_cuda_stream();
|
||||||
/*If the tensor types are FP16/BF16, try to use the optimized kernel
|
constexpr int vector_width = 8;
|
||||||
with packed + vectorized ops.
|
constexpr int req_alignment_bytes = vector_width * 2;
|
||||||
Max optimization is achieved with a width-8 vector of FP16/BF16s
|
|
||||||
since we can load at most 128 bits at once in a global memory op.
|
|
||||||
However, this requires each tensor's data to be aligned to 16
|
|
||||||
bytes.
|
|
||||||
*/
|
|
||||||
auto inp_ptr = reinterpret_cast<std::uintptr_t>(input.data_ptr());
|
auto inp_ptr = reinterpret_cast<std::uintptr_t>(input.data_ptr());
|
||||||
auto res_ptr = reinterpret_cast<std::uintptr_t>(residual.data_ptr());
|
auto res_ptr = reinterpret_cast<std::uintptr_t>(residual.data_ptr());
|
||||||
auto wt_ptr = reinterpret_cast<std::uintptr_t>(weight.data_ptr());
|
|
||||||
constexpr int vector_width = 8;
|
|
||||||
constexpr int req_alignment_bytes =
|
|
||||||
vector_width * 2; // vector_width * sizeof(bfloat16 or float16) (float32
|
|
||||||
// falls back to non-vectorized version anyway)
|
|
||||||
bool ptrs_are_aligned = inp_ptr % req_alignment_bytes == 0 &&
|
|
||||||
res_ptr % req_alignment_bytes == 0 &&
|
|
||||||
wt_ptr % req_alignment_bytes == 0;
|
|
||||||
bool offsets_are_multiple_of_vector_width =
|
bool offsets_are_multiple_of_vector_width =
|
||||||
hidden_size % vector_width == 0 && input_stride % vector_width == 0;
|
hidden_size % vector_width == 0 && input_stride % vector_width == 0;
|
||||||
bool batch_invariant_launch = vllm::vllm_is_batch_invariant();
|
bool batch_invariant_launch = vllm::vllm_is_batch_invariant();
|
||||||
if (ptrs_are_aligned && offsets_are_multiple_of_vector_width &&
|
const bool has_weight = weight.has_value();
|
||||||
!batch_invariant_launch) {
|
if (has_weight) {
|
||||||
LAUNCH_FUSED_ADD_RMS_NORM(8);
|
auto wt_ptr = reinterpret_cast<std::uintptr_t>(weight->data_ptr());
|
||||||
|
bool ptrs_are_aligned = inp_ptr % req_alignment_bytes == 0 &&
|
||||||
|
res_ptr % req_alignment_bytes == 0 &&
|
||||||
|
wt_ptr % req_alignment_bytes == 0;
|
||||||
|
if (ptrs_are_aligned && offsets_are_multiple_of_vector_width &&
|
||||||
|
!batch_invariant_launch) {
|
||||||
|
LAUNCH_FUSED_ADD_RMS_NORM(8, true);
|
||||||
|
} else {
|
||||||
|
LAUNCH_FUSED_ADD_RMS_NORM(0, true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LAUNCH_FUSED_ADD_RMS_NORM(0);
|
bool ptrs_are_aligned = inp_ptr % req_alignment_bytes == 0 &&
|
||||||
|
res_ptr % req_alignment_bytes == 0;
|
||||||
|
if (ptrs_are_aligned && offsets_are_multiple_of_vector_width &&
|
||||||
|
!batch_invariant_launch) {
|
||||||
|
LAUNCH_FUSED_ADD_RMS_NORM(8, false);
|
||||||
|
} else {
|
||||||
|
LAUNCH_FUSED_ADD_RMS_NORM(0, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,8 +66,13 @@ __global__ void rms_norm_static_fp8_quant_kernel(
|
|||||||
#pragma unroll
|
#pragma unroll
|
||||||
for (int j = 0; j < VEC_SIZE; j++) {
|
for (int j = 0; j < VEC_SIZE; j++) {
|
||||||
float x = static_cast<float>(src1.val[j]);
|
float x = static_cast<float>(src1.val[j]);
|
||||||
// Multiply in weight's native dtype to match rms_norm_kernel.
|
float w = static_cast<float>(src2.val[j]);
|
||||||
scalar_t out_norm = static_cast<scalar_t>(x * s_variance) * src2.val[j];
|
// Round normalized result through scalar_t to match the precision of the
|
||||||
|
// unfused composite (rms_norm writes scalar_t, then
|
||||||
|
// static_scaled_fp8_quant re-loads it as float before FP8 conversion).
|
||||||
|
// Without this round, the fused path is strictly more accurate and
|
||||||
|
// disagrees with the composite at exact E4M3 quantization tie boundaries.
|
||||||
|
scalar_t out_norm = static_cast<scalar_t>(x * s_variance * w);
|
||||||
out[blockIdx.x * hidden_size + idx * VEC_SIZE + j] =
|
out[blockIdx.x * hidden_size + idx * VEC_SIZE + j] =
|
||||||
scaled_fp8_conversion<true, fp8_type>(static_cast<float>(out_norm),
|
scaled_fp8_conversion<true, fp8_type>(static_cast<float>(out_norm),
|
||||||
scale_inv);
|
scale_inv);
|
||||||
@@ -137,8 +142,12 @@ fused_add_rms_norm_static_fp8_quant_kernel(
|
|||||||
#pragma unroll
|
#pragma unroll
|
||||||
for (int i = 0; i < width; ++i) {
|
for (int i = 0; i < width; ++i) {
|
||||||
float x = Converter::convert(res.data[i]);
|
float x = Converter::convert(res.data[i]);
|
||||||
// Multiply in weight's native dtype to match fused_add_rms_norm_kernel.
|
float wf = Converter::convert(w.data[i]);
|
||||||
HipT out_norm_h = Converter::convert(x * s_variance) * w.data[i];
|
// See note in rms_norm_static_fp8_quant_kernel: round through scalar_t
|
||||||
|
// to match the unfused composite path at FP8 boundaries. We use the
|
||||||
|
// backend's hip_type for the intermediate since c10::Half/BFloat16 has
|
||||||
|
// ambiguous conversions on CUDA and no implicit conversion on ROCm.
|
||||||
|
HipT out_norm_h = Converter::convert(x * s_variance * wf);
|
||||||
out[id * width + i] = scaled_fp8_conversion<true, fp8_type>(
|
out[id * width + i] = scaled_fp8_conversion<true, fp8_type>(
|
||||||
Converter::convert(out_norm_h), scale_inv);
|
Converter::convert(out_norm_h), scale_inv);
|
||||||
}
|
}
|
||||||
@@ -183,8 +192,10 @@ fused_add_rms_norm_static_fp8_quant_kernel(
|
|||||||
|
|
||||||
for (int idx = threadIdx.x; idx < hidden_size; idx += blockDim.x) {
|
for (int idx = threadIdx.x; idx < hidden_size; idx += blockDim.x) {
|
||||||
float x = (float)residual[blockIdx.x * hidden_size + idx];
|
float x = (float)residual[blockIdx.x * hidden_size + idx];
|
||||||
// Multiply in weight's native dtype to match fused_add_rms_norm_kernel.
|
float w = (float)weight[idx];
|
||||||
scalar_t out_norm = static_cast<scalar_t>(x * s_variance) * weight[idx];
|
// See note in rms_norm_static_fp8_quant_kernel: round through scalar_t
|
||||||
|
// to match the unfused composite path at FP8 boundaries.
|
||||||
|
scalar_t out_norm = static_cast<scalar_t>(x * s_variance * w);
|
||||||
out[blockIdx.x * hidden_size + idx] = scaled_fp8_conversion<true, fp8_type>(
|
out[blockIdx.x * hidden_size + idx] = scaled_fp8_conversion<true, fp8_type>(
|
||||||
static_cast<float>(out_norm), scale_inv);
|
static_cast<float>(out_norm), scale_inv);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <torch/headeronly/core/ScalarType.h>
|
#include <torch/headeronly/core/ScalarType.h>
|
||||||
|
|
||||||
#include "../../cuda_compat.h"
|
#include "../../cuda_compat.h"
|
||||||
#include "core/math.hpp"
|
#include "libtorch_stable/core/math.hpp"
|
||||||
#include "libtorch_stable/dispatch_utils.h"
|
#include "libtorch_stable/dispatch_utils.h"
|
||||||
#include "libtorch_stable/torch_utils.h"
|
#include "libtorch_stable/torch_utils.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
||||||
// Adapted from SGLang:
|
|
||||||
// https://github.com/sgl-project/sglang/blob/ded068a76e00878881d52d5bfb791e0f60d7311b/sgl-kernel/csrc/expert_specialization/es_sm100_mxfp8_blockscaled.cu
|
|
||||||
|
|
||||||
#include <torch/csrc/stable/library.h>
|
|
||||||
#include <torch/csrc/stable/tensor.h>
|
|
||||||
#include "libtorch_stable/torch_utils.h"
|
|
||||||
|
|
||||||
#include "cutlass_mxfp8_grouped_mm_launcher.cuh"
|
|
||||||
|
|
||||||
void cutlass_mxfp8_grouped_mm(const torch::stable::Tensor& a,
|
|
||||||
const torch::stable::Tensor& b,
|
|
||||||
const torch::stable::Tensor& sfa,
|
|
||||||
const torch::stable::Tensor& sfb,
|
|
||||||
torch::stable::Tensor& d,
|
|
||||||
const torch::stable::Tensor& problem_sizes,
|
|
||||||
const torch::stable::Tensor& expert_offsets,
|
|
||||||
const torch::stable::Tensor& blockscale_offsets) {
|
|
||||||
#if defined(CUTLASS_ARCH_MMA_SM100_SUPPORTED)
|
|
||||||
STD_TORCH_CHECK(problem_sizes.dim() == 2, "problem_sizes must be 2D tensor");
|
|
||||||
STD_TORCH_CHECK(problem_sizes.size(1) == 3,
|
|
||||||
"problem_sizes must have shape (num_experts, 3)");
|
|
||||||
STD_TORCH_CHECK(
|
|
||||||
problem_sizes.size(0) == expert_offsets.size(0),
|
|
||||||
"Number of experts in problem_sizes must match expert_offsets");
|
|
||||||
STD_TORCH_CHECK(
|
|
||||||
problem_sizes.scalar_type() == torch::headeronly::ScalarType::Int,
|
|
||||||
"problem_sizes must be int32");
|
|
||||||
STD_TORCH_CHECK(
|
|
||||||
expert_offsets.scalar_type() == torch::headeronly::ScalarType::Int,
|
|
||||||
"expert_offsets must be int32");
|
|
||||||
STD_TORCH_CHECK(
|
|
||||||
blockscale_offsets.scalar_type() == torch::headeronly::ScalarType::Int,
|
|
||||||
"blockscale_offsets must be int32");
|
|
||||||
STD_TORCH_CHECK(a.dim() == 2,
|
|
||||||
"a must be a 2D tensor of shape (num_tokens, k)");
|
|
||||||
STD_TORCH_CHECK(b.dim() == 3,
|
|
||||||
"b must be a 3D tensor of shape (num_experts, k, n)");
|
|
||||||
STD_TORCH_CHECK(a.size(1) == b.size(1) && a.size(1) % 128 == 0,
|
|
||||||
"k should align 128");
|
|
||||||
STD_TORCH_CHECK(b.size(2) % 128 == 0, "n should align 128");
|
|
||||||
STD_TORCH_CHECK(a.stride(1) == 1, "a must be row major");
|
|
||||||
STD_TORCH_CHECK(b.stride(1) == 1, "b must be column major");
|
|
||||||
|
|
||||||
const torch::stable::accelerator::DeviceGuard device_guard(
|
|
||||||
a.get_device_index());
|
|
||||||
auto stream = get_current_cuda_stream(a.get_device_index());
|
|
||||||
if (d.scalar_type() == torch::headeronly::ScalarType::BFloat16) {
|
|
||||||
expert_specialization::cutlass_mxfp8_grouped_mm_dispatch_out_dtype<
|
|
||||||
cutlass::bfloat16_t>(a, b, sfa, sfb, d, problem_sizes, expert_offsets,
|
|
||||||
blockscale_offsets, stream);
|
|
||||||
} else if (d.scalar_type() == torch::headeronly::ScalarType::Half) {
|
|
||||||
expert_specialization::cutlass_mxfp8_grouped_mm_dispatch_out_dtype<
|
|
||||||
cutlass::half_t>(a, b, sfa, sfb, d, problem_sizes, expert_offsets,
|
|
||||||
blockscale_offsets, stream);
|
|
||||||
} else {
|
|
||||||
STD_TORCH_CHECK(false, "dtype must be kFloat16 or kBFloat16");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
STD_TORCH_CHECK(false,
|
|
||||||
"No implemented cutlass_mxfp8_grouped_mm for "
|
|
||||||
"current device");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
STABLE_TORCH_LIBRARY_IMPL(_C, CUDA, m) {
|
|
||||||
m.impl("cutlass_mxfp8_grouped_mm", TORCH_BOX(&cutlass_mxfp8_grouped_mm));
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
||||||
// Adapted from SGLang:
|
|
||||||
// https://github.com/sgl-project/sglang/blob/ded068a76e00878881d52d5bfb791e0f60d7311b/sgl-kernel/csrc/expert_specialization/es_sm100_mxfp8_blockscaled_functor.cuh
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <cuda.h>
|
|
||||||
|
|
||||||
#include "cute/tensor.hpp"
|
|
||||||
#include "cutlass/util/packed_stride.hpp"
|
|
||||||
#include "cutlass_mxfp8_grouped_mm_traits.cuh"
|
|
||||||
|
|
||||||
namespace expert_specialization {
|
|
||||||
|
|
||||||
using namespace cute;
|
|
||||||
|
|
||||||
template <typename GemmTraits>
|
|
||||||
struct CutlassMxfp8GroupedMmOffsetFunctor {
|
|
||||||
using Gemm = typename GemmTraits::Gemm;
|
|
||||||
using ElementA = typename Gemm::ElementA;
|
|
||||||
using ElementB = typename Gemm::ElementB;
|
|
||||||
using ElementSF = typename GemmTraits::ElementSF;
|
|
||||||
using ElementD = typename GemmTraits::ElementOutput;
|
|
||||||
// Input
|
|
||||||
int* expert_offsets{nullptr};
|
|
||||||
int* blockscale_offsets{nullptr};
|
|
||||||
// Output
|
|
||||||
ElementA* a_base{nullptr};
|
|
||||||
ElementB* b_base{nullptr};
|
|
||||||
ElementSF* sfa_base{nullptr};
|
|
||||||
ElementSF* sfb_base{nullptr};
|
|
||||||
ElementD* d_base{nullptr};
|
|
||||||
ElementA** a_offsets{nullptr};
|
|
||||||
ElementB** b_offsets{nullptr};
|
|
||||||
ElementSF** sfa_offsets{nullptr};
|
|
||||||
ElementSF** sfb_offsets{nullptr};
|
|
||||||
ElementD** d_offsets{nullptr};
|
|
||||||
|
|
||||||
CutlassMxfp8GroupedMmOffsetFunctor() = default;
|
|
||||||
CutlassMxfp8GroupedMmOffsetFunctor(
|
|
||||||
int* _expert_offsets, int* _blockscale_offsets, ElementA* _a_base,
|
|
||||||
ElementB* _b_base, ElementSF* _sfa_base, ElementSF* _sfb_base,
|
|
||||||
ElementD* _d_base, ElementA** _a_offsets, ElementB** _b_offsets,
|
|
||||||
ElementSF** _sfa_offsets, ElementSF** _sfb_offsets, ElementD** _d_offsets)
|
|
||||||
: expert_offsets{_expert_offsets},
|
|
||||||
blockscale_offsets{_blockscale_offsets},
|
|
||||||
a_base(_a_base),
|
|
||||||
b_base(_b_base),
|
|
||||||
sfa_base(_sfa_base),
|
|
||||||
sfb_base(_sfb_base),
|
|
||||||
d_base(_d_base),
|
|
||||||
a_offsets(_a_offsets),
|
|
||||||
b_offsets(_b_offsets),
|
|
||||||
sfa_offsets(_sfa_offsets),
|
|
||||||
sfb_offsets(_sfb_offsets),
|
|
||||||
d_offsets(_d_offsets) {}
|
|
||||||
|
|
||||||
void CUTE_DEVICE operator()(int64_t expert_id, int m, int n, int k) {
|
|
||||||
int64_t expert_offset = static_cast<int64_t>(expert_offsets[expert_id]);
|
|
||||||
int64_t blockscale_offset =
|
|
||||||
static_cast<int64_t>(blockscale_offsets[expert_id]);
|
|
||||||
int64_t a_stride = expert_offset * k;
|
|
||||||
int64_t b_stride = expert_id * k * n;
|
|
||||||
int64_t d_stride = expert_offset * n;
|
|
||||||
int64_t sfa_stride = blockscale_offset * (k / 32);
|
|
||||||
int64_t sfb_stride = expert_id * n * (k / 32);
|
|
||||||
|
|
||||||
a_offsets[expert_id] = a_base + a_stride;
|
|
||||||
b_offsets[expert_id] = b_base + b_stride;
|
|
||||||
sfa_offsets[expert_id] = sfa_base + sfa_stride;
|
|
||||||
sfb_offsets[expert_id] = sfb_base + sfb_stride;
|
|
||||||
d_offsets[expert_id] = d_base + d_stride;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename GemmTraits>
|
|
||||||
struct CutlassMxfp8GroupedMmLayoutFunctor {
|
|
||||||
using Sm1xxBlkScaledConfig = typename GemmTraits::Sm1xxBlkScaledConfig;
|
|
||||||
using LayoutSFA = typename GemmTraits::LayoutSFA;
|
|
||||||
using LayoutSFB = typename GemmTraits::LayoutSFB;
|
|
||||||
LayoutSFA* layout_sfa_base{nullptr};
|
|
||||||
LayoutSFB* layout_sfb_base{nullptr};
|
|
||||||
|
|
||||||
CutlassMxfp8GroupedMmLayoutFunctor() = default;
|
|
||||||
CutlassMxfp8GroupedMmLayoutFunctor(LayoutSFA* _layout_sfa_base,
|
|
||||||
LayoutSFB* _layout_sfb_base)
|
|
||||||
: layout_sfa_base(_layout_sfa_base), layout_sfb_base(_layout_sfb_base) {}
|
|
||||||
|
|
||||||
void CUTE_DEVICE operator()(int64_t expert_id, int m, int n, int k) {
|
|
||||||
LayoutSFA* layout_sfa_ptr = layout_sfa_base + expert_id;
|
|
||||||
LayoutSFB* layout_sfb_ptr = layout_sfb_base + expert_id;
|
|
||||||
*layout_sfa_ptr = Sm1xxBlkScaledConfig::tile_atom_to_shape_SFA(
|
|
||||||
cute::make_shape(m, n, k, 1));
|
|
||||||
*layout_sfb_ptr = Sm1xxBlkScaledConfig::tile_atom_to_shape_SFB(
|
|
||||||
cute::make_shape(m, n, k, 1));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename GemmTraits>
|
|
||||||
struct CutlassMxfp8GroupedMmStrideFunctor {
|
|
||||||
using StrideA = typename GemmTraits::StrideA;
|
|
||||||
using StrideB = typename GemmTraits::StrideB;
|
|
||||||
using StrideD = typename GemmTraits::StrideD;
|
|
||||||
StrideA* stride_A_base{nullptr};
|
|
||||||
StrideB* stride_B_base{nullptr};
|
|
||||||
StrideD* stride_D_base{nullptr};
|
|
||||||
|
|
||||||
CutlassMxfp8GroupedMmStrideFunctor() = default;
|
|
||||||
CutlassMxfp8GroupedMmStrideFunctor(StrideA* _stride_A_base,
|
|
||||||
StrideB* _stride_B_base,
|
|
||||||
StrideD* _stride_D_base)
|
|
||||||
: stride_A_base(_stride_A_base),
|
|
||||||
stride_B_base(_stride_B_base),
|
|
||||||
stride_D_base(_stride_D_base) {}
|
|
||||||
|
|
||||||
void CUTE_DEVICE operator()(int64_t expert_id, int m, int n, int k) {
|
|
||||||
StrideA* stride_A = stride_A_base + expert_id;
|
|
||||||
StrideB* stride_B = stride_B_base + expert_id;
|
|
||||||
StrideD* stride_D = stride_D_base + expert_id;
|
|
||||||
*stride_A = cutlass::make_cute_packed_stride(StrideA{}, {m, k, 1});
|
|
||||||
*stride_B = cutlass::make_cute_packed_stride(StrideB{}, {n, k, 1});
|
|
||||||
*stride_D = cutlass::make_cute_packed_stride(StrideD{}, {m, n, 1});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename OffsetFunctor, typename LayoutFunctor,
|
|
||||||
typename StrideFunctor>
|
|
||||||
__global__ void cutlassMxfp8GroupedMmPreComputeKernel(
|
|
||||||
int* problem_sizes, OffsetFunctor offset_functor,
|
|
||||||
LayoutFunctor layout_functor, StrideFunctor stride_functor) {
|
|
||||||
int64_t expert_id = static_cast<int64_t>(threadIdx.x);
|
|
||||||
int m = problem_sizes[expert_id * 3 + 0];
|
|
||||||
int n = problem_sizes[expert_id * 3 + 1];
|
|
||||||
int k = problem_sizes[expert_id * 3 + 2];
|
|
||||||
|
|
||||||
offset_functor(expert_id, m, n, k);
|
|
||||||
layout_functor(expert_id, m, n, k);
|
|
||||||
stride_functor(expert_id, m, n, k);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace expert_specialization
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
||||||
// Adapted from SGLang:
|
|
||||||
// https://github.com/sgl-project/sglang/blob/ded068a76e00878881d52d5bfb791e0f60d7311b/sgl-kernel/csrc/expert_specialization/es_sm100_mxfp8_blockscaled_launcher.cuh
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <torch/csrc/stable/tensor.h>
|
|
||||||
#include <torch/headeronly/util/Exception.h>
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "cute/tensor.hpp"
|
|
||||||
#include "cutlass_mxfp8_grouped_mm_functor.cuh"
|
|
||||||
#include "cutlass_mxfp8_grouped_mm_traits.cuh"
|
|
||||||
#include "libtorch_stable/torch_utils.h"
|
|
||||||
|
|
||||||
namespace expert_specialization {
|
|
||||||
|
|
||||||
template <typename GemmTraits>
|
|
||||||
void cutlass_mxfp8_grouped_mm_pre_compute(
|
|
||||||
torch::stable::Tensor& a_ptrs, torch::stable::Tensor& b_ptrs,
|
|
||||||
torch::stable::Tensor& sfa_ptrs, torch::stable::Tensor& sfb_ptrs,
|
|
||||||
torch::stable::Tensor& d_ptrs, torch::stable::Tensor& stride_a,
|
|
||||||
torch::stable::Tensor& stride_b, torch::stable::Tensor& stride_d,
|
|
||||||
torch::stable::Tensor& layout_sfa, torch::stable::Tensor& layout_sfb,
|
|
||||||
const torch::stable::Tensor& a, const torch::stable::Tensor& b,
|
|
||||||
const torch::stable::Tensor& sfa, const torch::stable::Tensor& sfb,
|
|
||||||
const torch::stable::Tensor& d, const torch::stable::Tensor& problem_sizes,
|
|
||||||
const torch::stable::Tensor& expert_offsets,
|
|
||||||
const torch::stable::Tensor& blockscale_offsets, cudaStream_t stream) {
|
|
||||||
using OffsetFunctor = CutlassMxfp8GroupedMmOffsetFunctor<GemmTraits>;
|
|
||||||
using ElementA = typename OffsetFunctor::ElementA;
|
|
||||||
using ElementB = typename OffsetFunctor::ElementB;
|
|
||||||
using ElementSF = typename OffsetFunctor::ElementSF;
|
|
||||||
using ElementD = typename OffsetFunctor::ElementD;
|
|
||||||
|
|
||||||
using LayoutFunctor = CutlassMxfp8GroupedMmLayoutFunctor<GemmTraits>;
|
|
||||||
using LayoutSFA = typename LayoutFunctor::LayoutSFA;
|
|
||||||
using LayoutSFB = typename LayoutFunctor::LayoutSFB;
|
|
||||||
|
|
||||||
using StrideFunctor = CutlassMxfp8GroupedMmStrideFunctor<GemmTraits>;
|
|
||||||
using StrideA = typename StrideFunctor::StrideA;
|
|
||||||
using StrideB = typename StrideFunctor::StrideB;
|
|
||||||
using StrideD = typename StrideFunctor::StrideD;
|
|
||||||
|
|
||||||
int num_experts = static_cast<int>(expert_offsets.size(0));
|
|
||||||
STD_TORCH_CHECK(num_experts <= 1024,
|
|
||||||
"Number of experts cannot exceed 1024, the maximum number of "
|
|
||||||
"threads per block.");
|
|
||||||
|
|
||||||
OffsetFunctor offset_functor(
|
|
||||||
reinterpret_cast<int*>(expert_offsets.data_ptr()),
|
|
||||||
reinterpret_cast<int*>(blockscale_offsets.data_ptr()),
|
|
||||||
reinterpret_cast<ElementA*>(a.data_ptr()),
|
|
||||||
reinterpret_cast<ElementB*>(b.data_ptr()),
|
|
||||||
reinterpret_cast<ElementSF*>(sfa.data_ptr()),
|
|
||||||
reinterpret_cast<ElementSF*>(sfb.data_ptr()),
|
|
||||||
reinterpret_cast<ElementD*>(d.data_ptr()),
|
|
||||||
reinterpret_cast<ElementA**>(a_ptrs.data_ptr()),
|
|
||||||
reinterpret_cast<ElementB**>(b_ptrs.data_ptr()),
|
|
||||||
reinterpret_cast<ElementSF**>(sfa_ptrs.data_ptr()),
|
|
||||||
reinterpret_cast<ElementSF**>(sfb_ptrs.data_ptr()),
|
|
||||||
reinterpret_cast<ElementD**>(d_ptrs.data_ptr()));
|
|
||||||
LayoutFunctor layout_functor(
|
|
||||||
reinterpret_cast<LayoutSFA*>(layout_sfa.data_ptr()),
|
|
||||||
reinterpret_cast<LayoutSFB*>(layout_sfb.data_ptr()));
|
|
||||||
StrideFunctor stride_functor(reinterpret_cast<StrideA*>(stride_a.data_ptr()),
|
|
||||||
reinterpret_cast<StrideB*>(stride_b.data_ptr()),
|
|
||||||
reinterpret_cast<StrideD*>(stride_d.data_ptr()));
|
|
||||||
cutlassMxfp8GroupedMmPreComputeKernel<<<1, num_experts, 0, stream>>>(
|
|
||||||
static_cast<int*>(problem_sizes.data_ptr()), offset_functor,
|
|
||||||
layout_functor, stride_functor);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename GemmTraits>
|
|
||||||
void cutlass_mxfp8_grouped_mm(const torch::stable::Tensor& a_ptrs,
|
|
||||||
const torch::stable::Tensor& b_ptrs,
|
|
||||||
const torch::stable::Tensor& sfa_ptrs,
|
|
||||||
const torch::stable::Tensor& sfb_ptrs,
|
|
||||||
const torch::stable::Tensor& d_ptrs,
|
|
||||||
const torch::stable::Tensor& stride_a,
|
|
||||||
const torch::stable::Tensor& stride_b,
|
|
||||||
const torch::stable::Tensor& stride_d,
|
|
||||||
const torch::stable::Tensor& layout_sfa,
|
|
||||||
const torch::stable::Tensor& layout_sfb,
|
|
||||||
const torch::stable::Tensor& problem_sizes,
|
|
||||||
cudaStream_t stream) {
|
|
||||||
using Gemm = typename GemmTraits::Gemm;
|
|
||||||
using ElementA = typename Gemm::ElementA;
|
|
||||||
using ElementB = typename Gemm::ElementB;
|
|
||||||
using ElementSF = typename GemmTraits::ElementSF;
|
|
||||||
using ElementD = typename GemmTraits::ElementOutput;
|
|
||||||
using StrideA = typename GemmTraits::StrideA;
|
|
||||||
using StrideB = typename GemmTraits::StrideB;
|
|
||||||
using StrideD = typename GemmTraits::StrideD;
|
|
||||||
using LayoutSFA = typename GemmTraits::LayoutSFA;
|
|
||||||
using LayoutSFB = typename GemmTraits::LayoutSFB;
|
|
||||||
using UnderlyingProblemShape =
|
|
||||||
typename GemmTraits::ProblemShape::UnderlyingProblemShape;
|
|
||||||
|
|
||||||
cutlass::KernelHardwareInfo hw_info;
|
|
||||||
hw_info.device_id = d_ptrs.get_device_index();
|
|
||||||
hw_info.sm_count = get_device_prop()->multiProcessorCount;
|
|
||||||
hw_info.cluster_shape = GemmTraits::MMAConfig::preferred_cluster;
|
|
||||||
hw_info.cluster_shape_fallback = GemmTraits::MMAConfig::fallback_cluster;
|
|
||||||
|
|
||||||
int num_experts = static_cast<int>(problem_sizes.size(0));
|
|
||||||
|
|
||||||
UnderlyingProblemShape* underlying_problem_shape =
|
|
||||||
reinterpret_cast<UnderlyingProblemShape*>(problem_sizes.data_ptr());
|
|
||||||
|
|
||||||
typename Gemm::Arguments arguments = {
|
|
||||||
cutlass::gemm::GemmUniversalMode::kGrouped,
|
|
||||||
{num_experts, underlying_problem_shape, nullptr},
|
|
||||||
{reinterpret_cast<const ElementA**>(a_ptrs.data_ptr()),
|
|
||||||
reinterpret_cast<StrideA*>(stride_a.data_ptr()),
|
|
||||||
reinterpret_cast<const ElementB**>(b_ptrs.data_ptr()),
|
|
||||||
reinterpret_cast<StrideB*>(stride_b.data_ptr()),
|
|
||||||
reinterpret_cast<const ElementSF**>(sfa_ptrs.data_ptr()),
|
|
||||||
reinterpret_cast<LayoutSFA*>(layout_sfa.data_ptr()),
|
|
||||||
reinterpret_cast<const ElementSF**>(sfb_ptrs.data_ptr()),
|
|
||||||
reinterpret_cast<LayoutSFB*>(layout_sfb.data_ptr())},
|
|
||||||
{{},
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
reinterpret_cast<ElementD**>(d_ptrs.data_ptr()),
|
|
||||||
reinterpret_cast<StrideD*>(stride_d.data_ptr())},
|
|
||||||
hw_info,
|
|
||||||
{} // Scheduler
|
|
||||||
};
|
|
||||||
|
|
||||||
Gemm gemm;
|
|
||||||
|
|
||||||
auto can_implement_status = gemm.can_implement(arguments);
|
|
||||||
STD_TORCH_CHECK(can_implement_status == cutlass::Status::kSuccess,
|
|
||||||
"Failed to implement GEMM");
|
|
||||||
|
|
||||||
size_t workspace_size = gemm.get_workspace_size(arguments);
|
|
||||||
torch::stable::Tensor workspace = torch::stable::empty(
|
|
||||||
{static_cast<int64_t>(workspace_size)},
|
|
||||||
torch::headeronly::ScalarType::Byte, std::nullopt, d_ptrs.device());
|
|
||||||
|
|
||||||
auto status = gemm.initialize(arguments, workspace.data_ptr(), stream);
|
|
||||||
STD_TORCH_CHECK(status == cutlass::Status::kSuccess,
|
|
||||||
"Failed to initialize GEMM");
|
|
||||||
|
|
||||||
status = gemm.run(stream, nullptr, true); // Enable PDL
|
|
||||||
STD_TORCH_CHECK(status == cutlass::Status::kSuccess, "Failed to run GEMM");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename OutType>
|
|
||||||
void cutlass_mxfp8_grouped_mm_dispatch_out_dtype(
|
|
||||||
const torch::stable::Tensor& a, const torch::stable::Tensor& b,
|
|
||||||
const torch::stable::Tensor& sfa, const torch::stable::Tensor& sfb,
|
|
||||||
torch::stable::Tensor& d, const torch::stable::Tensor& problem_sizes,
|
|
||||||
const torch::stable::Tensor& expert_offsets,
|
|
||||||
const torch::stable::Tensor& blockscale_offsets, cudaStream_t stream) {
|
|
||||||
int num_experts = static_cast<int>(problem_sizes.size(0));
|
|
||||||
auto device = a.device();
|
|
||||||
|
|
||||||
torch::stable::Tensor a_ptrs = torch::stable::empty(
|
|
||||||
num_experts, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
||||||
torch::stable::Tensor b_ptrs = torch::stable::empty(
|
|
||||||
num_experts, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
||||||
torch::stable::Tensor sfa_ptrs = torch::stable::empty(
|
|
||||||
num_experts, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
||||||
torch::stable::Tensor sfb_ptrs = torch::stable::empty(
|
|
||||||
num_experts, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
||||||
torch::stable::Tensor d_ptrs = torch::stable::empty(
|
|
||||||
num_experts, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
||||||
|
|
||||||
torch::stable::Tensor stride_a = torch::stable::empty(
|
|
||||||
num_experts, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
||||||
torch::stable::Tensor stride_b = torch::stable::empty(
|
|
||||||
num_experts, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
||||||
torch::stable::Tensor stride_d = torch::stable::empty(
|
|
||||||
num_experts, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
||||||
torch::stable::Tensor layout_sfa =
|
|
||||||
torch::stable::empty({num_experts, 5}, torch::headeronly::ScalarType::Int,
|
|
||||||
std::nullopt, device);
|
|
||||||
torch::stable::Tensor layout_sfb =
|
|
||||||
torch::stable::empty({num_experts, 5}, torch::headeronly::ScalarType::Int,
|
|
||||||
std::nullopt, device);
|
|
||||||
|
|
||||||
using GemmTraits = CutlassMxfp8GroupedMmGemmTraits<MMA1SMConfig, OutType>;
|
|
||||||
cutlass_mxfp8_grouped_mm_pre_compute<GemmTraits>(
|
|
||||||
a_ptrs, b_ptrs, sfa_ptrs, sfb_ptrs, d_ptrs, stride_a, stride_b, stride_d,
|
|
||||||
layout_sfa, layout_sfb, a, b, sfa, sfb, d, problem_sizes, expert_offsets,
|
|
||||||
blockscale_offsets, stream);
|
|
||||||
cutlass_mxfp8_grouped_mm<GemmTraits>(
|
|
||||||
a_ptrs, b_ptrs, sfa_ptrs, sfb_ptrs, d_ptrs, stride_a, stride_b, stride_d,
|
|
||||||
layout_sfa, layout_sfb, problem_sizes, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace expert_specialization
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
||||||
// Adapted from SGLang:
|
|
||||||
// https://github.com/sgl-project/sglang/blob/ded068a76e00878881d52d5bfb791e0f60d7311b/sgl-kernel/csrc/expert_specialization/es_sm100_mxfp8_blockscaled_traits.cuh
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// Misc
|
|
||||||
#include "cute/tensor.hpp"
|
|
||||||
#include "cutlass/arch/arch.h"
|
|
||||||
#include "cutlass/arch/mma.h"
|
|
||||||
#include "cutlass/cutlass.h"
|
|
||||||
#include "cutlass/detail/sm100_blockscaled_layout.hpp"
|
|
||||||
#include "cutlass/epilogue/dispatch_policy.hpp"
|
|
||||||
#include "cutlass/gemm/dispatch_policy.hpp"
|
|
||||||
#include "cutlass/gemm/group_array_problem_shape.hpp"
|
|
||||||
#include "cutlass/layout/layout.h"
|
|
||||||
#include "cutlass/numeric_conversion.h"
|
|
||||||
#include "cutlass/numeric_size.h"
|
|
||||||
|
|
||||||
// Collective Builder
|
|
||||||
#include "cutlass/epilogue/collective/collective_builder.hpp"
|
|
||||||
#include "cutlass/epilogue/fusion/sm90_callbacks_tma_warpspecialized.hpp"
|
|
||||||
#include "cutlass/epilogue/thread/activation.h"
|
|
||||||
#include "cutlass/gemm/collective/collective_builder.hpp"
|
|
||||||
|
|
||||||
// Integration
|
|
||||||
#include "cutlass/gemm/device/gemm_universal_adapter.h"
|
|
||||||
#include "cutlass/gemm/kernel/gemm_universal.hpp"
|
|
||||||
|
|
||||||
namespace expert_specialization {
|
|
||||||
|
|
||||||
using namespace cute;
|
|
||||||
|
|
||||||
// Different configs for 1SM and 2SM MMA kernel
|
|
||||||
struct MMA1SMConfig {
|
|
||||||
using MmaTileShape = Shape<_128, _128, _128>;
|
|
||||||
using KernelSchedule =
|
|
||||||
cutlass::gemm::KernelPtrArrayTmaWarpSpecialized1SmMxf8f6f4Sm100;
|
|
||||||
using EpilogueSchedule = cutlass::epilogue::PtrArrayTmaWarpSpecialized1Sm;
|
|
||||||
const static dim3 preferred_cluster;
|
|
||||||
const static dim3 fallback_cluster;
|
|
||||||
};
|
|
||||||
const dim3 MMA1SMConfig::preferred_cluster(1, 4, 1);
|
|
||||||
const dim3 MMA1SMConfig::fallback_cluster(1, 2, 1);
|
|
||||||
|
|
||||||
template <typename _MMAConfig, typename OutputDtype>
|
|
||||||
struct CutlassMxfp8GroupedMmGemmTraits {
|
|
||||||
using MMAConfig = _MMAConfig;
|
|
||||||
using ElementInput = cutlass::float_e4m3_t;
|
|
||||||
using ElementOutput = OutputDtype;
|
|
||||||
using ProblemShape = cutlass::gemm::GroupProblemShape<Shape<int, int, int>>;
|
|
||||||
|
|
||||||
// A matrix configuration
|
|
||||||
using ElementA = cutlass::mx_float8_t<ElementInput>;
|
|
||||||
using LayoutA = cutlass::layout::RowMajor;
|
|
||||||
constexpr static int AlignmentA = 32;
|
|
||||||
|
|
||||||
// B matrix configuration
|
|
||||||
using ElementB = cutlass::mx_float8_t<ElementInput>;
|
|
||||||
using LayoutB = cutlass::layout::ColumnMajor;
|
|
||||||
constexpr static int AlignmentB = 32;
|
|
||||||
|
|
||||||
// C/D matrix configuration
|
|
||||||
using ElementC = void;
|
|
||||||
using ElementD = ElementOutput;
|
|
||||||
using LayoutC = cutlass::layout::RowMajor;
|
|
||||||
using LayoutD = cutlass::layout::RowMajor;
|
|
||||||
constexpr static int AlignmentC = 128 / cutlass::sizeof_bits<ElementD>::value;
|
|
||||||
constexpr static int AlignmentD = 128 / cutlass::sizeof_bits<ElementD>::value;
|
|
||||||
using ElementAccumulator = float;
|
|
||||||
|
|
||||||
static constexpr auto RoundStyle = cutlass::FloatRoundStyle::round_to_nearest;
|
|
||||||
using CustomEVTIdentity = // acc
|
|
||||||
cutlass::epilogue::fusion::Sm90EVT<
|
|
||||||
cutlass::epilogue::fusion::Sm90Compute<
|
|
||||||
cutlass::epilogue::thread::Identity, ElementD, ElementAccumulator,
|
|
||||||
RoundStyle>,
|
|
||||||
cutlass::epilogue::fusion::Sm90AccFetch>;
|
|
||||||
|
|
||||||
// Core kernel configurations
|
|
||||||
using ArchTag = cutlass::arch::Sm100;
|
|
||||||
using OperatorClass = cutlass::arch::OpClassBlockScaledTensorOp;
|
|
||||||
using StageCountType = cutlass::gemm::collective::StageCountAuto;
|
|
||||||
|
|
||||||
// Runtime Cluster Shape
|
|
||||||
using ClusterShape = Shape<int32_t, int32_t, _1>;
|
|
||||||
|
|
||||||
// Define Epilogue
|
|
||||||
using CollectiveEpilogue =
|
|
||||||
typename cutlass::epilogue::collective::CollectiveBuilder<
|
|
||||||
ArchTag, OperatorClass, typename MMAConfig::MmaTileShape,
|
|
||||||
ClusterShape, Shape<_64, _64>, ElementAccumulator, ElementAccumulator,
|
|
||||||
ElementC, LayoutC*, AlignmentC, ElementD, LayoutD*, AlignmentD,
|
|
||||||
typename MMAConfig::EpilogueSchedule,
|
|
||||||
CustomEVTIdentity>::CollectiveOp;
|
|
||||||
|
|
||||||
// Define Mainloop
|
|
||||||
using CollectiveMainloop =
|
|
||||||
typename cutlass::gemm::collective::CollectiveBuilder<
|
|
||||||
ArchTag, OperatorClass, ElementA, LayoutA*, AlignmentA, ElementB,
|
|
||||||
LayoutB*, AlignmentB, ElementAccumulator,
|
|
||||||
typename MMAConfig::MmaTileShape, ClusterShape,
|
|
||||||
cutlass::gemm::collective::StageCountAutoCarveout<static_cast<int>(
|
|
||||||
sizeof(typename CollectiveEpilogue::SharedStorage))>,
|
|
||||||
typename MMAConfig::KernelSchedule>::CollectiveOp;
|
|
||||||
|
|
||||||
// Define GemmKernel
|
|
||||||
using GemmKernel =
|
|
||||||
cutlass::gemm::kernel::GemmUniversal<ProblemShape, CollectiveMainloop,
|
|
||||||
CollectiveEpilogue>;
|
|
||||||
using Gemm = cutlass::gemm::device::GemmUniversalAdapter<GemmKernel>;
|
|
||||||
|
|
||||||
using ElementSF = typename Gemm::GemmKernel::ElementSF;
|
|
||||||
using StrideA = typename Gemm::GemmKernel::InternalStrideA;
|
|
||||||
using StrideB = typename Gemm::GemmKernel::InternalStrideB;
|
|
||||||
using StrideC = typename Gemm::GemmKernel::InternalStrideC;
|
|
||||||
using StrideD = typename Gemm::GemmKernel::InternalStrideD;
|
|
||||||
using LayoutSFA =
|
|
||||||
typename Gemm::GemmKernel::CollectiveMainloop::InternalLayoutSFA;
|
|
||||||
using LayoutSFB =
|
|
||||||
typename Gemm::GemmKernel::CollectiveMainloop::InternalLayoutSFB;
|
|
||||||
using Sm1xxBlkScaledConfig =
|
|
||||||
typename Gemm::GemmKernel::CollectiveMainloop::Sm1xxBlkScaledConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace expert_specialization
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
||||||
// Adapted from SGLang:
|
|
||||||
// https://github.com/sgl-project/sglang/blob/ded068a76e00878881d52d5bfb791e0f60d7311b/sgl-kernel/csrc/expert_specialization/es_sm100_mxfp8_blockscaled_group_quant.cu
|
|
||||||
|
|
||||||
#include <torch/csrc/stable/library.h>
|
|
||||||
#include <torch/csrc/stable/tensor.h>
|
|
||||||
#include "libtorch_stable/torch_utils.h"
|
|
||||||
|
|
||||||
#include "mxfp8_experts_quant.cuh"
|
|
||||||
|
|
||||||
void mxfp8_experts_quant(const torch::stable::Tensor& input,
|
|
||||||
const torch::stable::Tensor& problem_sizes,
|
|
||||||
const torch::stable::Tensor& expert_offsets,
|
|
||||||
const torch::stable::Tensor& blockscale_offsets,
|
|
||||||
torch::stable::Tensor& quant_output,
|
|
||||||
torch::stable::Tensor& scale_factor) {
|
|
||||||
#if defined(CUTLASS_ARCH_MMA_SM100_SUPPORTED)
|
|
||||||
STD_TORCH_CHECK(input.dim() == 2, "input must be 2D tensor");
|
|
||||||
STD_TORCH_CHECK(input.size(1) % 128 == 0, "k must align to 128");
|
|
||||||
STD_TORCH_CHECK(input.stride(1) == 1, "input must be row major");
|
|
||||||
STD_TORCH_CHECK(problem_sizes.dim() == 2, "problem_sizes must be 2D tensor");
|
|
||||||
STD_TORCH_CHECK(
|
|
||||||
problem_sizes.scalar_type() == torch::headeronly::ScalarType::Int,
|
|
||||||
"problem_sizes must be int32");
|
|
||||||
STD_TORCH_CHECK(
|
|
||||||
expert_offsets.scalar_type() == torch::headeronly::ScalarType::Int,
|
|
||||||
"expert_offsets must be int32");
|
|
||||||
STD_TORCH_CHECK(
|
|
||||||
blockscale_offsets.scalar_type() == torch::headeronly::ScalarType::Int,
|
|
||||||
"blockscale_offsets must be int32");
|
|
||||||
|
|
||||||
auto groups = problem_sizes.size(0);
|
|
||||||
STD_TORCH_CHECK(
|
|
||||||
expert_offsets.dim() == 1 && expert_offsets.size(0) == groups,
|
|
||||||
"expert_offsets must be 1D and have size equal to the number of groups");
|
|
||||||
STD_TORCH_CHECK(
|
|
||||||
blockscale_offsets.dim() == 1 && blockscale_offsets.size(0) == groups,
|
|
||||||
"blockscale_offsets must be 1D and have size equal to the number of "
|
|
||||||
"groups");
|
|
||||||
|
|
||||||
const torch::stable::accelerator::DeviceGuard device_guard(
|
|
||||||
input.get_device_index());
|
|
||||||
if (input.scalar_type() == torch::headeronly::ScalarType::BFloat16) {
|
|
||||||
expert_specialization::launch_mxfp8_experts_quant<__nv_bfloat16>(
|
|
||||||
input, problem_sizes, expert_offsets, blockscale_offsets, quant_output,
|
|
||||||
scale_factor);
|
|
||||||
} else if (input.scalar_type() == torch::headeronly::ScalarType::Half) {
|
|
||||||
expert_specialization::launch_mxfp8_experts_quant<__half>(
|
|
||||||
input, problem_sizes, expert_offsets, blockscale_offsets, quant_output,
|
|
||||||
scale_factor);
|
|
||||||
} else {
|
|
||||||
STD_TORCH_CHECK(false, "dtype must be kFloat16 or kBFloat16");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
STD_TORCH_CHECK(false,
|
|
||||||
"No implemented mxfp8_experts_quant for "
|
|
||||||
"current device");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Registered here (not torch_bindings.cpp) because ENABLE_ES_MXFP8_GROUPED_MM
|
|
||||||
// is applied only under COMPILE_LANGUAGE:CUDA.
|
|
||||||
STABLE_TORCH_LIBRARY_IMPL(_C, CUDA, m) {
|
|
||||||
m.impl("mxfp8_experts_quant", TORCH_BOX(&mxfp8_experts_quant));
|
|
||||||
}
|
|
||||||
@@ -1,416 +0,0 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
||||||
// Adapted from SGLang:
|
|
||||||
// https://github.com/sgl-project/sglang/blob/ded068a76e00878881d52d5bfb791e0f60d7311b/sgl-kernel/csrc/expert_specialization/es_sm100_mxfp8_blockscaled_group_quant.cuh
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <cuda.h>
|
|
||||||
#include <cuda_bf16.h>
|
|
||||||
#include <cuda_fp16.h>
|
|
||||||
|
|
||||||
#include <torch/csrc/inductor/aoti_torch/c/shim.h>
|
|
||||||
#include <torch/csrc/stable/macros.h>
|
|
||||||
#include <torch/csrc/stable/tensor.h>
|
|
||||||
#include <torch/headeronly/util/Exception.h>
|
|
||||||
|
|
||||||
#include <cuda/ptx>
|
|
||||||
|
|
||||||
#include "cute/tensor.hpp"
|
|
||||||
#include "libtorch_stable/torch_utils.h"
|
|
||||||
|
|
||||||
namespace expert_specialization {
|
|
||||||
|
|
||||||
using namespace cute;
|
|
||||||
|
|
||||||
constexpr uint32_t THREAD_BLOCK_SIZE = 128;
|
|
||||||
constexpr uint32_t WARP_SIZE = 32;
|
|
||||||
constexpr int BLOCK_M = 128;
|
|
||||||
constexpr int BLOCK_K = 128;
|
|
||||||
using ThrLayout = Layout<Shape<_16, _8>, Stride<_8, _1>>;
|
|
||||||
using ValLayout = Layout<Shape<_1, _16>>;
|
|
||||||
using SfR2SThrLayout = Layout<Shape<_16, _4>, Stride<_4, _1>>;
|
|
||||||
using SfR2SValLayout = Layout<Shape<_1, _1>>;
|
|
||||||
using ScaleFactorTileLayout =
|
|
||||||
Layout<Shape<Shape<_32, _4>, _4>, Stride<Stride<_16, _4>, _1>>;
|
|
||||||
|
|
||||||
// Fast reciprocal.
|
|
||||||
inline __device__ float reciprocal_approximate_ftz(float a) {
|
|
||||||
float b;
|
|
||||||
asm volatile("rcp.approx.ftz.f32 %0, %1;\n" : "=f"(b) : "f"(a));
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some code references TRT-LLM:
|
|
||||||
// https://github.com/NVIDIA/TensorRT-LLM/blob/main/cpp/tensorrt_llm/kernels/quantization.cuh
|
|
||||||
template <typename FragmentS, typename FragmentD>
|
|
||||||
__inline__ __device__ uint8_t cvt_warp_fp16_to_mxfp8(FragmentS& fragment_s,
|
|
||||||
FragmentD& fragment_d) {
|
|
||||||
using FragmentSLayout = typename FragmentS::layout_type;
|
|
||||||
using FragmentDLayout = typename FragmentD::layout_type;
|
|
||||||
FragmentSLayout fragment_s_layout;
|
|
||||||
FragmentDLayout fragment_d_layout;
|
|
||||||
static_assert(is_static<FragmentSLayout>::value &&
|
|
||||||
size(fragment_s_layout) == 16);
|
|
||||||
static_assert(is_static<FragmentDLayout>::value &&
|
|
||||||
size(fragment_d_layout) == 16);
|
|
||||||
|
|
||||||
constexpr int eles_per_thr = 16;
|
|
||||||
using ValType = typename FragmentS::element_type;
|
|
||||||
using VecType = std::conditional_t<std::is_same_v<ValType, __nv_bfloat16>,
|
|
||||||
__nv_bfloat162, __half2>;
|
|
||||||
VecType vec[8];
|
|
||||||
// Assign vals
|
|
||||||
vec[0].x = fragment_s(Int<0>{});
|
|
||||||
vec[0].y = fragment_s(Int<1>{});
|
|
||||||
vec[1].x = fragment_s(Int<2>{});
|
|
||||||
vec[1].y = fragment_s(Int<3>{});
|
|
||||||
vec[2].x = fragment_s(Int<4>{});
|
|
||||||
vec[2].y = fragment_s(Int<5>{});
|
|
||||||
vec[3].x = fragment_s(Int<6>{});
|
|
||||||
vec[3].y = fragment_s(Int<7>{});
|
|
||||||
vec[4].x = fragment_s(Int<8>{});
|
|
||||||
vec[4].y = fragment_s(Int<9>{});
|
|
||||||
vec[5].x = fragment_s(Int<10>{});
|
|
||||||
vec[5].y = fragment_s(Int<11>{});
|
|
||||||
vec[6].x = fragment_s(Int<12>{});
|
|
||||||
vec[6].y = fragment_s(Int<13>{});
|
|
||||||
vec[7].x = fragment_s(Int<14>{});
|
|
||||||
vec[7].y = fragment_s(Int<15>{});
|
|
||||||
|
|
||||||
auto local_max = __habs2(vec[0]);
|
|
||||||
for (int i = 1; i < eles_per_thr / 2; i++) {
|
|
||||||
local_max = __hmax2(__habs2(vec[i]), local_max);
|
|
||||||
}
|
|
||||||
local_max = __hmax2(__shfl_xor_sync(uint32_t(-1), local_max, 1), local_max);
|
|
||||||
|
|
||||||
// Get the final absolute maximum values.
|
|
||||||
float block_max(0.0f);
|
|
||||||
if constexpr (std::is_same_v<ValType, __nv_bfloat16>) {
|
|
||||||
block_max = __bfloat162float(__hmax(local_max.x, local_max.y));
|
|
||||||
} else {
|
|
||||||
block_max = __half2float(__hmax(local_max.x, local_max.y));
|
|
||||||
}
|
|
||||||
// Get the SF (max value of the vector / max value of mxfp8).
|
|
||||||
float sf_val = block_max * reciprocal_approximate_ftz(448.0f);
|
|
||||||
// 8 bits representation of the SF.
|
|
||||||
uint8_t fp8_sf_val;
|
|
||||||
|
|
||||||
__nv_fp8_e8m0 tmp_sf_val;
|
|
||||||
tmp_sf_val.__x =
|
|
||||||
__nv_cvt_float_to_e8m0(sf_val, __NV_SATFINITE, cudaRoundPosInf);
|
|
||||||
sf_val = static_cast<float>(tmp_sf_val);
|
|
||||||
fp8_sf_val = tmp_sf_val.__x;
|
|
||||||
// Get the output scale (reciprocal of the SFValue).
|
|
||||||
float output_scale =
|
|
||||||
block_max != 0.f ? reciprocal_approximate_ftz(sf_val) : 0.0f;
|
|
||||||
|
|
||||||
// Convert the input to float.
|
|
||||||
float2 fp2_vals[eles_per_thr / 2];
|
|
||||||
|
|
||||||
#pragma unroll
|
|
||||||
for (int i = 0; i < eles_per_thr / 2; i++) {
|
|
||||||
if constexpr (std::is_same_v<ValType, __half>) {
|
|
||||||
fp2_vals[i] = __half22float2(vec[i]);
|
|
||||||
} else {
|
|
||||||
fp2_vals[i] = __bfloat1622float2(vec[i]);
|
|
||||||
}
|
|
||||||
fp2_vals[i].x *= output_scale;
|
|
||||||
fp2_vals[i].y *= output_scale;
|
|
||||||
}
|
|
||||||
union {
|
|
||||||
uint8_t bytes[16];
|
|
||||||
__nv_fp8x2_e4m3 elts[8];
|
|
||||||
} u;
|
|
||||||
u.elts[0] = __nv_fp8x2_e4m3(fp2_vals[0]);
|
|
||||||
u.elts[1] = __nv_fp8x2_e4m3(fp2_vals[1]);
|
|
||||||
u.elts[2] = __nv_fp8x2_e4m3(fp2_vals[2]);
|
|
||||||
u.elts[3] = __nv_fp8x2_e4m3(fp2_vals[3]);
|
|
||||||
u.elts[4] = __nv_fp8x2_e4m3(fp2_vals[4]);
|
|
||||||
u.elts[5] = __nv_fp8x2_e4m3(fp2_vals[5]);
|
|
||||||
u.elts[6] = __nv_fp8x2_e4m3(fp2_vals[6]);
|
|
||||||
u.elts[7] = __nv_fp8x2_e4m3(fp2_vals[7]);
|
|
||||||
fragment_d(Int<0>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[0]);
|
|
||||||
fragment_d(Int<1>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[1]);
|
|
||||||
fragment_d(Int<2>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[2]);
|
|
||||||
fragment_d(Int<3>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[3]);
|
|
||||||
fragment_d(Int<4>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[4]);
|
|
||||||
fragment_d(Int<5>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[5]);
|
|
||||||
fragment_d(Int<6>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[6]);
|
|
||||||
fragment_d(Int<7>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[7]);
|
|
||||||
fragment_d(Int<8>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[8]);
|
|
||||||
fragment_d(Int<9>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[9]);
|
|
||||||
fragment_d(Int<10>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[10]);
|
|
||||||
fragment_d(Int<11>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[11]);
|
|
||||||
fragment_d(Int<12>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[12]);
|
|
||||||
fragment_d(Int<13>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[13]);
|
|
||||||
fragment_d(Int<14>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[14]);
|
|
||||||
fragment_d(Int<15>{}) = cutlass::float_e4m3_t::bitcast(u.bytes[15]);
|
|
||||||
return fp8_sf_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TensorS, typename TensorP, typename TensorD,
|
|
||||||
typename TensorSharedSF, typename TensorSF, typename TiledCopyG2R,
|
|
||||||
typename TiledCopyR2G, typename TiledCopyR2S>
|
|
||||||
__inline__ __device__ void mxfp8_experts_quant_tile(
|
|
||||||
TensorS& tensor_s, TensorP& tensor_p, TensorD& tensor_d,
|
|
||||||
TensorSharedSF& tensor_shared_sf, TensorSF& tensor_sf, int m,
|
|
||||||
TiledCopyG2R& tiled_copy_g2r, TiledCopyR2G& tiled_copy_r2g,
|
|
||||||
TiledCopyR2S& tiled_copy_r2s) {
|
|
||||||
static_assert(size(get<0>(typename TensorS::layout_type{})) == 128 &&
|
|
||||||
size(get<1>(typename TensorS::layout_type{})) == 128 &&
|
|
||||||
stride(get<1>(typename TensorS::layout_type{})) == 1);
|
|
||||||
static_assert(size(get<0>(typename TensorD::layout_type{})) == 128 &&
|
|
||||||
size(get<1>(typename TensorD::layout_type{})) == 128 &&
|
|
||||||
stride(get<1>(typename TensorD::layout_type{})) == 1);
|
|
||||||
static_assert(size(get<0>(typename TensorP::layout_type{})) == 128 &&
|
|
||||||
size(get<1>(typename TensorP::layout_type{})) == 128);
|
|
||||||
static_assert(size(get<0>(typename TensorSharedSF::layout_type{})) == 128 &&
|
|
||||||
size(get<1>(typename TensorSharedSF::layout_type{})) == 4);
|
|
||||||
static_assert(size(get<0>(typename TensorSF::layout_type{})) == 128 &&
|
|
||||||
size(get<1>(typename TensorSF::layout_type{})) == 4);
|
|
||||||
|
|
||||||
using Tiler_MN = typename TiledCopyG2R::Tiler_MN;
|
|
||||||
auto tiler_mn = Tiler_MN{};
|
|
||||||
static_assert(size<0>(tiler_mn) == 16 && size<1>(tiler_mn) == 128);
|
|
||||||
|
|
||||||
auto tiled_tensor_s = tiled_divide(tensor_s, tiler_mn);
|
|
||||||
auto tiled_tensor_p = tiled_divide(tensor_p, tiler_mn);
|
|
||||||
auto tiled_tensor_d = tiled_divide(tensor_d, tiler_mn);
|
|
||||||
static_assert(size<2>(tiled_tensor_s) == 1);
|
|
||||||
static_assert(size<2>(tiled_tensor_p) == 1);
|
|
||||||
static_assert(size<2>(tiled_tensor_d) == 1);
|
|
||||||
auto squeeze_tiled_tensor_s = take<0, 2>(tiled_tensor_s);
|
|
||||||
auto squeeze_tiled_tensor_p = take<0, 2>(tiled_tensor_p);
|
|
||||||
auto squeeze_tiled_tensor_d = take<0, 2>(tiled_tensor_d);
|
|
||||||
|
|
||||||
using SF_Tiler_MN = typename TiledCopyR2S::Tiler_MN;
|
|
||||||
auto sf_tiler_mn = SF_Tiler_MN{};
|
|
||||||
static_assert(size<0>(sf_tiler_mn) == 16 && size<1>(sf_tiler_mn) == 4);
|
|
||||||
|
|
||||||
auto tiled_tensor_sf = tiled_divide(tensor_sf, sf_tiler_mn);
|
|
||||||
auto tiled_tensor_shared_sf = tiled_divide(tensor_shared_sf, sf_tiler_mn);
|
|
||||||
auto squeeze_tiled_tensor_sf = take<0, 2>(tiled_tensor_sf);
|
|
||||||
auto squeeze_tiled_tensor_shared_sf = take<0, 2>(tiled_tensor_shared_sf);
|
|
||||||
|
|
||||||
constexpr int tile_loop_count = size<1>(tiled_tensor_s);
|
|
||||||
constexpr int rows_in_tile = 16;
|
|
||||||
// We don't need to clear shared memory
|
|
||||||
// clear(squeeze_tiled_tensor_shared_sf);
|
|
||||||
#pragma unroll 4
|
|
||||||
for (int t = 0; t < tile_loop_count; t++) {
|
|
||||||
if (t * rows_in_tile >= m) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto current_copy_tile_s = tensor<0>(squeeze_tiled_tensor_s(_, t));
|
|
||||||
auto current_copy_tile_p = tensor<0>(squeeze_tiled_tensor_p(_, t));
|
|
||||||
auto current_copy_tile_d = tensor<0>(squeeze_tiled_tensor_d(_, t));
|
|
||||||
auto current_copy_tile_sf = tensor<0>(squeeze_tiled_tensor_sf(_, t));
|
|
||||||
auto current_copy_tile_shared_sf =
|
|
||||||
tensor<0>(squeeze_tiled_tensor_shared_sf(_, t));
|
|
||||||
|
|
||||||
// Global to Register copy
|
|
||||||
auto thr_copy_g2r = tiled_copy_g2r.get_thread_slice(threadIdx.x);
|
|
||||||
auto thr_tile_g2r_s = thr_copy_g2r.partition_S(current_copy_tile_s);
|
|
||||||
auto thr_tile_g2r_p = thr_copy_g2r.partition_S(current_copy_tile_p);
|
|
||||||
auto input_fragment = make_fragment_like(thr_tile_g2r_s);
|
|
||||||
|
|
||||||
// Register to Global copy
|
|
||||||
auto thr_copy_r2g = tiled_copy_r2g.get_thread_slice(threadIdx.x);
|
|
||||||
auto thr_tile_r2g_d = thr_copy_r2g.partition_D(current_copy_tile_d);
|
|
||||||
auto thr_tile_r2g_p = thr_copy_r2g.partition_D(current_copy_tile_p);
|
|
||||||
auto output_fragment = make_fragment_like(thr_tile_r2g_d);
|
|
||||||
|
|
||||||
// Register to Shared copy
|
|
||||||
auto thr_copy_r2s = tiled_copy_r2s.get_thread_slice(threadIdx.x / 2);
|
|
||||||
auto thr_tile_r2s_shared_sf =
|
|
||||||
thr_copy_r2s.partition_D(current_copy_tile_shared_sf);
|
|
||||||
auto shared_sf_fragment = make_fragment_like(thr_tile_r2s_shared_sf);
|
|
||||||
|
|
||||||
// CopyG2R & convert & CopyR2G
|
|
||||||
copy_if(tiled_copy_g2r, thr_tile_g2r_p, thr_tile_g2r_s, input_fragment);
|
|
||||||
uint8_t fp8_sf_val =
|
|
||||||
cvt_warp_fp16_to_mxfp8(input_fragment, output_fragment);
|
|
||||||
copy_if(tiled_copy_r2g, thr_tile_r2g_p, output_fragment, thr_tile_r2g_d);
|
|
||||||
shared_sf_fragment[0] = fp8_sf_val;
|
|
||||||
|
|
||||||
// Before first copy r2s, clear shared memory and wait previous group
|
|
||||||
if (t == 0 && threadIdx.x == 0) {
|
|
||||||
// Wait for the group to have completed reading from shared memory.
|
|
||||||
cuda::ptx::cp_async_bulk_wait_group_read(cuda::ptx::n32_t<0>());
|
|
||||||
}
|
|
||||||
__syncthreads();
|
|
||||||
|
|
||||||
if (threadIdx.x % 2 == 0) {
|
|
||||||
copy(tiled_copy_r2s, shared_sf_fragment, thr_tile_r2s_shared_sf);
|
|
||||||
}
|
|
||||||
__syncthreads();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for shared memory writes to be visible to TMA engine.
|
|
||||||
cuda::ptx::fence_proxy_async(cuda::ptx::space_shared); // b)
|
|
||||||
__syncthreads();
|
|
||||||
|
|
||||||
if (threadIdx.x == 0) {
|
|
||||||
cuda::ptx::cp_async_bulk(cuda::ptx::space_global, cuda::ptx::space_shared,
|
|
||||||
squeeze_tiled_tensor_sf.data().get(),
|
|
||||||
squeeze_tiled_tensor_shared_sf.data().get(), 512);
|
|
||||||
// Wait for TMA transfer to have finished reading shared memory.
|
|
||||||
// Create a "bulk async-group" out of the previous bulk copy operation.
|
|
||||||
cuda::ptx::cp_async_bulk_commit_group();
|
|
||||||
}
|
|
||||||
__syncthreads();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T_IN, typename TiledCopyG2R, typename TiledCopyR2G,
|
|
||||||
typename TiledCopyR2S>
|
|
||||||
__global__ void mxfp8_experts_quant_kernel(
|
|
||||||
const T_IN* input, const int* problem_sizes, const int* expert_offsets,
|
|
||||||
const int* blockscale_offsets, cutlass::float_e4m3_t* quant_output,
|
|
||||||
uint8_t* scale_factor, int groups, TiledCopyG2R tiled_copy_g2r,
|
|
||||||
TiledCopyR2G tiled_copy_r2g, TiledCopyR2S tiled_copy_r2s) {
|
|
||||||
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 1000
|
|
||||||
__shared__ __align__(512) uint8_t shared_memory[512];
|
|
||||||
ScaleFactorTileLayout scale_factor_tile_layout{};
|
|
||||||
auto scale_factor_shared =
|
|
||||||
make_tensor(make_smem_ptr(shared_memory),
|
|
||||||
scale_factor_tile_layout); // ((_32,_4), _4):((_16,_4), _1)
|
|
||||||
// TODO: Transform Groupwise Schedule into a more efficient Schedule
|
|
||||||
for (int g = 0; g < groups; g++) {
|
|
||||||
int m = problem_sizes[g * 3 + 0];
|
|
||||||
int k = problem_sizes[g * 3 + 2];
|
|
||||||
int64_t expert_offset = static_cast<int64_t>(expert_offsets[g]);
|
|
||||||
int64_t blockscale_offset = static_cast<int64_t>(blockscale_offsets[g]);
|
|
||||||
|
|
||||||
auto input_tensor = make_tensor(
|
|
||||||
make_gmem_ptr(input + expert_offset * k),
|
|
||||||
make_layout(make_shape(m, k),
|
|
||||||
LayoutRight{})); // (M, K):(K, 1) half_t/bfloat16_t
|
|
||||||
|
|
||||||
auto quant_output_tensor = make_tensor(
|
|
||||||
make_gmem_ptr(quant_output + expert_offset * k),
|
|
||||||
make_layout(make_shape(m, k),
|
|
||||||
LayoutRight{})); // (M, K):(K, 1) cutlass::float_e4m3_t
|
|
||||||
|
|
||||||
auto scale_factor_shape = make_shape(ceil_div(m, 128) * 128, k / 32);
|
|
||||||
auto scale_factor_layout = tile_to_shape(scale_factor_tile_layout,
|
|
||||||
scale_factor_shape, LayoutRight{});
|
|
||||||
// layout<0>(layout<0>(scale_factor_layout)) (_32,_4):(_16,_4) -- static
|
|
||||||
// layout<1>(layout<0>(scale_factor_layout)) M_align_128 / 128 -- dynamic
|
|
||||||
// shape dynamic stride layout<0>(layout<1>(scale_factor_layout)) _4:_1 --
|
|
||||||
// static layout<1>(layout<1>(scale_factor_layout)) (K / 32) / 4 : _512 --
|
|
||||||
// dynamic shape static stride
|
|
||||||
|
|
||||||
// Reshape to zipped layout for 1D indexing
|
|
||||||
auto zipped_scale_factor_layout = make_layout(
|
|
||||||
make_layout(layout<0>(layout<0>(scale_factor_layout)),
|
|
||||||
layout<0>(layout<1>(scale_factor_layout))),
|
|
||||||
make_layout(
|
|
||||||
layout<1>(layout<0>(scale_factor_layout)),
|
|
||||||
layout<1>(layout<1>(
|
|
||||||
scale_factor_layout)))); // (((_32,_4),_4),(M_align_128 /
|
|
||||||
// 128,(K / 32) /
|
|
||||||
// 4)):(((_16,_4),_1),(?,_512))
|
|
||||||
|
|
||||||
auto scale_factor_tensor =
|
|
||||||
make_tensor(make_gmem_ptr(scale_factor + blockscale_offset * (k / 32)),
|
|
||||||
zipped_scale_factor_layout);
|
|
||||||
|
|
||||||
// Used for cases where M is not divisible by 128 (most scenarios).
|
|
||||||
auto input_shape = shape(input_tensor); // (M, K):(K, 1)
|
|
||||||
auto identity_tensor = make_identity_tensor(input_shape);
|
|
||||||
auto predict_tensor = cute::lazy::transform(
|
|
||||||
identity_tensor, [&](auto c) { return elem_less(c, input_shape); });
|
|
||||||
|
|
||||||
// (_128, _128)
|
|
||||||
auto tiler = make_shape(Int<BLOCK_M>{}, Int<BLOCK_K>{});
|
|
||||||
|
|
||||||
auto tiled_input_tensor = zipped_divide(
|
|
||||||
input_tensor, tiler); // ((128, 128), (cdiv(M, 128), cdiv(K, 128)))
|
|
||||||
auto tiled_quant_output_tensor =
|
|
||||||
zipped_divide(quant_output_tensor,
|
|
||||||
tiler); // ((128, 128), (cdiv(M, 128), cdiv(K, 128)))
|
|
||||||
auto tiled_predict_tensor = zipped_divide(
|
|
||||||
predict_tensor, tiler); // ((128, 128), (cdiv(M, 128), cdiv(K, 128)))
|
|
||||||
|
|
||||||
auto total_tiles =
|
|
||||||
size<1>(tiled_input_tensor); // cdiv(M, 128) * cdiv(K, 128)
|
|
||||||
decltype(total_tiles) blk_offset = blockIdx.x;
|
|
||||||
while (blk_offset < total_tiles) {
|
|
||||||
auto current_input_tile = tensor<0>(tiled_input_tensor(_, blk_offset));
|
|
||||||
auto current_quant_output_tile =
|
|
||||||
tensor<0>(tiled_quant_output_tensor(_, blk_offset));
|
|
||||||
auto current_predict_tile =
|
|
||||||
tensor<0>(tiled_predict_tensor(_, blk_offset));
|
|
||||||
auto current_scale_factor_tile =
|
|
||||||
tensor<0>(scale_factor_tensor(_, blk_offset));
|
|
||||||
|
|
||||||
mxfp8_experts_quant_tile<
|
|
||||||
decltype(current_input_tile), decltype(current_predict_tile),
|
|
||||||
decltype(current_quant_output_tile), decltype(scale_factor_shared),
|
|
||||||
decltype(current_scale_factor_tile), TiledCopyG2R, TiledCopyR2G,
|
|
||||||
TiledCopyR2S>(current_input_tile, current_predict_tile,
|
|
||||||
current_quant_output_tile, scale_factor_shared,
|
|
||||||
current_scale_factor_tile, m, tiled_copy_g2r,
|
|
||||||
tiled_copy_r2g, tiled_copy_r2s);
|
|
||||||
blk_offset += gridDim.x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T_IN>
|
|
||||||
void launch_mxfp8_experts_quant(const torch::stable::Tensor& input,
|
|
||||||
const torch::stable::Tensor& problem_sizes,
|
|
||||||
const torch::stable::Tensor& expert_offsets,
|
|
||||||
const torch::stable::Tensor& blockscale_offsets,
|
|
||||||
torch::stable::Tensor& quant_output,
|
|
||||||
torch::stable::Tensor& scale_factor) {
|
|
||||||
ThrLayout thr_layout{};
|
|
||||||
ValLayout val_layout{};
|
|
||||||
SfR2SThrLayout r2s_thr_layout{};
|
|
||||||
SfR2SValLayout r2s_val_layout{};
|
|
||||||
|
|
||||||
using CopyOpG2R =
|
|
||||||
UniversalCopy<cutlass::AlignedArray<T_IN, size(val_layout)>>;
|
|
||||||
using CopyAtomG2R = cute::Copy_Atom<CopyOpG2R, T_IN>;
|
|
||||||
auto tiled_copy_g2r = cute::make_tiled_copy(
|
|
||||||
CopyAtomG2R{}, thr_layout, val_layout); // Tiler_MN: (16, 128)
|
|
||||||
|
|
||||||
using CopyOpR2G = UniversalCopy<
|
|
||||||
cutlass::AlignedArray<cutlass::float_e4m3_t, size(val_layout)>>;
|
|
||||||
using CopyAtomR2G = cute::Copy_Atom<CopyOpR2G, cutlass::float_e4m3_t>;
|
|
||||||
auto tiled_copy_r2g = cute::make_tiled_copy(
|
|
||||||
CopyAtomR2G{}, thr_layout, val_layout); // Tiler_MN: (16, 128)
|
|
||||||
|
|
||||||
using CopyOpR2S =
|
|
||||||
UniversalCopy<cutlass::AlignedArray<uint8_t, size(r2s_val_layout)>>;
|
|
||||||
using CopyAtomR2S = cute::Copy_Atom<CopyOpR2S, uint8_t>;
|
|
||||||
auto tiled_copy_r2s = cute::make_tiled_copy(
|
|
||||||
CopyAtomR2S{}, r2s_thr_layout, r2s_val_layout); // Tiler_MN: (16, 4)
|
|
||||||
|
|
||||||
int max_active_blocks_per_sm = -1;
|
|
||||||
STD_CUDA_CHECK(cudaOccupancyMaxActiveBlocksPerMultiprocessor(
|
|
||||||
&max_active_blocks_per_sm,
|
|
||||||
mxfp8_experts_quant_kernel<T_IN, decltype(tiled_copy_g2r),
|
|
||||||
decltype(tiled_copy_r2g),
|
|
||||||
decltype(tiled_copy_r2s)>,
|
|
||||||
THREAD_BLOCK_SIZE, 0));
|
|
||||||
|
|
||||||
dim3 grid(get_device_prop()->multiProcessorCount * max_active_blocks_per_sm,
|
|
||||||
1, 1);
|
|
||||||
dim3 block(THREAD_BLOCK_SIZE, 1, 1);
|
|
||||||
int num_experts = static_cast<int>(problem_sizes.size(0));
|
|
||||||
auto stream = get_current_cuda_stream(input.get_device_index());
|
|
||||||
mxfp8_experts_quant_kernel<T_IN, decltype(tiled_copy_g2r),
|
|
||||||
decltype(tiled_copy_r2g), decltype(tiled_copy_r2s)>
|
|
||||||
<<<grid, block, 0, stream>>>(
|
|
||||||
reinterpret_cast<const T_IN*>(input.data_ptr()),
|
|
||||||
reinterpret_cast<const int*>(problem_sizes.data_ptr()),
|
|
||||||
reinterpret_cast<const int*>(expert_offsets.data_ptr()),
|
|
||||||
reinterpret_cast<const int*>(blockscale_offsets.data_ptr()),
|
|
||||||
reinterpret_cast<cutlass::float_e4m3_t*>(quant_output.data_ptr()),
|
|
||||||
reinterpret_cast<uint8_t*>(scale_factor.data_ptr()), num_experts,
|
|
||||||
tiled_copy_g2r, tiled_copy_r2g, tiled_copy_r2s);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace expert_specialization
|
|
||||||
@@ -2,6 +2,25 @@
|
|||||||
|
|
||||||
#include <torch/csrc/stable/library.h>
|
#include <torch/csrc/stable/library.h>
|
||||||
#include <torch/csrc/stable/tensor.h>
|
#include <torch/csrc/stable/tensor.h>
|
||||||
|
#include <torch/headeronly/util/Exception.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <torch/csrc/stable/ops.h>
|
||||||
|
|
||||||
|
inline torch::stable::Tensor weak_ref_tensor(torch::stable::Tensor& tensor) {
|
||||||
|
// Ensure tensor is on CUDA
|
||||||
|
STD_TORCH_CHECK(tensor.device().is_cuda(), "Tensor must be on CUDA device");
|
||||||
|
|
||||||
|
// Get the raw data pointer
|
||||||
|
void* data_ptr = tensor.mutable_data_ptr();
|
||||||
|
|
||||||
|
/// Create a new tensor from the raw data pointer
|
||||||
|
return torch::stable::from_blob(data_ptr, tensor.sizes(), tensor.strides(),
|
||||||
|
tensor.device(), tensor.scalar_type());
|
||||||
|
}
|
||||||
|
|
||||||
void per_token_group_quant_fp8(const torch::stable::Tensor& input,
|
void per_token_group_quant_fp8(const torch::stable::Tensor& input,
|
||||||
torch::stable::Tensor& output_q,
|
torch::stable::Tensor& output_q,
|
||||||
@@ -185,11 +204,12 @@ torch::stable::Tensor hadacore_transform(torch::stable::Tensor& x,
|
|||||||
|
|
||||||
// Layernorm kernels (shared CUDA/ROCm)
|
// Layernorm kernels (shared CUDA/ROCm)
|
||||||
void rms_norm(torch::stable::Tensor& out, torch::stable::Tensor& input,
|
void rms_norm(torch::stable::Tensor& out, torch::stable::Tensor& input,
|
||||||
torch::stable::Tensor& weight, double epsilon);
|
std::optional<torch::stable::Tensor> weight, double epsilon);
|
||||||
|
|
||||||
void fused_add_rms_norm(torch::stable::Tensor& input,
|
void fused_add_rms_norm(torch::stable::Tensor& input,
|
||||||
torch::stable::Tensor& residual,
|
torch::stable::Tensor& residual,
|
||||||
torch::stable::Tensor& weight, double epsilon);
|
std::optional<torch::stable::Tensor> weight,
|
||||||
|
double epsilon);
|
||||||
|
|
||||||
// Layernorm-quant kernels (shared CUDA/ROCm)
|
// Layernorm-quant kernels (shared CUDA/ROCm)
|
||||||
void rms_norm_static_fp8_quant(torch::stable::Tensor& out,
|
void rms_norm_static_fp8_quant(torch::stable::Tensor& out,
|
||||||
@@ -297,7 +317,8 @@ void fused_minimax_m3_qknorm_rope_kv_insert(
|
|||||||
std::optional<torch::stable::Tensor> kv_cache,
|
std::optional<torch::stable::Tensor> kv_cache,
|
||||||
std::optional<torch::stable::Tensor> index_cache, int64_t block_size,
|
std::optional<torch::stable::Tensor> index_cache, int64_t block_size,
|
||||||
std::optional<torch::stable::Tensor> q_out,
|
std::optional<torch::stable::Tensor> q_out,
|
||||||
std::optional<torch::stable::Tensor> index_q_out);
|
std::optional<torch::stable::Tensor> index_q_out,
|
||||||
|
const std::string& kv_cache_dtype);
|
||||||
|
|
||||||
// Sampler kernels (shared CUDA/ROCm)
|
// Sampler kernels (shared CUDA/ROCm)
|
||||||
void apply_repetition_penalties_(
|
void apply_repetition_penalties_(
|
||||||
@@ -366,6 +387,18 @@ void silu_and_mul(torch::stable::Tensor& out, torch::stable::Tensor& input);
|
|||||||
void silu_and_mul_clamp(torch::stable::Tensor& out,
|
void silu_and_mul_clamp(torch::stable::Tensor& out,
|
||||||
torch::stable::Tensor& input, double limit,
|
torch::stable::Tensor& input, double limit,
|
||||||
double alpha = 1.0, double beta = 0.0);
|
double alpha = 1.0, double beta = 0.0);
|
||||||
|
|
||||||
|
void silu_and_mul_quant(torch::stable::Tensor& out,
|
||||||
|
torch::stable::Tensor& input,
|
||||||
|
torch::stable::Tensor& scale);
|
||||||
|
|
||||||
|
void persistent_masked_m_silu_mul_quant(
|
||||||
|
const torch::stable::Tensor& input, // (E, T, 2*H)
|
||||||
|
const torch::stable::Tensor& tokens_per_expert, // (E)
|
||||||
|
torch::stable::Tensor& y_q, // (E, T, H) [OUT]
|
||||||
|
torch::stable::Tensor& y_s, // (E, T, H//group_size) [OUT]
|
||||||
|
bool use_ue8m0);
|
||||||
|
|
||||||
void mul_and_silu(torch::stable::Tensor& out, torch::stable::Tensor& input);
|
void mul_and_silu(torch::stable::Tensor& out, torch::stable::Tensor& input);
|
||||||
void gelu_and_mul(torch::stable::Tensor& out, torch::stable::Tensor& input);
|
void gelu_and_mul(torch::stable::Tensor& out, torch::stable::Tensor& input);
|
||||||
void gelu_tanh_and_mul(torch::stable::Tensor& out,
|
void gelu_tanh_and_mul(torch::stable::Tensor& out,
|
||||||
|
|||||||
+63
-55
@@ -1,16 +1,12 @@
|
|||||||
#include <ATen/cuda/CUDAContext.h>
|
#include "libtorch_stable/torch_utils.h"
|
||||||
#include <torch/all.h>
|
|
||||||
#include <c10/cuda/CUDAGuard.h>
|
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "core/math.hpp"
|
|
||||||
#include "../cuda_compat.h"
|
|
||||||
#include "dispatch_utils.h"
|
|
||||||
|
|
||||||
|
#include "libtorch_stable/core/math.hpp"
|
||||||
|
#include "cuda_compat.h"
|
||||||
|
#include "libtorch_stable/dispatch_utils.h"
|
||||||
#include "quantization/w8a8/fp8/common.cuh"
|
#include "quantization/w8a8/fp8/common.cuh"
|
||||||
|
|
||||||
#include <c10/util/Float8_e4m3fn.h>
|
|
||||||
|
|
||||||
#ifndef USE_ROCM
|
#ifndef USE_ROCM
|
||||||
#include <cuda_bf16.h>
|
#include <cuda_bf16.h>
|
||||||
#include <cuda_fp16.h>
|
#include <cuda_fp16.h>
|
||||||
@@ -33,7 +29,6 @@ typedef __hip_fp8x4_e4m3_fnuz __nv_fp8x4_e4m3;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "core/registration.h"
|
|
||||||
namespace vllm {
|
namespace vllm {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -564,41 +559,47 @@ __global__ void silu_mul_fp8_quant_deep_gemm_kernel(
|
|||||||
} // namespace vllm
|
} // namespace vllm
|
||||||
|
|
||||||
// Launch activation, gating, and quantize kernel.
|
// Launch activation, gating, and quantize kernel.
|
||||||
#define LAUNCH_ACTIVATION_GATE_KERNEL(KERNEL) \
|
#define LAUNCH_ACTIVATION_GATE_KERNEL(KERNEL) \
|
||||||
int d = input.size(-1) / 2; \
|
int d = input.size(-1) / 2; \
|
||||||
int64_t num_tokens = input.numel() / input.size(-1); \
|
int64_t num_tokens = input.numel() / input.size(-1); \
|
||||||
dim3 grid(num_tokens, num_tokens > 16 ? num_tokens > 32 ? 1 : 2 : 4); \
|
dim3 grid(num_tokens, num_tokens > 16 ? num_tokens > 32 ? 1 : 2 : 4); \
|
||||||
dim3 block(std::min(d, 512)); \
|
dim3 block(std::min(d, 512)); \
|
||||||
const at::cuda::OptionalCUDAGuard device_guard(device_of(input)); \
|
const torch::stable::accelerator::DeviceGuard device_guard( \
|
||||||
const cudaStream_t stream = at::cuda::getCurrentCUDAStream(); \
|
input.get_device_index()); \
|
||||||
VLLM_DISPATCH_FLOATING_TYPES( \
|
const cudaStream_t stream = \
|
||||||
input.scalar_type(), "act_and_mul_kernel", [&] { \
|
get_current_cuda_stream(input.get_device_index()); \
|
||||||
VLLM_DISPATCH_FP8_TYPES( \
|
VLLM_STABLE_DISPATCH_FLOATING_TYPES( \
|
||||||
out.scalar_type(), "fused_add_rms_norm_kernel_fp8_type", [&] { \
|
input.scalar_type(), "act_and_mul_kernel", [&] { \
|
||||||
vllm::act_and_mul_quant_kernel<scalar_t, KERNEL<scalar_t>, \
|
VLLM_STABLE_DISPATCH_FP8_TYPES( \
|
||||||
fp8_t> \
|
out.scalar_type(), "act_and_mul_quant_kernel_fp8_type", [&] { \
|
||||||
<<<grid, block, 0, stream>>>(out.data_ptr<fp8_t>(), \
|
vllm::act_and_mul_quant_kernel<scalar_t, KERNEL<scalar_t>, \
|
||||||
input.data_ptr<scalar_t>(), \
|
fp8_t> \
|
||||||
scale.data_ptr<float>(), d); \
|
<<<grid, block, 0, stream>>>( \
|
||||||
}); \
|
out.mutable_data_ptr<fp8_t>(), \
|
||||||
|
input.const_data_ptr<scalar_t>(), \
|
||||||
|
scale.const_data_ptr<float>(), d); \
|
||||||
|
}); \
|
||||||
});
|
});
|
||||||
|
|
||||||
void silu_and_mul_quant(torch::Tensor& out, // [..., d]
|
void silu_and_mul_quant(torch::stable::Tensor& out, // [..., d]
|
||||||
torch::Tensor& input, // [..., 2 * d]
|
torch::stable::Tensor& input, // [..., 2 * d]
|
||||||
torch::Tensor& scale) {
|
torch::stable::Tensor& scale) {
|
||||||
TORCH_CHECK(out.dtype() == torch::kFloat8_e4m3fn ||
|
STD_TORCH_CHECK(
|
||||||
out.dtype() == torch::kFloat8_e4m3fnuz);
|
out.scalar_type() == torch::headeronly::ScalarType::Float8_e4m3fn ||
|
||||||
TORCH_CHECK(input.dtype() == torch::kFloat16 ||
|
out.scalar_type() == torch::headeronly::ScalarType::Float8_e4m3fnuz);
|
||||||
input.dtype() == torch::kBFloat16);
|
STD_TORCH_CHECK(
|
||||||
TORCH_CHECK(input.size(-1) % 2 == 0);
|
input.scalar_type() == torch::headeronly::ScalarType::Half ||
|
||||||
|
input.scalar_type() == torch::headeronly::ScalarType::BFloat16,
|
||||||
|
"Input must be FP16 or BF16");
|
||||||
|
STD_TORCH_CHECK(input.size(-1) % 2 == 0);
|
||||||
LAUNCH_ACTIVATION_GATE_KERNEL(vllm::silu_kernel);
|
LAUNCH_ACTIVATION_GATE_KERNEL(vllm::silu_kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void persistent_masked_m_silu_mul_quant(
|
void persistent_masked_m_silu_mul_quant(
|
||||||
const at::Tensor& input, // (E, T, 2*H)
|
const torch::stable::Tensor& input, // (E, T, 2*H)
|
||||||
const at::Tensor& tokens_per_expert, // (E)
|
const torch::stable::Tensor& tokens_per_expert, // (E)
|
||||||
at::Tensor& y_q, // (E, T, H) [OUT]
|
torch::stable::Tensor& y_q, // (E, T, H) [OUT]
|
||||||
at::Tensor& y_s, // (E, T, H//group_size) [OUT]
|
torch::stable::Tensor& y_s, // (E, T, H//group_size) [OUT]
|
||||||
bool cast_scale_ue8m0) {
|
bool cast_scale_ue8m0) {
|
||||||
#ifndef USE_ROCM
|
#ifndef USE_ROCM
|
||||||
|
|
||||||
@@ -606,14 +607,18 @@ void persistent_masked_m_silu_mul_quant(
|
|||||||
// fixed GROUP_SIZE of 128.
|
// fixed GROUP_SIZE of 128.
|
||||||
static constexpr int GROUP_SIZE = 128;
|
static constexpr int GROUP_SIZE = 128;
|
||||||
|
|
||||||
TORCH_CHECK(input.dtype() == torch::kBFloat16);
|
STD_TORCH_CHECK(input.scalar_type() ==
|
||||||
TORCH_CHECK(y_q.dtype() == torch::kFloat8_e4m3fn ||
|
torch::headeronly::ScalarType::BFloat16);
|
||||||
y_q.dtype() == torch::kFloat8_e4m3fnuz);
|
STD_TORCH_CHECK(
|
||||||
TORCH_CHECK(input.size(-1) % (GROUP_SIZE * 2) == 0);
|
y_q.scalar_type() == torch::headeronly::ScalarType::Float8_e4m3fn ||
|
||||||
|
y_q.scalar_type() == torch::headeronly::ScalarType::Float8_e4m3fnuz);
|
||||||
|
STD_TORCH_CHECK(input.size(-1) % (GROUP_SIZE * 2) == 0);
|
||||||
|
|
||||||
bool const is_packed_ue8m0 =
|
bool const is_packed_ue8m0 =
|
||||||
(y_s.dtype() == torch::kInt32 && cast_scale_ue8m0);
|
(y_s.scalar_type() == torch::headeronly::ScalarType::Int &&
|
||||||
TORCH_CHECK(y_s.dtype() == torch::kFloat32 || is_packed_ue8m0);
|
cast_scale_ue8m0);
|
||||||
|
STD_TORCH_CHECK(y_s.scalar_type() == torch::headeronly::ScalarType::Float ||
|
||||||
|
is_packed_ue8m0);
|
||||||
|
|
||||||
using Idx_t = int64_t;
|
using Idx_t = int64_t;
|
||||||
|
|
||||||
@@ -631,7 +636,7 @@ void persistent_masked_m_silu_mul_quant(
|
|||||||
|
|
||||||
int const NUM_GROUPS = H / GROUP_SIZE;
|
int const NUM_GROUPS = H / GROUP_SIZE;
|
||||||
|
|
||||||
const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
|
const cudaStream_t stream = get_current_cuda_stream(input.get_device_index());
|
||||||
|
|
||||||
// TODO: Get this from cuda_arch ?
|
// TODO: Get this from cuda_arch ?
|
||||||
static constexpr int SILU_V2_BLOCK_COUNT = 132 * 32;
|
static constexpr int SILU_V2_BLOCK_COUNT = 132 * 32;
|
||||||
@@ -643,18 +648,21 @@ void persistent_masked_m_silu_mul_quant(
|
|||||||
static constexpr int max_shared_mem_bytes = \
|
static constexpr int max_shared_mem_bytes = \
|
||||||
GROUP_SIZE * 2 * STAGES * NUM_WARPS * 2; \
|
GROUP_SIZE * 2 * STAGES * NUM_WARPS * 2; \
|
||||||
dim3 grid(sms), block(THREAD_COUNT); \
|
dim3 grid(sms), block(THREAD_COUNT); \
|
||||||
const at::cuda::OptionalCUDAGuard device_guard(device_of(input)); \
|
const torch::stable::accelerator::DeviceGuard device_guard( \
|
||||||
VLLM_DISPATCH_FP8_TYPES( \
|
input.get_device_index()); \
|
||||||
|
VLLM_STABLE_DISPATCH_FP8_TYPES( \
|
||||||
y_q.scalar_type(), "silu_mul_fp8_quant_deep_gemm_kernel", [&] { \
|
y_q.scalar_type(), "silu_mul_fp8_quant_deep_gemm_kernel", [&] { \
|
||||||
vllm::silu_mul_fp8_quant_deep_gemm_kernel< \
|
vllm::silu_mul_fp8_quant_deep_gemm_kernel< \
|
||||||
BLOCK_COUNT, max_shared_mem_bytes, fp8_t, scale_t, THREAD_COUNT, \
|
BLOCK_COUNT, max_shared_mem_bytes, fp8_t, scale_t, THREAD_COUNT, \
|
||||||
Idx_t, CEIL_UE8M0, GROUP_SIZE, STAGES> \
|
Idx_t, CEIL_UE8M0, GROUP_SIZE, STAGES> \
|
||||||
<<<grid, block, max_shared_mem_bytes + (E + 1) * 16, stream>>>( \
|
<<<grid, block, max_shared_mem_bytes + (E + 1) * 16, stream>>>( \
|
||||||
reinterpret_cast<__nv_bfloat16*>(input.data_ptr()), \
|
reinterpret_cast<const __nv_bfloat16*>( \
|
||||||
(fp8_t*)y_q.data_ptr(), \
|
input.const_data_ptr()), \
|
||||||
reinterpret_cast<scale_t*>(y_s.data_ptr()), \
|
y_q.mutable_data_ptr<fp8_t>(), \
|
||||||
reinterpret_cast<int32_t*>(tokens_per_expert.data_ptr()), E, \
|
reinterpret_cast<scale_t*>(y_s.mutable_data_ptr()), \
|
||||||
T, H, stride_i_e, stride_i_t, stride_i_h, stride_yq_e, \
|
reinterpret_cast<const int32_t*>( \
|
||||||
|
tokens_per_expert.const_data_ptr()), \
|
||||||
|
E, T, H, stride_i_e, stride_i_t, stride_i_h, stride_yq_e, \
|
||||||
stride_yq_t, stride_yq_h, STRIDE_YS_E, STRIDE_YS_T, \
|
stride_yq_t, stride_yq_h, STRIDE_YS_E, STRIDE_YS_T, \
|
||||||
STRIDE_YS_G, STRIDE_YS_P, stride_counts_e); \
|
STRIDE_YS_G, STRIDE_YS_P, stride_counts_e); \
|
||||||
});
|
});
|
||||||
@@ -679,7 +687,7 @@ void persistent_masked_m_silu_mul_quant(
|
|||||||
Idx_t stride_ys_g = y_s.stride(2);
|
Idx_t stride_ys_g = y_s.stride(2);
|
||||||
Idx_t stride_ys_p = 0;
|
Idx_t stride_ys_p = 0;
|
||||||
if (!cast_scale_ue8m0) {
|
if (!cast_scale_ue8m0) {
|
||||||
TORCH_CHECK(!is_packed_ue8m0);
|
STD_TORCH_CHECK(!is_packed_ue8m0);
|
||||||
LAUNCH_ON_H(float, stride_ys_e, stride_ys_t, stride_ys_g, stride_ys_p,
|
LAUNCH_ON_H(float, stride_ys_e, stride_ys_t, stride_ys_g, stride_ys_p,
|
||||||
false);
|
false);
|
||||||
return;
|
return;
|
||||||
@@ -692,8 +700,8 @@ void persistent_masked_m_silu_mul_quant(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TORCH_CHECK(cast_scale_ue8m0 && is_packed_ue8m0);
|
STD_TORCH_CHECK(cast_scale_ue8m0 && is_packed_ue8m0);
|
||||||
TORCH_CHECK(y_s.dtype() == torch::kInt32);
|
STD_TORCH_CHECK(y_s.scalar_type() == torch::headeronly::ScalarType::Int);
|
||||||
|
|
||||||
// Int32 packed ue8m0 scales tensor.
|
// Int32 packed ue8m0 scales tensor.
|
||||||
// Let E, T, G be the number to experts, number of tokens and number of groups
|
// Let E, T, G be the number to experts, number of tokens and number of groups
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#include "cutlass/util/packed_stride.hpp"
|
#include "cutlass/util/packed_stride.hpp"
|
||||||
|
|
||||||
#include "core/math.hpp"
|
#include "libtorch_stable/core/math.hpp"
|
||||||
#include "core/batch_invariant.hpp"
|
#include "core/batch_invariant.hpp"
|
||||||
|
|
||||||
using namespace cute;
|
using namespace cute;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#include "cutlass/util/packed_stride.hpp"
|
#include "cutlass/util/packed_stride.hpp"
|
||||||
|
|
||||||
#include "core/math.hpp"
|
#include "libtorch_stable/core/math.hpp"
|
||||||
#include "core/batch_invariant.hpp"
|
#include "core/batch_invariant.hpp"
|
||||||
|
|
||||||
using namespace cute;
|
using namespace cute;
|
||||||
|
|||||||
@@ -24,13 +24,21 @@ __device__ inline void vectorize_with_alignment(
|
|||||||
ScaOp&& scalar_op) { // InT -> OutT
|
ScaOp&& scalar_op) { // InT -> OutT
|
||||||
static_assert(VEC_SIZE > 0 && (VEC_SIZE & (VEC_SIZE - 1)) == 0,
|
static_assert(VEC_SIZE > 0 && (VEC_SIZE & (VEC_SIZE - 1)) == 0,
|
||||||
"VEC_SIZE must be a positive power-of-two");
|
"VEC_SIZE must be a positive power-of-two");
|
||||||
constexpr int WIDTH = VEC_SIZE * sizeof(InT); // eg: 64 B
|
constexpr int WIDTH = VEC_SIZE * sizeof(InT); // eg: 16 B
|
||||||
|
constexpr int OUT_WIDTH = VEC_SIZE * sizeof(OutT); // eg: 16 B
|
||||||
uintptr_t addr = reinterpret_cast<uintptr_t>(in);
|
uintptr_t addr = reinterpret_cast<uintptr_t>(in);
|
||||||
|
uintptr_t out_addr = reinterpret_cast<uintptr_t>(out);
|
||||||
|
|
||||||
// fast path when the whole region is already aligned
|
// fast path when input and output are both fully aligned. The vector
|
||||||
// Note: currently the output is guaranteed to be same as the input, so we
|
// load/store below go through vec_n_t<T, VEC_SIZE>, declared
|
||||||
// don't check it here, comments here just for future reference.
|
// __align__(VEC_SIZE * sizeof(T)), so each side must be aligned to its
|
||||||
bool can_vec = ((addr & (WIDTH - 1)) == 0) && ((len & (VEC_SIZE - 1)) == 0);
|
// own vector width. out is NOT generally co-aligned with in: e.g.
|
||||||
|
// reshape_and_cache_flash writes KV-cache rows whose byte offset is a
|
||||||
|
// multiple of head_size, which for head sizes that are not a multiple
|
||||||
|
// of VEC_SIZE puts some rows off the vector-width boundary.
|
||||||
|
bool can_vec = ((addr & (WIDTH - 1)) == 0) &&
|
||||||
|
((out_addr & (OUT_WIDTH - 1)) == 0) &&
|
||||||
|
((len & (VEC_SIZE - 1)) == 0);
|
||||||
if (can_vec) {
|
if (can_vec) {
|
||||||
int num_vec = len / VEC_SIZE;
|
int num_vec = len / VEC_SIZE;
|
||||||
|
|
||||||
@@ -55,6 +63,16 @@ __device__ inline void vectorize_with_alignment(
|
|||||||
prefix_elems /= sizeof(InT);
|
prefix_elems /= sizeof(InT);
|
||||||
prefix_elems = min(prefix_elems, len); // 0 ≤ prefix < 16
|
prefix_elems = min(prefix_elems, len); // 0 ≤ prefix < 16
|
||||||
|
|
||||||
|
// the prefix below aligns in; if that does not also align out (their
|
||||||
|
// addresses differ modulo the vector width), vectorizing is impossible
|
||||||
|
// and the whole copy must stay scalar.
|
||||||
|
if (((out_addr + prefix_elems * sizeof(OutT)) & (OUT_WIDTH - 1)) != 0) {
|
||||||
|
for (int i = tid; i < len; i += stride) {
|
||||||
|
scalar_op(out[i], in[i]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 1. prefill the when it is unsafe to vectorize
|
// 1. prefill the when it is unsafe to vectorize
|
||||||
for (int i = tid; i < prefix_elems; i += stride) {
|
for (int i = tid; i < prefix_elems; i += stride) {
|
||||||
scalar_op(out[i], in[i]);
|
scalar_op(out[i], in[i]);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include "cutlass/gemm/collective/collective_builder.hpp"
|
#include "cutlass/gemm/collective/collective_builder.hpp"
|
||||||
#include "cutlass/util/packed_stride.hpp"
|
#include "cutlass/util/packed_stride.hpp"
|
||||||
|
|
||||||
#include "core/math.hpp"
|
#include "libtorch_stable/core/math.hpp"
|
||||||
#include "libtorch_stable/cutlass_extensions/common.hpp"
|
#include "libtorch_stable/cutlass_extensions/common.hpp"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
#include "cutlass/epilogue/collective/collective_builder.hpp"
|
#include "cutlass/epilogue/collective/collective_builder.hpp"
|
||||||
#include "cutlass/gemm/collective/collective_builder.hpp"
|
#include "cutlass/gemm/collective/collective_builder.hpp"
|
||||||
|
|
||||||
#include "core/math.hpp"
|
#include "libtorch_stable/core/math.hpp"
|
||||||
#include "libtorch_stable/cutlass_extensions/common.hpp"
|
#include "libtorch_stable/cutlass_extensions/common.hpp"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
#include "cutlass/epilogue/threadblock/fusion/visitors.hpp"
|
#include "cutlass/epilogue/threadblock/fusion/visitors.hpp"
|
||||||
#include "cutlass/gemm/kernel/default_gemm_universal_with_visitor.h"
|
#include "cutlass/gemm/kernel/default_gemm_universal_with_visitor.h"
|
||||||
|
|
||||||
#include "core/math.hpp"
|
#include "libtorch_stable/core/math.hpp"
|
||||||
#include "libtorch_stable/cutlass_extensions/common.hpp"
|
#include "libtorch_stable/cutlass_extensions/common.hpp"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|||||||
@@ -301,12 +301,21 @@ __global__ void per_token_group_quant_8bit_packed_register_kernel(
|
|||||||
|
|
||||||
const int sf_k_local = local_group_id % kGroupsPerBlockX;
|
const int sf_k_local = local_group_id % kGroupsPerBlockX;
|
||||||
const int row_local = local_group_id / kGroupsPerBlockX;
|
const int row_local = local_group_id / kGroupsPerBlockX;
|
||||||
const int sf_k_idx = blockIdx.x * kGroupsPerBlockX + sf_k_local;
|
// Rows on grid.x: mn scales with tokens and can exceed the 65535 grid.y cap.
|
||||||
const int mn_idx = blockIdx.y * kRowsPerBlock + row_local;
|
const int sf_k_idx = blockIdx.y * kGroupsPerBlockX + sf_k_local;
|
||||||
|
const int mn_idx = blockIdx.x * kRowsPerBlock + row_local;
|
||||||
|
|
||||||
|
#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900))
|
||||||
|
asm volatile("griddepcontrol.wait;");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (mn_idx >= tma_aligned_mn) {
|
if (mn_idx >= tma_aligned_mn) {
|
||||||
|
#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900))
|
||||||
|
asm volatile("griddepcontrol.launch_dependents;");
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool is_valid_group = (mn_idx < mn) && (sf_k_idx < groups_per_row);
|
const bool is_valid_group = (mn_idx < mn) && (sf_k_idx < groups_per_row);
|
||||||
|
|
||||||
// Load 16 input elements (32 B) into registers as two adjacent uint4
|
// Load 16 input elements (32 B) into registers as two adjacent uint4
|
||||||
@@ -417,6 +426,10 @@ __global__ void per_token_group_quant_8bit_packed_register_kernel(
|
|||||||
static_cast<int64_t>(mn_idx) * groups_per_row * GROUP_SIZE +
|
static_cast<int64_t>(mn_idx) * groups_per_row * GROUP_SIZE +
|
||||||
sf_k_idx * GROUP_SIZE + lane_id * VEC_SIZE;
|
sf_k_idx * GROUP_SIZE + lane_id * VEC_SIZE;
|
||||||
*reinterpret_cast<uint4*>(group_output) = packed_out;
|
*reinterpret_cast<uint4*>(group_output) = packed_out;
|
||||||
|
|
||||||
|
#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900))
|
||||||
|
asm volatile("griddepcontrol.launch_dependents;");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public entry point: register-resident packed quant kernel.
|
// Public entry point: register-resident packed quant kernel.
|
||||||
@@ -484,34 +497,66 @@ void per_token_group_quant_8bit_packed(const torch::stable::Tensor& input,
|
|||||||
" is not a multiple of 4.");
|
" is not a multiple of 4.");
|
||||||
const int kx = GetGroupsPerBlockX(padded_groups_per_row);
|
const int kx = GetGroupsPerBlockX(padded_groups_per_row);
|
||||||
const int ry = 16 / kx;
|
const int ry = 16 / kx;
|
||||||
const int64_t blocks_x = padded_groups_per_row / kx;
|
const int64_t row_blocks = (tma_aligned_mn + ry - 1) / ry;
|
||||||
const int64_t blocks_y = (tma_aligned_mn + ry - 1) / ry;
|
const int64_t sf_k_blocks = padded_groups_per_row / kx;
|
||||||
const int num_threads = (kx * ry) * THREADS_PER_GROUP;
|
const int num_threads = (kx * ry) * THREADS_PER_GROUP;
|
||||||
// CUDA caps grid.x and grid.y at 2^31 - 1; guard against pathological inputs.
|
// CUDA caps grid.x at 2^31 - 1 and grid.y at 2^16 - 1 (65535).
|
||||||
STD_TORCH_CHECK(blocks_x <= static_cast<int64_t>(INT32_MAX) &&
|
constexpr int64_t kMaxGridDimYZ = 65535;
|
||||||
blocks_y <= static_cast<int64_t>(INT32_MAX),
|
STD_TORCH_CHECK(row_blocks <= static_cast<int64_t>(INT32_MAX) &&
|
||||||
|
sf_k_blocks <= kMaxGridDimYZ,
|
||||||
"per_token_group_quant_8bit_packed grid too large: (",
|
"per_token_group_quant_8bit_packed grid too large: (",
|
||||||
blocks_x, ", ", blocks_y, ").");
|
row_blocks, ", ", sf_k_blocks, ").");
|
||||||
|
|
||||||
auto dst_type = output_q.scalar_type();
|
auto dst_type = output_q.scalar_type();
|
||||||
|
|
||||||
#define LAUNCH_REG_KERNEL_INST(T, DST_DTYPE, KX, RY) \
|
// PDL (Programmatic Dependent Launch) is NVIDIA-only; ROCm/HIP has no
|
||||||
do { \
|
// equivalent launch attribute, so fall back to a classic launch there.
|
||||||
dim3 grid(static_cast<unsigned int>(blocks_x), \
|
#ifndef USE_ROCM
|
||||||
static_cast<unsigned int>(blocks_y)); \
|
#define LAUNCH_REG_KERNEL_INST(T, DST_DTYPE, KX, RY) \
|
||||||
dim3 block(num_threads); \
|
do { \
|
||||||
per_token_group_quant_8bit_packed_register_kernel<T, DST_DTYPE, 128, KX, \
|
cudaLaunchConfig_t config = {}; \
|
||||||
RY> \
|
config.gridDim = dim3(static_cast<unsigned int>(row_blocks), \
|
||||||
<<<grid, block, 0, stream>>>( \
|
static_cast<unsigned int>(sf_k_blocks)); \
|
||||||
static_cast<const T*>(input.data_ptr()), output_q.data_ptr(), \
|
config.blockDim = dim3(num_threads); \
|
||||||
reinterpret_cast<unsigned int*>(output_s_packed.data_ptr()), \
|
config.dynamicSmemBytes = 0; \
|
||||||
static_cast<int>(padded_groups_per_row), \
|
config.stream = stream; \
|
||||||
static_cast<int>(groups_per_row), static_cast<int>(mn), \
|
cudaLaunchAttribute attrs[1]; \
|
||||||
static_cast<int>(output_q_mn_extent), \
|
attrs[0].id = cudaLaunchAttributeProgrammaticStreamSerialization; \
|
||||||
static_cast<int>(tma_aligned_mn), num_scale_elems, \
|
attrs[0].val.programmaticStreamSerializationAllowed = 1; \
|
||||||
static_cast<float>(eps), static_cast<float>(min_8bit), \
|
config.numAttrs = 1; \
|
||||||
static_cast<float>(max_8bit)); \
|
config.attrs = attrs; \
|
||||||
} while (0)
|
cudaLaunchKernelEx( \
|
||||||
|
&config, \
|
||||||
|
per_token_group_quant_8bit_packed_register_kernel<T, DST_DTYPE, 128, \
|
||||||
|
KX, RY>, \
|
||||||
|
static_cast<const T*>(input.data_ptr()), output_q.data_ptr(), \
|
||||||
|
reinterpret_cast<unsigned int*>(output_s_packed.data_ptr()), \
|
||||||
|
static_cast<int>(padded_groups_per_row), \
|
||||||
|
static_cast<int>(groups_per_row), static_cast<int>(mn), \
|
||||||
|
static_cast<int>(output_q_mn_extent), \
|
||||||
|
static_cast<int>(tma_aligned_mn), num_scale_elems, \
|
||||||
|
static_cast<float>(eps), static_cast<float>(min_8bit), \
|
||||||
|
static_cast<float>(max_8bit)); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define LAUNCH_REG_KERNEL_INST(T, DST_DTYPE, KX, RY) \
|
||||||
|
do { \
|
||||||
|
dim3 grid(static_cast<unsigned int>(row_blocks), \
|
||||||
|
static_cast<unsigned int>(sf_k_blocks)); \
|
||||||
|
dim3 block(num_threads); \
|
||||||
|
per_token_group_quant_8bit_packed_register_kernel<T, DST_DTYPE, 128, KX, \
|
||||||
|
RY> \
|
||||||
|
<<<grid, block, 0, stream>>>( \
|
||||||
|
static_cast<const T*>(input.data_ptr()), output_q.data_ptr(), \
|
||||||
|
reinterpret_cast<unsigned int*>(output_s_packed.data_ptr()), \
|
||||||
|
static_cast<int>(padded_groups_per_row), \
|
||||||
|
static_cast<int>(groups_per_row), static_cast<int>(mn), \
|
||||||
|
static_cast<int>(output_q_mn_extent), \
|
||||||
|
static_cast<int>(tma_aligned_mn), num_scale_elems, \
|
||||||
|
static_cast<float>(eps), static_cast<float>(min_8bit), \
|
||||||
|
static_cast<float>(max_8bit)); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define LAUNCH_REG_KERNEL(T, DST_DTYPE) \
|
#define LAUNCH_REG_KERNEL(T, DST_DTYPE) \
|
||||||
do { \
|
do { \
|
||||||
|
|||||||
@@ -34,6 +34,20 @@ STABLE_TORCH_LIBRARY_FRAGMENT(_C, ops) {
|
|||||||
// TODO: Remove this once ROCm upgrade to torch 2.11.
|
// TODO: Remove this once ROCm upgrade to torch 2.11.
|
||||||
ops.def("get_cuda_view_from_cpu_tensor(Tensor cpu_tensor) -> Tensor");
|
ops.def("get_cuda_view_from_cpu_tensor(Tensor cpu_tensor) -> Tensor");
|
||||||
|
|
||||||
|
// Note about marlin kernel 'workspace' arguments:
|
||||||
|
// Technically these should be mutable since they are modified by the kernel.
|
||||||
|
// But since they are set back to zero once the kernel is finished we can
|
||||||
|
// hand wave and say that they have no net effect.
|
||||||
|
//
|
||||||
|
// The reason to mark 'workspace' as immutable is so that they don't interfere
|
||||||
|
// with using ScalarType arguments in the ops. If they are marked as mutable,
|
||||||
|
// pytorch throws an assert in
|
||||||
|
// 'torch._higher_order_ops._register_effectful_op' that prevents these
|
||||||
|
// kernels from being torch.compile'd.
|
||||||
|
// See the following document for more info on custom types and ops that use
|
||||||
|
// custom types:
|
||||||
|
// https://docs.google.com/document/d/18fBMPuOJ0fY5ZQ6YyrHUppw9FA332CpNtgB6SOIgyuA
|
||||||
|
|
||||||
// Machete (Dense) Optimized Mixed Precision GEMM for Hopper.
|
// Machete (Dense) Optimized Mixed Precision GEMM for Hopper.
|
||||||
ops.def(
|
ops.def(
|
||||||
"machete_supported_schedules("
|
"machete_supported_schedules("
|
||||||
@@ -308,22 +322,6 @@ STABLE_TORCH_LIBRARY_FRAGMENT(_C, ops) {
|
|||||||
"awq_dequantize(Tensor _kernel, Tensor _scaling_factors, "
|
"awq_dequantize(Tensor _kernel, Tensor _scaling_factors, "
|
||||||
"Tensor _zeros, SymInt split_k_iters, int thx, int thy) -> Tensor");
|
"Tensor _zeros, SymInt split_k_iters, int thx, int thy) -> Tensor");
|
||||||
|
|
||||||
// Expert-specialization mxfp8 blockscaled grouped quantization (SM100+).
|
|
||||||
ops.def(
|
|
||||||
"mxfp8_experts_quant("
|
|
||||||
" Tensor input, Tensor problem_sizes, Tensor expert_offsets,"
|
|
||||||
" Tensor blockscale_offsets, Tensor! quant_output, Tensor! scale_factor)"
|
|
||||||
" -> ()");
|
|
||||||
// conditionally compiled so impl registration is in source file
|
|
||||||
|
|
||||||
// Expert-specialization mxfp8 blockscaled grouped GEMM (SM100+).
|
|
||||||
ops.def(
|
|
||||||
"cutlass_mxfp8_grouped_mm("
|
|
||||||
" Tensor a, Tensor b, Tensor sfa, Tensor sfb, Tensor! out,"
|
|
||||||
" Tensor problem_sizes, Tensor expert_offsets, Tensor blockscale_offsets)"
|
|
||||||
" -> ()");
|
|
||||||
// conditionally compiled so impl registration is in source file
|
|
||||||
|
|
||||||
// DeepSeek V3 fused A GEMM (SM 9.0+, bf16 only, 1-16 tokens).
|
// DeepSeek V3 fused A GEMM (SM 9.0+, bf16 only, 1-16 tokens).
|
||||||
// conditionally compiled so impl registration is in source file
|
// conditionally compiled so impl registration is in source file
|
||||||
ops.def(
|
ops.def(
|
||||||
@@ -369,12 +367,13 @@ STABLE_TORCH_LIBRARY_FRAGMENT(_C, ops) {
|
|||||||
|
|
||||||
// Apply Root Mean Square (RMS) Normalization to the input tensor.
|
// Apply Root Mean Square (RMS) Normalization to the input tensor.
|
||||||
ops.def(
|
ops.def(
|
||||||
"rms_norm(Tensor! result, Tensor input, Tensor weight, float epsilon) -> "
|
"rms_norm(Tensor! result, Tensor input, Tensor? weight, float epsilon) "
|
||||||
|
"-> "
|
||||||
"()");
|
"()");
|
||||||
|
|
||||||
// In-place fused Add and RMS Normalization.
|
// In-place fused Add and RMS Normalization.
|
||||||
ops.def(
|
ops.def(
|
||||||
"fused_add_rms_norm(Tensor! input, Tensor! residual, Tensor weight, "
|
"fused_add_rms_norm(Tensor! input, Tensor! residual, Tensor? weight, "
|
||||||
"float epsilon) -> ()");
|
"float epsilon) -> ()");
|
||||||
|
|
||||||
// Layernorm-quant
|
// Layernorm-quant
|
||||||
@@ -471,7 +470,8 @@ STABLE_TORCH_LIBRARY_FRAGMENT(_C, ops) {
|
|||||||
"int num_index_heads, "
|
"int num_index_heads, "
|
||||||
"Tensor? slot_mapping, Tensor? index_slot_mapping, "
|
"Tensor? slot_mapping, Tensor? index_slot_mapping, "
|
||||||
"Tensor!? kv_cache, Tensor!? index_cache, "
|
"Tensor!? kv_cache, Tensor!? index_cache, "
|
||||||
"int block_size, Tensor!? q_out, Tensor!? index_q_out) -> ()");
|
"int block_size, Tensor!? q_out, Tensor!? index_q_out, "
|
||||||
|
"str kv_cache_dtype) -> ()");
|
||||||
|
|
||||||
// Apply repetition penalties to logits in-place.
|
// Apply repetition penalties to logits in-place.
|
||||||
ops.def(
|
ops.def(
|
||||||
@@ -494,6 +494,11 @@ STABLE_TORCH_LIBRARY_FRAGMENT(_C, ops) {
|
|||||||
"Tensor workspace, int k, int max_seq_len) -> ()");
|
"Tensor workspace, int k, int max_seq_len) -> ()");
|
||||||
|
|
||||||
// Activation ops
|
// Activation ops
|
||||||
|
ops.def(
|
||||||
|
"persistent_masked_m_silu_mul_quant(Tensor input, Tensor counts, Tensor! "
|
||||||
|
"y_q, Tensor! y_s, bool use_ue8m0) -> ()");
|
||||||
|
ops.def("weak_ref_tensor(Tensor input) -> Tensor");
|
||||||
|
|
||||||
// Activation function used in SwiGLU.
|
// Activation function used in SwiGLU.
|
||||||
ops.def("silu_and_mul(Tensor! result, Tensor input) -> ()");
|
ops.def("silu_and_mul(Tensor! result, Tensor input) -> ()");
|
||||||
|
|
||||||
@@ -506,6 +511,10 @@ STABLE_TORCH_LIBRARY_FRAGMENT(_C, ops) {
|
|||||||
"silu_and_mul_with_clamp(Tensor! result, Tensor input, float limit, "
|
"silu_and_mul_with_clamp(Tensor! result, Tensor input, float limit, "
|
||||||
"float alpha=1.0, float beta=0.0) -> ()");
|
"float alpha=1.0, float beta=0.0) -> ()");
|
||||||
|
|
||||||
|
// SwiGLU activation with FP8 quantization.
|
||||||
|
ops.def(
|
||||||
|
"silu_and_mul_quant(Tensor! result, Tensor input, Tensor scale) -> ()");
|
||||||
|
|
||||||
// Activation function used in GeGLU with `none` approximation.
|
// Activation function used in GeGLU with `none` approximation.
|
||||||
ops.def("gelu_and_mul(Tensor! out, Tensor input) -> ()");
|
ops.def("gelu_and_mul(Tensor! out, Tensor input) -> ()");
|
||||||
|
|
||||||
@@ -704,6 +713,10 @@ STABLE_TORCH_LIBRARY_IMPL(_C, CUDA, ops) {
|
|||||||
ops.impl("persistent_topk", TORCH_BOX(&persistent_topk));
|
ops.impl("persistent_topk", TORCH_BOX(&persistent_topk));
|
||||||
|
|
||||||
// Activation kernels (shared CUDA/ROCm)
|
// Activation kernels (shared CUDA/ROCm)
|
||||||
|
ops.impl("persistent_masked_m_silu_mul_quant",
|
||||||
|
TORCH_BOX(&persistent_masked_m_silu_mul_quant));
|
||||||
|
ops.impl("weak_ref_tensor", TORCH_BOX(&weak_ref_tensor));
|
||||||
|
ops.impl("silu_and_mul_quant", TORCH_BOX(&silu_and_mul_quant));
|
||||||
ops.impl("silu_and_mul", TORCH_BOX(&silu_and_mul));
|
ops.impl("silu_and_mul", TORCH_BOX(&silu_and_mul));
|
||||||
ops.impl("mul_and_silu", TORCH_BOX(&mul_and_silu));
|
ops.impl("mul_and_silu", TORCH_BOX(&mul_and_silu));
|
||||||
ops.impl("gelu_and_mul", TORCH_BOX(&gelu_and_mul));
|
ops.impl("gelu_and_mul", TORCH_BOX(&gelu_and_mul));
|
||||||
|
|||||||
+3
-35
@@ -9,36 +9,14 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
torch::Tensor weak_ref_tensor(torch::Tensor& tensor) {
|
|
||||||
// Ensure tensor is on CUDA
|
|
||||||
if (!tensor.is_cuda()) {
|
|
||||||
throw std::runtime_error("Tensor must be on CUDA device");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the raw data pointer
|
|
||||||
void* data_ptr = tensor.data_ptr();
|
|
||||||
|
|
||||||
// Get tensor sizes and strides
|
|
||||||
std::vector<int64_t> sizes = tensor.sizes().vec();
|
|
||||||
std::vector<int64_t> strides = tensor.strides().vec();
|
|
||||||
|
|
||||||
// Get tensor options (dtype, device)
|
|
||||||
auto options = tensor.options();
|
|
||||||
|
|
||||||
// Create a new tensor from the raw data pointer
|
|
||||||
auto new_tensor = torch::from_blob(data_ptr, sizes, strides, options);
|
|
||||||
|
|
||||||
return new_tensor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rms_norm and fused_add_rms_norm declarations also exist in
|
// rms_norm and fused_add_rms_norm declarations also exist in
|
||||||
// csrc/libtorch_stable/ops.h (torch::stable ABI for CUDA). They remain here
|
// csrc/libtorch_stable/ops.h (torch::stable ABI for CUDA). They remain here
|
||||||
// because the CPU build still uses these torch::Tensor declarations.
|
// because the CPU build still uses these torch::Tensor declarations.
|
||||||
void rms_norm(torch::Tensor& out, torch::Tensor& input, torch::Tensor& weight,
|
void rms_norm(torch::Tensor& out, torch::Tensor& input,
|
||||||
double epsilon);
|
std::optional<torch::Tensor> weight, double epsilon);
|
||||||
|
|
||||||
void fused_add_rms_norm(torch::Tensor& input, torch::Tensor& residual,
|
void fused_add_rms_norm(torch::Tensor& input, torch::Tensor& residual,
|
||||||
torch::Tensor& weight, double epsilon);
|
std::optional<torch::Tensor> weight, double epsilon);
|
||||||
|
|
||||||
// rotary_embedding also exist in csrc/libtorch_stable/ops.h (torch::stable
|
// rotary_embedding also exist in csrc/libtorch_stable/ops.h (torch::stable
|
||||||
// ABI for CUDA). It remains here because the CPU build still uses these
|
// ABI for CUDA). It remains here because the CPU build still uses these
|
||||||
@@ -53,16 +31,6 @@ void silu_and_mul(torch::Tensor& out, torch::Tensor& input);
|
|||||||
void silu_and_mul_clamp(torch::Tensor& out, torch::Tensor& input, double limit,
|
void silu_and_mul_clamp(torch::Tensor& out, torch::Tensor& input, double limit,
|
||||||
double alpha = 1.0, double beta = 0.0);
|
double alpha = 1.0, double beta = 0.0);
|
||||||
|
|
||||||
void silu_and_mul_quant(torch::Tensor& out, torch::Tensor& input,
|
|
||||||
torch::Tensor& scale);
|
|
||||||
|
|
||||||
void persistent_masked_m_silu_mul_quant(
|
|
||||||
const at::Tensor& input, // (E, T, 2*H)
|
|
||||||
const at::Tensor& counts, // (E)
|
|
||||||
at::Tensor& y_q, // (E, T, H) [OUT]
|
|
||||||
at::Tensor& y_s, // (E, T, H//group_size) [OUT]
|
|
||||||
bool use_ue8m0);
|
|
||||||
|
|
||||||
void gelu_and_mul(torch::Tensor& out, torch::Tensor& input);
|
void gelu_and_mul(torch::Tensor& out, torch::Tensor& input);
|
||||||
|
|
||||||
void gelu_tanh_and_mul(torch::Tensor& out, torch::Tensor& input);
|
void gelu_tanh_and_mul(torch::Tensor& out, torch::Tensor& input);
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include "core/registration.h"
|
||||||
|
|
||||||
|
// QuTLASS registers torch.ops._qutlass_C via TORCH_LIBRARY in bindings.cpp.
|
||||||
|
// This stub lets Python import vllm._qutlass_C to trigger op registration.
|
||||||
|
REGISTER_EXTENSION(_qutlass_C)
|
||||||
@@ -20,17 +20,6 @@
|
|||||||
|
|
||||||
TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
|
TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
|
||||||
// vLLM custom ops
|
// vLLM custom ops
|
||||||
//
|
|
||||||
|
|
||||||
ops.def(
|
|
||||||
"persistent_masked_m_silu_mul_quant(Tensor input, Tensor counts, Tensor! "
|
|
||||||
"y_q, Tensor! y_s,"
|
|
||||||
"bool use_ue8m0) -> ()");
|
|
||||||
ops.impl("persistent_masked_m_silu_mul_quant", torch::kCUDA,
|
|
||||||
&persistent_masked_m_silu_mul_quant);
|
|
||||||
|
|
||||||
ops.def("weak_ref_tensor(Tensor input) -> Tensor");
|
|
||||||
ops.impl("weak_ref_tensor", torch::kCUDA, &weak_ref_tensor);
|
|
||||||
|
|
||||||
#ifdef USE_ROCM
|
#ifdef USE_ROCM
|
||||||
// TODO: Remove this once we upgrade to torch 2.11.
|
// TODO: Remove this once we upgrade to torch 2.11.
|
||||||
@@ -39,35 +28,6 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
|
|||||||
ops.def("get_cuda_view_from_cpu_tensor(Tensor cpu_tensor) -> Tensor");
|
ops.def("get_cuda_view_from_cpu_tensor(Tensor cpu_tensor) -> Tensor");
|
||||||
ops.impl("get_cuda_view_from_cpu_tensor", torch::kCPU,
|
ops.impl("get_cuda_view_from_cpu_tensor", torch::kCPU,
|
||||||
&get_cuda_view_from_cpu_tensor);
|
&get_cuda_view_from_cpu_tensor);
|
||||||
#endif
|
|
||||||
|
|
||||||
// Activation ops (quantized only — basic ops moved to _C_stable_libtorch)
|
|
||||||
ops.def(
|
|
||||||
"silu_and_mul_quant(Tensor! result, Tensor input, Tensor scale) -> ()");
|
|
||||||
ops.impl("silu_and_mul_quant", torch::kCUDA, &silu_and_mul_quant);
|
|
||||||
|
|
||||||
// Horizontally-fused DeepseekV4-MLA: per-head RMSNorm + GPT-J RoPE for Q, and
|
|
||||||
// GPT-J RoPE + UE8M0 FP8 quant + paged cache insert for KV, all in one
|
|
||||||
// kernel launch. Registered in _C_stable_libtorch (incl. the FlashInfer V4
|
|
||||||
// full-cache bf16/fp8 variants).
|
|
||||||
|
|
||||||
// Quantization ops
|
|
||||||
#ifndef USE_ROCM
|
|
||||||
|
|
||||||
// Note about marlin kernel 'workspace' arguments:
|
|
||||||
// Technically these should be mutable since they are modified by the kernel.
|
|
||||||
// But since they are set back to zero once the kernel is finished we can
|
|
||||||
// hand wave and say that they have no net effect.
|
|
||||||
//
|
|
||||||
// The reason to mark 'workspace' as immutable is so that they don't interfere
|
|
||||||
// with using ScalarType arguments in the ops. If they are marked as mutable,
|
|
||||||
// pytorch throws an assert in
|
|
||||||
// 'torch._higher_order_ops._register_effectful_op' that prevents these
|
|
||||||
// kernels from being torch.compile'd.
|
|
||||||
// See the following document for more info on custom types and ops that use
|
|
||||||
// custom types:
|
|
||||||
// https://docs.google.com/document/d/18fBMPuOJ0fY5ZQ6YyrHUppw9FA332CpNtgB6SOIgyuA
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-19
@@ -75,13 +75,13 @@ RUN wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRO
|
|||||||
# Install UMD
|
# Install UMD
|
||||||
RUN mkdir neo && \
|
RUN mkdir neo && \
|
||||||
cd neo && \
|
cd neo && \
|
||||||
wget https://github.com/intel/intel-graphics-compiler/releases/download/v2.24.8/intel-igc-core-2_2.24.8+20344_amd64.deb && \
|
wget https://github.com/intel/intel-graphics-compiler/releases/download/v2.34.4/intel-igc-core-2_2.34.4+21428_amd64.deb && \
|
||||||
wget https://github.com/intel/intel-graphics-compiler/releases/download/v2.24.8/intel-igc-opencl-2_2.24.8+20344_amd64.deb && \
|
wget https://github.com/intel/intel-graphics-compiler/releases/download/v2.34.4/intel-igc-opencl-2_2.34.4+21428_amd64.deb && \
|
||||||
wget https://github.com/intel/compute-runtime/releases/download/25.48.36300.8/intel-ocloc_25.48.36300.8-0_amd64.deb && \
|
wget https://github.com/intel/compute-runtime/releases/download/26.18.38308.1/intel-ocloc_26.18.38308.1-0_amd64.deb && \
|
||||||
wget https://github.com/intel/compute-runtime/releases/download/25.48.36300.8/intel-opencl-icd_25.48.36300.8-0_amd64.deb && \
|
wget https://github.com/intel/compute-runtime/releases/download/26.18.38308.1/intel-opencl-icd_26.18.38308.1-0_amd64.deb && \
|
||||||
wget https://github.com/intel/compute-runtime/releases/download/25.48.36300.8/libigdgmm12_22.8.2_amd64.deb && \
|
wget https://github.com/intel/compute-runtime/releases/download/26.18.38308.1/libigdgmm12_22.10.0_amd64.deb && \
|
||||||
wget https://github.com/intel/compute-runtime/releases/download/25.48.36300.8/libze-intel-gpu1_25.48.36300.8-0_amd64.deb && \
|
wget https://github.com/intel/compute-runtime/releases/download/26.18.38308.1/libze-intel-gpu1_26.18.38308.1-0_amd64.deb && \
|
||||||
wget https://github.com/oneapi-src/level-zero/releases/download/v1.26.0/level-zero_1.26.0+u24.04_amd64.deb && \
|
wget https://github.com/oneapi-src/level-zero/releases/download/v1.28.2/level-zero_1.28.2+u24.04_amd64.deb && \
|
||||||
dpkg -i *.deb && \
|
dpkg -i *.deb && \
|
||||||
cd .. && \
|
cd .. && \
|
||||||
rm -rf neo
|
rm -rf neo
|
||||||
@@ -131,8 +131,8 @@ CMD ["/bin/bash"]
|
|||||||
# never included in the final runtime image (mirrors ROCm's build_rixl stage).
|
# never included in the final runtime image (mirrors ROCm's build_rixl stage).
|
||||||
FROM vllm-base AS ucx-nixl-build
|
FROM vllm-base AS ucx-nixl-build
|
||||||
|
|
||||||
ARG UCX_VERSION=e5d98879705239d254ede40b4a52891850cb5349
|
ARG UCX_VERSION=v1.21.0-rc2
|
||||||
ARG NIXL_VERSION=0.7.0
|
ARG NIXL_VERSION=v1.2.0
|
||||||
|
|
||||||
# Build-time only: compiler, autotools, and verbs dev headers
|
# Build-time only: compiler, autotools, and verbs dev headers
|
||||||
RUN apt-get update -y && apt-get install -y --no-install-recommends \
|
RUN apt-get update -y && apt-get install -y --no-install-recommends \
|
||||||
@@ -149,26 +149,25 @@ RUN apt-get update -y && apt-get install -y --no-install-recommends \
|
|||||||
# patchelf (installed via uv) is used by the NIXL wheel build to rewrite
|
# patchelf (installed via uv) is used by the NIXL wheel build to rewrite
|
||||||
# RPATH entries, making the wheel portable across stages.
|
# RPATH entries, making the wheel portable across stages.
|
||||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
git clone https://github.com/openucx/ucx /tmp/ucx_source && \
|
git clone --depth 1 --branch "${UCX_VERSION}" https://github.com/openucx/ucx /tmp/ucx_source && \
|
||||||
cd /tmp/ucx_source && git checkout "${UCX_VERSION}" && \
|
cd /tmp/ucx_source && \
|
||||||
bash autogen.sh && \
|
bash autogen.sh && \
|
||||||
./configure --prefix=/tmp/ucx_install --with-ze=yes --enable-examples --enable-mt && \
|
./configure --prefix=/tmp/ucx_install --with-ze=yes --enable-examples --enable-mt && \
|
||||||
make CFLAGS="-Wno-error=incompatible-pointer-types" -j8 && make install && \
|
make CFLAGS="-Wno-error=incompatible-pointer-types" -j"$(nproc)" && make install && \
|
||||||
git clone https://github.com/ai-dynamo/nixl /tmp/nixl_source && \
|
git clone --depth 1 --branch "${NIXL_VERSION}" https://github.com/ai-dynamo/nixl /tmp/nixl_source && \
|
||||||
cd /tmp/nixl_source && git checkout "${NIXL_VERSION}" && \
|
cd /tmp/nixl_source && \
|
||||||
uv pip install --upgrade meson pybind11 patchelf && \
|
uv pip install --upgrade meson pybind11 patchelf && \
|
||||||
uv pip install -r requirements.txt && \
|
uv pip install -r requirements.txt && \
|
||||||
PKG_CONFIG_PATH=/tmp/ucx_install/lib/pkgconfig \
|
PKG_CONFIG_PATH=/tmp/ucx_install/lib/pkgconfig \
|
||||||
LD_LIBRARY_PATH=/tmp/ucx_install/lib \
|
LD_LIBRARY_PATH=/tmp/ucx_install/lib \
|
||||||
python -m pip wheel --no-deps . -w /tmp/nixl_wheels/ && \
|
python -m pip wheel --no-deps . -w /tmp/nixl_wheels/ && \
|
||||||
find /tmp/ucx_install -type f \( -name '*.a' -o -name '*.la' \) -delete && \
|
find /tmp/ucx_install -type f \( -name '*.a' -o -name '*.la' \) -delete && \
|
||||||
rm -rf /tmp/ucx_install/include /tmp/ucx_install/share /tmp/ucx_install/etc /tmp/ucx_install/lib/cmake /tmp/ucx_install/bin && \
|
rm -rf /tmp/ucx_install/{include,share,etc,bin} /tmp/ucx_install/lib/cmake \
|
||||||
rm -rf /tmp/ucx_source /tmp/nixl_source
|
/tmp/ucx_source /tmp/nixl_source
|
||||||
|
|
||||||
FROM vllm-base AS vllm-openai
|
FROM vllm-base AS vllm-openai
|
||||||
|
|
||||||
ARG UCX_VERSION=e5d98879705239d254ede40b4a52891850cb5349
|
ARG NIXL_VERSION=v1.2.0
|
||||||
ARG NIXL_VERSION=0.7.0
|
|
||||||
|
|
||||||
# Copy compiled UCX runtime libraries and the pre-built NIXL wheel.
|
# Copy compiled UCX runtime libraries and the pre-built NIXL wheel.
|
||||||
# No compiler or autotools are installed in this stage.
|
# No compiler or autotools are installed in this stage.
|
||||||
@@ -192,7 +191,8 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
|||||||
ibverbs-providers \
|
ibverbs-providers \
|
||||||
librdmacm1t64 \
|
librdmacm1t64 \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& uv pip install --no-deps /tmp/nixl_wheels/nixl-*.whl \
|
&& uv pip install --no-deps /tmp/nixl_wheels/nixl*.whl \
|
||||||
|
&& uv pip install nixl==${NIXL_VERSION} && uv pip uninstall nixl-cu13 \
|
||||||
&& rm -rf /tmp/nixl_wheels
|
&& rm -rf /tmp/nixl_wheels
|
||||||
|
|
||||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
|
|||||||
@@ -304,9 +304,15 @@ review process:
|
|||||||
resources. The reviewer will add `ready` label to the PR when the PR is
|
resources. The reviewer will add `ready` label to the PR when the PR is
|
||||||
ready to merge or a full CI run is needed.
|
ready to merge or a full CI run is needed.
|
||||||
|
|
||||||
### Escalating Stalled Contributions
|
### Pull Request Limits and Escalation
|
||||||
|
|
||||||
If you have an important contribution that has not yet received maintainer attention, please email us at:
|
vLLM uses GitHub's [pull request limit](https://github.blog/open-source/maintainers/how-pull-request-limits-are-cutting-down-the-noise/)
|
||||||
|
for contributors without write access. The current cap is 6 open PRs. If this
|
||||||
|
blocks well-intentioned critical work, contact a committer to request bypass
|
||||||
|
list access.
|
||||||
|
|
||||||
|
If you need an expedited review for an important contribution, please email us
|
||||||
|
at:
|
||||||
|
|
||||||
<pr-review-request@vllm.ai>
|
<pr-review-request@vllm.ai>
|
||||||
|
|
||||||
|
|||||||
@@ -133,10 +133,10 @@ The model should inherit protocol `IsAttentionFree` and also implement class met
|
|||||||
For the mamba layers themselves, please use the [`MambaMixer`](../../../vllm/model_executor/layers/mamba/mamba_mixer.py) (for Mamba-1) or [`MambaMixer2`](../../../vllm/model_executor/layers/mamba/mamba_mixer2.py) (for Mamba-2) classes.
|
For the mamba layers themselves, please use the [`MambaMixer`](../../../vllm/model_executor/layers/mamba/mamba_mixer.py) (for Mamba-1) or [`MambaMixer2`](../../../vllm/model_executor/layers/mamba/mamba_mixer2.py) (for Mamba-2) classes.
|
||||||
The model should also be added to the `MODELS_CONFIG_MAP` dictionary in [vllm/model_executor/models/config.py](../../../vllm/model_executor/models/config.py) to ensure that the runtime defaults are optimized.
|
The model should also be added to the `MODELS_CONFIG_MAP` dictionary in [vllm/model_executor/models/config.py](../../../vllm/model_executor/models/config.py) to ensure that the runtime defaults are optimized.
|
||||||
|
|
||||||
For case (2), we recommend using as a reference the implementation of [`JambaForCausalLM`](../../../vllm/model_executor/models/jamba.py) (for an example of a model that uses Mamba-1 and attention together) or [`BambaForCausalLM`](../../../vllm/model_executor/models/bamba.py) (for an example of a model that uses Mamba-2 and attention together).
|
For case (2), we recommend using as a reference the implementation of [`JambaForCausalLM`](../../../vllm/model_executor/models/jamba.py) (for an example of a model that uses Mamba-1 and attention together) or [`NemotronHForCausalLM`](../../../vllm/model_executor/models/nemotron_h.py) (for an example of a model that uses Mamba-2 and attention together).
|
||||||
These models should follow the same instructions as case (1), but they should inherit protocol `IsHybrid` (instead of `IsAttentionFree`) and it is *not* necessary to add them to the `MODELS_CONFIG_MAP` (their runtime defaults will be inferred from the protocol).
|
These models should follow the same instructions as case (1), but they should inherit protocol `IsHybrid` (instead of `IsAttentionFree`) and it is *not* necessary to add them to the `MODELS_CONFIG_MAP` (their runtime defaults will be inferred from the protocol).
|
||||||
|
|
||||||
For case (3), we recommend looking at the implementation of [`MiniMaxText01ForCausalLM`](../../../vllm/model_executor/models/minimax_text_01.py) or [`Lfm2ForCausalLM`](../../../vllm/model_executor/models/lfm2.py) as a reference, which use custom "mamba-like" layers `MiniMaxText01LinearAttention` and `ShortConv` respectively.
|
For case (3), we recommend looking at the implementation of [`Lfm2ForCausalLM`](../../../vllm/model_executor/models/lfm2.py) as a reference, which uses a custom "mamba-like" layer `ShortConv`.
|
||||||
Please follow the same guidelines as case (2) for implementing these models.
|
Please follow the same guidelines as case (2) for implementing these models.
|
||||||
We use "mamba-like" to refer to layers that possess a state that is updated in-place, rather than being appended-to (like KV cache for attention).
|
We use "mamba-like" to refer to layers that possess a state that is updated in-place, rather than being appended-to (like KV cache for attention).
|
||||||
For implementing new custom mamba-like layers, one should inherit from `MambaBase` and implement the methods `get_state_dtype`, `get_state_shape` to calculate the data types and state shapes at runtime, as well as `mamba_type` and `get_attn_backend`.
|
For implementing new custom mamba-like layers, one should inherit from `MambaBase` and implement the methods `get_state_dtype`, `get_state_shape` to calculate the data types and state shapes at runtime, as well as `mamba_type` and `get_attn_backend`.
|
||||||
@@ -144,5 +144,5 @@ It is also necessary to implement the "attention meta-data" class which handles
|
|||||||
Please see [`LinearAttentionMetadata`](../../../vllm/v1/attention/backends/linear_attn.py) or [`ShortConvAttentionMetadata`](../../../vllm/v1/attention/backends/short_conv_attn.py) for examples of this.
|
Please see [`LinearAttentionMetadata`](../../../vllm/v1/attention/backends/linear_attn.py) or [`ShortConvAttentionMetadata`](../../../vllm/v1/attention/backends/short_conv_attn.py) for examples of this.
|
||||||
It is also worth noting that we should update `MambaAttentionBackendEnum` in [`registry.py`](../../../vllm/v1/attention/backends/registry.py) when adding a new mamba backend.
|
It is also worth noting that we should update `MambaAttentionBackendEnum` in [`registry.py`](../../../vllm/v1/attention/backends/registry.py) when adding a new mamba backend.
|
||||||
Finally, if one wants to support torch compile and CUDA graphs, it necessary to wrap the call to the mamba-like layer inside a custom op and register it.
|
Finally, if one wants to support torch compile and CUDA graphs, it necessary to wrap the call to the mamba-like layer inside a custom op and register it.
|
||||||
Please see the calls to `direct_register_custom_op` in [vllm/model_executor/models/minimax_text_01.py](../../../vllm/model_executor/models/minimax_text_01.py) or [vllm/model_executor/layers/mamba/short_conv.py](../../../vllm/model_executor/layers/mamba/short_conv.py) for examples of this.
|
Please see the calls to `direct_register_custom_op` in [vllm/model_executor/layers/mamba/linear/minimax_linear_attn.py](../../../vllm/model_executor/layers/mamba/linear/minimax_linear_attn.py) or [vllm/model_executor/layers/mamba/short_conv.py](../../../vllm/model_executor/layers/mamba/short_conv.py) for examples of this.
|
||||||
The new custom op should then be added to the list `_attention_ops` in [vllm/config/compilation.py](../../../vllm/config/compilation.py) to ensure that piecewise CUDA graphs works as intended.
|
The new custom op should then be added to the list `_attention_ops` in [vllm/config/compilation.py](../../../vllm/config/compilation.py) to ensure that piecewise CUDA graphs works as intended.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Deploying vLLM on Kubernetes is a scalable and efficient way to serve machine le
|
|||||||
|
|
||||||
* **Upstream vLLM compatibility** – It wraps around upstream vLLM without modifying its code.
|
* **Upstream vLLM compatibility** – It wraps around upstream vLLM without modifying its code.
|
||||||
* **Ease of use** – Simplified deployment via Helm charts and observability through Grafana dashboards.
|
* **Ease of use** – Simplified deployment via Helm charts and observability through Grafana dashboards.
|
||||||
* **High performance** – Optimized for LLM workloads with features like multimodel support, model-aware and prefix-aware routing, fast vLLM bootstrapping, and KV cache offloading with [LMCache](https://github.com/LMCache/LMCache), among others.
|
* **High performance** – Optimized for LLM workloads with features like multimodel support, model-aware and prefix-aware routing, fast vLLM bootstrapping, and KV cache offloading with [LMCache](https://github.com/LMCache/LMCache) (wired up in vLLM via `--kv-offloading-backend lmcache`; see the [LMCache examples](https://github.com/vllm-project/vllm/tree/main/examples/disaggregated/lmcache) and [docs.lmcache.ai](https://docs.lmcache.ai)), among others.
|
||||||
|
|
||||||
If you are new to Kubernetes, don't worry: in the vLLM production stack [repo](https://github.com/vllm-project/production-stack), we provide a step-by-step [guide](https://github.com/vllm-project/production-stack/blob/main/tutorials/00-install-kubernetes-env.md) and a [short video](https://www.youtube.com/watch?v=EsTJbQtzj0g) to set up everything and get started in **4 minutes**!
|
If you are new to Kubernetes, don't worry: in the vLLM production stack [repo](https://github.com/vllm-project/production-stack), we provide a step-by-step [guide](https://github.com/vllm-project/production-stack/blob/main/tutorials/00-install-kubernetes-env.md) and a [short video](https://www.youtube.com/watch?v=EsTJbQtzj0g) to set up everything and get started in **4 minutes**!
|
||||||
|
|
||||||
|
|||||||
@@ -170,8 +170,8 @@ Priority is **1 = highest** (tried first).
|
|||||||
| Backend | Version | Dtypes | KV Dtypes | Block Sizes | Head Sizes | Sink | Non-Causal | MM Prefix | DCP | Attention Types | Compute Cap. |
|
| Backend | Version | Dtypes | KV Dtypes | Block Sizes | Head Sizes | Sink | Non-Causal | MM Prefix | DCP | Attention Types | Compute Cap. |
|
||||||
| ------- | ------- | ------ | --------- | ----------- | ---------- | ---- | ---------- | --------- | --- | --------------- | ------------ |
|
| ------- | ------- | ------ | --------- | ----------- | ---------- | ---- | ---------- | --------- | --- | --------------- | ------------ |
|
||||||
| `CPU_ATTN` | | fp16, bf16, fp32 | `auto`, `fp8`, `fp8_e4m3`, `fp8_e5m2` | %16 | 32, 64, 80, 96, 112, 128, 160, 192, 224, 256, 512 | ❌ | ❌ | ❌ | ❌ | All | N/A |
|
| `CPU_ATTN` | | fp16, bf16, fp32 | `auto`, `fp8`, `fp8_e4m3`, `fp8_e5m2` | %16 | 32, 64, 80, 96, 112, 128, 160, 192, 224, 256, 512 | ❌ | ❌ | ❌ | ❌ | All | N/A |
|
||||||
| `FLASHINFER` | Native† | fp16, bf16 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3`, `fp8_e5m2` | 16, 32, 64, 128, 256, 512, 1024 | 64, 128, 256, 512 | ❌ | ❌ | ❌ | ✅ | Decoder | 7.x-9.x |
|
| `FLASHINFER` | Native† | fp16, bf16 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3`, `fp8_e5m2` | 16, 32, 64, 128, 256, 512, 1024 | 64, 128, 256, 512 | ❌ | ✅ | ❌ | ✅ | Decoder | 7.x-9.x |
|
||||||
| `FLASHINFER` | TRTLLM† | fp16, bf16 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3`, `fp8_e5m2`, `nvfp4` | 16, 32, 64, 128, 256, 512, 1024 | 64, 128, 256, 512 | ✅ | ❌ | ❌ | ✅ | Decoder | 10.x |
|
| `FLASHINFER` | TRTLLM† | fp16, bf16 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3`, `fp8_e5m2`, `nvfp4` | 16, 32, 64, 128, 256, 512, 1024 | 64, 128, 256, 512 | ✅ | ✅ | ❌ | ✅ | Decoder | 10.x |
|
||||||
| `FLASH_ATTN` | FA2* | fp16, bf16 | `auto`, `float16`, `bfloat16` | %16 | Any | ❌ | ✅ | ❌ | ✅ | All | ≥8.0 |
|
| `FLASH_ATTN` | FA2* | fp16, bf16 | `auto`, `float16`, `bfloat16` | %16 | Any | ❌ | ✅ | ❌ | ✅ | All | ≥8.0 |
|
||||||
| `FLASH_ATTN` | FA3* | fp16, bf16 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3`, `fp8_e5m2` | %16 | Any | ✅ | ✅ | ❌ | ✅ | All | 9.x |
|
| `FLASH_ATTN` | FA3* | fp16, bf16 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3`, `fp8_e5m2` | %16 | Any | ✅ | ✅ | ❌ | ✅ | All | 9.x |
|
||||||
| `FLASH_ATTN` | FA4* | fp16, bf16 | `auto`, `float16`, `bfloat16` | %16 | Any | ✅ | ✅ | ❌ | ✅ | All | ≥10.0 |
|
| `FLASH_ATTN` | FA4* | fp16, bf16 | `auto`, `float16`, `bfloat16` | %16 | Any | ✅ | ✅ | ❌ | ✅ | All | ≥10.0 |
|
||||||
@@ -214,9 +214,9 @@ hardware and configuration.
|
|||||||
| Backend | Description | Dtypes | Compute Cap. | Notes |
|
| Backend | Description | Dtypes | Compute Cap. | Notes |
|
||||||
| ------- | ----------- | ------ | ------------ | ----- |
|
| ------- | ----------- | ------ | ------------ | ----- |
|
||||||
| `FLASH_ATTN`‡ | FlashAttention varlen (FA2/FA3/FA4) | fp16, bf16 | Any | FA4 on SM100+, FA3 on SM90, FA2 otherwise |
|
| `FLASH_ATTN`‡ | FlashAttention varlen (FA2/FA3/FA4) | fp16, bf16 | Any | FA4 on SM100+, FA3 on SM90, FA2 otherwise |
|
||||||
| `TRTLLM_RAGGED` | TensorRT-LLM ragged attention | fp16, bf16 | 10.x | DeepSeek R1 dims only |
|
| `TRTLLM_RAGGED` | TensorRT-LLM ragged attention | fp16, bf16 | 10.x | (qk_nope_head_dim=128, qk_rope_head_dim=64, v_head_dim=128) or (qk_nope_head_dim=192, qk_rope_head_dim=64, v_head_dim=256) only |
|
||||||
| `FLASHINFER` | FlashInfer CUTLASS backend | fp16, bf16 | 10.x | DeepSeek R1 dims only |
|
| `FLASHINFER` | FlashInfer CUTLASS backend | fp16, bf16 | 10.x | (qk_nope_head_dim=128, qk_rope_head_dim=64, v_head_dim=128) only |
|
||||||
| `TOKENSPEED_MLA` | | fp16, bf16 | 10.x | DeepSeek R1 dims only |
|
| `TOKENSPEED_MLA` | | fp16, bf16 | 10.x | (qk_nope_head_dim=128, qk_rope_head_dim=64, v_head_dim=128) only |
|
||||||
|
|
||||||
> **‡** Automatic selection tries FlashAttention first. On Blackwell
|
> **‡** Automatic selection tries FlashAttention first. On Blackwell
|
||||||
> (SM100), the fallback order is TRT-LLM Ragged, FlashInfer, then
|
> (SM100), the fallback order is TRT-LLM Ragged, FlashInfer, then
|
||||||
@@ -252,6 +252,6 @@ default on NVIDIA is `FLASHMLA_SPARSE_DSV4`.
|
|||||||
|
|
||||||
| Backend | Dtypes | KV Dtypes | Block Sizes | Head Sizes | Sink | Non-Causal | Sparse | MM Prefix | DCP | Attention Types | Compute Cap. |
|
| Backend | Dtypes | KV Dtypes | Block Sizes | Head Sizes | Sink | Non-Causal | Sparse | MM Prefix | DCP | Attention Types | Compute Cap. |
|
||||||
| ------- | ------ | --------- | ----------- | ---------- | ---- | ---------- | ------ | --------- | --- | --------------- | ------------ |
|
| ------- | ------ | --------- | ----------- | ---------- | ---- | ---------- | ------ | --------- | --- | --------------- | ------------ |
|
||||||
| `FLASHINFER_MLA_SPARSE_DSV4` | fp16, bf16 | `auto` | Any | Any | ❌ | ❌ | ❌ | ❌ | ❌ | Decoder | Any |
|
| `FLASHINFER_MLA_SPARSE_DSV4` | bf16 | `auto`, `bfloat16`, `fp8` | Any | Any | ❌ | ❌ | ❌ | ❌ | ❌ | Decoder | Any |
|
||||||
| `FLASHMLA_SPARSE_DSV4` | bf16 | `auto`, `bfloat16`, `fp8_ds_mla`, `fp8` | 256 | 512 | ❌ | ❌ | ✅ | ❌ | ❌ | Decoder | 9.x-10.x |
|
| `FLASHMLA_SPARSE_DSV4` | bf16 | `auto`, `fp8_ds_mla`, `fp8` | 256 | 512 | ❌ | ❌ | ✅ | ❌ | ❌ | Decoder | 9.x-10.x |
|
||||||
| `ROCM_FLASHMLA_SPARSE_DSV4` | fp16, bf16 | `auto` | Any | Any | ❌ | ❌ | ❌ | ❌ | ❌ | Decoder | N/A |
|
| `ROCM_FLASHMLA_SPARSE_DSV4` | fp16, bf16 | `auto` | Any | Any | ❌ | ❌ | ❌ | ❌ | ❌ | Decoder | N/A |
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
The [CUDA Graphs](cuda_graphs.md) infrastructure in vLLM primarily targets the **decoder** (language model) forward pass. vLLM also supports capturing the **encoder** (vision transformer) forward pass as CUDA Graphs, independently from the decoder. This is based on <https://github.com/vllm-project/vllm/pull/35963>.
|
The [CUDA Graphs](cuda_graphs.md) infrastructure in vLLM primarily targets the **decoder** (language model) forward pass. vLLM also supports capturing the **encoder** (vision transformer) forward pass as CUDA Graphs, independently from the decoder. This is based on <https://github.com/vllm-project/vllm/pull/35963>.
|
||||||
|
|
||||||
|
For two-tower vision encoders (e.g., DeepSeek-OCR's SAM + CLIP with dynamic tiling), a **dual-path graph** mode captures two independent sets of CUDA graphs — one for the global image path and one for the local patch path — enabling independent budget selection and partial eager fallback per path. This is based on <https://github.com/vllm-project/vllm/pull/43586>.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
Encoder CUDA Graphs are orthogonal to decoder CUDA Graphs — both can be enabled simultaneously. Encoder graphs capture the vision encoder execution (e.g., ViT in Qwen3-VL), while decoder graphs capture the language model execution as described in the [CUDA Graphs design document](cuda_graphs.md).
|
Encoder CUDA Graphs are orthogonal to decoder CUDA Graphs — both can be enabled simultaneously. Encoder graphs capture the vision encoder execution (e.g., ViT in Qwen3-VL), while decoder graphs capture the language model execution as described in the [CUDA Graphs design document](cuda_graphs.md).
|
||||||
|
|
||||||
@@ -11,6 +13,8 @@ Vision encoder inference incurs CUDA kernel launch overhead on the host side. Th
|
|||||||
|
|
||||||
Encoder CUDA Graphs eliminate this overhead by pre-capturing the full encoder forward pass at multiple token budget levels during model initialization, then replaying the appropriate graph at runtime.
|
Encoder CUDA Graphs eliminate this overhead by pre-capturing the full encoder forward pass at multiple token budget levels during model initialization, then replaying the appropriate graph at runtime.
|
||||||
|
|
||||||
|
For two-tower vision encoders such as DeepSeek-OCR (SAM + CLIP with dynamic tiling), the global image path and local patch path have independent token profiles (272 tokens per global image vs. 100 tokens per local patch). Capturing a single monolithic graph for both paths would significantly reduce packing efficiency. The dual-path graph mode captures each path as a separate set of budgets, allowing the manager to pack and replay each path independently.
|
||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
The encoder CUDA Graph system uses a **budget-based capture/replay** strategy, managed by [EncoderCudaGraphManager][vllm.v1.worker.encoder_cudagraph.EncoderCudaGraphManager]. The system contains the following core components:
|
The encoder CUDA Graph system uses a **budget-based capture/replay** strategy, managed by [EncoderCudaGraphManager][vllm.v1.worker.encoder_cudagraph.EncoderCudaGraphManager]. The system contains the following core components:
|
||||||
@@ -37,10 +41,14 @@ class BudgetGraphMetadata:
|
|||||||
|
|
||||||
Budgets are auto-generated as power-of-2 levels from a model-provided range via `get_encoder_cudagraph_budget_range()`, with the maximum budget always included even if it does not fall on a power-of-2 boundary. Budgets can also be explicitly specified by the user via `encoder_cudagraph_token_budgets` in `CompilationConfig`.
|
Budgets are auto-generated as power-of-2 levels from a model-provided range via `get_encoder_cudagraph_budget_range()`, with the maximum budget always included even if it does not fall on a power-of-2 boundary. Budgets can also be explicitly specified by the user via `encoder_cudagraph_token_budgets` in `CompilationConfig`.
|
||||||
|
|
||||||
|
When `EncoderCudaGraphConfig.enable_dual_path_graph` is `True`, the manager generates two independent budget lists — `global_token_budgets` (multiples of `global_token_per_image`) and `local_token_budgets` (multiples of `local_token_per_patch`) — and stores captured graphs under `budget_graphs["global"]` and `budget_graphs["local"]` respectively.
|
||||||
|
|
||||||
### Greedy bin-packing at runtime
|
### Greedy bin-packing at runtime
|
||||||
|
|
||||||
When a batch of images arrives, the manager sorts images by output token count (smallest first) and greedily packs as many images as possible into each sub-batch while staying within the **largest** token budget and the maximum batch size. Once a sub-batch is finalized (the next image would overflow either constraint), the manager finds the **smallest** budget that fits the sub-batch's total tokens and replays the corresponding CUDA Graph. This repeats until the batch is exhausted. Images that exceed all budgets fall back to eager execution.
|
When a batch of images arrives, the manager sorts images by output token count (smallest first) and greedily packs as many images as possible into each sub-batch while staying within the **largest** token budget and the maximum batch size. Once a sub-batch is finalized (the next image would overflow either constraint), the manager finds the **smallest** budget that fits the sub-batch's total tokens and replays the corresponding CUDA Graph. This repeats until the batch is exhausted. Images that exceed all budgets fall back to eager execution.
|
||||||
|
|
||||||
|
For dual-path models, the manager routes to `_execute_local_dual_path()`, which constrains both global and local token budgets simultaneously during packing (see [Dual-Path graph capture](#dual-path-graph-capture)).
|
||||||
|
|
||||||
For each graph replay:
|
For each graph replay:
|
||||||
|
|
||||||
1. Call `prepare_encoder_cudagraph_replay_buffers()` to compute buffer values (including `pixel_values` and precomputed metadata) from actual batch inputs.
|
1. Call `prepare_encoder_cudagraph_replay_buffers()` to compute buffer values (including `pixel_values` and precomputed metadata) from actual batch inputs.
|
||||||
@@ -48,6 +56,42 @@ For each graph replay:
|
|||||||
3. Replay the CUDA Graph.
|
3. Replay the CUDA Graph.
|
||||||
4. Clone outputs from `output_buffer` (cloning is necessary since the buffer is reused across replays).
|
4. Clone outputs from `output_buffer` (cloning is necessary since the buffer is reused across replays).
|
||||||
|
|
||||||
|
### Dual-Path graph capture
|
||||||
|
|
||||||
|
For two-tower vision encoders (e.g., DeepSeek-OCR), the `EncoderCudaGraphConfig` sets `enable_dual_path_graph=True` and provides `global_token_per_image` / `local_token_per_patch`. The manager captures two independent sets of CUDA graphs — one for the **global** image path and one for the **local** patch path — stored under `budget_graphs["global"]` and `budget_graphs["local"]` respectively.
|
||||||
|
|
||||||
|
**Budget generation.** Two separate budget lists are generated:
|
||||||
|
|
||||||
|
* `global_token_budgets` — power-of-2 multiples of `global_token_per_image` (e.g., `[272, 544, 1088, 2176, 4352, 8704, 13824]` for DeepSeek-OCR).
|
||||||
|
* `local_token_budgets` — power-of-2 multiples of `local_token_per_patch` (e.g., `[0, 100, 200, 400, 800, 1600, 3200, 6400, 12800]` for DeepSeek-OCR). A budget of `0` is always included to handle images with no local patches (images ≤ 640×640 that produce only global features).
|
||||||
|
|
||||||
|
Both lists are capped at the same `max_budget`.
|
||||||
|
|
||||||
|
**Dual-path greedy packing.** Each `EncoderItemSpec` provides both `global_output_tokens` (constant per image) and `local_output_tokens` (proportional to the patch count). The dual-path packing algorithm constrains both budgets simultaneously:
|
||||||
|
|
||||||
|
* Sort images by total output tokens (global + local), smallest first.
|
||||||
|
* Greedily pack images: an image is added to the current sub-batch only if both the accumulated global tokens ≤ `max_global_budget` **and** the accumulated local tokens ≤ `max_local_budget`, with the image count ≤ `max_batch_size`.
|
||||||
|
* Once either constraint would overflow, finalize the sub-batch and find the smallest fitting budget **independently** for each path.
|
||||||
|
* Repeat until all images are packed.
|
||||||
|
|
||||||
|
**Partial graph fallback.** After packing, each sub-batch falls into one of four execution scenarios:
|
||||||
|
|
||||||
|
| Global budget | Local budget | Execution |
|
||||||
|
| :---: | :---: | --- |
|
||||||
|
| Found | Found | Both paths use CUDA graph replay |
|
||||||
|
| Found | `None` | Global graph replay + local path skipped (no patches) |
|
||||||
|
| `None` | Found | Global eager fallback + local graph replay |
|
||||||
|
| `None` | `None` | Both paths fall back to eager execution |
|
||||||
|
|
||||||
|
Note that the `0`-budget graph is never actually replayed for local — it signals that local patch processing should be skipped entirely.
|
||||||
|
|
||||||
|
**Buffer keys per path.** Global and local paths use different buffer keys. For DeepSeek-OCR, the global path uses `pixel_values` (full images, shape `[B, 3, 1280, 1280]`) while the local path uses `images_crop` (patches, shape `[P, 3, 1024, 1024]`). The manager iterates over each captured graph's own `input_buffers.keys()` rather than a shared `buffer_keys` list, so both paths can use different buffers.
|
||||||
|
|
||||||
|
**Post-processing.** The `postprocess_encoder_output` method receives a `local_output` parameter (a tensor or `None`) containing the local-path encoder output. The model is responsible for assembling global and local features into the final per-image embedding. For DeepSeek-OCR, this means reshaping the global output into `[B, 272, n_embed]`, the local output into `[P, 100, n_embed]`, assembling patch grids with newline tokens, and concatenating `[patches_grid, global, view_separator]` for each image.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
The dual-path design enables partial CUDA graph coverage — one path can hit while the other falls back to eager. This avoids wasted compute on zero-padded patch buffers for untiled images and avoids graph invalidation caused by variable `crop_shape` per image.
|
||||||
|
|
||||||
### Data-parallel support
|
### Data-parallel support
|
||||||
|
|
||||||
When `mm_encoder_tp_mode="data"`, the manager distributes images across TP ranks using load-balanced assignment via `get_load_balance_assignment`, executes locally on each rank, then gathers results back in the original order via `tensor_model_parallel_all_gather`.
|
When `mm_encoder_tp_mode="data"`, the manager distributes images across TP ranks using load-balanced assignment via `get_load_balance_assignment`, executes locally on each rank, then gathers results back in the original order via `tensor_model_parallel_all_gather`.
|
||||||
@@ -67,29 +111,31 @@ Models opt-in to encoder CUDA Graphs by implementing the [SupportsEncoderCudaGra
|
|||||||
|
|
||||||
* `get_encoder_cudagraph_config()` — returns static configuration (supported modalities, buffer keys, output hidden size, padding logics, max frames per video).
|
* `get_encoder_cudagraph_config()` — returns static configuration (supported modalities, buffer keys, output hidden size, padding logics, max frames per video).
|
||||||
* `get_encoder_cudagraph_budget_range(vllm_config)` — returns `(min_budget, max_budget)` for auto-inference of token budgets.
|
* `get_encoder_cudagraph_budget_range(vllm_config)` — returns `(min_budget, max_budget)` for auto-inference of token budgets.
|
||||||
* `get_encoder_cudagraph_item_specs(mm_kwargs)` — returns `list[EncoderItemSpec]` describing each item with its input size and output token count. Replaces the former three separate methods (`get_num_items`, `get_per_item_output_tokens`, `get_per_item_input_sizes`).
|
* `get_encoder_cudagraph_item_specs(mm_kwargs)` — returns `list[EncoderItemSpec]` describing each item with its input size, total output token count (`output_tokens`), and optionally per-path token counts (`global_output_tokens`, `local_output_tokens`) for dual-path models.
|
||||||
* `select_encoder_cudagraph_items(mm_kwargs, indices)` — extracts a sub-batch of items by index, used during greedy packing and DP sharding.
|
* `select_encoder_cudagraph_items(mm_kwargs, indices)` — extracts a sub-batch of items by index, used during greedy packing and DP sharding.
|
||||||
* `prepare_encoder_cudagraph_capture_inputs(...)` — creates dummy inputs for graph capture. Returns `EncoderCudaGraphCaptureInputs` with a single `values: dict[str, torch.Tensor]` that contains all buffers to be recorded into the graph.
|
* `prepare_encoder_cudagraph_capture_inputs(..., path="default")` — creates dummy inputs for graph capture. The `path` parameter (`"global"` or `"local"`) tells the model which path to generate dummy inputs for. Returns `EncoderCudaGraphCaptureInputs` with a single `values: dict[str, torch.Tensor]` that contains all buffers to be recorded into the graph.
|
||||||
* `prepare_encoder_cudagraph_replay_buffers(mm_kwargs, max_batch_size, max_frames_per_batch)` — computes buffer values from actual batch inputs. Returns `EncoderCudaGraphReplayBuffers` with a `values` dict whose keys match `buffer_keys` in the config.
|
* `prepare_encoder_cudagraph_replay_buffers(mm_kwargs, max_batch_size, max_frames_per_batch, path="default")` — computes buffer values from actual batch inputs. The `path` parameter selects which modality keys to extract from `mm_kwargs`. Returns `EncoderCudaGraphReplayBuffers` with a `values` dict whose keys match the captured graph's `input_buffers.keys()`.
|
||||||
* `encoder_cudagraph_forward(inputs: dict[str, torch.Tensor])` — forward pass accepting only fixed-shaped input tensors (the captured `values` dict). Called during both capture and replay. The `pixel_values` tensor is included in `inputs` alongside metadata buffers.
|
* `encoder_cudagraph_forward(inputs: dict[str, torch.Tensor], path="default")` — forward pass accepting only fixed-shaped input tensors (the captured `values` dict). Called during both capture and replay. The `path` parameter dispatches to the correct encoder sub-module (e.g., global vs. local path for DeepSeek-OCR).
|
||||||
* `encoder_eager_forward(mm_kwargs)` — fallback eager forward when no graph fits.
|
* `encoder_eager_forward(mm_kwargs, path="default")` — fallback eager forward when no graph fits. When `path` is `"global"` or `"local"`, runs only that encoder path without graph capture.
|
||||||
* `postprocess_encoder_output(...)` — post-process encoder output, delegates to `scatter_output_slices` by default.
|
* `postprocess_encoder_output(..., local_output=None)` — post-process encoder output. The `local_output` parameter receives the local-path encoder output tensor (or `None`), enabling dual-path models to assemble global and local features into the final per-image embedding.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
The `SupportsEncoderCudaGraph` protocol is designed to be model-agnostic. New vision encoder models can opt-in by implementing the protocol methods without modifying the manager.
|
The `SupportsEncoderCudaGraph` protocol is designed to be model-agnostic. New vision encoder models can opt-in by implementing the protocol methods without modifying the manager.
|
||||||
|
|
||||||
**Supported models:**
|
**Supported models:**
|
||||||
|
|
||||||
| Architecture | Models | CG for Image | CG for Video |
|
| Architecture | Models | CG for Image | CG for Video | Dual-Path Graph |
|
||||||
| ------------ | ------ | ------------ | ------------ |
|
| ------------ | ------ | ------------ | ------------ | --------------- |
|
||||||
| `Llama4ForConditionalGeneration` | `Llama 4` | ✅︎ | - |
|
| `DeepseekOCRForCausalLM` | `DeepSeek-OCR` | ✅︎ | ❌︎ | ✅︎ |
|
||||||
| `InternVLChatModel` | `InternVL3.5`, `InternVL3`, `InternVL2.5`, `InternVL2` | ✅︎ | ✅︎ |
|
| `Glm4vForConditionalGeneration` | `GLM-4.1V, GLM-4.6V-Flash` | ✅︎ | ✅︎ | ❌︎ |
|
||||||
| `Qwen2VLForConditionalGeneration` | `Qwen2-VL` | ✅︎ | ✅︎ |
|
| `InternVLChatModel` | `InternVL3.5`, `InternVL3`, `InternVL2.5`, `InternVL2` | ✅︎ | ✅︎ | ❌︎ |
|
||||||
| `Qwen2_5_VLForConditionalGeneration` | `Qwen2.5-VL` | ✅︎ | ✅︎ |
|
| `KimiVLForConditionalGeneration` | `Kimi-VL` | ✅︎ | ❌︎ | ❌︎ |
|
||||||
| `Qwen3VLForConditionalGeneration` | `Qwen3-VL` | ✅︎ | ✅︎ |
|
| `Llama4ForConditionalGeneration` | `Llama 4` | ✅︎ | ❌︎ | ❌︎ |
|
||||||
| `Qwen3_5ForConditionalGeneration` | `Qwen3.5` | ✅︎ | ✅︎ |
|
| `Qwen2VLForConditionalGeneration` | `Qwen2-VL` | ✅︎ | ✅︎ | ❌︎ |
|
||||||
| `Step3VLForConditionalGeneration` | `Step3-VL` | ✅︎ | ❌︎ |
|
| `Qwen2_5_VLForConditionalGeneration` | `Qwen2.5-VL` | ✅︎ | ✅︎ | ❌︎ |
|
||||||
| `Glm4vForConditionalGeneration` | `GLM-4.1V, GLM-4.6V-Flash` | ✅︎ | ✅︎ |
|
| `Qwen3VLForConditionalGeneration` | `Qwen3-VL` | ✅︎ | ✅︎ | ❌︎ |
|
||||||
|
| `Qwen3_5ForConditionalGeneration` | `Qwen3.5` | ✅︎ | ✅︎ | ❌︎ |
|
||||||
|
| `Step3VLForConditionalGeneration` | `Step3-VL` | ✅︎ | ❌︎ | ❌︎ |
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
Encoder CUDA Graphs have currently been tested with `--mm-encoder-attn-backend=FLASH_ATTN` and `--mm-encoder-attn-backend=FLASHINFER` on Blackwell GPUs.
|
Encoder CUDA Graphs have currently been tested with `--mm-encoder-attn-backend=FLASH_ATTN` and `--mm-encoder-attn-backend=FLASHINFER` on Blackwell GPUs.
|
||||||
@@ -104,6 +150,8 @@ Three fields in `CompilationConfig` control encoder CUDA Graphs:
|
|||||||
* `encoder_cudagraph_max_vision_items_per_batch` (`int`, default `0`) — maximum number of images/videos per batch during capture. If 0 (default), auto-inferred as `max_budget // min_budget`.
|
* `encoder_cudagraph_max_vision_items_per_batch` (`int`, default `0`) — maximum number of images/videos per batch during capture. If 0 (default), auto-inferred as `max_budget // min_budget`.
|
||||||
* `encoder_cudagraph_max_frames_per_batch` (`int`, default `None`) — maximum number of video frames per batch during capture. If `None` (default), auto-inferred as `encoder_cudagraph_max_vision_items_per_batch * max_frames_per_video` (`max_frames_per_video` is a model-specific value from `EncoderCudaGraphConfig`, computed by `get_max_frames_per_video()` on the model). If we limit the video count per prompt to `0`, it will also be set to `0` (i.e., fall back to image-only mode).
|
* `encoder_cudagraph_max_frames_per_batch` (`int`, default `None`) — maximum number of video frames per batch during capture. If `None` (default), auto-inferred as `encoder_cudagraph_max_vision_items_per_batch * max_frames_per_video` (`max_frames_per_video` is a model-specific value from `EncoderCudaGraphConfig`, computed by `get_max_frames_per_video()` on the model). If we limit the video count per prompt to `0`, it will also be set to `0` (i.e., fall back to image-only mode).
|
||||||
|
|
||||||
|
Dual-path mode is configured at the model level via `EncoderCudaGraphConfig` fields (`enable_dual_path_graph`, `global_token_per_image`, `local_token_per_patch`) — no additional user configuration is required. The manager automatically generates separate budget lists and routes to dual-path execution when the model opts in.
|
||||||
|
|
||||||
## Usage guide
|
## Usage guide
|
||||||
|
|
||||||
### Image inference
|
### Image inference
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Two main reasons:
|
|||||||
Now supports 9 types of connectors:
|
Now supports 9 types of connectors:
|
||||||
|
|
||||||
- **ExampleConnector**: refer to [examples/disaggregated/example_connector/run.sh](../../examples/disaggregated/example_connector/run.sh) for the example usage of ExampleConnector disaggregated prefilling.
|
- **ExampleConnector**: refer to [examples/disaggregated/example_connector/run.sh](../../examples/disaggregated/example_connector/run.sh) for the example usage of ExampleConnector disaggregated prefilling.
|
||||||
- **LMCacheConnectorV1**: refer to [examples/disaggregated/lmcache/disagg_prefill_lmcache_v1/disagg_example_nixl.sh](../../examples/disaggregated/lmcache/disagg_prefill_lmcache_v1/disagg_example_nixl.sh) for the example usage of LMCacheConnectorV1 disaggregated prefilling which uses NIXL as the underlying KV transmission.
|
- **LMCacheConnectorV1**: refer to [examples/disaggregated/lmcache/disagg_prefill_lmcache_v1/disagg_example_nixl.sh](../../examples/disaggregated/lmcache/disagg_prefill_lmcache_v1/disagg_example_nixl.sh) for the example usage of LMCacheConnectorV1 disaggregated prefilling which uses NIXL as the underlying KV transmission. LMCache also offers a multi-process (MP) mode via `LMCacheMPConnector`, where a standalone `lmcache server` holds the KV cache shared by one or more vLLM instances; see the [LMCache examples](../../examples/disaggregated/lmcache/README.md) and the [LMCache docs](https://docs.lmcache.ai) for setup.
|
||||||
- **NixlConnector**: refer to [tests/v1/kv_connector/nixl_integration/run_accuracy_test.sh](../../tests/v1/kv_connector/nixl_integration/run_accuracy_test.sh) for the example usage of NixlConnector disaggregated prefilling which support fully async send/recv. For detailed usage guide, see [NixlConnector Usage Guide](nixl_connector_usage.md). For feature compatibility details, see [NixlConnector Compatibility Matrix](nixl_connector_compatibility.md). You may specify one or multiple NIXL transfer backends, such as:
|
- **NixlConnector**: refer to [tests/v1/kv_connector/nixl_integration/run_accuracy_test.sh](../../tests/v1/kv_connector/nixl_integration/run_accuracy_test.sh) for the example usage of NixlConnector disaggregated prefilling which support fully async send/recv. For detailed usage guide, see [NixlConnector Usage Guide](nixl_connector_usage.md). For feature compatibility details, see [NixlConnector Compatibility Matrix](nixl_connector_compatibility.md). You may specify one or multiple NIXL transfer backends, such as:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ vllm serve <model> \
|
|||||||
| `max_tracker_size` | no | `64000` | single-tier | Max entries in the lookup tracker. |
|
| `max_tracker_size` | no | `64000` | single-tier | Max entries in the lookup tracker. |
|
||||||
| `secondary_tiers` | no | `[]` | multi-tier | List of secondary tier configs (see below). |
|
| `secondary_tiers` | no | `[]` | multi-tier | List of secondary tier configs (see below). |
|
||||||
| `offload_prompt_only` | no | `true` | both | If `true`, only prompt (prefill) blocks are offloaded; decode blocks are skipped. |
|
| `offload_prompt_only` | no | `true` | both | If `true`, only prompt (prefill) blocks are offloaded; decode blocks are skipped. |
|
||||||
|
| `self_describing_kv_events` | no | `false` | single-tier | Opt-in. When `true` *and* KV cache events are enabled (`--kv-events-config` with `enable_kv_cache_events`), the connector emits self-describing block-granular `BlockStored`/`BlockRemoved` payloads (constituent block hashes, whole-chunk `token_ids`, per-block `block_size`, parent hash, LoRA + group/cache-spec metadata) instead of the placeholder fallback, so external KV-event consumers can index offloaded blocks. Inert unless events are enabled. Currently rejected by `TieringOffloadingSpec`. Full-attention groups only; sliding-window/SSM groups keep the placeholder fallback. In chunk mode (`block_size` > GPU block size), overlapping chunks re-announce shared per-block hashes, so consumers must reference-count (deduplicate) repeated store/remove announcements. |
|
||||||
| `spec_module_path` | no | — | both | Python import path for a custom `OffloadingSpec` not in the built-in registry. Required only when `spec_name` is not built-in (advanced). |
|
| `spec_module_path` | no | — | both | Python import path for a custom `OffloadingSpec` not in the built-in registry. Required only when `spec_name` is not built-in (advanced). |
|
||||||
|
|
||||||
## Secondary Tiers
|
## Secondary Tiers
|
||||||
@@ -127,6 +128,29 @@ PYTHONHASHSEED=0 vllm serve ...
|
|||||||
- FS thread counts: tune `n_read_threads` and `n_write_threads` to the parallelism your storage can sustain. Reads are latency-sensitive on the prefill path, so prefer more read threads when prefill hit rates are high.
|
- FS thread counts: tune `n_read_threads` and `n_write_threads` to the parallelism your storage can sustain. Reads are latency-sensitive on the prefill path, so prefer more read threads when prefill hit rates are high.
|
||||||
- Sharing `root_dir` across runs: runs with the same model, `block_size`, parallelism layout, and dtype share files under the same `<digest>` subdirectory. Changing any of these produces a new subdirectory; old ones are orphaned but harmless. Delete them to reclaim disk.
|
- Sharing `root_dir` across runs: runs with the same model, `block_size`, parallelism layout, and dtype share files under the same `<digest>` subdirectory. Changing any of these produces a new subdirectory; old ones are orphaned but harmless. Delete them to reclaim disk.
|
||||||
|
|
||||||
|
## Per-Request Selective Offload
|
||||||
|
|
||||||
|
Individual requests can cap how many of their tokens are eligible for offload by setting `max_offload_tokens` in the request's `kv_transfer_params`. Only the first `max_offload_tokens` tokens of the request are offloaded; blocks beyond that point are skipped on the store path. This is useful when a known prefix (e.g., a system prompt or shared context) is worth caching but later request-specific tokens are not.
|
||||||
|
|
||||||
|
| Key | Type | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `max_offload_tokens` | non-negative `int` | Upper bound on tokens to offload for this request. `0` disables offload for the request entirely; omit the key (or set to `None`) for no cap. Non-`int`, negative, or `bool` values are rejected with a warning and treated as no cap. |
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
`max_offload_tokens` is experimental and subject to change.
|
||||||
|
|
||||||
|
Example (OpenAI-compatible completions request):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"model": "<model>",
|
||||||
|
"prompt": "...",
|
||||||
|
"kv_transfer_params": {
|
||||||
|
"max_offload_tokens": 1024
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Further Reading
|
## Further Reading
|
||||||
|
|
||||||
- [vLLM blog: KV Offloading Connector](https://vllm.ai/blog/2026-01-08-kv-offloading-connector) — motivation, architecture (DMA-based async transfer), and benchmarks (TTFT and throughput).
|
- [vLLM blog: KV Offloading Connector](https://vllm.ai/blog/2026-01-08-kv-offloading-connector) — motivation, architecture (DMA-based async transfer), and benchmarks (TTFT and throughput).
|
||||||
|
|||||||
@@ -203,8 +203,10 @@ the vLLM JSON config.
|
|||||||
### kv_connector_extra_config
|
### kv_connector_extra_config
|
||||||
|
|
||||||
- `load_async` (bool): Enable asynchronous loading for better compute-I/O overlap. Default: `true`.
|
- `load_async` (bool): Enable asynchronous loading for better compute-I/O overlap. Default: `true`.
|
||||||
|
- `lookup_async` (bool): Run the external prefix-cache lookup on a background thread so it never blocks the scheduler step. The request is held until the in-flight lookup completes, then resumed on a later step. Default: `false`.
|
||||||
- `enable_cross_layers_blocks` (bool): Enable cross-layer block packing for reduced store operations. Default: `false`.
|
- `enable_cross_layers_blocks` (bool): Enable cross-layer block packing for reduced store operations. Default: `false`.
|
||||||
- `lookup_rpc_port` (int): Custom port for the ZMQ lookup RPC socket. Default: `0`.
|
- `lookup_rpc_port` (int): Custom port for the ZMQ lookup RPC socket. Default: `0`.
|
||||||
|
- `cache_prefix` (str): Namespace prepended to every store key. Lets separate deployments share one Mooncake master without polluting each other — instances configured with different prefixes never see each other's cached blocks, even for identical prompts. All instances that should share a prefix cache must use the same value. Default: `""` (no prefix; keys are byte-identical to the unprefixed format).
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ To run an AWQ model with vLLM, you can use [TheBloke/Llama-2-7b-Chat-AWQ](https:
|
|||||||
```bash
|
```bash
|
||||||
python examples/deployment/llm_engine_example.py \
|
python examples/deployment/llm_engine_example.py \
|
||||||
--model TheBloke/Llama-2-7b-Chat-AWQ \
|
--model TheBloke/Llama-2-7b-Chat-AWQ \
|
||||||
--quantization awq
|
--quantization auto_awq
|
||||||
```
|
```
|
||||||
|
|
||||||
AWQ models are also supported directly through the LLM entrypoint:
|
AWQ models are also supported directly through the LLM entrypoint:
|
||||||
@@ -70,7 +70,7 @@ AWQ models are also supported directly through the LLM entrypoint:
|
|||||||
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
|
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
|
||||||
|
|
||||||
# Create an LLM.
|
# Create an LLM.
|
||||||
llm = LLM(model="TheBloke/Llama-2-7b-Chat-AWQ", quantization="AWQ")
|
llm = LLM(model="TheBloke/Llama-2-7b-Chat-AWQ", quantization="auto_awq")
|
||||||
# Generate texts from the prompts. The output is a list of RequestOutput objects
|
# Generate texts from the prompts. The output is a list of RequestOutput objects
|
||||||
# that contain the prompt, generated text, and other information.
|
# that contain the prompt, generated text, and other information.
|
||||||
outputs = llm.generate(prompts, sampling_params)
|
outputs = llm.generate(prompts, sampling_params)
|
||||||
|
|||||||
@@ -321,15 +321,6 @@ For Qwen2.5, the chat template in tokenizer_config.json has already included sup
|
|||||||
|
|
||||||
Flags: `--tool-call-parser hermes`
|
Flags: `--tool-call-parser hermes`
|
||||||
|
|
||||||
### MiniMax Models (`minimax_m1`)
|
|
||||||
|
|
||||||
Supported models:
|
|
||||||
|
|
||||||
* `MiniMaxAi/MiniMax-M1-40k` (use with [examples/tool_chat_template_minimax_m1.jinja](../../examples/tool_chat_template_minimax_m1.jinja))
|
|
||||||
* `MiniMaxAi/MiniMax-M1-80k` (use with [examples/tool_chat_template_minimax_m1.jinja](../../examples/tool_chat_template_minimax_m1.jinja))
|
|
||||||
|
|
||||||
Flags: `--tool-call-parser minimax --chat-template examples/tool_chat_template_minimax_m1.jinja`
|
|
||||||
|
|
||||||
### DeepSeek-V3 Models (`deepseek_v3`)
|
### DeepSeek-V3 Models (`deepseek_v3`)
|
||||||
|
|
||||||
Supported models:
|
Supported models:
|
||||||
|
|||||||
@@ -142,6 +142,10 @@ VLLM_USE_PRECOMPILED=1 VLLM_PRECOMPILED_WHEEL_VARIANT=cpu VLLM_TARGET_DEVICE=cpu
|
|||||||
=== "IBM Z (S390X)"
|
=== "IBM Z (S390X)"
|
||||||
--8<-- "docs/getting_started/installation/cpu.s390x.inc.md:build-image-from-source"
|
--8<-- "docs/getting_started/installation/cpu.s390x.inc.md:build-image-from-source"
|
||||||
|
|
||||||
|
## AMD Zen optimizations {#amd-zen-optimizations}
|
||||||
|
|
||||||
|
--8<-- "docs/getting_started/installation/cpu.x86.inc.md:amd-zen-optimizations"
|
||||||
|
|
||||||
## Related runtime environment variables
|
## Related runtime environment variables
|
||||||
|
|
||||||
- `VLLM_CPU_KVCACHE_SPACE`: specify the KV Cache size (e.g, `VLLM_CPU_KVCACHE_SPACE=40` means 40 GiB space for KV cache), larger setting will allow vLLM to run more requests in parallel. This parameter should be set based on the hardware configuration and memory management pattern of users. Default value is `0`.
|
- `VLLM_CPU_KVCACHE_SPACE`: specify the KV Cache size (e.g, `VLLM_CPU_KVCACHE_SPACE=40` means 40 GiB space for KV cache), larger setting will allow vLLM to run more requests in parallel. This parameter should be set based on the hardware configuration and memory management pattern of users. Default value is `0`.
|
||||||
@@ -149,12 +153,14 @@ VLLM_USE_PRECOMPILED=1 VLLM_PRECOMPILED_WHEEL_VARIANT=cpu VLLM_TARGET_DEVICE=cpu
|
|||||||
- `VLLM_CPU_NUM_OF_RESERVED_CPU`: specify the number of CPU cores which are not dedicated to the OpenMP threads for each rank. The variable only takes effect when VLLM_CPU_OMP_THREADS_BIND is set to `auto`. Default value is `None`. If the value is not set and use `auto` thread binding, no CPU will be reserved for `world_size == 1`, 1 CPU per rank will be reserved for `world_size > 1`.
|
- `VLLM_CPU_NUM_OF_RESERVED_CPU`: specify the number of CPU cores which are not dedicated to the OpenMP threads for each rank. The variable only takes effect when VLLM_CPU_OMP_THREADS_BIND is set to `auto`. Default value is `None`. If the value is not set and use `auto` thread binding, no CPU will be reserved for `world_size == 1`, 1 CPU per rank will be reserved for `world_size > 1`.
|
||||||
- `CPU_VISIBLE_MEMORY_NODES`: specify visible NUMA memory nodes for vLLM CPU workers, similar to ```CUDA_VISIBLE_DEVICES```. The variable only takes effect when VLLM_CPU_OMP_THREADS_BIND is set to `auto`. The variable provides more control for the auto thread-binding feature, such as masking nodes and changing nodes binding sequence.
|
- `CPU_VISIBLE_MEMORY_NODES`: specify visible NUMA memory nodes for vLLM CPU workers, similar to ```CUDA_VISIBLE_DEVICES```. The variable only takes effect when VLLM_CPU_OMP_THREADS_BIND is set to `auto`. The variable provides more control for the auto thread-binding feature, such as masking nodes and changing nodes binding sequence.
|
||||||
- `VLLM_CPU_SGL_KERNEL` (x86 only, Experimental): whether to use small-batch optimized kernels for linear layer and MoE layer, especially for low-latency requirements like online serving. The kernels require AMX instruction set, BFloat16 weight type and weight shapes divisible by 32. Default is `0` (False).
|
- `VLLM_CPU_SGL_KERNEL` (x86 only, Experimental): whether to use small-batch optimized kernels for linear layer and MoE layer, especially for low-latency requirements like online serving. The kernels require AMX instruction set, BFloat16 weight type and weight shapes divisible by 32. Default is `0` (False).
|
||||||
|
- `VLLM_ZENTORCH_WEIGHT_PREPACK` (AMD Zen only): when `ZenCpuPlatform` is active, eagerly prepack linear weights into ZenDNN's blocked layout at model load time, eliminating per-inference layout conversion overhead. Default is `1` (enabled). See [AMD Zen optimizations](#amd-zen-optimizations).
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
### Which `dtype` should be used?
|
### Which `dtype` should be used?
|
||||||
|
|
||||||
- Currently, vLLM CPU uses model default settings as `dtype`. However, due to unstable float16 support in torch CPU, it is recommended to explicitly set `dtype=bfloat16` if there are any performance or accuracy problem.
|
- Currently, vLLM CPU uses model default settings as `dtype`. However, due to unstable float16 support in torch CPU, it is recommended to explicitly set `dtype=bfloat16` if there are any performance or accuracy problem.
|
||||||
|
- On AMD Zen CPUs (`ZenCpuPlatform`), `float16` is **not** supported. Only `bfloat16` and `float32` are accepted; models declared with `float16` are auto-downcast to `bfloat16` at model load time. See [AMD Zen optimizations](#amd-zen-optimizations).
|
||||||
|
|
||||||
### How to launch a vLLM service on CPU?
|
### How to launch a vLLM service on CPU?
|
||||||
|
|
||||||
@@ -227,6 +233,25 @@ By providing MODEL_FILTER and DTYPE_FILTER, only commands for related model ID a
|
|||||||
ON_CPU=1 SERVING_JSON=serving-tests-cpu-text.json DRY_RUN=1 MODEL_FILTER=meta-llama/Llama-3.1-8B-Instruct DTYPE_FILTER=bfloat16 bash .buildkite/performance-benchmarks/scripts/run-performance-benchmarks.sh
|
ON_CPU=1 SERVING_JSON=serving-tests-cpu-text.json DRY_RUN=1 MODEL_FILTER=meta-llama/Llama-3.1-8B-Instruct DTYPE_FILTER=bfloat16 bash .buildkite/performance-benchmarks/scripts/run-performance-benchmarks.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### How do I enable AMD Zen optimizations? {#how-do-i-enable-amd-zen-optimizations}
|
||||||
|
|
||||||
|
On an AMD Zen 4 / Zen 5 CPU, install the CPU wheel with the `zen` extra so vLLM pulls the tested `zentorch` version for that release:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export VLLM_VERSION=$(curl -s https://api.github.com/repos/vllm-project/vllm/releases/latest | jq -r .tag_name | sed 's/^v//')
|
||||||
|
uv pip install "vllm[zen]" --extra-index-url https://wheels.vllm.ai/${VLLM_VERSION}/cpu --index-strategy first-index --torch-backend cpu
|
||||||
|
```
|
||||||
|
|
||||||
|
vLLM auto-detects the platform and routes linear layers through ZenDNN-optimized kernels - no flag needed. To verify it is engaged, look for the platform-selection line in the server's startup logs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vllm serve Qwen/Qwen3-0.6B 2>&1 | grep "AMD Zen CPU detected with zentorch installed"
|
||||||
|
```
|
||||||
|
|
||||||
|
For per-backend dispatch details (which kernel each linear layer was bound to), re-run with `VLLM_LOGGING_LEVEL=DEBUG` and grep for `CPU unquantized GEMM dispatch`.
|
||||||
|
|
||||||
|
See [AMD Zen optimizations](#amd-zen-optimizations) for detection rules, supported dtypes, and the `VLLM_ZENTORCH_WEIGHT_PREPACK` knob.
|
||||||
|
|
||||||
### How to decide `VLLM_CPU_OMP_THREADS_BIND`?
|
### How to decide `VLLM_CPU_OMP_THREADS_BIND`?
|
||||||
|
|
||||||
- Default `auto` thread-binding is recommended for most cases. Ideally, each OpenMP thread will be bound to a dedicated physical core respectively, threads of each rank will be bound to the same NUMA node respectively, and 1 CPU per rank will be reserved for other vLLM components when `world_size > 1`. If you have any performance problems or unexpected binding behaviours, please try to bind threads as following.
|
- Default `auto` thread-binding is recommended for most cases. Ideally, each OpenMP thread will be bound to a dedicated physical core respectively, threads of each rank will be bound to the same NUMA node respectively, and 1 CPU per rank will be reserved for other vLLM components when `world_size > 1`. If you have any performance problems or unexpected binding behaviours, please try to bind threads as following.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- markdownlint-disable MD041 -->
|
<!-- markdownlint-disable MD041 MD051 -->
|
||||||
--8<-- [start:installation]
|
--8<-- [start:installation]
|
||||||
|
|
||||||
vLLM supports basic model inferencing and serving on x86 CPU platform, with data types FP32, FP16 and BF16.
|
vLLM supports basic model inferencing and serving on x86 CPU platform, with data types FP32, FP16 and BF16.
|
||||||
@@ -200,7 +200,19 @@ docker build -f docker/Dockerfile.cpu \
|
|||||||
--target vllm-openai .
|
--target vllm-openai .
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Launching the OpenAI server
|
#### Building with AMD Zen optimizations
|
||||||
|
|
||||||
|
For AMD Zen 4 / Zen 5 hosts (`linux/amd64` only), use the `vllm-openai-zen` target. It extends the default `vllm-openai` image and adds `zentorch` via the `vllm[zen]` extra so `ZenCpuPlatform` auto-activates at runtime:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -f docker/Dockerfile.cpu \
|
||||||
|
--tag vllm-cpu-zen-env \
|
||||||
|
--target vllm-openai-zen .
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting image accepts the same arguments and environment variables as `vllm-openai` (see [Launching the OpenAI server](#launching-the-openai-server) below); no extra flag is needed to engage Zen optimizations. See [AMD Zen optimizations](cpu.md#amd-zen-optimizations) for runtime behavior and the supported-dtype caveats.
|
||||||
|
|
||||||
|
#### Launching the OpenAI server {#launching-the-openai-server}
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
@@ -216,5 +228,36 @@ docker run --rm \
|
|||||||
```
|
```
|
||||||
|
|
||||||
--8<-- [end:build-image-from-source]
|
--8<-- [end:build-image-from-source]
|
||||||
|
--8<-- [start:amd-zen-optimizations]
|
||||||
|
|
||||||
|
On AMD Zen CPUs, vLLM auto-selects `ZenCpuPlatform` (a subclass of `CpuPlatform`) which dispatches linear layers through [`zentorch`](https://github.com/amd/ZenDNN-pytorch-plugin)'s ZenDNN-optimized kernels. See the FAQ entry [How do I enable AMD Zen optimizations?](#how-do-i-enable-amd-zen-optimizations) for the install command.
|
||||||
|
|
||||||
|
### Detection rules
|
||||||
|
|
||||||
|
`ZenCpuPlatform` is selected when **all** of the following hold:
|
||||||
|
|
||||||
|
- vLLM is built for CPU
|
||||||
|
- `/proc/cpuinfo` reports `AuthenticAMD` and `avx512`
|
||||||
|
- `import zentorch` succeeds
|
||||||
|
|
||||||
|
Otherwise, vLLM falls back to the default `CpuPlatform` (oneDNN / sgl-kernel paths).
|
||||||
|
|
||||||
|
### Supported dtypes
|
||||||
|
|
||||||
|
`float16` is **not** supported on `ZenCpuPlatform`. `ZenCpuPlatform.supported_dtypes` advertises only `bfloat16` and `float32`, so models declared with `torch_dtype=float16` are auto-downcast to `bfloat16` at load time with the standard `"Your device 'cpu' doesn't support torch.float16. Falling back to torch.bfloat16 for compatibility."` warning emitted from `vllm/config/model.py`.
|
||||||
|
|
||||||
|
### Environment variables
|
||||||
|
|
||||||
|
- `VLLM_ZENTORCH_WEIGHT_PREPACK` (default `1`): eagerly prepacks linear weights into ZenDNN's blocked layout at model load time, eliminating per-inference layout conversion overhead. Set to `0` to disable.
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
The `vllm-openai-zen` Docker target (in `docker/Dockerfile.cpu`) extends the default `vllm-openai` image with `vllm[zen]`. Build it with `docker build -f docker/Dockerfile.cpu --target vllm-openai-zen .` — see [Building with AMD Zen optimizations](#building-with-amd-zen-optimizations) for the full command and run instructions.
|
||||||
|
|
||||||
|
### Reference
|
||||||
|
|
||||||
|
For the design rationale, see [RFC #35089: In-Tree AMD Zen CPU Backend via zentorch](https://github.com/vllm-project/vllm/issues/35089).
|
||||||
|
|
||||||
|
--8<-- [end:amd-zen-optimizations]
|
||||||
--8<-- [start:extra-information]
|
--8<-- [start:extra-information]
|
||||||
--8<-- [end:extra-information]
|
--8<-- [end:extra-information]
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ Currently, there are no pre-built XPU wheels.
|
|||||||
|
|
||||||
- First, install required [driver](https://dgpu-docs.intel.com/driver/installation.html#installing-gpu-drivers).
|
- First, install required [driver](https://dgpu-docs.intel.com/driver/installation.html#installing-gpu-drivers).
|
||||||
- Second, install Python packages for vLLM XPU backend building (Intel OneAPI dependencies are installed automatically as part of `torch-xpu`, see [PyTorch XPU get started](https://docs.pytorch.org/docs/stable/notes/get_start_xpu.html)):
|
- Second, install Python packages for vLLM XPU backend building (Intel OneAPI dependencies are installed automatically as part of `torch-xpu`, see [PyTorch XPU get started](https://docs.pytorch.org/docs/stable/notes/get_start_xpu.html)):
|
||||||
|
- Start from vllm-xpu-kernels v0.1.10, we recommend user upgrade driver to [compute runtime 26.18](https://github.com/intel/compute-runtime/releases/tag/26.14.37833.4) release, to avoid potential compatibility issue.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/vllm-project/vllm.git
|
git clone https://github.com/vllm-project/vllm.git
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
# CPU - Intel® Xeon®
|
# CPU - Intel® Xeon®
|
||||||
|
|
||||||
|
!!! note "AMD Zen CPUs"
|
||||||
|
On AMD Zen 4 / Zen 5 CPUs, AMD Zen optimizations are auto-enabled when the [`zentorch`](https://github.com/amd/ZenDNN-pytorch-plugin) package is installed. All models supported by vLLM on CPU are supported on AMD Zen as well; model compatibility does not change. This page reflects the current CPU reference validation matrix on Intel systems. See [AMD Zen optimizations](../../getting_started/installation/cpu.md#amd-zen-optimizations) for details.
|
||||||
|
|
||||||
## Validated Hardware
|
## Validated Hardware
|
||||||
|
|
||||||
| Hardware |
|
| Hardware |
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ Models of any architecture can be converted into embedding models using `--conve
|
|||||||
| `ColModernVBertForRetrieval` | ColModernVBERT | T / I | `ModernVBERT/colmodernvbert-merged` | | |
|
| `ColModernVBertForRetrieval` | ColModernVBERT | T / I | `ModernVBERT/colmodernvbert-merged` | | |
|
||||||
| `ColPaliForRetrieval` | ColPali | T / I | `vidore/colpali-v1.3-hf` | | |
|
| `ColPaliForRetrieval` | ColPali | T / I | `vidore/colpali-v1.3-hf` | | |
|
||||||
| `ColQwen3` | Qwen3-VL | T / I | `TomoroAI/tomoro-colqwen3-embed-4b`, `TomoroAI/tomoro-colqwen3-embed-8b` | | |
|
| `ColQwen3` | Qwen3-VL | T / I | `TomoroAI/tomoro-colqwen3-embed-4b`, `TomoroAI/tomoro-colqwen3-embed-8b` | | |
|
||||||
| `ColQwen3_5` | ColQwen3.5 | T + I + V | `athrael-soju/colqwen3.5-4.5B-v3` | | |
|
| `ColQwen3_5` | ColQwen3.5 | T + I + V | `athrael-soju/colqwen3.5-4.5B-v3`, `vultr/VultronRetrieverPrime-Qwen3.5-8B` | | |
|
||||||
| `OpsColQwen3Model` | Qwen3-VL | T / I | `OpenSearch-AI/Ops-Colqwen3-4B`, `OpenSearch-AI/Ops-Colqwen3-8B` | | |
|
| `OpsColQwen3Model` | Qwen3-VL | T / I | `OpenSearch-AI/Ops-Colqwen3-4B`, `OpenSearch-AI/Ops-Colqwen3-8B` | | |
|
||||||
| `Qwen3VLNemotronEmbedModel` | Qwen3-VL | T / I | `nvidia/nemotron-colembed-vl-4b-v2`, `nvidia/nemotron-colembed-vl-8b-v2` | ✅︎ | ✅︎ |
|
| `Qwen3VLNemotronEmbedModel` | Qwen3-VL | T / I | `nvidia/nemotron-colembed-vl-4b-v2`, `nvidia/nemotron-colembed-vl-8b-v2` | ✅︎ | ✅︎ |
|
||||||
| `*ForConditionalGeneration`<sup>C</sup>, `*ForCausalLM`<sup>C</sup>, etc. | Generative models | \* | N/A | \* | \* |
|
| `*ForConditionalGeneration`<sup>C</sup>, `*ForCausalLM`<sup>C</sup>, etc. | Generative models | \* | N/A | \* | \* |
|
||||||
|
|||||||
@@ -374,7 +374,6 @@ th {
|
|||||||
| `BailingMoeForCausalLM` | Ling | `inclusionAI/Ling-lite-1.5`, `inclusionAI/Ling-plus`, etc. | ✅︎ | ✅︎ |
|
| `BailingMoeForCausalLM` | Ling | `inclusionAI/Ling-lite-1.5`, `inclusionAI/Ling-plus`, etc. | ✅︎ | ✅︎ |
|
||||||
| `BailingMoeV2ForCausalLM` | Ling | `inclusionAI/Ling-mini-2.0`, etc. | ✅︎ | ✅︎ |
|
| `BailingMoeV2ForCausalLM` | Ling | `inclusionAI/Ling-mini-2.0`, etc. | ✅︎ | ✅︎ |
|
||||||
| `BailingMoeV2_5ForCausalLM` | Ling | `inclusionAI/Ling-2.5-1T`, `inclusionAI/Ring-2.5-1T` | | ✅︎ |
|
| `BailingMoeV2_5ForCausalLM` | Ling | `inclusionAI/Ling-2.5-1T`, `inclusionAI/Ring-2.5-1T` | | ✅︎ |
|
||||||
| `BambaForCausalLM` | Bamba | `ibm-ai-platform/Bamba-9B-fp8`, `ibm-ai-platform/Bamba-9B` | ✅︎ | ✅︎ |
|
|
||||||
| `BloomForCausalLM` | BLOOM, BLOOMZ, BLOOMChat | `bigscience/bloom`, `bigscience/bloomz`, etc. | | ✅︎ |
|
| `BloomForCausalLM` | BLOOM, BLOOMZ, BLOOMChat | `bigscience/bloom`, `bigscience/bloomz`, etc. | | ✅︎ |
|
||||||
| `ChatGLMModel`, `ChatGLMForConditionalGeneration` | ChatGLM | `zai-org/chatglm2-6b`, `zai-org/chatglm3-6b`, `thu-coai/ShieldLM-6B-chatglm3`, etc. | ✅︎ | ✅︎ |
|
| `ChatGLMModel`, `ChatGLMForConditionalGeneration` | ChatGLM | `zai-org/chatglm2-6b`, `zai-org/chatglm3-6b`, `thu-coai/ShieldLM-6B-chatglm3`, etc. | ✅︎ | ✅︎ |
|
||||||
| `CohereForCausalLM`, `Cohere2ForCausalLM` | Command-R, Command-A | `CohereLabs/c4ai-command-r-v01`, `CohereLabs/c4ai-command-r7b-12-2024`, `CohereLabs/c4ai-command-a-03-2025`, `CohereLabs/command-a-reasoning-08-2025`, etc. | ✅︎ | ✅︎ |
|
| `CohereForCausalLM`, `Cohere2ForCausalLM` | Command-R, Command-A | `CohereLabs/c4ai-command-r-v01`, `CohereLabs/c4ai-command-r7b-12-2024`, `CohereLabs/c4ai-command-a-03-2025`, `CohereLabs/command-a-reasoning-08-2025`, etc. | ✅︎ | ✅︎ |
|
||||||
@@ -386,7 +385,6 @@ th {
|
|||||||
| `DeepseekV2ForCausalLM` | DeepSeek-V2 | `deepseek-ai/DeepSeek-V2`, `deepseek-ai/DeepSeek-V2-Chat`, etc. | ✅︎ | ✅︎ |
|
| `DeepseekV2ForCausalLM` | DeepSeek-V2 | `deepseek-ai/DeepSeek-V2`, `deepseek-ai/DeepSeek-V2-Chat`, etc. | ✅︎ | ✅︎ |
|
||||||
| `DeepseekV3ForCausalLM` | DeepSeek-V3 | `deepseek-ai/DeepSeek-V3`, `deepseek-ai/DeepSeek-R1`, `deepseek-ai/DeepSeek-V3.1`, etc. | ✅︎ | ✅︎ |
|
| `DeepseekV3ForCausalLM` | DeepSeek-V3 | `deepseek-ai/DeepSeek-V3`, `deepseek-ai/DeepSeek-R1`, `deepseek-ai/DeepSeek-V3.1`, etc. | ✅︎ | ✅︎ |
|
||||||
| `DeepseekV4ForCausalLM` | DeepSeek-V4 | `deepseek-ai/DeepSeek-V4-Flash`, `deepseek-ai/DeepSeek-V4-Pro`, etc. | | ✅︎ |
|
| `DeepseekV4ForCausalLM` | DeepSeek-V4 | `deepseek-ai/DeepSeek-V4-Flash`, `deepseek-ai/DeepSeek-V4-Pro`, etc. | | ✅︎ |
|
||||||
| `Dots1ForCausalLM` | dots.llm1 | `rednote-hilab/dots.llm1.base`, `rednote-hilab/dots.llm1.inst`, etc. | | ✅︎ |
|
|
||||||
| `DotsOCRForCausalLM` | dots_ocr | `rednote-hilab/dots.ocr` | ✅︎ | ✅︎ |
|
| `DotsOCRForCausalLM` | dots_ocr | `rednote-hilab/dots.ocr` | ✅︎ | ✅︎ |
|
||||||
| `Ernie4_5ForCausalLM` | Ernie4.5 | `baidu/ERNIE-4.5-0.3B-PT`, etc. | ✅︎ | ✅︎ |
|
| `Ernie4_5ForCausalLM` | Ernie4.5 | `baidu/ERNIE-4.5-0.3B-PT`, etc. | ✅︎ | ✅︎ |
|
||||||
| `Ernie4_5_MoeForCausalLM` | Ernie4.5MoE | `baidu/ERNIE-4.5-21B-A3B-PT`, `baidu/ERNIE-4.5-300B-A47B-PT`, etc. | ✅︎ | ✅︎ |
|
| `Ernie4_5_MoeForCausalLM` | Ernie4.5MoE | `baidu/ERNIE-4.5-21B-A3B-PT`, `baidu/ERNIE-4.5-300B-A47B-PT`, etc. | ✅︎ | ✅︎ |
|
||||||
@@ -419,6 +417,7 @@ th {
|
|||||||
| `GritLM` | GritLM | `parasail-ai/GritLM-7B-vllm`. | ✅︎ | ✅︎ |
|
| `GritLM` | GritLM | `parasail-ai/GritLM-7B-vllm`. | ✅︎ | ✅︎ |
|
||||||
| `Grok1ModelForCausalLM` | Grok1 | `hpcai-tech/grok-1`. | ✅︎ | ✅︎ |
|
| `Grok1ModelForCausalLM` | Grok1 | `hpcai-tech/grok-1`. | ✅︎ | ✅︎ |
|
||||||
| `Grok1ForCausalLM` | Grok2 | `xai-org/grok-2` | ✅︎ | ✅︎ |
|
| `Grok1ForCausalLM` | Grok2 | `xai-org/grok-2` | ✅︎ | ✅︎ |
|
||||||
|
| `HrmTextForCausalLM` | HRM-Text | `sapientinc/HRM-Text-1B`, etc. | | |
|
||||||
| `HunYuanDenseV1ForCausalLM` | Hunyuan Dense | `tencent/Hunyuan-7B-Instruct` | ✅︎ | ✅︎ |
|
| `HunYuanDenseV1ForCausalLM` | Hunyuan Dense | `tencent/Hunyuan-7B-Instruct` | ✅︎ | ✅︎ |
|
||||||
| `HunYuanMoEV1ForCausalLM` | Hunyuan-A13B | `tencent/Hunyuan-A13B-Instruct`, `tencent/Hunyuan-A13B-Pretrain`, `tencent/Hunyuan-A13B-Instruct-FP8`, etc. | ✅︎ | ✅︎ |
|
| `HunYuanMoEV1ForCausalLM` | Hunyuan-A13B | `tencent/Hunyuan-A13B-Instruct`, `tencent/Hunyuan-A13B-Pretrain`, `tencent/Hunyuan-A13B-Instruct-FP8`, etc. | ✅︎ | ✅︎ |
|
||||||
| `HYV3ForCausalLM` | HY3 | `tencent/Hy3-preview-Base`, `tencent/Hy3-preview` | ✅︎ | ✅︎ |
|
| `HYV3ForCausalLM` | HY3 | `tencent/Hy3-preview-Base`, `tencent/Hy3-preview` | ✅︎ | ✅︎ |
|
||||||
@@ -442,7 +441,6 @@ th {
|
|||||||
| `MiMoV2ForCausalLM` | MiMoV2Pro | `XiaomiMiMo/MiMo-V2.5-Pro`, etc. | | ✅︎ |
|
| `MiMoV2ForCausalLM` | MiMoV2Pro | `XiaomiMiMo/MiMo-V2.5-Pro`, etc. | | ✅︎ |
|
||||||
| `MiniCPMForCausalLM` | MiniCPM | `openbmb/MiniCPM-2B-sft-bf16`, `openbmb/MiniCPM-2B-dpo-bf16`, `openbmb/MiniCPM-S-1B-sft`, etc. | ✅︎ | ✅︎ |
|
| `MiniCPMForCausalLM` | MiniCPM | `openbmb/MiniCPM-2B-sft-bf16`, `openbmb/MiniCPM-2B-dpo-bf16`, `openbmb/MiniCPM-S-1B-sft`, etc. | ✅︎ | ✅︎ |
|
||||||
| `MiniCPM3ForCausalLM` | MiniCPM3 | `openbmb/MiniCPM3-4B`, etc. | ✅︎ | ✅︎ |
|
| `MiniCPM3ForCausalLM` | MiniCPM3 | `openbmb/MiniCPM3-4B`, etc. | ✅︎ | ✅︎ |
|
||||||
| `MiniMaxForCausalLM` | MiniMax-Text | `MiniMaxAI/MiniMax-Text-01-hf`, etc. | | |
|
|
||||||
| `MiniMaxM2ForCausalLM` | MiniMax-M2, MiniMax-M2.1 | `MiniMaxAI/MiniMax-M2`, etc. | ✅︎ | ✅︎ |
|
| `MiniMaxM2ForCausalLM` | MiniMax-M2, MiniMax-M2.1 | `MiniMaxAI/MiniMax-M2`, etc. | ✅︎ | ✅︎ |
|
||||||
| `MistralForCausalLM` | Ministral-3, Mistral, Mistral-Instruct | `mistralai/Ministral-3-3B-Instruct-2512`, `mistralai/Mistral-7B-v0.1`, `mistralai/Mistral-7B-Instruct-v0.1`, etc. | ✅︎ | ✅︎ |
|
| `MistralForCausalLM` | Ministral-3, Mistral, Mistral-Instruct | `mistralai/Ministral-3-3B-Instruct-2512`, `mistralai/Mistral-7B-v0.1`, `mistralai/Mistral-7B-Instruct-v0.1`, etc. | ✅︎ | ✅︎ |
|
||||||
| `MistralLarge3ForCausalLM` | Mistral-Large-3-675B-Base-2512, Mistral-Large-3-675B-Instruct-2512 | `mistralai/Mistral-Large-3-675B-Base-2512`, `mistralai/Mistral-Large-3-675B-Instruct-2512`, etc. | ✅︎ | ✅︎ |
|
| `MistralLarge3ForCausalLM` | Mistral-Large-3-675B-Base-2512, Mistral-Large-3-675B-Instruct-2512 | `mistralai/Mistral-Large-3-675B-Base-2512`, `mistralai/Mistral-Large-3-675B-Instruct-2512`, etc. | ✅︎ | ✅︎ |
|
||||||
@@ -488,8 +486,6 @@ th {
|
|||||||
| `TeleChat2ForCausalLM` | TeleChat2 | `Tele-AI/TeleChat2-3B`, `Tele-AI/TeleChat2-7B`, `Tele-AI/TeleChat2-35B`, etc. | ✅︎ | ✅︎ |
|
| `TeleChat2ForCausalLM` | TeleChat2 | `Tele-AI/TeleChat2-3B`, `Tele-AI/TeleChat2-7B`, `Tele-AI/TeleChat2-35B`, etc. | ✅︎ | ✅︎ |
|
||||||
| `TeleChat3ForCausalLM` | TeleChat3 | `Tele-AI/TeleChat3-36B-Thinking`, `Tele-AI/TeleChat3-Coder-36B-Thinking`, etc. | ✅︎ | ✅︎ |
|
| `TeleChat3ForCausalLM` | TeleChat3 | `Tele-AI/TeleChat3-36B-Thinking`, `Tele-AI/TeleChat3-Coder-36B-Thinking`, etc. | ✅︎ | ✅︎ |
|
||||||
| `TeleFLMForCausalLM` | TeleFLM | `CofeAI/FLM-2-52B-Instruct-2407`, `CofeAI/Tele-FLM`, etc. | ✅︎ | ✅︎ |
|
| `TeleFLMForCausalLM` | TeleFLM | `CofeAI/FLM-2-52B-Instruct-2407`, `CofeAI/Tele-FLM`, etc. | ✅︎ | ✅︎ |
|
||||||
| `MiniMaxM1ForCausalLM` | MiniMax-Text | `MiniMaxAI/MiniMax-M1-40k`, `MiniMaxAI/MiniMax-M1-80k`, etc. | | |
|
|
||||||
| `MiniMaxText01ForCausalLM` | MiniMax-Text | `MiniMaxAI/MiniMax-Text-01`, etc. | | |
|
|
||||||
| `Zamba2ForCausalLM` | Zamba2 | `Zyphra/Zamba2-7B-instruct`, `Zyphra/Zamba2-2.7B-instruct`, `Zyphra/Zamba2-1.2B-instruct`, etc. | | |
|
| `Zamba2ForCausalLM` | Zamba2 | `Zyphra/Zamba2-7B-instruct`, `Zyphra/Zamba2-2.7B-instruct`, `Zyphra/Zamba2-1.2B-instruct`, etc. | | |
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
@@ -596,6 +592,7 @@ These models primarily accept the [`LLM.generate`](./generative_models.md#llmgen
|
|||||||
| `MiMoV2OmniForCausalLM` | MiMo-V2.5-Omni | T + I<sup>E+</sup> + V<sup>E+</sup> + A<sup>+</sup> | `XiaomiMiMo/MiMo-V2.5-Omni` | | ✅︎ |
|
| `MiMoV2OmniForCausalLM` | MiMo-V2.5-Omni | T + I<sup>E+</sup> + V<sup>E+</sup> + A<sup>+</sup> | `XiaomiMiMo/MiMo-V2.5-Omni` | | ✅︎ |
|
||||||
| `MiniCPMO` | MiniCPM-O | T + I<sup>E+</sup> + V<sup>E+</sup> + A<sup>E+</sup> | `openbmb/MiniCPM-o-2_6`, etc. | ✅︎ | ✅︎ |
|
| `MiniCPMO` | MiniCPM-O | T + I<sup>E+</sup> + V<sup>E+</sup> + A<sup>E+</sup> | `openbmb/MiniCPM-o-2_6`, etc. | ✅︎ | ✅︎ |
|
||||||
| `MiniCPMV` | MiniCPM-V | T + I<sup>E+</sup> + V<sup>E+</sup> | `openbmb/MiniCPM-V-2` (see note), `openbmb/MiniCPM-Llama3-V-2_5`, `openbmb/MiniCPM-V-2_6`, `openbmb/MiniCPM-V-4`, `openbmb/MiniCPM-V-4_5`, etc. | ✅︎ | |
|
| `MiniCPMV` | MiniCPM-V | T + I<sup>E+</sup> + V<sup>E+</sup> | `openbmb/MiniCPM-V-2` (see note), `openbmb/MiniCPM-Llama3-V-2_5`, `openbmb/MiniCPM-V-2_6`, `openbmb/MiniCPM-V-4`, `openbmb/MiniCPM-V-4_5`, etc. | ✅︎ | |
|
||||||
|
| `MiniMaxM3SparseForConditionalGeneration` | MiniMax-M3 | T + I<sup>+</sup> + V<sup>+</sup> | `MiniMaxAI/MiniMax-M3`, `MiniMaxAI/MiniMax-M3-MXFP8`, etc. | | |
|
||||||
| `MiniMaxVL01ForConditionalGeneration` | MiniMax-VL | T + I<sup>E+</sup> | `MiniMaxAI/MiniMax-VL-01`, etc. | | ✅︎ |
|
| `MiniMaxVL01ForConditionalGeneration` | MiniMax-VL | T + I<sup>E+</sup> | `MiniMaxAI/MiniMax-VL-01`, etc. | | ✅︎ |
|
||||||
| `Mistral3ForConditionalGeneration` | Mistral3 (HF Transformers) | T + I<sup>+</sup> | `mistralai/Mistral-Small-3.1-24B-Instruct-2503`, etc. | ✅︎ | ✅︎ |
|
| `Mistral3ForConditionalGeneration` | Mistral3 (HF Transformers) | T + I<sup>+</sup> | `mistralai/Mistral-Small-3.1-24B-Instruct-2503`, etc. | ✅︎ | ✅︎ |
|
||||||
| `MolmoForCausalLM` | Molmo | T + I<sup>+</sup> | `allenai/Molmo-7B-D-0924`, `allenai/Molmo-7B-O-0924`, etc. | ✅︎ | ✅︎ |
|
| `MolmoForCausalLM` | Molmo | T + I<sup>+</sup> | `allenai/Molmo-7B-D-0924`, `allenai/Molmo-7B-O-0924`, etc. | ✅︎ | ✅︎ |
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ For more information on implementation, see [Low Level `layerwise` API](#low-lev
|
|||||||
Online quantization refers to when a user provides full precision weights and those weights are quantized on-the-fly as they are loaded into the model. The layerwise reloading system handles this by treating online quantization as a **processing** step, which is then handled in an online way both during first-time load and during reload. A typical online quantization method implementation should look like this:
|
Online quantization refers to when a user provides full precision weights and those weights are quantized on-the-fly as they are loaded into the model. The layerwise reloading system handles this by treating online quantization as a **processing** step, which is then handled in an online way both during first-time load and during reload. A typical online quantization method implementation should look like this:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Fp8OnlineLinearMethod(Fp8LinearMethod):
|
class Fp8PerTensorOnlineLinearMethod(LinearMethodBase):
|
||||||
"""Online version of Fp8LinearMethod which loads a full precision checkpoint
|
"""Online version of FP8 per-tensor quantization which loads a full
|
||||||
and quantizes weights during loading."""
|
precision checkpoint and quantizes weights during loading."""
|
||||||
|
|
||||||
uses_meta_device: bool = True
|
uses_meta_device: bool = True
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ Models that use Mamba-2 and Mamba-1 layers (e.g., `Mamba2ForCausalLM`, `MambaFor
|
|||||||
Hybrid models that combine Mamba-2 and Mamba-1 layers with standard attention layers are also supported (e.g., `BambaForCausalLM`,
|
Hybrid models that combine Mamba-2 and Mamba-1 layers with standard attention layers are also supported (e.g., `BambaForCausalLM`,
|
||||||
`Zamba2ForCausalLM`, `NemotronHForCausalLM`, `FalconH1ForCausalLM` and `GraniteMoeHybridForCausalLM`, `JambaForCausalLM`, `Plamo2ForCausalLM`).
|
`Zamba2ForCausalLM`, `NemotronHForCausalLM`, `FalconH1ForCausalLM` and `GraniteMoeHybridForCausalLM`, `JambaForCausalLM`, `Plamo2ForCausalLM`).
|
||||||
|
|
||||||
Hybrid models with mechanisms different to Mamba are also supported (e.g, `MiniMaxText01ForCausalLM`, `MiniMaxM1ForCausalLM`, `Lfm2ForCausalLM`).
|
Hybrid models with mechanisms different to Mamba are also supported (e.g, `Lfm2ForCausalLM`).
|
||||||
|
|
||||||
Please note that prefix caching is not yet supported for any of the above models.
|
Please note that prefix caching is not yet supported for any of the above models.
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,38 @@
|
|||||||
# LMCache Examples
|
# LMCache Examples
|
||||||
|
|
||||||
This folder demonstrates how to use LMCache for disaggregated prefilling, CPU offloading and KV cache sharing.
|
This folder demonstrates how to use LMCache with vLLM v1 for KV cache
|
||||||
|
offloading, disaggregated prefilling, and KV cache sharing.
|
||||||
|
|
||||||
## 1. Disaggregated Prefill in vLLM v1
|
## Integration modes
|
||||||
|
|
||||||
This example demonstrates how to run LMCache with disaggregated prefill using NIXL on a single node.
|
LMCache integrates with vLLM v1 in two ways:
|
||||||
|
|
||||||
|
- **In-process mode** (`LMCacheConnectorV1`): LMCache runs inside the vLLM
|
||||||
|
process and is configured through environment variables or a YAML config
|
||||||
|
file (`LMCACHE_CONFIG_FILE`). This is the simplest way to add single-node
|
||||||
|
CPU/disk offloading.
|
||||||
|
- **Multi-process (MP) mode** (`LMCacheMPConnector`): LMCache runs as a
|
||||||
|
standalone server (`lmcache server`) that owns the KV cache storage; one or
|
||||||
|
more vLLM instances connect to it. This is the recommended mode for
|
||||||
|
distributed KV storage and for sharing KV cache across instances. See the
|
||||||
|
[LMCache docs](https://docs.lmcache.ai) for the full MP setup.
|
||||||
|
|
||||||
|
## 1. CPU offload (in-process)
|
||||||
|
|
||||||
|
- `python cpu_offload_lmcache.py` - CPU offloading with `LMCacheConnectorV1`
|
||||||
|
for vLLM v1.
|
||||||
|
|
||||||
|
## 2. CPU offload (multi-process)
|
||||||
|
|
||||||
|
- `bash cpu_offload_lmcache_mp.sh` - CPU offloading with `LMCacheMPConnector`,
|
||||||
|
using a standalone `lmcache server`. vLLM provides a built-in shortcut for
|
||||||
|
this setup via `--kv-offloading-backend lmcache` and
|
||||||
|
`--kv-offloading-size <GiB>`.
|
||||||
|
|
||||||
|
## 3. Disaggregated Prefill in vLLM v1
|
||||||
|
|
||||||
|
This example demonstrates how to run LMCache with disaggregated prefill using
|
||||||
|
NIXL on a single node.
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
@@ -46,15 +74,7 @@ The main script generates several log files:
|
|||||||
- `decoder.log` - Logs from the decode server
|
- `decoder.log` - Logs from the decode server
|
||||||
- `proxy.log` - Logs from the proxy server
|
- `proxy.log` - Logs from the proxy server
|
||||||
|
|
||||||
## 2. CPU Offload Examples
|
## 4. KV Cache Sharing
|
||||||
|
|
||||||
- `python cpu_offload_lmcache.py -v v0` - CPU offloading implementation for vLLM v0
|
The `kv_cache_sharing_lmcache_v1.py` example demonstrates how to share KV
|
||||||
- `python cpu_offload_lmcache.py -v v1` - CPU offloading implementation for vLLM v1
|
caches between vLLM v1 instances through a centralized LMCache server.
|
||||||
|
|
||||||
## 3. KV Cache Sharing
|
|
||||||
|
|
||||||
The `kv_cache_sharing_lmcache_v1.py` example demonstrates how to share KV caches between vLLM v1 instances.
|
|
||||||
|
|
||||||
## 4. Disaggregated Prefill in vLLM v0
|
|
||||||
|
|
||||||
The `disaggregated_prefill_lmcache_v0.py` provides an example of how to run disaggregated prefill in vLLM v0.
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user