Skip to content

fix: TensorRT-RTX Turing (SM 7.5) capability guards and compute-capability targeting - #4643

Open
tp5uiuc wants to merge 3 commits into
mainfrom
tp5uiuc/trtrtx-turing-foundation
Open

fix: TensorRT-RTX Turing (SM 7.5) capability guards and compute-capability targeting#4643
tp5uiuc wants to merge 3 commits into
mainfrom
tp5uiuc/trtrtx-turing-foundation

Conversation

@tp5uiuc

Copy link
Copy Markdown
Collaborator

What — Adds a target_compute_capabilities compilation setting, declares it on the TensorRT-RTX
builder config, and falls back to PyTorch for the ops TensorRT-RTX cannot serve on Turing.

Why — TensorRT-RTX runs on SM 7.5 and up, but its support matrix carves Turing out of several
paths: FP32 GEMMs and 3D convolutions are unsupported at compute capability 7.5, and Turing has no
bfloat16 hardware. Torch-TensorRT had no notion of this and handed those ops over anyway:

  • FP32 GEMM, static shapes — createExecutionContext() returns null
  • FP32 GEMM, dynamic shapes — the engine builds and runs, returning an all-zero tensor of the
    correct shape and dtype, with no exception
  • 3D convolution — null execution context
  • bfloat16 — segmentation fault

The dynamic-shape GEMM is the motivating case, because it fails silently.

Separately, the builder was never told which architecture it was building for. With
num_compute_capabilities == 0, Myelin looks for a precompiled module instead of JIT-ing one and
the build dies — Compatible cubin or ptx module for device target '75' not found — so on Turing
every refittable build failed.

How — Guards key off the capabilities being built for, not the build host, so an
ahead-of-time build for another architecture partitions correctly instead of baking in the build
machine. An undeclared target is resolved rather than skipped, to the current device, matching how
partitioning already resolved it — and by naming ComputeCapability.CURRENT rather than looking up
SM<major><minor>, because TensorRT-RTX names only a subset of architectures and the implicit path
must not start failing on hosts that build fine today.

The GEMM guard keys on fp32 operands only, so fp16 GEMMs accumulating in fp32 are unaffected. The
convolution guard covers forward 3D only, since transposed 3D works on Turing. bfloat16 is gated at
the partitioner rather than per-converter because the crash is not operator-specific, mirroring the
existing complex-dtype handling. Converter unit tests bypass the partitioner, so a rejected node
raises instead of falling back; those tests skip explicitly.

Testing — Confirmation sweep at the series tip, T4 (SM 7.5) and L40S (SM 8.9), driver 595.58.03,
identical stacks: T4 2668 passed / 17 failed / 226 skipped; L40S 2780 / 13 / 118; 2911 collected on
each.
Declaring the capability alone closes 42 of the 91 original Turing failures. Defaulting
costs nothing off Turing: on an L40S, engines built with the default and with an explicit [(8, 9)]
are byte-identical (280148 B and 287100 B for a small conv net; 47148116 B and 24184052 B for
resnet18), with no measurable build-time difference. On the L40S there is not one status change
across all six test modules
— every guard is inert off Turing.

Cost / Gotchas

  • The guards switch off 105 tests on Turing, 97 of them in conversion/: the T4 runs 1981 of
    2126 tests where the L40S runs 2079. Green on Turing does not mean equally tested on Turing.
  • Also clears two pre-existing lint failures in aten_ops_converters.py (an unused
    type: ignore[assignment] and a spelling the typos hook rejects). Both predate this change, but
    the file is now in the changed set so pre-commit blocks on them.

Followups — Three more capability gaps ship as stacked PRs on this branch: 3D convolution behind
the pad-folding pass, the GEMM cdist emits internally, and FP32 GEMMs reaching TensorRT-RTX through
linear and attention.

🤖 Generated with Claude Code

@github-actionsgithub-actionsBot added component: tests Issues re: Tests component: conversion Issues re: Conversion stage component: core Issues re: The core compiler component: api [Python] Issues re: Python API component: dynamo Issues relating to the `torch.compile` or `torch._dynamo.export` paths labels Aug 29, 2026
@tp5uiuc

Copy link
Copy Markdown
CollaboratorAuthor

Stack — merge #4643 first; #4644, #4645 and #4646 are based on it and GitHub will retarget them to main once it lands. They are independent of each other and can merge in any order, but all three add cases to tests/py/dynamo/models/test_turing_capability_guards.py, so the second and third will want a trivial rebase. #4647 and #4648 are not Turing bugs and are independent of this stack entirely.

