Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 90 additions & 3 deletions ggml/src/ggml-vulkan/ggml-vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,14 @@ enum shader_reduction_mode {
static constexpr uint32_t num_argsort_pipelines = 11;
static constexpr uint32_t num_topk_moe_pipelines = 10;
static constexpr uint32_t num_topk_pipelines = 11;
// Keep these values in sync with topk_global.comp.
static constexpr uint32_t topk_global_radix_bits = 5;
static constexpr uint32_t topk_global_num_buckets = 1u << topk_global_radix_bits;
static constexpr uint32_t topk_global_num_passes = (32 + topk_global_radix_bits - 1) / topk_global_radix_bits;
static constexpr uint32_t topk_global_items_per_thread[] = { 2, 4, 8 };
static constexpr uint32_t num_topk_global_pipelines = sizeof(topk_global_items_per_thread) / sizeof(topk_global_items_per_thread[0]);
static constexpr uint32_t topk_global_default_pipeline = 0;
static constexpr uint32_t topk_global_max_auto_pipeline = 2;

static constexpr std::initializer_list<ggml_op> topk_moe_early_softmax_norm{ GGML_OP_SOFT_MAX, GGML_OP_RESHAPE, GGML_OP_ARGSORT,
GGML_OP_VIEW, GGML_OP_GET_ROWS, GGML_OP_RESHAPE,
Expand Down Expand Up @@ -1056,6 +1064,8 @@ struct vk_device_struct {
vk_pipeline pipeline_argsort_f32[num_argsort_pipelines];
vk_pipeline pipeline_argsort_large_f32[num_argsort_pipelines];
vk_pipeline pipeline_topk_f32[num_topk_pipelines];
vk_pipeline pipeline_topk_global_f32[num_topk_global_pipelines];
vk_pipeline pipeline_topk_global_subgroup_f32[num_topk_global_pipelines];
vk_pipeline pipeline_sum_rows_f32;
vk_pipeline pipeline_cross_entropy_loss_f32, pipeline_cross_entropy_loss_f32_wg512;
vk_pipeline pipeline_cross_entropy_loss_back_f32, pipeline_cross_entropy_loss_back_f32_wg512;
Expand Down Expand Up @@ -1748,6 +1758,13 @@ struct vk_op_topk_push_constants {
uint32_t last_pass;
};

struct vk_op_topk_global_push_constants {
uint32_t ncols;
uint32_t k;
uint32_t nrows;
uint32_t pass;
};

struct vk_op_im2col_push_constants {
uint64_t dst_addr;
uint32_t batch_offset; uint32_t offset_delta;
Expand Down Expand Up @@ -5812,6 +5829,19 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
}
}

const uint32_t topk_global_block_size = 1u << std::min(device->max_workgroup_size_log2, 7u);
for (uint32_t i = 0; i < num_topk_global_pipelines; ++i) {
const uint32_t items_per_thread = topk_global_items_per_thread[i];
const uint32_t chunk_size = topk_global_block_size * items_per_thread;
const std::string suffix = "_i" + std::to_string(items_per_thread);
ggml_vk_create_pipeline2(device, device->pipeline_topk_global_f32[i], "topk_global_f32" + suffix, topk_global_f32_len, topk_global_f32_data, "main", 3,
sizeof(vk_op_topk_global_push_constants), {chunk_size, 1, 1}, {topk_global_block_size, items_per_thread}, 1, true);
if (device->subgroup_basic && device->subgroup_arithmetic && device->subgroup_ballot && device->subgroup_require_full_support && device->subgroup_size >= topk_global_num_buckets) {
ggml_vk_create_pipeline2(device, device->pipeline_topk_global_subgroup_f32[i], "topk_global_subgroup_f32" + suffix, topk_global_subgroup_f32_len, topk_global_subgroup_f32_data, "main", 3,
sizeof(vk_op_topk_global_push_constants), {chunk_size, 1, 1}, {topk_global_block_size, items_per_thread}, 1, true, true, device->subgroup_size);
}
}

ggml_vk_create_pipeline(device, device->pipeline_argmax_f32, "argmax_f32", argmax_f32_len, argmax_f32_data, "main", 2, sizeof(vk_op_push_constants), {1, 1, 1}, { device->subgroup_size }, 1);

ggml_vk_create_pipeline(device, device->pipeline_sum_rows_f32, "sum_rows_f32", sum_rows_f32_len, sum_rows_f32_data, "main", 2, sizeof(vk_op_sum_rows_push_constants), {1, 1, 1}, { device->subgroup_size }, 1);
Expand Down Expand Up @@ -13931,11 +13961,70 @@ static void ggml_vk_argsort(ggml_backend_vk_context * ctx, vk_context& subctx, c
}
}

static void ggml_vk_topk_global(ggml_backend_vk_context * ctx, vk_context& subctx, const ggml_tensor * src0, ggml_tensor * dst) {
const uint32_t ncols = src0->ne[0];
const uint32_t nrows = ggml_nrows(src0);
const uint32_t k = dst->ne[0];
const size_t scratch_size = size_t{nrows} * (topk_global_num_passes * topk_global_num_buckets + 8) * sizeof(uint32_t);

if (ctx->prealloc_size_x < scratch_size) {
ctx->prealloc_size_x = scratch_size;
ggml_vk_preallocate_buffers(ctx, subctx);
}
if (ctx->prealloc_x_need_sync) {
ggml_vk_sync_buffers(ctx, subctx);
}

vk_subbuffer src_buf = ggml_vk_tensor_subbuffer(ctx, src0);
vk_subbuffer scratch_buf = { ctx->prealloc_x, 0, scratch_size };
vk_subbuffer dst_buf = ggml_vk_tensor_subbuffer(ctx, dst);
uint32_t pipeline_index = topk_global_default_pipeline;
const uint64_t min_workgroups = 4ull * std::max(1u, ctx->device->shader_core_count);
for (uint32_t i = topk_global_max_auto_pipeline; i > topk_global_default_pipeline; --i) {
vk_pipeline candidate = ctx->device->pipeline_topk_global_subgroup_f32[i] ? ctx->device->pipeline_topk_global_subgroup_f32[i] : ctx->device->pipeline_topk_global_f32[i];
const uint64_t workgroups = uint64_t(nrows) * ((ncols + candidate->wg_denoms[0] - 1) / candidate->wg_denoms[0]);
if (workgroups >= min_workgroups) {
pipeline_index = i;
break;
}
}
vk_pipeline pipeline = ctx->device->pipeline_topk_global_subgroup_f32[pipeline_index] ? ctx->device->pipeline_topk_global_subgroup_f32[pipeline_index] : ctx->device->pipeline_topk_global_f32[pipeline_index];
GGML_ASSERT(pipeline);

subctx->s->buffer->buf.fillBuffer(scratch_buf.buffer->buffer, scratch_buf.offset, scratch_buf.size, 0);
ggml_vk_sync_buffers(ctx, subctx);

std::array<uint32_t, 3> elements = {
ncols,
std::min(nrows, ctx->device->properties.limits.maxComputeWorkGroupCount[1]),
1,
};
vk_op_topk_global_push_constants pc { ncols, k, nrows, 0 };

for (uint32_t pass = 0; pass < topk_global_num_passes; ++pass) {
pc.pass = pass;
ggml_pipeline_request_descriptor_sets(ctx, pipeline, 1);
ggml_vk_dispatch_pipeline(ctx, subctx, pipeline, { src_buf, scratch_buf, dst_buf }, pc, elements);
ggml_vk_sync_buffers(ctx, subctx);
}

pc.pass = topk_global_num_passes;
ggml_pipeline_request_descriptor_sets(ctx, pipeline, 1);
ggml_vk_dispatch_pipeline(ctx, subctx, pipeline, { src_buf, scratch_buf, dst_buf }, pc, elements);
ctx->prealloc_x_need_sync = true;
}

static void ggml_vk_topk(ggml_backend_vk_context * ctx, vk_context& subctx, const ggml_tensor * src0, ggml_tensor * dst) {
uint32_t ncols = src0->ne[0];
uint32_t nrows = ggml_nrows(src0);
uint32_t k = dst->ne[0];

uint32_t min_pipeline = (uint32_t)log2f(float(k)) + 1;
if (min_pipeline >= num_topk_pipelines || !ctx->device->pipeline_topk_f32[min_pipeline]) {
ggml_vk_topk_global(ctx, subctx, src0, dst);
return;
}

vk_op_topk_push_constants pc { ncols, ncols, ncols, k, nrows, 0, 0 };

if (ctx->prealloc_x_need_sync) {
Expand Down Expand Up @@ -18717,12 +18806,10 @@ static bool ggml_backend_vk_device_supports_op(ggml_backend_dev_t dev, const ggm
if (!ggml_is_contiguous(op) || !ggml_is_contiguous(op->src[0])) {
return false;
}
// We could potentially support larger, using argsort to sort the
// whole thing. Not clear if this is needed.
uint32_t min_pipeline = (uint32_t)log2f(float(op->ne[0])) + 1;
if (min_pipeline >= num_topk_pipelines ||
!device->pipeline_topk_f32[min_pipeline]) {
return false;
return device->pipeline_topk_global_subgroup_f32[topk_global_default_pipeline] != nullptr || device->pipeline_topk_global_f32[topk_global_default_pipeline] != nullptr;
}
}
return true;
Expand Down
Loading
Loading