已合并
feat(_inductor): add ascendc backend support for aclgraph capture/replay #40263
feat(_inductor): add ascendc backend support for aclgraph capture/replay #40263
已合并
dingdairong创建于 7月7日
4 个文件变更+130-14
@@ -0,0 +1,53 @@
1+"""AscendC backend: basic compilation and numeric correctness."""
2+import unittest
3+import torch
4+import torch_npu
5+from torch.testing._internal.common_utils import (
6+ instantiate_parametrized_tests,
7+ parametrize,
8+ run_tests,
9+ TestCase,
10+)
11+ 
12+ 
13+@unittest.skipIf(not torch.npu.is_available(), "requires an NPU device")
14+class TestAscendcBasic(TestCase):
15+ 
16+ @classmethod
17+ def setUpClass(cls):
18+ super().setUpClass()
19+ cls._ascendc_ok = False
20+ try:
21+ x = torch.randn(4, 4, device="npu")
22+ torch.compile(lambda t: t + 1, backend="inductor",
23+ options={"npu_backend": "ascendc"})(x)
24+ cls._ascendc_ok = True
25+ except Exception:
26+ pass
27+ 
28+ def setUp(self):
29+ super().setUp()
30+ if not self._ascendc_ok:
31+ self.skipTest("ascendc backend not available")
32+ 
33+ @parametrize("dtype", [torch.float32, torch.float16])
34+ def test_mul_sub(self, dtype):
35+ """Pointwise pattern: compiled output matches eager."""
36+ def fn(x, y):
37+ return (x * y - x)
38+ 
39+ x = torch.randn(64, 64, dtype=dtype, device="npu")
40+ y = torch.randn(64, 64, dtype=dtype, device="npu")
41+ 
42+ eager_out = fn(x, y)
43+ compiled_fn = torch.compile(fn, backend="inductor",
44+ options={"npu_backend": "ascendc"})
45+ compiled_out = compiled_fn(x, y)
46+ 
47+ torch.testing.assert_close(compiled_out, eager_out, rtol=1e-3, atol=1e-3)
48+ 
49+ 
50+instantiate_parametrized_tests(TestAscendcBasic)
51+ 
52+if __name__ == "__main__":
53+ run_tests()
@@ -0,0 +1,52 @@
1+"""AscendC backend: reduce-overhead mode (aclgraph capture/replay)."""
2+import unittest
3+import torch
4+import torch_npu
5+from torch.testing._internal.common_utils import run_tests, TestCase
6+ 
7+ 
8+@unittest.skipIf(not torch.npu.is_available(), "requires an NPU device")
9+class TestAscendcReduceOverhead(TestCase):
10+ 
11+ @classmethod
12+ def setUpClass(cls):
13+ super().setUpClass()
14+ cls._ascendc_ok = False
15+ try:
16+ x = torch.randn(4, 4, device="npu")
17+ torch.compile(lambda t: t + 1, backend="inductor",
18+ options={"npu_backend": "ascendc"})(x)
19+ cls._ascendc_ok = True
20+ except Exception:
21+ pass
22+ 
23+ def setUp(self):
24+ super().setUp()
25+ if not self._ascendc_ok:
26+ self.skipTest("ascendc backend not available")
27+ 
28+ def test_capture_replay(self):
29+ """Verify reduce-overhead triggers graph capture and results are correct."""
30+ def fn(x, y):
31+ return x * y - x
32+ 
33+ x = torch.randn(64, 64, device="npu")
34+ y = torch.randn(64, 64, device="npu")
35+ 
36+ compiled_fn = torch.compile(
37+ fn, backend="inductor",
38+ options={"npu_backend": "ascendc", "triton.cudagraphs": True},
39+ )
40+ 
41+ # Warmup (triggers compilation + first capture)
42+ with torch.no_grad():
43+ for _ in range(3):
44+ out = compiled_fn(x, y)
45+ 
46+ # Verify correctness
47+ eager_out = fn(x, y)
48+ torch.testing.assert_close(out, eager_out, rtol=1e-3, atol=1e-3)
49+ 
50+ 
51+if __name__ == "__main__":
52+ run_tests()
@@ -6,18 +6,30 @@ from .graph import patch_codegen_with_cpp_wrapper
6from .utils import patch_has_triton, patch_device_supports_tma, patch_is_gpu, get_current_raw_stream6from .utils import patch_has_triton, patch_device_supports_tma, patch_is_gpu, get_current_raw_stream
7from ._npu_meta_registration import npu_patch_meta7from ._npu_meta_registration import npu_patch_meta
8 8 
9+# 顶层 patch:所有 inductor backend(triton / mlir / dvm / ascendc)都需要的 NPU 设备级patch,
10+# 与 codegen 后端选择无关,在任何 backend loader 之前无条件执行
9npu_patch_meta()11npu_patch_meta()
10register_device_op_overrides_npu()12register_device_op_overrides_npu()
11-patch_has_triton()13+ 
12-patch_is_gpu()14+ 
13-patch_device_supports_tma()15+def _apply_common_patches():
14-patch_codegen_with_cpp_wrapper()16+ # triton / mlir 后端共用的 patch
15-patch_cache_base_get_system()17+ patch_has_triton()
18+ patch_is_gpu()
19+ patch_device_supports_tma()
20+ patch_codegen_with_cpp_wrapper()
21+ patch_cache_base_get_system()
22+ 
16 23 
17def _get_backend() -> str:24def _get_backend() -> str:
18 return os.getenv("TORCHINDUCTOR_NPU_BACKEND", "default")25 return os.getenv("TORCHINDUCTOR_NPU_BACKEND", "default")
19 26 
27+ 
28+def _load_ascendc_backend():
29+ from . import ascendc
atomgit-bot
atomgit-botatomgit-bot7月7日

