ZhengyangZhang commited on
Commit
3df3613
·
verified ·
1 Parent(s): 0867b0c

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/torch/_awaits/__init__.py +53 -0
  2. lib/python3.12/site-packages/torch/_awaits/__pycache__/__init__.cpython-312.pyc +0 -0
  3. lib/python3.12/site-packages/torch/_dispatch/__init__.py +0 -0
  4. lib/python3.12/site-packages/torch/_dispatch/__pycache__/__init__.cpython-312.pyc +0 -0
  5. lib/python3.12/site-packages/torch/_dispatch/__pycache__/python.cpython-312.pyc +0 -0
  6. lib/python3.12/site-packages/torch/_dispatch/python.py +180 -0
  7. lib/python3.12/site-packages/torch/_inductor/__init__.py +292 -0
  8. lib/python3.12/site-packages/torch/_inductor/aoti_eager.py +299 -0
  9. lib/python3.12/site-packages/torch/_inductor/autoheuristic/__init__.py +0 -0
  10. lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/__init__.cpython-312.pyc +0 -0
  11. lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/autoheuristic.cpython-312.pyc +0 -0
  12. lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/autoheuristic_utils.cpython-312.pyc +0 -0
  13. lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/learned_heuristic_controller.cpython-312.pyc +0 -0
  14. lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/learnedheuristic_interface.cpython-312.pyc +0 -0
  15. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MMRankingA100.py +296 -0
  16. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MMRankingH100.py +321 -0
  17. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MixedMMA100.py +150 -0
  18. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MixedMMH100.py +149 -0
  19. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_PadMMA100.py +109 -0
  20. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__init__.py +0 -0
  21. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MMRankingA100.cpython-312.pyc +0 -0
  22. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MMRankingH100.cpython-312.pyc +0 -0
  23. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MixedMMA100.cpython-312.pyc +0 -0
  24. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MixedMMH100.cpython-312.pyc +0 -0
  25. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_PadMMA100.cpython-312.pyc +0 -0
  26. lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/__init__.cpython-312.pyc +0 -0
  27. lib/python3.12/site-packages/torch/_inductor/autoheuristic/autoheuristic.py +315 -0
  28. lib/python3.12/site-packages/torch/_inductor/autoheuristic/autoheuristic_utils.py +339 -0
  29. lib/python3.12/site-packages/torch/_inductor/autoheuristic/learned_heuristic_controller.py +119 -0
  30. lib/python3.12/site-packages/torch/_inductor/autoheuristic/learnedheuristic_interface.py +92 -0
  31. lib/python3.12/site-packages/torch/_inductor/autotune_process.py +931 -0
  32. lib/python3.12/site-packages/torch/_inductor/bounds.py +141 -0
  33. lib/python3.12/site-packages/torch/_inductor/choices.py +314 -0
  34. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/__init__.cpython-312.pyc +0 -0
  35. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/aoti_hipify_utils.cpython-312.pyc +0 -0
  36. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/block_analysis.cpython-312.pyc +0 -0
  37. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_bmm_template.cpython-312.pyc +0 -0
  38. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_flex_attention_template.cpython-312.pyc +0 -0
  39. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_gemm_template.cpython-312.pyc +0 -0
  40. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_micro_gemm.cpython-312.pyc +0 -0
  41. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_template.cpython-312.pyc +0 -0
  42. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_template_kernel.cpython-312.pyc +0 -0
  43. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_utils.cpython-312.pyc +0 -0
  44. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_wrapper_cpu_array_ref.cpython-312.pyc +0 -0
  45. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_wrapper_gpu.cpython-312.pyc +0 -0
  46. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpu_device_op_overrides.cpython-312.pyc +0 -0
  47. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cuda_combined_scheduling.cpython-312.pyc +0 -0
  48. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/debug_utils.cpython-312.pyc +0 -0
  49. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/halide.cpython-312.pyc +0 -0
  50. lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/memory_planning.cpython-312.pyc +0 -0
lib/python3.12/site-packages/torch/_awaits/__init__.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from typing import Generic, TypeVar
4
+
5
+ import torch
6
+
7
+ __all__ = ['Await']
8
+
9
+ W = TypeVar("W")
10
+
11
+ class _PyAwaitMeta(type(torch._C._Await), type(Generic)): # type: ignore[misc, no-redef]
12
+ pass
13
+
14
+ class _Await(torch._C._Await, Generic[W], metaclass=_PyAwaitMeta):
15
+ r"""
16
+ Wrapper around a ``torch._C.Await`` which encapsulates delayed execution
17
+ of a callable. All manipulations happen with functions ``torch.jit._awaitable``,
18
+ ``torch.jit._awaitable_wait``, ``torch.jit._awaitable_nowait``.
19
+
20
+ Torch scriptable manipulations:
21
+ ``torch.jit._awaitable(func, *args)``
22
+ Creates ``Await[W]`` object, where W is return type of func.
23
+
24
+ Returns:
25
+ ``torch.jit._awaitable_wait(Await[W])``
26
+ Returns the result of the function, specified at ``_awaitable``, with specified arguments.
27
+
28
+ Returns:
29
+ The result of type ``W`` of the function call. The result is owned by ``Await[W]``
30
+ and returned on all following ``_awaitable_wait`` calls.
31
+
32
+
33
+ ``torch.jit._awaitable_nowait(W)``
34
+ Returns:
35
+ Trivial ``Await[W]`` with specified result.
36
+
37
+
38
+ Only in eager mode:
39
+ ``fn() -> Callable[Tuple[Any], W]``
40
+ Returns:
41
+ Specified at ``_awaitable`` python function ``func``.
42
+
43
+ ``args() -> Tuple[Any]``
44
+ Returns:
45
+ Specified at ``_awaitable`` python args.
46
+
47
+ ``is_nowait() -> _bool``
48
+ Returns:
49
+ ``True`` if this object was created via ``_awaitable_nowait`` call (trivial `Await[W]`).
50
+
51
+ In eager mode ``Await[W]`` can be used as ``W`` i.e. attributes of W can be called on ``Await[W]``,
52
+ ``_awaitable_wait()`` call will be transparently added.
53
+ """
lib/python3.12/site-packages/torch/_awaits/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (2.26 kB). View file
 
lib/python3.12/site-packages/torch/_dispatch/__init__.py ADDED
File without changes
lib/python3.12/site-packages/torch/_dispatch/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (194 Bytes). View file
 
lib/python3.12/site-packages/torch/_dispatch/__pycache__/python.cpython-312.pyc ADDED
Binary file (11 kB). View file
 
