Files
tilelang/examples/topk/example_topk.py
T
8ce2778221 [CI][Refactor] Merge test CI workflow files into one (#973)
* refactor: merge test CI workflow files into one

* chore: set `UV_INDEX_STRATEGY=unsafe-best-match`

* feat: add AST test with Python 3.8

* feat: implement manual caching mechanism for self-hosted runners

* refactor: simplify cache logic for self-hosted runners

* chore: clear uv cache on failure

* chore: print format.sh output to logs

* chore: improve uv caching

* chore: disable parallel test

* chore: use `PYTHONDEVMODE=1` in CI

* feat: enable coredump generation

* fix: fix perfbench condition

* Revert "feat: enable coredump generation"

This reverts commit c52da65cb5.

* chore: move example CI down

* Revert "chore: move example CI down"

This reverts commit 9d8e65055e.

* chore: skip example `test_example_mha_sink_bwd_bhsd`

* chore: skip example `test_example_gqa_sink_bwd_bhsd`

* fix: fix example argument passing

* fix: loosen test criteria

* chore: rename `CMAKE_CONFIGURE_OPTIONS` -> `CLANG_TIDY_CMAKE_OPTIONS` for clarity

* feat: enable parallel testings

* chore: update pytest options

* remove skipped test as now been resolved

* chore: empty commit to re-trigger ci

* test for n 1

* chore: remove ` --numprocesses=1` option in example

* chore: disable failfast

* chore: update cibw selection

* fix: fix git submodule clone

* chore: update cibw commands

* fix: fix yapf multiprocessing

* chore: setup ccache for CIBW on macOS only

* chore: update comments

* chore: update artifact listing

* fix: do not fail if not found nvcc in PATH

* fix: fix flash-attn installation

* chore: update dist workflow trigger

* chore: remove outdated comments

* chore(workflows/dist): simplify build matrix strategy

* fix: fix CUDA path finding

* fix: fix CUDA path finding

* chore: imcrease CI timeout

* ci: disable failfast

* fix: hide path prefix

* chore: more verbose

* chore: disable PR trigger for dist workflow

* fix: seed for tests

* fix: use nightly torch for ROCm tests

* chore: enable PR trigger for dist workflow

* chore: stop uploading debug wheels as artifacts in PR

* chore: do not run workflows in forks

* chore: housekeep requirements

* chore: use Nightly-ROCm-6.3 for CI

* chore: use Nightly-ROCm-6.4 for CI

* Update ROCm toolkit version to 7.0

* chore: restore previous rocm-ci.yml for test

* fix: cleanup PYTHONPATH

* chore: remove previous rocm-ci.yml

* ci fix

* chore: remove previous rocm-ci.yml

* chore: enable parallel example run

---------

Co-authored-by: LeiWang1999 <leiwang1999@outlook.com>
Co-authored-by: alex_xiao <xinyuxiao2024@gmail.com>
2025-10-15 22:12:41 +08:00

98 lines
3.0 KiB
Python

import tilelang
import tilelang.language as T
import torch
import itertools
import argparse
def get_configs():
iter_params = dict(
blk_m=[64, 128, 256],
threads=[128, 256, 512],
)
return [dict(zip(iter_params, values)) for values in itertools.product(*iter_params.values())]
@tilelang.autotune(configs=get_configs())
@tilelang.jit(out_idx=[1, 2])
def tl_topk(
M,
N,
topk,
blk_m,
threads=128,
):
dtype = "float32"
@T.prim_func
def topk_kernel(
logits: T.Tensor([M, N], dtype),
topk_gates: T.Tensor([M, topk], dtype),
topk_indices: T.Tensor([M, topk], "int32"),
):
with T.Kernel(T.ceildiv(M, blk_m), threads=threads) as bx:
logits_frag = T.alloc_fragment([blk_m, N], dtype=dtype)
max_val = T.alloc_fragment([blk_m], dtype=dtype)
expand_max_idx = T.alloc_fragment([blk_m, N], "int32")
max_idx = T.alloc_fragment([blk_m], "int32")
T.copy(logits[bx * blk_m, 0], logits_frag)
for k in T.serial(topk):
T.fill(expand_max_idx, -1)
T.reduce_max(logits_frag, max_val, dim=1, clear=True)
for i, j in T.Parallel(blk_m, N):
expand_max_idx[i, j] = T.if_then_else(max_val[i] == logits_frag[i, j], j,
expand_max_idx[i, j])
T.reduce_max(expand_max_idx, max_idx, dim=1, clear=True)
for i, j in T.Parallel(blk_m, N):
logits_frag[i, j] = T.if_then_else(max_val[i] == logits_frag[i, j], -10000.0,
logits_frag[i, j])
for i in T.Parallel(blk_m):
topk_gates[bx * blk_m + i, k] = max_val[i]
topk_indices[bx * blk_m + i, k] = max_idx[i]
return topk_kernel
def ref_program(logits, top_k):
top_k_gates, top_k_indices = logits.topk(top_k, dim=1)
return top_k_gates, top_k_indices.to(torch.int32)
def main(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument("--M", type=int, default=320, help="num_tokens")
parser.add_argument("--N", type=int, default=128, help="num_experts")
parser.add_argument("--topk", type=int, default=6, help="topk")
parser.add_argument("--blk_m", type=int, default=64, help="blk_m")
args = parser.parse_args(argv)
M, N, topk, blk_m = args.M, args.N, args.topk, args.blk_m
logits = torch.rand((M, N), device="cuda", dtype=torch.float32)
kernel = tl_topk(M=M, N=N, topk=topk, blk_m=blk_m)
tl_gates, tl_indices = kernel(logits)
torch_gates, torch_indices = ref_program(logits, topk)
# test accuracy
torch.testing.assert_close(tl_gates, torch_gates)
torch.testing.assert_close(tl_indices, torch_indices)
# profile
profiler = kernel.get_profiler(tensor_supply_type=tilelang.TensorSupplyType.Auto)
tilelang_latency = profiler.do_bench()
print(f"Tilelang latency: {tilelang_latency}")
if __name__ == "__main__":
main()