Repository navigation
cutile: one CodegenMode for device debug, plus CUTILE_JIT_* run-time overrides - #1600
almightychang wants to merge 4 commits into
Conversation
…nMode
`tileiras` accepts `--device-debug` only at optimization level 0, but
`CompileOptions` kept the level and the debug flag as independent fields.
Debug builds default to full debug, so adding only `.opt_level(3)` produced
`--opt-level 3 --device-debug`, which `tileiras` rejects at JIT time.
Replace `opt_level`, `device_debug`, and `lineinfo` with
`codegen: CodegenMode`, where `Debug` owns level 0 and
`Optimized { level, lineinfo }` covers the rest. Every value now maps to
flags `tileiras` accepts. `debug_info()` and `opt_level()` select a mode,
and the last call wins. The level-0 default rule in
`TileirasOptions::from_compile_options` is gone, and the frontend reads the
same mode to decide check hoisting.
Remove the `device_debug(bool)` and `lineinfo(bool)` setters, which
`debug_info()` covers. The cache key and entry header bytes are unchanged
for every mode; a test pins them against the previous encoding.
Signed-off-by: almightychang (Sam, Joochul Chang) <almightychang@icloud.com>
Nothing could switch an already-built application to a debug or sanitizer build without changing its code. Add three process-wide variables, read once per process: - CUTILE_JIT_DEBUG=none|line|full acts like `debug_info()` - CUTILE_JIT_OPT_LEVEL=0|1|2|3 acts like `opt_level()` - CUTILE_JIT_SANITIZE=memcheck|none acts like `sanitize_memcheck()` Each applies after the code's options, as if its setter were called last. `CompileOptions::with_jit_env_overrides()` applies them once before both compile stages, so the frontend's check placement and the `tileiras` flags always come from the same options. Invalid values, and full debug together with an explicit level, return a JIT error naming the variable. This continues NVlabs/cutile-rs#237, which applied the overrides only to the `tileiras` flags and left the frontend hoisting checks under `CUTILE_JIT_OPTIMIZATION=debug`. Signed-off-by: almightychang (Sam, Joochul Chang) <almightychang@icloud.com>
|
Reviewing this against #1428. The setter/parser unit tests, subprocess full-debug test, previous-cache-encoding regression, and recorded real Two integration gaps to close:
For the debug-mode claim, retain a source-breakpoint/inline-backtrace smoke test on the produced full-debug cubin. This PR controls compilation mode; it should not be treated as the fix for #1379's trap attribution or #1476's inline-call breakpoint resolver. Once accepted, #1428 is the issue this PR should close; the other source-location audit items remain independent. |
…cesses Every override case now runs in a child process that inherits no CUTILE_JIT_* setting and is selected by a dedicated marker variable. The cases cover explicit none, line with an opt level, full, an invalid value, the full/opt-level conflict, and the read-once rule. The cache-key check compares keys reported by independent processes, each under its own overrides, so a key that dropped the effective mode would let two distinct modes collide. A GPU test runs the normal launcher against one shared disk store and checks the kernel result, the check placement, and whether stage 2 came from tileiras or the store. Signed-off-by: almightychang (Sam, Joochul Chang) <almightychang@icloud.com>
|
Thanks, both gaps were real. Pushed 765cb1f (tests only). Hermetic overrides. Each case runs in a child selected by Cache key. The old assertion compared two configurations under the same override, as you said. Now:
A key that ignores the mode does not show up at the launcher. The entry header also records opt level and flags, so a colliding entry is rejected and recompiled. That case is covered by the Debug claim. The cuda-gdb smoke test in |
… main Integrate the v0.5.0 baseline and document the removed CompileOptions fields/setters, setter precedence, and runtime override behavior. Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
|
/ok to test a844d56 |
|
Pushed CUDA 13.3 validation: all seven environment tests pass with all three overrides set in the parent; the normal-launcher shared-cache GPU matrix passes; all nine debug and six generated-source tests pass including assembler/GPU/CUDA-GDB; strict compiler Clippy and formatting pass. CUDA 13.2/13.4 Tile CI, build, semver, shared-host and reactor checks pass. Rust CodeQL is still running. This addresses the requested migration treatment and validation for #1428. #1379/#1476 remain separate. Combined source-location/debug-mode validation in #1613 passes all 35 tests. Release tracking: #1606. |
Closes #1428. Continues NVlabs/cutile-rs#237.
This PR controls which compile mode a kernel gets. It does not fix trap attribution (#1379) or the inline-call breakpoint resolver (#1476); the other source-location audit items stay independent.
Problem
tileirasaccepts--device-debugonly at--opt-level 0. That rule spans two fields, butCompileOptionsstores them independently, and each source writes them field by field:A field-by-field merge cannot keep a rule that spans two fields. Each writer would need its own copy of the "level 0 if debug" rule. Today the only copy, the default in
from_compile_options, applies only when no level is set. The resolved options can still hold the rejected pair, so the only real check istileirasitself, at JIT time, far from the setter that caused it.NVlabs/cutile-rs#285 made the build profile another writer. Dev-profile builds now start in full debug, so
CompileOptions::new().opt_level(3)alone fails at JIT time, while the same code passes with--release. The run-time overrides that NVlabs/cutile-rs#237 proposed would add a third writer and a third copy of the rule.Change
Make the rejected pair unrepresentable, and have each writer replace the whole value:
The rule is removed instead of copied. The run-time overrides then reduce to the same setters, applied after the code's:
CUTILE_JIT_DEBUGnone,line,fulldebug_info(...)CUTILE_JIT_OPT_LEVEL0–3opt_level(n)CUTILE_JIT_SANITIZEmemcheck,nonesanitize_memcheck(...)CUTILE_JIT_DEBUG=fulltogether withCUTILE_JIT_OPT_LEVEL, or an invalid value, fails with a JIT error that names the variable. The overrides are applied once before both compile stages, so the frontend andtileirassee the same mode. NVlabs/cutile-rs#237 applied them only to thetileirasflags.Behavior and API changes
opt_level(3)-O3 --device-debug, rejected-O3.debug_info(Full).opt_level(3)-O3 --device-debug, rejected-O3(last call wins).opt_level(3).debug_info(Full)-O3 --device-debug, rejected-O0 --device-debugdevice_debug(bool),lineinfo(bool)debug_info()covers themopt_level,device_debug,lineinfofieldscodegenCache key and entry-header bytes are unchanged for every mode; a test pins them against the previous encoding.
DebugInfoLevelanddebug_info()from NVlabs/cutile-rs#285 stay. The v0.5.0 changelog and book include the field/setter migration and ordering rules.Validation
Local container from
nvidia/cuda:13.3.1-devel-ubuntu24.04with an RTX 5080 (driver 580, CUDA 13.0):cargo fmt -- --check;cargo clippy --workspace --exclude cuda-tile-rs --all-targets(only the existingrmsnorm.rsunused-unsafewarning)scripts/run_cpu_tests.shandscripts/run_gpu_tests.sh: all passedscripts/test_debug_defaults.sh: passedtests/jit_env_overrides.rs: every case runs in a child that inherits noCUTILE_JIT_*, and passes with all three exported in the parent shell. The cache-key matrix compares keys from independent processes; it fails when the mode is dropped from the key.tests/gpu/jit_env_overrides.rs: the normal launcher, eight processes, one shared disk store. Each checks the kernel result, check placement, andstage2_source; it fails when the launcher skips the overrides.tests/debug_info.rs --ignored: the cuda-gdb source-breakpoint and inline-frame smoke test on the full-debug cubin passes.tileiras(CUTILE_TILEIRAS_PATH, empty disk cache) recorded the flags it received: