Repository navigation
Conversation
…k only When the sanitizer concretizes a data-dependent value (a loaded value, or a loop bound computed from one), it uses the running block's values and makes the launch run every block. Its checks still let the program ids range over the whole grid, so one block's concretized values were combined with every other block's addresses: - a bounds mask AND-ed with a condition on loaded values is concretized as a whole; in block 0 the bounds mask is true in every lane, so the last block's access was checked without it; - a loop bound loaded per block: block 0's bound was applied to every block. Once a block has concretized a value, pin pid_0..2 to that block in its checks. Every block of such a launch runs and checks its own accesses. Outside loops, the check cache also keys on the block, so a later block that builds the same concretized expression is still checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016HMpCLXdUVNfMbJTj8aHE2
Performance Benchmark
Iterations: 1 warmup + 20 measured |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When the sanitizer concretizes a data-dependent value, it uses the running block's values:
_materialize_memory_operandreplaces an operand that contains a load with constants, and_materialize_loop_valuedoes the same for a loop bound._on_data_dependent_valuethen setsneed_full_grid, so every block of the launch runs. The checks, however, still add onlypid_ok, which letspid_0..2range over the whole grid. One block's concretized values were therefore combined with every other block's addresses, which gives false positives such as:mask = (offs < n) & (flag == 0)is concretized as a whole. In block 0,offs < nis true in every lane, so the concretized mask is all ones, and the accessp + offswas checked for the last block without its bounds mask.for j in range(0, tl.load(lens_ptr + pid)), block 0's bound was applied to every block.This PR pins
pid_0..2to the running block (grid_idx) in_check_range_satisfiableonce the block has concretized a value (need_full_gridis set). Every block of such a launch runs and checks its own accesses, so nothing is skipped. Outside loops, the check cache also keys on the block in that case. Otherwise a later block that builds the same concretized expression would be skipped as a repeat of block 0's check.Checks made before a block concretizes anything are unchanged: they involve no concretized value and still cover every program id.
Tests
tests/end_to_end/test_sanitizer.py:test_data_dependent_mask_is_checked_per_block: the masked-add pattern above, three blocks, with the last block partly masked off. It fails on main and passes with this PR.test_loop_bound_loaded_per_block[fits]: per-block loop bounds[4, 3]over a buffer that holds 7 rows. It fails on main and passes with this PR.test_loop_bound_loaded_per_block[overruns]: bounds[3, 4], where block 1 reads row 7. It is reported on main and with this PR.test_data_dependent_mask_without_bounds_reports_last_block: the masked-add kernel without the bounds mask, so the last block reads pastp. Blocks 0-2 build the same concretized mask, so this test fails if the cache does not key on the block.pytest tests/: 366 passed, 6 skipped on main; 370 passed, 6 skipped with this PR (Python 3.12, Triton 3.8.0).ruff checkandruff format --check(v0.1.9, as pinned in.pre-commit-config.yaml) pass on both changed files.mypy(v1.8.0) reports no new errors insanitizer.py.buildjob installs Triton 3.9.0 and then Triton main. With those, about 96 tests of the existing suite fail whatever the change (the run on [FIX] Stop the sanitizer from skipping repeated launches #518 also has 96 failures), mostly with'SymbolicScalarDType' object has no attribute 'scalar'or'SymbolicExprDataWrapper' object has no attribute 'astype'. The new end-to-end tests fail there with the same errors as the existing sanitizer tests; the new unit tests pass.🤖 Generated with Claude Code
https://claude.ai/code/session_016HMpCLXdUVNfMbJTj8aHE2