Skip to content

feat: model full debug and add TileIR JIT overrides - #237

Open
almightychang wants to merge 4 commits into
NVlabs:mainfrom
almightychang:feat/pass-tileiras-devtool-flags
Open

feat: model full debug and add TileIR JIT overrides#237
almightychang wants to merge 4 commits into
NVlabs:mainfrom
almightychang:feat/pass-tileiras-devtool-flags

Conversation

@almightychang

@almightychang almightychang commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR has been rewritten on top of main after #236 landed with most of the original implementation. The remaining scope is:

  • model TileIR optimization as Optimization::Level(u8) | Optimization::FullDebug
  • add process-wide environment overrides for optimization, memcheck, and line information

Why the optimization model comes first

On current main, device_debug=true plus an explicit optimized level produces an argv combination that tileiras rejects (optimized debugging is currently not supported; only O0 is accepted with --device-debug). Without environment overrides, both setters come from one call site, so that behavior was a reasonable API choice for the new compile options.

The override changes who produces the combination: an application can set level 3 while a wrapper independently enables debug through the environment. Neither party made an invalid local choice, but the failure would surface later during JIT in a process the wrapper does not own. Making full debug a distinct optimization state prevents that cross-party invalid combination; FullDebug owns both --opt-level 0 and --device-debug.

Only the opt_level / device_debug pair is folded together. lineinfo and sanitize_memcheck remain independent because the measured combinations are accepted by tileiras (-O3 --lineinfo, -O0 -g --sanitize=memcheck, and -O3 --sanitize=memcheck).

This modeling change does not change cache identity. FullDebug still encodes opt level 0 and device-debug in flags bit 0; lineinfo remains bit 1 and memcheck bit 2. The L2 key regression test compares the new representation with the previous encoding across every valid combination. The cache domain, entry format version, and entry header layout are unchanged.

Environment overrides

  • CUTILE_JIT_OPTIMIZATION=0|1|2|3|debug
  • CUTILE_JIT_SANITIZE=memcheck|none
  • CUTILE_JIT_LINEINFO=1|0 (also true/false, yes/no, and on/off)

Each variable has three states: unset preserves the code setting, an explicit value overrides it (including explicit off), and an invalid or non-Unicode value returns a clear JIT error. The values are read once per process with OnceLock in the existing TileirasOptions::from_compile_options resolution point, before the L2 cache key is constructed.

CUTILE_JIT_LINEINFO is included for completeness because #236 added lineinfo to the programmatic surface after the original PR was written. I am happy to remove that override if the additional knob is not wanted.

Validation

Validated in the cutile-ci:13.3 container used to mirror .github/workflows/pr.yml:

  • cargo build
  • cargo fmt -- --check
  • cargo clippy --all-features
  • cargo test --no-run
  • bash scripts/run_cpu_tests.sh
  • TileIR smoke test with --nocapture
  • loom model check and miri slot-table checks
  • bash scripts/run_all.sh (CPU section passed; GPU-dependent sections failed because libcuda.so was unavailable)

compiler2_e2e was confirmed to execute rather than silently skip: it printed its target and produced non-empty cubins with the real CUDA 13.3 tileiras. In particular, application code specifying opt_level(3) plus CUTILE_JIT_OPTIMIZATION=debug resolved to --opt-level 0 --device-debug and compiled successfully. The real backend also accepted the directly tested default, O0, debug, debug+memcheck, O3+memcheck, and lineinfo argv combinations.

GPU launch paths were not validated on this machine because the container had no CUDA driver (libcuda.so, driver error 303); those paths rely on CI with a compatible GPU and driver. The local wrapper also lacks the workflow's seccomp=unconfined option, so the ThreadSanitizer command stopped at setarch: Operation not permitted; the dedicated CI job remains the verification for that check.

@copy-pr-bot

copy-pr-bot Bot commented Aug 23, 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.

@elibol

elibol commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

@almightychang I just merged #236 and it overlaps substantially with this impl. Sorry, I never flagged on #210 that work was already in flight and I only realized the overlap after merging and looking at this PR for the first time.

Otherwise, this PR looks good. There are some ideas here that I'd like to see in main with you as author, if you're up for it:

  1. The env overrides (CUTILE_JIT_OPTIMIZATION / CUTILE_JIT_SANITIZE). Right now, nothing on main can switch a kernel to a debug or sanitizer build without a code change. Main now resolves all of these flags in one place (TileirasOptions::from_compile_options), so the override slice should rebase cleanly.
  2. Your Level | FullDebug modeling. You measured the same thing we did (tileiras rejects --device-debug above level 0); main expresses it as "device_debug implies 0 unless set explicitly", but making the invalid combination unrepresentable is a fair argument. The API is days old, so there's still time to make the case for it.

If you're up for the env-override follow-up, it's yours. Sorry again!

@almightychang

Copy link
Copy Markdown
Contributor Author

@elibol
Ah, I missed #236 was already in flight.
I will rebase onto main and narrow down the scope to the follow ups.

Full device debug only works at optimization level zero, but the two independent options allowed callers to construct combinations that tileiras rejects. Model level selection and full debug as one choice and reject unsupported levels as a recoverable JIT error.

Keep lineinfo and memcheck independent. Preserve the existing opt-level byte and flags bit layout so cache keys and entry encoding remain unchanged, with a regression test against the previous representation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Sam, Joochul Chang <almightychang@icloud.com>
@almightychang
almightychang force-pushed the feat/pass-tileiras-devtool-flags branch from 9121046 to eef759b Compare August 24, 2026 16:03
@almightychang almightychang changed the title feat: pass tileiras devtool flags feat: model full debug and add TileIR JIT overrides Aug 24, 2026
Wrappers need to switch an already-built application into debug or sanitizer compilation without changing its source. Resolve optimization, memcheck, and lineinfo overrides once at the existing stage-2 option boundary, before cache-key construction.

Unset variables preserve code settings, explicit off values disable them, and malformed or non-Unicode values return through the existing JIT error path. A debug override replaces an explicit optimized level, relying on the optimization model that makes the resulting O0 plus device-debug pair valid.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Sam, Joochul Chang <almightychang@icloud.com>
@almightychang
almightychang force-pushed the feat/pass-tileiras-devtool-flags branch from eef759b to 900a473 Compare August 24, 2026 16:11
@almightychang

almightychang commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

@elibol
Reworked this PR on top of main after #236 landed. The updated branch now contains two focused commits:

  1. Model optimization as Level(u8) | FullDebug, while preserving the existing cache-key bit layout.
  2. Add process-wide JIT environment overrides and regression coverage for their composition with code-level options.

In particular, the tests now pin the critical case where code requests optimization level 3 but CUTILE_JIT_OPTIMIZATION=debug resolves to full debug (--opt-level 0 --device-debug). They also cover preserving code settings when overrides are unset, explicit on/off behavior for sanitizer and lineinfo, and invalid environment values.

Validation was run in the cutile-ci:13.3 container: all 142 cutile-compiler library tests and the formatting check pass. I also verified the effective TileIRAS argv combinations, including the level-3-to-debug override case.

@elibol elibol modified the milestone: cuTile RUST v0.4.0 Sep 1, 2026
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.

2 participants