Skip to content

Latest commit

 

History

History
595 lines (463 loc) · 26.8 KB

File metadata and controls

595 lines (463 loc) · 26.8 KB

kernel_package 编写指南(面向 agent / 新提交者)

本指南面向「需要从零创建一个全新 kernel_package 并提交到 kernel_zoo」的 agent 或开发 者。规范层面的权威来源是 docs/kernel_package_format.md(自动生成自 schemas/*.json) 与 docs/superpowers/specs/2026-08-02-kernel_zoo-design.md。本指南解释为什么这么 设计每个文件如何与系统交互,并给出可直接落地的工程步骤。

相关文档:

阅读顺序建议:先看 §1(系统全景)建立心智模型 → 看 §2(目录布局)→ 按 §3 逐文件 编写 → 用 §5 的本地校验闭环跑一遍 → 用 §6 的清单做提交前自检。


1. 系统全景:kernel_package 在 kernel_zoo 里扮演什么角色

kernel_zoo 是一个 git 仓库驱动的 GPU 算子排行榜。仓库根目录就是 kernel_data 仓库本 身,每个算子实现对应仓库中的一个 kernel_package 目录。Server 把仓库直接当数据 源:GET /api/kernels 来自仓库内 *.kernel_package/desc.yaml 的扫描,bench_result.yaml 就是排行榜的"成绩单",git log 就是历史尝试记录。没有外置数据库。

一个 kernel_package 的生命周期:

   [提交者]                          [server / git 仓库]                   [runner]
       │                                    │                                  │
   1. 本地构建 src/ 源码区             │  现有 HEAD:desc.yaml + bench_result.yaml + src/
   2. 打包 tar.gz                     │                                  │
   3. POST /api/submissions  ──────────▶  入队 pending/<uuid>/package.tar.gz │
       (multipart)                    │                                  │
                                      │  POST /api/runner/claim  ◀────────│  runner 拿到 uuid
                                      │  ──▶ 返回 package_url            │
                                      │                                  │
                                      │  GET /api/runner/package/<uuid> ◀─│  下载 tarball
                                      │  ──▶ stream tar.gz               │
                                      │                                  │  解包到 workdir
                                      │                                  │  python build_test_env.py workdir
                                      │                                  │  python benchmark.py workdir
                                      │                                  │  → stdout: benchmark_output.json
                                      │  POST /api/submissions/<uuid>/result ◀── 上报 JSON
                                      │                                    │
                                      │  accept=true:                     │
                                      │    - 覆盖 src/                    │
                                      │    - 更新 bench_result.yaml       │
                                      │    - git commit                   │
                                      │    - 触发 index.json 重算         │

关键设计决定(理解它,每个文件该写什么就自然清楚了):

  • 接受/拒绝策略不在 server 里:server 是个"信任 benchmark.py 判定结果"的薄壳。决策 逻辑(correctness 比对、回归容忍、best 打破规则)完全由 benchmark.py 内部黑盒完 成。这是为什么 §3.4 的 benchmark.py 是整个 package 里最需要动脑子的文件。
  • 源码区与元数据区分离.kernel_package/ 是元数据/契约区,只有 server 能写 bench_result.yamlsrc/(或任何与 .kernel_package 同级的文件/目录)是提交者 的自由区,每次 accept 整片覆盖。这隔离了"提交者的实现"与"系统的成绩记录"。
  • desc.yaml 是 agent 的契约:description 字段是给"想优化这个算子的自动化 agent" 读的,必须自包含到能让 agent 不看 src/ 也能写出一份合理实现。这是为什么 §3.1 对 description 的结构有明确建议。
  • 幂等性是硬约束:相同 desc.yaml + 相同 workdir 下,build_test_env.py 必须产生 bit-identical 的输入/期望(固定随机种子)。否则同一提交两次跑分会出现假回归,整个 排行榜的可比性会塌掉。

2. 目录布局

2.1 仓库内的路径即 kernel_id

<kernel_repo_root>/
└── gfx928/Attention/MHA/fp16/reference_impl/   ← 这条相对路径就是 kernel_id
    ├── .kernel_package/
    │   ├── desc.yaml
    │   ├── bench_result.yaml
    │   ├── build_test_env.py
    │   └── benchmark.py
    └── src/                                     ← 源码区,提交者自由组织
        └── ref_attention.py

硬约束:

  • 路径每段匹配 ^[A-Za-z0-9._-]+$(不允许空格、/..、Unicode)。
  • kernel_id = 该目录相对于仓库根的 POSIX 相对路径(无前导/尾随 /)。它出现在 desc.yaml 隐含的目录位置、bench_result.yaml.kernel_id、benchmark 输出的 kernel_id、URL /api/kernels/<kernel_id>、提交时的 multipart.kernel_id —— 所有这些位置的 kernel_id 必须一致
  • .kernel_package/必须有 4 个文件:desc.yamlbench_result.yamlbuild_test_env.pybenchmark.py。缺一不可,否则被标 invalid(list 接口可见但不 可 claim)。
  • .kernel_package/ 同级的所有其他文件/目录都属于"源码区"。可以叫 src/、可以 有 include/MakefileCMakeLists.txt,完全自由。

2.2 推荐的前 4 段约定

虽然 schema 不强制目录深度,但推荐沿用前 4 段约定命名(SP1 样例即如此):

<arch>/<op_class>/<sub_class>/<quant>/<your_name>/

例如 gfx928/Attention/MHA/fp16/reference_impldesc.yaml.category 里的 4 个字段 应当与目录前 4 段一一对应(schema 不强制,但 index.json 会冗余展示,错配会让 WebUI 分类错乱)。

2.3 提交时的 tarball 布局(重要!)

提交给 POST /api/submissions 的 tar.gz 内部必须是:

<kernel_id>/                       ← 顶层目录名 = kernel_id
├── .kernel_package/
│   ├── desc.yaml
│   ├── build_test_env.py
│   └── benchmark.py
└── src/...                        ← 你的实现源码

绝对不要.kernel_package/bench_result.yaml 打进 tarball —— server 会把它当作 "提交者试图篡改成绩单"的攻击,抛 VALIDATION_ERROR 拒收。成绩单由 server 在 accept 路径上自己维护。打包时请用 tf.add(src, arcname=kernel_id) 这种以 kernel_id 为顶层 的模式(参考 §5 的脚本)。


3. .kernel_package/ 四件套逐文件指南

3.1 desc.yaml —— 算子元数据契约

职责: 算子的"说明书",给 WebUI、index.json、benchmark.py(隐式)、第三方优化 agent 看。

最关键字段:description 这是给自动化 agent 读的:要包含数学定义、输入布局、 性能要点、已知陷阱。建议分章节:## 数学定义 / ## 输入布局 / ## 性能提示 / ## 已知陷阱。schema 不强制内部结构,但章节化能让 agent 解析更稳定。

字段速查(详细 schema 见 schemas/desc.json):

字段 必填 设计理由
schema_version semver。当前 "1.0.0"。用于未来 schema 演进时的迁移门控。
name 人类可读名(如 MHA FP16 Reference)。WebUI 展示用。
category {arch, op_class, sub_class, quant}冗余设计:与目录前 4 段重复但便于"单文件读取就能分类",否则 index 要回溯路径。
summary ≤300 字一句话简介。/api/kernels 列表展示用。
description 长文 markdown。给 agent 用。见上。
io_signature [{name, kind: in/out/inout, dtype, shape, shape_desc?, semantics?}]。dtype 用通用名(fp16/bf16/fp8_e4m3/int32...),不要绑硬件厂商命名。
quantization {scheme, granularity?, block_size?, group_size?}scheme: none 表示无量化。
reference_sources 字符串数组,相对当前 kernel_package 的源码路径(如 [src/ref_mha.py])。注意:这是文件路径列表,server 在 accept 时会校验这些路径真实存在(§6.3 of spec)。早期 spec 写过 {type, ...} 对象数组,当前 schema 已改为字符串数组——以 schemas/desc.json 为准。
status normal / frozen / deprecatedfrozen 不允许 claim(运营手段,防止老 package 继续被打榜)。
min_arch_feature mfma_f32_16x16。给 runner 选机型用。
tags / owner WebUI 筛选/归属。

反模式(不要做):

  • 不要在 reference_sources 里写 GitHub URL 或论文 DOI —— 那是早期 spec 的设计,现 在 schema 只接受文件路径。如果要引用论文,写在 description 里。
  • 不要把 acceptance.regression_tolerance 之类的字段写进来 —— 接受策略早已移到 benchmark.py 内部,desc 里加这些字段会被 schema 拒掉(additionalProperties: false)。

与系统交互:

  • GET /api/kernelsGET /api/kernels/{kernel_id} 直接读取此文件。
  • server 在 _validate_reference_sources(accept 路径)里检查列表中所有路径存在。
  • index.json 由 indexer 扫描所有 desc.yaml 生成。

3.2 bench_result.yaml —— 成绩单(提交时不存在,由 server 维护)

重要:你创建一个全新 package 时,仍然需要为它写一份 seed 版的 bench_result.yaml —— 因为它是 .kernel_package/ 四件套之一,缺了会被标 invalid。 但你写的只是占位 seed,server 在第一次 accept 时会改写它。

字段(详见 schemas/bench_result.json):

schema_version: "1.0.0"
kernel_id: gfx928/Attention/MHA/fp16/reference_impl   # 必须与目录路径一致
cases:
  - test_case_id: small_b1_h1_s16_d16
    metrics_best:
      primary_latency_ms:
        value: 0.20
        submitter: seed
        commit_sha: "0000000"          # seed sentinel
        recorded_at: "2026-08-02T00:00:00Z"
      tflops:
        value: 0.001
        submitter: seed
        commit_sha: "0000000"
        recorded_at: "2026-08-02T00:00:00Z"
    metrics_current:                   # 与 metrics_best 同结构
      primary_latency_ms: {value: 0.20, submitter: seed, commit_sha: "0000000", recorded_at: "2026-08-02T00:00:00Z"}
      tflops:             {value: 0.001, submitter: seed, commit_sha: "0000000", recorded_at: "2026-08-02T00:00:00Z"}
    correctness_current: passed        # passed | failed | unknown

设计要点:

  • 只存 best + current,不存历史:历史通过 git log 追溯。这避免了文件膨胀。
  • seed sentinel commit_sha: "0000000":server 在 accept 路径上识别这个特殊值, 会无条件覆盖(不参与 best 比较)。这样新 package 的占位 seed 不会被第一次真 实提交"卡住"。你写 seed 时必须用这个值。
  • correctness_current 是 package 当前 HEAD 是否通过 correctness 的标志。accept 时 server 会更新它。

与系统交互:

  • 提交 tarball 绝对不能包含此文件(见 §2.3)。
  • server accept 路径上的 _rewrite_bench_result + two-commit 流程会原子改写它(详见下方"commit_sha 是怎么写进去的")。
  • GET /api/kernels/{kernel_id} 摘要展示 current;index.json 展示 best。

commit_sha 是怎么写进去的(two-commit 模型,理解它能帮你避免对 git log 形态的误判):

server 不能在 commit 之前就知道 commit 自己的 SHA(SHA-1 不动点问题,无法预测),也不 能用 git commit --amend 回填——amend 会改变 SHA,让 bench_result.yaml 里刚 stamp 的 值指向一个被替换掉的悬空 commit。所以采用 两次 commit

Phase 1 (source commit):
  - stage 所有改动 *除了* bench_result.yaml
  - commit → 产生 SHA_src
  - 此时 worktree 里的 bench_result.yaml 仍含占位 __PENDING_COMMIT__(未 staged)

Phase 2 (bench-result commit):
  - 把 bench_result.yaml 里的 __PENDING_COMMIT__ 全部替换成 SHA_src
  - 只 stage 这一个文件并 commit → 产生 SHA_br(即新 HEAD)

最终:

  • bench_result.yaml.metrics_best.commit_sha = SHA_src自洽,SHA_src 真实存在 于 git log,不是悬空对象)
  • HEAD = SHA_br(一个独立的、只改 bench_result.yaml 的 commit)
  • API 返回的 commit_sha 字段 = SHA_src

所以你会看到 git log两次相邻 commit:先一个"接受提交"的 source commit, 紧接着一个"bench_result update (source <SHA_src 短>)"的小 commit。两者都是真实 commit、都在历史里、都可被 git show 查看。这是设计如此,不是 bug。


3.3 build_test_env.py —— 测试环境构造器

职责: 为 benchmark 阶段生成所有"输入 + 期望输出 + 编译产物"。runner 在执行 benchmark 前会先调用它一次。

契约:

  • 必须提供函数 build_env(workdir: Path) -> None
  • 必须可作为脚本运行:python build_test_env.py <workdir>
  • 落盘约定(runner 会按这些路径读):
    • workdir/inputs/<test_case_id>_*.npy —— 输入张量
    • workdir/expected/<test_case_id>_*.npy —— 期望输出(用于 correctness 比对)
    • workdir/build/ —— 编译产物(如 .so、.cubin,自由)
    • workdir/build_manifest.json —— 记录生成参数与文件 sha256
  • 幂等硬约束:相同 workdir + 相同 desc.yaml 下,重复调用必须产生 bit-identical 输出。CI 会做幂等测试。必须用固定种子numpy.random.default_rng(SEED),SEED 是常量),不要用 timeos.urandomrandom.random() 之类。

设计为什么是这样:

  • 构造与评测分离:把"造数据"和"跑分"拆开,是为了让造数据可以离线一次性完成、 重复跑分时不重新生成(否则随机数变化会让 correctness 比对失败)。
  • 落盘到 workdir 而不是 .kernel_package/:因为编译产物(.so.cubin)体积 大、平台相关,不应进 git。workdir 是 runner 临时目录,跑完即丢。
  • build_manifest.json 记录 sha256:用于调试"为什么同样的代码两次跑分不一致" ——可以快速定位是输入漂移还是实现漂移。

模板(最小可用版本,参考 docs/examples/.../build_test_env.py):

from __future__ import annotations
import hashlib, json, sys
from pathlib import Path
import numpy as np

PKG_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(PKG_ROOT / "src"))
from my_kernel import MyOp  # type: ignore[import-not-found]

# 必须与 benchmark.py 里的 KERNEL_ZOO_TEST_CASE_METAS 一一对应
TEST_CASE_PARAMS = {
    "small":  {"batch": 1, "heads": 1, "seq_len": 16, "head_dim": 16},
    "large":  {"batch": 1, "heads": 2, "seq_len": 64, "head_dim": 32},
}
SEED = 0xBEEF   # 固定种子,不要改

def build_env(workdir: Path) -> None:
    inputs = workdir / "inputs"
    expected = workdir / "expected"
    inputs.mkdir(parents=True, exist_ok=True)
    expected.mkdir(parents=True, exist_ok=True)
    rng = np.random.default_rng(SEED)
    manifest = {"seed": SEED, "test_cases": {}}
    for tc_id, params in TEST_CASE_PARAMS.items():
        # ... 生成 q/k/v 与期望 o,固定 rng ...
        np.save(inputs / f"{tc_id}_q.npy", q)
        # ...
        manifest["test_cases"][tc_id] = {"params": params, "files": {...}}
    (workdir / "build_manifest.json").write_text(json.dumps(manifest, indent=2))

def main(argv: list[str]) -> int:
    if len(argv) != 2:
        print("usage: build_test_env.py <workdir>", file=sys.stderr); return 2
    build_env(Path(argv[1])); return 0

if __name__ == "__main__":
    raise SystemExit(main(sys.argv))

与系统交互:

  • runner 下载 tarball 后,先 python build_test_env.py <workdir>
  • 失败(exit != 0 或异常)会被 runner 报告为 build_ok=false,server 直接 reject。

3.4 benchmark.py —— 评测脚本(最关键、最需要动脑子的文件

职责: 在 workdir 里跑你的实现、比对 correctness、计算 metrics、决定 accept/reject, 并把结果以严格 JSON 形式打到 stdout。

契约:

  • 必须提供模块级常量 KERNEL_ZOO_TEST_CASE_METAS: list[dict](每项 schema 见 schemas/test_case_meta.json)。
  • 必须可作为脚本运行:python benchmark.py <workdir>
  • stdout 只能输出一份 JSON(schema 见 schemas/benchmark_output.json),所有日 志/错误信息走 stderr。
  • 决策(accept / reject)在这里完成 —— server 不重判。

KERNEL_ZOO_TEST_CASE_METAS 项 schema:

{
  "test_case_id": "small",                  // ^[A-Za-z0-9._-]+$,package 内唯一
  "params": { ... },                        // 自由 dict,给 WebUI / 优化者参考
  "primary_metric": "primary_latency_ms",   // 必须等于 metrics[].name 之一
  "metrics": [
    {"name": "primary_latency_ms", "unit": "ms", "direction": "lower_better"},
    {"name": "tflops",              "unit": "TFlops", "direction": "higher_better"}
  ],
  "tolerance": {"correctness_atol": 1e-3, "correctness_rtol": 1e-3}
}

为什么 direction 在这里而不是在 bench_result.yaml:因为 best 比较规则由 benchmark.py 自陈,server 据此判定是否打破纪录;成绩单只记数值,不重复声明方向。

stdout 输出 schema(核心字段):

{
  "schema_version": "1.0.0",
  "kernel_id": "gfx928/Attention/MHA/fp16/reference_impl",  // 必须与路径一致
  "ran_at": "2026-08-02T11:00:00Z",
  "runner_id": "runner-sh01",
  "arch": "gfx928",
  "overall": {
    "accept": true,
    "accept_reason": "all cases passed; primary_latency within 5% of best",
    "build_ok": true
  },
  "cases": [
    {
      "test_case_id": "small",
      "correctness": "passed",                  // passed | failed | skipped
      "correctness_detail": {"max_abs_err": 1.2e-4, "max_rel_err": 8e-5},
      "accept": true,
      "accept_reason": "primary_latency 1.20ms vs current 1.23ms (-2.4%)",
      "metrics": [
        {"name": "primary_latency_ms", "value": 1.20},
        {"name": "tflops",             "value": 318.7}
      ],
      "error": null
    }
  ]
}

Server 在 accept 路径上的硬约束(违反任一 → reject):

  1. 输出 JSON 通过 benchmark_output.json schema 校验。
  2. cases[].test_case_id 集合 必须等于 KERNEL_ZOO_TEST_CASE_METAS 集合(不能 少跑也不能多跑)。
  3. overall.accept=true 时,所有 case 必须 correctness=passed
  4. overall.build_ok=true

接受策略完全由你定。 推荐但非强制的常见模式:

  • 每个 case 独立判 accept(correctness 通过 + 该 case 的 primary_metric 不超过历史 best 的 N% 回归)。
  • overall.accept = AND(case.accept)(任一失败即整体拒绝)。
  • 也可设计"分发型":不同 case 走不同实现,整体 accept 容忍局部回撤(spec §2.5 推荐 但不强制)。

正确性比对的标准模式(来自样例):

out, latency_ms = _measure(q, k, v)        # 你的实现
exp = np.load(expected / f"{tc_id}_o.npy") # build_test_env 生成的期望
abs_err = float(np.max(np.abs(out - exp)))
rel_err = float(np.max(np.abs(out - exp) / (np.abs(exp) + 1e-12)))
passed = (abs_err <= tol["correctness_atol"]
          and rel_err <= tol["correctness_rtol"])

回归检查的标准模式(读 bench_result.yaml 当前值做对比):

bench_file = PKG_ROOT / ".kernel_package" / "bench_result.yaml"
prev = _load_current_best(bench_file)  # {test_case_id: {metric_name: value}}
if tc_id in prev and "primary_latency_ms" in prev[tc_id]:
    rel_change = (latency_ms - prev[tc_id]["primary_latency_ms"]) / prev[tc_id]["primary_latency_ms"]
    if rel_change > REGRESSION_TOLERANCE:   # 例如 0.05
        case_accept = False

反模式(必踩坑):

  • ❌ 把日志打到 stdout —— server 解析 stdout 为 JSON,多一行就崩。
  • correctness=failedcase.accept=true —— 违反 schema 语义,server 抛 422。
  • metrics[].value = NaN/Inf —— schema 视为非法。
  • cases 数组少一个 case(觉得这个 case 不重要就不跑)—— 违反硬约束 #2。
  • ❌ 从 stdout 之外的地方(环境变量、文件)传结果 —— runner 只看 stdout。

与系统交互:

  • runner 调 python benchmark.py <workdir>,捕获 stdout,按 benchmark_output.json schema 校验。
  • 通过 POST /api/submissions/{uuid}/result 把这份 JSON(连同 runner logs,base64)回 传给 server。
  • server 据此进入接受路径(§1 流程图的最右侧)或拒绝路径(结果留档但不写 git)。

4. src/ 源码区

唯一硬约束: desc.yaml.reference_sources 里列出的所有路径必须存在。

其他全部自由:可以用 src/include/MakefileCMakeLists.txt.cu.py.hip.o 均可。提交 tarball 时整片打包;server accept 时整片覆盖(保留 .kernel_package/bench_result.yaml)。

设计理由: 把"提交者的实现"与"系统的成绩记录"物理隔离。这样:

  • 提交者无须担心"会不会动到成绩单"——成绩单在 .kernel_package/ 下,server 才能写。
  • server 的覆盖逻辑简单粗暴——删掉源码区、复制新内容,不用做精细 merge。

5. 本地校验闭环(提交前必跑)

5.1 目录结构 + schema 校验

# 1. 用自带 CLI 校验四件套齐全 + 所有 schema 通过
python -m kernel_zoo.cli.validate_package <kernel_package 目录或 .tar.gz>

# 2. 跑一次 indexer,看 index.json 是否生成
KERNEL_ZOO_KERNEL_REPO_PATH=<repo 根> \
KERNEL_ZOO_INDEX_PATH=/tmp/i.json \
python -m kernel_zoo.cli.indexer_now

5.2 端到端 dry run(在本地模拟 runner)

WORKDIR=$(mktemp -d)
KERNEL_PKG=<kernel_package 目录绝对路径>

# Step 1: 构造测试环境
python "$KERNEL_PKG/.kernel_package/build_test_env.py" "$WORKDIR"

# Step 2: 跑 benchmark,捕获 stdout
python "$KERNEL_PKG/.kernel_package/benchmark.py" "$WORKDIR" > /tmp/result.json 2> /tmp/stderr.log

# Step 3: 用 schema 校验输出
python -c "import json, jsonschema; \
  jsonschema.validate(json.load(open('/tmp/result.json')), \
  json.load(open('schemas/benchmark_output.json')))"

# Step 4: 幂等测试(重要!)
WORKDIR2=$(mktemp -d)
python "$KERNEL_PKG/.kernel_package/build_test_env.py" "$WORKDIR2"
diff -r "$WORKDIR/inputs" "$WORKDIR2/inputs" && echo "inputs identical"
diff -r "$WORKDIR/expected" "$WORKDIR2/expected" && echo "expected identical"

5.3 打包 tarball(用于 POST /api/submissions)

import io, tarfile
from pathlib import Path

KERNEL_ID = "gfx928/Attention/MHA/fp16/my_new_impl"
pkg_root = Path(KERNEL_ID)   # 你的本地 package 根(含 .kernel_package/ 与 src/)

buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode="w:gz") as tf:
    tf.add(pkg_root, arcname=KERNEL_ID)
    # 注意:不要包含 .kernel_package/bench_result.yaml!
    # 如果它存在于本地(作为 seed),打包前先排除:
    # for member in tf.getmembers():
    #     if member.name.endswith(".kernel_package/bench_result.yaml"):
    #         tf.members.remove(member)
tarball_bytes = buf.getvalue()

或更稳妥地,先把 .kernel_package/bench_result.yaml 临时移走再打包。


6. 提交前自检清单

逐条核对,全部 ✓ 才能提交:

目录与命名

  • ☐ kernel_id(目录路径)每段匹配 ^[A-Za-z0-9._-]+$
  • .kernel_package/ 内有 4 个文件:desc.yaml / bench_result.yaml / build_test_env.py / benchmark.py
  • desc.yaml.category 与目录前 4 段一致
  • bench_result.yaml.kernel_id 与目录路径一致

desc.yaml

  • reference_sources 中所有路径在源码区真实存在
  • description 自包含(agent 不看 src/ 也能理解算子)
  • status 不是 frozen(否则无法 claim)
  • ☐ 无 acceptance.* 等已废弃字段(schema 会拒)

build_test_env.py

  • ☐ 提供 build_env(workdir) 函数
  • ☐ 可作为脚本运行(python build_test_env.py <workdir>
  • ☐ 使用固定随机种子(幂等性硬约束
  • ☐ 输出落在 workdir/inputs/workdir/expected/workdir/build_manifest.json

benchmark.py

  • ☐ 模块级 KERNEL_ZOO_TEST_CASE_METASbench_result.yaml.cases 一一对应
  • ☐ 每个 meta 的 primary_metric 出现在 metrics[].name
  • ☐ 可作为脚本运行(python benchmark.py <workdir>
  • ☐ stdout 只输出一份合法 JSON,所有日志走 stderr
  • correctness=failed 的 case 必有 accept=false
  • metrics[].value 无 NaN/Inf
  • ☐ accept 策略已实现(不只输出 metrics,确实决定 accept/reject)

tarball

  • ☐ 顶层目录名 = kernel_id
  • 不含 .kernel_package/bench_result.yaml
  • ☐ 文件名以 .tar.gz 结尾

7. 附录:从零创建一个新 package 的最小步骤

KERNEL_ID="gfx928/Attention/MHA/fp16/my_new_impl"

# 1. 建目录结构
mkdir -p "$KERNEL_ID/.kernel_package" "$KERNEL_ID/src"

# 2. 写四个文件(参考 docs/examples/gfx928/Attention/MHA/fp16/reference_impl/)
$EDITOR "$KERNEL_ID/.kernel_package/desc.yaml"
$EDITOR "$KERNEL_ID/.kernel_package/build_test_env.py"
$EDITOR "$KERNEL_ID/.kernel_package/benchmark.py"

# 3. 写 seed 版 bench_result.yaml(commit_sha 必须是 "0000000")
$EDITOR "$KERNEL_ID/.kernel_package/bench_result.yaml"

# 4. 写你的实现
$EDITOR "$KERNEL_ID/src/my_kernel.py"

# 5. 本地校验闭环(§5)—— 直到全绿
# 6. 提交到 server:
curl -X POST https://<server>/api/submissions \
  -H "X-Submitter-Id: alice" \
  -F "kernel_id=$KERNEL_ID" \
  -F "submitter_id=alice" \
  -F "package=@package.tar.gz;type=application/gzip"

提交后用 GET /api/submissions/{uuid}/status(长轮询)等结果。如果 accept,源码会 被覆盖、bench_result.yaml 会被更新、git log 会多一条 commit、index.json 会重算——你 的算子就正式上排行榜了。