Repository navigation
CUDA: branchless Q4_K/Q5_K unpack to speed up mmvq, L2 prefetch on DGX Spark #26705
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
am17an
merged 10 commits into
ggml-org:master
from
praneshgo:pgonegandla/mmvq-q4k-q5k-branchless
Sep 7, 2026
Merged
Changes from 7 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
10d708a
Update Q4_K and Q5_K to use branchless computation, which stops the s…
praneshgo b686848
Gating the change off from DGX Spark due to no gain
praneshgo 6754cee
Adding prefetch gated to Spark, making branchless change in Q4_K and …
praneshgo 9b9cf68
Guard the mmvq L2 prefetch against MUSA as well as HIP
praneshgo 63daa18
Define the mmvq L2 prefetch only under the Spark guard
praneshgo 99e1393
Update switch point for Q4_K to accommodate more models
praneshgo 2097c8c
Remove stale comments
praneshgo 9c2afe6
Add block_size to ggml_cuda_type_traits and create a separate mmvq_sh…
praneshgo 22c832a
Rename block_size to bs for cleaner indentation
praneshgo aa17a1b
Fix build error on non-Spark CUDA arch with appropriate conditional a…
praneshgo 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,23 @@ | |
| #include <cstdint> | ||
| #include <type_traits> | ||
|
|
||
| // block size in bytes; 0 compiles the prefetch out for that type | ||
| template <ggml_type type> struct mmvq_pf { static constexpr int bytes = 0; }; | ||
| template <> struct mmvq_pf<GGML_TYPE_Q4_0> { static constexpr int bytes = sizeof(block_q4_0); }; | ||
| template <> struct mmvq_pf<GGML_TYPE_Q8_0> { static constexpr int bytes = sizeof(block_q8_0); }; | ||
| template <> struct mmvq_pf<GGML_TYPE_Q3_K> { static constexpr int bytes = sizeof(block_q3_K); }; | ||
| template <> struct mmvq_pf<GGML_TYPE_Q4_K> { static constexpr int bytes = sizeof(block_q4_K); }; | ||
| template <> struct mmvq_pf<GGML_TYPE_Q5_K> { static constexpr int bytes = sizeof(block_q5_K); }; | ||
| template <> struct mmvq_pf<GGML_TYPE_Q6_K> { static constexpr int bytes = sizeof(block_q6_K); }; | ||
| template <> struct mmvq_pf<GGML_TYPE_IQ4_XS> { static constexpr int bytes = sizeof(block_iq4_xs); }; | ||
| // Q2_K is left out: prefetching does not raise its L2 hit rate, so the requests only add pressure | ||
|
|
||
| #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK | ||
| static __device__ __forceinline__ void mmvq_prefetch_l2(const void * p) { | ||
| asm volatile("prefetch.global.L2 [%0];" :: "l"(p)); | ||
| } | ||
| #endif | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. leave a comment or link to PR discussion where DGX sparks numbers are displayed
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a comment with link to the PR comment for DGX Spark results |
||
|
|
||
| typedef float (*vec_dot_q_cuda_t)(const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs); | ||
|
|
||
| static constexpr __device__ vec_dot_q_cuda_t get_vec_dot_q_cuda(ggml_type type) { | ||
|
|
@@ -298,9 +315,6 @@ bool ggml_cuda_should_use_mmvq(enum ggml_type type, int cc, int64_t ne11) { | |
| return ne11 <= 4; | ||
| case GGML_TYPE_Q3_K: | ||
| return ne11 <= 6; | ||
| case GGML_TYPE_Q4_K: | ||
| case GGML_TYPE_Q5_K: | ||
| return ne11 <= 7; | ||
| default: | ||
| return ne11 <= MMVQ_MAX_BATCH_SIZE; | ||
| } | ||
|
|
@@ -310,8 +324,9 @@ bool ggml_cuda_should_use_mmvq(enum ggml_type type, int cc, int64_t ne11) { | |
| case GGML_TYPE_Q2_K: | ||
| case GGML_TYPE_Q3_K: | ||
| case GGML_TYPE_Q4_K: | ||
| case GGML_TYPE_Q5_K: | ||
| return ne11 <= 5; | ||
| case GGML_TYPE_Q5_K: | ||
| return ne11 <= 6; | ||
| case GGML_TYPE_Q6_K: | ||
| return ne11 <= 7; | ||
| default: | ||
|
|
@@ -663,6 +678,27 @@ static __global__ void mul_mat_vec_q( | |
| // x block quant index when casting the quants to int | ||
| const int kqs = vdr * (tid % (qi/vdr)); | ||
|
|
||
| #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK | ||
| // start the next iterations' weight loads early. only pays where the kernel is | ||
| // latency-bound rather than bandwidth-bound, which on this part it is | ||
| if constexpr (mmvq_pf<type>::bytes > 0) { | ||
| constexpr int pf_dist = 2; // loop iterations, not blocks | ||
| const int kbx_pf = kbx + pf_dist*blocks_per_iter; | ||
| if (kbx_pf < blocks_per_row_x) { | ||
| #pragma unroll | ||
| for (int i = 0; i < rows_per_cuda_block; ++i) { | ||
| const size_t off = (size_t)(kbx_offset + i*stride_row_x + kbx_pf) * mmvq_pf<type>::bytes; | ||
| mmvq_prefetch_l2((const char *) vx + off); | ||
| if constexpr (has_fusion) { | ||
| if (use_gate) { | ||
| mmvq_prefetch_l2((const char *) vgate + off); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| #endif | ||
|
|
||
| #pragma unroll | ||
| for (int j = 0; j < ncols_dst; ++j) { | ||
| #pragma unroll | ||
|
|
||
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
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.
Uh oh!
There was an error while loading. Please reload this page.
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.
block_size should be added to
ggml_cuda_type_traits, create a separatemmvq_should_prefetchfunction for excluding q2_kThere 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.
Acknowledged. I will commit the necessary changes for review in a short bit.
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.
Made the necessary changes in the latest commit. Please review.