Comment on lines +660 to +662
cannot see shapes fail open. Shared with the capability validator that rejects this
case on Turing and with the converter tests, so none of them can drift from the
branch below.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Remove "Shared with the capability validator that rejects this
case on Turing and with the converter tests, so none of them can drift from the
branch below."

# host, so a module compiled on Ampere and shipped to Turing does not retain ops Turing
# cannot execute.

TURING_COMPUTE_CAPABILITY = (7, 5)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Push it to inside the function, no one else consumes it.

getattr(settings, "target_compute_capabilities", None) if settings else None
)
if targets:
return tuple((int(major), int(minor)) for major, minor in targets)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

tuple(tuple(map(int, major_minor)) for major_minor in targets)

Comment threadpy/torch_tensorrt/_utils.py Outdated
Comment on lines +401 to +404
targets = (
getattr(settings, "target_compute_capabilities", None) if settings else None
)
if targets:

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

if settings and (targets := getattr(settings, "target_compute_capabilities", None)):

Comment on lines +390 to +432
# Declared targets name the architectures the artifact is built for; Turing is
# opt-in as an additional target because it can constrain kernel selection for the
# others. An undeclared target is resolved rather than skipped: the builder default
# leaves num_compute_capabilities at 0 and a refittable graph then fails with
# "Compatible cubin or ptx module for device target '75' not found". Resolve it to
# the current device the way get_target_compute_capabilities() already does for the
# validators, naming ComputeCapability.CURRENT because TensorRT-RTX names only a
# subset of architectures.
if ENABLED_FEATURES.tensorrt_rtx:
declared = self.compilation_settings.target_compute_capabilities
if declared:
builder_config.num_compute_capabilities = len(declared)
for idx, (major, minor) in enumerate(declared):
name = f"SM{major}{minor}"
compute_capability = getattr(trt.ComputeCapability, name, None)
if compute_capability is None:
supported = [
m for m in dir(trt.ComputeCapability) if m.startswith("SM")
]
raise ValueError(
f"TensorRT-RTX has no compute capability {name} for requested "
f"target ({major}, {minor}). Supported: {supported}"
)
if not builder_config.set_compute_capability(
compute_capability, idx
):
raise RuntimeError(
f"Failed to set TensorRT-RTX compute capability {name}"
)
_LOGGER.info(f"Targeting TensorRT-RTX compute capabilities {declared}")
else:
builder_config.num_compute_capabilities = 1
if not builder_config.set_compute_capability(
trt.ComputeCapability.CURRENT, 0
):
raise RuntimeError(
"Failed to set the TensorRT-RTX compute capability of the "
"current device"
)
_LOGGER.info(
"Targeting the TensorRT-RTX compute capability of the current "
f"device {get_target_compute_capabilities(self.compilation_settings)}"
)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

This should be refactored into its own function and unit-tested if possible.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Also the if else path (between declared SM and current) can also be two different hidden functions for ease of readability. so the top level call can be

if ENABLED_FEATURES.tensorrt_rtx:
set_compute_capabilities(self.build_config, self.compilation_settings.target_compute_capabilities)

and the rest can cascade into own function calls

enable_experimental_decompositions (bool): Use the full set of operator decompositions. These decompositions may not be tested but serve to make the graph easier to convert to TensorRT, potentially increasing the amount of graphs run in TensorRT.
dryrun (bool): Toggle for "Dryrun" mode, running everything except conversion to TRT and logging outputs
hardware_compatible (bool): Build the TensorRT engines compatible with GPU architectures other than that of the GPU on which the engine was built (currently works for NVIDIA Ampere and newer)
target_compute_capabilities (Optional[List[Tuple[int, int]]]): Compute capabilities to build for, e.g. ``[(7, 5)]`` for Turing. Defaults to None, meaning the current device. TensorRT-RTX only. Drives both engine targeting and op partitioning, so ops unsupported on any listed target fall back to PyTorch.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Cab we add a check where we error out if target_compute_capabilities is set for standard TensorRT (saying it is not supported)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

This support check can be here or in COmpilationSettings post init, wherever it makes most sense

Comment on lines +66 to +68
# None means "target the current device". Set explicitly to build an engine deployable
# on other architectures; see torch_tensorrt._utils for why capability validators must
# consult this rather than the build host's device.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Remove

Comment on lines +75 to +76
# Bind to a typed local: the imported helper is untyped from mypy's view here,
# and returning it directly trips --strict's no-any-return.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Remove

