mcpField
T
tilegym-adding-cutile-kernel

tilegym-adding-cutile-kernel

github.com/nvidia開発3.8k1.8k 回インストール今日更新
リポジトリ

tilegym-adding-cutile-kernel について

TileGym に cuTile オペレーターを追加する開発者向けの手順スキルです。ディスパッチ登録から実装、テスト、ベンチマーク、検証までを順に案内します。

主な機能

  1. 01順序付きの統合作業チェックリスト
  2. 02ディスパッチインターフェースの登録
  3. 03cuTile バックエンドの実装と登録
  4. 04テストとベンチマークの手順
  5. 05pytest と lint による検証

活用シーン

  1. 01TileGym への cuTile オペレーター追加
  2. 02新しいオペレーターのテストと測定
  3. 03提出前の実装確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/nvidia/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. 各 TODO は完了後に 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

さらに、__all__ に "my_op" を追加します。

手順 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

コメント