Skip to content

tilecpp: key the cubin disk cache on the nvcc that built it - #227

Merged
hannahli-nv merged 2 commits into
NVIDIA:mainfrom
0z5a:tilecpp-cache-key-compiler
Nov 13, 2026
Merged

hannahli-nv merged 2 commits into
NVIDIA:mainfrom
0z5a:tilecpp-cache-key-compiler

Conversation

@0z5a

@0z5a 0z5a commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Description

The tilecpp cubin disk cache key covers the kernel source, the template parameters and the target arch, but not the compiler. After switching TILECPP_NVCC_PATH or upgrading the CUDA toolkit, cubins built by the previous nvcc are silently reused. A compiler fix or regression is then not picked up until the cache is cleared or TILECPP_DISABLE_CACHE=1 is set. This also matters when retesting compiler-related reports such as #225 with another toolkit.

This change adds a per-process fingerprint of the nvcc in NVCC_PATH to the source hash: its nvcc --version output, or, when that fails or exits nonzero, its path as found on PATH. The fingerprint is computed once per compiler path, so the extra cost is one nvcc --version per process.

Test: test_cubin_cache_is_keyed_on_compiler compiles the same kernel with two stub compilers that report different versions and checks that the second compile does not return the first cubin. Fails on main and passes with this change. Three more tests cover the fallback: a stub that prints a version but exits 1, a bare nvcc found on PATH through a symlink, and an nvcc that is not found. Each fails without the second commit. After rebasing onto main, the whole file gives 18 passed on Linux (GH200, CUTILE_TUTORIALS_BACKEND=tilecpp).

I emailed my signed CLA (individual) to TileGym@nvidia.com on 2026-11-03.

CI Configuration

config:
  build: true
  # valid options are "ops", "benchmark", and "sanity"
  test: ["ops", "benchmark"]

Checklist

  • Code formatted and imports sorted via repo specifications (./format.sh)
  • Documentation updated (if needed)
  • CI configuration reviewed

@copy-pr-bot

copy-pr-bot Bot commented Nov 3, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

"""
if NVCC_PATH not in _compiler_fingerprints:
try:
identity = subprocess.run([NVCC_PATH, "--version"], capture_output=True, text=True, timeout=10).stdout

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add check=True to subprocess.run()? Without it, a nonzero exit code does not enter the exception handler.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 6150200. With check=True, a nonzero exit raises CalledProcessError, which the existing except (OSError, subprocess.SubprocessError) already catches, so no change to the handler was needed. A failing nvcc --version now falls back to the path instead of fingerprinting whatever it printed. A working nvcc exits 0, so existing fingerprints and cache entries don't change. Added a test with a stub that prints a version and exits 1.

identity = subprocess.run([NVCC_PATH, "--version"], capture_output=True, text=True, timeout=10).stdout
except (OSError, subprocess.SubprocessError):
identity = ""
_compiler_fingerprints[NVCC_PATH] = identity or os.path.realpath(NVCC_PATH)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we resolve NVCC_PATH with shutil.which() before applying os.path.realpath() in the fallback? The default is "nvcc", and realpath("nvcc") resolves relative to the working directory rather than finding the executable on PATH.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 6150200. The fallback now resolves shutil.which(NVCC_PATH) before realpath, so it finds the same binary the subprocess call would, matching selector._nvcc_version_supported. If nothing is found on PATH, the fingerprint is the NVCC_PATH string as given rather than a path in the working directory, so the key doesn't depend on where the process runs. Tests cover a bare nvcc found on PATH (through a symlink) and a missing one.

@hannahli-nv

Copy link
Copy Markdown
Collaborator

Hi @0z5a, thanks for the follow-up. #226 has been merged into main (759fb1a), so this branch now shows a conflict. Could you rebase onto the latest main?

0z5a and others added 2 commits November 12, 2026 09:50
The cache key covered the kernel source, template parameters and arch
but not the compiler. After switching TILECPP_NVCC_PATH or upgrading
the CUDA toolkit, previously cached cubins were silently reused, so
compiler fixes (or regressions) were not picked up until the cache was
cleared or TILECPP_DISABLE_CACHE=1 was set.

Add a per-process fingerprint of the nvcc in NVCC_PATH (its --version
output, or its resolved path when it cannot run) to the source hash.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: 0z5a <dezhen.lu@student.uni-tuebingen.de>
…print

Address review on the compiler fingerprint:

- Pass check=True to the nvcc --version probe, so a nonzero exit is
  treated as a failed probe and falls back to the path instead of
  fingerprinting whatever it printed. The existing except clause already
  covers CalledProcessError (a SubprocessError).
- Resolve NVCC_PATH with shutil.which() before realpath() in the
  fallback. The default is the bare name "nvcc", which realpath()
  resolved against the working directory rather than PATH. When nvcc is
  not found at all, fingerprint the NVCC_PATH string as given.

A working nvcc exits 0, so its fingerprint and existing cache entries
are unchanged.

Signed-off-by: 0z5a <dezhen.lu@student.uni-tuebingen.de>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@0z5a
0z5a force-pushed the tilecpp-cache-key-compiler branch from 6150200 to 249764d Compare November 12, 2026 09:02
@0z5a

0z5a commented Nov 12, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @hannahli-nv, rebased onto main (759fb1a). The branch now has only this PR's two commits, unchanged. tests/test_tilecpp_compiler.py gives 18 passed on Linux (GH200). I removed the "stacked on #226" note from the description.

@hannahli-nv

Copy link
Copy Markdown
Collaborator

/ok to test 249764d

@GordonWuCn GordonWuCn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

@hannahli-nv
hannahli-nv merged commit 2ac9848 into NVIDIA:main Nov 13, 2026
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants