├── web ├── apps │ ├── docs │ │ ├── content │ │ ├── postcss.config.js │ │ ├── mdx-components.js │ │ ├── next.config.ts │ │ ├── tsconfig.json │ │ ├── package.json │ │ ├── app │ │ │ ├── [[...mdxPath]] │ │ │ │ └── page.jsx │ │ │ └── layout.jsx │ │ └── gen_api_docs.sh │ └── web │ │ ├── .eslintrc.json │ │ ├── lib │ │ ├── schemas │ │ │ ├── index.ts │ │ │ └── model.ts │ │ ├── model-utils.ts │ │ └── utils.ts │ │ ├── app │ │ ├── icon.png │ │ ├── kernels │ │ │ └── [name] │ │ │ │ ├── solutions-types.ts │ │ │ │ ├── constraints.tsx │ │ │ │ ├── header.tsx │ │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── models │ │ │ ├── page.tsx │ │ │ └── [id] │ │ │ │ ├── page.tsx │ │ │ │ └── model-tabs.tsx │ │ ├── models.tsx │ │ ├── page.tsx │ │ └── leaderboard │ │ │ └── section.tsx │ │ ├── postcss.config.js │ │ ├── components │ │ ├── layout │ │ │ ├── footer.tsx │ │ │ └── header.tsx │ │ ├── fast-p-label.tsx │ │ └── model-card.tsx │ │ ├── microfrontends.json.disabled │ │ ├── middleware.ts │ │ ├── tsconfig.json │ │ ├── package.json │ │ ├── next.config.ts │ │ └── data │ │ └── baselines.ts ├── pnpm-workspace.yaml ├── packages │ ├── ui │ │ ├── src │ │ │ ├── brand │ │ │ │ ├── fib_logo.png │ │ │ │ ├── fib_mark.png │ │ │ │ ├── fib-black-bg.png │ │ │ │ ├── fib-white-bg.png │ │ │ │ └── Logo.tsx │ │ │ ├── providers │ │ │ │ └── Providers.tsx │ │ │ ├── index.ts │ │ │ └── components │ │ │ │ ├── label.tsx │ │ │ │ ├── textarea.tsx │ │ │ │ ├── input.tsx │ │ │ │ ├── hover-card.tsx │ │ │ │ ├── badge.tsx │ │ │ │ ├── avatar.tsx │ │ │ │ ├── alert.tsx │ │ │ │ ├── progress-circle.tsx │ │ │ │ ├── button.tsx │ │ │ │ ├── tabs.tsx │ │ │ │ ├── card.tsx │ │ │ │ ├── site-footer.tsx │ │ │ │ ├── site-header.tsx │ │ │ │ ├── toaster.tsx │ │ │ │ └── table.tsx │ │ ├── tsconfig.json │ │ └── package.json │ ├── utils │ │ ├── src │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── package.json │ └── config │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── src │ │ └── index.ts ├── package.json ├── turbo.json ├── README.md └── .gitignore ├── flashinfer_bench ├── integration │ ├── __init__.py │ ├── flashinfer │ │ ├── adapters │ │ │ ├── __init__.py │ │ │ └── rmsnorm.py │ │ ├── __init__.py │ │ └── common.py │ ├── utils.py │ └── patch_manager.py ├── cli │ └── __init__.py ├── bench │ ├── __init__.py │ ├── evaluators │ │ ├── __init__.py │ │ ├── registry.py │ │ ├── utils.py │ │ └── evaluator.py │ ├── runner │ │ ├── __init__.py │ │ └── runner.py │ └── config.py ├── compile │ ├── builders │ │ ├── __init__.py │ │ └── triton_builder.py │ ├── __init__.py │ └── utils.py ├── apply │ ├── __init__.py │ ├── config.py │ └── key.py ├── data │ ├── utils.py │ ├── __init__.py │ └── workload.py ├── tracing │ ├── workload_entry.py │ ├── __init__.py │ └── builtin │ │ └── configs.py ├── logging.py ├── __init__.py └── env.py ├── tests ├── __init__.py ├── integration │ ├── samplemods │ │ ├── __init__.py │ │ └── pm_dummy.py │ ├── __init__.py │ ├── test_utils.py │ └── test_patch_manager.py ├── bench │ └── test_benchmark_config.py ├── conftest.py ├── test_logging.py ├── apply │ └── test_key.py └── compile │ ├── test_triton_builder.py │ ├── test_python_builder.py │ └── test_utils.py ├── NOTICE ├── .gitmodules ├── docs ├── api │ ├── _static │ │ └── brand │ │ │ ├── fib-dark.png │ │ │ └── fib-light.png │ ├── requirements.txt │ ├── rst │ │ ├── schema_traceset.md │ │ ├── schema_solution.md │ │ ├── schema_definition.md │ │ ├── schema_trace.md │ │ ├── schema_workload.md │ │ ├── apply.md │ │ ├── tracing.md │ │ ├── schema.md │ │ └── compile.md │ ├── index.md │ └── build_docs.sh ├── start │ ├── installation.mdx │ └── quick_start.mdx ├── op_type_schema │ ├── gemm.md │ ├── rmsnorm.md │ ├── gqa_ragged.md │ ├── sampling.md │ ├── moe.md │ ├── gqa_paged.md │ └── mla_paged.md ├── index.mdx └── flashinfer_trace │ └── flashinfer_trace.md ├── examples ├── res │ └── win_at_p_curve_gemm_o3_gpt-5.png └── kernel_generator │ ├── .env.example │ └── README.md ├── .yamlfmt ├── scripts └── linting.sh ├── .github └── workflows │ ├── linting.yaml │ ├── unit_test.yaml │ └── build-and-upload-pypi.yml ├── RELEASE.md ├── .gitignore ├── .pre-commit-config.yaml ├── licenses └── cutlass.LICENSE.txt ├── README.md ├── pyproject.toml └── CONTRIBUTING.md /web/apps/docs/content: -------------------------------------------------------------------------------- 1 | ../../../docs -------------------------------------------------------------------------------- /flashinfer_bench/integration/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Test package for flashinfer_bench.""" 2 | -------------------------------------------------------------------------------- /web/pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/*" 3 | - "packages/*" 4 | -------------------------------------------------------------------------------- /web/apps/web/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | FlashInfer-Bench 2 | 3 | Copyright (c) 2025 by FlashInfer-Bench Contributors 4 | -------------------------------------------------------------------------------- /flashinfer_bench/cli/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import cli 2 | 3 | __all__ = ["cli"] 4 | -------------------------------------------------------------------------------- /tests/integration/samplemods/__init__.py: -------------------------------------------------------------------------------- 1 | """Sample modules for integration tests.""" 2 | -------------------------------------------------------------------------------- /web/apps/web/lib/schemas/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./model" 2 | export * from "./trace" 3 | -------------------------------------------------------------------------------- /flashinfer_bench/integration/flashinfer/adapters/__init__.py: -------------------------------------------------------------------------------- 1 | """Adapters for flashinfer integration.""" 2 | -------------------------------------------------------------------------------- /tests/integration/__init__.py: -------------------------------------------------------------------------------- 1 | # Mark tests/integration as a package to allow 'tests.integration.*' imports 2 | -------------------------------------------------------------------------------- /web/apps/web/app/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flashinfer-ai/flashinfer-bench/HEAD/web/apps/web/app/icon.png -------------------------------------------------------------------------------- /web/apps/docs/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | '@tailwindcss/postcss': {}, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /web/apps/web/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | '@tailwindcss/postcss': {}, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/cutlass"] 2 | path = thirdparty/cutlass 3 | url = https://github.com/NVIDIA/cutlass 4 | -------------------------------------------------------------------------------- /docs/api/_static/brand/fib-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flashinfer-ai/flashinfer-bench/HEAD/docs/api/_static/brand/fib-dark.png -------------------------------------------------------------------------------- /docs/api/_static/brand/fib-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flashinfer-ai/flashinfer-bench/HEAD/docs/api/_static/brand/fib-light.png -------------------------------------------------------------------------------- /web/packages/ui/src/brand/fib_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flashinfer-ai/flashinfer-bench/HEAD/web/packages/ui/src/brand/fib_logo.png -------------------------------------------------------------------------------- /web/packages/ui/src/brand/fib_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flashinfer-ai/flashinfer-bench/HEAD/web/packages/ui/src/brand/fib_mark.png -------------------------------------------------------------------------------- /web/packages/ui/src/brand/fib-black-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flashinfer-ai/flashinfer-bench/HEAD/web/packages/ui/src/brand/fib-black-bg.png -------------------------------------------------------------------------------- /web/packages/ui/src/brand/fib-white-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flashinfer-ai/flashinfer-bench/HEAD/web/packages/ui/src/brand/fib-white-bg.png -------------------------------------------------------------------------------- /examples/res/win_at_p_curve_gemm_o3_gpt-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flashinfer-ai/flashinfer-bench/HEAD/examples/res/win_at_p_curve_gemm_o3_gpt-5.png -------------------------------------------------------------------------------- /web/apps/web/components/layout/footer.tsx: -------------------------------------------------------------------------------- 1 | import { SiteFooter } from "@flashinfer-bench/ui" 2 | 3 | export function Footer() { 4 | return 5 | } 6 | -------------------------------------------------------------------------------- /tests/integration/samplemods/pm_dummy.py: -------------------------------------------------------------------------------- 1 | class Foo: 2 | def instance_method(self, x, y=2): 3 | return x + y 4 | 5 | 6 | def module_function(a, b=3): 7 | return a * b 8 | -------------------------------------------------------------------------------- /docs/api/requirements.txt: -------------------------------------------------------------------------------- 1 | autodoc_pydantic>=2.1,<3 2 | myst-parser[linkify]>=4,<5 3 | setuptools-scm>=8 4 | shibuya 5 | sphinx==7.4.* 6 | sphinx-tabs>=3.4.7 7 | sphinx-toolbox 8 | tomli 9 | -------------------------------------------------------------------------------- /.yamlfmt: -------------------------------------------------------------------------------- 1 | formatter: 2 | indent: 2 3 | retain_line_breaks_single: true 4 | max_line_length: 100 5 | # avoid replacing newline with #magic___^_^___line 6 | scan_folded_as_literal: true 7 | -------------------------------------------------------------------------------- /flashinfer_bench/bench/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from .benchmark import Benchmark 4 | from .config import BenchmarkConfig 5 | 6 | __all__ = ["Benchmark", "BenchmarkConfig"] 7 | -------------------------------------------------------------------------------- /web/packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /docs/api/rst/schema_traceset.md: -------------------------------------------------------------------------------- 1 | # flashinfer_bench.data.TraceSet 2 | 3 | ```{eval-rst} 4 | .. currentmodule:: flashinfer_bench.data 5 | 6 | .. autoclass:: TraceSet 7 | :members: 8 | :exclude-members: __init__ 9 | ``` 10 | -------------------------------------------------------------------------------- /scripts/linting.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eo pipefail 3 | set -x 4 | echo "Linting..." 5 | 6 | # Check if ruff is available, if not install it 7 | if ! command -v ruff &> /dev/null; then 8 | echo "ruff not found, installing ruff..." && pip install ruff 9 | fi 10 | 11 | ruff check . --fix 12 | -------------------------------------------------------------------------------- /flashinfer_bench/bench/evaluators/__init__.py: -------------------------------------------------------------------------------- 1 | from .default import DefaultEvaluator 2 | from .lowbit import LowBitEvaluator 3 | from .registry import resolve_evaluator 4 | from .sampling import SamplingEvaluator 5 | 6 | __all__ = ["DefaultEvaluator", "LowBitEvaluator", "SamplingEvaluator", "resolve_evaluator"] 7 | -------------------------------------------------------------------------------- /docs/api/rst/schema_solution.md: -------------------------------------------------------------------------------- 1 | # flashinfer_bench.data.Solution 2 | 3 | ```{eval-rst} 4 | .. currentmodule:: flashinfer_bench.data 5 | 6 | .. autopydantic_model:: Solution 7 | 8 | .. autoclass:: SupportedLanguages 9 | :members: 10 | 11 | .. autopydantic_model:: SourceFile 12 | 13 | .. autopydantic_model:: BuildSpec 14 | ``` 15 | -------------------------------------------------------------------------------- /web/apps/docs/mdx-components.js: -------------------------------------------------------------------------------- 1 | import { useMDXComponents as getThemeComponents } from 'nextra-theme-docs' 2 | 3 | // Get the default MDX components 4 | const themeComponents = getThemeComponents() 5 | 6 | // Merge components 7 | export function useMDXComponents(components) { 8 | return { 9 | ...themeComponents, 10 | ...components 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /web/apps/web/components/layout/header.tsx: -------------------------------------------------------------------------------- 1 | import { SiteHeader } from "@flashinfer-bench/ui" 2 | import { docsBasePath } from "@flashinfer-bench/config" 3 | 4 | const NAV_ITEMS = [ 5 | { href: docsBasePath, label: "Docs", external: true }, 6 | { href: "/viewer", label: "Viewer" }, 7 | ] 8 | 9 | export function Header() { 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /web/packages/config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@flashinfer-bench/config", 3 | "version": "0.1.0", 4 | "private": true, 5 | "main": "src/index.ts", 6 | "types": "src/index.ts", 7 | "license": "UNLICENSED", 8 | "sideEffects": false, 9 | "exports": { 10 | ".": { 11 | "types": "./src/index.ts", 12 | "import": "./src/index.ts" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /flashinfer_bench/compile/builders/__init__.py: -------------------------------------------------------------------------------- 1 | """Concrete builder implementations for different languages and build systems.""" 2 | 3 | from .python_builder import PythonBuilder 4 | from .torch_builder import TorchBuilder 5 | from .triton_builder import TritonBuilder 6 | from .tvm_ffi_builder import TVMFFIBuilder 7 | 8 | __all__ = ["TorchBuilder", "PythonBuilder", "TritonBuilder", "TVMFFIBuilder"] 9 | -------------------------------------------------------------------------------- /docs/api/rst/schema_definition.md: -------------------------------------------------------------------------------- 1 | # flashinfer_bench.data.Definition 2 | 3 | ```{eval-rst} 4 | .. currentmodule:: flashinfer_bench.data 5 | 6 | .. autopydantic_model:: Definition 7 | 8 | .. autopydantic_model:: AxisConst 9 | 10 | .. autopydantic_model:: AxisVar 11 | 12 | .. autopydantic_model:: TensorSpec 13 | 14 | .. autoclass:: flashinfer_bench.data.definition.DType 15 | :members: 16 | ``` 17 | -------------------------------------------------------------------------------- /web/packages/config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": false, 4 | "declaration": false, 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "Bundler", 8 | "jsx": "preserve", 9 | "target": "ES2022", 10 | "strict": true, 11 | "noEmit": true, 12 | "isolatedModules": true 13 | }, 14 | "include": ["src/**/*"] 15 | } 16 | -------------------------------------------------------------------------------- /web/packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": false, 4 | "declaration": false, 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "Bundler", 8 | "jsx": "preserve", 9 | "target": "ES2022", 10 | "strict": true, 11 | "noEmit": true, 12 | "isolatedModules": true 13 | }, 14 | "include": ["src/**/*"] 15 | } 16 | -------------------------------------------------------------------------------- /flashinfer_bench/apply/__init__.py: -------------------------------------------------------------------------------- 1 | from .apply_api import apply, disable_apply, enable_apply 2 | from .config import ApplyConfig 3 | from .runtime import ApplyRuntime, get_apply_runtime, set_apply_runtime 4 | 5 | __all__ = [ 6 | "apply", 7 | "disable_apply", 8 | "enable_apply", 9 | "get_apply_runtime", 10 | "set_apply_runtime", 11 | "ApplyConfig", 12 | "ApplyRuntime", 13 | ] 14 | -------------------------------------------------------------------------------- /docs/api/rst/schema_trace.md: -------------------------------------------------------------------------------- 1 | # flashinfer_bench.data.Trace 2 | 3 | ```{eval-rst} 4 | .. currentmodule:: flashinfer_bench.data 5 | 6 | .. autopydantic_model:: Trace 7 | 8 | .. autopydantic_model:: Correctness 9 | 10 | .. autopydantic_model:: Performance 11 | 12 | .. autopydantic_model:: Environment 13 | 14 | .. autoclass:: EvaluationStatus 15 | :members: 16 | 17 | .. autopydantic_model:: Evaluation 18 | ``` 19 | -------------------------------------------------------------------------------- /web/apps/docs/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from 'next' 2 | import nextra from 'nextra' 3 | 4 | const withNextra = nextra({}) 5 | 6 | const config: NextConfig = { 7 | reactStrictMode: true, 8 | basePath: '/docs', 9 | transpilePackages: [ 10 | '@flashinfer-bench/ui', 11 | '@flashinfer-bench/utils', 12 | '@flashinfer-bench/config', 13 | ], 14 | } 15 | 16 | export default withNextra(config) 17 | -------------------------------------------------------------------------------- /docs/api/rst/schema_workload.md: -------------------------------------------------------------------------------- 1 | # flashinfer_bench.data.Workload 2 | 3 | ```{eval-rst} 4 | .. currentmodule:: flashinfer_bench.data 5 | 6 | .. autopydantic_model:: Workload 7 | 8 | .. autopydantic_model:: RandomInput 9 | 10 | .. autopydantic_model:: ScalarInput 11 | 12 | .. autopydantic_model:: SafetensorsInput 13 | 14 | .. autodata:: InputSpec 15 | 16 | Union type representing all possible input specification types. 17 | ``` 18 | -------------------------------------------------------------------------------- /flashinfer_bench/bench/runner/__init__.py: -------------------------------------------------------------------------------- 1 | from .isolated_runner import IsolatedRunner 2 | from .persistent_runner import PersistentRunner 3 | from .runner import BaselineHandle, DeviceBaseline, RunnerError, RunnerFatalError 4 | 5 | __all__ = [ 6 | # General Runner 7 | "BaselineHandle", 8 | "DeviceBaseline", 9 | "RunnerError", 10 | "RunnerFatalError", 11 | # Specialized Runners 12 | "IsolatedRunner", 13 | "PersistentRunner", 14 | ] 15 | -------------------------------------------------------------------------------- /web/packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@flashinfer-bench/utils", 3 | "version": "0.1.0", 4 | "private": true, 5 | "main": "src/index.ts", 6 | "types": "src/index.ts", 7 | "license": "UNLICENSED", 8 | "sideEffects": false, 9 | "exports": { 10 | ".": { 11 | "types": "./src/index.ts", 12 | "import": "./src/index.ts" 13 | } 14 | }, 15 | "dependencies": { 16 | "clsx": "^2.1.1", 17 | "tailwind-merge": "^3.3.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /docs/api/rst/apply.md: -------------------------------------------------------------------------------- 1 | # flashinfer_bench.apply 2 | 3 | `flashinfer_bench.apply` provides a tool that meets two needs: 4 | 5 | 1. **Apply** best-performing one from FlashInfer Trace database to the LLM engine 6 | 2. **Trace** the kernel in the LLM engine and dump its input as FlashInfer Trace's workload format 7 | 8 | ```{eval-rst} 9 | .. currentmodule:: flashinfer_bench 10 | 11 | .. autofunction:: apply 12 | 13 | .. autofunction:: enable_apply 14 | 15 | .. autofunction:: disable_apply 16 | ``` 17 | -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flashinfer-bench", 3 | "private": true, 4 | "scripts": { 5 | "dev": "turbo run dev", 6 | "build": "turbo run build", 7 | "lint": "turbo run lint", 8 | "format": "prettier --write \"**/*.{ts,tsx,md}\"" 9 | }, 10 | "devDependencies": { 11 | "eslint": "^8", 12 | "eslint-config-custom": "^0.0.0", 13 | "prettier": "^3.6.2", 14 | "turbo": "^2.5.4" 15 | }, 16 | "packageManager": "pnpm@10.14.0", 17 | "engines": { 18 | "node": ">=22" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /web/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "globalEnv": [ 4 | "FLASHINFER_TRACE_PATH" 5 | ], 6 | "globalDependencies": ["**/.env.*local"], 7 | "tasks": { 8 | "build": { 9 | "dependsOn": ["^build"], 10 | "outputs": [".next/**", "!.next/cache/**", "public/docs/**"] 11 | }, 12 | "dev": { 13 | "cache": false, 14 | "persistent": true 15 | }, 16 | "lint": {}, 17 | "type-check": { 18 | "dependsOn": ["^build"] 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/linting.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | pull_request: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | linting: 10 | name: Pre-check on Ubuntu-latest 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | with: 16 | submodules: recursive 17 | 18 | - name: Pre-commit 19 | uses: pre-commit/action@v3.0.1 20 | 21 | - name: Linting 22 | run: | 23 | ./scripts/linting.sh 24 | -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | # FlashInfer Hub 2 | 3 | Community-driven ecosystem for high-performance kernels. 4 | 5 | ## Getting Started 6 | 7 | 1. Install dependencies: 8 | ```bash 9 | pnpm install 10 | ``` 11 | 12 | 2. Start the development server: 13 | ```bash 14 | pnpm dev 15 | ``` 16 | 17 | 3. Open [http://localhost:3000](http://localhost:3000) in your browser. 18 | 19 | ## Environment Variables 20 | 21 | Create a `.env.local` file in `apps/web/` with: 22 | 23 | ## Project Structure 24 | 25 | - `apps/web/` - Next.js web application 26 | -------------------------------------------------------------------------------- /examples/kernel_generator/.env.example: -------------------------------------------------------------------------------- 1 | # API Configuration 2 | # Copy this file to .env and fill in your actual API keys and URLs 3 | # Choose API Configuration based on model used by KernelGenerator 4 | 5 | # OpenAI API Configuration 6 | LLM_API_KEY=your_openai_api_key_here 7 | 8 | # Claude API Configuration 9 | LLM_API_KEY=your_claude_api_key_here 10 | BASE_URL=https://api.anthropic.com/v1/ 11 | 12 | # Gemini API Configuration 13 | LLM_API_KEY=your_gemini_api_key_here 14 | BASE_URL=https://generativelanguage.googleapis.com/v1beta/ 15 | -------------------------------------------------------------------------------- /web/apps/web/microfrontends.json.disabled: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://openapi.vercel.sh/microfrontends.json", 3 | "applications": { 4 | "flashinfer-bench": { 5 | "packageName": "@flashinfer-bench/web", 6 | "development": { 7 | "fallback": "bench.flashinfer.ai" 8 | } 9 | }, 10 | "flashinfer-bench-docs": { 11 | "packageName": "@flashinfer-bench/docs", 12 | "routing": [ 13 | { 14 | "paths": ["/docs", "/docs/:path*"] 15 | } 16 | ] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /flashinfer_bench/data/utils.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | 3 | from pydantic import BaseModel, ConfigDict, Field 4 | 5 | NonEmptyString = Annotated[str, Field(min_length=1)] 6 | """Type alias for non-empty strings with minimum length of 1.""" 7 | 8 | NonNegativeInt = Annotated[int, Field(ge=0)] 9 | """Type alias for non-negative integers.""" 10 | 11 | 12 | class BaseModelWithDocstrings(BaseModel): 13 | """Base model with the attribute docstrings being extracted to the model JSON schema.""" 14 | 15 | model_config = ConfigDict(use_attribute_docstrings=True) 16 | -------------------------------------------------------------------------------- /web/apps/web/app/kernels/[name]/solutions-types.ts: -------------------------------------------------------------------------------- 1 | import type { CurvePoint } from "@/lib/analytics" 2 | 3 | export type CorrectnessStats = { 4 | total: number 5 | passed: number 6 | incorrect: number 7 | runtime_error: number 8 | other: number 9 | } 10 | 11 | export type CurvesPayload = { 12 | nWorkloads: number 13 | curves: Record 14 | correctness: Record 15 | } 16 | 17 | export type SolutionFiltersState = { 18 | languages: string[] 19 | authors: string[] 20 | targets: string[] 21 | search: string 22 | } 23 | -------------------------------------------------------------------------------- /web/apps/web/lib/model-utils.ts: -------------------------------------------------------------------------------- 1 | import { Model } from "./schemas" 2 | 3 | /** 4 | * Get children of a module 5 | */ 6 | export function getChildren(model: Model, moduleName: string): string[] { 7 | return Object.entries(model.modules) 8 | .filter(([_, module]) => module.parent === moduleName) 9 | .map(([name]) => name) 10 | } 11 | 12 | /** 13 | * Get root modules (modules with no parent) 14 | */ 15 | export function getRootModules(model: Model): string[] { 16 | return Object.entries(model.modules) 17 | .filter(([_, module]) => !module.parent) 18 | .map(([name]) => name) 19 | } 20 | -------------------------------------------------------------------------------- /web/packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": false, 4 | "declaration": false, 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "Bundler", 8 | "jsx": "preserve", 9 | "target": "ES2022", 10 | "strict": true, 11 | "noEmit": true, 12 | "isolatedModules": true, 13 | "types": ["react", "react-dom"], 14 | "baseUrl": ".", 15 | "paths": { 16 | "@flashinfer-bench/utils": ["../utils/src/index.ts"], 17 | "@flashinfer-bench/config": ["../config/src/index.ts"] 18 | } 19 | }, 20 | "include": ["src/**/*"] 21 | } 22 | -------------------------------------------------------------------------------- /web/apps/web/components/fast-p-label.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@flashinfer-bench/utils" 2 | 3 | export type FastPLabelProps = { 4 | className?: string 5 | value?: string | number 6 | } 7 | 8 | export function FastPLabel({ className, value }: FastPLabelProps) { 9 | const subscript = value !== undefined ? String(value) : "p" 10 | return ( 11 | 15 | fast 16 | {subscript} 17 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /web/apps/web/middleware.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server" 2 | import type { NextRequest } from "next/server" 3 | 4 | export function middleware(request: NextRequest) { 5 | // Allow all routes for the static leaderboard site 6 | return NextResponse.next() 7 | } 8 | 9 | export const config = { 10 | matcher: [ 11 | /* 12 | * Match all request paths except: 13 | * - _next/static (static files) 14 | * - _next/image (image optimization files) 15 | * - favicon.ico (favicon file) 16 | * - public files 17 | */ 18 | "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)", 19 | ], 20 | } 21 | -------------------------------------------------------------------------------- /web/packages/config/src/index.ts: -------------------------------------------------------------------------------- 1 | export const siteName = 'FlashInfer-Bench' 2 | export const siteDescription = 'AI for AI Infrastructure for Accelerating AI Deployment' 3 | 4 | export const links = { 5 | org: 'https://github.com/flashinfer-ai', 6 | siteRepo: 'https://github.com/flashinfer-ai/flashinfer-bench', 7 | docsRepositoryBase: 'https://github.com/flashinfer-ai/flashinfer-bench/tree/main/docs', 8 | } 9 | 10 | export const docsBasePath = '/docs' 11 | 12 | export const env = { 13 | docsOriginVar: 'DOCS_ORIGIN', 14 | } 15 | 16 | export function getDefaultMetadata() { 17 | return { 18 | title: siteName, 19 | description: siteDescription, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /docs/api/rst/tracing.md: -------------------------------------------------------------------------------- 1 | # flashinfer_bench.tracing 2 | 3 | `flashinfer_bench.tracing` provides tools for tracing kernel executions during LLM inference 4 | and collecting workload traces for the FlashInfer Trace database. This module enables: 5 | 6 | 1. **Workload Collection**: Capture kernel inputs and execution patterns during runtime 7 | 2. **Configurable Tracing**: Control what data to collect and how to deduplicate or filter traces 8 | 3. **Filter Policies**: Apply policies to reduce redundant traces and manage dataset size 9 | 10 | ```{eval-rst} 11 | .. currentmodule:: flashinfer_bench 12 | 13 | .. autofunction:: enable_tracing 14 | 15 | .. autofunction:: disable_tracing 16 | ``` 17 | -------------------------------------------------------------------------------- /web/packages/ui/src/providers/Providers.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { QueryClient, QueryClientProvider } from "@tanstack/react-query" 4 | import { ThemeProvider } from "next-themes" 5 | import { useState } from "react" 6 | 7 | export function Providers({ children }: { children: React.ReactNode }) { 8 | const [queryClient] = useState(() => new QueryClient()) 9 | 10 | return ( 11 | 12 | 18 | {children} 19 | 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /docs/start/installation.mdx: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Prerequisites 4 | 5 | - OS: Linux 6 | - Python: 3.10, 3.11, 3.12, 3.13 7 | 8 | ## Python Package (WIP) 9 | 10 | FlashInfer-Bench is available via pip: 11 | 12 | ```bash 13 | python3 -m pip install flashinfer-bench 14 | ``` 15 | 16 | ## Install from Source 17 | 18 | You may want to install FlashInfer-Bench from source code for development purposes. 19 | 20 | ```bash 21 | # Clone the FlashInfer-Bench repository 22 | git clone https://github.com/flashinfer-ai/flashinfer-bench.git 23 | 24 | # Install the Python package 25 | pip install -v -e . 26 | ``` 27 | 28 | ## Verify installation 29 | 30 | ```python 31 | >>> import flashinfer_bench as flb 32 | >>> flb.__version__ 33 | '0.0.1' 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/op_type_schema/gemm.md: -------------------------------------------------------------------------------- 1 | # gemm 2 | 3 | General Matrix Multiplication (GEMM) operation that computes C = A × B^T. This is a fundamental linear algebra operation used in neural networks for layer computations, attention mechanisms, and other matrix transformations. 4 | 5 | Variants: 6 | - FP16 GEMM: Uses 16-bit floating point (FP16) inputs for A and B matrices 7 | - FP8 GEMM: Uses 8-bit floating point (FP8) inputs for A and B matrices, with scaling factors to maintain numerical stability 8 | 9 | Axes (3 dimensions): 10 | - `M`: variable 11 | - `N`, `K`: constant 12 | 13 | Inputs (2 or 4 tensors): 14 | - `A`: [M, K] 15 | - `B`: [N, K] 16 | - Scaling factors for FP8 GEMM: 17 | - `A_scale`: [M] 18 | - `B_scale`: [N] 19 | 20 | Outputs (1 tensor): 21 | - `C`: [M, N] 22 | -------------------------------------------------------------------------------- /docs/op_type_schema/rmsnorm.md: -------------------------------------------------------------------------------- 1 | # rmsnorm 2 | 3 | Root Mean Square Layer Normalization (RMSNorm) is a normalization technique that normalizes the input by the root mean square of its elements. 4 | 5 | Variants: 6 | - Standard RMSNorm: basic RMS normalization that scales input by RMS and applies learned weight parameters 7 | - Fused Add RMSNorm: adds residual connection before normalization in a single fused operation 8 | 9 | Axes (2 dimensions): 10 | - `batch_size`: variable 11 | - `hidden_size`: constant 12 | 13 | Inputs (2 or 3 tensors): 14 | - `hidden_states`: [batch_size, hidden_size] 15 | - `weight`: [hidden_size] 16 | - For Fused Add RMSNorm only: 17 | - `residual`: [batch_size, hidden_size] 18 | 19 | Outputs (1 tensor): 20 | - `output`: [batch_size, hidden_size] 21 | -------------------------------------------------------------------------------- /web/packages/ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/alert' 2 | export * from './components/avatar' 3 | export * from './components/badge' 4 | export * from './components/button' 5 | export * from './components/card' 6 | export * from './components/dropdown-menu' 7 | export * from './components/hover-card' 8 | export * from './components/input' 9 | export * from './components/label' 10 | export * from './components/select' 11 | export * from './components/table' 12 | export * from './components/tabs' 13 | export * from './components/textarea' 14 | export * from './components/progress-circle' 15 | export * from './components/toaster' 16 | 17 | export * from './providers/Providers' 18 | export * from './components/site-header' 19 | export * from './components/site-footer' 20 | -------------------------------------------------------------------------------- /tests/bench/test_benchmark_config.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import pytest 4 | 5 | from flashinfer_bench.bench import BenchmarkConfig 6 | 7 | 8 | def test_benchmark_config_defaults_valid(): 9 | cfg = BenchmarkConfig() 10 | assert cfg.warmup_runs >= 0 11 | assert cfg.iterations > 0 12 | assert cfg.num_trials > 0 13 | assert cfg.rtol > 0 and cfg.atol > 0 14 | 15 | 16 | @pytest.mark.parametrize( 17 | "field, value", 18 | [("warmup_runs", -1), ("iterations", 0), ("num_trials", 0), ("rtol", 0.0), ("atol", 0.0)], 19 | ) 20 | def test_benchmark_config_validation(field, value): 21 | kwargs = {} 22 | kwargs[field] = value 23 | with pytest.raises(ValueError): 24 | BenchmarkConfig(**kwargs) 25 | 26 | 27 | if __name__ == "__main__": 28 | pytest.main(sys.argv) 29 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | This project uses `setuptools_scm` for automatic version management from git tags. 4 | 5 | ## Workflow 6 | 7 | ### Option 1: GitHub GUI (Recommended) 8 | 9 | 1. Go to [GitHub Releases](https://github.com/flashinfer-ai/flashinfer-bench/releases) 10 | 2. Click "Draft a new release" 11 | 3. Click "Choose a tag" → Type tag name (e.g., `v0.1.0`) → "Create new tag on publish" 12 | 4. Fill in release notes 13 | 5. Click "Publish release" 14 | 6. PyPI publish automatically 15 | 16 | ### Option 2: Command Line 17 | 18 | ```bash 19 | # Create and push tag 20 | git tag v0.1.0rc1 21 | git push origin v0.1.0rc1 22 | 23 | # Then create GitHub Release (manual) 24 | # PyPI publish automatically 25 | ``` 26 | 27 | ## Version Format 28 | 29 | - `v0.1.0` - Stable 30 | - `v0.1.0rc1` - Release candidate 31 | -------------------------------------------------------------------------------- /docs/api/index.md: -------------------------------------------------------------------------------- 1 | # Welcome to FlashInfer-Bench Python API documentation! 2 | 3 | [Blog Post](https://flashinfer.ai/2025/10/21/flashinfer-bench.html) | [GitHub](https://github.com/flashinfer-ai/flashinfer-bench/) | [Slack (Join channel #flashinfer-bench)](https://join.slack.com/t/flashinfer/shared_invite/zt-379wct3hc-D5jR~1ZKQcU00WHsXhgvtA) 4 | 5 | FlashInfer-Bench is a comprehensive benchmark and infrastructure designed to create a "virtuous cycle" where AI can automatically optimize and improve the core GPU kernels of the AI systems it runs on. It provides a systematic framework to identify performance bottlenecks, generate solutions, and deploy them immediately into production. 6 | 7 | ```{toctree} 8 | :maxdepth: 2 9 | :caption: API Reference 10 | 11 | rst/schema 12 | rst/apply 13 | rst/tracing 14 | rst/compile 15 | ``` 16 | -------------------------------------------------------------------------------- /web/apps/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "ESNext", 5 | "jsx": "preserve", 6 | "strict": true, 7 | "baseUrl": ".", 8 | "skipLibCheck": true, 9 | "esModuleInterop": true, 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "allowJs": true, 13 | "noEmit": true, 14 | "lib": [ 15 | "dom", 16 | "dom.iterable", 17 | "esnext" 18 | ], 19 | "incremental": true, 20 | "isolatedModules": true, 21 | "plugins": [ 22 | { 23 | "name": "next" 24 | } 25 | ] 26 | }, 27 | "include": [ 28 | "**/*.md", 29 | "**/*.mdx", 30 | "**/*.ts", 31 | "**/*.tsx", 32 | ".next/types/**/*.ts" 33 | ], 34 | "exclude": [ 35 | "node_modules" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /web/packages/ui/src/components/label.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as LabelPrimitive from "@radix-ui/react-label" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "@flashinfer-bench/utils" 6 | 7 | const labelVariants = cva( 8 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 9 | ) 10 | 11 | const Label = React.forwardRef< 12 | HTMLLabelElement, 13 | React.ComponentPropsWithoutRef & 14 | VariantProps 15 | >(({ className, ...props }, ref) => ( 16 | 21 | )) 22 | Label.displayName = LabelPrimitive.Root.displayName 23 | 24 | export { Label } 25 | -------------------------------------------------------------------------------- /web/apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@flashinfer-bench/docs", 3 | "private": true, 4 | "version": "0.1.0", 5 | "scripts": { 6 | "dev": "next dev -p 3030", 7 | "build": "next build", 8 | "start": "next start -p 3030", 9 | "api-docs": "bash ./gen_api_docs.sh" 10 | }, 11 | "dependencies": { 12 | "@flashinfer-bench/config": "workspace:*", 13 | "@flashinfer-bench/ui": "workspace:*", 14 | "next": "^15.5.0", 15 | "nextra": "^4.4.0", 16 | "nextra-theme-docs": "^4.4.0", 17 | "react": "^19.1.1", 18 | "react-dom": "^19.1.1" 19 | }, 20 | "devDependencies": { 21 | "@tailwindcss/postcss": "^4.1.11", 22 | "@types/react": "^19.1.13", 23 | "@types/react-dom": "^19.1.9", 24 | "postcss": "^8.5.6", 25 | "tailwindcss": "^4.1.11", 26 | "typescript": "^5.8.3" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /docs/api/rst/schema.md: -------------------------------------------------------------------------------- 1 | # FlashInfer Trace Schema 2 | 3 | FlashInfer-Bench provides a schema for the FlashInfer Trace database. This document includes 4 | the Python API for the schema, including 5 | 6 | - The {py:class}`~flashinfer_bench.data.Definition` class, which defines the kernel specification. 7 | - The {py:class}`~flashinfer_bench.data.Solution` class, which defines the kernel implementation. 8 | - The {py:class}`~flashinfer_bench.data.Workload` class, which defines the kernel's input tensors. 9 | - The {py:class}`~flashinfer_bench.data.Trace` class, which defines the kernel execution trace. 10 | - The {py:class}`~flashinfer_bench.data.TraceSet` class, which defines a set of kernel execution traces. 11 | 12 | ```{toctree} 13 | :maxdepth: 2 14 | 15 | schema_definition 16 | schema_solution 17 | schema_workload 18 | schema_trace 19 | schema_traceset 20 | ``` 21 | -------------------------------------------------------------------------------- /flashinfer_bench/tracing/workload_entry.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Any, Dict, Optional 3 | 4 | 5 | @dataclass 6 | class WorkloadEntry: 7 | """In-memory buffer entry for collected workloads.""" 8 | 9 | def_name: str 10 | """Name of the definition this workload entry belongs to.""" 11 | 12 | axes: Dict[str, int] 13 | """Dictionary mapping axis names to their concrete integer values.""" 14 | 15 | inputs_to_dump: Dict[str, Any] 16 | """Inputs to dump. Maps input name to the tensor to dump. This field will be further stored 17 | to disk as a tensor blob.""" 18 | 19 | order: int 20 | """Sequential order number for this entry in the collection process.""" 21 | 22 | cuda_graph_snapshot: Optional[Dict[str, Any]] = None 23 | """CPU snapshot of tensors collected during CUDA Graph replay, if applicable.""" 24 | -------------------------------------------------------------------------------- /web/apps/web/app/kernels/[name]/constraints.tsx: -------------------------------------------------------------------------------- 1 | import { Card, CardContent } from "@flashinfer-bench/ui" 2 | import { Definition } from "@/lib/schemas" 3 | 4 | export function ConstraintsSection({ definition }: { definition: Definition }) { 5 | if (!definition.constraints || definition.constraints.length === 0) return null 6 | return ( 7 |
8 |

Constraints

9 | 10 | 11 |
    12 | {definition.constraints.map((constraint, idx) => ( 13 |
  • 14 | • {constraint} 15 |
  • 16 | ))} 17 |
18 |
19 |
20 |
21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Python ### 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | _build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # IMPORTANT: Include web project's lib directories 38 | !web/**/lib/ 39 | !web/**/lib/** 40 | 41 | # Sphinx 42 | .sphinx-deps 43 | web/**/public 44 | 45 | .claude 46 | .vscode 47 | 48 | tmp/ 49 | AGENTS.md 50 | .coverage 51 | -------------------------------------------------------------------------------- /flashinfer_bench/bench/evaluators/registry.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import List, Type 4 | 5 | from flashinfer_bench.data import Definition 6 | 7 | from .default import DefaultEvaluator 8 | from .evaluator import Evaluator 9 | from .lowbit import LowBitEvaluator 10 | from .sampling import SamplingEvaluator 11 | 12 | EvaluatorType = Type[Evaluator] 13 | 14 | _EVALUATORS: List[EvaluatorType] = [SamplingEvaluator, LowBitEvaluator] 15 | _DEFAULT_EVALUATOR: EvaluatorType = DefaultEvaluator 16 | 17 | 18 | def resolve_evaluator(definition: Definition) -> EvaluatorType: 19 | matches = [cls for cls in _EVALUATORS if cls.can_evaluate(definition)] 20 | if len(matches) == 1: 21 | return matches[0] 22 | if len(matches) == 0: 23 | return _DEFAULT_EVALUATOR 24 | raise ValueError(f"Multiple evaluator matches for definition '{definition.name}'") 25 | -------------------------------------------------------------------------------- /web/apps/docs/app/[[...mdxPath]]/page.jsx: -------------------------------------------------------------------------------- 1 | import { generateStaticParamsFor, importPage } from 'nextra/pages' 2 | import { useMDXComponents as getMDXComponents } from '../../mdx-components' 3 | 4 | export const generateStaticParams = generateStaticParamsFor('mdxPath') 5 | 6 | export async function generateMetadata(props) { 7 | const params = await props.params 8 | const { metadata } = await importPage(params.mdxPath) 9 | return metadata 10 | } 11 | 12 | const Wrapper = getMDXComponents().wrapper 13 | 14 | export default async function Page(props) { 15 | const params = await props.params 16 | const { 17 | default: MDXContent, 18 | toc, 19 | metadata, 20 | sourceCode 21 | } = await importPage(params.mdxPath) 22 | return ( 23 | 24 | 25 | 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /web/packages/ui/src/components/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@flashinfer-bench/utils" 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |