mcpField
T
tilegym-adding-cutile-kernel

tilegym-adding-cutile-kernel

github.com/promptingcompany开发039 次安装17 周前更新
代码仓库

关于 tilegym-adding-cutile-kernel

用于指导开发者为 TileGym 添加 cuTile 算子的技能,按顺序覆盖接口注册、后端实现、测试、基准测试和验证。

主要功能

  1. 01按步骤注册调度接口
  2. 02实现并注册 cuTile 后端
  3. 03添加算子测试
  4. 04创建性能基准测试
  5. 05运行测试与代码检查

适用场景

  1. 01为 TileGym 添加新算子
  2. 02为 cuTile 实现补充测试和基准
  3. 03检查算子集成并运行验证

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/promptingcompany/nv-skills --skill tilegym-adding-cutile-kernel

安装后在 Claude Code 中输入/tilegym-adding-cutile-kernel确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

BENCHMARK.md
skill-card.md
skill.oms.sig
evals/
evals.json

详细介绍

在 TileGym 中添加 cuTile 内核

使用 cuTile 后端添加新算子(例如 my_op)的端到端工作流。

执行规则

必须严格遵循以下规则:

  1. 编写任何代码之前,使用 TodoWrite 创建下方清单
  2. 按顺序执行步骤——不得跳步或合并步骤
  3. 每完成一项待办后,将其标记为 completed;开始执行时标记为 in_progress
  4. 如果某个步骤不适用(例如没有 cuTile 实现),请附注并将其标记为 completed,不得悄悄跳过
  5. 每个步骤都必须写入文件或明确决定跳过,不得默默遗漏

说明

开始时必须将此清单复制到 TodoWrite:

- [ ] Step 1: Register dispatch interface in ops.py
- [ ] Step 2: Implement cuTile backend
- [ ] Step 3: Register in __init__.py (cutile)
- [ ] Step 4: Add tests
- [ ] Step 5: Add benchmark to tests/benchmark
- [ ] Step 6: Verify (run pytest + lint)

步骤 1:注册分发接口

文件:src/tilegym/ops/ops.py

添加一个 @dispatch 函数——这是所有后端的唯一入口点。

@dispatch(
    "my_op",
)
def my_op(
    input: torch.Tensor,
    out: Optional[torch.Tensor] = None,
    **kwargs: Any,
):
    """
    Description of my_op.

    Args:
        input: Input tensor
        out: Optional preallocated output tensor
        **kwargs: Additional arguments for backend-specific configurations

    Returns:
        torch.Tensor
    """
    raise NotImplementedError(f"my_op is not implemented for {get_current_backend()}")

关键规则:

  • 函数体只能抛出 NotImplementedError
  • 使用 **kwargs 接收特定于后端的参数

参考:参阅 src/tilegym/ops/ops.py 中现有的算子(例如 silu_and_mul、softmax)

步骤 2:实现 cuTile 后端

文件:src/tilegym/ops/cutile/my_op.py

文件结构遵循以下模板:

import torch
import cuda.tile as ct

from tilegym.backend import register_impl


@ct.kernel
def my_op_kernel_ct(x, output, n_elements: ct.Constant[int], BLOCK_SIZE: ct.Constant[int]):
    bid = ct.bid(0)
    indices = bid * BLOCK_SIZE + ct.arange(0, BLOCK_SIZE)
    x_val = ct.gather(x, indices)
    # ... compute ...
    ct.scatter(output, indices, result)