🟠 High Priority

changed line: from . import ascendc (init.py line 32)

该 DIFF 在 _BACKEND_LOADERS 中注册了 "ascendc": _load_ascendc_backend,但 torch_npu/_inductor/ 目录下不存在 ascendc Python 包(既无 .py 文件也无 .so 编译产物,经 glob 全仓库扫描确认)。

当用户设置 TORCHINDUCTOR_NPU_BACKEND=ascendc 时,_load_backend()_load_ascendc_backend()from . import ascendc 将抛出 ImportError,导致 inductor 后端加载失败。

如果 ascendc 包计划在后续 PR 中添加,建议将 _load_ascendc_backend 函数及 _BACKEND_LOADERS 中的注册条目与 ascendc 包一并合入,而不是提前提交。

建议:方案一:将 _load_ascendc_backend_BACKEND_LOADERS["ascendc"] 的注册与 ascendc 包的添加放在同一个 PR 中合入。方案二:在 _load_ascendc_backend 中添加 try/except 并提供清晰的错误提示,例如 raise ImportError("ascendc backend is not yet available...")

likedislike
不准确?
dingdairong
7月8日 评论:
30+ 
20def _load_mlir_backend():31def _load_mlir_backend():
32+ _apply_common_patches()
21 import torch33 import torch
22 try:34 try:
23 import torch_mlir35 import torch_mlir
@@ -35,6 +47,7 @@ def _load_mlir_backend():
35 47 
36 48 
37def _load_dvm_backend():49def _load_dvm_backend():
50+ _apply_common_patches()
38 import torch51 import torch
39 from .ascend_npu_ir.ascend_npu_ir.npu import npu_inductor_plugin52 from .ascend_npu_ir.ascend_npu_ir.npu import npu_inductor_plugin
40 from .lowering_patch import apply_mlir_inductor_patch53 from .lowering_patch import apply_mlir_inductor_patch
@@ -47,6 +60,7 @@ def _load_dvm_backend():
47 60 
48 61 
49def _load_triton_backend():62def _load_triton_backend():
63+ _apply_common_patches()
50 import os64 import os
51 import torch65 import torch
52 has_triton = torch.utils._triton.has_triton()66 has_triton = torch.utils._triton.has_triton()
@@ -169,6 +183,7 @@ def _load_triton_backend():
169_BACKEND_LOADERS = {183_BACKEND_LOADERS = {
170 "mlir": _load_mlir_backend,184 "mlir": _load_mlir_backend,
171 "dvm": _load_dvm_backend,185 "dvm": _load_dvm_backend,
186+ "ascendc": _load_ascendc_backend,
172 "default": _load_triton_backend,187 "default": _load_triton_backend,
173}188}
174 189 
@@ -1,8 +1,6 @@
1import logging1import logging
2import os # noqa: C1012import os # noqa: C101
3 3 
4-from triton.runtime.driver import driver
5- 
6import torch4import torch
7from torch._inductor import config5from torch._inductor import config
8 6 
@@ -17,13 +15,11 @@ config.trace.enabled = True
17 15 
18config.fallback_random = True16config.fallback_random = True
19 17 
20-# npu hardware params from trion
21-target = driver.active.get_current_target()
22-device = driver.active.get_current_device()
23-prop = driver.active.utils.get_device_properties(device)
24 18 
25-num_cube_core = prop["num_aicore"]19+device = torch.npu.current_device()
26-num_vector_core = prop["num_aicore"]20+prop = torch.npu.get_device_properties(device)
21+num_cube_core = prop.cube_core_num
22+num_vector_core = prop.vector_core_num
27 23 
28# unit byte24# unit byte
29npu_block = 3225npu_block = 32
@@ -112,7 +108,7 @@ acc_comp_tol = {
112 "default": {"rtol": 1.3e-6, "atol": 1e-5},108 "default": {"rtol": 1.3e-6, "atol": 1e-5},
113}109}
114 110 
115-if "Ascend910B" in target.arch:111+if "Ascend910B" in prop.name:
116 num_vector_core = num_cube_core * 2112 num_vector_core = num_cube_core * 2
117 113 
118log_level_env = os.getenv("INDUCTOR_ASCEND_LOG_LEVEL", "WARNING").upper()114log_level_env = os.getenv("INDUCTOR_ASCEND_LOG_LEVEL", "WARNING").upper()