Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c6544d0
[PyTorch] [torch.compile] torch.compile support for Linear
pggPL Aug 5, 2026
dfa79c2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 5, 2026
116d477
[PyTorch] Keep the broad-except pylint disable on the anchored line
pggPL Aug 5, 2026
dc4ff77
[PyTorch] [torch.compile] Style pass on the Linear custom-op path
pggPL Aug 5, 2026
250bd71
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 5, 2026
39d10f8
Address review: fix recompile assert, empty-batch sentinel collision,…
pggPL Aug 10, 2026
2c37350
Address review: simplify check_gemm_dims, trim test comments, restore…
pggPL Aug 10, 2026
eb3f50f
Shorten check_gemm_dims docstring
pggPL Aug 10, 2026
9695013
Drop tensor_can_be_materialized: inline an exact-class check in the t…
pggPL Aug 10, 2026
c64a0b0
Trim paraphrase comments in the Linear fake impls
pggPL Aug 10, 2026
b9bf693
Rename SP leading-dim helpers for direction clarity, trim two comments
pggPL Aug 10, 2026
aeb3481
Tighten custom_op module docstring intro
pggPL Aug 10, 2026
53b811b
Merge and simplify custom_op docstring paragraphs 2-3
pggPL Aug 10, 2026
948f94e
Keep the impl-vs-op contrast as two paragraphs
pggPL Aug 10, 2026
872387f
Drop reference to a PyTorch PR that will not land
pggPL Aug 10, 2026
dcc3c9a
Shorten _ensure_distributed_opaque_types docstring
pggPL Aug 10, 2026
d87eda6
Fall back to eager cleanly when ProcessGroup opaque registration is u…
pggPL Aug 10, 2026
1950585
Fix leftover 'priority order' wording at _FIELD_ADAPTERS
pggPL Aug 10, 2026
9c4fadf
Restructure register_custom_op docstring: caller contract first, drop…
pggPL Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions tests/pytorch/distributed/run_layer_with_overlap.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,19 @@ def _parse_args(argv=None, namespace=None):
parser.add_argument(
"--use-cuda-graphs", action="store_true", default=False, help="Use CUDA Graphs."
)
parser.add_argument(
"--compile",
action="store_true",
default=False,
help="Wrap each layer in torch.compile (tests Userbuffers on the compiled path).",
)
parser.add_argument(
"--compile-mode",
type=str,
default="default",
choices=["default", "reduce-overhead"],
help="torch.compile mode used when --compile is set.",
)
parser.add_argument(
"--ub-cfg", type=str, default=None, help="Optional TP config yaml file input."
)
Expand Down Expand Up @@ -285,6 +298,9 @@ def _parse_args(argv=None, namespace=None):
)
args = parser.parse_args(argv, namespace)

if args.compile and args.use_cuda_graphs:
parser.error("--compile and --use-cuda-graphs are mutually exclusive.")
Comment on lines +301 to +302

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So how do we test the lower overhead mode? Shouldn't we just do that mode of the compilation if this
option is set?


if args.use_cuda_graphs and args.layer_type in [te.MultiheadAttention, te.TransformerLayer]:
warnings.warn(f"{args.layer_type.__name__} does not support CUDA Graphs!")
args.use_cuda_graphs = False
Expand Down Expand Up @@ -535,6 +551,17 @@ def run_fwd_bwd(model, x):
loss.backward()
return out

if opts.compile:
for i, layer in enumerate(test_model.layers):
# Static shapes; dynamic-shape coverage lives in tests/pytorch/test_torch_compile.py.
test_model.layers[i] = torch.compile(
layer, fullgraph=True, mode=opts.compile_mode, dynamic=False
)
dist_print(
f"Compiled test model layers with torch.compile (mode={opts.compile_mode})...",
debug=True,
)

torch_rng_state = torch.get_rng_state()
cuda_rng_state = torch.cuda.get_rng_state(torch.device(f"cuda:{LOCAL_RANK}"))
if opts.use_cuda_graphs:
Expand Down
49 changes: 43 additions & 6 deletions tests/pytorch/distributed/run_numerics.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,22 +310,40 @@ def _copy_params(model_distributed, model_single):


def _apply_models(
model_single_node, model_distributed, input_single_node, input_distributed, **kwargs
model_single_node,
model_distributed,
input_single_node,
input_distributed,
use_compile=False,
compile_mode="default",
**kwargs,
):
_alloc_main_grad(model_single_node, model_distributed) # for fuse_wgrad_accumulation=True
input_single_node.requires_grad_()
input_distributed.requires_grad_()
forward_single_node = model_single_node
forward_distributed = model_distributed
if use_compile:
# Reset the compile cache so parametrized cases don't trip recompile_limit.
torch._dynamo.reset()
# Static shapes; dynamic-shape coverage lives in tests/pytorch/test_torch_compile.py.
forward_single_node = torch.compile(
model_single_node, fullgraph=True, mode=compile_mode, dynamic=False
)
forward_distributed = torch.compile(
model_distributed, fullgraph=True, mode=compile_mode, dynamic=False
)
with te.autocast(
enabled=QUANTIZATION is not None,
recipe=quantization_recipe(),
):
output_single_node = model_single_node(input_single_node, **kwargs)
output_single_node = forward_single_node(input_single_node, **kwargs)
with te.autocast(
enabled=QUANTIZATION is not None,
recipe=quantization_recipe(),
amax_reduction_group=NCCL_WORLD,
):
output_distributed = model_distributed(input_distributed, **kwargs)
output_distributed = forward_distributed(input_distributed, **kwargs)
return output_single_node, output_distributed