@register_impl("my_op", backend="cutile")
def my_op(input: torch.Tensor, out: torch.Tensor = None, **kwargs) -> torch.Tensor:
    n = input.numel()
    if out is None:
        out = torch.empty_like(input)
    grid = ((n + 1023) // 1024,)
    ct.launch(stream, grid, kernel, (some args, ...))
    return out

参考:src/tilegym/ops/cutile/silu_and_mul.py

步骤 3:在 __init__.py 中注册(关键)

缺少此步骤会导致 cuTile 后端实现永远不会被加载。

文件:src/tilegym/ops/cutile/__init__.py

在 if is_backend_available("cutile"): 代码块中添加(按字母顺序排列):

from . import my_op

并在函数导入部分添加:

from .my_op import my_op

并将 "my_op" 添加到 __all__。

步骤 4:添加测试

文件:tests/ops/test_my_op.py

关键:始终从 tilegym.ops 导入,切勿从 tilegym.ops.cutile.my_op 导入。

import pytest
import torch

from tilegym.backend import is_backend_available, set_backend
from .. import common

_backends = ["cutile"]


class Test_MY_OP(common.PyTestCase):
    @staticmethod
    def reference(input):
        """Reference implementation using PyTorch."""
        return torch.some_reference(input)

    @pytest.mark.parametrize("shape, dtype", [
        ((1024,), torch.float16),
        ((1024, 512), torch.float32),
        ((64, 64, 64), torch.bfloat16),
    ])
    @pytest.mark.parametrize("backend", _backends)
    def test_op(self, shape, dtype, backend, arch):
        if backend == "cutile" and not is_backend_available("cutile"):
            pytest.skip("Cutile backend not available")
        try:
            set_backend(backend)
        except Exception as e:
            pytest.skip(f"Backend is not supported: {e}")

        self.setUp()

        from tilegym.ops import my_op

        A = torch.randn(*shape, dtype=dtype, device="cuda")
        self.assertCorrectness(
            my_op, self.reference, {"input": A},
            atol=1e-3, rtol=1e-3,
        )

关键模式:

  • _backends = ["cutile"]
  • test_op:使用 try-except 调用 set_backend(backend),并调用 self.setUp()

参考:tests/ops/test_silu_and_mul.py

以下是常见错误。

1. Missing _backends list (inside class)
2. test_op / test_op_xxx — missing @pytest.mark.parametrize("backend", _backends), backend parameter, and tilegym.is_backend_available / tilegym.set_backend pattern

步骤 5:在 tests/benchmark 中添加基准测试

文件:tests/benchmark/bench_my_op.py

benchmark_rules.md 中的关键规则:

  • 通过 tilegym.ops.my_op(a, b, ..., backend=backend) 调用算子——不要使用 set_backend。
  • 定义 ALL_BACKENDS(至少包含 cutile 和 torch),并使用 get_supported_backends() 进行筛选。
  • 实现 reference_my_op(...),并注册:register_impl("my_op", "torch")(reference_my_op)。
  • 使用 create_benchmark_config() 构建 triton.testing.Benchmark 配置(例如按形状/数据类型配置)。
  • 在 bench_my_op(...) 上使用 @triton.testing.perf_report([...]);在基准测试函数内部,先用 torch.testing.assert_close(fn(), ref(), ...) 检查正确性,然后调用 ms = triton.testing.do_bench(fn)(或 do_bench_cudagraph),计算 GB/s 或 TFLOPS,并返回该指标。
  • 入口:if __name__ == "__main__": bench_my_op.run(print_data=True)。

模板结构:

import torch
import triton
import triton.testing

import tilegym
from tilegym.backend import is_backend_available, register_impl

ALL_BACKENDS = [
    ("cutile", "cuTile", ("orange", "-")) if is_backend_available("cutile") else None,
    ("torch", "PyTorch", ("green", "-")),
]

def get_supported_backends():
    return [p for p in ALL_BACKENDS if p is not None]

def reference_my_op(input: torch.Tensor, out: torch.Tensor = None, **kwargs):
    """Reference implementation using PyTorch."""
    ...

register_impl("my_op", "torch")(reference_my_op)

def create_benchmark_config(datatype, ...):
    available_backends = get_supported_backends()
    if not available_backends:
        return None
    backends, names, styles = zip(*available_backends)
    return triton.testing.Benchmark(
        x_names=["M"],  # or other dimension names
        x_vals=[...],
        line_arg="backend",
        line_vals=list(backends),
        line_names=list(names),
        styles=list(styles),
        ylabel="GB/s",  # or TFLOPS
        plot_name="my-op-...",
        args={"datatype": datatype, ...},
    )

@triton.testing.perf_report([
    create_benchmark_config(datatype, ...)
    for datatype in [torch.float16, torch.float32]
    for ... in [...]
])
def bench_my_op(M, backend, datatype, ..., device="cuda"):
    x = torch.randn(..., dtype=datatype, device=device)

    fn = lambda: tilegym.ops.my_op(x, backend=backend)
    ref = lambda: reference_my_op(x)
    torch.testing.assert_close(fn(), ref(), rtol=1e-2, atol=1e-2)

    ms = triton.testing.do_bench(fn)  # or do_bench_cudagraph(fn)
    # Compute metric (e.g. GB/s or TFLOPS) from ms and problem size
    return metric

if __name__ == "__main__":
    bench_my_op.run(print_data=True)

基准测试图表名称:必须包含 -TFLOPS 或 -GBps 后缀

  • 示例:plot_name=f"persistent-layer-norm-M{num_rows}-{dtype_name}-GBps"

步骤 6:验证

# Run tests
pytest tests/ops/test_my_op.py -v

# Run benchmark (optional)
python tests/benchmark/bench_my_op.py

# Lint
pre-commit run -a

评论

支持 Markdown