Skip to content

Commit 52da041

Browse files
committed
add tle_raw cuda host cache key
1 parent 2cca130 commit 52da041

7 files changed

Lines changed: 197 additions & 14 deletions

File tree

python/triton/experimental/tle/raw/cache_key.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
# Protocol attribute checked by triton.runtime.jit.DependenciesFinder.
1010
# Value may be a str or a zero-arg callable returning the current key fragment.
1111
TLE_RAW_SOURCE_CACHE_KEY_ATTR = "__triton_tle_raw_source_cache_key__"
12+
TLE_RAW_COMMON_HOST_CACHE_KEY_ATTR = "__triton_tle_raw_common_host_cache_key__"
13+
TLE_RAW_HOST_CACHE_KEY_ATTR = "__triton_tle_raw_host_cache_key__"
1214

1315
_DIALECT_KWARG_KEYS = (
1416
"name",
@@ -107,3 +109,33 @@ def tle_raw_source_cache_key() -> str:
107109
return compute_tle_raw_source_cache_key(normalized, edsl=edsl)
108110

109111
setattr(edsl, TLE_RAW_SOURCE_CACHE_KEY_ATTR, tle_raw_source_cache_key)
112+
113+
114+
def compute_tle_raw_host_cache_key(source: Union[str, Path], arch: str) -> str:
115+
"""Hash CUDA host source files."""
116+
source_path = Path(source).resolve()
117+
hasher = hashlib.sha256()
118+
hasher.update(str(source_path).encode())
119+
hasher.update(_read_source(source_path).encode())
120+
hasher.update(str(arch).encode())
121+
122+
return hasher.hexdigest()
123+
124+
125+
def bind_tle_raw_common_host_cache_key(edsl: Any, **kwargs) -> None:
126+
"""Attach __triton_tle_raw_source_cache_key__ to a @dialect edsl object."""
127+
if getattr(edsl, TLE_RAW_COMMON_HOST_CACHE_KEY_ATTR, None) is not None:
128+
return
129+
130+
setattr(edsl, TLE_RAW_COMMON_HOST_CACHE_KEY_ATTR, kwargs.get("key"))
131+
132+
133+
def bind_tle_raw_host_cache_key(edsl: Any, **kwargs) -> None:
134+
"""Attach __triton_tle_raw_source_cache_key__ to a @dialect edsl object."""
135+
if getattr(edsl, TLE_RAW_HOST_CACHE_KEY_ATTR, None) is not None:
136+
return
137+
138+
# def tle_raw_host_cache_key() -> str:
139+
# return compute_tle_raw_host_cache_key(kwargs)
140+
141+
setattr(edsl, TLE_RAW_HOST_CACHE_KEY_ATTR, kwargs.get("key"))

python/tutorials/tle/raw/nvshmem/common/common-host.cu renamed to python/triton/experimental/tle/raw/cuda/common-host.cu

File renamed without changes.

python/triton/experimental/tle/raw/utils/nvshmem.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55
from pathlib import Path
66

77
import torch
8+
import functools
9+
import sysconfig
10+
import subprocess
11+
import re
12+
import tempfile
13+
import shlex
14+
from triton.runtime.cache import get_cache_manager
15+
from triton.experimental.tle.raw.cuda.runtime import _get_cuda_gpu_arch
16+
from triton.experimental.tle.raw.cache_key import compute_tle_raw_host_cache_key, bind_tle_raw_common_host_cache_key, bind_tle_raw_host_cache_key
817

918
try:
1019
from cuda.bindings import driver as cuda
@@ -20,6 +29,135 @@
2029
from cuda import cudart as cudart
2130

2231

32+
@functools.lru_cache()
33+
def get_nvshmem_home() -> Path:
34+
if (nvshmem_home := os.getenv("NVSHMEM_HOME")) is not None:
35+
return Path(nvshmem_home)
36+
37+
try:
38+
import nvidia.nvshmem
39+
return Path(nvidia.nvshmem.__path__[0])
40+
except Exception:
41+
pass
42+
43+
44+
@functools.lru_cache()
45+
def get_nvcc():
46+
return _path_to_binary("nvcc")
47+
48+
49+
@functools.lru_cache()
50+
def _path_to_binary(binary: str):
51+
binary += sysconfig.get_config_var("EXE")
52+
paths = [
53+
os.environ.get(f"TRITON_{binary.upper()}_PATH", ""),
54+
os.path.join(Path(os.path.dirname(__file__)).parent, "triton/backends/nvidia/bin", binary),
55+
]
56+
57+
cuda_home = os.getenv("CUDA_HOME", "/usr/local/cuda")
58+
59+
paths += [f"{cuda_home}/bin/{binary}"]
60+
61+
for path in paths:
62+
if os.path.exists(path) and os.path.isfile(path):
63+
result = subprocess.check_output([path, "--version"], stderr=subprocess.STDOUT)
64+
if result is not None:
65+
version = re.search(r".*release (\d+\.\d+).*", result.decode("utf-8"), flags=re.MULTILINE)
66+
if version is not None:
67+
return path, version.group(1)
68+
raise RuntimeError(f"Cannot find {binary}")
69+
70+
71+
def _compile_cuda_host_to_cache(
72+
source,
73+
nvshmem_home,
74+
arch: str = None,
75+
force: bool = False,
76+
) -> tuple[Path, str, bool]:
77+
source_path = Path(source).expanduser().resolve()
78+
if not arch:
79+
arch = _get_cuda_gpu_arch().split('=')[1]
80+
nvshmem_home = get_nvshmem_home()
81+
host_cache_key = compute_tle_raw_host_cache_key(source_path, arch)
82+
output_name = source_path.with_suffix(".so").name
83+
cache = get_cache_manager(host_cache_key)
84+
85+
cached = None if force else cache.get_file(output_name)
86+
if cached is not None:
87+
return Path(cached), host_cache_key, True
88+
89+
temporary = tempfile.NamedTemporaryFile(
90+
prefix=f".{output_name}.",
91+
suffix=".tmp",
92+
delete=False,
93+
)
94+
temporary_path = Path(temporary.name)
95+
temporary.close()
96+
nvcc, _ = get_nvcc()
97+
command = [
98+
nvcc,
99+
"-shared",
100+
"-Xcompiler",
101+
"-fPIC",
102+
"-rdc=true",
103+
f"-arch={arch}",
104+
f"-I{nvshmem_home / 'include'}",
105+
f"-L{nvshmem_home / 'lib'}",
106+
"-lnvshmem_host",
107+
"-lnvshmem_device",
108+
"-o",
109+
str(temporary_path),
110+
str(source_path),
111+
]
112+
try:
113+
build = subprocess.run(command, capture_output=True)
114+
if build.returncode != 0:
115+
raise RuntimeError("nvcc failed while compiling CUDA host library\n"
116+
f"command: {shlex.join(command)}\n"
117+
f"stderr:\n{build.stderr.decode()}")
118+
cached_path = cache.put(temporary_path.read_bytes(), output_name, binary=True)
119+
return Path(cached_path), host_cache_key, False
120+
finally:
121+
temporary_path.unlink(missing_ok=True)
122+
123+
124+
class CudaHostLibrary:
125+
126+
def __init__(self, bind_edsls, library_path, host_cache_key, type):
127+
self.edsls = bind_edsls
128+
self.path = Path(library_path).expanduser().resolve()
129+
self.host_cache_key = host_cache_key
130+
self.library = ctypes.CDLL(str(self.path))
131+
132+
if type == "common":
133+
for edsl in self.edsls:
134+
bind_tle_raw_common_host_cache_key(edsl, key=host_cache_key)
135+
elif type == "op":
136+
for edsl in self.edsls:
137+
bind_tle_raw_host_cache_key(edsl, key=host_cache_key)
138+
else:
139+
raise RuntimeError("Unsupported cuda-host type.")
140+
141+
def __getattr__(self, name):
142+
return getattr(self.library, name)
143+
144+
145+
def get_common_host_source() -> Path:
146+
return Path(__file__).resolve().parents[1] / "cuda" / "common-host.cu"
147+
148+
149+
def load_host(bind_edsls, source, type="op", nvshmem_home=None, arch: str | None = None,
150+
force: bool = False) -> CudaHostLibrary:
151+
path, host_cache_key, _ = _compile_cuda_host_to_cache(source, nvshmem_home, arch, force=force)
152+
return CudaHostLibrary(bind_edsls, path, host_cache_key, type)
153+
154+
155+
def load_common_host(bind_edsls, source=None, type="common", nvshmem_home=None, arch: str | None = None,
156+
force: bool = False) -> CudaHostLibrary:
157+
return load_host(bind_edsls, source or get_common_host_source(), type=type, nvshmem_home=nvshmem_home, arch=arch,
158+
force=force)
159+
160+
23161
def CUDA_CHECK(err):
24162
if isinstance(err, cuda.CUresult):
25163
if err != cuda.CUresult.CUDA_SUCCESS:

python/triton/runtime/jit.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,19 @@ def record_reference(self, val, var_dict=None, name=None):
128128
part = (tle_raw_source_cache_key() if callable(tle_raw_source_cache_key) else tle_raw_source_cache_key)
129129
self.hasher.update(str(part).encode("utf-8"))
130130

131+
tle_raw_common_host_cache_key = getattr(val, "__triton_tle_raw_common_host_cache_key__", None)
132+
if tle_raw_common_host_cache_key is not None:
133+
print(f"common host key: {tle_raw_common_host_cache_key}")
134+
part = (tle_raw_common_host_cache_key()
135+
if callable(tle_raw_common_host_cache_key) else tle_raw_common_host_cache_key)
136+
self.hasher.update(str(part).encode("utf-8"))
137+
138+
tle_raw_host_cache_key = getattr(val, "__triton_tle_raw_host_cache_key__", None)
139+
if tle_raw_host_cache_key is not None:
140+
print(f"host key: {tle_raw_host_cache_key}")
141+
part = (tle_raw_host_cache_key() if callable(tle_raw_host_cache_key) else tle_raw_host_cache_key)
142+
self.hasher.update(str(part).encode("utf-8"))
143+
131144
if getattr(val, "__triton_aggregate__", False):
132145
for attr in val.hash_attrs:
133146
self.record_reference(attr)

python/tutorials/tle/raw/nvshmem/01-simple-shift/simple-shift.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from triton.experimental.tle.raw import dialect
88

99
from triton.experimental.tle.raw.utils.nvshmem import (
10-
load_library,
10+
load_host,
1111
tensor_from_pointer,
1212
)
1313

@@ -28,8 +28,8 @@ def simple_shift_kernel(destination_ptr, ):
2828

2929

3030
def simpe_shift():
31-
host_path = Path(__file__).with_name("simple-shift-host.so")
32-
host_lib = load_library(host_path)
31+
host_source = Path(__file__).with_name("simple-shift-host.cu")
32+
host_lib = load_host(bind_edsl=simple_shift, source=host_source)
3333

3434
mype = ctypes.c_int()
3535
npes = ctypes.c_int()

python/tutorials/tle/raw/nvshmem/02-allgather-gemm/ag-gemm.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
from triton.experimental.tle.raw.utils.nvshmem import (
1414
print_perf_mean,
15-
load_library,
15+
load_common_host,
16+
load_host,
1617
init_torch_distributed,
1718
init_nvshmem_by_torch_pg,
1819
tensor_from_pointer,
@@ -469,10 +470,9 @@ def main():
469470
sys.exit()
470471

471472
group = init_torch_distributed()
472-
common_path = Path(__file__).parents[1] / "common" / "common-host.so"
473-
host_path = Path(__file__).with_name("ag-gemm-host.so")
474-
common = load_library(common_path)
475-
host = load_library(host_path)
473+
host_source = Path(__file__).with_name("ag-gemm-host.cu")
474+
host = load_host([mark_local_ready, wait_ready], host_source)
475+
common = load_common_host([mark_local_ready, wait_ready])
476476
configure_host_library(host)
477477
init_nvshmem_by_torch_pg(common, group)
478478

python/tutorials/tle/raw/nvshmem/common/build.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,15 +205,15 @@ def main():
205205
nvshmem_home = resolve_nvshmem_home(args.nvshmem_home)
206206
arch = detect_arch(args.arch)
207207
generated = generate_extern_files(target.parent)
208-
common = compile_common_host(nvshmem_home, arch, args.force)
209-
libraries = compile_host_files(target.parent, nvshmem_home, arch, args.force)
208+
# common = compile_common_host(nvshmem_home, arch, args.force)
209+
# libraries = compile_host_files(target.parent, nvshmem_home, arch, args.force)
210210

211211
for path in generated:
212212
print(f"[prepare] extern file: {path}")
213-
if common is not None:
214-
print(f"[prepare] common host: {common}")
215-
for path in libraries:
216-
print(f"[prepare] host: {path}")
213+
# if common is not None:
214+
# print(f"[prepare] common host: {common}")
215+
# for path in libraries:
216+
# print(f"[prepare] host: {path}")
217217
print(f"[prepare] NVSHMEM_HOME={nvshmem_home}")
218218
print(f"[prepare] CUDA architecture={arch}")
219219

0 commit comments

Comments
 (0)