Files
llama.cpp/ggml/src/ggml-vulkan/vulkan-shaders/count_experts.comp
T
Jeff Bolz c9ca51c1f6 vulkan: combine duplicated fastdiv functions, rename the one optimizing small divs (#27526)
* vulkan: combine duplicated fastdiv functions, rename the one optimizing small divs

* remove one more fastdiv
2026-08-29 10:59:48 +03:00

136 lines
4.4 KiB
Plaintext

#version 450
#extension GL_EXT_control_flow_attributes : enable
#ifdef USE_SUBGROUPS
#extension GL_KHR_shader_subgroup_basic : enable
#extension GL_KHR_shader_subgroup_arithmetic : enable
#endif
#include "types.glsl"
#include "utils.glsl"
layout (push_constant) uniform parameter
{
uint32_t ne00;
uint32_t ne01;
uint32_t nb00;
uint32_t nb01;
uint32_t a_offset;
uint32_t n_experts;
uint32_t hoist_row_ids;
uint32_t ne00mp;
uint32_t ne00L;
} p;
#define BLOCK_SIZE 256
layout(local_size_x = BLOCK_SIZE, local_size_y = 1, local_size_z = 1) in;
layout (binding = 0) readonly buffer A {uint data_a[];};
layout (binding = 1) writeonly buffer D {uint data_d[];};
shared uint vals[BLOCK_SIZE];
shared uint offsets[BLOCK_SIZE];
shared uint cursors[BLOCK_SIZE];
// data_d layout when p.hoist_row_ids is set:
// [0, n_experts) per-expert row count
// [n_experts, 2*n_experts) per-expert start offset into the row id region
// [2*n_experts] total row count
// [2*n_experts + 1, ) row ids grouped by expert, packed as (i01 << 16) | (i00 & 0xffff)
// Otherwise only data_d[expert_id] is written, holding that expert's row count.
void main() {
const uint expert_id = gl_WorkGroupID.x;
const uint num_elements = p.ne00 * p.ne01;
const uint tid = gl_LocalInvocationID.x;
if (p.hoist_row_ids != 0) {
if (tid < p.n_experts) {
vals[tid] = 0;
}
barrier();
for (uint idx = tid; idx < num_elements; idx += BLOCK_SIZE) {
const uint i01 = fastdiv(idx, p.ne00mp, p.ne00L);
const uint i00 = idx - i01 * p.ne00;
const uint expert = data_a[p.a_offset + i01 * p.nb01 + i00 * p.nb00];
if (expert < p.n_experts) {
atomicAdd(vals[expert], 1);
}
}
barrier();
#ifdef USE_SUBGROUPS
if (gl_SubgroupID == 0) {
// pad the trip count so the subgroup ops stay in uniform control flow
const uint n_experts_padded = (p.n_experts + gl_SubgroupSize - 1) & ~(gl_SubgroupSize - 1);
uint base = 0;
for (uint expert = gl_SubgroupInvocationID; expert < n_experts_padded; expert += gl_SubgroupSize) {
const bool in_range = expert < p.n_experts;
const uint count = in_range ? vals[expert] : 0;
const uint offset = base + subgroupExclusiveAdd(count);
if (in_range) {
data_d[expert] = count;
data_d[p.n_experts + expert] = offset;
offsets[expert] = offset;
cursors[expert] = 0;
}
base += subgroupAdd(count);
}
if (subgroupElect()) {
data_d[2 * p.n_experts] = base;
}
}
#else
if (tid == 0) {
uint offset = 0;
for (uint expert = 0; expert < p.n_experts; ++expert) {
const uint count = vals[expert];
data_d[expert] = count;
data_d[p.n_experts + expert] = offset;
offsets[expert] = offset;
cursors[expert] = 0;
offset += count;
}
data_d[2 * p.n_experts] = offset;
}
#endif
barrier();
for (uint idx = tid; idx < num_elements; idx += BLOCK_SIZE) {
const uint i01 = fastdiv(idx, p.ne00mp, p.ne00L);
const uint i00 = idx - i01 * p.ne00;
const uint expert = data_a[p.a_offset + i01 * p.nb01 + i00 * p.nb00];
if (expert < p.n_experts) {
const uint row = atomicAdd(cursors[expert], 1);
const uint packed_row_id = (i01 << 16) | (i00 & 0xffffu);
data_d[2 * p.n_experts + 1 + offsets[expert] + row] = packed_row_id;
}
}
return;
}
uint count = 0;
for (uint idx = tid; idx < num_elements; idx += BLOCK_SIZE) {
const uint i01 = fastdiv(idx, p.ne00mp, p.ne00L);
const uint i00 = idx - i01 * p.ne00;
const uint a = data_a[p.a_offset + i01 * p.nb01 + i00 * p.nb00];
count += uint(a == expert_id);
}
vals[tid] = count;
barrier();
[[unroll]] for (uint s = BLOCK_SIZE / 2; s > 0; s >>= 1) {
if (tid < s) {
vals[tid] += vals[tid + s];
}
barrier();
}
if (tid == 0) {
data_d[expert_id] = vals[0];
}
}