return validate_disabled_constant_fold_exclusions(rule_ids)
# Bind to a typed local: the imported helper is untyped from mypy's view here,
# and returning it directly trips --strict's no-any-return.
normalized: Set[str] = validate_disabled_constant_fold_exclusions(rule_ids)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Note : this is a mypy fix.

Comment on lines +256 to +257
# An engine built for one set of compute capabilities cannot be reused for a
# compile targeting a different set -- doing so would silently reintroduce ops the

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Reemove this comment

Adds a target_compute_capabilities setting naming the architectures an engine is
built for, and declares them on the TensorRT-RTX builder config, so an artifact
can be produced for something other than the build host. Declaring it on standard
TensorRT raises: that backend always builds for the current device.
An undeclared target is now resolved rather than skipped. Left at the builder
default num_compute_capabilities stays 0, and a refittable graph then fails with
"Compatible cubin or ptx module for device target '75' not found" -- so on Turing
every refittable build failed. It now resolves to the current device the way
partitioning already did via get_target_compute_capabilities(), naming
ComputeCapability.CURRENT rather than an SM<major><minor> lookup because
TensorRT-RTX names only a subset of architectures.
The builder-config work lives in set_rtx_compute_capabilities() so it can be unit
tested against a stub config, with no GPU and no engine build.
Not exposed on cross_compile_for_windows: TensorRT-RTX does not support that path.
The setting is engine-invariant: an engine built for one capability set must not
be reused for a compile targeting another.
TensorRT-RTX does not support FP32 GEMMs or 3D convolutions on Turing (SM 7.5),
and Turing has no bfloat16 hardware. Handed those ops anyway it returns a null
execution context, segfaults on bf16, or -- under dynamic shapes -- builds, runs
and returns an all-zero tensor with no exception. That silent case is the
motivating one.
Guards key off the capabilities being built for rather than the build host, so an
ahead-of-time build for another architecture partitions correctly. The GEMM guard
keys on fp32 operands only; the convolution guard covers forward 3D only, since
transposed 3D works on Turing. bfloat16 is gated in the partitioners because the
crash is not operator-specific, mirroring the existing complex-dtype handling.
Converter unit tests need explicit skips: DispatchTestCase bypasses the
partitioner, so a guarded node raises UnsupportedOperatorException instead of
falling back and an unguarded one reaches TensorRT-RTX and fails.
The cdist skips state the converter's condition rather than p == 2, because a
GEMM is only emitted for compute_mode 1, or 0/absent with an operand above the
row threshold. Measured on a T4: the 3 cases outside that condition pass, the 9
inside it fail. Rather than hand-copy the branch, it is extracted from
cdist_forward as cdist_emits_matmul/CDIST_MATMUL_ROW_THRESHOLD -- the converter
now consumes its own predicate, and the test and the Turing capability validator
consume the same one, so none of the three can drift. The threshold was a bare
literal in the converter until now. Four parameterisations named for a
compute_mode they do not use are renamed.
Also clears two pre-existing lint failures in aten_ops_converters.py that
pre-commit blocks on now the file is in the changed set: an unused
type: ignore[assignment] and a "mis-evaluate" spelling.
Adds the regression tests for the fallbacks introduced alongside the Turing
(SM 7.5) capability guards: FP32 GEMM, 3D convolution and bfloat16 must fall
back to PyTorch, while FP16 GEMM, 2D convolution and transposed 3D convolution
must stay on TensorRT.
Most of the coverage is written against target_compute_capabilities=[(7, 5)],
which forces Turing's partitioning on any GPU, so the guards are exercised in
CI without Turing hardware. A second class repeats the same checks natively and
is skipped off SM 7.5; it also pins the two failure modes that motivated the
guards -- a null execution context under static shapes and a silently all-zero
result under dynamic shapes.
Two further cases assert on the builder config rather than on compile success,
which is what makes them meaningful off Turing: everywhere except SM 7.5 an
undeclared compute capability is silent.
@tp5uiuc
tp5uiucforce-pushed the tp5uiuc/trtrtx-turing-foundation branch from 60522c1 to bb9c235CompareAugust 30, 2026 00:49
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla signedcomponent: api [Python]Issues re: Python APIcomponent: conversionIssues re: Conversion stagecomponent: convertersIssues re: Specific op converterscomponent: coreIssues re: The core compilercomponent: dynamoIssues relating to the `torch.compile` or `torch._dynamo.export` pathscomponent: testsIssues re: Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@tp5uiuc