[Benchmark] Retire stale benchmarks and consolidate RMSNorm (#57083)

Signed-off-by: Misha Goin <mgoin64@gmail.com>

Misha Goin committed Sep 16, 2026 at 13:21 UTC 1085b64425a9e6f5ca52876ad32e55fda5665f4e
7 files changed +3 -780
benchmarks/cutlass_benchmarks/utils.py deleted
-39
@@ -1,39 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -# Cutlass bench utils
5 -
6 -import torch
7 -
8 -
9 -def to_fp8(tensor: torch.Tensor) -> torch.Tensor:
10 - finfo = torch.finfo(torch.float8_e4m3fn)
11 - return torch.round(tensor.clamp(min=finfo.min, max=finfo.max)).to(
12 - dtype=torch.float8_e4m3fn
13 - )
14 -
15 -
16 -def to_int8(tensor: torch.Tensor) -> torch.Tensor:
17 - return torch.round(tensor.clamp(min=-128, max=127)).to(dtype=torch.int8)
18 -
19 -
20 -def to_bf16(tensor: torch.Tensor) -> torch.Tensor:
21 - return tensor.to(dtype=torch.bfloat16)
22 -
23 -
24 -def to_fp16(tensor: torch.Tensor) -> torch.Tensor:
25 - return tensor.to(dtype=torch.float16)
26 -
27 -
28 -def make_rand_tensors(
29 - dtype: torch.dtype, m: int, n: int, k: int
30 -) -> tuple[torch.Tensor, torch.Tensor]:
31 - a = torch.randn((m, k), device="cuda") * 5
32 - b = torch.randn((n, k), device="cuda").t() * 5
33 -
34 - if dtype == torch.int8:
35 - return to_int8(a), to_int8(b)
36 - if dtype == torch.float8_e4m3fn:
37 - return to_fp8(a), to_fp8(b)
38 -
39 - raise ValueError("unsupported dtype")
benchmarks/cutlass_benchmarks/w8a8_benchmarks.py deleted
-372
@@ -1,372 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -import argparse
5 -import copy
6 -import itertools
7 -import pickle as pkl
8 -import time
9 -from collections.abc import Callable, Iterable
10 -
11 -import torch
12 -import torch.utils.benchmark as TBenchmark
13 -from torch.utils.benchmark import Measurement as TMeasurement
14 -from utils import make_rand_tensors
15 -from weight_shapes import WEIGHT_SHAPES
16 -
17 -from vllm import _custom_ops as ops
18 -from vllm.model_executor.layers.quantization.utils.fp8_utils import (
19 - w8a8_triton_block_scaled_mm,
20 -)
21 -from vllm.utils.argparse_utils import FlexibleArgumentParser
22 -from vllm.utils.math_utils import cdiv
23 -
24 -DEFAULT_MODELS = list(WEIGHT_SHAPES.keys())
25 -DEFAULT_BATCH_SIZES = [1, 16, 32, 64, 128, 256, 512]
26 -DEFAULT_TP_SIZES = [1]
27 -
28 -
29 -# bench
30 -def bench_fn(
31 - label: str, sub_label: str, description: str, fn: Callable, *args, **kwargs
32 -) -> TMeasurement:
33 - min_run_time = 1
34 -
35 - globals = {
36 - "args": args,
37 - "kwargs": kwargs,
38 - "fn": fn,
39 - }
40 - return TBenchmark.Timer(
41 - stmt="fn(*args, **kwargs)",
42 - globals=globals,
43 - label=label,
44 - sub_label=sub_label,
45 - description=description,
46 - ).blocked_autorange(min_run_time=min_run_time)
47 -
48 -
49 -def bench_int8(
50 - dtype: torch.dtype,
51 - m: int,
52 - k: int,
53 - n: int,
54 - label: str,
55 - sub_label: str,
56 - bench_kernels: list[str] | None = None,
57 -) -> Iterable[TMeasurement]:
58 - """Benchmark INT8-based kernels."""
59 - assert dtype == torch.int8
60 - a, b = make_rand_tensors(torch.int8, m, n, k)
61 - scale_a = torch.tensor(1.0, device="cuda", dtype=torch.float32)
62 - scale_b = torch.tensor(1.0, device="cuda", dtype=torch.float32)
63 - bias = torch.zeros((n,), device="cuda", dtype=torch.bfloat16)
64 - azp = torch.zeros((m,), device="cuda", dtype=torch.int32)
65 - azp_adj = torch.zeros((n,), device="cuda", dtype=torch.int32)
66 -
67 - bench_fns = {
68 - "pytorch_bf16_bf16_bf16_matmul-no-scales": lambda: torch.mm(
69 - a.to(dtype=torch.bfloat16), b.to(dtype=torch.bfloat16)
70 - ),
71 - "pytorch_fp16_fp16_fp16_matmul-no-scales": lambda: torch.mm(
72 - a.to(dtype=torch.float16), b.to(dtype=torch.float16)
73 - ),
74 - "cutlass_i8_i8_bf16_scaled_mm": lambda: ops.cutlass_scaled_mm(
75 - a, b, scale_a, scale_b, torch.bfloat16
76 - ),
77 - "cutlass_i8_i8_bf16_scaled_mm_bias": lambda: ops.cutlass_scaled_mm(
78 - a, b, scale_a, scale_b, torch.bfloat16, bias
79 - ),
80 - "cutlass_i8_i8_bf16_scaled_mm_azp": lambda: ops.cutlass_scaled_mm_azp(
81 - a, b, scale_a, scale_b, torch.bfloat16, azp_adj
82 - ),
83 - "cutlass_i8_i8_bf16_scaled_mm_azp_bias": lambda: ops.cutlass_scaled_mm_azp(
84 - a, b, scale_a, scale_b, torch.bfloat16, azp_adj, None, bias
85 - ),
86 - "cutlass_i8_i8_bf16_scaled_mm_azp_pt": lambda: ops.cutlass_scaled_mm_azp(
87 - a, b, scale_a, scale_b, torch.bfloat16, azp_adj, azp
88 - ),
89 - "cutlass_i8_i8_bf16_scaled_mm_azp_pt_bias": lambda: ops.cutlass_scaled_mm_azp(
90 - a, b, scale_a, scale_b, torch.bfloat16, azp_adj, azp, bias
91 - ),
92 - }
93 -
94 - timers = []
95 - for name, fn in bench_fns.items():
96 - # If bench_kernels is None, run all. Otherwise, run only exact matches.
97 - if bench_kernels is None or name in bench_kernels:
98 - print(f"Running {name}")
99 - timers.append(bench_fn(label, sub_label, name, fn))
100 -
101 - return timers
102 -
103 -
104 -def bench_fp8(
105 - dtype: torch.dtype,
106 - m: int,
107 - k: int,
108 - n: int,
109 - label: str,
110 - sub_label: str,
111 - bench_kernels: list[str] | None = None,
112 -) -> Iterable[TMeasurement]:
113 - """Benchmark FP8-based kernels."""
114 - assert dtype == torch.float8_e4m3fn
115 - a, b = make_rand_tensors(torch.float8_e4m3fn, m, n, k)
116 - a_cont = a.contiguous()
117 - scale_a = torch.tensor(1.0, device="cuda", dtype=torch.float32)
118 - scale_b = torch.tensor(1.0, device="cuda", dtype=torch.float32)
119 -
120 - block_scale_a = torch.rand((m, cdiv(k, 128)), device="cuda", dtype=torch.float32)
121 - block_scale_b = torch.rand(
122 - cdiv(k, 128), cdiv(n, 128), device="cuda", dtype=torch.float32
123 - )
124 - block_scale_a_M_major = block_scale_a.t().contiguous().t()
125 - block_scale_b_K_major = block_scale_b.t().contiguous().t()
126 - bias = torch.zeros((n,), device="cuda", dtype=torch.bfloat16)
127 -
128 - print(m, k, n)
129 -
130 - bench_fns = {
131 - "pytorch_bf16_bf16_bf16_matmul-no-scales": lambda: torch.mm(
132 - a.to(dtype=torch.bfloat16), b.to(dtype=torch.bfloat16)
133 - ),
134 - "pytorch_fp16_fp16_fp16_matmul-no-scales": lambda: torch.mm(
135 - a.to(dtype=torch.float16), b.to(dtype=torch.float16)
136 - ),
137 - "pytorch_fp8_fp8_fp16_scaled_mm": lambda: torch._scaled_mm(
138 - a, b, scale_a, scale_b, out_dtype=torch.float16
139 - ),
140 - "pytorch_fp8_fp8_fp16_scaled_mm_fast_accum": lambda: torch._scaled_mm(
141 - a, b, scale_a, scale_b, out_dtype=torch.float16, use_fast_accum=True
142 - ),
143 - "pytorch_fp8_fp8_bf16_scaled_mm": lambda: torch._scaled_mm(
144 - a, b, scale_a, scale_b, out_dtype=torch.bfloat16
145 - ),
146 - "pytorch_fp8_fp8_bf16_scaled_mm_fast_accum": lambda: torch._scaled_mm(
147 - a, b, scale_a, scale_b, out_dtype=torch.bfloat16, use_fast_accum=True
148 - ),
149 - "cutlass_fp8_fp8_bf16_scaled_mm": lambda: ops.cutlass_scaled_mm(
150 - a, b, scale_a, scale_b, torch.bfloat16
151 - ),
152 - "cutlass_fp8_fp8_fp16_scaled_mm": lambda: ops.cutlass_scaled_mm(
153 - a, b, scale_a, scale_b, torch.float16
154 - ),
155 - "cutlass_fp8_fp8_bf16_scaled_mm_bias": lambda: ops.cutlass_scaled_mm(
156 - a, b, scale_a, scale_b, torch.bfloat16, bias
157 - ),
158 - "cutlass_fp8_fp8_fp16_scaled_mm_bias": lambda: ops.cutlass_scaled_mm(
159 - a, b, scale_a, scale_b, torch.float16, bias.to(dtype=torch.float16)
160 - ),
161 - "triton_fp8_fp8_fp16_scaled_mm_blockwise": lambda: w8a8_triton_block_scaled_mm(
162 - a_cont, b.t(), block_scale_a, block_scale_b.t(), (128, 128)
163 - ),
164 - "cutlass_fp8_fp8_fp16_scaled_mm_blockwise": lambda: ops.cutlass_scaled_mm(
165 - a, b, block_scale_a_M_major, block_scale_b_K_major, torch.float16
166 - ),
167 - }
168 -
169 - timers = []
170 - for name, fn in bench_fns.items():
171 - # If bench_kernels is None, run all. Otherwise, run only exact matches.
172 - if bench_kernels is None or name in bench_kernels:
173 - print(f"Running {name}")
174 - timers.append(bench_fn(label, sub_label, name, fn))
175 -
176 - return timers
177 -
178 -
179 -def bench(
180 - dtype: torch.dtype,
181 - m: int,
182 - k: int,
183 - n: int,
184 - label: str,
185 - sub_label: str,
186 - bench_kernels: list[str] | None = None,
187 -) -> Iterable[TMeasurement]:
188 - if dtype == torch.int8:
189 - return bench_int8(dtype, m, k, n, label, sub_label, bench_kernels)
190 - if dtype == torch.float8_e4m3fn:
191 - return bench_fp8(dtype, m, k, n, label, sub_label, bench_kernels)
192 - raise ValueError("unsupported type")
193 -
194 -
195 -# runner
196 -def print_timers(timers: Iterable[TMeasurement]):
197 - compare = TBenchmark.Compare(timers)
198 - compare.print()
199 -
200 -
201 -def run(
202 - dtype: torch.dtype,
203 - MKNs: Iterable[tuple[int, int, int]],
204 - bench_kernels: list[str] | None = None,
205 -) -> Iterable[TMeasurement]:
206 - results = []
207 - for m, k, n in MKNs:
208 - timers = bench(
209 - dtype,
210 - m,
211 - k,
212 - n,
213 - f"scaled-{dtype}-gemm",
214 - f"MKN=({m}x{k}x{n})",
215 - bench_kernels=bench_kernels,
216 - )
217 - print_timers(timers)
218 - results.extend(timers)
219 - return results
220 -
221 -
222 -def make_output(
223 - data: Iterable[TMeasurement],
224 - MKNs: Iterable[tuple[int, int, int]],
225 - base_description: str,
226 - timestamp=None,
227 -):
228 - print(f"== All Results {base_description} ====")
229 - print_timers(data)
230 -
231 - # pickle all the results
232 - timestamp = int(time.time()) if timestamp is None else timestamp
233 - with open(f"{base_description}-{timestamp}.pkl", "wb") as f:
234 - pkl.dump(data, f)
235 -
236 -
237 -def run_square_bench(args):
238 - dim_sizes = list(range(args.dim_start, args.dim_end + 1, args.dim_increment))
239 - MKNs = list(zip(dim_sizes, dim_sizes, dim_sizes))
240 - data = run(args.dtype, MKNs, bench_kernels=args.kernels)
241 - make_output(data, MKNs, f"square_bench-{args.dtype}")
242 -
243 -
244 -def run_range_bench(args):
245 - dim_sizes = list(range(args.dim_start, args.dim_end, args.dim_increment))
246 - n = len(dim_sizes)
247 - Ms = [args.m_constant] * n if args.m_constant is not None else dim_sizes
248 - Ks = [args.k_constant] * n if args.k_constant is not None else dim_sizes
249 - Ns = [args.n_constant] * n if args.n_constant is not None else dim_sizes
250 - MKNs = list(zip(Ms, Ks, Ns))
251 - data = run(args.dtype, MKNs, bench_kernels=args.kernels)
252 - make_output(data, MKNs, f"range_bench-{args.dtype}")
253 -
254 -
255 -def run_model_bench(args):
256 - print("Benchmarking models:")
257 - for i, model in enumerate(args.models):
258 - print(f"[{i}] {model}")
259 -
260 - def model_shapes(model_name: str, tp_size: int) -> list[tuple[int, int]]:
261 - KNs = []
262 - for KN, tp_split_dim in copy.deepcopy(WEIGHT_SHAPES[model_name]):
263 - KN[tp_split_dim] = KN[tp_split_dim] // tp_size
264 - KNs.append(KN)
265 - return KNs
266 -
267 - model_bench_data = []
268 - models_tps = list(itertools.product(args.models, args.tp_sizes))
269 - for model, tp_size in models_tps:
270 - Ms = args.batch_sizes
271 - KNs = model_shapes(model, tp_size)
272 - MKNs = []
273 - for m in Ms:
274 - for k, n in KNs:
275 - MKNs.append((m, k, n))
276 -
277 - data = run(args.dtype, MKNs, bench_kernels=args.kernels)
278 - model_bench_data.append(data)
279 -
280 - # Print all results
281 - for data, model_tp in zip(model_bench_data, models_tps):
282 - model, tp_size = model_tp
283 - print(f"== Results {args.dtype} {model}-TP{tp_size} ====")
284 - print_timers(data)
285 -
286 - timestamp = int(time.time())
287 -
288 - all_data = []
289 - for d in model_bench_data:
290 - all_data.extend(d)
291 - # pickle all data
292 - with open(f"model_bench-{args.dtype}-{timestamp}.pkl", "wb") as f:
293 - pkl.dump(all_data, f)
294 -
295 -
296 -if __name__ == "__main__":
297 -
298 - def to_torch_dtype(dt):
299 - if dt == "int8":
300 - return torch.int8
301 - if dt == "fp8":
302 - return torch.float8_e4m3fn
303 - raise ValueError("unsupported dtype")
304 -
305 - parser = FlexibleArgumentParser(
306 - description="""
307 -Benchmark Cutlass GEMM.
308 -
309 - To run square GEMMs:
310 - python3 ./benchmarks/cutlass_benchmarks/w8a8_benchmarks.py --dtype fp8 square_bench --dim-start 128 --dim-end 512 --dim-increment 64
311 -
312 - To run constant N and K and sweep M:
313 - python3 ./benchmarks/cutlass_benchmarks/w8a8_benchmarks.py --dtype fp8 range_bench --dim-start 128 --dim-end 512 --dim-increment 64 --n-constant 16384 --k-constant 16384
314 -
315 - To run dimensions from a model:
316 - python3 ./benchmarks/cutlass_benchmarks/w8a8_benchmarks.py --dtype fp8 model_bench --models meta-llama/Llama-2-7b-hf --batch-sizes 16 --tp-sizes 1
317 -
318 - Output:
319 - - a .pkl file, that is a list of raw torch.benchmark.utils.Measurements for the pytorch and cutlass implementations for the various GEMMs.
320 - """, # noqa: E501
321 - formatter_class=argparse.RawTextHelpFormatter,
322 - )
323 -
324 - parser.add_argument(
325 - "--dtype",
326 - type=to_torch_dtype,
327 - required=True,
328 - help="Available options are ['int8', 'fp8']",
329 - )
330 - parser.add_argument(
331 - "--kernels",
332 - nargs="+",
333 - type=str,
334 - default=None,
335 - help="Exact names of the kernels to benchmark. If not set, runs all kernels.",
336 - )
337 -
338 - subparsers = parser.add_subparsers(dest="cmd")
339 -
340 - square_parser = subparsers.add_parser("square_bench")
341 - square_parser.add_argument("--dim-start", type=int, required=True)
342 - square_parser.add_argument("--dim-end", type=int, required=True)
343 - square_parser.add_argument("--dim-increment", type=int, required=True)
344 - square_parser.set_defaults(func=run_square_bench)
345 -
346 - range_parser = subparsers.add_parser("range_bench")
347 - range_parser.add_argument("--dim-start", type=int, required=True)
348 - range_parser.add_argument("--dim-end", type=int, required=True)
349 - range_parser.add_argument("--dim-increment", type=int, required=True)
350 - range_parser.add_argument("--m-constant", type=int, default=None)
351 - range_parser.add_argument("--n-constant", type=int, default=None)
352 - range_parser.add_argument("--k-constant", type=int, default=None)
353 - range_parser.set_defaults(func=run_range_bench)
354 -
355 - model_parser = subparsers.add_parser("model_bench")
356 - model_parser.add_argument(
357 - "--models",
358 - nargs="+",
359 - type=str,
360 - default=DEFAULT_MODELS,
361 - choices=WEIGHT_SHAPES.keys(),
362 - )
363 - model_parser.add_argument(
364 - "--tp-sizes", nargs="+", type=int, default=DEFAULT_TP_SIZES
365 - )
366 - model_parser.add_argument(
367 - "--batch-sizes", nargs="+", type=int, default=DEFAULT_BATCH_SIZES
368 - )
369 - model_parser.set_defaults(func=run_model_bench)
370 -
371 - args = parser.parse_args()
372 - args.func(args)
benchmarks/cutlass_benchmarks/weight_shapes.py deleted
-46
@@ -1,46 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -# Weight Shapes are in the format
5 -# ([K, N], TP_SPLIT_DIM)
6 -# Example:
7 -# A shape of ([14336, 4096], 0) indicates the following GEMM shape,
8 -# - TP1 : K = 14336, N = 4096
9 -# - TP2 : K = 7168, N = 4096
10 -# A shape of ([4096, 6144], 1) indicates the following GEMM shape,
11 -# - TP1 : K = 4096, N = 6144
12 -# - TP4 : K = 4096, N = 1536
13 -
14 -# TP1 shapes
15 -WEIGHT_SHAPES = {
16 - "mistralai/Mistral-7B-v0.1": [
17 - ([4096, 6144], 1),
18 - ([4096, 4096], 0),
19 - ([4096, 28672], 1),
20 - ([14336, 4096], 0),
21 - ],
22 - "meta-llama/Llama-2-7b-hf": [
23 - ([4096, 12288], 1),
24 - ([4096, 4096], 0),
25 - ([4096, 22016], 1),
26 - ([11008, 4096], 0),
27 - ],
28 - "meta-llama/Llama-3-8b": [
29 - ([4096, 6144], 1),
30 - ([4096, 4096], 0),
31 - ([4096, 28672], 1),
32 - ([14336, 4096], 0),
33 - ],
34 - "meta-llama/Llama-2-13b-hf": [
35 - ([5120, 15360], 1),
36 - ([5120, 5120], 0),
37 - ([5120, 27648], 1),
38 - ([13824, 5120], 0),
39 - ],
40 - "meta-llama/Llama-2-70b-hf": [
41 - ([8192, 10240], 1),
42 - ([8192, 8192], 0),
43 - ([8192, 57344], 1),
44 - ([28672, 8192], 0),
45 - ],
46 -}
benchmarks/kernels/benchmark_rmsnorm.py deleted
-255
@@ -1,255 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -import itertools
5 -
6 -import torch
7 -from flashinfer.norm import fused_add_rmsnorm, rmsnorm
8 -from torch import nn
9 -
10 -from vllm import _custom_ops as vllm_ops
11 -from vllm.triton_utils import triton
12 -
13 -
14 -class HuggingFaceRMSNorm(nn.Module):
15 - def __init__(self, hidden_size: int, eps: float = 1e-6) -> None:
16 - super().__init__()
17 - self.weight = nn.Parameter(torch.ones(hidden_size))
18 - self.variance_epsilon = eps
19 -
20 - def forward(
21 - self,
22 - x: torch.Tensor,
23 - residual: torch.Tensor | None = None,
24 - ) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
25 - orig_dtype = x.dtype
26 - x = x.to(torch.float32)
27 - if residual is not None:
28 - x = x + residual.to(torch.float32)
29 - residual = x.to(orig_dtype)
30 -
31 - variance = x.pow(2).mean(dim=-1, keepdim=True)
32 - x = x * torch.rsqrt(variance + self.variance_epsilon)
33 - x = x.to(orig_dtype) * self.weight
34 - if residual is None:
35 - return x
36 - else:
37 - return x, residual
38 -
39 -
40 -def rmsnorm_naive(
41 - x: torch.Tensor,
42 - weight: torch.Tensor,
43 - residual: torch.Tensor | None = None,
44 - eps: float = 1e-6,
45 -):
46 - naive_norm = HuggingFaceRMSNorm(x.shape[-1], eps=eps)
47 - naive_norm.weight = nn.Parameter(weight)
48 - naive_norm = naive_norm.to(x.device)
49 -
50 - orig_shape = x.shape
51 - x = x.view(-1, x.shape[-1])
52 - if residual is not None:
53 - residual = residual.view(-1, residual.shape[-1])
54 -
55 - output = naive_norm(x, residual)
56 -
57 - if isinstance(output, tuple):
58 - output = (output[0].view(orig_shape), output[1].view(orig_shape))
59 - else:
60 - output = output.view(orig_shape)
61 - return output
62 -
63 -
64 -def rmsnorm_flashinfer(
65 - x: torch.Tensor,
66 - weight: torch.Tensor,
67 - residual: torch.Tensor | None = None,
68 - eps: float = 1e-6,
69 -):
70 - orig_shape = x.shape
71 - x = x.view(-1, x.shape[-1])
72 - if residual is not None:
73 - residual = residual.view(-1, residual.shape[-1])
74 -
75 - if residual is not None:
76 - fused_add_rmsnorm(x, residual, weight, eps)
77 - output = (x, residual)
78 - else:
79 - output = rmsnorm(x, weight, eps)
80 -
81 - if isinstance(output, tuple):
82 - output = (output[0].view(orig_shape), output[1].view(orig_shape))
83 - else:
84 - output = output.view(orig_shape)
85 - return output
86 -
87 -
88 -def rmsnorm_vllm(
89 - x: torch.Tensor,
90 - weight: torch.Tensor,
91 - residual: torch.Tensor | None = None,
92 - eps: float = 1e-6,
93 -):
94 - orig_shape = x.shape
95 - x = x.view(-1, x.shape[-1])
96 - if residual is not None:
97 - residual = residual.view(-1, residual.shape[-1])
98 -
99 - if residual is not None:
100 - vllm_ops.fused_add_rms_norm(x, residual, weight, eps)
101 - output = (x, residual)
102 - else:
103 - out = torch.empty_like(x)
104 - vllm_ops.rms_norm(out, x, weight, eps)
105 - output = out
106 -
107 - if isinstance(output, tuple):
108 - output = (output[0].view(orig_shape), output[1].view(orig_shape))
109 - else:
110 - output = output.view(orig_shape)
111 - return output
112 -
113 -
114 -def calculate_diff(batch_size, seq_len, hidden_size, use_residual=True):
115 - dtype = torch.bfloat16
116 - x = torch.randn(batch_size, seq_len, hidden_size, dtype=dtype, device="cuda")
117 - weight = torch.ones(hidden_size, dtype=dtype, device="cuda")
118 - residual = torch.randn_like(x) if use_residual else None
119 -
120 - output_naive = rmsnorm_naive(
121 - x.clone(), weight, residual.clone() if residual is not None else None
122 - )
123 - output_flashinfer = rmsnorm_flashinfer(
124 - x.clone(), weight, residual.clone() if residual is not None else None
125 - )
126 - output_vllm = rmsnorm_vllm(
127 - x.clone(), weight, residual.clone() if residual is not None else None
128 - )
129 -
130 - if use_residual:
131 - output_naive = output_naive[0]
132 - output_flashinfer = output_flashinfer[0]
133 - output_vllm = output_vllm[0]
134 -
135 - print(f"Naive output={output_naive}")
136 - print(f"FlashInfer output={output_flashinfer}")
137 - print(f"vLLM output={output_vllm}")
138 -
139 - if torch.allclose(
140 - output_naive, output_flashinfer, atol=1e-2, rtol=1e-2
141 - ) and torch.allclose(output_naive, output_vllm, atol=1e-2, rtol=1e-2):
142 - print("✅ All implementations match")
143 - else:
144 - print("❌ Implementations differ")
145 -
146 -
147 -batch_size_range = [2**i for i in range(0, 7, 2)]
148 -seq_length_range = [2**i for i in range(6, 11, 1)]
149 -head_num_range = [32, 48]
150 -configs = list(itertools.product(head_num_range, batch_size_range, seq_length_range))
151 -
152 -
153 -def get_benchmark(use_residual):
154 - @triton.testing.perf_report(
155 - triton.testing.Benchmark(
156 - x_names=["head_num", "batch_size", "seq_len"],
157 - x_vals=[list(_) for _ in configs],
158 - line_arg="provider",
159 - line_vals=["huggingface", "flashinfer", "vllm"],
160 - line_names=["HuggingFace", "FlashInfer", "vLLM"],
161 - styles=[("blue", "-"), ("green", "-"), ("red", "-")],
162 - ylabel="us",
163 - plot_name=f"rmsnorm-perf-{'with' if use_residual else 'without'}-residual",
164 - args={},
165 - )
166 - )
167 - def benchmark(head_num, batch_size, seq_len, provider):
168 - dtype = torch.bfloat16
169 - hidden_size = head_num * 128 # assuming head_dim = 128
170 -
171 - x = torch.randn(batch_size, seq_len, hidden_size, dtype=dtype, device="cuda")
172 - weight = torch.ones(hidden_size, dtype=dtype, device="cuda")
173 - residual = torch.randn_like(x) if use_residual else None
174 -
175 - quantiles = [0.5, 0.2, 0.8]
176 -
177 - if provider == "huggingface":
178 - ms, min_ms, max_ms = triton.testing.do_bench(
179 - lambda: rmsnorm_naive(
180 - x.clone(),
181 - weight,
182 - residual.clone() if residual is not None else None,
183 - ),
184 - quantiles=quantiles,
185 - )
186 - elif provider == "flashinfer":
187 - ms, min_ms, max_ms = triton.testing.do_bench(
188 - lambda: rmsnorm_flashinfer(
189 - x.clone(),
190 - weight,
191 - residual.clone() if residual is not None else None,
192 - ),
193 - quantiles=quantiles,
194 - )
195 - else:
196 - ms, min_ms, max_ms = triton.testing.do_bench(
197 - lambda: rmsnorm_vllm(
198 - x.clone(),
199 - weight,
200 - residual.clone() if residual is not None else None,
201 - ),
202 - quantiles=quantiles,
203 - )
204 -
205 - return 1000 * ms, 1000 * max_ms, 1000 * min_ms
206 -
207 - return benchmark
208 -
209 -
210 -if __name__ == "__main__":
211 - import argparse
212 -
213 - parser = argparse.ArgumentParser()
214 - parser.add_argument(
215 - "--batch-size",
216 - type=int,
217 - default=4,
218 - help="Batch size",
219 - )
220 - parser.add_argument(
221 - "--seq-len",
222 - type=int,
223 - default=128,
224 - help="Sequence length",
225 - )
226 - parser.add_argument(
227 - "--hidden-size",
228 - type=int,
229 - default=4096,
230 - help="Hidden size (2nd dimension) of the sequence",
231 - )
232 - parser.add_argument(
233 - "--use-residual", action="store_true", help="Whether to use residual connection"
234 - )
235 - parser.add_argument(
236 - "--save-path",
237 - type=str,
238 - default="./configs/rmsnorm/",
239 - help="Path to save rmsnorm benchmark results",
240 - )
241 -
242 - args = parser.parse_args()
243 -
244 - # Run correctness test
245 - calculate_diff(
246 - batch_size=args.batch_size,
247 - seq_len=args.seq_len,
248 - hidden_size=args.hidden_size,
249 - use_residual=args.use_residual,
250 - )
251 -
252 - # Get the benchmark function with proper use_residual setting
253 - benchmark = get_benchmark(args.use_residual)
254 - # Run performance benchmark
255 - benchmark.run(print_data=True, save_path=args.save_path)
benchmarks/kernels/ir/shapes.py
+3 -2
@@ -18,10 +18,11 @@ COMMON_HIDDEN_SIZES = [
18 # Each entry maps an op name to a list of kwarg dicts that will be passed
19 # to that op's registered input generator via op.generate_inputs(**kwargs).
20 SHAPE_CONFIGS: dict[str, list[dict]] = {
21 - "rms_norm": [
21 + op_name: [
22 {"num_tokens": n, "hidden_size": d, "dtype": dtype}
23 for dtype in [torch.float16, torch.bfloat16, torch.float32]
24 for d in COMMON_HIDDEN_SIZES
25 for n in NUM_TOKENS
26 - ],
26 + ]
27 + for op_name in ("rms_norm", "fused_add_rms_norm")
28 }
benchmarks/overheads/benchmark_hashing.py deleted
-64
@@ -1,64 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -import cProfile
5 -import pstats
6 -
7 -from vllm import LLM, SamplingParams
8 -from vllm.utils.argparse_utils import FlexibleArgumentParser
9 -
10 -# A very long prompt, total number of tokens is about 15k.
11 -LONG_PROMPT = ["You are an expert in large language models, aren't you?"] * 1000
12 -LONG_PROMPT = " ".join(LONG_PROMPT)
13 -
14 -
15 -def main(args):
16 - llm = LLM(
17 - model=args.model,
18 - enforce_eager=True,
19 - enable_prefix_caching=True,
20 - tensor_parallel_size=args.tensor_parallel_size,
21 - )
22 -
23 - sampling_params = SamplingParams(temperature=0, max_tokens=args.output_len)
24 - profiler = cProfile.Profile()
25 -
26 - print("------warm up------")
27 - for i in range(3):
28 - output = llm.generate(LONG_PROMPT, sampling_params)
29 - print(output[0].outputs[0].text)
30 -
31 - print("------start generating------")
32 - for i in range(3):
33 - profiler.runctx(
34 - "llm.generate(LONG_PROMPT, sampling_params)", globals(), locals()
35 - )
36 -
37 - # analyze the runtime of hashing function
38 - stats = pstats.Stats(profiler)
39 - stats.sort_stats("cumulative")
40 - total_time = 0
41 - total_calls = 0
42 - for func in stats.stats:
43 - if "hash_of_block" in func[2]:
44 - total_time = stats.stats[func][3]
45 - total_calls = stats.stats[func][0]
46 - percentage = (total_time / stats.total_tt) * 100
47 - print(
48 - f"Hashing took {total_time:.2f} seconds,{percentage:.2f}% of the total runtime."
49 - )
50 -
51 -
52 -if __name__ == "__main__":
53 - parser = FlexibleArgumentParser(
54 - description="Benchmark the performance of hashing function in"
55 - "automatic prefix caching."
56 - )
57 - parser.add_argument("--model", type=str, default="lmsys/longchat-7b-16k")
58 - parser.add_argument("--tensor-parallel-size", "-tp", type=int, default=1)
59 - parser.add_argument("--output-len", type=int, default=10)
60 - parser.add_argument(
61 - "--enable-prefix-caching", action="store_true", help="enable prefix caching"
62 - )
63 - args = parser.parse_args()
64 - main(args)
tools/pre_commit/check_forbidden_imports.py
-2
@@ -60,8 +60,6 @@ CHECK_IMPORTS = {
60 "benchmarks/kernels/benchmark_lora.py",
61 "benchmarks/kernels/benchmark_machete.py",
62 "benchmarks/fused_kernels/layernorm_rms_benchmarks.py",
63 - "benchmarks/cutlass_benchmarks/w8a8_benchmarks.py",
64 - "benchmarks/cutlass_benchmarks/sparse_benchmarks.py",
63 # cloudpickle
64 "vllm/v1/executor/multiproc_executor.py",
65 "vllm/v1/executor/ray_executor.py",