@@ -1907,6 +1907,38 @@ static bool vk_enable_sync_logger = false;
19071907static uint32_t vk_perf_logger_frequency = 1;
19081908static std::string vk_pipeline_stats_filter;
19091909
1910+ static uint64_t ggml_vk_get_node_flops(const ggml_tensor * node) {
1911+ if (node->op == GGML_OP_MUL_MAT || node->op == GGML_OP_MUL_MAT_ID) {
1912+ const uint64_t m = node->ne[0];
1913+ const uint64_t n = node->ne[1];
1914+ const uint64_t k = node->src[1]->ne[0];
1915+ const uint64_t batch = node->ne[2] * node->ne[3];
1916+ return m * n * (k + (k - 1)) * batch;
1917+ }
1918+ if (node->op == GGML_OP_CONV_2D || node->op == GGML_OP_CONV_TRANSPOSE_2D) {
1919+ const ggml_tensor * knl = node->src[0];
1920+ const uint64_t Cout = node->ne[2];
1921+ const uint64_t size_K = node->src[1]->ne[2] * knl->ne[0] * knl->ne[1];
1922+ const uint64_t size_N = node->ne[3] * node->ne[0] * node->ne[1];
1923+ return Cout * size_N * (size_K + (size_K - 1));
1924+ }
1925+ if (node->op == GGML_OP_CONV_3D) {
1926+ const ggml_tensor * knl = node->src[0];
1927+ const uint64_t OC = ggml_get_op_params_i32(node, 11);
1928+ const uint64_t IC = ggml_get_op_params_i32(node, 9);
1929+ const uint64_t size_K = IC * knl->ne[0] * knl->ne[1] * knl->ne[2];
1930+ const uint64_t size_N = node->ne[3] / OC * node->ne[0] * node->ne[1] * node->ne[2];
1931+ return OC * size_N * (size_K + (size_K - 1));
1932+ }
1933+ if (node->op == GGML_OP_FLASH_ATTN_EXT) {
1934+ const ggml_tensor * q = node->src[0];
1935+ const ggml_tensor * k = node->src[1];
1936+ const ggml_tensor * v = node->src[2];
1937+ return 2ull * q->ne[1] * q->ne[2] * (k->ne[0] + v->ne[0]) * k->ne[1] * q->ne[3];
1938+ }
1939+ return 0;
1940+ }
1941+
19101942class vk_perf_logger {
19111943 public:
19121944 void print_timings(bool force = false) {
@@ -1955,7 +1987,7 @@ class vk_perf_logger {
19551987 }
19561988
19571989 std::string get_node_fusion_name(const ggml_tensor * node, const char *fusion_name, uint64_t *n_flops) {
1958- *n_flops = 0 ;
1990+ *n_flops = ggml_vk_get_node_flops(node) ;
19591991 std::string fusion_str;
19601992 if (fusion_name) {
19611993 fusion_str = fusion_name + std::string(" ");
@@ -1982,35 +2014,22 @@ class vk_perf_logger {
19822014 if (batch > 1) {
19832015 name += " batch=" + std::to_string(batch);
19842016 }
1985- name = fusion_str + name;
1986- *n_flops = m * n * (k + (k - 1)) * batch;
1987- return name;
2017+ return fusion_str + name;
19882018 }
19892019 if (node->op == GGML_OP_CONV_2D || node->op == GGML_OP_CONV_TRANSPOSE_2D) {
19902020 std::string name = ggml_op_name(node->op);
1991- ggml_tensor * knl = node->src[0];
1992- uint64_t OW = node->ne[0];
1993- uint64_t OH = node->ne[1];
1994- uint64_t N = node->ne[3];
2021+ const ggml_tensor * knl = node->src[0];
19952022 uint64_t Cout = node->ne[2];
1996- uint64_t KW = knl->ne[0];
1997- uint64_t KH = knl->ne[1];
1998- uint64_t Cin = node->src[1]->ne[2];
1999- // KxCRS @ CRSxNPQ = KxNPQ -> M=K, K=CRS, N=NPQ
2000- uint64_t size_M = Cout;
2001- uint64_t size_K = Cin * KW * KH;
2002- uint64_t size_N = N * OW * OH;
2003- *n_flops = size_M * size_N * (size_K + (size_K - 1));
2004- name += " M=Cout=" + std::to_string(size_M) + ", K=Cin*KW*KH=" + std::to_string(size_K) +
2023+ uint64_t size_K = node->src[1]->ne[2] * knl->ne[0] * knl->ne[1];
2024+ uint64_t size_N = node->ne[3] * node->ne[0] * node->ne[1];
2025+ name += " M=Cout=" + std::to_string(Cout) + ", K=Cin*KW*KH=" + std::to_string(size_K) +
20052026 ", N=N*OW*OH=" + std::to_string(size_N);
2006- name = fusion_str + name;
2007- return name;
2027+ return fusion_str + name;
20082028 }
20092029 if (node->op == GGML_OP_RMS_NORM) {
20102030 std::string name = ggml_op_name(node->op);
20112031 name += "(" + std::to_string(node->ne[0]) + "," + std::to_string(node->ne[1]) + "," + std::to_string(node->ne[2]) + "," + std::to_string(node->ne[3]) + ")";
2012- name = fusion_str + name;
2013- return name;
2032+ return fusion_str + name;
20142033 }
20152034 if (node->op == GGML_OP_FLASH_ATTN_EXT) {
20162035 const ggml_tensor * dst = node;
@@ -2026,7 +2045,6 @@ class vk_perf_logger {
20262045 " k(" << k->ne[0] << "," << k->ne[1] << "," << k->ne[2] << "," << k->ne[3] << "), " <<
20272046 " v(" << v->ne[0] << "," << v->ne[1] << "," << v->ne[2] << "," << v->ne[3] << "), " <<
20282047 " m(" << (m?m->ne[0]:0) << "," << (m?m->ne[1]:0) << "," << (m?m->ne[2]:0) << "," << (m?m->ne[3]:0) << ")";
2029- *n_flops = 2ull * q->ne[1] * q->ne[2] * (k->ne[0] + v->ne[0]) * k->ne[1] * q->ne[3];
20302048 return name.str();
20312049 }
20322050 if (node->op == GGML_OP_TOP_K) {
@@ -2090,7 +2108,7 @@ struct ggml_backend_vk_context {
20902108 bool do_add_rms_partials_offset_calculation;
20912109 bool do_add_rms_partials;
20922110
2093- uint64_t last_total_mul_mat_bytes { };
2111+ uint64_t last_total_flops {UINT64_MAX };
20942112
20952113 // Cache most recent tensor that was converted into prealloc_y, and what pipeline it used to convert.
20962114 vk_pipeline_struct * prealloc_y_last_pipeline_used {};
@@ -16188,22 +16206,23 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
1618816206 }
1618916207
1619016208 // Submit after enough work has accumulated, to overlap CPU cmdbuffer generation with GPU execution.
16191- // Estimate the amount of matmul work by looking at the weight matrix size, and submit every 100MB
16192- // (and scaled down based on model size, so smaller models submit earlier).
16193- int submitted_nodes = 0;
16194- int submit_count = 0;
16195- uint64_t mul_mat_bytes = 0;
16196- uint64_t total_mul_mat_bytes = 0;
16197- uint64_t mul_mat_bytes_per_submit = std::min(uint64_t(100*1000*1000), ctx->last_total_mul_mat_bytes / 40u);
16209+ // Estimate the amount of compute work using flops, and submit every 200 GFLOP
16210+ // (and scaled down based on total graph flops, so smaller models submit earlier).
16211+ // Also submit at least every 100 nodes, in case there are workloads without heavy compute.
16212+ uint32_t submitted_nodes = 0;
16213+ uint32_t submit_count = 0;
16214+ uint64_t batch_flops = 0;
16215+ uint64_t total_flops = 0;
16216+ uint64_t flops_per_submit = std::min(uint64_t(200'000'000'000), ctx->last_total_flops / 40u);
1619816217 for (int i = 0; i < cgraph->n_nodes; i++) {
1619916218 if (first_node_in_batch) {
1620016219 submit_node_idx = i;
1620116220 }
1620216221
16203- if (cgraph->nodes[i]->op == GGML_OP_MUL_MAT || cgraph->nodes[i]->op == GGML_OP_MUL_MAT_ID) {
16204- auto bytes = ggml_nbytes (cgraph->nodes[i]->src[0 ]);
16205- mul_mat_bytes += bytes ;
16206- total_mul_mat_bytes += bytes ;
16222+ {
16223+ auto node_flops = ggml_vk_get_node_flops (cgraph->nodes[i]);
16224+ batch_flops += node_flops ;
16225+ total_flops += node_flops ;
1620716226 }
1620816227
1620916228 // op_srcs_fused_elementwise indicates whether an op's srcs all contribute to
@@ -16415,8 +16434,8 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
1641516434
1641616435 // Signal the almost_ready fence when the graph is mostly complete (< 20% remaining)
1641716436 bool almost_ready = (cgraph->n_nodes - i) < cgraph->n_nodes / 5;
16418- bool submit = ((uint32_t) submitted_nodes >= ctx->device->max_nodes_per_submit) ||
16419- (mul_mat_bytes_per_submit != 0 && mul_mat_bytes >= mul_mat_bytes_per_submit ) ||
16437+ bool submit = (submitted_nodes >= ctx->device->max_nodes_per_submit) ||
16438+ (flops_per_submit != 0 && batch_flops >= flops_per_submit ) ||
1642016439 (i + ctx->num_additional_fused_ops >= last_node) ||
1642116440 (almost_ready && !ctx->almost_ready_fence_pending);
1642216441
@@ -16450,9 +16469,9 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
1645016469 if (submit && enqueued) {
1645116470 first_node_in_batch = true;
1645216471 submitted_nodes = 0;
16453- mul_mat_bytes = 0;
16472+ batch_flops = 0;
1645416473 if (submit_count < 3) {
16455- mul_mat_bytes_per_submit *= 2;
16474+ flops_per_submit *= 2;
1645616475 }
1645716476 submit_count++;
1645816477 }
@@ -16461,7 +16480,7 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
1646116480 ctx->fused_ops_write_mask = 0;
1646216481 }
1646316482
16464- ctx->last_total_mul_mat_bytes = total_mul_mat_bytes ;
16483+ ctx->last_total_flops = total_flops ;
1646516484
1646616485 if (vk_perf_logger_enabled) {
1646716486 // End the command buffer and submit/wait
0 commit comments