Skip to main content

extract-kernel-definitions

Generate Definition JSON files for the flashinfer-trace HuggingFace dataset by harvesting them from a short SGLang inference pass (FlashInfer's @flashinfer_api(trace=...) dumper) — or, as a fallback, by manually transcribing the schema from SGLang sources when FlashInfer doesn't yet have a trace template. Use when adding a new model, extracting GPU kernels (MLA, MoE, GQA, RMSNorm, GEMM, GDN, RoPE, sampling), or filling gaps in the dataset.

跳到安装

来源信息

仓库
flashinfer-ai/flashinfer-bench
最近来源活动
2026年5月1日 00:34
检测到的 SKILL.md 语言
英语
星标
281
分支
50

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
extract-kernel-definitions
description
Generate Definition JSON files for the flashinfer-trace HuggingFace dataset by harvesting them from a short SGLang inference pass (FlashInfer's @flashinfer_api(trace=...) dumper) — or, as a fallback, by manually transcribing the schema from SGLang sources when FlashInfer doesn't yet have a trace template. Use when adding a new model, extracting GPU kernels (MLA, MoE, GQA, RMSNorm, GEMM, GDN, RoPE, sampling), or filling gaps in the dataset.
# Extract Kernel Definitions Produce per-(op, shape) Definition JSONs and stage them in the HuggingFace dataset clone at `tmp/flashinfer-trace/definitions/{op_type}/`. PR submission is **out of scope** here — see [`submit-onboarding-prs`](../submit-onboarding-prs/SKILL.md) (Phase 4 of `/onboard-model`). ## Two paths | Path | When to use | What you do | |------|-------------|-------------| | **A. Trace-dump (primary)** | Kernel is `fi_supported` per `/discover-models` — i.e. the FlashInfer API used by SGLang carries a `@flashinfer_api(trace=...)` template (see [coverage list](#flashinfer-trace-coverage)). | Run a short SGLang inference pass with `FLASHINFER_TRACE_DUMP=1`. The dumper writes one JSON per unique (op, shape) before the kernel runs (crash-safe, deduplicated). | | **B. Manual extraction (fallback)** | Kernel is `fi_missing`, **or** the relevant FlashInfer API is not yet trace-instrumented. | Read the SGLang model source + sgl-cookbook serving config + HF model config; write the Definition JSON by hand using the [schema reference](#schema-reference). | The trace-dump path is the default — it eliminates manual axis derivation and produces JSONs that already carry `axes`, `inputs`, `outputs`, `tags` (`fi_api:*`, `status:verified`), and a `reference` implementation. > Background: the trace dumper was added in > [flashinfer-ai/flashinfer#2931](https://github.com/flashinfer-ai/flashinfer/pull/2931). > Schema and full env-var docs live at > [`docs/fi_trace.rst`](https://github.com/flashinfer-ai/flashinfer/blob/main/docs/fi_trace.rst) > in the FlashInfer repo. SGLang harness reference: > [`tests/trace/example_sglang.py`](https://github.com/flashinfer-ai/flashinfer/blob/main/tests/trace/example_sglang.py). ## Usage ```bash # Path A — auto-dump every fi_supported definition for a model in one inference pass /extract-kernel-definitions --model-name llama-3.2-3b --hf-repo-id meta-llama/Llama-3.2-3B-Instruct # Path A — multi-config: one short run per (TP, EP) listed in sgl-cookbook /extract-kernel-definitions --model-name qwen3-next --tp-list 2,4 # Path B — manual fallback for fi_missing kernels (or names that didn't appear in the dump) /extract-kernel-definitions --model-name kimi-k2 --manual --op-types new_op_type ``` ## Parameters - `--model-name` (required): Model slug (e.g. `llama`, `deepseek-v3`, `qwen3-next`). Used to look up the SGLang model file and the sgl-cookbook YAML. - `--hf-repo-id` (optional): HuggingFace repo override; inferred from `--model-name` if omitted. - `--tp-list` (optional): Comma-separated TP values to run for; default reads sgl-cookbook YAML. - `--ep-list` (optional): Comma-separated EP values for MoE models. - `--manual` (optional): Force Path B (manual extraction) even for fi_supported ops. - `--op-types` (optional): Comma-separated `op_type` filter when using `--manual` or for `--dry-run` reporting. - `--dry-run` (optional): Report what would be dumped/written without running anything. - `--skip-existing` (optional, default `true`): Skip any definition whose name already exists under `tmp/flashinfer-trace/definitions/`. ## Prerequisites - `/clone-repos` has been run, so `tmp/sglang/`, `tmp/flashinfer/`, `tmp/sgl-cookbook/`, and `tmp/flashinfer-trace/` are present and current. The HF dataset clone at `tmp/flashinfer-trace/` is the only home for definitions — the in-repo `flashinfer_trace/` directory was removed in the trace-dataset refactor. - For Path A: a working CUDA-enabled environment, GPU memory sufficient for the chosen model + TP, and `attention_backend="flashinfer"` available in the installed SGLang. - For Path B: HuggingFace `config.json` access for the target model. --- ## Path A: trace-dump from a short SGLang pass The dumper fires inside FlashInfer when both env vars are set **before** the FlashInfer import. SGLang routes through `@flashinfer_api(trace=...)`-decorated APIs whenever `attention_backend="flashinfer"` is selected, so a single short prefill+decode pass exercises most ops at once. ### A1. Pick the serving config(s) Open the sgl-cookbook YAML for the target model and list the unique TP/EP values — one trace-dump pass per unique combination is enough to cover every shape variant. ```bash ls tmp/sgl-cookbook/data/models/generated/v0.5.6/ | grep -i {model_name} cat tmp/sgl-cookbook/data/models/generated/v0.5.6/{model_yaml} ``` If the model has no cookbook entry, default to TP=1 (single-GPU baseline) and skip EP. ### A2. Run the trace-dump pass Use `tools/gpu-lock` so `CUDA_VISIBLE_DEVICES` is set correctly. The script below mirrors [`tests/trace/example_sglang.py`](https://github.com/flashinfer-ai/flashinfer/blob/main/tests/trace/example_sglang.py) in the FlashInfer repo — adapt the `model_path`, `tp_size`, and `attention_backend`: ```bash DUMP_DIR=tmp/dumps/fi_trace_{model_slug}_tp{TP}_ep{EP} tools/gpu-lock --gpus {TP} --exec-timeout 1800 -- python - <<EOF import os, shutil from pathlib import Path # Must be set BEFORE flashinfer / sglang import. os.environ["FLASHINFER_TRACE_DUMP"] = "1" os.environ["FLASHINFER_TRACE_DUMP_DIR"] = "$DUMP_DIR" os.environ.setdefault("SGLANG_SKIP_CUBIN_DOWNLOAD", "1") dump = Path("$DUMP_DIR") if dump.exists(): shutil.rmtree(dump) from sglang.srt.entrypoints.engine import Engine engine = Engine( model_path="{hf_repo_id}", attention_backend="flashinfer", disable_cuda_graph=True, # keep first call on the Python path mem_fraction_static=0.5, tp_size={TP}, disable_radix_cache=True, log_level="warning", ) engine.generate( ["The capital of France is"], {"temperature": 0.0, "max_new_tokens": 4, "top_k": 50, "top_p": 0.9}, ) engine.shutdown() EOF ``` A few non-obvious requirements: - **Set the env vars before import.** `FLASHINFER_TRACE_DUMP` and `FLASHINFER_TRACE_DUMP_DIR` are read at call time, but the `@flashinfer_api` decorator binding happens at import — set them in the shell or at the top of the entry script *before* any `import flashinfer` / `import sglang` runs. - **Use `attention_backend="flashinfer"`.** Other SGLang backends bypass the FlashInfer APIs and produce no dumps. - **Disable CUDA graphs (`disable_cuda_graph=True`)** for the trace pass. Cached graphs skip the Python path and therefore the dumper. - **Page-size variants need separate runs.** SGLang's page size is fixed per server, so to capture both `_ps16` and `_ps64` shapes (for example) you must run twice with different `--page-size`. Enumerate the page sizes used by the target model. - **MoE routing methods.** Each `routing_method_type` (Default, Renormalize, DeepSeekV3, Llama4, RenormalizeNaive, TopK) emits its own template; only the routing actually exercised by the model in your prompts will dump. For DeepSeek-V3 use a real DSv3 model to capture the `ds_routing` variant. - **Quantized variants** (fp8/mxfp8/fp4 GEMM, fp8/fp4 block-scale MoE) require the model to actually use that quant config — load with the matching `--quantization` flag. ### A3. Dedupe and stage into the dataset ```bash # 1. List what was dumped ls "$DUMP_DIR" # 2. For each {name}.json: sort it under the right op_type subdirectory. # The op_type field inside the JSON is the source of truth for the subfolder. python - <<'EOF' import json, shutil from pathlib import Path src = Path("$DUMP_DIR") dst_root = Path("tmp/flashinfer-trace/definitions") for p in src.glob("*.json"): op_type = json.loads(p.read_text())["op_type"] dst = dst_root / op_type / p.name if dst.exists(): print(f"skip (exists): {dst.relative_to(dst_root)}") continue dst.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(p, dst) print(f"added: {dst.relative_to(dst_root)}") EOF ``` ### A3b. Normalize the staged JSONs for `flashinfer-bench validate` The trace dumper's output has three known mismatches with `flashinfer-bench`'s `Definition` schema (all originate in the trace templates shipped with [flashinfer-ai/flashinfer#2931](https://github.com/flashinfer-ai/flashinfer/pull/2931)): 1. `reference` declares the function as `def _<name>_reference(...)`, but `flashinfer-bench` requires a top-level `def run(...)`. 2. Plan-time index tensors (`kv_indptr`, `kv_indices`, `qo_indptr`) come back with `dtype: "unknown"` because the dumper inspects only `run()`'s kwargs, not the wrapper state set during `plan()`. The validator only accepts concrete dtypes from its enum. 3. In-place ops (e.g. `fused_add_rmsnorm`'s residual) declare the same name in both `inputs` and `outputs`. `flashinfer-bench` rejects overlapping I/O names; the dumper's `reference` function only returns the non-overlap outputs anyway, so it's safe to drop the duplicates from `outputs`. Run this once per staging pass to make the JSONs validate: ```bash python - <<'EOF' import json, re from pathlib import Path INDEX_TENSOR_DTYPE = "int32" KNOWN_INDEX_TENSORS = { "kv_indptr", "kv_indices", "qo_indptr", "paged_kv_indptr", "paged_kv_indices", "kv_last_page_len", } REF_RE = re.compile(r"^def\s+_[A-Za-z0-9_]+_reference\b", re.MULTILINE) for p in Path("tmp/flashinfer-trace/definitions").rglob("*.json"): d = json.loads(p.read_text()); changed = False ref = d.get("reference", "") if ref and "def run(" not in ref: new_ref, n = REF_RE.subn("def run", ref, count=1) if n == 1: d["reference"], changed = new_ref, True for name, spec in d.get("inputs", {}).items(): if isinstance(spec, dict) and spec.get("dtype") == "unknown" and name in KNOWN_INDEX_TENSORS: spec["dtype"], changed = INDEX_TENSOR_DTYPE, True overlap = set(d.get("inputs", {})) & set(d.get("outputs", {})) for name in overlap: d["outputs"].pop(name, None) changed = True if changed: p.write_text(json.dumps(d, indent=2) + "\n") print(f"normalized: {p}") EOF ``` These three patches are mechanical — file a follow-up issue against `flashinfer-ai/flashinfer` to emit `def run(...)`, resolve plan-time dtypes, and drop in-place outputs (or rename them) inside the dumper itself, after which A3b becomes a no-op. ### A3c. Validate ```bash flashinfer-bench validate --dataset tmp/flashinfer-trace --disable-gpu ``` Newly staged definitions should report `[WARNING]` (missing descriptions on axes/inputs/outputs are advisory) and not `[ERROR]`. Any `[ERROR]` on a definition you just staged means A3b didn't normalize a new failure mode — inspect the report (`tmp/flashinfer-trace/reports/report-*.txt`) and extend the snippet. That's it for Path A — once normalized, the staged JSONs carry `axes`, `inputs`, `outputs`, `tags` (`fi_api:*`, `status:verified`), and a `reference` implementation, so they're ready for the rest of the onboarding pipeline (workloads → baseline → eval → Phase 4 PRs). ### Trade-off vs. tag enrichment The dumper does **not** auto-emit `tp:N`, `ep:N`, `model:*`, or `quantization:*` tags — those are workflow-level metadata, not kernel-shape metadata. After staging, append the appropriate tags to the JSONs you just produced: ```bash python - <<'EOF' import json from pathlib import Path extra_tags = ["model:{model_slug}", "tp:{TP}"] # add ep:{EP} for MoE for p in Path("tmp/flashinfer-trace/definitions").rglob("*.json"): if p.stat().st_mtime < {dump_run_start_epoch}: continue j = json.loads(p.read_text()) j["tags"] = sorted(set(j.get("tags", []) + extra_tags)) p.write_text(json.dumps(j, indent=2) + "\n") EOF ``` ### FlashInfer trace coverage Per [`docs/fi_trace.rst`](https://github.com/flashinfer-ai/flashinfer/blob/main/docs/fi_trace.rst), the trace registry currently covers: | FlashInfer module | API(s) | `op_type` | |-------------------|--------|-----------|
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看