Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
75432f2
[CI][CRCR] Update mergebot rule to adapt CRCR L3 (#185612)
KarhouTam Jul 14, 2026
45b19ed
rewrite exception handling to be more closer to CPython (#188004)
guilhermeleobas Jul 14, 2026
9b68752
[Dynamo] Fix CLEANUP_THROW (#188638)
guilhermeleobas Jul 14, 2026
c5ea3d6
[Dynamo] Corretly implement SEND opcode (#188639)
guilhermeleobas Jul 14, 2026
d8a8f74
[generator] Close all open generators in compile_subgraph (#157149)
guilhermeleobas Jul 14, 2026
d6b2d8f
Port doctest tests from cpython test_generators.py (#188824)
guilhermeleobas Jul 14, 2026
edae8f1
[Dynamo] Track generator attribute mutations for proper closure handl…
guilhermeleobas Jul 14, 2026
138e834
[Dynamo] Implement subgenerator support in ".throw" / ".close" method…
guilhermeleobas Jul 14, 2026
ad710eb
[Dynamo] Support exception attribute access (StopIteration/AttributeE…
guilhermeleobas Jul 14, 2026
1d8576a
Fix partitioner backward SymInt bindings for replaced symbols (#189783)
aorenste Jul 13, 2026
329a5b4
[llvm21] test_float_to_int_conversion_finite: fold int8 into int16 br…
atalman Jul 14, 2026
b9970c5
[BE] Use is_apple_family_or_newer helper (#189867)
Isalia20 Jul 14, 2026
2b2255a
[TEST][cuDNN] Exercise cuDNN in more varlen attention tests where ava…
eqy Jul 14, 2026
e81d4ff
[Inductor][xpu] Add Intel GPU PVC device info and support get dram gb…
etaf Jul 14, 2026
d9de3ab
[Dynamo] Bind rank-0 tensor inputs in the TVM relay backend (#189699)
guan404ming Jul 14, 2026
b7ad53d
Add XPU to externalId (#184358)
PawelSwider2000 Jul 14, 2026
b2662af
[BE] use round up utility (#189869)
Isalia20 Jul 14, 2026
e17c8e1
[XPU] Re-enable test_optimizer_non_static_param for XPU (#189344)
xuhancn Jul 14, 2026
90be926
Finish mobilenetv2_100 eager-nondeterministic skip: update remaining …
frgossen Jul 14, 2026
324a2d9
[dynamo] Filter torch_version artifact in structured trace tests (#18…
bobrenjc93 Jul 14, 2026
9b94c3c
Update aot_inductor_torchbench baseline: microbench_unbacked_tolist_s…
frgossen Jul 14, 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
Binary file modified .github/scripts/drci_mocks.json.gz
Binary file not shown.
38 changes: 38 additions & 0 deletions .github/scripts/test_trymerge.py
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,44 @@ def test_dont_ignore_flaky_failures(self, *args: Any) -> None:
str(w[0].message),
)

def test_get_classifications_crcr_l3(self, *args: Any) -> None:
"""Test that CRCR L3 failures are classified as CRCR_L3
and are always non-blocking regardless of the ok_failed_checks_threshold."""
pr = GitHubPR("pytorch", "pytorch", 100652)
checks = pr.get_checkrun_conclusions()
checks = get_classifications(
pr.pr_num,
pr.project,
checks,
[],
)
oot_check = (
"inductor / cuda11.8-py3.10-gcc7-sm86"
" / test (inductor_timm, 2, 2, linux.g5.4xlarge.nvidia.gpu)"
)
self.assertEqual(checks[oot_check].classification, "CRCR_L3")

# BROKEN_TRUNK classification still works independently
bt_check = (
"inductor / cuda11.8-py3.10-gcc7-sm86"
" / test (inductor_torchbench_dynamic, 1, 1, linux.g5.4xlarge.nvidia.gpu)"
)
self.assertEqual(checks[bt_check].classification, "BROKEN_TRUNK")

# CRCR_L3 is always non-blocking: ignored by default
pending, failed, ignorable = categorize_checks(checks, list(checks.keys()))
self.assertTrue(len(pending) == 0)
self.assertTrue(len(failed) == 0)
self.assertTrue(len(ignorable["CRCR_L3"]) == 1)

# CRCR_L3 stays ignored even with threshold=0, unlike flaky/broken_trunk
# which get promoted to blocking failures when the threshold is exceeded
pending, failed, ignorable = categorize_checks(
checks, list(checks.keys()), ok_failed_checks_threshold=0
)
self.assertTrue(len(pending) == 0)
self.assertTrue(len(ignorable["CRCR_L3"]) == 1)


@mock.patch("trymerge.gh_graphql", side_effect=mocked_gh_graphql)
@mock.patch("trymerge.gh_fetch_merge_base", return_value="")
Expand Down
40 changes: 39 additions & 1 deletion .github/scripts/trymerge.py
Original file line number Diff line number Diff line change
Expand Up @@ -1911,6 +1911,26 @@ def is_invalid_cancel(
)


def is_crcr_l3(check: JobCheckState, drci_classifications: Any) -> bool:
"""Return True if this check is a non-blocking CRCR L3 failure.

Dr.CI is the classification authority. A check is L3 non-blocking when
Dr.CI returns it under the ``CRCR_L3`` category. CRCR (cross-repo CI
relay) L3 check runs are named ``crcr/<owner>/<repo>/<workflow>`` and will be
classified as CRCR_L3 by Dr.CI when their downstream_repo_level is L3.
"""
if not check or not drci_classifications:
return False

name = check.name
job_id = check.job_id

return any(
name == crcr["name"] or (job_id and job_id == crcr["id"])
for crcr in drci_classifications.get("CRCR_L3", [])
)


def get_classifications(
pr_num: int,
project: str,
Expand Down Expand Up @@ -2009,6 +2029,18 @@ def get_readable_drci_results(drci_classifications: Any) -> str:
)
continue

elif is_crcr_l3(check, drci_classifications):
checks_with_classifications[name] = JobCheckState(
check.name,
check.url,
check.status,
"CRCR_L3",
check.job_id,
check.title,
check.summary,
)
continue

if ignore_current_checks is not None and name in ignore_current_checks:
checks_with_classifications[name] = JobCheckState(
check.name,
Expand Down Expand Up @@ -2298,7 +2330,13 @@ def categorize_checks(
target = (
failed_checks_categorization[classification]
if classification
in ("IGNORE_CURRENT_CHECK", "BROKEN_TRUNK", "FLAKY", "UNSTABLE")
in (
"IGNORE_CURRENT_CHECK",
"BROKEN_TRUNK",
"FLAKY",
"UNSTABLE",
"CRCR_L3",
)
else failed_checks
)
target.append((checkname, url, job_id))
Expand Down
2 changes: 1 addition & 1 deletion aten/src/ATen/native/mps/operations/Indexing.mm
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ static void nonzero_impl_mps(const Tensor& self, Tensor& out_, std::optional<int

[computeEncoder setComputePipelineState:pso_step2];
mtl_setArgs(computeEncoder, block_sums_buf, block_offsets_buf, total_nonzero_buf, num_blocks);
uint32_t tg_size_blocks = std::min(1024u, ((num_blocks + 31) / 32) * 32);
uint32_t tg_size_blocks = std::min(1024u, c10::metal::round_up(num_blocks, 32u));
[computeEncoder dispatchThreads:MTLSizeMake(tg_size_blocks, 1, 1)
threadsPerThreadgroup:MTLSizeMake(tg_size_blocks, 1, 1)];
}
Expand Down
7 changes: 1 addition & 6 deletions aten/src/ATen/native/mps/operations/Linear.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@
#include <ATen/ops/linear_backward_native.h>
#include <ATen/ops/linear_native.h>

// MTLGPUFamilyApple10 is only defined in the macOS 26+ SDK.
#if !defined(__MAC_26_0)
static constexpr auto MTLGPUFamilyApple10 = static_cast<MTLGPUFamily>(1010);
#endif

namespace at::native {

using namespace mps;
Expand All @@ -20,7 +15,7 @@
// non-deterministic results for >2D fp16/bf16 inputs on Apple M5+ (Apple10 GPU family).
// Flatten to 2D to work around the issue (See https://github.com/pytorch/pytorch/issues/180776 )
static bool needs_nd_workaround(const Tensor& input) {
static const bool is_m5_or_newer = [MPSDevice::getInstance()->device() supportsFamily:MTLGPUFamilyApple10];
static const bool is_m5_or_newer = is_apple_family_or_newer(AppleGPUFamily::APPLE_10_PLUS);
return input.dim() > 2 && is_m5_or_newer && (input.scalar_type() == kHalf || input.scalar_type() == kBFloat16);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ maml_omniglot,pass,0



microbench_unbacked_tolist_sum,fail_to_run,0
microbench_unbacked_tolist_sum,pass,0



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ inception_v3,pass,6



mobilenetv2_100,pass,7
mobilenetv2_100,pass_due_to_skip,7



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ inception_v3,pass,6



mobilenetv2_100,pass,7
mobilenetv2_100,pass_due_to_skip,7



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ inception_v3,pass,6



mobilenetv2_100,pass,7
mobilenetv2_100,pass_due_to_skip,7



Expand Down
4 changes: 2 additions & 2 deletions test/cpython/v3_13/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,8 @@ class BadException(Exception):
def __init__(self_):
raise RuntimeError("can't instantiate BadException")

class InvalidException:
pass
class InvalidException:
pass

@unittest.skipIf(_testcapi is None, "requires _testcapi")
def test_capi1():
Expand Down
12 changes: 9 additions & 3 deletions test/dynamo/test_aot_autograd.py
Original file line number Diff line number Diff line change
Expand Up @@ -1950,9 +1950,15 @@ def test_partitioner_saves_unreplaced_input_symbols_for_bw(self):
joint, [], [derived_node], num_fwd_outputs=1
)
bw_placeholders = list(bw_graph.graph.find_nodes(op="placeholder"))
# The backward binds the unreplaced symbol u0 (needed by runtime
# assertions, which preserve raw placeholder expressions) *and* the
# replacement target s0 (needed by sizevar codegen and FxGraphCache
# guards, which use ShapeEnv replacements). Binding only u0 leaves s0
# undefined in the backward, surfacing as a KeyError during backward
# FxGraphCache guard evaluation.
self.assertEqual(
[node.meta["val"].node._expr for node in bw_placeholders],
[u0, u0 + 1],
[s0, u0, u0 + 1],
)

graph_inputs = [node.meta["val"] for node in bw_placeholders]
Expand All @@ -1964,14 +1970,14 @@ def test_partitioner_saves_unreplaced_input_symbols_for_bw(self):

self.assertEqual(
[lowering.graph_inputs[name] for name in lowering.graph_input_names],
[u1, u1 + 1],
[s0, u1, u1 + 1],
)
self.assertEqual(
[
lowering.graph_inputs[name].xreplace({u1: s0})
for name in lowering.graph_input_names
],
[s0, s0 + 1],
[s0, s0, s0 + 1],
)

def test_batched_matmul_inference_mode(self):
Expand Down
16 changes: 16 additions & 0 deletions test/dynamo/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,22 @@ def test_tvm(self, device):
"tvm", device, boxed=False, backward=False, options={"opt_level": 0}
)

@unittest.skipIf(not has_tvm(), "requires tvm")
def test_tvm_scalar_tensor_input(self, device):
class ScalarParam(torch.nn.Module):
def __init__(self):
super().__init__()
self.scale = torch.nn.Parameter(torch.tensor(3.0))

def forward(self, x):
return x + self.scale

model = ScalarParam().eval().to(device)
x = torch.randn(2, 10, device=device)
expected = model(x)
compiled = torch.compile(model, backend="tvm")
self.assertTrue(same(expected, compiled(x), tol=0.01))

def test_tvm_scheduler_backends(self, device):
from torch._dynamo.backends.tvm import tvm_auto_scheduler, tvm_meta_schedule

Expand Down
95 changes: 95 additions & 0 deletions test/dynamo/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,30 @@ def fn(x):
):
opt_fn(torch.ones(1))

def test_raise_non_exception_type_error(self):
# PyExceptionClass_Check must reject non-exception builtins: they are
# BuiltinVariables but not BaseException subclasses.
def fn(x):
try:
raise int
except TypeError as e:
return x.sin(), str(e)

x = torch.randn(4)
opt_fn = torch.compile(fn, backend="eager", fullgraph=True)
self.assertEqual(fn(x), opt_fn(x))

def test_raise_from_non_exception_type_error(self):
def fn(x):
try:
raise ValueError("v") from dict
except TypeError as e:
return x.sin(), str(e)

x = torch.randn(4)
opt_fn = torch.compile(fn, backend="eager", fullgraph=True)
self.assertEqual(fn(x), opt_fn(x))

def test_builtin_arg_count_type_errors(self):
def check(fn):
x = torch.randn(4)
Expand Down Expand Up @@ -937,6 +961,77 @@ def fn(t):
self.assertIsInstance(v.__context__, ValueError)
self.assertIsInstance(v.__cause__, RuntimeError)

def test_reconstruct_AttributeError(self):
sentinel = object()

@torch.compile(backend="eager", fullgraph=True)
def fn(t):
return t.sin(), AttributeError("boom", name="myattr", obj=sentinel)

t = torch.randn(2)
y, v = fn(t)
self.assertEqual(y, t.sin())
self.assertIsInstance(v, AttributeError)
self.assertEqual(v.args, ("boom",))
self.assertEqual(v.name, "myattr")
self.assertIs(v.obj, sentinel)

def test_reconstruct_AttributeError_from_getattr(self):
class Foo:
bar = 1

@torch.compile(backend="eager", fullgraph=True)
def fn(t):
obj = Foo()
try:
obj.missing
except AttributeError as e:
return t.sin(), e

t = torch.randn(2)
y, v = fn(t)
self.assertEqual(y, t.sin())
self.assertIsInstance(v, AttributeError)
self.assertEqual(v.name, "missing")

def test_reconstruct_NameError(self):
@torch.compile(backend="eager", fullgraph=True)
def fn(t):
return t.sin(), NameError("boom", name="myvar")

t = torch.randn(2)
y, v = fn(t)
self.assertEqual(y, t.sin())
self.assertIsInstance(v, NameError)
self.assertEqual(v.args, ("boom",))
self.assertEqual(v.name, "myvar")

def test_reconstruct_NameError_from_undefined(self):
@torch.compile(backend="eager", fullgraph=True)
def fn(t):
try:
undefined_name
except NameError as e:
return t.sin(), e

t = torch.randn(2)
y, v = fn(t)
self.assertEqual(y, t.sin())
self.assertIsInstance(v, NameError)
self.assertEqual(v.name, "undefined_name")

def test_reconstruct_StopIteration(self):
@torch.compile(backend="eager", fullgraph=True)
def fn(t):
return t.sin(), StopIteration(42)

t = torch.randn(2)
y, v = fn(t)
self.assertEqual(y, t.sin())
self.assertIsInstance(v, StopIteration)
self.assertEqual(v.args, (42,))
self.assertEqual(v.value, 42)

def test_raise_GeneratorExit(self):
# GeneratorExit does not inherit from Exception
@torch.compile(backend="eager", fullgraph=True)
Expand Down
Loading