lib/python3.12/site-packages/torch/_dispatch/python.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ import itertools
3
+ import unittest.mock
4
+ from contextlib import contextmanager
5
+ from typing import Iterator
6
+
7
+ import torch
8
+ import torch._C
9
+ import torch._ops
10
+ import torch.utils._python_dispatch
11
+ import torch.utils._pytree as pytree
12
+
13
+
14
+ __all__ = ["enable_python_dispatcher", "no_python_dispatcher", "enable_pre_dispatch"]
15
+
16
+ no_python_dispatcher = torch._C._DisablePythonDispatcher
17
+ enable_python_dispatcher = torch._C._EnablePythonDispatcher
18
+ enable_pre_dispatch = torch._C._EnablePreDispatch
19
+
20
+ CROSSREF_FUNCTIONALIZE = False
21
+
22
+
23
+ def all_py_loaded_overloads() -> Iterator[torch._ops.OpOverload]:
24
+ """
25
+ Warning: the set of overloads this will report is very subtle. It is precisely
26
+ the set of torch.ops functions that have actually been accessed from Python
27
+ (e.g., we actually called torch.ops.aten.blah at some point. This is DIFFERENT
28
+ from the set of registered operators, which will in general be a larger set,
29
+ as this would include all operators which we ran C++ static initializers or
30
+ Python operator registration on. This does not eagerly populate the list on
31
+ torch.ops.aten; this list is lazy!
32
+
33
+ In other words, this is good for traversing over everything that has an
34
+ OpOverload object allocated in Python. We use it for cache invalidation, but
35
+ don't rely on this list being complete.
36
+
37
+ Note that even if we did report all C++ registered overloads, this isn't guaranteed
38
+ to be complete either, as a subsequent lazy load of a library which triggers more
39
+ registrations could add more things to the set.
40
+ """
41
+ for ns in torch.ops:
42
+ packets = getattr(torch.ops, ns)
43
+ for op_name in packets:
44
+ packet = getattr(packets, op_name)
45
+ for overload in packet:
46
+ yield getattr(packet, overload)
47
+
48
+
49
+ @contextmanager
50
+ def suspend_functionalization():
51
+ f_tls = torch._C._dispatch_tls_is_dispatch_key_included(
52
+ torch._C.DispatchKey.Functionalize
53
+ )
54
+ f_rv = torch._C._functionalization_reapply_views_tls()
55
+ if f_tls:
56
+ torch._disable_functionalization()
57
+ try:
58
+ yield
59
+ finally:
60
+ if f_tls:
61
+ torch._enable_functionalization(reapply_views=f_rv)
62
+
63
+
64
+ def check_tensor_metadata_matches(nv, rv, desc):
65
+ assert callable(desc)
66
+ assert nv.size() == rv.size(), f"{desc()}: sizes {nv.size()} != {rv.size()}"
67
+ assert nv.dtype == rv.dtype, f"{desc()}: dtype {nv.dtype} != {rv.dtype}"
68
+ same_strides, idx = torch._prims_common.check_significant_strides(
69
+ nv, rv, only_cuda=False
70
+ )
71
+ assert (
72
+ same_strides
73
+ ), f"{desc()}: strides {nv.stride()} != {rv.stride()} (mismatch at index {idx})"
74
+
75
+
76
+ def check_metadata_matches(n, r, desc):
77
+ assert callable(desc)
78
+ n_vals, n_spec = pytree.tree_flatten(n)
79
+ r_vals, r_spec = pytree.tree_flatten(r)
80
+ # TODO: test the specs match; empirically sometimes we have a tuple
81
+ # on one side and a list on the other
82
+ assert len(n_vals) == len(r_vals), f"{len(n_vals)} != {len(r_vals)}"
83
+ for i, nv, rv in zip(range(len(n_vals)), n_vals, r_vals):
84
+ if not isinstance(rv, torch.Tensor):
85
+ continue
86
+ check_tensor_metadata_matches(nv, rv, lambda: f"{desc()} output {i}")
87
+
88
+
89
+ class Lit:
90
+ def __init__(self, s):
91
+ self.s = s
92
+
93
+ def __repr__(self):
94
+ return self.s
95
+
96
+
97
+ def _fmt(a: object) -> object:
98
+ if isinstance(a, torch.Tensor):
99
+ return Lit(
100
+ f"torch.empty_strided({tuple(a.size())}, {a.stride()}, dtype={a.dtype})"
101
+ )
102
+ else:
103
+ return a
104
+
105
+
106
+ def make_crossref_functionalize(op, final_key):
107
+ from torch._subclasses.fake_tensor import FakeTensorMode
108
+
109
+ # This case is pretty weird, suppress it for now
110
+ if op == torch.ops.aten.lift_fresh.default:
111
+ return final_key
112
+
113
+ def handler(*args, **kwargs):
114
+ fake_mode = FakeTensorMode()
115
+
116
+ def fakeify_defun(t):
117
+ if isinstance(t, torch.Tensor):
118
+ if torch._is_functional_tensor(t):
119
+ r = torch._from_functional_tensor(t)
120
+ # NB: This assumes that the inner tensor sizes/strides match
121
+ # the outer tensor sizes/strides. This doesn't necessarily have to
122
+ # be the case, see discussion at
123
+ # https://github.com/pytorch/pytorch/pull/87610/files/401ddeda1d769bedc88a12de332c7357b60e51a4#r1007264456
124
+ assert t.size() == r.size()
125
+ assert t.stride() == r.stride()
126
+ else:
127
+ r = t
128
+ # TODO: suppress guards
129
+ return fake_mode.from_tensor(r)
130
+ return t
131
+
132
+ def maybe_detach(t):
133
+ if isinstance(t, torch.Tensor):
134
+ return t.detach()
135
+ else:
136
+ return t
137
+
138
+ # TODO: This probably does the wrong thing if you're running other
139
+ # substantive modes with the normal op outside here
140
+ with torch.utils._python_dispatch._disable_current_modes(), suspend_functionalization():
141
+ f_args, f_kwargs = pytree.tree_map(fakeify_defun, (args, kwargs))
142
+ orig_f_args, orig_f_kwargs = pytree.tree_map(
143
+ maybe_detach, (f_args, f_kwargs)
144
+ )
145
+ with fake_mode:
146
+ f_r = op(*f_args, **f_kwargs)
147
+ r = op._op_dk(final_key, *args, **kwargs)
148
+
149
+ def desc():
150
+ fmt_args = ", ".join(
151
+ itertools.chain(
152
+ (repr(pytree.tree_map(_fmt, a)) for a in orig_f_args),
153
+ (
154
+ f"{k}={pytree.tree_map(_fmt, v)}"
155
+ for k, v in orig_f_kwargs.items()
156
+ ),
157
+ )
158
+ )
159
+ return f"{op}({fmt_args})"
160
+
161
+ check_metadata_matches(f_r, r, desc)
162
+ return r
163
+
164
+ return handler
165
+
166
+
167
+ # NB: enabling this is slow, don't do it in a hot loop. This is purely
168
+ # for debugging purposes.
169
+ @contextmanager
170
+ def enable_crossref_functionalize():
171
+ for op in all_py_loaded_overloads():
172
+ op._uncache_dispatch(torch._C.DispatchKey.Functionalize)
173
+ try:
174
+ with enable_python_dispatcher(), unittest.mock.patch(
175
+ "torch._dispatch.python.CROSSREF_FUNCTIONALIZE", True
176
+ ):
177
+ yield
178
+ finally:
179
+ for op in all_py_loaded_overloads():
180
+ op._uncache_dispatch(torch._C.DispatchKey.Functionalize)
lib/python3.12/site-packages/torch/_inductor/__init__.py ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ from __future__ import annotations
3
+
4
+ import io
5
+ import logging
6
+ import os
7
+ from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING, Union
8
+
9
+ import torch._inductor.config
10
+ import torch.fx
11
+
12
+
13
+ if TYPE_CHECKING:
14
+ from torch._inductor.utils import InputType
15
+ from torch.export import ExportedProgram
16
+
17
+
18
+ __all__ = [
19
+ "compile",
20
+ "list_mode_options",
21
+ "list_options",
22
+ "cudagraph_mark_step_begin",
23
+ ]
24
+
25
+
26
+ log = logging.getLogger(__name__)
27
+
28
+
29
+ def compile(
30
+ gm: torch.fx.GraphModule,
31
+ example_inputs: List[InputType],
32
+ options: Optional[Dict[str, Any]] = None,
33
+ ):
34
+ """
35
+ Compile a given FX graph with TorchInductor. This allows compiling
36
+ FX graphs captured without using TorchDynamo.
37
+
38
+ Args:
39
+ gm: The FX graph to compile.
40
+ example_inputs: List of tensor inputs.
41
+ options: Optional dict of config options. See `torch._inductor.config`.
42
+
43
+ Returns:
44
+ Callable with same behavior as gm but faster.
45
+ """
46
+ from .compile_fx import compile_fx
47
+
48
+ return compile_fx(gm, example_inputs, config_patches=options)
49
+
50
+
51
+ def aoti_compile_and_package(
52
+ exported_program: ExportedProgram,
53
+ _deprecated_unused_args=None,
54
+ _deprecated_unused_kwargs=None,
55
+ *,
56
+ package_path: Optional[Union[str, io.BytesIO]] = None,
57
+ inductor_configs: Optional[Dict[str, Any]] = None,
58
+ ) -> str:
59
+ """
60
+ Compiles the exported program with AOTInductor, and packages it into a .pt2
61
+ artifact specified by the input package_path. To load the package, you can
62
+ call `torch._inductor.aoti_load_package(package_path)`.
63
+
64
+ To compile and save multiple models into a single .pt2 artifact, you can do
65
+ the following:
66
+ ```
67
+ ep1 = torch.export.export(M1(), ...)
68
+ aoti_file1 = torch._inductor.aot_compile(ep1, ...)
69
+ ep2 = torch.export.export(M2(), ...)
70
+ aoti_file2 = torch._inductor.aot_compile(ep2, ...)
71
+
72
+ from torch._inductor.package import package_aoti, load_package
73
+ package_aoti("my_package.pt2", {"model1": aoti_file1, "model2": aoti_file2})
74
+
75
+ compiled_model1 = load_package("my_package.pt2", "model1")
76
+ compiled_model2 = load_package("my_package.pt2", "model2")
77
+ ```
78
+
79
+ Args:
80
+ exported_program: An exported program created through a call from torch.export
81
+ package_path: Optional specified path to the generated .pt2 artifact.
82
+ inductor_configs: Optional dictionary of configs to control inductor.
83
+
84
+ Returns:
85
+ Path to the generated artifact
86
+ """
87
+ from torch.export import ExportedProgram
88
+
89
+ from .debug import aot_inductor_minifier_wrapper
90
+
91
+ if not isinstance(exported_program, ExportedProgram):
92
+ raise ValueError("Only ExportedProgram is supported")
93
+
94
+ if exported_program.example_inputs is None:
95
+ raise RuntimeError(
96
+ "exported_program.example_inputs is required to be set in order "
97
+ "for AOTInductor compilation."
98
+ )
99
+
100
+ if _deprecated_unused_args is not None or _deprecated_unused_kwargs is not None:
101
+ log.warning(
102
+ "You no longer need to specify args/kwargs to aoti_compile_and_package "
103
+ "as we can get this information from exported_program.example_inputs."
104
+ )
105
+
106
+ assert (
107
+ package_path is None
108
+ or isinstance(package_path, io.BytesIO)
109
+ or (isinstance(package_path, str) and package_path.endswith(".pt2"))
110
+ ), f"Expect package path to be a file ending in .pt2, is None, or is a buffer. Instead got {package_path}"
111
+
112
+ inductor_configs = inductor_configs or {}
113
+ inductor_configs["aot_inductor.package"] = True
114
+
115
+ if inductor_configs.get("aot_inductor.output_path"):
116
+ raise RuntimeError(
117
+ "Please pass in a package path to aot_inductor_compile() instead "
118
+ "of setting the aot_inductor.output_path config."
119
+ )
120
+
121
+ # a wrapper around aoti_compile_and_package_inner.
122
+ return aot_inductor_minifier_wrapper(
123
+ _aoti_compile_and_package_inner,
124
+ exported_program,
125
+ package_path=package_path,
126
+ inductor_configs=inductor_configs,
127
+ )
128
+
129
+
130
+ def _aoti_compile_and_package_inner(
131
+ gm: torch.nn.Module,
132
+ # flat_example_inputs: List[Any],
133
+ args: Tuple[Any],
134
+ kwargs: Optional[Dict[str, Any]] = None,
135
+ *,
136
+ load_and_run: bool = False,
137
+ package_path: Optional[Union[str, io.BytesIO]] = None,
138
+ inductor_configs: Optional[Dict[str, Any]] = None,
139
+ ):
140
+ """
141
+ See docstring for aoti_compile_and_package.
142
+
143
+ If `load_and_run` is True, this function will load the compiled model and run it.
144
+ This is for the minifier to check the correctness of the compiled model.
145
+ """
146
+ from .package import package_aoti
147
+
148
+ assert isinstance(gm, torch.fx.GraphModule)
149
+
150
+ kwargs = kwargs or {}
151
+
152
+ aoti_files = aot_compile(gm, args, kwargs, options=inductor_configs)
153
+ assert isinstance(aoti_files, list)
154
+
155
+ if package_path is None:
156
+ path = [
157
+ os.path.splitext(file)[0]
158
+ for file in aoti_files
159
+ if os.path.splitext(file)[1] == ".so"
160
+ ]
161
+ if len(path) == 0:
162
+ path = [
163
+ os.path.splitext(file)[0]
164
+ for file in aoti_files
165
+ if os.path.splitext(file)[1] == ".cpp"
166
+ ]
167
+ package_path = path[0] + ".pt2"
168
+
169
+ res = package_aoti(package_path, aoti_files)
170
+ assert res == package_path
171
+
172
+ if load_and_run:
173
+ compiled_model = aoti_load_package(package_path)
174
+ aoti_result = compiled_model(*args, **kwargs)
175
+ return package_path
176
+
177
+
178
+ def aoti_load_package(path: Union[str, io.BytesIO]) -> Any: # type: ignore[type-arg]
179
+ """
180
+ Loads the model from the PT2 package.
181
+
182
+ If multiple models were packaged into the PT2, this will load the default
183
+ model. To load a specific model, you can directly call the load API
184
+ ```
185
+ from torch._inductor.package import load_package
186
+
187
+ compiled_model1 = load_package("my_package.pt2", "model1")
188
+ compiled_model2 = load_package("my_package.pt2", "model2")
189
+ ```
190
+
191
+ Args:
192
+ path: Path to the .pt2 package
193
+ """
194
+ from torch._inductor.package import load_package
195
+
196
+ return load_package(path)
197
+
198
+
199
+ def aot_compile(
200
+ gm: torch.fx.GraphModule,
201
+ args: Tuple[Any],
202
+ kwargs: Optional[Dict[str, Any]] = None,
203
+ *,
204
+ options: Optional[Dict[str, Any]] = None,
205
+ ) -> Union[str, List[str]]:
206
+ """
207
+ Ahead-of-time compile a given FX graph with TorchInductor into a shared library.
208
+
209
+ Args:
210
+ gm: The FX graph to compile.
211
+ args: Example arguments
212
+ kwargs: Example keyword arguments
213
+ options: Optional dict of config options. See `torch._inductor.config`.
214
+
215
+ Returns:
216
+ Path to the generated shared library, or a list of files generated by
217
+ AOTI if aot_inductor.package=True.
218
+ TODO: make it return a list by default
219
+ """
220
+ from .compile_fx import _aoti_flatten_inputs, compile_fx_aot
221
+
222
+ flat_example_inputs, options = _aoti_flatten_inputs(
223
+ gm, args, kwargs, options=options
224
+ )
225
+
226
+ return compile_fx_aot(
227
+ gm,
228
+ flat_example_inputs, # type: ignore[arg-type]
229
+ config_patches=options,
230
+ )
231
+
232
+
233
+ def list_mode_options(
234
+ mode: Optional[str] = None, dynamic: Optional[bool] = None
235
+ ) -> Dict[str, Any]:
236
+ r"""Returns a dictionary describing the optimizations that each of the available
237
+ modes passed to `torch.compile()` performs.
238
+
239
+ Args:
240
+ mode (str, optional): The mode to return the optimizations for.
241
+ If None, returns optimizations for all modes
242
+ dynamic (bool, optional): Whether dynamic shape is enabled.
243
+
244
+ Example::
245
+ >>> torch._inductor.list_mode_options()
246
+ """
247
+
248
+ mode_options: Dict[str, Dict[str, bool]] = {
249
+ "default": {},
250
+ # enable cudagraphs
251
+ "reduce-overhead": {
252
+ "triton.cudagraphs": True,
253
+ },
254
+ # enable max-autotune
255
+ "max-autotune-no-cudagraphs": {
256
+ "max_autotune": True,
257
+ "coordinate_descent_tuning": True,
258
+ },
259
+ # enable max-autotune
260
+ # enable cudagraphs
261
+ "max-autotune": {
262
+ "max_autotune": True,
263
+ "triton.cudagraphs": True,
264
+ "coordinate_descent_tuning": True,
265
+ },
266
+ }
267
+ return mode_options[mode] if mode else mode_options # type: ignore[return-value]
268
+
269
+
270
+ def list_options() -> List[str]:
271
+ r"""Returns a dictionary describing the optimizations and debug configurations
272
+ that are available to `torch.compile()`.
273
+
274
+ The options are documented in `torch._inductor.config`.
275
+
276
+ Example::
277
+
278
+ >>> torch._inductor.list_options()
279
+ """
280
+
281
+ from torch._inductor import config
282
+
283
+ current_config: Dict[str, Any] = config.get_config_copy()
284
+
285
+ return list(current_config.keys())
286
+
287
+
288
+ def cudagraph_mark_step_begin():
289
+ "Indicates that a new iteration of inference or training is about to begin."
290
+ from .cudagraph_trees import mark_step_begin
291
+
292
+ mark_step_begin()
lib/python3.12/site-packages/torch/_inductor/aoti_eager.py ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import logging
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Any, Callable, Dict, List, Optional, Tuple
6
+ from unittest import mock
7
+
8
+ import torch
9
+ import torch._export
10
+ from torch._inductor.utils import is_cpu_device
11
+
12
+ from .runtime.runtime_utils import cache_dir
13
+
14
+
15
+ log = logging.getLogger(__name__)
16
+
17
+
18
+ def aoti_eager_cache_dir(namespace: str, device: str) -> Path:
19
+ return Path(cache_dir()) / "aoti_eager" / namespace / device
20
+
21
+
22
+ def aoti_eager_op_conf_lock(op_func_name_with_overload: str) -> Any:
23
+ from filelock import FileLock
24
+
25
+ # Avoid circular import
26
+ from torch._inductor.codecache import get_lock_dir, LOCK_TIMEOUT
27
+
28
+ op_conf_lock_file = f"{op_func_name_with_overload}.lock"
29
+ lock_dir = get_lock_dir()
30
+ return FileLock(os.path.join(lock_dir, op_conf_lock_file), timeout=LOCK_TIMEOUT)
31
+
32
+
33
+ def load_aoti_eager_cache(
34
+ ns: str, op_func_name_with_overload: str, device_type: str
35
+ ) -> List[Optional[Dict[str, Any]]]:
36
+ device_kernel_cache = aoti_eager_cache_dir(ns, device_type)
37
+ op_conf = device_kernel_cache / f"{op_func_name_with_overload}.json"
38
+ if not op_conf.exists():
39
+ return []
40
+
41
+ try:
42
+ with aoti_eager_op_conf_lock(op_func_name_with_overload):
43
+ with open(op_conf) as f:
44
+ json_data = json.load(f)
45
+ for item in json_data:
46
+ # Get absolution path for kernel library
47
+ kernel_lib_abs_path = device_kernel_cache / item["kernel_path"]
48
+ item["kernel_path"] = kernel_lib_abs_path.as_posix()
49
+
50
+ # Check if the kernel library exists
51
+ if not kernel_lib_abs_path.exists():
52
+ return []
53
+
54
+ for metadata in item["meta_info"]:
55
+ if metadata.get("is_dynamic"):
56
+ raise NotImplementedError(
57
+ "Only support static shape for now"
58
+ )
59
+ if (
60
+ "device_type" in metadata
61
+ and metadata["device_type"] == "cpu"
62
+ ):
63
+ metadata["device_index"] = -1
64
+ for dtype_key in ["dtype", "dtype_value"]:
65
+ if dtype_key in metadata:
66
+ metadata[dtype_key] = getattr(
67
+ torch, metadata[dtype_key].split(".")[-1]
68
+ )
69
+ if "layout_value" in metadata:
70
+ metadata["layout_value"] = getattr(
71
+ torch, metadata["layout_value"].split(".")[-1]
72
+ )
73
+ if "memory_format_value" in metadata:
74
+ metadata["memory_format_value"] = getattr(
75
+ torch, metadata["memory_format_value"].split(".")[-1]
76
+ )
77
+
78
+ return json_data
79
+ except Exception as e:
80
+ err_msg = f"Failed to load aoti eager cache: {e}"
81
+ log.exception(err_msg)
82
+ return []
83
+
84
+
85
+ def supported_builtin_dtype_torch_dtype() -> Dict[type, torch.dtype]:
86
+ return {int: torch.int32, float: torch.float, bool: torch.bool}
87
+
88
+
89
+ def supported_scalar_types() -> Tuple[type, ...]:
90
+ type_to_torch_dtype = supported_builtin_dtype_torch_dtype()
91
+ return tuple(type_to_torch_dtype.keys())
92
+
93
+
94
+ def extract_tensor_metadata(dynamic: bool, input: torch.Tensor) -> Dict[str, Any]:
95
+ metadata: Dict[str, Any] = {}
96
+ metadata["is_dynamic"] = dynamic
97
+
98
+ assert isinstance(input, torch.Tensor)
99
+ metadata["device_type"] = f"{input.device.type}"
100
+ if is_cpu_device([input]):
101
+ metadata["device_index"] = -1
102
+ else:
103
+ metadata["device_index"] = input.device.index
104
+ metadata["dtype"] = f"{input.dtype}"
105
+ metadata["sizes"] = list(input.size())
106
+ metadata["strides"] = list(input.stride())
107
+ metadata["requires_grad"] = input.requires_grad
108
+ metadata["dispatch_key_set"] = torch._C._dispatch_keys(input).raw_repr()
109
+ return metadata
110
+
111
+
112
+ def extract_tensor_list_metadata(
113
+ dynamic: bool,
114
+ input: List[torch.Tensor],
115
+ ) -> Dict[str, Any]:
116
+ metadata_list = []
117
+ for item in input:
118
+ assert isinstance(item, torch.Tensor)
119
+ metadata_list.append(extract_tensor_metadata(dynamic, item))
120
+
121
+ metadata: Dict[str, Any] = {}
122
+ metadata["tensor_list"] = metadata_list
123
+ return metadata
124
+
125
+
126
+ def extract_scalar_metadata(device_type: str, input: Any) -> Dict[str, Any]:
127
+ assert isinstance(input, supported_scalar_types())
128
+ metadata: Dict[str, Any] = {}
129
+ metadata["is_dynamic"] = False
130
+ # Scalar tensor
131
+ metadata["device_type"] = device_type
132
+ metadata["device_index"] = -1 if device_type == "cpu" else 0
133
+ type_to_torch_dtype = supported_builtin_dtype_torch_dtype()
134
+ metadata["dtype"] = f"{type_to_torch_dtype[type(input)]}"
135
+ metadata["scalar_value"] = input
136
+ return metadata
137
+
138
+
139
+ def extract_string_metadata(input: str) -> Dict[str, Any]:
140
+ assert isinstance(input, str)
141
+ metadata: Dict[str, Any] = {}
142
+ metadata["string_value"] = input
143
+ return metadata
144
+
145
+
146
+ def extract_dtype_metadata(input: torch.dtype) -> Dict[str, Any]:
147
+ assert isinstance(input, torch.dtype)
148
+ metadata: Dict[str, Any] = {}
149
+ metadata["dtype_value"] = f"{input}"
150
+ return metadata
151
+
152
+
153
+ def extract_device_metadata(input: torch.device) -> Dict[str, Any]:
154
+ assert isinstance(input, torch.device)
155
+ metadata: Dict[str, Any] = {}
156
+ metadata["device_type_value"] = f"{input.type}"
157
+ metadata["device_index_value"] = input.index
158
+ return metadata
159
+
160
+
161
+ def extract_layout_metadata(input: torch.layout) -> Dict[str, Any]:
162
+ assert isinstance(input, torch.layout)
163
+ metadata: Dict[str, Any] = {}
164
+ metadata["layout_value"] = f"{input}"
165
+ return metadata
166
+
167
+
168
+ def aoti_compile_with_persistent_cache(
169
+ ns: str,
170
+ op_func_name_with_overload: str,
171
+ device_type: str,
172
+ dynamic: bool,
173
+ f: Callable[..., Any],
174
+ args: Tuple[Any],
175
+ kwargs: Dict[str, Any],
176
+ *,
177
+ dynamic_shapes: Optional[Dict[str, Any]] = None,
178
+ options: Optional[Dict[str, Any]] = None,
179
+ remove_runtime_assertions: bool = False,
180
+ disable_constraint_solver: bool = False,
181
+ ) -> str:
182
+ """
183
+ Compile the given function with persistent cache for AOTI eager mode.
184
+ """
185
+ assert not dynamic, "Only support static shape for now"
186
+ flattened_inputs = list(args) + list(kwargs.values())
187
+ if not all(
188
+ isinstance(
189
+ input,
190
+ (
191
+ supported_scalar_types(),
192
+ torch.Tensor,
193
+ list,
194
+ str,
195
+ torch.dtype,
196
+ torch.device,
197
+ torch.layout,
198
+ ),
199
+ )
200
+ for input in flattened_inputs
201
+ ):
202
+ err_msg = f"Unsupported input types: {flattened_inputs}"
203
+ log.exception(err_msg)
204
+ raise NotImplementedError(err_msg)
205
+
206
+ for input in flattened_inputs:
207
+ if isinstance(input, list) and not all(
208
+ isinstance(item, torch.Tensor) for item in input
209
+ ):
210
+ err_msg = f"_impl_with_aoti_compile encounters unsupported input types: {flattened_inputs}"
211
+ log.exception(err_msg)
212
+ raise NotImplementedError(err_msg)
213
+
214
+ persistent_cache = aoti_eager_cache_dir(ns, device_type)
215
+ if not persistent_cache.exists():
216
+ persistent_cache.mkdir(parents=True)
217
+
218
+ persistent_cache_lib = persistent_cache / "lib"
219
+ if not persistent_cache_lib.exists():
220
+ persistent_cache_lib.mkdir()
221
+
222
+ with mock.patch.dict(
223
+ os.environ,
224
+ {"TORCHINDUCTOR_CACHE_DIR": persistent_cache_lib.absolute().as_posix()},
225
+ ):
226
+ try:
227
+ kernel_lib_path = torch._export.aot_compile(
228
+ f,
229
+ args,
230
+ kwargs,
231
+ dynamic_shapes=dynamic_shapes,
232
+ remove_runtime_assertions=remove_runtime_assertions,
233
+ disable_constraint_solver=disable_constraint_solver,
234
+ # Some operations may have non-Tensor parameters like int, float, bool. These
235
+ # non-Tensor parameters will not be the input of the graph. Therefore, we do
236
+ # need to keep the same signature.
237
+ same_signature=False,
238
+ )
239
+ assert isinstance(kernel_lib_path, str)
240
+
241
+ kernel_metadata_items = []
242
+
243
+ for idx, input in enumerate(flattened_inputs):
244
+ if isinstance(input, torch.Tensor):
245
+ metadata = extract_tensor_metadata(dynamic, input)
246
+ elif isinstance(input, list):
247
+ assert all(isinstance(item, torch.Tensor) for item in input)
248
+ metadata = extract_tensor_list_metadata(dynamic, input)
249
+ elif isinstance(input, supported_scalar_types()):
250
+ metadata = extract_scalar_metadata(device_type, input)
251
+ elif isinstance(input, str):
252
+ metadata = extract_string_metadata(input)
253
+ elif isinstance(input, torch.dtype):
254
+ metadata = extract_dtype_metadata(input)
255
+ elif isinstance(input, torch.device):
256
+ metadata = extract_device_metadata(input)
257
+ elif isinstance(input, torch.layout):
258
+ metadata = extract_layout_metadata(input)
259
+ else:
260
+ raise NotImplementedError(f"Unsupported input type: {type(input)}")
261
+
262
+ metadata["arg_order"] = idx
263
+ kernel_metadata_items.append(metadata)
264
+
265
+ kernel_meta_info: Dict[str, Any] = {}
266
+ kernel_meta_info["meta_info"] = kernel_metadata_items
267
+ kernel_meta_info["kernel_path"] = (
268
+ Path(kernel_lib_path).relative_to(persistent_cache).as_posix()
269
+ )
270
+
271
+ json_data = []
272
+ update_json = True
273
+ op_conf = persistent_cache / f"{op_func_name_with_overload}.json"
274
+ mode = "r" if op_conf.exists() else "w"
275
+ with aoti_eager_op_conf_lock(op_func_name_with_overload):
276
+ with open(op_conf, mode) as op_conf_file:
277
+ try:
278
+ json_data = json.load(op_conf_file)
279
+ except Exception as e:
280
+ json_data = []
281
+
282
+ assert isinstance(json_data, list)
283
+ for item in json_data:
284
+ assert isinstance(item, dict)
285
+ # Same kernel meta info already exists in the json file
286
+ if item["meta_info"] == kernel_metadata_items:
287
+ update_json = False
288
+ break
289
+
290
+ if update_json:
291
+ json_data.append(kernel_meta_info)
292
+ with open(op_conf, "w") as op_conf_file:
293
+ json.dump(json_data, op_conf_file, indent=4)
294
+
295
+ return kernel_lib_path
296
+ except Exception as e:
297
+ err_msg = f"Failed to compile {op_func_name_with_overload}: {e}"
298
+ log.exception(err_msg)
299
+ return ""
lib/python3.12/site-packages/torch/_inductor/autoheuristic/__init__.py ADDED
File without changes
lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (208 Bytes). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/autoheuristic.cpython-312.pyc ADDED
Binary file (15.7 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/autoheuristic_utils.cpython-312.pyc ADDED
Binary file (17 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/learned_heuristic_controller.cpython-312.pyc ADDED
Binary file (5.25 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/learnedheuristic_interface.cpython-312.pyc ADDED
Binary file (5.21 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MMRankingA100.py ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # flake8: noqa: B950
2
+ # fmt: off
3
+ # This file was generated by AutoHeuristic. Do not modify it manually!
4
+ # To regenerate this file, take a look at the steps in the README.md file inside torchgen/_autoheuristic/mm/
5
+ from typing import List, Optional, Tuple
6
+
7
+ from torch._inductor.autoheuristic.autoheuristic_utils import (
8
+ AHContext,
9
+ AHMetadata,
10
+ Choice,
11
+ )
12
+ from torch._inductor.autoheuristic.learnedheuristic_interface import (
13
+ LearnedHeuristicDecision,
14
+ )
15
+
16
+
17
+ class MMRankingA100(LearnedHeuristicDecision):
18
+
19
+ def __init__(self) -> None:
20
+ self.choices: List[Choice] = []
21
+ self.fill_choices()
22
+
23
+ def check_precondition(self, metadata: AHMetadata, context: AHContext,) -> bool:
24
+ return (
25
+ metadata.name == self.get_name()
26
+ and metadata.shared_memory == 166912
27
+ and str(metadata.device_capa) == "(8, 0)"
28
+ )
29
+
30
+ def get_confidence_threshold(self) -> float:
31
+ return 0.0
32
+
33
+ def get_choice(self, idx: int) -> Optional[str]:
34
+ if idx < len(self.choices):
35
+ return self.choices[idx]
36
+ return None
37
+
38
+ def fill_choices(self) -> None:
39
+ self.choices.append('extern_mm')
40
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=128_BLOCK-N=16_numstages=4_numwarps=8')
41
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=128_BLOCK-N=32_numstages=4_numwarps=8')
42
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=128_BLOCK-N=64_numstages=4_numwarps=8')
43
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=2_numwarps=8')
44
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=3_numwarps=4')
45
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=3_numwarps=8')
46
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=4_numwarps=4')
47
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=5_numwarps=4')
48
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=5_numwarps=8')
49
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=2_numwarps=2')
50
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=2_numwarps=8')
51
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=3_numwarps=4')
52
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=3_numwarps=8')
53
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=4_numwarps=4')
54
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=4_numwarps=8')
55
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=5_numwarps=4')
56
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=5_numwarps=8')
57
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=2_numwarps=2')
58
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=2_numwarps=8')
59
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=3_numwarps=4')
60
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=3_numwarps=8')
61
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=4_numwarps=4')
62
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=4_numwarps=8')
63
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=4')
64
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=8')
65
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=2_numwarps=2')
66
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=2_numwarps=8')
67
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=3_numwarps=4')
68
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=3_numwarps=8')
69
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=4_numwarps=4')
70
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=4_numwarps=8')
71
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=5_numwarps=4')
72
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=5_numwarps=8')
73
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=2_numwarps=8')
74
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=4')
75
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=8')
76
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=4_numwarps=4')
77
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=5_numwarps=4')
78
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=5_numwarps=8')
79
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=2_numwarps=8')
80
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=3_numwarps=4')
81
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=3_numwarps=8')
82
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=4_numwarps=4')
83
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=4_numwarps=8')
84
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=5_numwarps=4')
85
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=5_numwarps=8')
86
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=2_numwarps=2')
87
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=2_numwarps=8')
88
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=3_numwarps=4')
89
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=3_numwarps=8')
90
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=4_numwarps=4')
91
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=4_numwarps=8')
92
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=4')
93
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=8')
94
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=2_numwarps=2')
95
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=2_numwarps=8')
96
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=4')
97
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=8')
98
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=4_numwarps=4')
99
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=4_numwarps=8')
100
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=4')
101
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=8')
102
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=4')
103
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=8')
104
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=4')
105
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=8')
106
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=16_numstages=3_numwarps=4')
107
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=16_numstages=3_numwarps=8')
108
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=16_numstages=4_numwarps=8')
109
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=16_numstages=5_numwarps=4')
110
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=16_numstages=5_numwarps=8')
111
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=32_numstages=3_numwarps=4')
112
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=32_numstages=3_numwarps=8')
113
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=32_numstages=4_numwarps=8')
114
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=32_numstages=5_numwarps=4')
115
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=32_numstages=5_numwarps=8')
116
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=4')
117
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=8')
118
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=64_numstages=4_numwarps=8')
119
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=64_numstages=5_numwarps=4')
120
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=64_numstages=5_numwarps=8')
121
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
122
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=2')
123
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=64_numstages=3_numwarps=4')
124
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=64_numstages=4_numwarps=4')
125
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=64_numstages=5_numwarps=4')
126
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=3_numwarps=4')
127
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=3_numwarps=8')
128
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=4_numwarps=4')
129
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=4_numwarps=8')
130
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=5_numwarps=8')
131
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=16_numstages=5_numwarps=1')
132
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=32_numstages=1_numwarps=2')
133
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=32_numstages=2_numwarps=2')
134
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=32_numstages=3_numwarps=2')
135
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=32_numstages=4_numwarps=2')
136
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=2')
137
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=64_numstages=2_numwarps=4')
138
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=64_numstages=4_numwarps=4')
139
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=64_numstages=5_numwarps=4')
140
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=4')
141
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=128_numstages=4_numwarps=4')
142
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=16_numstages=5_numwarps=1')
143
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=2')
144
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=4')
145
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=64_numstages=4_numwarps=4')
146
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=4')
147
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=4')
148
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=8')
149
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=32_numstages=2_numwarps=2')
150
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=4')
151
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=64_numstages=4_numwarps=4')
152
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=64_numstages=5_numwarps=4')
153
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
154
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=16_numstages=2_numwarps=2')
155
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=32_numstages=2_numwarps=4')
156
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=4')
157
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=64_numstages=3_numwarps=4')
158
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=64_numstages=4_numwarps=8')
159
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=64_numstages=5_numwarps=4')
160
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=16_numstages=1_numwarps=2')
161
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=16_numstages=2_numwarps=2')
162
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=16_numstages=5_numwarps=2')
163
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=32_numstages=1_numwarps=2')
164
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=32_numstages=2_numwarps=4')
165
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=4')
166
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=64_numstages=5_numwarps=8')
167
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=32_BLOCK-N=16_numstages=2_numwarps=2')
168
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=32_BLOCK-N=16_numstages=5_numwarps=2')
169
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=8')
170
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=4')
171
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=4')
172
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=64_BLOCK-N=32_numstages=2_numwarps=4')
173
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
174
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=16_numstages=3_numwarps=4')
175
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=16_numstages=4_numwarps=4')
176
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=16_numstages=5_numwarps=4')
177
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=32_numstages=3_numwarps=4')
178
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=32_numstages=4_numwarps=4')
179
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=4')
180
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=64_numstages=3_numwarps=4')
181
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=64_numstages=4_numwarps=4')
182
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=64_numstages=4_numwarps=8')
183
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=64_numstages=5_numwarps=4')
184
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=128_numstages=3_numwarps=4')
185
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=128_numstages=4_numwarps=4')
186
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=128_numstages=4_numwarps=8')
187
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=16_numstages=2_numwarps=4')
188
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=16_numstages=3_numwarps=4')
189
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=16_numstages=4_numwarps=4')
190
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=16_numstages=5_numwarps=4')
191
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=2_numwarps=4')
192
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=3_numwarps=4')
193
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=3_numwarps=8')
194
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=4_numwarps=4')
195
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=4_numwarps=8')
196
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=4')
197
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=8')
198
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=2_numwarps=4')
199
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=3_numwarps=4')
200
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=3_numwarps=8')
201
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=4_numwarps=4')
202
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=4_numwarps=8')
203
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=5_numwarps=4')
204
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=4')
205
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=128_numstages=4_numwarps=4')
206
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=128_numstages=4_numwarps=8')
207
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=16_numstages=2_numwarps=4')
208
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=16_numstages=3_numwarps=4')
209
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=16_numstages=4_numwarps=4')
210
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=16_numstages=5_numwarps=4')
211
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=2_numwarps=4')
212
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=3_numwarps=4')
213
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=3_numwarps=8')
214
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=4_numwarps=4')
215
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=4_numwarps=8')
216
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=4')
217
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=8')
218
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=2_numwarps=4')
219
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=4')
220
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=8')
221
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=4_numwarps=4')
222
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=4_numwarps=8')
223
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=4')
224
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=4')
225
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=128_numstages=4_numwarps=4')
226
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=16_numstages=3_numwarps=4')
227
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=16_numstages=4_numwarps=4')
228
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=16_numstages=5_numwarps=4')
229
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=32_numstages=3_numwarps=4')
230
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=32_numstages=3_numwarps=8')
231
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=32_numstages=4_numwarps=4')
232
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=32_numstages=5_numwarps=4')
233
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=4')
234
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=8')
235
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=64_numstages=4_numwarps=4')
236
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=64_numstages=5_numwarps=4')
237
+
238
+ def get_name(self) -> str:
239
+ return 'mm'
240
+
241
+ def get_best_choices(self, context: AHContext) -> Optional[List[Tuple[float, int]]]:
242
+ if context.get_value('arith_intensity') <= 52.6245059967041:
243
+ if context.get_value('n') <= 34.0:
244
+ if context.get_value('n') <= 18.0:
245
+ if context.get_value('k*n') <= 312.0:
246
+ return [(0.093, 12), (0.081, 16), (0.081, 148), (0.070, 10), (0.070, 17), (0.070, 149), (0.070, 151), (0.070, 150), (0.070, 14), (0.058, 11), (0.058, 15), (0.058, 13), (0.058, 122), (0.047, 121), (0.035, 123), (0.012, 92)]
247
+ else:
248
+ if context.get_value('k') <= 40.0:
249
+ return [(0.083, 42), (0.083, 46), (0.083, 44), (0.083, 40), (0.083, 128), (0.067, 45), (0.067, 43), (0.067, 41), (0.067, 169), (0.067, 171), (0.067, 168), (0.067, 129), (0.067, 170), (0.033, 103), (0.017, 121)]
250
+ else:
251
+ return [(0.112, 137), (0.104, 136), (0.101, 0), (0.081, 1), (0.073, 135), (0.069, 67), (0.066, 187), (0.058, 41), (0.050, 71), (0.046, 68), (0.046, 70), (0.031, 44), (0.027, 43), (0.027, 170), (0.019, 189), (0.019, 188), (0.015, 169), (0.015, 171), (0.012, 115), (0.012, 168), (0.012, 69), (0.004, 103)]
252
+ else:
253
+ if context.get_value('mat1_stride_0') <= 20.0:
254
+ return [(0.069, 0), (0.059, 157), (0.059, 22), (0.059, 153), (0.059, 155), (0.059, 25), (0.059, 23), (0.059, 19), (0.044, 21), (0.044, 18), (0.044, 152), (0.044, 158), (0.044, 154), (0.044, 156), (0.044, 20), (0.044, 124), (0.044, 24), (0.030, 125), (0.029, 126), (0.015, 97), (0.015, 95), (0.015, 96), (0.010, 2), (0.010, 75)]
255
+ else:
256
+ if context.get_value('k') <= 68.0:
257
+ return [(0.087, 72), (0.087, 74), (0.087, 73), (0.086, 76), (0.077, 75), (0.067, 192), (0.058, 190), (0.048, 47), (0.048, 193), (0.048, 49), (0.048, 51), (0.048, 191), (0.038, 53), (0.019, 133), (0.019, 50), (0.019, 175), (0.019, 172), (0.019, 48), (0.019, 174), (0.010, 173), (0.010, 177), (0.010, 52), (0.010, 54), (0.010, 178), (0.010, 176)]
258
+ else:
259
+ return [(0.154, 52), (0.154, 72), (0.102, 75), (0.087, 49), (0.087, 73), (0.086, 51), (0.057, 176), (0.045, 2), (0.038, 191), (0.038, 178), (0.038, 190), (0.029, 173), (0.029, 76), (0.026, 138), (0.013, 139), (0.013, 140), (0.003, 0)]
260
+ else:
261
+ if context.get_value('k') <= 35.0:
262
+ if context.get_value('k') <= 18.0:
263
+ if context.get_value('m*n') <= 19505152.0:
264
+ return [(0.151, 159), (0.140, 160), (0.129, 164), (0.055, 127), (0.051, 29), (0.044, 161), (0.044, 147), (0.040, 146), (0.040, 31), (0.037, 145), (0.026, 28), (0.022, 90), (0.022, 93), (0.022, 94), (0.022, 100), (0.022, 125), (0.022, 158), (0.022, 157), (0.011, 87), (0.011, 88), (0.011, 89), (0.011, 91), (0.011, 95), (0.011, 96), (0.011, 98), (0.011, 99)]
265
+ else:
266
+ return [(0.069, 7), (0.069, 5), (0.067, 147), (0.066, 8), (0.061, 145), (0.058, 146), (0.052, 124), (0.049, 29), (0.049, 159), (0.046, 31), (0.043, 157), (0.041, 9), (0.041, 4), (0.040, 6), (0.035, 164), (0.035, 160), (0.026, 158), (0.017, 125), (0.017, 28), (0.017, 32), (0.017, 162), (0.017, 27), (0.017, 30), (0.017, 161), (0.009, 33), (0.009, 26), (0.009, 163), (0.006, 0)]
267
+ else:
268
+ if context.get_value('n') <= 68.0:
269
+ return [(0.101, 182), (0.101, 59), (0.088, 57), (0.076, 184), (0.076, 61), (0.076, 179), (0.076, 62), (0.076, 58), (0.063, 180), (0.063, 60), (0.051, 56), (0.050, 181), (0.025, 130), (0.025, 177), (0.025, 183), (0.013, 178), (0.013, 55)]
270
+ else:
271
+ return [(0.089, 180), (0.079, 60), (0.066, 35), (0.066, 181), (0.066, 38), (0.066, 58), (0.066, 179), (0.066, 57), (0.062, 184), (0.053, 37), (0.044, 166), (0.040, 55), (0.040, 39), (0.040, 36), (0.040, 165), (0.040, 167), (0.027, 177), (0.027, 34), (0.022, 159)]
272
+ else:
273
+ if context.get_value('m*n') <= 309760.0:
274
+ return [(0.298, 0), (0.097, 140), (0.080, 83), (0.072, 86), (0.044, 84), (0.036, 178), (0.036, 117), (0.036, 82), (0.032, 120), (0.032, 85), (0.028, 119), (0.024, 130), (0.024, 109), (0.020, 108), (0.020, 118), (0.012, 104), (0.012, 116), (0.012, 141), (0.012, 144), (0.008, 105), (0.008, 106), (0.008, 111), (0.008, 114), (0.008, 107), (0.008, 132), (0.004, 101), (0.004, 102), (0.004, 110), (0.004, 112), (0.004, 113), (0.004, 131)]
275
+ else:
276
+ if context.get_value('n') <= 72.0:
277
+ return [(0.227, 77), (0.118, 78), (0.102, 194), (0.086, 80), (0.059, 57), (0.054, 81), (0.049, 196), (0.048, 197), (0.048, 59), (0.043, 79), (0.032, 195), (0.027, 180), (0.022, 3), (0.021, 141), (0.016, 60), (0.016, 142), (0.011, 183), (0.011, 0), (0.011, 144)]
278
+ else:
279
+ return [(0.140, 186), (0.132, 185), (0.109, 63), (0.085, 65), (0.078, 37), (0.077, 35), (0.062, 197), (0.047, 194), (0.046, 165), (0.046, 57), (0.039, 78), (0.039, 79), (0.039, 66), (0.039, 64), (0.016, 195), (0.008, 159)]
280
+ else:
281
+ if str(context.get_value('using_tf32')) != 'False':
282
+ if context.get_value('m*n') <= 815360.0:
283
+ if context.get_value('k') <= 1184.0:
284
+ return [(0.218, 140), (0.205, 0), (0.154, 144), (0.115, 141), (0.051, 185), (0.051, 104), (0.039, 78), (0.038, 116), (0.026, 165), (0.026, 130), (0.026, 178), (0.013, 57), (0.013, 195), (0.013, 167), (0.013, 186)]
285
+ else:
286
+ return [(0.901, 0), (0.030, 144), (0.030, 134), (0.016, 3), (0.006, 78), (0.006, 77), (0.002, 57), (0.002, 194), (0.002, 59), (0.002, 60), (0.002, 143)]
287
+ else:
288
+ if context.get_value('arith_intensity') <= 187.23922729492188:
289
+ if context.get_value('mat1_stride_0') <= 198.0:
290
+ return [(0.273, 63), (0.158, 37), (0.152, 35), (0.127, 57), (0.097, 165), (0.053, 185), (0.031, 0), (0.028, 64), (0.014, 60), (0.014, 78), (0.009, 55), (0.008, 134), (0.005, 34), (0.005, 167), (0.005, 179), (0.005, 65), (0.005, 66), (0.005, 186), (0.005, 194), (0.002, 166)]
291
+ else:
292
+ return [(0.296, 63), (0.235, 0), (0.132, 64), (0.074, 37), (0.069, 78), (0.051, 185), (0.051, 35), (0.030, 57), (0.020, 77), (0.016, 194), (0.008, 66), (0.007, 65), (0.003, 3), (0.003, 165), (0.003, 141), (0.001, 134), (0.001, 166)]
293
+ else:
294
+ return [(0.405, 0), (0.246, 37), (0.177, 63), (0.145, 35), (0.005, 185), (0.005, 65), (0.005, 64), (0.004, 57), (0.003, 66), (0.002, 165), (0.001, 78), (0.001, 55)]
295
+ else:
296
+ return [(0.357, 0), (0.112, 165), (0.101, 57), (0.094, 179), (0.086, 64), (0.074, 167), (0.067, 60), (0.064, 159), (0.033, 35), (0.007, 195), (0.002, 180), (0.001, 34), (0.001, 166), (0.001, 78)]
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MMRankingH100.py ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # flake8: noqa: B950
2
+ # fmt: off
3
+ # This file was generated by AutoHeuristic. Do not modify it manually!
4
+ # To regenerate this file, take a look at the steps in the README.md file inside torchgen/_autoheuristic/mm/
5
+ from typing import List, Optional, Tuple
6
+
7
+ from torch._inductor.autoheuristic.autoheuristic_utils import (
8
+ AHContext,
9
+ AHMetadata,
10
+ Choice,
11
+ )
12
+ from torch._inductor.autoheuristic.learnedheuristic_interface import (
13
+ LearnedHeuristicDecision,
14
+ )
15
+
16
+
17
+ class MMRankingH100(LearnedHeuristicDecision):
18
+
19
+ def __init__(self) -> None:
20
+ self.choices: List[Choice] = []
21
+ self.fill_choices()
22
+
23
+ def check_precondition(self, metadata: AHMetadata, context: AHContext,) -> bool:
24
+ return (
25
+ metadata.name == self.get_name()
26
+ and metadata.shared_memory == 232448
27
+ and str(metadata.device_capa) == "(9, 0)"
28
+ )
29
+
30
+ def get_confidence_threshold(self) -> float:
31
+ return 0.0
32
+
33
+ def get_choice(self, idx: int) -> Optional[str]:
34
+ if idx < len(self.choices):
35
+ return self.choices[idx]
36
+ return None
37
+
38
+ def fill_choices(self) -> None:
39
+ self.choices.append('extern_mm')
40
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=128_BLOCK-N=16_numstages=4_numwarps=8')
41
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=128_BLOCK-N=32_numstages=4_numwarps=8')
42
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=128_BLOCK-N=64_numstages=4_numwarps=8')
43
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=2_numwarps=8')
44
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=3_numwarps=4')
45
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=3_numwarps=8')
46
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=4_numwarps=4')
47
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=5_numwarps=4')
48
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=128_numstages=5_numwarps=8')
49
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=2_numwarps=2')
50
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=2_numwarps=8')
51
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=3_numwarps=4')
52
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=3_numwarps=8')
53
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=4_numwarps=4')
54
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=4_numwarps=8')
55
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=5_numwarps=4')
56
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=16_numstages=5_numwarps=8')
57
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=2_numwarps=2')
58
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=2_numwarps=8')
59
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=3_numwarps=4')
60
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=4_numwarps=4')
61
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=4_numwarps=8')
62
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=4')
63
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=2_numwarps=2')
64
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=2_numwarps=8')
65
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=3_numwarps=4')
66
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=3_numwarps=8')
67
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=4_numwarps=4')
68
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=4_numwarps=8')
69
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=5_numwarps=4')
70
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=16_BLOCK-N=64_numstages=5_numwarps=8')
71
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=2_numwarps=8')
72
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=4')
73
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=8')
74
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=4_numwarps=4')
75
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=5_numwarps=4')
76
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=5_numwarps=8')
77
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=2_numwarps=2')
78
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=2_numwarps=8')
79
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=3_numwarps=4')
80
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=3_numwarps=8')
81
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=4_numwarps=4')
82
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=4_numwarps=8')
83
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=5_numwarps=4')
84
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=16_numstages=5_numwarps=8')
85
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=2_numwarps=2')
86
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=2_numwarps=8')
87
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=3_numwarps=4')
88
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=3_numwarps=8')
89
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=4_numwarps=4')
90
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=4_numwarps=8')
91
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=4')
92
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=8')
93
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=2_numwarps=2')
94
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=2_numwarps=8')
95
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=4')
96
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=8')
97
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=4_numwarps=4')
98
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=4_numwarps=8')
99
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=4')
100
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=8')
101
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=4')
102
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=8')
103
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=4')
104
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=8')
105
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=16_numstages=3_numwarps=4')
106
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=16_numstages=3_numwarps=8')
107
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=16_numstages=4_numwarps=8')
108
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=16_numstages=5_numwarps=4')
109
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=16_numstages=5_numwarps=8')
110
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=32_numstages=3_numwarps=4')
111
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=32_numstages=3_numwarps=8')
112
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=32_numstages=4_numwarps=8')
113
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=32_numstages=5_numwarps=4')
114
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=32_numstages=5_numwarps=8')
115
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=4')
116
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=8')
117
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=64_numstages=4_numwarps=8')
118
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=64_numstages=5_numwarps=4')
119
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=64_numstages=5_numwarps=8')
120
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
121
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=32_numstages=2_numwarps=2')
122
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=2')
123
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=64_numstages=3_numwarps=4')
124
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=64_numstages=4_numwarps=4')
125
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=64_numstages=5_numwarps=4')
126
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=2_numwarps=8')
127
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=3_numwarps=4')
128
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=3_numwarps=8')
129
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=4_numwarps=4')
130
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=4_numwarps=8')
131
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=5_numwarps=4')
132
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=128_numstages=5_numwarps=8')
133
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=16_numstages=3_numwarps=1')
134
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=16_numstages=4_numwarps=1')
135
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=16_numstages=5_numwarps=1')
136
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=32_numstages=1_numwarps=2')
137
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=32_numstages=2_numwarps=2')
138
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=32_numstages=3_numwarps=2')
139
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=32_numstages=4_numwarps=2')
140
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=2')
141
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=64_numstages=2_numwarps=2')
142
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=64_numstages=2_numwarps=4')
143
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=64_numstages=3_numwarps=4')
144
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=64_numstages=4_numwarps=4')
145
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=16_BLOCK-N=64_numstages=5_numwarps=4')
146
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=128_numstages=2_numwarps=8')
147
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=4')
148
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=128_numstages=4_numwarps=4')
149
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=128_numstages=4_numwarps=8')
150
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=16_numstages=4_numwarps=1')
151
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=16_numstages=5_numwarps=1')
152
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=32_numstages=4_numwarps=2')
153
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=2')
154
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=64_numstages=2_numwarps=4')
155
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=64_numstages=4_numwarps=4')
156
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=4')
157
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=4')
158
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=8')
159
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=4')
160
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=8')
161
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=4')
162
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=16_numstages=2_numwarps=2')
163
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=32_numstages=2_numwarps=4')
164
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=4')
165
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=64_numstages=5_numwarps=4')
166
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=16_numstages=1_numwarps=2')
167
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=16_numstages=2_numwarps=2')
168
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=16_numstages=5_numwarps=2')
169
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=32_numstages=1_numwarps=2')
170
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=32_numstages=2_numwarps=4')
171
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=4')
172
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=16_BLOCK-N=64_numstages=5_numwarps=8')
173
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=32_BLOCK-N=16_numstages=2_numwarps=2')
174
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=32_BLOCK-N=16_numstages=5_numwarps=2')
175
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=32_BLOCK-N=32_numstages=2_numwarps=4')
176
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=4')
177
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=8')
178
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=64_BLOCK-N=16_numstages=2_numwarps=2')
179
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=64_BLOCK-N=32_numstages=2_numwarps=4')
180
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
181
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=16_numstages=3_numwarps=4')
182
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=16_numstages=4_numwarps=4')
183
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=16_numstages=5_numwarps=4')
184
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=32_numstages=3_numwarps=4')
185
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=32_numstages=4_numwarps=4')
186
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=4')
187
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=64_numstages=3_numwarps=4')
188
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=64_numstages=4_numwarps=4')
189
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=64_numstages=5_numwarps=4')
190
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=128_numstages=3_numwarps=4')
191
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=128_numstages=4_numwarps=4')
192
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=128_numstages=4_numwarps=8')
193
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=16_numstages=2_numwarps=4')
194
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=16_numstages=3_numwarps=4')
195
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=16_numstages=4_numwarps=4')
196
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=16_numstages=5_numwarps=4')
197
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=2_numwarps=4')
198
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=3_numwarps=4')
199
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=4_numwarps=4')
200
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=4')
201
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=32_numstages=5_numwarps=8')
202
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=2_numwarps=4')
203
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=3_numwarps=4')
204
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=3_numwarps=8')
205
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=4_numwarps=4')
206
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=4_numwarps=8')
207
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=16_BLOCK-N=64_numstages=5_numwarps=4')
208
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=4')
209
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=128_numstages=4_numwarps=4')
210
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=128_numstages=4_numwarps=8')
211
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=16_numstages=2_numwarps=4')
212
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=16_numstages=3_numwarps=4')
213
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=16_numstages=4_numwarps=4')
214
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=16_numstages=5_numwarps=4')
215
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=2_numwarps=4')
216
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=3_numwarps=4')
217
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=3_numwarps=8')
218
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=4_numwarps=4')
219
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=4_numwarps=8')
220
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=4')
221
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=32_numstages=5_numwarps=8')
222
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=2_numwarps=4')
223
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=4')
224
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=8')
225
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=4_numwarps=4')
226
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=4_numwarps=8')
227
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=4')
228
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=4')
229
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=128_numstages=4_numwarps=4')
230
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=16_numstages=3_numwarps=4')
231
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=16_numstages=4_numwarps=4')
232
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=16_numstages=5_numwarps=4')
233
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=32_numstages=3_numwarps=4')
234
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=32_numstages=3_numwarps=8')
235
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=32_numstages=4_numwarps=4')
236
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=32_numstages=5_numwarps=4')
237
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=4')
238
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=8')
239
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=64_numstages=4_numwarps=4')
240
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=64_numstages=5_numwarps=4')
241
+
242
+ def get_name(self) -> str:
243
+ return 'mm'
244
+
245
+ def get_best_choices(self, context: AHContext) -> Optional[List[Tuple[float, int]]]:
246
+ if context.get_value('arith_intensity') <= 29.89772129058838:
247
+ if context.get_value('n') <= 34.0:
248
+ if context.get_value('n') <= 18.0:
249
+ if context.get_value('k*n') <= 432.0:
250
+ if context.get_value('arith_intensity') <= 7.8700292110443115:
251
+ return [(0.098, 128), (0.098, 129), (0.098, 127), (0.073, 14), (0.073, 16), (0.073, 12), (0.073, 154), (0.073, 156), (0.073, 157), (0.073, 155), (0.049, 10), (0.049, 94), (0.049, 95), (0.048, 96)]
252
+ else:
253
+ return [(0.091, 154), (0.073, 10), (0.073, 15), (0.073, 13), (0.073, 11), (0.073, 17), (0.073, 16), (0.073, 14), (0.073, 12), (0.055, 127), (0.054, 157), (0.054, 156), (0.054, 155), (0.036, 129), (0.036, 128), (0.018, 41), (0.018, 43)]
254
+ else:
255
+ if context.get_value('k') <= 40.0:
256
+ return [(0.070, 39), (0.069, 45), (0.069, 41), (0.069, 43), (0.069, 111), (0.069, 112), (0.056, 38), (0.056, 40), (0.056, 42), (0.056, 44), (0.056, 174), (0.056, 173), (0.056, 175), (0.056, 134), (0.056, 172), (0.056, 135), (0.014, 154), (0.014, 127)]
257
+ else:
258
+ return [(0.147, 144), (0.119, 143), (0.087, 142), (0.083, 0), (0.073, 191), (0.059, 69), (0.050, 67), (0.046, 70), (0.041, 1), (0.036, 174), (0.032, 43), (0.032, 123), (0.028, 40), (0.027, 42), (0.027, 173), (0.023, 175), (0.018, 66), (0.014, 192), (0.014, 193), (0.014, 139), (0.014, 68), (0.014, 127)]
259
+ else:
260
+ if context.get_value('mat1_stride_0') <= 40.0:
261
+ if context.get_value('mat1_stride_0') <= 20.0:
262
+ return [(0.109, 23), (0.109, 21), (0.109, 20), (0.088, 0), (0.087, 131), (0.066, 18), (0.065, 130), (0.065, 132), (0.065, 159), (0.065, 160), (0.065, 161), (0.065, 158), (0.022, 22), (0.022, 19)]
263
+ else:
264
+ return [(0.065, 46), (0.064, 52), (0.064, 50), (0.064, 48), (0.064, 51), (0.064, 49), (0.064, 47), (0.064, 53), (0.064, 181), (0.064, 177), (0.064, 179), (0.064, 176), (0.038, 130), (0.038, 136), (0.026, 182), (0.026, 178), (0.026, 180), (0.026, 137), (0.025, 158), (0.013, 114), (0.013, 113)]
265
+ else:
266
+ if context.get_value('mat1_stride_0') <= 68.0:
267
+ return [(0.138, 140), (0.125, 195), (0.100, 71), (0.100, 74), (0.100, 196), (0.100, 194), (0.100, 197), (0.075, 75), (0.062, 72), (0.062, 73), (0.012, 180), (0.012, 51), (0.012, 182)]
268
+ else:
269
+ return [(0.124, 180), (0.124, 182), (0.114, 75), (0.103, 74), (0.093, 51), (0.093, 71), (0.072, 72), (0.062, 194), (0.052, 145), (0.052, 195), (0.021, 48), (0.021, 50), (0.021, 47), (0.020, 124), (0.010, 147), (0.010, 146), (0.010, 46)]
270
+ else:
271
+ if context.get_value('k') <= 18.0:
272
+ if context.get_value('m*k') <= 528.0:
273
+ return [(0.097, 88), (0.087, 92), (0.077, 90), (0.058, 105), (0.058, 103), (0.058, 104), (0.058, 99), (0.058, 100), (0.058, 106), (0.058, 93), (0.057, 91), (0.057, 97), (0.057, 98), (0.057, 101), (0.048, 102), (0.029, 87), (0.029, 89)]
274
+ else:
275
+ if context.get_value('n') <= 80.0:
276
+ return [(0.057, 161), (0.057, 130), (0.057, 24), (0.056, 164), (0.056, 163), (0.056, 166), (0.056, 168), (0.056, 30), (0.056, 28), (0.056, 26), (0.056, 25), (0.056, 27), (0.056, 29), (0.056, 31), (0.042, 131), (0.028, 99), (0.028, 101), (0.028, 100), (0.028, 167), (0.028, 165), (0.028, 133)]
277
+ else:
278
+ return [(0.110, 164), (0.108, 163), (0.106, 168), (0.069, 161), (0.066, 151), (0.060, 152), (0.055, 165), (0.050, 27), (0.050, 29), (0.048, 131), (0.043, 153), (0.037, 133), (0.037, 130), (0.028, 8), (0.028, 5), (0.027, 7), (0.026, 26), (0.016, 162), (0.012, 9), (0.007, 4), (0.005, 100), (0.005, 6), (0.005, 24)]
279
+ else:
280
+ if context.get_value('k') <= 36.0:
281
+ if context.get_value('n') <= 68.0:
282
+ return [(0.097, 184), (0.097, 56), (0.086, 186), (0.086, 183), (0.086, 188), (0.086, 58), (0.086, 60), (0.065, 54), (0.043, 187), (0.043, 185), (0.043, 57), (0.043, 61), (0.032, 55), (0.032, 130), (0.032, 59), (0.011, 181), (0.011, 163), (0.011, 136), (0.011, 138)]
283
+ else:
284
+ return [(0.117, 184), (0.117, 170), (0.117, 169), (0.107, 183), (0.106, 188), (0.075, 181), (0.064, 130), (0.064, 56), (0.053, 171), (0.032, 57), (0.032, 59), (0.032, 185), (0.011, 163), (0.011, 32), (0.011, 37), (0.011, 34), (0.011, 33), (0.011, 35), (0.011, 36), (0.011, 54)]
285
+ else:
286
+ if context.get_value('mat2_stride_0') <= 384.0:
287
+ return [(0.244, 0), (0.061, 76), (0.061, 79), (0.030, 3), (0.030, 183), (0.030, 189), (0.030, 187), (0.030, 64), (0.030, 190), (0.030, 62), (0.030, 198), (0.030, 201), (0.030, 77), (0.030, 200), (0.030, 80), (0.030, 199), (0.030, 78), (0.030, 184), (0.020, 86), (0.020, 84), (0.020, 120), (0.020, 81), (0.020, 121), (0.020, 85), (0.020, 122), (0.010, 83), (0.010, 118), (0.010, 119), (0.010, 82)]
288
+ else:
289
+ return [(0.274, 83), (0.171, 86), (0.152, 0), (0.071, 85), (0.061, 125), (0.050, 84), (0.020, 109), (0.020, 117), (0.020, 81), (0.020, 118), (0.020, 121), (0.020, 108), (0.020, 115), (0.020, 116), (0.010, 110), (0.010, 120), (0.010, 103), (0.010, 107), (0.010, 119), (0.010, 122)]
290
+ else:
291
+ if context.get_value('arith_intensity') <= 56.995582580566406:
292
+ if context.get_value('n') <= 68.0:
293
+ if context.get_value('k*n') <= 4448.0:
294
+ if context.get_value('m*n') <= 29626368.0:
295
+ return [(0.107, 198), (0.107, 200), (0.107, 201), (0.107, 199), (0.106, 76), (0.106, 79), (0.064, 197), (0.063, 56), (0.043, 184), (0.043, 187), (0.042, 80), (0.042, 77), (0.042, 183), (0.021, 78)]
296
+ else:
297
+ return [(0.073, 201), (0.073, 198), (0.073, 200), (0.073, 199), (0.073, 197), (0.073, 56), (0.073, 58), (0.073, 79), (0.073, 76), (0.072, 59), (0.072, 78), (0.072, 77), (0.072, 80), (0.018, 184), (0.018, 55), (0.018, 54)]
298
+ else:
299
+ if context.get_value('k') <= 348.0:
300
+ return [(0.206, 76), (0.183, 77), (0.169, 198), (0.160, 199), (0.053, 59), (0.046, 56), (0.038, 3), (0.030, 148), (0.030, 58), (0.030, 187), (0.023, 184), (0.015, 0), (0.008, 55), (0.008, 54)]
301
+ else:
302
+ return [(0.146, 198), (0.145, 199), (0.145, 148), (0.126, 0), (0.084, 76), (0.084, 77), (0.042, 80), (0.042, 79), (0.021, 149), (0.021, 150), (0.021, 3), (0.014, 46), (0.014, 74), (0.014, 75), (0.014, 124), (0.014, 194), (0.014, 195), (0.007, 145), (0.007, 146), (0.007, 2), (0.007, 72), (0.007, 147), (0.007, 71)]
303
+ else:
304
+ if context.get_value('m') <= 3264.0:
305
+ return [(0.247, 147), (0.115, 197), (0.066, 199), (0.066, 201), (0.066, 198), (0.049, 0), (0.049, 169), (0.049, 171), (0.033, 140), (0.033, 125), (0.033, 114), (0.016, 126), (0.016, 183), (0.016, 184), (0.016, 185), (0.016, 182), (0.016, 188), (0.016, 78), (0.016, 148), (0.016, 138), (0.016, 77), (0.016, 56), (0.016, 59)]
306
+ else:
307
+ if context.get_value('k') <= 62.5:
308
+ return [(0.226, 190), (0.226, 189), (0.122, 62), (0.122, 64), (0.055, 77), (0.055, 78), (0.037, 198), (0.036, 201), (0.036, 33), (0.024, 163), (0.018, 56), (0.018, 35), (0.018, 169), (0.006, 171)]
309
+ else:
310
+ return [(0.162, 35), (0.118, 33), (0.096, 189), (0.096, 190), (0.088, 169), (0.074, 62), (0.073, 56), (0.066, 171), (0.051, 198), (0.051, 201), (0.044, 59), (0.037, 64), (0.029, 63), (0.007, 0), (0.007, 77)]
311
+ else:
312
+ if context.get_value('m*n') <= 1097728.0:
313
+ return [(0.403, 0), (0.179, 141), (0.134, 150), (0.086, 147), (0.051, 148), (0.048, 3), (0.024, 189), (0.020, 199), (0.017, 64), (0.010, 65), (0.010, 77), (0.007, 114), (0.003, 138), (0.003, 59), (0.003, 182)]
314
+ else:
315
+ if context.get_value('m*n') <= 3244032.0:
316
+ return [(0.295, 189), (0.176, 64), (0.157, 65), (0.090, 0), (0.069, 62), (0.059, 63), (0.046, 77), (0.039, 169), (0.023, 199), (0.020, 35), (0.013, 33), (0.010, 171), (0.003, 141)]
317
+ else:
318
+ if context.get_value('n') <= 136.0:
319
+ return [(0.197, 189), (0.197, 63), (0.161, 77), (0.157, 62), (0.061, 33), (0.044, 65), (0.039, 35), (0.039, 64), (0.030, 169), (0.026, 0), (0.017, 199), (0.017, 148), (0.009, 56), (0.004, 3)]
320
+ else:
321
+ return [(0.460, 0), (0.145, 62), (0.138, 63), (0.081, 35), (0.047, 33), (0.043, 189), (0.023, 64), (0.018, 77), (0.013, 169), (0.009, 65), (0.009, 56), (0.005, 32), (0.005, 59), (0.002, 183), (0.002, 163)]
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MixedMMA100.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # flake8: noqa: B950
2
+ # fmt: off
3
+ # This file was generated by AutoHeuristic. Do not modify it manually!
4
+ # To regenerate this file, take a look at the steps in the README.md file inside torchgen/_autoheuristic/mixed_mm/
5
+ from typing import List, Optional, Tuple
6
+
7
+ from torch._inductor.autoheuristic.autoheuristic_utils import (
8
+ AHContext,
9
+ AHMetadata,
10
+ Choice,
11
+ )
12
+ from torch._inductor.autoheuristic.learnedheuristic_interface import (
13
+ LearnedHeuristicDecision,
14
+ )
15
+
16
+
17
+ class MixedMMA100(LearnedHeuristicDecision):
18
+
19
+ def __init__(self) -> None:
20
+ self.choices: List[Choice] = []
21
+ self.fill_choices()
22
+
23
+ def check_precondition(self, metadata: AHMetadata, context: AHContext,) -> bool:
24
+ return (
25
+ metadata.name == self.get_name()
26
+ and metadata.shared_memory == 166912
27
+ and str(metadata.device_capa) == "(8, 0)"
28
+ )
29
+
30
+ def get_confidence_threshold(self) -> float:
31
+ return 0.0
32
+
33
+ def get_choice(self, idx: int) -> Optional[str]:
34
+ if idx < len(self.choices):
35
+ return self.choices[idx]
36
+ return None
37
+
38
+ def fill_choices(self) -> None:
39
+ self.choices.append('extern_fallback_mixed_mm')
40
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=4')
41
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=4')
42
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
43
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=32_numstages=2_numwarps=2')
44
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=2')
45
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=64_numstages=5_numwarps=4')
46
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=256_BLOCK-N=128_numstages=3_numwarps=4')
47
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=256_BLOCK-N=128_numstages=5_numwarps=8')
48
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=8')
49
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=4')
50
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
51
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=32_numstages=2_numwarps=4')
52
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=4')
53
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
54
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=4')
55
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=64_numstages=5_numwarps=4')
56
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=4')
57
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=128_numstages=4_numwarps=8')
58
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=4')
59
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=4')
60
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=8')
61
+
62
+ def get_name(self) -> str:
63
+ return 'mixed_mm'
64
+
65
+ def get_best_choices(self, context: AHContext) -> Optional[List[Tuple[float, int]]]:
66
+ if str(context.get_value('1LEQmLEQ16')) != 'True':
67
+ if context.get_value('m') <= 32.5:
68
+ if context.get_value('n') <= 6976.0:
69
+ if context.get_value('n') <= 3520.0:
70
+ if context.get_value('m*n') <= 37632.0:
71
+ return None
72
+ else:
73
+ return [(1.000, 13)]
74
+ else:
75
+ if context.get_value('m*k') <= 452352.0:
76
+ return [(0.590, 13), (0.256, 8), (0.103, 7), (0.051, 11)]
77
+ else:
78
+ return [(0.778, 8), (0.222, 13)]
79
+ else:
80
+ if context.get_value('k*n') <= 102776832.0:
81
+ if context.get_value('n') <= 14656.0:
82
+ return [(1.000, 11)]
83
+ else:
84
+ return [(0.889, 11), (0.111, 13)]
85
+ else:
86
+ return [(1.000, 11)]
87
+ else:
88
+ if context.get_value('m*n') <= 446464.0:
89
+ if context.get_value('m*n') <= 223424.0:
90
+ if context.get_value('mat1_stride_0') <= 3968.0:
91
+ return None
92
+ else:
93
+ return None
94
+ else:
95
+ if context.get_value('m*n') <= 346112.0:
96
+ return [(0.960, 16), (0.040, 7)]
97
+ else:
98
+ return [(0.750, 16), (0.136, 14), (0.114, 7)]
99
+ else:
100
+ if str(context.get_value('33LEQmLEQ64')) != 'True':
101
+ if context.get_value('n') <= 6976.0:
102
+ return [(1.000, 14)]
103
+ else:
104
+ return [(0.753, 2), (0.222, 1), (0.015, 7), (0.007, 16), (0.004, 12)]
105
+ else:
106
+ if context.get_value('n') <= 13888.0:
107
+ return [(0.710, 14), (0.275, 21), (0.014, 12)]
108
+ else:
109
+ return [(0.374, 19), (0.339, 20), (0.106, 21), (0.101, 16), (0.066, 17), (0.009, 14), (0.004, 18)]
110
+ else:
111
+ if context.get_value('n') <= 3520.0:
112
+ if context.get_value('arith_intensity') <= 3.994754433631897:
113
+ if str(context.get_value('mat2_dtype')) != 'torch.uint8':
114
+ if context.get_value('m*k') <= 18944.0:
115
+ return [(0.577, 5), (0.423, 6)]
116
+ else:
117
+ return [(0.988, 5), (0.012, 6)]
118
+ else:
119
+ if context.get_value('arith_intensity') <= 2.9899919033050537:
120
+ return None
121
+ else:
122
+ return None
123
+ else:
124
+ if context.get_value('arith_intensity') <= 7.956453561782837:
125
+ if context.get_value('k*n') <= 9244032.0:
126
+ return [(0.822, 5), (0.178, 6)]
127
+ else:
128
+ return [(0.977, 5), (0.023, 0)]
129
+ else:
130
+ if context.get_value('m*k') <= 978944.0:
131
+ return [(1.000, 5)]
132
+ else:
133
+ return [(0.971, 5), (0.029, 0)]
134
+ else:
135
+ if context.get_value('n') <= 13632.0:
136
+ if context.get_value('n') <= 6976.0:
137
+ return [(1.000, 6)]
138
+ else:
139
+ if context.get_value('k') <= 3968.0:
140
+ return [(0.617, 3), (0.111, 5), (0.099, 7), (0.086, 9), (0.062, 6), (0.025, 8)]
141
+ else:
142
+ return [(0.779, 8), (0.119, 5), (0.053, 7), (0.035, 6), (0.013, 3)]
143
+ else:
144
+ if context.get_value('k*n') <= 39518208.0:
145
+ return [(0.385, 4), (0.327, 3), (0.192, 6), (0.038, 7), (0.038, 10), (0.019, 5)]
146
+ else:
147
+ if context.get_value('n') <= 20800.0:
148
+ return [(0.821, 6), (0.121, 7), (0.029, 4), (0.014, 5), (0.007, 3), (0.007, 8)]
149
+ else:
150
+ return [(0.530, 7), (0.386, 6), (0.046, 8), (0.021, 3), (0.015, 4), (0.002, 5)]
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MixedMMH100.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # flake8: noqa: B950
2
+ # fmt: off
3
+ # This file was generated by AutoHeuristic. Do not modify it manually!
4
+ # To regenerate this file, take a look at the steps in the README.md file inside torchgen/_autoheuristic/mixed_mm/
5
+ from typing import List, Optional, Tuple
6
+
7
+ from torch._inductor.autoheuristic.autoheuristic_utils import (
8
+ AHContext,
9
+ AHMetadata,
10
+ Choice,
11
+ )
12
+ from torch._inductor.autoheuristic.learnedheuristic_interface import (
13
+ LearnedHeuristicDecision,
14
+ )
15
+
16
+
17
+ class MixedMMH100(LearnedHeuristicDecision):
18
+
19
+ def __init__(self) -> None:
20
+ self.choices: List[Choice] = []
21
+ self.fill_choices()
22
+
23
+ def check_precondition(self, metadata: AHMetadata, context: AHContext,) -> bool:
24
+ return (
25
+ metadata.name == self.get_name()
26
+ and metadata.shared_memory == 232448
27
+ and str(metadata.device_capa) == "(9, 0)"
28
+ )
29
+
30
+ def get_confidence_threshold(self) -> float:
31
+ return 0.0
32
+
33
+ def get_choice(self, idx: int) -> Optional[str]:
34
+ if idx < len(self.choices):
35
+ return self.choices[idx]
36
+ return None
37
+
38
+ def fill_choices(self) -> None:
39
+ self.choices.append('extern_fallback_mixed_mm')
40
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=128_numstages=3_numwarps=4')
41
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=32_BLOCK-N=64_numstages=3_numwarps=4')
42
+ self.choices.append('type=triton_BLOCK-M=128_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=8')
43
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
44
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=32_numstages=2_numwarps=2')
45
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=2')
46
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=128_BLOCK-N=64_numstages=5_numwarps=4')
47
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=256_BLOCK-N=128_numstages=3_numwarps=4')
48
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=256_BLOCK-N=128_numstages=5_numwarps=8')
49
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=128_numstages=5_numwarps=8')
50
+ self.choices.append('type=triton_BLOCK-M=16_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=4')
51
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
52
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=32_numstages=2_numwarps=4')
53
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=4')
54
+ self.choices.append('type=triton_BLOCK-M=32_BLOCK-K=32_BLOCK-N=64_numstages=5_numwarps=8')
55
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=128_numstages=4_numwarps=4')
56
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=32_numstages=5_numwarps=4')
57
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=128_BLOCK-N=64_numstages=5_numwarps=4')
58
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=128_numstages=3_numwarps=4')
59
+ self.choices.append('type=triton_BLOCK-M=64_BLOCK-K=64_BLOCK-N=64_numstages=3_numwarps=8')
60
+
61
+ def get_name(self) -> str:
62
+ return 'mixed_mm'
63
+
64
+ def get_best_choices(self, context: AHContext) -> Optional[List[Tuple[float, int]]]:
65
+ if context.get_value('arith_intensity') <= 15.988086223602295:
66
+ if context.get_value('n') <= 25280.0:
67
+ if context.get_value('n') <= 1344.0:
68
+ if context.get_value('mat1_stride_0') <= 7808.0:
69
+ return [(0.581, 7), (0.419, 6)]
70
+ else:
71
+ if context.get_value('m*n') <= 7680.0:
72
+ return [(0.875, 0), (0.125, 6)]
73
+ else:
74
+ return [(0.833, 0), (0.167, 7)]
75
+ else:
76
+ if context.get_value('n') <= 8512.0:
77
+ if str(context.get_value('mat2_dtype')) != 'torch.int8':
78
+ return [(0.763, 6), (0.237, 7)]
79
+ else:
80
+ return [(0.725, 7), (0.275, 6)]
81
+ else:
82
+ if str(context.get_value('mat1_dtype')) != 'torch.bfloat16':
83
+ return [(0.736, 7), (0.197, 9), (0.048, 6), (0.014, 8), (0.005, 10)]
84
+ else:
85
+ return [(0.473, 7), (0.398, 6), (0.097, 9), (0.032, 10)]
86
+ else:
87
+ if context.get_value('n') <= 42254.0:
88
+ if context.get_value('n') <= 33856.0:
89
+ if context.get_value('k*n') <= 68157440.0:
90
+ return [(0.370, 4), (0.370, 5), (0.074, 7), (0.074, 8), (0.074, 11), (0.037, 6)]
91
+ else:
92
+ return [(0.916, 8), (0.036, 7), (0.036, 9), (0.012, 4)]
93
+ else:
94
+ return [(0.659, 5), (0.341, 6)]
95
+ else:
96
+ if context.get_value('k*n') <= 326052992.0:
97
+ if context.get_value('n') <= 55232.0:
98
+ return [(0.571, 6), (0.321, 7), (0.036, 4), (0.036, 8), (0.036, 9)]
99
+ else:
100
+ return [(0.506, 6), (0.325, 8), (0.104, 7), (0.039, 5), (0.026, 9)]
101
+ else:
102
+ if context.get_value('n') <= 57024.0:
103
+ return [(0.462, 9), (0.385, 7), (0.115, 6), (0.038, 8)]
104
+ else:
105
+ return [(0.598, 8), (0.223, 9), (0.107, 6), (0.071, 7)]
106
+ else:
107
+ if context.get_value('m*n') <= 543936.0:
108
+ if str(context.get_value('17LEQmLEQ32')) != 'True':
109
+ if context.get_value('m*n') <= 262272.0:
110
+ if context.get_value('n') <= 1592.5:
111
+ return [(0.860, 0), (0.140, 9)]
112
+ else:
113
+ return None
114
+ else:
115
+ if context.get_value('m*k') <= 1294336.0:
116
+ return [(0.833, 17), (0.150, 18), (0.017, 15)]
117
+ else:
118
+ return [(0.917, 17), (0.083, 8)]
119
+ else:
120
+ if context.get_value('n') <= 12416.0:
121
+ if context.get_value('m*n') <= 43008.0:
122
+ return None
123
+ else:
124
+ return [(0.853, 14), (0.147, 9)]
125
+ else:
126
+ return [(0.625, 12), (0.375, 14)]
127
+ else:
128
+ if context.get_value('m') <= 32.5:
129
+ if context.get_value('mat2_stride_1') <= 6656.0:
130
+ if context.get_value('n') <= 69184.0:
131
+ return [(0.611, 12), (0.361, 14), (0.028, 13)]
132
+ else:
133
+ return [(1.000, 12)]
134
+ else:
135
+ if context.get_value('mat2_stride_1') <= 20864.0:
136
+ return [(1.000, 12)]
137
+ else:
138
+ return [(0.958, 12), (0.042, 9)]
139
+ else:
140
+ if context.get_value('m*n') <= 1085440.0:
141
+ if context.get_value('n') <= 9152.0:
142
+ return [(1.000, 18)]
143
+ else:
144
+ return [(0.780, 18), (0.160, 16), (0.060, 20)]
145
+ else:
146
+ if context.get_value('m') <= 67.0:
147
+ return [(0.650, 16), (0.203, 19), (0.122, 18), (0.016, 20), (0.008, 1)]
148
+ else:
149
+ return [(0.561, 3), (0.185, 16), (0.096, 20), (0.083, 19), (0.076, 2)]
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_PadMMA100.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # flake8: noqa: B950
2
+ # fmt: off
3
+ # This file was generated by AutoHeuristic. Do not modify it manually!
4
+ # To regenerate this file, take a look at the steps in the README.md file inside torchgen/_autoheuristic/pad_mm/
5
+ from torch._inductor.autoheuristic.autoheuristic_utils import AHContext, AHMetadata, Choice, CHOICE_COL
6
+ from torch._inductor.autoheuristic.learnedheuristic_interface import (
7
+ LearnedHeuristicRegression,
8
+ )
9
+
10
+
11
+ class PadMMA100(LearnedHeuristicRegression):
12
+
13
+ def __init__(self) -> None:
14
+ pass
15
+
16
+ def check_precondition(self, metadata: AHMetadata, context: AHContext,) -> bool:
17
+ return (
18
+ metadata.name == self.get_name()
19
+ and metadata.shared_memory == 166912
20
+ and str(metadata.device_capa) == "(8, 0)"
21
+ )
22
+
23
+ def get_feedback(self, context: AHContext, choice: Choice) -> float:
24
+ context.context_dict[CHOICE_COL] = choice
25
+ return self.predict(context)
26
+
27
+ def get_confidence_threshold(self) -> float:
28
+ return 1.7025303314066
29
+
30
+ def get_name(self) -> str:
31
+ return 'pad_mm'
32
+
33
+ def predict(self, context: AHContext) -> float:
34
+ if str(context.get_value('choice')) != 'pad':
35
+ if str(context.get_value('using_tf32')) != 'False':
36
+ if context.get_value('m*n') <= 4171264.0:
37
+ if context.get_value('m*k') <= 3999308.0:
38
+ return 1.8751469764071178
39
+ else:
40
+ if str(context.get_value('n_multiple_32')) != 'True':
41
+ return 0.9117231355626345
42
+ else:
43
+ return 1.1607689608873861
44
+ else:
45
+ if str(context.get_value('n_multiple_2')) != 'True':
46
+ if str(context.get_value('using_tf32')) != 'True':
47
+ return 0.7430382200435992
48
+ else:
49
+ return 0.8531269794448678
50
+ else:
51
+ if str(context.get_value('k_multiple_2')) != 'True':
52
+ return 0.7577181972719917
53
+ else:
54
+ return 0.8977349440424219
55
+ else:
56
+ if context.get_value('m*n') <= 1299712.0:
57
+ return 1.1669723418995592
58
+ else:
59
+ if context.get_value('mat2_stride_1') <= 45217.5:
60
+ if context.get_value('m*n') <= 55884158.0:
61
+ return 1.0262769936909601
62
+ else:
63
+ return 1.0022677428470845
64
+ else:
65
+ if context.get_value('m') <= 18478.0:
66
+ return 1.1127066261894312
67
+ else:
68
+ return 1.0337740659894263
69
+ else:
70
+ if str(context.get_value('mat1_dtype')) != 'torch.float32':
71
+ if str(context.get_value('n_multiple_2')) != 'False':
72
+ if str(context.get_value('k_multiple_2')) != 'True':
73
+ if context.get_value('mat1_stride_0') <= 561.0:
74
+ return 1.2900382135142956
75
+ else:
76
+ return 1.5761737616057887
77
+ else:
78
+ if context.get_value('num_dims_needs_padding') <= 1.5:
79
+ return 1.0472263310239422
80
+ else:
81
+ return 1.1727673465762514
82
+ else:
83
+ if context.get_value('k') <= 28238.5:
84
+ if context.get_value('k/(m*n)') <= 0.00026227018679492176:
85
+ return 1.6770542505397175
86
+ else:
87
+ return 1.3974785435105923
88
+ else:
89
+ if str(context.get_value('mat1_dtype')) != 'torch.bfloat16':
90
+ return 1.3952699800111992
91
+ else:
92
+ return 1.5759286511628336
93
+ else:
94
+ if str(context.get_value('using_tf32')) != 'False':
95
+ if context.get_value('m*n') <= 14119424.0:
96
+ return 0.8875772670422478
97
+ else:
98
+ if str(context.get_value('mat2_innermost_needs_padding')) != 'True':
99
+ return 1.1467728924377265
100
+ else:
101
+ return 1.215842963532998
102
+ else:
103
+ if context.get_value('arith_intensity') <= 396.8774871826172:
104
+ return 0.89940161869551
105
+ else:
106
+ if context.get_value('mat2_stride_1') <= 45217.5:
107
+ return 0.9964328169353532
108
+ else:
109
+ return 0.9493479238294826
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__init__.py ADDED
File without changes
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MMRankingA100.cpython-312.pyc ADDED
Binary file (37.1 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MMRankingH100.cpython-312.pyc ADDED
Binary file (39.4 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MixedMMA100.cpython-312.pyc ADDED
Binary file (9.08 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MixedMMH100.cpython-312.pyc ADDED
Binary file (9.18 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_PadMMA100.cpython-312.pyc ADDED
Binary file (4.56 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (218 Bytes). View file
 
lib/python3.12/site-packages/torch/_inductor/autoheuristic/autoheuristic.py ADDED
@@ -0,0 +1,315 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from functools import partial
4
+ from typing import Any, Callable, Dict, List, Optional
5
+
6
+ import torch
7
+ from torch._inductor.autoheuristic.autoheuristic_utils import (
8
+ AHContext,
9
+ AHMetadata,
10
+ AHOperation,
11
+ Choice,
12
+ CHOICE_COL,
13
+ Feedback,
14
+ FEEDBACK_COL,
15
+ get_metadata_str_from_log,
16
+ )
17
+ from torch._inductor.autoheuristic.learned_heuristic_controller import (
18
+ LearnedHeuristicController,
19
+ )
20
+ from torch._inductor.ir import ChoiceCaller
21
+ from torch._inductor.runtime.runtime_utils import cache_dir
22
+ from torch._inductor.utils import get_gpu_shared_memory
23
+
24
+
25
+ class LocalFeedback:
26
+ """
27
+ To be able to collect data for a choice, a function providing feedback given a choice has to be provided.
28
+ LocalFeedback can be used when AutoHeuristic should immediately run the function to collect feedback for each choice
29
+ (see pad_mm.py, where the autotuning happens locally, for an example).
30
+ """
31
+
32
+ def __init__(self, feedback_fn: Callable[[Choice], Feedback]) -> None:
33
+ self.feedback_fn = feedback_fn
34
+
35
+ def __call__(self, choice: Choice) -> Feedback:
36
+ return self.feedback_fn(choice)
37
+
38
+
39
+ class InconsistentMetadata(Exception):
40
+ """
41
+ Exception that is thrown when AutoHeuristic tries to log data to a file where the metadata stored in the file does
42
+ not match the metadata it would store if the file didn't exist.
43
+ """
44
+
45
+
46
+ class AutoHeuristic:
47
+ """
48
+ AutoHeuristic is a framework that allows one to collect data, learn a heuristic (i.e. a regression tree) and
49
+ generate the heuristic to code. This class allows one to collect data. The collected data can then be used to train
50
+ a heuristic (see torchgen/autoheuristic/).
51
+ """
52
+
53
+ collected_feedback: Dict[Choice, Feedback]
54
+
55
+ def __init__(
56
+ self,
57
+ fallback: Callable[[], Choice],
58
+ choices: List[Choice],
59
+ feedback: Optional[LocalFeedback],
60
+ context: AHContext,
61
+ name: str,
62
+ augment_context: Optional[List[AHOperation]] = None,
63
+ precondition: Optional[Callable[[AHMetadata, AHContext], bool]] = None,
64
+ ) -> None:
65
+ """
66
+ Initializes an instance of the AutoHeuristic class.
67
+
68
+ Args:
69
+ fallback: A callable that returns a Choice when the heuristic is unsure which choice to make, or
70
+ AutoHeuristic is in data collection mode.
71
+ choices: A list of possible choices the heuristic can make.
72
+ feedback: An instance of LocalFeedback that provides feedback for a given choice.
73
+ context: Context to store with each choice and feedback.
74
+ name: A string that identifies the heuristic.
75
+ augment_context: An optional list of AHOperation instances that augment the context.
76
+ precondition: A callable that returns a boolean indicating whether AutoHeuristic should run.
77
+ """
78
+ self.fallback = fallback
79
+ self.choices = choices
80
+ self.feedback = feedback
81
+ self.context = context
82
+ self.name = name
83
+ self.collected_feedback = {}
84
+ self.augment_context = augment_context
85
+ self.metadata = AHMetadata(
86
+ get_gpu_shared_memory(),
87
+ torch.cuda.get_device_capability(),
88
+ self.choices,
89
+ self.name,
90
+ )
91
+ self.precondition = precondition
92
+
93
+ if not self.satisfies_precondition():
94
+ return
95
+
96
+ if torch._inductor.config.autoheuristic_log_path == "DEFAULT":
97
+ self.log_path = self.get_default_log_path()
98
+ else:
99
+ self.log_path = torch._inductor.config.autoheuristic_log_path
100
+
101
+ if torch._inductor.config.collect_autoheuristic(self.name):
102
+ if self.feedback is not None:
103
+ for choice in self.choices:
104
+ feedback_val = self.feedback(choice)
105
+ self.save_data(choice, feedback_val)
106
+
107
+ def satisfies_precondition(self) -> bool:
108
+ return self.precondition is None or self.precondition(
109
+ self.metadata, self.context
110
+ )
111
+
112
+ def get_choice(self) -> Choice:
113
+ """
114
+ Returns the chosen option based on the value of autoheuristic_use.
115
+ If self.name is one of the comma separated strings in autoheuristic_use,
116
+ it queries a learned heuristic to make a decision. Otherwise, it returns the fallback option.
117
+ """
118
+
119
+ if not self.satisfies_precondition():
120
+ return self.fallback()
121
+
122
+ if torch._inductor.config.use_autoheuristic(self.name):
123
+ if self.augment_context is not None:
124
+ self.context.apply_operations(self.augment_context)
125
+ controller = LearnedHeuristicController(
126
+ self.metadata,
127
+ self.context,
128
+ )
129
+ decision = controller.get_decision()
130
+ if decision not in self.choices:
131
+ # TODO(AlnisM): We might want to allow this in the future
132
+ return self.fallback()
133
+ if decision is not None:
134
+ return decision
135
+ return self.fallback()
136
+
137
+ def get_top_k_choices(
138
+ self, top_k: int, always_included: Optional[List[str]] = None
139
+ ) -> Optional[List[Choice]]:
140
+ if not self.satisfies_precondition():
141
+ return None
142
+ if torch._inductor.config.use_autoheuristic(self.name):
143
+ if self.augment_context is not None:
144
+ self.context.apply_operations(self.augment_context)
145
+ controller = LearnedHeuristicController(
146
+ self.metadata,
147
+ self.context,
148
+ )
149
+ choices = controller.get_decisions_ranked(top_k)
150
+ if choices is None:
151
+ return None
152
+ if always_included is not None:
153
+ for choice in always_included:
154
+ if choice not in choices:
155
+ choices.append(choice)
156
+ return choices
157
+ return None
158
+
159
+ def get_collected_feedback(self, choice: Choice) -> Any:
160
+ return self.collected_feedback.get(choice, None)
161
+
162
+ @staticmethod
163
+ def get_device_identifier() -> str:
164
+ # a heuristic might work well for one GPU, but not for another
165
+ # we store the collected data per GPU model and learn a heuristic per GPU model
166
+
167
+ # TODO(AlnisM): just using the device name for now, but the same GPU model can have different names
168
+ device_name = torch.cuda.get_device_name().replace(" ", "_")
169
+ return device_name
170
+
171
+ def get_default_log_path(self) -> str:
172
+ device_name = self.get_device_identifier()
173
+ path = f"{cache_dir()}/autoheuristic/{device_name}/"
174
+ os.makedirs(path, exist_ok=True)
175
+ path += f"{self.name}.txt"
176
+ return path
177
+
178
+ def serialize_metadata(self) -> str:
179
+ metadata_dict = self.metadata.to_dict()
180
+ (
181
+ num_features,
182
+ cat_features,
183
+ ) = self.context.get_numerical_and_categorical_features()
184
+ metadata_dict["numerical_features"] = num_features
185
+ metadata_dict["categorical_features"] = cat_features
186
+ return json.dumps(metadata_dict)
187
+
188
+ def save_data(self, choice: Choice, feedback_val: Feedback) -> None:
189
+ self.collected_feedback[choice] = feedback_val
190
+ log_path = self.log_path
191
+
192
+ lines = []
193
+ log_exists = os.path.exists(log_path)
194
+ if log_exists:
195
+ # if log already exists, make sure it is consistent
196
+ metadata = self.serialize_metadata()
197
+ existing_metadata = get_metadata_str_from_log(self.log_path)
198
+ if existing_metadata != metadata:
199
+ raise InconsistentMetadata(
200
+ "Given metadata does not match existing metadata"
201
+ )
202
+ else:
203
+ lines.append(self.serialize_metadata())
204
+ feature_header = self.context.get_feature_names_csv()
205
+ header = feature_header + "," + CHOICE_COL + "," + FEEDBACK_COL
206
+ lines.append(header)
207
+
208
+ line = ""
209
+ feature_values = self.context.get_feature_values_csv()
210
+ line += feature_values + "," + choice + "," + str(feedback_val)
211
+ lines.append(line)
212
+
213
+ with open(log_path, "a") as f:
214
+ f.write("\n".join(lines) + "\n")
215
+
216
+
217
+ class AutoHeuristicSelectAlgorithm(AutoHeuristic):
218
+ """
219
+ AutoHeuristicSelectAlgorithm is a subclass of AutoHeuristic that allows one to collect data and learn a heuristic
220
+ when one wants to use AutoHeuristic for kernel choice selection.
221
+ """
222
+
223
+ def __init__(
224
+ self,
225
+ fallback: Callable[[], Optional[ChoiceCaller]],
226
+ choices: List[ChoiceCaller],
227
+ input_nodes: List[Any],
228
+ context: AHContext,
229
+ name: str,
230
+ augment_context: Optional[List[AHOperation]] = None,
231
+ precondition: Optional[Callable[[AHMetadata, AHContext], bool]] = None,
232
+ ) -> None:
233
+ """
234
+ The arguments choices, input_nodes and name have to match the ones used in the call to
235
+ autotune_select_algorithm(), e.g. if the following call is made
236
+ autotune_select_algorithm(name, choices, input_nodes, layout), the same name, choices and input_nodes
237
+ have to be used here.
238
+ """
239
+ self.input_nodes = input_nodes
240
+ self.choicestr2choice: Dict[str, ChoiceCaller] = {}
241
+ for choice in choices:
242
+ self.choicestr2choice[choice.autoheuristic_id()] = choice
243
+ choices_str = list(self.choicestr2choice.keys())
244
+
245
+ def fallback_str() -> str:
246
+ fallback_choice = fallback()
247
+ if fallback_choice is None:
248
+ # TODO: Find a nicer way to handle this
249
+ return "unsure"
250
+ return fallback_choice.autoheuristic_id()
251
+
252
+ super().__init__(
253
+ fallback_str,
254
+ choices_str,
255
+ None,
256
+ context,
257
+ name,
258
+ augment_context,
259
+ precondition,
260
+ )
261
+
262
+ if (
263
+ torch._inductor.config.collect_autoheuristic(self.name)
264
+ and self.satisfies_precondition()
265
+ ):
266
+ self.register_global_feedback(input_nodes, choices)
267
+
268
+ def register_global_feedback(
269
+ self, input_nodes: List[Any], choices: List[ChoiceCaller]
270
+ ) -> None:
271
+ """
272
+ Registers a callback in select_algorithm, which is called with the timing of each choice.
273
+ """
274
+
275
+ from torch._inductor.select_algorithm import (
276
+ add_feedback_saver,
277
+ create_inputs_key,
278
+ create_precompile_key,
279
+ )
280
+
281
+ def store_global_feedback(
282
+ ah_inputs_key: str,
283
+ ah_precompile_key: str,
284
+ timings: Dict[ChoiceCaller, float],
285
+ name: str,
286
+ input_nodes: List[Any],
287
+ choices: List[ChoiceCaller],
288
+ ) -> None:
289
+ current_inputs_key = create_inputs_key(input_nodes)
290
+ if current_inputs_key != ah_inputs_key:
291
+ return
292
+ current_precompile_key = create_precompile_key(
293
+ name, current_inputs_key, choices
294
+ )
295
+ if current_precompile_key != ah_precompile_key:
296
+ return
297
+ for choice, time in timings.items():
298
+ self.save_data(choice.autoheuristic_id(), time)
299
+
300
+ inputs_key = create_inputs_key(input_nodes)
301
+ precompile_key = create_precompile_key(self.name, inputs_key, choices)
302
+ feedback_saver = partial(store_global_feedback, inputs_key, precompile_key)
303
+ add_feedback_saver(feedback_saver)
304
+
305
+ def get_choice_caller(self) -> Optional[ChoiceCaller]:
306
+ choice = self.get_choice()
307
+ return self.choicestr2choice.get(choice, None)
308
+
309
+ def get_top_k_choices_caller(
310
+ self, top_k: int, always_included: Optional[List[str]] = None
311
+ ) -> Optional[List[ChoiceCaller]]:
312
+ choices = self.get_top_k_choices(top_k, always_included)
313
+ if choices is None:
314
+ return None
315
+ return [self.choicestr2choice[choice] for choice in choices]
lib/python3.12/site-packages/torch/_inductor/autoheuristic/autoheuristic_utils.py ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import functools
2
+ from typing import Any, Callable, Dict, List, Tuple
3
+
4
+ import torch
5
+
6
+
7
+ Feedback = float
8
+ Choice = str
9
+ Value = Any
10
+
11
+ CHOICE_COL = "choice"
12
+ FEEDBACK_COL = "feedback"
13
+
14
+
15
+ class AHFeature:
16
+ """
17
+ The context, that AutoHeuristic stores, is a list of features. AutoHeuristic needs to know whether a feature is
18
+ categorical (i.e., not a continuous variable) to learn a machine learning model.
19
+ """
20
+
21
+ def __init__(self, name: str, value: Value, is_categorical: bool = False) -> None:
22
+ self.name = name
23
+ self.value = value
24
+ self.is_categorical = is_categorical
25
+
26
+
27
+ class AHOperation:
28
+ """
29
+ AHOperation can be used to augment the data collected by AutoHeuristic.
30
+ One might for example store features like m, k, n, but also want to use
31
+ features like m*n, or k*n, to learn a heuristic. Instead of storing features
32
+ that can be created from the collected data, one can use AHOperation to
33
+ create new features from the collected data.
34
+ """
35
+
36
+ def __init__(
37
+ self, name: str, func: Callable[[Any], Value], is_categorical: bool = False
38
+ ) -> None:
39
+ self.name = name
40
+ self.func = func
41
+ self.is_categorical = is_categorical
42
+
43
+ def apply_operation(self, data: Any) -> None:
44
+ data[self.name] = self.func(data)
45
+
46
+
47
+ class AHContext:
48
+ """
49
+ This class is used to specify which information AutoHeuristic should store. For each choice, AutoHeursitic will
50
+ store the context and the collected feedback. The context could be something like the shape of a tensor, i.e.,
51
+ information that will help to learn a heuristic.
52
+ """
53
+
54
+ features: List[AHFeature]
55
+ context_dict: Dict[str, Value]
56
+
57
+ def __init__(self) -> None:
58
+ self.features = []
59
+ self.context_dict = {}
60
+
61
+ def add_feature(
62
+ self, name: str, value: Value, is_categorical: bool = False
63
+ ) -> None:
64
+ self.features.append(AHFeature(name, value, is_categorical=is_categorical))
65
+ self.context_dict[name] = value
66
+
67
+ def get_numerical_and_categorical_features(self) -> Tuple[List[str], List[str]]:
68
+ numerical_features = []
69
+ categorical_features = []
70
+ for feature in self.features:
71
+ if feature.is_categorical:
72
+ categorical_features.append(feature.name)
73
+ else:
74
+ numerical_features.append(feature.name)
75
+
76
+ return numerical_features, categorical_features
77
+
78
+ def get_feature_names_csv(self) -> str:
79
+ return ",".join(feature.name for feature in self.features)
80
+
81
+ def get_feature_values_csv(self) -> str:
82
+ return ",".join(str(feature.value) for feature in self.features)
83
+
84
+ def get_value(self, name: str) -> Value:
85
+ return self.context_dict[name]
86
+
87
+ def apply_operations(self, operations: List[AHOperation]) -> None:
88
+ for op in operations:
89
+ op.apply_operation(self.context_dict)
90
+
91
+
92
+ class AHMetadata:
93
+ def __init__(
94
+ self,
95
+ shared_memory: Any,
96
+ device_capa: Tuple[int, int],
97
+ choices: List[Choice],
98
+ name: str,
99
+ ) -> None:
100
+ # use amount of shared_memory and device_capability to identify GPU
101
+ # TODO(AlnisM): there might be a better way to do this
102
+ self.shared_memory = shared_memory
103
+ self.device_capa = device_capa
104
+ self.choices = choices
105
+ self.name = name
106
+
107
+ def to_dict(self) -> Dict[str, Value]:
108
+ return {
109
+ "shared_memory": self.shared_memory,
110
+ "device_capa": self.device_capa,
111
+ "name": self.name,
112
+ }
113
+
114
+
115
+ def get_metadata_str_from_log(log_path: str) -> str:
116
+ with open(log_path, newline="") as file:
117
+ json_string = file.readline().strip()
118
+ return json_string
119
+
120
+
121
+ def check_minsize(context: AHContext, minsize: int) -> bool:
122
+ return (
123
+ context.get_value("m") >= minsize
124
+ and context.get_value("k") >= minsize
125
+ and context.get_value("n") >= minsize
126
+ )
127
+
128
+
129
+ def pad_mm_precondition(metadata: AHMetadata, context: AHContext) -> bool:
130
+ if metadata.shared_memory == 166912 and metadata.device_capa == (8, 0):
131
+ # A100 precondition
132
+ return check_minsize(context, 512)
133
+ elif metadata.shared_memory == 232448 and metadata.device_capa == (9, 0):
134
+ # H100 precondition
135
+ return check_minsize(context, 768)
136
+ return True
137
+
138
+
139
+ def get_mixedmm_precondition(metadata: AHMetadata, context: AHContext) -> bool:
140
+ m = context.get_value("m")
141
+ k = context.get_value("k")
142
+ n = context.get_value("n")
143
+ if m > 128 or k < 1024 or n < 1024:
144
+ return False
145
+ mat1_iscontig = context.get_value("mat1_iscontig")
146
+ mat2_iscontig = context.get_value("mat2_iscontig")
147
+ return mat1_iscontig and not mat2_iscontig
148
+
149
+
150
+ def get_mult_dims_ops() -> List[AHOperation]:
151
+ m_times_k_op = AHOperation("m*k", lambda data: data["m"] * data["k"])
152
+ m_times_n_op = AHOperation("m*n", lambda data: data["m"] * data["n"])
153
+ k_times_n_op = AHOperation("k*n", lambda data: data["k"] * data["n"])
154
+ return [m_times_k_op, m_times_n_op, k_times_n_op]
155
+
156
+
157
+ def get_arith_intensity(data: Any) -> float:
158
+ m = data["m"]
159
+ k = data["k"]
160
+ n = data["n"]
161
+ if m == 0 or k == 0 or n == 0:
162
+ return 0.0
163
+ return m * k * n / (m * k + k * n + m * n)
164
+
165
+
166
+ def pad_mm_operations() -> List[AHOperation]:
167
+ mult_dims_ops = get_mult_dims_ops()
168
+ k_div_m_times_n_op = AHOperation(
169
+ "k/(m*n)", lambda data: data["k"] / (data["m"] * data["n"])
170
+ )
171
+
172
+ def bfloat_perf_hit(data: Any) -> bool:
173
+ m = data["m"]
174
+ k = data["k"]
175
+ n = data["n"]
176
+ is_bfloat = str(data["mat1_dtype"]) == "torch.bfloat16"
177
+ return k > (m * 1024) and k > (n * 1024) and is_bfloat
178
+
179
+ bfloat_perf_hit_op = AHOperation(
180
+ "bfloat_perf_hit", bfloat_perf_hit, is_categorical=True
181
+ )
182
+
183
+ arith_intensity_op = AHOperation("arith_intensity", get_arith_intensity)
184
+ dims_need_padding_ops = get_dims_need_padding_ops()
185
+ dims_multiple_ops = get_dims_multiple_ops()
186
+ is_contig_ops = get_is_contig_ops()
187
+
188
+ ah_operations = mult_dims_ops + [
189
+ k_div_m_times_n_op,
190
+ bfloat_perf_hit_op,
191
+ arith_intensity_op,
192
+ ]
193
+ ah_operations.extend(dims_need_padding_ops)
194
+ ah_operations.extend(dims_multiple_ops)
195
+ ah_operations.extend(is_contig_ops)
196
+ return ah_operations
197
+
198
+
199
+ def between_op(data: Any, dim: str, lower: int, upper: int) -> bool:
200
+ return data[dim] >= lower and data[dim] <= upper
201
+
202
+
203
+ def between_ops() -> List[AHOperation]:
204
+ dims = ["m", "k", "n"]
205
+ limits = [(1, 16), (17, 32), (33, 64), (65, 128), (129, 256)]
206
+ ah_operations = []
207
+ for dim in dims:
208
+ for lower, upper in limits:
209
+ between_op_fn = functools.partial(
210
+ between_op, dim=dim, lower=lower, upper=upper
211
+ )
212
+ # using 'LEQ' instead of '<=' because '<=' cannot be exported to dot
213
+ between_op_name = f"{lower}LEQ{dim}LEQ{upper}"
214
+ ah_operations.append(
215
+ AHOperation(between_op_name, between_op_fn, is_categorical=True)
216
+ )
217
+ return ah_operations
218
+
219
+
220
+ def pow2_op(data: Any, dim: str, exponent: int) -> bool:
221
+ return data[dim] == 2**exponent
222
+
223
+
224
+ def mm_operations() -> List[AHOperation]:
225
+ mult_dims_ops = get_mult_dims_ops()
226
+ arith_intensity_op = AHOperation("arith_intensity", get_arith_intensity)
227
+ return mult_dims_ops + [arith_intensity_op]
228
+
229
+
230
+ def mixed_mm_operations() -> List[AHOperation]:
231
+ return mm_operations() + between_ops()
232
+
233
+
234
+ def is_multiple(data: Any, dim: str, mult: int) -> bool:
235
+ return data[dim] % mult == 0
236
+
237
+
238
+ def get_dims_multiple_ops() -> List[AHOperation]:
239
+ multiples = [2, 4, 8, 16, 32]
240
+ dims = ["m", "k", "n"]
241
+ dims_multiple_ops = []
242
+ for dim in dims:
243
+ for mult in multiples:
244
+ is_multiple_fn = functools.partial(is_multiple, dim=dim, mult=mult)
245
+ dims_multiple_op = AHOperation(
246
+ f"{dim}_multiple_{mult}", is_multiple_fn, is_categorical=True
247
+ )
248
+ dims_multiple_ops.append(dims_multiple_op)
249
+ return dims_multiple_ops
250
+
251
+
252
+ def get_dims_need_padding_ops() -> List[AHOperation]:
253
+ def mat1_innermost_needs_padding_fn(data: Any) -> bool:
254
+ mat1_stride_0 = data["mat1_stride_0"]
255
+ mat1_stride_1 = data["mat1_stride_1"]
256
+ m_padded_length = data["m_padded_length"]
257
+ k_padded_length = data["k_padded_length"]
258
+ mat1_innermost_needs_padding = False
259
+ if mat1_stride_0 == 1 and m_padded_length != 0:
260
+ mat1_innermost_needs_padding = True
261
+ if mat1_stride_1 == 1 and k_padded_length != 0:
262
+ mat1_innermost_needs_padding = True
263
+ return mat1_innermost_needs_padding
264
+
265
+ mat1_innermost_op = AHOperation(
266
+ "mat1_innermost_needs_padding",
267
+ mat1_innermost_needs_padding_fn,
268
+ is_categorical=True,
269
+ )
270
+
271
+ def mat2_innermost_needs_padding_fn(data: Any) -> bool:
272
+ mat2_stride_0 = data["mat2_stride_0"]
273
+ mat2_stride_1 = data["mat2_stride_1"]
274
+ k_padded_length = data["k_padded_length"]
275
+ n_padded_length = data["n_padded_length"]
276
+ mat2_innermost_needs_padding = False
277
+ if mat2_stride_0 == 1 and k_padded_length != 0:
278
+ mat2_innermost_needs_padding = True
279
+ if mat2_stride_1 == 1 and n_padded_length != 0:
280
+ mat2_innermost_needs_padding = True
281
+ return mat2_innermost_needs_padding
282
+
283
+ mat2_innermost_op = AHOperation(
284
+ "mat2_innermost_needs_padding",
285
+ mat2_innermost_needs_padding_fn,
286
+ is_categorical=True,
287
+ )
288
+
289
+ def num_dims_needs_padding_fn(data: Any) -> int:
290
+ m_padded_length = data["m_padded_length"]
291
+ k_padded_length = data["k_padded_length"]
292
+ n_padded_length = data["n_padded_length"]
293
+ num_dims_needs_padding = 0
294
+ if m_padded_length != 0:
295
+ num_dims_needs_padding += 1
296
+ if k_padded_length != 0:
297
+ num_dims_needs_padding += 1
298
+ if n_padded_length != 0:
299
+ num_dims_needs_padding += 1
300
+ return num_dims_needs_padding
301
+
302
+ num_dims_op = AHOperation("num_dims_needs_padding", num_dims_needs_padding_fn)
303
+ return [mat1_innermost_op, mat2_innermost_op, num_dims_op]
304
+
305
+
306
+ def get_is_contig_ops() -> List[AHOperation]:
307
+ def mat1_is_contig_fn(data: Any) -> bool:
308
+ stride_0 = data["mat1_stride_0"]
309
+ stride_1 = data["mat1_stride_1"]
310
+ k = data["k"]
311
+ return stride_0 == k and stride_1 == 1
312
+
313
+ mat1_is_contig_op = AHOperation(
314
+ "mat1_iscontig", mat1_is_contig_fn, is_categorical=True
315
+ )
316
+
317
+ def mat2_is_contig_fn(data: Any) -> bool:
318
+ stride_0 = data["mat2_stride_0"]
319
+ stride_1 = data["mat2_stride_1"]
320
+ n = data["n"]
321
+ return stride_0 == n and stride_1 == 1
322
+
323
+ mat2_is_contig_op = AHOperation(
324
+ "mat2_iscontig", mat2_is_contig_fn, is_categorical=True
325
+ )
326
+
327
+ return [mat1_is_contig_op, mat2_is_contig_op]
328
+
329
+
330
+ def context_add_strides(context: AHContext, name: str, stride: Tuple[int, ...]) -> None:
331
+ for i, s in enumerate(stride):
332
+ context.add_feature(f"{name}_stride_{i}", s)
333
+
334
+
335
+ def context_add_using_tf32(context: AHContext, dtype: torch.dtype) -> None:
336
+ using_tf32 = "not_float_32"
337
+ if dtype == torch.float32:
338
+ using_tf32 = torch.backends.cuda.matmul.allow_tf32
339
+ context.add_feature("using_tf32", using_tf32, is_categorical=True)
lib/python3.12/site-packages/torch/_inductor/autoheuristic/learned_heuristic_controller.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import importlib
2
+ import inspect
3
+ import pkgutil
4
+ from collections import defaultdict
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ from torch._inductor.autoheuristic.autoheuristic_utils import (
8
+ AHContext,
9
+ AHMetadata,
10
+ Choice,
11
+ )
12
+ from torch._inductor.autoheuristic.learnedheuristic_interface import LearnedHeuristic
13
+
14
+
15
+ def find_and_instantiate_subclasses(
16
+ package_name: str, base_class: Any
17
+ ) -> List[LearnedHeuristic]:
18
+ instances = []
19
+
20
+ package = importlib.import_module(package_name)
21
+ for _, module_name, _ in pkgutil.walk_packages(
22
+ package.__path__, package.__name__ + "."
23
+ ):
24
+ try:
25
+ module_basename = module_name.split(".")[-1]
26
+ if not module_basename.startswith("_"):
27
+ # learned heuristics start with an underscore
28
+ continue
29
+ module = importlib.import_module(module_name)
30
+
31
+ # look for classes that are subclasses of base_class
32
+ for name, obj in inspect.getmembers(module):
33
+ if (
34
+ inspect.isclass(obj)
35
+ and issubclass(obj, base_class)
36
+ and obj != base_class
37
+ ):
38
+ instance = obj()
39
+ instances.append(instance)
40
+ except Exception as e:
41
+ print(f"Error processing module {module_name}: {e}")
42
+
43
+ return instances
44
+
45
+
46
+ class LearnedHeuristicController:
47
+ """
48
+ Class that finds and instantiates all learned heuristics. It also provides
49
+ a way to get the decision of a learned heuristic.
50
+ """
51
+
52
+ existing_heuristics: Dict[str, List[LearnedHeuristic]] = defaultdict(list)
53
+ """
54
+ A dictionary that stores all the learned heuristics for each optimization.
55
+ The key is the optimization name, and the value is a list of LearnedHeuristic objects.
56
+ """
57
+
58
+ heuristics_initialized: bool = False
59
+ """
60
+ A flag that indicates whether the learned heuristics have been initialized.
61
+ Set to true when the get_decision() function is called for the first time.
62
+ """
63
+
64
+ def __init__(
65
+ self,
66
+ metadata: AHMetadata,
67
+ context: AHContext,
68
+ ) -> None:
69
+ self.metadata = metadata
70
+ self.context = context
71
+
72
+ def get_heuristics(self, name: str) -> List[LearnedHeuristic]:
73
+ """
74
+ Returns a list of learned heuristics for the given optimization name.
75
+ """
76
+
77
+ if not LearnedHeuristicController.heuristics_initialized:
78
+ # learned heuristics are generated into the following package
79
+ learned_heuristics_package = "torch._inductor.autoheuristic.artifacts"
80
+
81
+ # learned heuristics have to be of type LearnedHeuristic
82
+ base_class = LearnedHeuristic
83
+ found_heuristics = find_and_instantiate_subclasses(
84
+ learned_heuristics_package, base_class
85
+ )
86
+
87
+ for learned_heuristic in found_heuristics:
88
+ opt_name = learned_heuristic.get_name()
89
+ LearnedHeuristicController.existing_heuristics[opt_name].append(
90
+ learned_heuristic
91
+ )
92
+ LearnedHeuristicController.heuristics_initialized = True
93
+
94
+ return LearnedHeuristicController.existing_heuristics[name]
95
+
96
+ def get_decision(self) -> Optional[Choice]:
97
+ """
98
+ Returns the decision made by the learned heuristic or None if no heuristic was found or the heuristic is unsure
99
+ which choice to make.
100
+ """
101
+
102
+ heuristics = self.get_heuristics(self.metadata.name)
103
+ for heuristic in heuristics:
104
+ if heuristic.check_precondition(self.metadata, self.context):
105
+ return heuristic.get_decision(self.context, self.metadata.choices)
106
+ return None
107
+
108
+ def get_decisions_ranked(self, top_k: int) -> Optional[List[Choice]]:
109
+ heuristics = self.get_heuristics(self.metadata.name)
110
+ for heuristic in heuristics:
111
+ if heuristic.check_precondition(self.metadata, self.context):
112
+ choices = heuristic.get_decisions_ranked(self.context)
113
+ if choices is None:
114
+ return None
115
+ avail_choices = [
116
+ choice for choice in choices if choice in self.metadata.choices
117
+ ]
118
+ return avail_choices[:top_k]
119
+ return None
lib/python3.12/site-packages/torch/_inductor/autoheuristic/learnedheuristic_interface.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Optional, Tuple
2
+
3
+ from torch._inductor.autoheuristic.autoheuristic_utils import (
4
+ AHContext,
5
+ AHMetadata,
6
+ Choice,
7
+ )
8
+
9
+
10
+ class LearnedHeuristic:
11
+ """
12
+ LearnedHeuristic is a base class for all learned heuristics.
13
+ """
14
+
15
+ def __init__(self) -> None:
16
+ pass
17
+
18
+ def check_precondition(
19
+ self,
20
+ metadata: AHMetadata,
21
+ context: AHContext,
22
+ ) -> bool:
23
+ return True
24
+
25
+ def get_decision(
26
+ self, context: AHContext, choices: List[Choice]
27
+ ) -> Optional[Choice]:
28
+ return None
29
+
30
+ def get_confidence_threshold(self) -> float:
31
+ return 1.0
32
+
33
+ def get_name(self) -> str:
34
+ return ""
35
+
36
+ def get_decisions_ranked(self, context: AHContext) -> Optional[List[str]]:
37
+ return None
38
+
39
+
40
+ class LearnedHeuristicRegression(LearnedHeuristic):
41
+ def __init__(self) -> None:
42
+ super().__init__()
43
+
44
+ def get_feedback(self, context: AHContext, choice: Choice) -> float:
45
+ return 1.0
46
+
47
+ def get_decision(
48
+ self, context: AHContext, choices: List[Choice]
49
+ ) -> Optional[Choice]:
50
+ choice2feedback = {}
51
+ for choice in choices:
52
+ predicted_feedback = self.get_feedback(context, choice)
53
+ choice2feedback[choice] = predicted_feedback
54
+ sorted_choices_feedback = sorted(choice2feedback.items(), key=lambda t: t[1])
55
+ highest_feedback = sorted_choices_feedback[-1][1]
56
+ second_highest_feedback = sorted_choices_feedback[-2][1]
57
+ if highest_feedback / second_highest_feedback > self.get_confidence_threshold():
58
+ return sorted_choices_feedback[-1][0]
59
+ # We are not sure which choice is the best one
60
+ return None
61
+
62
+
63
+ class LearnedHeuristicDecision(LearnedHeuristic):
64
+ def __init__(self) -> None:
65
+ super().__init__()
66
+
67
+ def get_choice(self, idx: int) -> Optional[str]:
68
+ return None
69
+
70
+ def get_decision(
71
+ self, context: AHContext, choices: List[Choice]
72
+ ) -> Optional[Choice]:
73
+ best_choices = self.get_best_choices(context)
74
+ if not best_choices:
75
+ return None
76
+ (best_choice_proba, best_choice_idx) = best_choices[0]
77
+ if best_choice_proba <= self.get_confidence_threshold():
78
+ return None
79
+ return self.get_choice(best_choice_idx)
80
+
81
+ def get_decisions_ranked(self, context: AHContext) -> Optional[List[str]]:
82
+ feedback_idx_list = self.get_best_choices(context)
83
+ if feedback_idx_list is None:
84
+ return None
85
+ choices = [
86
+ self.get_choice(feedback_idx[1]) for feedback_idx in feedback_idx_list
87
+ ]
88
+ choices = [choice for choice in choices if choice is not None]
89
+ return choices
90
+
91
+ def get_best_choices(self, context: AHContext) -> Optional[List[Tuple[float, int]]]:
92
+ return []
lib/python3.12/site-packages/torch/_inductor/autotune_process.py ADDED
@@ -0,0 +1,931 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ from __future__ import annotations
3
+
4
+ import contextlib
5
+ import ctypes
6
+ import dataclasses
7
+ import functools
8
+ import logging
9
+ import os
10
+ import queue
11
+ import time
12
+ import warnings
13
+ from concurrent.futures import ThreadPoolExecutor
14
+ from ctypes import byref, c_size_t, c_void_p, CDLL
15
+ from typing import (
16
+ Any,
17
+ Callable,
18
+ Dict,
19
+ Iterable,
20
+ List,
21
+ Optional,
22
+ Sequence,
23
+ TYPE_CHECKING,
24
+ Union,
25
+ )
26
+
27
+ import torch
28
+ import torch._inductor.async_compile # noqa: F401 required to warm up AsyncCompile pools
29
+ from torch import multiprocessing
30
+ from torch._dynamo.testing import rand_strided
31
+ from torch._inductor import ir
32
+ from torch._inductor.codecache import (
33
+ CppCodeCache,
34
+ CUDACodeCache,
35
+ DLLWrapper,
36
+ get_hash,
37
+ PyCodeCache,
38
+ )
39
+
40
+
41
+ if TYPE_CHECKING:
42
+ from multiprocessing.process import BaseProcess
43
+ from multiprocessing.queues import Queue
44
+ from types import ModuleType
45
+
46
+ from torch._inductor.select_algorithm import TritonTemplateCaller
47
+ from .codegen.common import WorkspaceArg
48
+
49
+ from . import config
50
+ from .codegen.common import WorkspaceZeroMode
51
+ from .runtime.benchmarking import benchmarker
52
+ from .virtualized import V
53
+
54
+
55
+ CUDA_VISIBLE_DEVICES = "CUDA_VISIBLE_DEVICES"
56
+ EXIT_HANDLER_REGISTERED = False
57
+
58
+ log = logging.getLogger(__name__)
59
+
60
+
61
+ # Used to synchronize between parent and child processes
62
+ class Ping:
63
+ pass
64
+
65
+
66
+ class Pong:
67
+ pass
68
+
69
+
70
+ class NonzeroWorkspaceNotSupportedError(Exception):
71
+ pass
72
+
73
+
74
+ @contextlib.contextmanager
75
+ def set_cuda_visible_device(device: Optional[int]):
76
+ """
77
+ Context manager to set the CUDA_VISIBLE_DEVICES environment variable to the
78
+ specified single device. If device is None, don't manipulate the environment.
79
+ """
80
+ if device is None:
81
+ yield
82
+ return
83
+
84
+ current = os.environ.get(CUDA_VISIBLE_DEVICES)
85
+ os.environ[CUDA_VISIBLE_DEVICES] = str(device)
86
+ try:
87
+ yield
88
+ finally:
89
+ if current is None:
90
+ del os.environ[CUDA_VISIBLE_DEVICES]
91
+ else:
92
+ os.environ[CUDA_VISIBLE_DEVICES] = current
93
+
94
+
95
+ @dataclasses.dataclass
96
+ class TuningProcess:
97
+ """
98
+ Abstraction for launching a helper process to benchmark kernels. Spawns
99
+ the parent process and uses multiprocessing queues to send benchmark
100
+ requests and return results.
101
+ """
102
+
103
+ device: Optional[int] = None
104
+ process: Optional[BaseProcess] = None
105
+ request_queue: Optional[Queue[Any]] = None
106
+ response_queue: Optional[Queue[Any]] = None
107
+
108
+ @staticmethod
109
+ def process_main(
110
+ request_queue: Queue[Any],
111
+ response_queue: Queue[Any],
112
+ ) -> None:
113
+ """
114
+ Entry point for the child process.
115
+ """
116
+ log.debug(
117
+ "Entering TuningProcess child. Visible devices = %s",
118
+ os.environ.get(CUDA_VISIBLE_DEVICES),
119
+ )
120
+ try:
121
+ TuningProcess.workloop(request_queue, response_queue)
122
+ except Exception as ex:
123
+ log.exception("Exception in TuningProcess")
124
+
125
+ @staticmethod
126
+ def workloop(request_queue: Queue[Any], response_queue: Queue[Any]) -> None:
127
+ """
128
+ Work loop for the benchmarking subprocess.
129
+ """
130
+ while True:
131
+ obj = request_queue.get()
132
+
133
+ if obj is None:
134
+ break # None is a sentinel for the child to terminate
135
+ elif isinstance(obj, Ping):
136
+ response_queue.put(Pong())
137
+ elif isinstance(obj, BenchmarkRequest):
138
+ response_queue.put(obj.benchmark())
139
+ else:
140
+ raise RuntimeError(f"Invalid request type {type(obj)}")
141
+
142
+ def valid(self) -> bool:
143
+ """
144
+ True if the sub-process has been initialized.
145
+ """
146
+ return (
147
+ self.process is not None
148
+ and self.request_queue is not None
149
+ and self.response_queue is not None
150
+ )
151
+
152
+ def clear(self) -> None:
153
+ """
154
+ Reset to an uninitialized state.
155
+ """
156
+ self.process = self.request_queue = self.response_queue = None
157
+
158
+ def initialize(self) -> None:
159
+ """
160
+ Create child process, request/response queues, and do the warm up.
161
+ Set the environment to make only the provided GPU device visible
162
+ to the process.
163
+ """
164
+ if self.valid():
165
+ return
166
+
167
+ # cuda runtime does not work with "fork", use "spawn" to start processes.
168
+ ctx = multiprocessing.get_context("spawn")
169
+ self.request_queue = ctx.Queue()
170
+ self.response_queue = ctx.Queue()
171
+
172
+ self.process = ctx.Process(
173
+ target=self.process_main,
174
+ args=(
175
+ self.request_queue,
176
+ self.response_queue,
177
+ ),
178
+ )
179
+ assert self.process is not None
180
+ with set_cuda_visible_device(self.device):
181
+ self.process.start()
182
+
183
+ def put(self, obj: Any) -> None:
184
+ """
185
+ Push a work item to the child process.
186
+ """
187
+ # In case of a prior crash, ensure the subprocess is running
188
+ self.initialize()
189
+ assert self.request_queue is not None
190
+ self.request_queue.put(obj)
191
+
192
+ def get(
193
+ self, result_timeout=120.0, graceful_timeout=3.0, terminate_timeout=1.0
194
+ ) -> Any:
195
+ """
196
+ Get a response from the child process. Raises queue.Empty on timeout
197
+ or if the process dies.
198
+
199
+ This method is (so far) only used by TuningProcessPool, where torch._inductor.config entries are being used
200
+ to populate the timeouts:
201
+
202
+ Arguments:
203
+
204
+ @param result_timeout: Timeout in seconds, defaults to 120.0 or to
205
+ config.max_autotune_subproc_result_timeout_seconds when called by TuningProcessPool
206
+ @param graceful_timeout: Timeout in seconds to allow graceful shutdown (SIGTERM is sent after this time).
207
+ Defaults to 3.0 or to config.max_autotune_subproc_graceful_timeout_seconds
208
+ @param terminate_timeout: Timeout in seconds after SIGTERM, until we send SIGKILL if the process
209
+ remains alive. Defaults to 1.0 or to
210
+ config.max_autotune_subproc_terminate_timeout_seconds.
211
+ Returns:
212
+ A response from the child process (Any type)
213
+ """
214
+ assert self.process is not None
215
+ assert self.response_queue is not None
216
+ while True:
217
+ try:
218
+ remaining_timeout = result_timeout
219
+ res = None
220
+ while remaining_timeout is not None and remaining_timeout >= 1.0:
221
+ remaining_timeout -= 0.5
222
+ try:
223
+ res = self.response_queue.get(timeout=0.5)
224
+ break
225
+ except queue.Empty:
226
+ if not self.process.is_alive():
227
+ raise # is being caught a few lines below
228
+ if res is None:
229
+ res = self.response_queue.get(timeout=remaining_timeout)
230
+ return res
231
+ except queue.Empty:
232
+ status = self.process.exitcode
233
+ if status is None:
234
+ self.kill(
235
+ graceful_timeout=graceful_timeout,
236
+ terminate_timeout=terminate_timeout,
237
+ )
238
+ else:
239
+ # child process crashed
240
+ self.clear()
241
+ raise
242
+
243
+ def terminate(self) -> None:
244
+ """
245
+ Signal the child process to terminate.
246
+ """
247
+ if self.valid():
248
+ assert self.process is not None
249
+ assert self.request_queue is not None
250
+ self.request_queue.put(None)
251
+
252
+ def wait(self) -> None:
253
+ """
254
+ Wait for the child process to exit.
255
+ """
256
+ if self.process is not None:
257
+ self.process.join()
258
+ self.clear()
259
+
260
+ def kill(self, graceful_timeout=5.0, terminate_timeout=1.0) -> None:
261
+ # Tries to kill the process, using a graceful_timeout in which the process
262
+ # is allowed to exit gracefully. If the process is still alive,
263
+ # it will be terminated. If that is not sufficient to end it
264
+ # within terminate_timeout seconds, it will be killed.
265
+ if self.process is not None:
266
+ self.terminate()
267
+ self.process.join(timeout=graceful_timeout)
268
+ if self.process.is_alive():
269
+ log.warning(
270
+ "Sending SIGTERM to process with PID %d",
271
+ self.process.pid,
272
+ )
273
+ self.process.terminate()
274
+ self.process.join(timeout=terminate_timeout)
275
+ if self.process.is_alive():
276
+ log.error(
277
+ "Sending SIGKILL to process with PID %d",
278
+ self.process.pid,
279
+ )
280
+ self.process.kill() # This should definitely end the process
281
+ self.clear()
282
+
283
+
284
+ @dataclasses.dataclass
285
+ class TuningProcessPool:
286
+ """
287
+ Maintains a pool of TuningProcesses to benchmark kernels in parallel
288
+ across devices. By default, we create one TuningProcess per device and
289
+ set the sub-process environment to make only that device visible.
290
+ """
291
+
292
+ processes: Optional[queue.Queue[TuningProcess]] = None
293
+ executor: Optional[ThreadPoolExecutor] = None
294
+
295
+ def initialize(self) -> None:
296
+ """
297
+ Start the child processes.
298
+ """
299
+ assert (self.processes is None) == (self.executor is None)
300
+ if self.processes is not None:
301
+ return
302
+
303
+ devices = self.get_device_list()
304
+ log.debug("Sub-process autotune device list: %s", devices)
305
+
306
+ # Launch the child processes and push a msg to "warm up"
307
+ self.processes = queue.Queue()
308
+ for device in devices:
309
+ p = TuningProcess(device=device)
310
+ p.initialize()
311
+ p.put(Ping())
312
+ self.processes.put(p)
313
+
314
+ # Wait for the initialization to finish
315
+ for p in self.processes.queue:
316
+ assert isinstance(p.get(result_timeout=None), Pong)
317
+
318
+ # Use a thread pool to manage distributing work to the subprocesses.
319
+ # Threads block on an available process, so it makes sense to match
320
+ # the number of threads with the number of devices.
321
+ self.executor = ThreadPoolExecutor(max_workers=len(devices))
322
+
323
+ # Register the exit handler for the parent process so it will terminate
324
+ # the child processes.
325
+ global EXIT_HANDLER_REGISTERED
326
+ if not EXIT_HANDLER_REGISTERED:
327
+ EXIT_HANDLER_REGISTERED = True
328
+ import atexit
329
+
330
+ atexit.register(self.terminate)
331
+
332
+ def get_device_list(self) -> Sequence[Optional[int]]:
333
+ """
334
+ Gather the list of devices to be used in the pool.
335
+ """
336
+ if not config.autotune_multi_device:
337
+ # Don't use multiple devices
338
+ return [None]
339
+
340
+ count = torch.cuda.device_count()
341
+
342
+ # If the user specified the visible devices in the env, use those.
343
+ if CUDA_VISIBLE_DEVICES in os.environ:
344
+ devices = [int(d) for d in os.environ[CUDA_VISIBLE_DEVICES].split(",")]
345
+ assert len(devices) <= count
346
+ return devices
347
+
348
+ return list(range(count))
349
+
350
+ def terminate(self) -> None:
351
+ """
352
+ Signal all child processes to terminate.
353
+ """
354
+ if self.executor is not None:
355
+ self.executor.shutdown()
356
+ self.executor = None
357
+
358
+ if self.processes is not None:
359
+ for p in self.processes.queue:
360
+ p.terminate()
361
+ for p in self.processes.queue:
362
+ p.wait()
363
+ self.processes = None
364
+
365
+ def target(self, choice: TritonTemplateCaller) -> float:
366
+ """
367
+ Entry point for the thread-pool helper threads: Wait for an open TuningProcess,
368
+ remove it from the queue, execute the benchmark in that subprocess, and return
369
+ the TuningProcess to the queue.
370
+ """
371
+ assert choice.bmreq is not None
372
+ assert self.processes is not None
373
+
374
+ process = self.processes.get()
375
+ process.put(choice.bmreq)
376
+ try:
377
+ return process.get(
378
+ config.max_autotune_subproc_result_timeout_seconds,
379
+ config.max_autotune_subproc_graceful_timeout_seconds,
380
+ config.max_autotune_subproc_terminate_timeout_seconds,
381
+ )
382
+ except queue.Empty:
383
+ warnings.warn(
384
+ f"Failed to benchmark choice '{choice}'. It will be ignored. "
385
+ "Please debug the root cause in case the choice can bring perf gains."
386
+ )
387
+ # set to INF so this choice will be ignored
388
+ return float("inf")
389
+ finally:
390
+ self.processes.put(process)
391
+
392
+ def benchmark(
393
+ self,
394
+ choices: List[TritonTemplateCaller],
395
+ ) -> Dict[TritonTemplateCaller, float]:
396
+ """
397
+ Benchmark each choice in a separate process.
398
+ """
399
+ assert self.processes is not None, "Tuning process pool is not initialized"
400
+ assert self.executor is not None
401
+
402
+ results = {}
403
+
404
+ # Use a ThreadExecutorPool to spread the work across the subprocesses and
405
+ # to grab subprocesses as soon as they're free.
406
+ for choice, result in zip(choices, self.executor.map(self.target, choices)):
407
+ results[choice] = result
408
+
409
+ return results
410
+
411
+
412
+ tuning_pool = TuningProcessPool()
413
+
414
+
415
+ LayoutOrBuffer = Union[ir.Layout, ir.Buffer]
416
+
417
+
418
+ @dataclasses.dataclass
419
+ class TensorMeta:
420
+ device: torch.device
421
+ dtype: torch.dtype
422
+ sizes: torch._prims_common.ShapeType
423
+ strides: torch._prims_common.StrideType
424
+ offset: int
425
+ name: Optional[str] = None
426
+
427
+ @classmethod
428
+ def from_irnodes(
429
+ cls, irnodes: Union[LayoutOrBuffer, Sequence[LayoutOrBuffer]]
430
+ ) -> Union[TensorMeta, List[TensorMeta]]:
431
+ if isinstance(irnodes, Sequence):
432
+ result: List[Any] = [cls.from_irnodes(x) for x in irnodes]
433
+ assert all(isinstance(x, TensorMeta) for x in result)
434
+ return result
435
+
436
+ node = irnodes
437
+ if isinstance(node, ir.Layout):
438
+ node = ir.Buffer(name="fake", layout=node)
439
+
440
+ dtype = node.get_dtype()
441
+ assert dtype is not None
442
+ device = node.get_device()
443
+ assert device is not None
444
+
445
+ return TensorMeta(
446
+ device=device,
447
+ dtype=dtype,
448
+ sizes=V.graph.sizevars.size_hints(
449
+ node.get_size(),
450
+ fallback=config.unbacked_symint_fallback,
451
+ ),
452
+ strides=V.graph.sizevars.size_hints(
453
+ node.get_stride(),
454
+ fallback=config.unbacked_symint_fallback,
455
+ ),
456
+ offset=V.graph.sizevars.size_hint(
457
+ node.get_layout().offset,
458
+ fallback=config.unbacked_symint_fallback,
459
+ ),
460
+ name=node.get_name(),
461
+ )
462
+
463
+ def to_tensor(self) -> torch.Tensor:
464
+ return rand_strided(
465
+ self.sizes,
466
+ self.strides,
467
+ device=self.device,
468
+ dtype=self.dtype,
469
+ extra_size=self.offset,
470
+ )
471
+
472
+
473
+ @dataclasses.dataclass
474
+ class BenchmarkRequest:
475
+ """
476
+ Only handle triton template benchmark for now. The extern kernel benchmark
477
+ can be done inside the same process since they usually don't cause crash.
478
+
479
+ Important: Instances of this class and subclasses have to be serializable
480
+ across process boundaries. Do not put CUDA Tensors in here!
481
+ """
482
+
483
+ def __init__(
484
+ self,
485
+ kernel_name: str,
486
+ input_tensor_meta: Union[TensorMeta, List[TensorMeta]],
487
+ output_tensor_meta: Union[TensorMeta, List[TensorMeta]],
488
+ extra_args: Iterable[Any],
489
+ ) -> None:
490
+ # the kernel name defined in the module
491
+ self.kernel_name = kernel_name
492
+
493
+ if isinstance(input_tensor_meta, TensorMeta):
494
+ input_tensor_meta = [input_tensor_meta]
495
+ self.input_tensor_meta = input_tensor_meta
496
+
497
+ if isinstance(output_tensor_meta, (tuple, list)):
498
+ assert len(output_tensor_meta) == 1
499
+ output_tensor_meta = output_tensor_meta[0]
500
+ self.output_tensor_meta = output_tensor_meta
501
+
502
+ self.extra_args = extra_args
503
+
504
+ def make_run_fn(
505
+ self, *input_tensors: torch.Tensor, output_tensor: torch.Tensor
506
+ ) -> Callable[[], None]:
507
+ raise NotImplementedError
508
+
509
+ def cleanup_run_fn(self) -> None:
510
+ pass
511
+
512
+ def do_bench(
513
+ self,
514
+ fn,
515
+ *input_tensors: torch.Tensor,
516
+ output_tensor: Optional[torch.Tensor] = None,
517
+ ) -> float:
518
+ raise NotImplementedError
519
+
520
+ def benchmark(
521
+ self,
522
+ *input_tensors: torch.Tensor,
523
+ output_tensor: Optional[torch.Tensor] = None,
524
+ ) -> float:
525
+ debug = log.isEnabledFor(logging.DEBUG)
526
+ if debug:
527
+ start_ts = time.time()
528
+
529
+ # create args and out tensor
530
+ if output_tensor is None:
531
+ assert len(input_tensors) == 0
532
+ input_tensors = tuple(x.to_tensor() for x in self.input_tensor_meta)
533
+ output_tensor = self.output_tensor_meta.to_tensor()
534
+
535
+ if debug:
536
+ create_tensor_elapse = time.time() - start_ts # type: ignore[possibly-undefined]
537
+ start_ts = time.time()
538
+ try:
539
+ fn = self.make_run_fn(*input_tensors, output_tensor=output_tensor)
540
+ except NonzeroWorkspaceNotSupportedError:
541
+ # Skipping all ops with nonzero workspace requirements
542
+ log.info("Skipping op due to nonzero workspace requirement")
543
+ return float("inf")
544
+
545
+ if debug:
546
+ load_elapse = time.time() - start_ts # type: ignore[possibly-undefined]
547
+ start_ts = time.time()
548
+
549
+ out = self.do_bench(fn, *input_tensors, output_tensor)
550
+
551
+ if debug:
552
+ bench_elapse = time.time() - start_ts # type: ignore[possibly-undefined]
553
+ log.debug(
554
+ "InChildProcess %s: load %f, create tensor %f, bench %f",
555
+ str(self),
556
+ load_elapse, # type: ignore[possibly-undefined]
557
+ create_tensor_elapse, # type: ignore[possibly-undefined]
558
+ bench_elapse,
559
+ )
560
+ self.cleanup_run_fn()
561
+ return out
562
+
563
+
564
+ class TestBenchmarkRequest(BenchmarkRequest):
565
+ """
566
+ Supports unit testing. Defined in this file so that the TuningProcess
567
+ sub-process knows how to unpickle these objects.
568
+ """
569
+
570
+ def __init__(self, value: Optional[float] = None) -> None:
571
+ self.value = value
572
+
573
+ def benchmark(
574
+ self, *input_tensors: torch.Tensor, output_tensor: Optional[torch.Tensor] = None
575
+ ) -> float:
576
+ if self.value is None:
577
+ raise Exception("Failed to run") # noqa: TRY002
578
+ return self.value
579
+
580
+
581
+ class GPUDeviceBenchmarkMixin:
582
+ def do_bench(
583
+ self,
584
+ fn,
585
+ *input_tensors: torch.Tensor,
586
+ output_tensor: Optional[torch.Tensor] = None,
587
+ ) -> float:
588
+ device_idx_set = {
589
+ tensor.device.index
590
+ for tensor in [*input_tensors, output_tensor]
591
+ if isinstance(tensor, torch.Tensor)
592
+ and tensor.is_cuda
593
+ and tensor.device.index is not None
594
+ }
595
+ assert len(device_idx_set) <= 1, f"Can not mix devices {device_idx_set}"
596
+ if len(device_idx_set) == 1:
597
+ device_idx = next(iter(device_idx_set))
598
+ else:
599
+ device_idx = torch.cuda.current_device()
600
+
601
+ with torch.cuda.device(device_idx):
602
+ out = benchmarker.benchmark_gpu(fn)
603
+ torch.cuda.synchronize() # shake out any CUDA errors
604
+
605
+ return out
606
+
607
+
608
+ class CPUDeviceBenchmarkMixin:
609
+ def do_bench(
610
+ self,
611
+ fn,
612
+ *input_tensors: torch.Tensor,
613
+ output_tensor: Optional[torch.Tensor] = None,
614
+ ) -> float:
615
+ return benchmarker.benchmark_cpu(fn)
616
+
617
+
618
+ class TritonBenchmarkRequest(BenchmarkRequest):
619
+ # Important: Instances of this class have to be serializable
620
+ # across process boundaries. Do not put CUDA Tensors in here!
621
+ def __init__(
622
+ self,
623
+ kernel_name: str,
624
+ input_tensor_meta: Union[TensorMeta, List[TensorMeta]],
625
+ output_tensor_meta: Union[TensorMeta, List[TensorMeta]],
626
+ extra_args: Iterable[Any],
627
+ module_path: str, # the path of the module defining the triton kernel
628
+ module_cache_key: str,
629
+ grid: List[int],
630
+ num_stages: int,
631
+ num_warps: int,
632
+ matrix_instr_nonkdim: int = 0, # only used for hip to choose the shape of mfma instruction.
633
+ workspace_arg: Optional[WorkspaceArg] = None,
634
+ ) -> None:
635
+ super().__init__(kernel_name, input_tensor_meta, output_tensor_meta, extra_args)
636
+ self.module_path = module_path
637
+ self.module_cache_key = module_cache_key
638
+ self.grid = grid
639
+ self.num_stages = num_stages
640
+ self.num_warps = num_warps
641
+ self.matrix_instr_nonkdim = matrix_instr_nonkdim
642
+ self.workspace_arg = workspace_arg
643
+
644
+ def make_run_fn(
645
+ self, *input_tensors: torch.Tensor, output_tensor: torch.Tensor
646
+ ) -> Callable[[], None]:
647
+ mod = PyCodeCache.load_by_key_path(self.module_cache_key, self.module_path)
648
+ log.debug(
649
+ "benchmark module key: %s, path: %s",
650
+ self.module_cache_key,
651
+ self.module_path,
652
+ )
653
+
654
+ run_method = getattr(mod, self.kernel_name).run
655
+ extra_args = list(self.extra_args)
656
+ run_method.__self__.with_bandwidth_info = False
657
+
658
+ # Newer version of triton add warmup argument to JITFunction.run.
659
+ # This code handles backward-compatibility.
660
+ warmup_arg = {}
661
+ import inspect
662
+
663
+ if "warmup" in inspect.signature(run_method).parameters:
664
+ warmup_arg["warmup"] = False
665
+
666
+ if output_tensor.device.type == "cpu":
667
+ stream = 0
668
+ else:
669
+ from torch._C import _cuda_getCurrentRawStream as get_raw_stream
670
+
671
+ stream = get_raw_stream(self.output_tensor_meta.device.index)
672
+
673
+ if self.workspace_arg is not None:
674
+ # Create a function that handles both workspace creation and kernel execution
675
+ workspace_arg = self.workspace_arg
676
+
677
+ def run_with_workspace():
678
+ # Create workspace tensor
679
+ workspace_size = workspace_arg.count
680
+ workspace_tensor = torch.empty_strided(
681
+ (workspace_size,),
682
+ (1,),
683
+ dtype=torch.uint8,
684
+ device=output_tensor.device,
685
+ )
686
+
687
+ # Handle zero initialization if needed
688
+ if workspace_arg.zero_mode == WorkspaceZeroMode.ZERO_ON_CALL:
689
+ workspace_tensor.zero_()
690
+
691
+ # Run the kernel with workspace
692
+ run_method(
693
+ *input_tensors,
694
+ output_tensor,
695
+ *extra_args,
696
+ workspace_tensor,
697
+ grid=self.grid,
698
+ **warmup_arg,
699
+ stream=stream,
700
+ benchmark_run=True,
701
+ )
702
+
703
+ return run_with_workspace
704
+ if isinstance(
705
+ getattr(mod, self.kernel_name),
706
+ torch._inductor.runtime.triton_heuristics.DebugAutotuner,
707
+ ):
708
+ return functools.partial(
709
+ run_method,
710
+ *input_tensors,
711
+ output_tensor,
712
+ *extra_args,
713
+ grid=self.grid,
714
+ **warmup_arg,
715
+ stream=stream,
716
+ )
717
+ else:
718
+ return functools.partial(
719
+ run_method,
720
+ *input_tensors,
721
+ output_tensor,
722
+ *extra_args,
723
+ grid=self.grid,
724
+ **warmup_arg,
725
+ stream=stream,
726
+ benchmark_run=True,
727
+ )
728
+
729
+ def precompile(self):
730
+ mod = PyCodeCache.load_by_key_path(self.module_cache_key, self.module_path)
731
+ getattr(mod, self.kernel_name).precompile()
732
+
733
+ def __str__(self) -> str:
734
+ return f"{self.kernel_name=}, {self.module_path=}, {self.module_cache_key=}"
735
+
736
+
737
+ class TritonGPUBenchmarkRequest(GPUDeviceBenchmarkMixin, TritonBenchmarkRequest):
738
+ pass
739
+
740
+
741
+ class TritonCPUBenchmarkRequest(CPUDeviceBenchmarkMixin, TritonBenchmarkRequest):
742
+ pass
743
+
744
+
745
+ class CUDABenchmarkRequest(GPUDeviceBenchmarkMixin, BenchmarkRequest):
746
+ # Important: Instances of this class have to be serializable
747
+ # across process boundaries. Do not put CUDA Tensors in here!
748
+
749
+ def __init__(
750
+ self,
751
+ kernel_name: str,
752
+ input_tensor_meta: Union[TensorMeta, List[TensorMeta]],
753
+ output_tensor_meta: Union[TensorMeta, List[TensorMeta]],
754
+ extra_args: Iterable[Any],
755
+ source_code: str,
756
+ ) -> None:
757
+ super().__init__(kernel_name, input_tensor_meta, output_tensor_meta, extra_args)
758
+ self.source_code = source_code
759
+ self.workspace_size: int = 0
760
+ self.workspace: Optional[torch.Tensor] = None
761
+ self.DLL: Optional[DLLWrapper] = None
762
+ self._workspace_size_updated = False
763
+ self.hash_key: str = ""
764
+ self.source_file: str = ""
765
+ self.hash_key, self.source_file = CUDACodeCache.write(self.source_code, "so")
766
+
767
+ def precompile(self):
768
+ # Prepopulate CUDACodeCache
769
+ # may happen in separate Threadpool
770
+ log.debug("Precompiling %s", self)
771
+ CUDACodeCache.compile(self.source_code, "so")
772
+ log.debug("Done precompiling %s", self)
773
+
774
+ def make_run_fn(
775
+ self, *input_tensors: torch.Tensor, output_tensor: torch.Tensor
776
+ ) -> Callable[[], None]:
777
+ self.ensure_dll_loaded()
778
+ self.update_workspace_size()
779
+ args = [
780
+ c_void_p(tensor.data_ptr())
781
+ for tensor in list(input_tensors) + [output_tensor]
782
+ ]
783
+ log.debug(
784
+ "make_run_fn: self.kernel_name=%s, self.source_file=%s, self.hash_key=%s, self.DLL=%s, args=%s, self.extra_args=%s",
785
+ self.kernel_name,
786
+ self.source_file,
787
+ self.hash_key,
788
+ self.DLL,
789
+ args,
790
+ self.extra_args,
791
+ )
792
+ stream_ptr = c_void_p(torch.cuda.current_stream().cuda_stream)
793
+ run_method = getattr(self.DLL, self.kernel_name)
794
+ workspace_ptr = c_void_p(0)
795
+ if self.workspace_size > 0:
796
+ self.workspace = torch.zeros(
797
+ (self.workspace_size + 7) // 8,
798
+ dtype=torch.float64,
799
+ device=output_tensor.device,
800
+ )
801
+ workspace_ptr = c_void_p(self.workspace.data_ptr())
802
+
803
+ # Generate partial function.
804
+ return functools.partial(
805
+ run_method,
806
+ *args,
807
+ *self.extra_args,
808
+ None, # null workspace size ptr
809
+ workspace_ptr, # set workspace ptr,
810
+ stream_ptr,
811
+ )
812
+
813
+ def update_workspace_size(self) -> None:
814
+ if self._workspace_size_updated:
815
+ return
816
+ self.ensure_dll_loaded()
817
+ unique_input_count = len({meta.name for meta in self.input_tensor_meta})
818
+ args = [c_void_p(None) for _ in range(unique_input_count + 1)]
819
+ stream_ptr = c_void_p(torch.cuda.current_stream().cuda_stream)
820
+
821
+ run_method = getattr(self.DLL, self.kernel_name)
822
+ # Retrieve workspace_size and initialize workspace.
823
+ c_workspace_size = c_size_t()
824
+ run_method(
825
+ *args, # input ptrs and output ptrs
826
+ *self.extra_args,
827
+ byref(
828
+ c_workspace_size
829
+ ), # set workspace size ptr to retrieve workspace size
830
+ None, # null workspace ptr
831
+ stream_ptr,
832
+ )
833
+ torch.cuda.synchronize() # shake out any CUDA errors
834
+ self.workspace_size = c_workspace_size.value
835
+ log.debug(
836
+ "update_workspace_size called: new workspace size=%d, self.kernel_name=%s, self.source_file=%s, self.hash_key=%s, self.DLL=%s, args=%s, self.extra_args=%s", # noqa: B950
837
+ self.workspace_size,
838
+ self.kernel_name,
839
+ self.source_file,
840
+ self.hash_key,
841
+ self.DLL,
842
+ args,
843
+ self.extra_args,
844
+ )
845
+ self._workspace_size_updated = True
846
+
847
+ def ensure_dll_loaded(self):
848
+ if self.DLL is None:
849
+ self.DLL, self.hash_key, self.source_file = CUDACodeCache.load(
850
+ self.source_code, "so"
851
+ )
852
+
853
+ def cleanup_run_fn(self) -> None:
854
+ if self.DLL is not None:
855
+ self.DLL.close()
856
+ self.workspace = None
857
+
858
+ def __str__(self) -> str:
859
+ return f"{self.kernel_name=}, {self.source_file=}, {self.hash_key=}"
860
+
861
+
862
+ class CppBenchmarkRequest(CPUDeviceBenchmarkMixin, BenchmarkRequest):
863
+ # Important: Instances of this class have to be serializable
864
+ # across process boundaries. Do not put Tensors in here!
865
+
866
+ def __init__(
867
+ self,
868
+ kernel_name: str,
869
+ input_tensor_meta: Union[TensorMeta, List[TensorMeta]],
870
+ output_tensor_meta: Union[TensorMeta, List[TensorMeta]],
871
+ extra_args: Iterable[Any],
872
+ source_code: str,
873
+ ) -> None:
874
+ super().__init__(kernel_name, input_tensor_meta, output_tensor_meta, extra_args)
875
+ self.source_code = source_code
876
+ self.hash_key = get_hash(source_code)
877
+ self.DLL: Optional[Union[CDLL, ModuleType]] = None
878
+
879
+ def precompile(self):
880
+ # Prepopulate CppCodeCache
881
+ # may happen in separate Threadpool
882
+ log.debug("Precompiling %s", self)
883
+ CppCodeCache.load(self.source_code, device_type="cpu")
884
+ log.debug("Done precompiling %s", self)
885
+
886
+ def make_run_fn(
887
+ self, *input_tensors: torch.Tensor, output_tensor: torch.Tensor
888
+ ) -> Callable[[], None]:
889
+ # TODO(jgong5): use CppPythonBindingsCodeCache for better binding perf
890
+ self.DLL = CppCodeCache.load(self.source_code, device_type="cpu")
891
+ args = [tensor.data_ptr() for tensor in list(input_tensors) + [output_tensor]]
892
+ log.debug(
893
+ "make_run_fn: self.kernel_name=%s, self.DLL=%s, args=%s, self.extra_args=%s",
894
+ self.kernel_name,
895
+ self.DLL,
896
+ args,
897
+ self.extra_args,
898
+ )
899
+ run_method = getattr(self.DLL, self.kernel_name)
900
+ # Assume only size with type ctypes.c_ulonglong in extra_args
901
+ assert all(isinstance(arg, ctypes.c_ulonglong) for arg in self.extra_args)
902
+ run_method.argtypes = [ctypes.c_ulonglong] * (
903
+ len(args) + len(list(self.extra_args))
904
+ )
905
+
906
+ # Generate partial function.
907
+ return functools.partial(
908
+ run_method,
909
+ *args,
910
+ *self.extra_args,
911
+ )
912
+
913
+ def cleanup_run_fn(self) -> None:
914
+ if self.DLL is not None:
915
+ """
916
+ Check close attr due to it crash on Windows.
917
+ """
918
+ if hasattr(self.DLL, "close"):
919
+ self.DLL.close()
920
+
921
+ def __str__(self) -> str:
922
+ return f"{self.kernel_name=}"
923
+
924
+
925
+ def benchmark_in_sub_process(
926
+ choices: List[TritonTemplateCaller],
927
+ ) -> Dict[TritonTemplateCaller, float]:
928
+ """
929
+ Do benchmarking in a subprocess and return the perf number (latency).
930
+ """
931
+ return tuning_pool.benchmark(choices)
lib/python3.12/site-packages/torch/_inductor/bounds.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import operator
3
+ from functools import partial
4
+ from typing import Any, Callable, Dict, Union
5
+
6
+ from sympy import Expr
7
+
8
+ import torch
9
+ from torch.utils._sympy.value_ranges import bound_sympy, ValueRangeAnalysis, ValueRanges
10
+
11
+ from .loop_body import InterpreterShim, LoopBody, LoopBodyBlock
12
+ from .utils import cache_on_self, dominated_nodes
13
+ from .virtualized import V
14
+
15
+
16
+ log = logging.getLogger(__name__)
17
+
18
+
19
+ class BoundVars:
20
+ """
21
+ Performs Value Range Analysis on LoopBody's fx graph by calling BoundVars.run()
22
+ It exposes the ranges of the nodes in the `bounds` variable
23
+
24
+ Note. A current limitation of this analysis is that it just works on a per-loop basis.
25
+ We should be able to propagate the bounds between across the whole graph. This may benefit
26
+ the case a bounded variable is returned by a kernel and fed into another.
27
+ """
28
+
29
+ def __init__(self, loop_body: LoopBody) -> None:
30
+ def upper_bound(v: Union[Expr, int]) -> int:
31
+ return bound_sympy(v).upper if isinstance(v, Expr) else v
32
+
33
+ self.loop_body = loop_body
34
+ self.replacement_vals = {
35
+ k: ValueRanges[Expr](0, upper_bound(v) - 1)
36
+ for k, v in loop_body.var_ranges.items()
37
+ }
38
+ # avoid computing these values, pessimistically assume that they are unbounded
39
+ self.unbounded_vars = dominated_nodes(
40
+ node
41
+ for node in self.loop_body.get_nodes()
42
+ if node.target in ["load", "reduction", operator.getitem]
43
+ or "masked_subblock" in node.target
44
+ )
45
+ # To access this variable call `get_bounds()`
46
+ self._bounds: Dict[torch.fx.Node, ValueRanges[Expr]] = {}
47
+
48
+ def __repr__(self) -> str:
49
+ return (
50
+ f"{self.__class__.__name__}("
51
+ f"loop_body={self.loop_body},\n "
52
+ f"replacement_vals={self.replacement_vals}, \n"
53
+ f"unbounded_vars={self.unbounded_vars}, \n"
54
+ f"_bounds={self._bounds})"
55
+ )
56
+
57
+ @cache_on_self
58
+ def get_bounds(self) -> Dict[torch.fx.Node, ValueRanges[Expr]]:
59
+ submodules = self.swap_submodules(self.loop_body.submodules)
60
+
61
+ # Initialize the environment with the unbounded variables
62
+ for node in self.unbounded_vars:
63
+ # we need to evaluate masked_subblock to recurse, and we need to set indirect values
64
+ if not isinstance(node.target, str) or (
65
+ "masked_subblock" not in node.target
66
+ and "set_indirect" not in node.target
67
+ ):
68
+ self._bounds[node] = ValueRanges[Expr].unknown()
69
+
70
+ with V.set_ops_handler(ValueRangeAnalysis()):
71
+ interpreter = InterpreterShim(self.loop_body.root_block.graph, submodules)
72
+ log.debug("get_bounds:\n%s", self.loop_body.root_block.graph)
73
+ interpreter.run(V.get_ops_handler(), initial_env=self._bounds)
74
+ return self._bounds
75
+
76
+ def swap_submodules(
77
+ self, submodules: Dict[str, Callable[..., Any]]
78
+ ) -> Dict[str, Callable[..., ValueRanges[Expr]]]:
79
+ result: Dict[str, Callable[..., ValueRanges[Expr]]] = {}
80
+ for key in submodules.keys():
81
+ if key == "get_index":
82
+ result[key] = self.get_index
83
+ elif "masked_subblock" in key:
84
+ subblock = self.loop_body.subblocks[key]
85
+ # The result within the lambda will reference to the final
86
+ # set of modules at the end of the for-loop as it stores a reference to it
87
+
88
+ # bind subblock in a function because python lambdas close over by reference
89
+ # moving the lambda out of make_fn would close over the reference to subblock,
90
+ # so all lambdas would have the same subblock reference that is the final
91
+ # subblock in the loop
92
+ def make_fn(
93
+ subblock: LoopBodyBlock,
94
+ ) -> Callable[[Any, Any], ValueRanges[Expr]]:
95
+ return lambda mask, value: self.masked_subblock(
96
+ subblock, self._bounds, mask, value, result
97
+ )
98
+
99
+ result[key] = make_fn(subblock)
100
+ elif "set_indirect" in key:
101
+ idx = int(key[len("set_indirect") :])
102
+ var = self.loop_body.indirect_vars[idx]
103
+ indirect = partial(self.set_indirect, var)
104
+ result[key] = indirect
105
+ else:
106
+ assert "scan" in key
107
+ result[key] = submodules[key]
108
+
109
+ return result
110
+
111
+ def masked_subblock(
112
+ self,
113
+ subblock: LoopBodyBlock,
114
+ env: Dict[torch.fx.Node, ValueRanges[Expr]],
115
+ mask: Any,
116
+ value: Any,
117
+ submodules: Dict[str, Callable[..., Any]],
118
+ ) -> ValueRanges[Expr]:
119
+ interp = InterpreterShim(subblock.graph, submodules)
120
+ interp.run(V.get_ops_handler(), initial_env=env)
121
+ output = [node for node in subblock.graph.nodes if node.target == "output"]
122
+ assert len(output) == 1
123
+ # dont bother unioning with value since the load from buffer will be
124
+ # pessimistically assumed to be inf anyway
125
+ return interp.env[output[0]]
126
+
127
+ def set_indirect(self, old: Expr, new: ValueRanges[Expr]) -> ValueRanges[Expr]:
128
+ assert isinstance(new, ValueRanges)
129
+ self.replacement_vals[old] = new
130
+ return new
131
+
132
+ def get_index(self, name: str) -> ValueRanges[Expr]:
133
+ expr = self.loop_body.indexing_exprs[name]
134
+ bound = self.replacement_vals.get(expr)
135
+ if bound is None:
136
+ bound = bound_sympy(expr, self.replacement_vals)
137
+ # The following assertion is true at the time of this writing
138
+ # We don't assert is as to not execute bound_sympy when bound is not None
139
+ # assert bound is None or bound == bound_sympy(expr, self.replacement_vals)
140
+ self.replacement_vals[name] = bound
141
+ return bound
lib/python3.12/site-packages/torch/_inductor/choices.py ADDED
@@ -0,0 +1,314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+ from typing import Any, Dict, List, Type, TYPE_CHECKING
5
+
6
+ import sympy
7
+
8
+ from . import config
9
+ from .codecache import write_text
10
+ from .metrics import get_metric_table, is_metric_table_enabled
11
+ from .runtime.hints import DeviceProperties, ReductionHint
12
+ from .scheduler import BaseSchedulerNode, Scheduler, WhyNoFuse
13
+ from .virtualized import V
14
+
15
+
16
+ if TYPE_CHECKING:
17
+ import torch
18
+
19
+ from .codegen.simd_kernel_features import SIMDKernelFeatures
20
+ from .codegen.triton import TritonKernel
21
+
22
+
23
+ class Sortable(typing.Protocol):
24
+ """Anything that can be used as a list.sort() key (int/tuple/etc)"""
25
+
26
+ def __lt__(self, other: typing.Self) -> bool:
27
+ ...
28
+
29
+
30
+ class InductorChoices:
31
+ """
32
+ This class contains a collection of default heuristics that effect performance of our generated
33
+ code. We try to not put correctness requirements in this file.
34
+
35
+ You can override the choices made here by doing:
36
+
37
+ class MyHeuristics(InductorChoices):
38
+ ...
39
+
40
+ torch._inductor.virtualized.V.set_choices_handler(MyHeuristics())
41
+ """
42
+
43
+ def triton_kernel_kwargs(
44
+ self,
45
+ kernel_cls: Type[TritonKernel],
46
+ features: SIMDKernelFeatures,
47
+ groups: List[sympy.Expr],
48
+ kernel_kwargs: Dict[str, Any],
49
+ ) -> Dict[str, Any]:
50
+ """Hook to change the kwargs passed to TritonKernel, used to apply fixed configurations"""
51
+ return kernel_kwargs
52
+
53
+ @staticmethod
54
+ def should_use_cooperative_reduction(features: SIMDKernelFeatures) -> bool:
55
+ """Heuristic to decide if a cooperative reduction should be used."""
56
+ if config.triton.force_cooperative_reductions:
57
+ return True
58
+ if (
59
+ not config.triton.cooperative_reductions
60
+ or V.graph.get_current_device_or_throw().type == "cpu"
61
+ ):
62
+ return False
63
+
64
+ xhint = V.graph.sizevars.size_hint(features.numel, fallback=2)
65
+ if xhint <= 8:
66
+ threshold = 32768 * xhint
67
+ elif xhint <= 16:
68
+ threshold = 2097152
69
+ else:
70
+ return False
71
+ # TODO(jansel): should this default on for dynamic shapes?
72
+ return V.graph.sizevars.statically_known_geq(
73
+ features.reduction_numel, threshold
74
+ )
75
+
76
+ @staticmethod
77
+ def should_use_persistent_reduction(
78
+ features: SIMDKernelFeatures, cooperative_reduction: bool
79
+ ) -> bool:
80
+ """
81
+ Heuristic to decide if a persistent reduction should be used.
82
+ """
83
+ if not config.triton.persistent_reductions:
84
+ return False
85
+ threshold = {
86
+ ReductionHint.INNER: 1024,
87
+ }.get(features.get_reduction_hint(), 64)
88
+
89
+ if cooperative_reduction:
90
+ # The RSPLIT of cooperative reductions means each thread block is operating on fewer elements
91
+ try:
92
+ threshold *= 32 // min(V.graph.sizevars.size_hint(features.numel), 32)
93
+ except ValueError:
94
+ pass # unbacked symint
95
+
96
+ # If multi_kernel is enabled, we do more aggressive persistent reduction.
97
+ # This may result in some persistent reductions slower than the
98
+ # corresponding non-persistent reductions. MultiKernel will do benchmarking
99
+ # to pick the faster one.
100
+ if config.triton.multi_kernel:
101
+ threshold *= 16
102
+ return V.graph.sizevars.statically_known_leq(features.reduction_numel, threshold) # type: ignore[arg-types]
103
+
104
+ @staticmethod
105
+ def want_no_x_dim(features: SIMDKernelFeatures) -> bool:
106
+ """
107
+ Heuristic to decide if we should drop the X dimension from a persistent reduction kernel.
108
+ So the [XBLOCK, RBLOCK] block becomes a [RBLOCK] block and XBLOCK is forced to be always 1.
109
+ Strangely this is faster than a [1, RBLOCK] block in some cases.
110
+ """
111
+ return (
112
+ features.get_reduction_hint() == ReductionHint.INNER
113
+ and V.graph.sizevars.statically_known_geq(features.reduction_numel, 256)
114
+ )
115
+
116
+ @staticmethod
117
+ def reduction_split_factor(
118
+ device: torch.device,
119
+ reduction_numel_hint: int,
120
+ numel_hint: int,
121
+ inner_reduction: bool,
122
+ ) -> int:
123
+ """Heuristic to decide the RSPLIT used for split reductions.
124
+ When a reduction has a small number of outputs there is not enough parallelism,
125
+ so we will do the reduction in two phases."""
126
+ props = DeviceProperties.create(device)
127
+ num_sm = props.multi_processor_count
128
+ min_elements_per_thread = 32
129
+ max_elements_per_thread = 512
130
+ threads_per_sm = 2048
131
+ min_elements_per_device = min_elements_per_thread * num_sm * threads_per_sm
132
+ max_elements_per_device = max_elements_per_thread * num_sm * threads_per_sm
133
+ num_warps = 8
134
+ num_threads = 32 * num_warps
135
+
136
+ if inner_reduction:
137
+ # do heuristics that's close to eager mode for split inner reduction
138
+ # we leak reduction autotune configs here, and will need to refactor to avoid this later
139
+ if numel_hint >= 2 * num_sm: # don't split if there are enough outputs
140
+ return 1
141
+ if reduction_numel_hint <= 8192:
142
+ return 1
143
+ if reduction_numel_hint * numel_hint <= min_elements_per_device:
144
+ split_size = min_elements_per_thread
145
+ elif reduction_numel_hint * numel_hint < max_elements_per_device:
146
+ target_blocks = num_sm * threads_per_sm // (2 * num_threads)
147
+ blocks_per_output = (target_blocks + numel_hint - 1) // numel_hint
148
+ tmp_split_size = (
149
+ reduction_numel_hint + num_threads * blocks_per_output - 1
150
+ ) // (num_threads * blocks_per_output)
151
+ divisors = sympy.divisors(reduction_numel_hint)
152
+ closest = min(divisors, key=lambda x: abs(x - tmp_split_size))
153
+ if abs(closest - tmp_split_size) < 30:
154
+ # prefer even splits, but never smalle than min_elements_per_thread
155
+ split_size = max(closest, min_elements_per_thread)
156
+ else:
157
+ split_size = tmp_split_size
158
+ else:
159
+ divisors = sympy.divisors(reduction_numel_hint)
160
+ closest = min(divisors, key=lambda x: abs(x - max_elements_per_thread))
161
+ if abs(closest - max_elements_per_thread) < 50:
162
+ # prefer even splits
163
+ split_size = closest
164
+ else:
165
+ split_size = max_elements_per_thread
166
+ return (reduction_numel_hint + split_size * num_threads - 1) // (
167
+ split_size * num_threads
168
+ )
169
+ else:
170
+ # TODO the best heuristic currently has XBLOCK (corresponding to numel_hint) 128
171
+ # extend to even smaller number of outputs
172
+ rvals_per_thread = 4 # comes from heuristics, refactor to not leak here
173
+ xvals_per_block = 128
174
+ xblocks = (numel_hint + xvals_per_block - 1) // xvals_per_block
175
+ if reduction_numel_hint * numel_hint < min_elements_per_device:
176
+ split_size = min_elements_per_thread
177
+ elif reduction_numel_hint * numel_hint < max_elements_per_device:
178
+ target_blocks = num_sm * threads_per_sm // (num_threads)
179
+ target_blocks = (target_blocks + xblocks - 1) // xblocks
180
+ tmp_split_size = (
181
+ reduction_numel_hint + rvals_per_thread * target_blocks - 1
182
+ ) // (rvals_per_thread * target_blocks)
183
+ divisors = sympy.divisors(reduction_numel_hint)
184
+ closest = min(divisors, key=lambda x: abs(x - tmp_split_size))
185
+ if abs(tmp_split_size - closest) < 20:
186
+ split_size = max(closest, min_elements_per_thread)
187
+ else:
188
+ split_size = tmp_split_size
189
+ else:
190
+ divisors = sympy.divisors(reduction_numel_hint)
191
+ closest = min(divisors, key=lambda x: abs(x - max_elements_per_thread))
192
+ if abs(closest - max_elements_per_thread) < 50:
193
+ # prefer even splits
194
+ split_size = closest
195
+ else:
196
+ split_size = max_elements_per_thread
197
+
198
+ return (reduction_numel_hint + rvals_per_thread * split_size - 1) // (
199
+ rvals_per_thread * split_size
200
+ )
201
+
202
+ @staticmethod
203
+ def can_fuse(
204
+ scheduler: Scheduler,
205
+ node1: BaseSchedulerNode,
206
+ node2: BaseSchedulerNode,
207
+ shared_data_score: int,
208
+ ) -> bool:
209
+ """
210
+ Heuristics to prevent fusion applied to both horizontal and vertical fusions. Heuristics here should not
211
+ be needed for correctness and tweaking them may yield additional performance.
212
+
213
+ See also some related heuristics that can be changed via config:
214
+ - config.triton.tiling_prevents_pointwise_fusion
215
+ - config.triton.tiling_prevents_reduction_fusion
216
+ - config.aggressive_fusion (will cause this function to be called more times)
217
+ """
218
+ if shared_data_score == 0 and (
219
+ not config.aggressive_fusion or node1.is_reduction() or node2.is_reduction()
220
+ ):
221
+ if is_metric_table_enabled("fusion_failure_due_to_indexing_mismatch"):
222
+ common_buf_names = (
223
+ node1.read_writes.buffer_names() & node2.read_writes.buffer_names()
224
+ )
225
+ if len(common_buf_names) > 0:
226
+ get_metric_table("fusion_failure_due_to_indexing_mismatch").add_row(
227
+ lambda: {
228
+ "pre_grad_graph_id": V.graph.graph_id,
229
+ "post_grad_graph_id": V.graph.post_grad_graph_id,
230
+ "node1_name": node1.get_name(),
231
+ "node2_name": node2.get_name(),
232
+ "node1_debug_str": write_text(node1.debug_str()),
233
+ "node2_debug_str": write_text(node2.debug_str()),
234
+ "common_buffer_names": list(common_buf_names),
235
+ "failure_reason": scheduler.decide_fusion_fail_reason(
236
+ node1, node2, common_buf_names
237
+ ),
238
+ }
239
+ )
240
+
241
+ WhyNoFuse(node1, node2)("no shared data due to indexing mismatch")
242
+ return False
243
+ WhyNoFuse(node1, node2)("no shared data")
244
+ return False # heuristic not needed for correctness
245
+
246
+ if (
247
+ not node1.is_foreach()
248
+ and not node2.is_foreach()
249
+ and len(node1.get_nodes()) + len(node2.get_nodes()) > config.max_fusion_size
250
+ ):
251
+ WhyNoFuse(node1, node2)("exceeds max fusion")
252
+ return False # heuristic not needed for correctness
253
+
254
+ if scheduler.can_fusion_increase_peak_memory(node1, node2):
255
+ WhyNoFuse(node1, node2)("Fusion will increase peak memory")
256
+ return False
257
+
258
+ return True
259
+
260
+ @staticmethod
261
+ def can_fuse_vertical(
262
+ scheduler: Scheduler,
263
+ node1: BaseSchedulerNode,
264
+ node2: BaseSchedulerNode,
265
+ shared_data_score: int,
266
+ ) -> bool:
267
+ """Hook for heuristics to prevent vertical (producer/consumer) fusions"""
268
+ return True
269
+
270
+ @staticmethod
271
+ def can_fuse_horizontal(
272
+ scheduler: Scheduler,
273
+ node1: BaseSchedulerNode,
274
+ node2: BaseSchedulerNode,
275
+ shared_data_score: int,
276
+ ) -> bool:
277
+ """Hook for heuristics to prevent horizontal (consumer/consumer) fusions"""
278
+ if shared_data_score < config.score_fusion_memory_threshold:
279
+ WhyNoFuse(node1, node2)("score_fusion_memory_threshold")
280
+ return False
281
+ if scheduler.are_long_distant_nodes(node1, node2):
282
+ WhyNoFuse(node1, node2)(
283
+ "Nodes are too far away. Fusing them may increase peak memory."
284
+ )
285
+ return False
286
+ return True
287
+
288
+ @staticmethod
289
+ def score_fusion(
290
+ scheduler: Scheduler,
291
+ node1: BaseSchedulerNode,
292
+ node2: BaseSchedulerNode,
293
+ ) -> Sortable:
294
+ """
295
+ Assign a score (higher comes first) to the fusion of node1 and node2.
296
+ When different fusions conflict with each other, this is the way we
297
+ decide what order to run them in.
298
+
299
+ Our current score is based on:
300
+ - The type of fusion (template/reduction/etc)
301
+ - Estimate of the saved memory operations
302
+ - Fusions closer together in original graph order
303
+ """
304
+ memory_score = scheduler.score_fusion_memory(node1, node2)
305
+ proximity_score = -max(
306
+ abs(node1.min_order - node2.max_order),
307
+ abs(node2.min_order - node1.max_order),
308
+ )
309
+ return (
310
+ node1.is_template() == config.epilogue_fusion_first and memory_score > 0,
311
+ node1.is_reduction() == node2.is_reduction() and memory_score > 0,
312
+ memory_score,
313
+ proximity_score,
314
+ )
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (202 Bytes). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/aoti_hipify_utils.cpython-312.pyc ADDED
Binary file (1.13 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/block_analysis.cpython-312.pyc ADDED
Binary file (5.83 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_bmm_template.cpython-312.pyc ADDED
Binary file (11.5 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_flex_attention_template.cpython-312.pyc ADDED
Binary file (45.1 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_gemm_template.cpython-312.pyc ADDED
Binary file (64.6 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_micro_gemm.cpython-312.pyc ADDED
Binary file (35.3 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_template.cpython-312.pyc ADDED
Binary file (7.04 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_template_kernel.cpython-312.pyc ADDED
Binary file (25.4 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_utils.cpython-312.pyc ADDED
Binary file (44.2 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_wrapper_cpu_array_ref.cpython-312.pyc ADDED
Binary file (48.4 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_wrapper_gpu.cpython-312.pyc ADDED
Binary file (26.6 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpu_device_op_overrides.cpython-312.pyc ADDED
Binary file (1.3 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cuda_combined_scheduling.cpython-312.pyc ADDED
Binary file (6.12 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/debug_utils.cpython-312.pyc ADDED
Binary file (11.4 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/halide.cpython-312.pyc ADDED
Binary file (93.6 kB). View file
 
lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/memory_planning.cpython-312.pyc ADDED
Binary file (40.7 kB). View file