Register a cuTile kernel as an AOT QDP plugin via torch_tensorrt.kernels.cutile_op#
cutile_op is the cuTile counterpart of cuda_kernel_op, and the declarative form of the hand-written AOT plugin in aot_plugin: it takes a @ct.kernel program, compiles it ahead of time, and registers the PyTorch custom op, the TensorRT plugin descriptor, the AOT impl (with the compiled PTX embedded in the engine), and the Torch-TensorRT converter — in one call.
The piece cutile_op exists to handle is the calling convention. cuTile expands every array parameter into (ptr, extents..., strides...), grouped per array in declaration order. TensorRT’s AOT plugin launcher instead passes (input_ptrs..., extra_args..., output_ptrs...). Those two orders do not agree, and a mismatch does not fail — the kernel reads whatever landed in each slot and returns plausible-looking garbage. cutile_op permutes the compiled PTX’s parameter list and supplies
the matching extents and strides as AOT extra arguments, so the kernel binds what it expects.
This example requires cuda-tile>=1.3,<2 and tileiras from a system CUDA Toolkit compatible with that package, on PATH or under CUDA_HOME.
[ ]:
import argparse
import cuda.tile as ct
import tensorrt.plugin as trtp
import torch
import torch_tensorrt
import torch_tensorrt.kernels as ttk
parser = argparse.ArgumentParser()
parser.add_argument("--min_block_size", type=int, default=1)
ARGS, _ = parser.parse_known_args()
Step 1: Define the cuTile kernel (pure cuTile, nothing TensorRT-specific)#
Array parameters come first — inputs then outputs — followed by the ct.Constant parameters, which are baked into the compiled symbol.
[ ]:
TILE_SIZE = 128
@ct.kernel
def add_one_kernel(x, out, tile_size: ct.Constant[int]):
pid = ct.bid(0)
tile = ct.load(x, index=(pid,), shape=(tile_size,))
ct.store(out, index=(pid,), tile=tile + 1.0)
Step 2: Describe the op and register it with a single cutile_op call#
signature— the array parameters and their element types, in declaration order.ndimdefaults to 1, matching a kernel written against a flattened view, so a rank-1 array’s extent is the tensor’s element count and the op accepts any input shape.constants— thect.Constantvalues to compile for.grid— the launch grid in tiles, computed fromtrtp.TensorDescinputs. Using.shape_exprkeeps it symbolic so one engine covers a range of shapes.meta_fn— shape/dtype inference for FakeTensors (the Torch schema is inferred from its type hints).eager_fn— optional; letstorch.ops.cutile_example.add_onealso run outside TensorRT.
[ ]:
def add_one_meta(x: torch.Tensor) -> torch.Tensor:
return torch.empty_like(x, memory_format=torch.contiguous_format)
def add_one_eager(x: torch.Tensor) -> torch.Tensor:
# The flat kernel must write a view of the returned allocation, including
# when x is transposed or uses another noncontiguous layout.
out = torch.empty_like(x, memory_format=torch.contiguous_format)
flat_x = x.contiguous().reshape(-1)
flat_out = out.reshape(-1)
ct.launch(
torch.cuda.current_stream().cuda_stream,
(ct.cdiv(flat_x.numel(), TILE_SIZE), 1, 1),
add_one_kernel,
(flat_x, flat_out, TILE_SIZE),
)
return out
ttk.cutile_op(
"cutile_example::add_one",
kernel=add_one_kernel,
signature={"x": "fp32", "out": "fp32"},
meta_fn=add_one_meta,
grid=lambda inputs, outputs: (trtp.cdiv(inputs[0].shape_expr.numel(), TILE_SIZE),),
constants={"tile_size": TILE_SIZE},
eager_fn=add_one_eager,
)
Step 3: Use it — the op lowers to the AOT QDP plugin inside the engine#
[ ]:
class AddOne(torch.nn.Module):
def forward(self, x: torch.Tensor) -> torch.Tensor:
return torch.ops.cutile_example.add_one(x)
if __name__ == "__main__":
x = torch.randn(4, 256, device="cuda", dtype=torch.float32)
model = AddOne().cuda().eval()
ref = x + 1
assert torch.allclose(model(x), ref), "eager path mismatch"
print("eager path OK")
trt_model = torch_tensorrt.compile(
model,
inputs=[x],
min_block_size=ARGS.min_block_size,
)
print("engine compiled with the AOT QDP plugin")
trt_out = trt_model(x)
assert torch.allclose(trt_out, ref, atol=1e-5), "cutile_op TRT output mismatch"
print("cutile_op AOT QDP plugin ran correctly under Torch-TensorRT")