Repository navigation
Rebase the fork onto v0.32.4; qmv_quad ragged-tile scale/bias read (gemma4-qat#302) #12
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
Merged
Merged
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
d084f85
metal: 1-bit uint32 wide-load qdot over upstream #3161; non-aligned-K…
jeethu aaa6558
python/tests: make test_qmv_fast_tail_non_aligned_k honest and future…
jeethu f44c32a
quantized: bias-free symmetric 1/2-bit affine (affine_sym) on upstrea…
jeethu f4eba18
quantized: implied-bias affine quantized_matmul/dequantize on upstrea…
jeethu 939c71e
quantized: qmv_fast for affine 4-bit K % 256 and 1-bit K % 512 on ups…
jeethu 30e08d8
quantized: affine qmv_wide by bit width and batch, single-tile 6-7 ro…
jeethu 8d396ce
metal: dispatch/commit/sync/wait counters (gemma4-qat#181, #282)
jeethu 158d0ce
metal_kernel: build and hash each kernel variant once, bounded memo (…
jeethu 87e099a
metal: gate NAX off for gen-17 (M5-class) at every NAX dispatch site …
jeethu cffb7f5
metal: keep transcendentals precise unless MathMode::Fast (#282)
jeethu 5d2510a
fast: spec_decode_verify op (CPU composition + fused Metal) (#282)
jeethu 4783e7b
python/tests: clarify qmv tail/qmv_wide test comments (#282)
jeethu 26aaef3
fast: spec_decode_verify materializes non-row-contiguous drafts (#282)
jeethu e6b7bbe
fast: spec_decode_verify CPU path handles K = 0 like Metal (#282)
jeethu f54067d
fast: spec_decode_verify returns empty results for B = 0 without disp…
jeethu 438e420
fast: spec_decode_verify takes the composition for K = 0 on every bac…
jeethu 329b79a
metal: condense the gen-17 NAX gate comment (#282)
jeethu fc4c06a
fast: spec_decode_verify rejects non-integer draft tokens (#282)
jeethu 44a6aa9
export: serialize SpecDecodeVerify (#282)
jeethu c28faeb
metal: condense the qmv partial-last-block comment (#282)
jeethu bee9e9d
metal: default D512 vector attention to GPU generation 17+ (#291)
jeethu ee0b1bc
metal: condense the D512 vector-attention gate comment (#291)
jeethu 33ef381
metal: qmv_quad reads no scale/bias for rows past N on a ragged last …
jeethu 4c4d61c
fast: SpecDecodeVerify rebuilds its fallback after import (#282)
jeethu 1e1f993
fast: spec_decode_verify takes the primitive for every K and on CPU (…
jeethu cbbbe2f
metal: condense the 1-bit qdot comment (#282)
jeethu c134ee2
python/tests: run the shapeless spec_decode_verify test on GPU only w…
jeethu 560cd02
fast: spec_decode_verify builds one graph for every B, including B = …
jeethu 9482135
cpu: point the bias-free affine error at the implied-bias factor (#282)
jeethu 7b7e8d2
metal: condense the ragged-tile comment in qmv_quad (#282)
jeethu c52689c
metal: condense the spec_decode and qmv alignment comments (#282)
jeethu 7474d2c
fast: spec_decode_verify refuses a shapeless trace on the CUDA compos…
jeethu 713bf19
metal_kernel: build a missing variant under the cache lock (#282)
jeethu bb8fa5f
Condense the remaining multi-line source comments to two lines (#282)
jeethu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| // Copyright © 2026 Apple Inc. | ||
|
|
||
| #include "mlx/allocator.h" | ||
| #include "mlx/backend/cpu/encoder.h" | ||
| #include "mlx/fast_primitives.h" | ||
|
|
||
| namespace mlx::core::fast { | ||
|
|
||
| void SpecDecodeVerify::eval_cpu( | ||
| const std::vector<array>& inputs, | ||
| std::vector<array>& outputs) { | ||
| auto& draft = inputs[0]; // [B, K] int32 | ||
| auto& target = inputs[1]; // [B, K+1] int32 | ||
| auto& n_accepted = outputs[0]; // [B] int32 | ||
| auto& committed = outputs[1]; // [B, K+1] int32 | ||
| n_accepted.set_data(allocator::malloc(n_accepted.nbytes())); | ||
| committed.set_data(allocator::malloc(committed.nbytes())); | ||
| if (n_accepted.size() == 0) { | ||
| return; | ||
| } | ||
|
|
||
| auto& encoder = cpu::get_command_encoder(stream()); | ||
| encoder.set_input_array(draft); | ||
| encoder.set_input_array(target); | ||
| encoder.set_output_array(n_accepted); | ||
| encoder.set_output_array(committed); | ||
| encoder.dispatch([draft = array::unsafe_weak_copy(draft), | ||
| target = array::unsafe_weak_copy(target), | ||
| n_accepted = array::unsafe_weak_copy(n_accepted), | ||
| committed = array::unsafe_weak_copy(committed)]() mutable { | ||
| int B = draft.shape(0); | ||
| int K = draft.shape(1); | ||
| auto ds = draft.strides(); | ||
| auto ts = target.strides(); | ||
| auto* d = draft.data<int32_t>(); | ||
| auto* t = target.data<int32_t>(); | ||
| auto* n_out = n_accepted.data<int32_t>(); | ||
| auto* c_out = committed.data<int32_t>(); | ||
| for (int b = 0; b < B; ++b) { | ||
| auto dt = [&](int j) { return d[b * ds[0] + j * ds[1]]; }; | ||
| auto tt = [&](int j) { return t[b * ts[0] + j * ts[1]]; }; | ||
| int n = K; | ||
| for (int j = 0; j < K; ++j) { | ||
| if (dt(j) != tt(j)) { | ||
| n = j; | ||
| break; | ||
| } | ||
| } | ||
| n_out[b] = n; | ||
| int32_t* c = c_out + b * (K + 1); | ||
| for (int j = 0; j < K + 1; ++j) { | ||
| c[j] = (j < n) ? dt(j) : ((j == n) ? tt(n) : 0); | ||
| } | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| } // namespace mlx::core::fast |
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When multiple threads request the same previously unseen variant concurrently, they can all miss the initial locked lookup and independently execute
write_template,write_signature, source allocation, and hashing before the second lock discards every result but one. This defeats the new build-once memoization precisely for concurrent first use, potentially multiplying large source-generation work by the number of racing callers; coordinate construction per key rather than doing it outside the protected section.Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 713bf19. A missing variant is now built while
cache->mutexis held, so concurrent first callers build it once and the rest reuse it. The lock covers only source generation and hashing: the Metal library is compiled later, inCustomKernel::eval_gpu, so the extra serialization is small. Python suite: 965 passed, 57 skipped. C++: 311/311 on Metal, 311/311 on Metal JIT, 274/274 on CPU-only.