-
Notifications
You must be signed in to change notification settings - Fork 1.2k
refactor: pull trtllm-gen batch-gemm/gemm headers from artifactory; update tma descriptor shape init #2235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: pull trtllm-gen batch-gemm/gemm headers from artifactory; update tma descriptor shape init #2235
Changes from 23 commits
7fbbcd3
ece1cd7
8e5bfc8
e6350d0
16172a9
a2f4f52
670df3d
4176fa4
4be0702
5ffb1d6
61a7ecf
16252e7
df3babf
96e1b7c
de30cfe
baf8716
a0aaa98
22c4213
7c4672a
ee89fa0
2b4034e
4f43409
e51719d
fe51e7d
c8cdc5d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -79,6 +79,54 @@ def get_available_cubin_files( | |
| return tuple() | ||
|
|
||
|
|
||
| def get_available_header_files( | ||
| source: str, retries: int = 3, delay: int = 5, timeout: int = 10 | ||
| ) -> tuple[str, ...]: | ||
| """ | ||
| Recursively navigates through child directories (e.g., include/) and finds | ||
| all *.h header files, returning them as a tuple of relative paths. | ||
| """ | ||
| result: list[str] = [] | ||
|
|
||
| def fetch_directory(url: str, prefix: str = "") -> None: | ||
| for attempt in range(1, retries + 1): | ||
| try: | ||
| response = requests.get(url, timeout=timeout) | ||
| response.raise_for_status() | ||
|
|
||
| # Find all .h header files in this directory | ||
| header_hrefs = re.findall(r'<a href="([^"]+\.h)">', response.text) | ||
| for h in header_hrefs: | ||
| result.append(prefix + h if prefix else h) | ||
|
|
||
| # Find all subdirectories (links ending with /) | ||
| dir_hrefs = re.findall(r'<a href="([^"]+/)">', response.text) | ||
| for d in dir_hrefs: | ||
| # Skip parent directory links | ||
| if d == "../" or d.startswith(".."): | ||
| continue | ||
| subdir_url = safe_urljoin(url, d) | ||
| subdir_prefix = prefix + d if prefix else d | ||
| fetch_directory(subdir_url, subdir_prefix) | ||
|
|
||
| return # Success, exit retry loop | ||
|
|
||
| except requests.exceptions.RequestException as e: | ||
| logger.warning( | ||
| f"Fetching available header files {url}: attempt {attempt} failed: {e}" | ||
| ) | ||
|
|
||
| if attempt < retries: | ||
| logger.info(f"Retrying in {delay} seconds...") | ||
| time.sleep(delay) | ||
|
|
||
| logger.error(f"Max retries reached for {url}. Fetch failed.") | ||
|
|
||
| fetch_directory(source) | ||
| logger.info(f"result: {result}") | ||
| return tuple(result) | ||
|
Comment on lines
+82
to
+127
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This new function
Comment on lines
+82
to
+127
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Silent failures in recursive directory traversal may cause incomplete results. The nested
Proposed fix to raise on failure if attempt < retries:
logger.info(f"Retrying in {delay} seconds...")
time.sleep(delay)
- logger.error(f"Max retries reached for {url}. Fetch failed.")
+ logger.error(f"Max retries reached for {url}. Fetch failed.")
+ raise RuntimeError(f"Failed to fetch header files from {url}")
fetch_directory(source)π§° Toolsπͺ Ruff (0.14.14)112-112: Consider moving this statement to an (TRY300) π€ Prompt for AI Agents |
||
|
|
||
|
|
||
| @dataclass(frozen=True) | ||
| class ArtifactPath: | ||
| """ | ||
|
|
@@ -182,6 +230,9 @@ def get_subdir_file_list() -> Generator[tuple[str, str], None, None]: | |
| yield (checksum_path, CheckSumHash.map_checksums[checksum_path]) | ||
| for name in get_available_cubin_files(safe_urljoin(base, cubin_dir)): | ||
| yield (safe_urljoin(cubin_dir, name), checksums[name]) | ||
| for name in get_available_header_files(safe_urljoin(base, cubin_dir)): | ||
| full_path = safe_urljoin(cubin_dir, name) | ||
| yield (full_path, checksums[full_path]) | ||
|
|
||
|
|
||
| def download_artifacts() -> None: | ||
|
|
@@ -190,7 +241,7 @@ def download_artifacts() -> None: | |
| # use a shared session to make use of HTTP keep-alive and reuse of | ||
| # HTTPS connections. | ||
| session = requests.Session() | ||
| cubin_files = list(get_subdir_file_list()) | ||
| cubin_files = list[tuple[str, str]](get_subdir_file_list()) | ||
| num_threads = int(os.environ.get("FLASHINFER_CUBIN_DOWNLOAD_THREADS", "4")) | ||
| with tqdm_logging_redirect( | ||
| total=len(cubin_files), desc="Downloading cubins" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,13 +17,16 @@ | |
| import ctypes | ||
| import hashlib | ||
| import os | ||
| import pathlib | ||
| from urllib.parse import urljoin | ||
| import shutil | ||
| import time | ||
| from typing import Union | ||
| import uuid | ||
|
|
||
| import filelock | ||
|
|
||
| from .utils import write_if_different | ||
| from .core import logger | ||
| from .env import FLASHINFER_CUBIN_DIR | ||
|
|
||
|
|
@@ -136,14 +139,20 @@ def download_file( | |
| return False | ||
|
|
||
|
|
||
| def get_meta_hash(checksums_bytes: bytes) -> str: | ||
| def get_meta_hash( | ||
| checksums_bytes: bytes, target_file: str = "flashinferMetaInfo.h" | ||
| ) -> str: | ||
| """ | ||
| Parse the checksums.txt file and get the hash of corresponding flashinferMetaInfo.h file | ||
| """ | ||
| checksums_lines = checksums_bytes.decode("utf-8").splitlines() | ||
| for line in checksums_lines: | ||
| sha256, filename = line.strip().split() | ||
| if ".h" in filename: | ||
| # Match on path segment boundary to avoid substring collisions | ||
| # (e.g. "Enums.h" must not match "BatchedGemmEnums.h") | ||
| if filename.lower() == target_file.lower() or filename.lower().endswith( | ||
| "/" + target_file.lower() | ||
| ): | ||
| return sha256 | ||
| raise ValueError("Invalid checksums.txt, no flashinferMetaInfo.h found") | ||
|
Comment on lines
+142
to
157
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update error message to include the actual target file. The error message on line 151 is hardcoded to mention Proposed fix- raise ValueError("Invalid checksums.txt, no flashinferMetaInfo.h found")
+ raise ValueError(f"Invalid checksums.txt, no {target_file} found")π§° Toolsπͺ Ruff (0.14.14)151-151: Avoid specifying long messages outside the exception class (TRY003) π€ Prompt for AI Agents |
||
|
|
||
|
|
@@ -189,6 +198,27 @@ def load_cubin(cubin_path: str, sha256: str) -> bytes: | |
| return b"" | ||
|
|
||
|
|
||
| def get_file( | ||
| uri_path: str, | ||
| sha256: str, | ||
| file_path: str, | ||
| session=None, | ||
| ) -> bytes: | ||
| """ | ||
| Load a file from local cache directory {file_path}, ensure that the sha256 signature matches. | ||
| Otherwise, download the file from {uri_path} and write to {file_path}. | ||
| """ | ||
|
|
||
| file = load_cubin(file_path, sha256) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| if file: | ||
| return file | ||
| os.makedirs(os.path.dirname(file_path), exist_ok=True) | ||
| uri = safe_urljoin(FLASHINFER_CUBINS_REPOSITORY, uri_path) | ||
| logger.info(f"Fetching file from {uri}") | ||
| download_file(uri, file_path, session=session) | ||
| return load_cubin(file_path, sha256) | ||
|
Comment on lines
+201
to
+219
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If Consider raising on download failure: Proposed fix file = load_cubin(file_path, sha256)
if file:
return file
os.makedirs(os.path.dirname(file_path), exist_ok=True)
uri = safe_urljoin(FLASHINFER_CUBINS_REPOSITORY, uri_path)
logger.info(f"Fetching file from {uri}")
- download_file(uri, file_path, session=session)
- return load_cubin(file_path, sha256)
+ if not download_file(uri, file_path, session=session):
+ raise RuntimeError(f"Failed to download {uri}")
+ result = load_cubin(file_path, sha256)
+ if not result:
+ raise RuntimeError(f"Downloaded file failed integrity check: {file_path}")
+ return resultπ€ Prompt for AI Agents |
||
|
|
||
|
|
||
| def get_cubin(file_name: str, sha256: str, session=None) -> bytes: | ||
| """ | ||
| Load a cubin from the local cache directory with {file_name} and | ||
|
|
@@ -211,6 +241,80 @@ def get_cubin(file_name: str, sha256: str, session=None) -> bytes: | |
| return load_cubin(cubin_path, sha256) | ||
|
|
||
|
|
||
| def download_trtllm_headers( | ||
| op: str, | ||
| header_dest_dir: Union[str, pathlib.Path], | ||
| header_path: str, | ||
| artifact_path: str, | ||
| checksum: bytes, | ||
| ): | ||
| header_dest_dir = pathlib.Path(header_dest_dir) | ||
|
|
||
| if op == "bmm": | ||
| header_files = [ | ||
| "BatchedGemmEnums.h", | ||
| "BatchedGemmInterface.h", | ||
| "BatchedGemmOptions.h", | ||
| "Enums.h", | ||
| "GemmGatedActOptions.h", | ||
| "GemmOptions.h", | ||
| "KernelParams.h", | ||
| "KernelParamsDecl.h", | ||
| "KernelTraits.h", | ||
| "TmaDescriptor.h", | ||
| "trtllm/gen/CommonUtils.h", | ||
| "trtllm/gen/CudaArchDecl.h", | ||
| "trtllm/gen/CudaKernelLauncher.h", | ||
| "trtllm/gen/DtypeDecl.h", | ||
| "trtllm/gen/MmaDecl.h", | ||
| "trtllm/gen/SfLayoutDecl.h", | ||
| "trtllm/gen/SparsityDecl.h", | ||
| ] | ||
|
|
||
| else: | ||
| header_files = [ | ||
| "GemmInterface.h", | ||
| "GemmOptions.h", | ||
| "Enums.h", | ||
| "KernelTraits.h", | ||
| "KernelParams.h", | ||
| "KernelParamsDecl.h", | ||
| "TmaDescriptor.h", | ||
| "trtllm/gen/CommonUtils.h", | ||
| "trtllm/gen/CudaKernelLauncher.h", | ||
| "trtllm/gen/DtypeDecl.h", | ||
| "trtllm/gen/MmaDecl.h", | ||
| "trtllm/gen/SfLayoutDecl.h", | ||
| "trtllm/gen/CudaArchDecl.h", | ||
| ] | ||
|
|
||
| artifact_hash_path = header_dest_dir / ".artifact_hash" | ||
|
|
||
| # Check if cached headers are from a different artifact version (e.g. after git checkout) | ||
| if artifact_hash_path.exists(): | ||
| with open(artifact_hash_path, "r") as f: | ||
| cached_hash = f.read().strip() | ||
| if cached_hash != artifact_path: | ||
| raise RuntimeError( | ||
| f"Detected inconsistent cached artifacts. " | ||
| f"(Cached trtllm headers were downloaded for artifact " | ||
| f"'{cached_hash}', but current code expects " | ||
| f"'{artifact_path}'). " | ||
| f"Please clear the cache to confirm and allow the new headers to be downloaded: " | ||
| f"rm -rf {header_dest_dir}." | ||
| ) | ||
|
|
||
| for file in header_files: | ||
| uri_path = f"{header_path}/{file}" | ||
| file_hash = get_meta_hash(checksum, file) | ||
| file_path = str(header_dest_dir / file) | ||
| result = get_file(uri_path, file_hash, file_path) | ||
| assert result, f"{file} not found" | ||
|
|
||
| # Record which artifact version these headers belong to | ||
| write_if_different(artifact_hash_path, artifact_path) | ||
|
|
||
|
|
||
| def convert_to_ctypes_char_p(data: bytes): | ||
| return ctypes.c_char_p(data) | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.