Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/python3.12/site-packages/torch/_awaits/__init__.py +53 -0
- lib/python3.12/site-packages/torch/_awaits/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_dispatch/__init__.py +0 -0
- lib/python3.12/site-packages/torch/_dispatch/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_dispatch/__pycache__/python.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_dispatch/python.py +180 -0
- lib/python3.12/site-packages/torch/_inductor/__init__.py +292 -0
- lib/python3.12/site-packages/torch/_inductor/aoti_eager.py +299 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/__init__.py +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/autoheuristic.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/autoheuristic_utils.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/learned_heuristic_controller.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/__pycache__/learnedheuristic_interface.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MMRankingA100.py +296 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MMRankingH100.py +321 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MixedMMA100.py +150 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_MixedMMH100.py +149 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/_PadMMA100.py +109 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__init__.py +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MMRankingA100.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MMRankingH100.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MixedMMA100.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_MixedMMH100.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/_PadMMA100.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/artifacts/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/autoheuristic.py +315 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/autoheuristic_utils.py +339 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/learned_heuristic_controller.py +119 -0
- lib/python3.12/site-packages/torch/_inductor/autoheuristic/learnedheuristic_interface.py +92 -0
- lib/python3.12/site-packages/torch/_inductor/autotune_process.py +931 -0
- lib/python3.12/site-packages/torch/_inductor/bounds.py +141 -0
- lib/python3.12/site-packages/torch/_inductor/choices.py +314 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/aoti_hipify_utils.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/block_analysis.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_bmm_template.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_flex_attention_template.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_gemm_template.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_micro_gemm.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_template.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_template_kernel.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_utils.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_wrapper_cpu_array_ref.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpp_wrapper_gpu.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cpu_device_op_overrides.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/cuda_combined_scheduling.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/debug_utils.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/_inductor/codegen/__pycache__/halide.cpython-312.pyc +0 -0
- 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
|
|
|