Operator Performance Testing and Tuning: autotune Feature Usage Guide
Document Positioning
This document introduces two auto-tuning methods provided by Triton-distributed:
Function-level auto-tuning:
triton_dist.tune.autotune;Context auto-tuning:
triton_dist.autotuner.contextual_autotune.
The content is for those who already have callable Triton Kernels and want to further tune distributed operators, focusing on usage methods, tuning boundaries, distributed selection, and caching behavior on Ascend.
For Kernel-level triton.autotune used internally by the context method, refer to Triton-Ascend autotune Usage Guide, API Documentation, and Usage Examples.
Feature Overview
Tuning Method |
Tuning Object |
Config Source |
Cache |
Typical Scenario |
|---|---|---|---|---|
|
Regular Python Host launcher |
|
In-process and disk cache |
Tune complete function containing communication and one or more Kernels |
|
Python function containing autotune Kernel |
Internal Kernel configs |
Internal Kernel in-process cache |
Kernel must complete tuning in real outer context |
Both methods are adapted for Ascend device timing and support taking maximum time across multiple ranks before selecting global configuration.
Quick Start
Function-Level Auto-Tuning
Below is a minimal example organized from repository Ascend scale test. Function-level decorator is added to Host launcher:
import torch
import triton
import triton.language as tl
from triton_dist.tune import autotune
@triton.jit
def scale_kernel(x_ptr, y_ptr, alpha, n, BLOCK: tl.constexpr):
pid = tl.program_id(0)
offsets = pid * BLOCK + tl.arange(0, BLOCK)
mask = offsets < n
x = tl.load(x_ptr + offsets, mask=mask, other=0.0)
tl.store(y_ptr + offsets, alpha * x, mask=mask)
def config_space():
return [
{"cfg": triton.Config({"BLOCK": block}, num_warps=warps)}
for block in (256, 512, 1024, 2048)
for warps in (4, 8)
]
def key_fn(x, alpha, *args, **kwargs):
return (tuple(x.shape), str(x.dtype))
def prune_fn(entry, x, alpha, *args, **kwargs):
block = entry["cfg"].all_kwargs()["BLOCK"]
return block * x.element_size() < 32 * 1024
@autotune(
config_space=config_space(),
key_fn=key_fn,
prune_fn=prune_fn,
)
def scale(x, alpha, cfg):
y = torch.empty_like(x)
meta = cfg.all_kwargs()
grid = (triton.cdiv(x.numel(), meta["BLOCK"]),)
scale_kernel[grid](x, y, alpha, x.numel(), **meta)
return y
When calling, no need to pass cfg, tuner will inject from config space:
x = torch.randn(1 << 18, device="npu", dtype=torch.float32)
y = scale(x, 2.5, autotune=True, autotune_verbose=True)
torch.testing.assert_close(y, 2.5 * x, atol=1e-5, rtol=1e-4)
On first encounter of a new key, framework filters and tests candidate configs; subsequent calls reuse best config. This example doesn’t put alpha in key because it doesn’t change input layout and tuning config selection.
Context Auto-Tuning
Context method decorates outer Python function, which internally calls Kernel with Kernel-level autotune:
import torch
import triton
import triton.language as tl
from triton_dist.autotuner import contextual_autotune
BLOCK = 512
@triton.autotune(
configs=[
triton.Config({"BLOCK": BLOCK}, num_warps=warps)
for warps in (4, 8)
],
key=["n"],
)
@triton.jit
def scale_kernel(x_ptr, y_ptr, alpha, n, BLOCK: tl.constexpr):
pid = tl.program_id(0)
offsets = pid * BLOCK + tl.arange(0, BLOCK)
mask = offsets < n
x = tl.load(x_ptr + offsets, mask=mask, other=0.0)
tl.store(y_ptr + offsets, alpha * x, mask=mask)
@contextual_autotune(is_dist=False, n_repeat=3, n_warmup=2)
def run_scale(x, alpha):
y = torch.empty_like(x)
grid = (triton.cdiv(x.numel(), BLOCK),)
scale_kernel[grid](x, y, alpha, x.numel())
return y
x = torch.randn(1 << 18, device="npu", dtype=torch.float32)
y = run_scale(x, 3.0)
torch.testing.assert_close(y, 3.0 * x, atol=1e-5, rtol=1e-4)
assert scale_kernel.best_config is not None
Context tuner will drive internal Kernel to run per-config during complete run_scale call, and write best config to internal Kernel cache.
Working Principle
Function-Level Method
On first call with a new business key:
key_fngenerates key from business parameters;Query in-process cache and disk cache;
When cache misses, use
prune_fnto filter candidate configs;For each config, execute 5 warmup and 10 timing runs;
In multi-rank mode, perform
MAXreduction on time from each rank;Save best config, and execute launcher again with best config.
Function-level method measures complete device-side work triggered by decorated Host function. Config can affect both Kernel parameters and launch method or communication pipeline in launcher.
Context Method
Context tuner takes over internal Kernel’s autotune flow during outer function execution:
Execute outer function and discover internal Kernels needing tuning;
In same outer context, warmup and time each candidate config of internal Kernel;
After one internal Kernel completes selection, continue processing subsequent Kernels;
After all Kernels complete, execute outer function once more using their respective best configs.
n_warmup and n_repeat control warmup count and timing count for each candidate config respectively. When is_dist=True, takes maximum of candidate time from each rank for selection.
How to Choose
Use function-level method when:
Want to directly tune regular Python launcher;
Config affects communication, Kernel launch, or multiple execution steps simultaneously;
Need to reuse disk cache across processes;
Need to use
key_fnandprune_fnfor custom caching and pruning logic.
Use context method when:
Function internally already has one or more autotune Kernels;
Kernel cannot be independently tested outside outer communication, synchronization, or buffer state;
Want to complete internal Kernel selection during real function call.
Ascend and Distributed Support
Function-level method uses torch.npu.Event for timing; context method creates Event, gets stream, and cleans benchmark cache through current Triton Ascend driver’s device interface.
Distributed selection uniformly adopts slowest rank time:
global_time(config) = max(time_rank_0, ..., time_rank_n)
Function-level method passes in HCCL ProcessGroup through autotune_pg:
result = scale(
x,
alpha,
autotune=True,
autotune_pg=process_group,
)
Context method enables distributed reduction through is_dist=True, and uses PyTorch default WORLD group. All participating ranks must execute same candidate order and call flow.
Caching and Logging
Tuning Method |
Cache |
Logging |
|---|---|---|
Function-level |
In-process cache and |
Located in same function directory as disk cache |
Context |
Internal Kernel’s in-process autotune cache |
|
Function-level disk cache records function source code, hardware info, business key, and software dependencies. Modifying function source or hardware generates different cache; when dependencies mismatch, defaults to warning, can set TRITON_DIST_AUTOTUNE_VERSION_CHECK=1 to force re-tune.
Set the following environment variable to ignore existing function-level results:
export TRITON_DIST_AUTOTUNE_ALWAYS_TUNE=1
Performance Testing Process
Recommend separating first tuning from steady-state performance testing:
Execute tuning with real shape, dtype, and rank count;
Use reference implementation to verify correctness of best config;
Retain disk cache or in-process cache;
Run again with same key, only measure steady-state time of best config;
For distributed operators, focus on both per-rank time and slowest rank time.
Usage Considerations
Both methods repeatedly execute tuned function, input, output, and synchronization state must support repeated calls;
autotune only compares time, doesn’t automatically verify correctness;
Function-level
prune_fnonly filters configs, not responsible for performance comparison;Multi-rank key, config count, config order, and pruning results must be consistent;
Context tuner only allows one active instance at a time, doesn’t support nesting or concurrent use;
First call includes search and compilation overhead, cannot be directly used as steady-state performance result.
Summary
Function-level method is suitable for using Host launcher as complete tuning boundary; context method is suitable for tuning internal Kernel in real outer call. Both select based on actual timing results, and use slowest rank’s time as selection basis in distributed scenarios.
For complete interface, see Distributed General Host Interface: autotune, for distributed operator practice, see autotune Example: Optimization Method Practice.