Expand Down Expand Up @@ -641,12 +659,20 @@ def test_quantized_all_gather():
# Linear #
############################################
@run_distributed_test()
def _test_linear(parallel_mode=None, sequence_parallel=False, **kwargs):
def _test_linear(
parallel_mode=None,
sequence_parallel=False,
use_compile=False,
compile_mode="default",
**kwargs,
):
"""Test the linear layer with specified parallel mode and sequence parallelization.

Args:
parallel_mode (str): 'row' or 'column' parallelism.
sequence_parallel (bool): Enable sequence parallelism if True.
use_compile (bool): Wrap the modules in ``torch.compile`` before running.
compile_mode (str): ``torch.compile`` mode ("default" or "reduce-overhead").
kwargs (dict): Additional arguments for the linear layer.
"""
# Set parameter data type
Expand Down Expand Up @@ -696,7 +722,12 @@ def _test_linear(parallel_mode=None, sequence_parallel=False, **kwargs):

# Apply models
output_single_node, output_distributed = _apply_models(
model_single_node, model_distributed, input_single_node, input_distributed
model_single_node,
model_distributed,
input_single_node,
input_distributed,
use_compile=use_compile,
compile_mode=compile_mode,
)

if "return_bias" in kwargs:
Expand Down Expand Up @@ -740,12 +771,18 @@ def test_linear():
{"params_dtype": torch.float16 if QUANTIZATION != "nvfp4" else torch.bfloat16},
{"delay_wgrad_compute": True},
{"save_original_input": True},
{"use_compile": True},
{"use_compile": True, "compile_mode": "reduce-overhead"},
]

for kwargs in kwargs_list:
if kwargs.get("save_original_input", False) and QUANTIZATION == "fp8":
continue
if kwargs.get("delay_wgrad_compute", False) and NVTE_TEST_NVINSPECT_ENABLED:
# use_compile: debug instrumentation forces the eager fallback, so
# compile is a no-op there.
if NVTE_TEST_NVINSPECT_ENABLED and (
kwargs.get("delay_wgrad_compute", False) or kwargs.get("use_compile", False)
):
continue
for parallel_mode in ["column", "row"]:
for sequence_parallel in [False, True]:
Expand Down
34 changes: 34 additions & 0 deletions tests/pytorch/distributed/test_comm_gemm_overlap.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ def _run_layer_with_overlap(
quantization,
num_layers=1,
use_cublasmp=False,
use_compile=False,
compile_mode="default",
):
test_path = TEST_ROOT / "run_layer_with_overlap.py"
test_cmd = LAUNCH_CMD + [
Expand All @@ -129,6 +131,10 @@ def _run_layer_with_overlap(
if overlap_rs_dgrad:
test_cmd.append("--overlap-rs-dgrad")

if use_compile:
test_cmd.append("--compile")
test_cmd.append(f"--compile-mode={compile_mode}")

if fp8:
if quantization in ("fp8_delayed_scaling", "fp8_current_scaling") and not fp8_available:
pytest.skip(reason_for_no_fp8)
Expand Down Expand Up @@ -281,6 +287,34 @@ def test_layers_with_overlap_bf16(
)


@pytest.mark.parametrize("compile_mode", ["default", "reduce-overhead"])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kind of a general comment, but do we expect to ever see a case that would work under reduce
overhead mode but not work under the default mode? If so then maybe we could just test the stricter
mode if things are supposed to work under both of them?

@pytest.mark.parametrize(
"linear_parallel_mode,overlap_rs_dgrad",
[
("row", False),
("column", False),
("column", True),
],
ids=[
"ROW-PARALLEL",
"COL-PARALLEL - BULK DGRAD/WGRAD",
"COL-PARALLEL - DGRAD+RS",
],
)
def test_linear_with_overlap_compile(linear_parallel_mode, overlap_rs_dgrad, compile_mode):
"""te.Linear comm+GEMM overlap (Userbuffers) under torch.compile (BF16),
checked numerically against the eager, non-overlap reference."""
_run_layer_with_overlap(
te.Linear.__name__,
linear_parallel_mode,
overlap_rs_dgrad,
False,
None,
use_compile=True,
compile_mode=compile_mode,
)


@pytest.mark.parametrize("use_cublasmp", (False, True))
@pytest.mark.parametrize(
"quantization",
Expand Down
2 changes: 1 addition & 1 deletion tests/pytorch/test_hybrid_quantization.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ def test_supports_only_rowwise_all_gather_nvfp4_columnwise(self):
``gather_along_first_dim`` cannot operate on a columnwise-only
NVFP4 hybrid sub-storage. ``HybridQuantizer.supports_only_rowwise_all_gather``
must return True in this case so ``_linear_forward_impl`` /
``_linear_backward`` preserve rowwise data (which NVFP4 can
``_linear_backward_impl`` preserve rowwise data (which NVFP4 can
dequantize) instead.
"""
hq = HybridQuantizer(
Expand Down
Loading
Loading